From 440d44340d3bf61223b5a47d5b91d029f8783494 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 26 Apr 2025 15:49:30 +0800 Subject: [PATCH 001/127] Remove outdated bbl network agent functions --- src/slic3r/Utils/NetworkAgent.cpp | 28 ---------------------------- src/slic3r/Utils/NetworkAgent.hpp | 6 ------ 2 files changed, 34 deletions(-) diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 47c3a7068e5..9eae4ea4345 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -73,7 +73,6 @@ func_get_user_nickanme NetworkAgent::get_user_nickanme_ptr = nullpt func_build_login_cmd NetworkAgent::build_login_cmd_ptr = nullptr; func_build_logout_cmd NetworkAgent::build_logout_cmd_ptr = nullptr; func_build_login_info NetworkAgent::build_login_info_ptr = nullptr; -func_get_model_id_from_desgin_id NetworkAgent::get_model_id_from_desgin_id_ptr = nullptr; func_ping_bind NetworkAgent::ping_bind_ptr = nullptr; func_bind_detect NetworkAgent::bind_detect_ptr = nullptr; func_set_server_callback NetworkAgent::set_server_callback_ptr = nullptr; @@ -110,7 +109,6 @@ func_modify_printer_name NetworkAgent::modify_printer_name_ptr = null func_get_camera_url NetworkAgent::get_camera_url_ptr = nullptr; func_get_design_staffpick NetworkAgent::get_design_staffpick_ptr = nullptr; func_start_pubilsh NetworkAgent::start_publish_ptr = nullptr; -func_get_profile_3mf NetworkAgent::get_profile_3mf_ptr = nullptr; func_get_model_publish_url NetworkAgent::get_model_publish_url_ptr = nullptr; func_get_model_mall_home_url NetworkAgent::get_model_mall_home_url_ptr = nullptr; func_get_model_mall_detail_url NetworkAgent::get_model_mall_detail_url_ptr = nullptr; @@ -288,7 +286,6 @@ int NetworkAgent::initialize_network_module(bool using_backup) ping_bind_ptr = reinterpret_cast(get_network_function("bambu_network_ping_bind")); bind_detect_ptr = reinterpret_cast(get_network_function("bambu_network_bind_detect")); set_server_callback_ptr = reinterpret_cast(get_network_function("bambu_network_set_server_callback")); - get_model_id_from_desgin_id_ptr = reinterpret_cast(get_network_function("bambu_network_get_model_id_from_desgin_id")); bind_ptr = reinterpret_cast(get_network_function("bambu_network_bind")); unbind_ptr = reinterpret_cast(get_network_function("bambu_network_unbind")); get_bambulab_host_ptr = reinterpret_cast(get_network_function("bambu_network_get_bambulab_host")); @@ -322,7 +319,6 @@ int NetworkAgent::initialize_network_module(bool using_backup) get_camera_url_ptr = reinterpret_cast(get_network_function("bambu_network_get_camera_url")); get_design_staffpick_ptr = reinterpret_cast(get_network_function("bambu_network_get_design_staffpick")); start_publish_ptr = reinterpret_cast(get_network_function("bambu_network_start_publish")); - get_profile_3mf_ptr = reinterpret_cast(get_network_function("bambu_network_get_profile_3mf")); get_model_publish_url_ptr = reinterpret_cast(get_network_function("bambu_network_get_model_publish_url")); get_subtask_ptr = reinterpret_cast(get_network_function("bambu_network_get_subtask")); get_model_mall_home_url_ptr = reinterpret_cast(get_network_function("bambu_network_get_model_mall_home_url")); @@ -409,7 +405,6 @@ int NetworkAgent::unload_network_module() build_login_cmd_ptr = nullptr; build_logout_cmd_ptr = nullptr; build_login_info_ptr = nullptr; - get_model_id_from_desgin_id_ptr = nullptr; ping_bind_ptr = nullptr; bind_ptr = nullptr; unbind_ptr = nullptr; @@ -443,7 +438,6 @@ int NetworkAgent::unload_network_module() get_camera_url_ptr = nullptr; get_design_staffpick_ptr = nullptr; start_publish_ptr = nullptr; - get_profile_3mf_ptr = nullptr; get_model_publish_url_ptr = nullptr; get_subtask_ptr = nullptr; get_model_mall_home_url_ptr = nullptr; @@ -1003,18 +997,6 @@ std::string NetworkAgent::build_login_info() return ret; } -int NetworkAgent::get_model_id_from_desgin_id(std::string& desgin_id, std::string& model_id) -{ - int ret = 0; - if (network_agent && get_model_id_from_desgin_id_ptr) { - ret = get_model_id_from_desgin_id_ptr(network_agent, desgin_id, model_id); - if (ret) - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, pin code=%3%") - % network_agent % ret % desgin_id; - } - return ret; -} - int NetworkAgent::ping_bind(std::string ping_code) { int ret = 0; @@ -1426,16 +1408,6 @@ int NetworkAgent::start_publish(PublishParams params, OnUpdateStatusFn update_fn return ret; } -int NetworkAgent::get_profile_3mf(BBLProfile* profile) -{ - int ret = -1; - if (network_agent && get_profile_3mf_ptr) { - ret = get_profile_3mf_ptr(network_agent, profile); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%") % network_agent % ret; - } - return ret; -} - int NetworkAgent::get_model_publish_url(std::string* url) { int ret = 0; diff --git a/src/slic3r/Utils/NetworkAgent.hpp b/src/slic3r/Utils/NetworkAgent.hpp index fc006c8e093..c889c33817f 100644 --- a/src/slic3r/Utils/NetworkAgent.hpp +++ b/src/slic3r/Utils/NetworkAgent.hpp @@ -53,7 +53,6 @@ typedef std::string (*func_get_user_nickanme)(void *agent); typedef std::string (*func_build_login_cmd)(void *agent); typedef std::string (*func_build_logout_cmd)(void *agent); typedef std::string (*func_build_login_info)(void *agent); -typedef int (*func_get_model_id_from_desgin_id)(void *agent, std::string& desgin_id, std::string& model_id); typedef int (*func_ping_bind)(void *agent, std::string ping_code); typedef int (*func_bind_detect)(void *agent, std::string dev_ip, std::string sec_link, detectResult& detect); typedef int (*func_set_server_callback)(void *agent, OnServerErrFn fn); @@ -90,7 +89,6 @@ typedef int (*func_modify_printer_name)(void *agent, std::string dev_id, std::st typedef int (*func_get_camera_url)(void *agent, std::string dev_id, std::function callback); typedef int (*func_get_design_staffpick)(void *agent, int offset, int limit, std::function callback); typedef int (*func_start_pubilsh)(void *agent, PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out); -typedef int (*func_get_profile_3mf)(void *agent, BBLProfile* profile); typedef int (*func_get_model_publish_url)(void *agent, std::string* url); typedef int (*func_get_subtask)(void *agent, BBLModelTask* task, OnGetSubTaskFn getsub_fn); typedef int (*func_get_model_mall_home_url)(void *agent, std::string* url); @@ -172,7 +170,6 @@ class NetworkAgent std::string build_login_cmd(); std::string build_logout_cmd(); std::string build_login_info(); - int get_model_id_from_desgin_id(std::string& desgin_id, std::string& model_id); int ping_bind(std::string ping_code); int bind_detect(std::string dev_ip, std::string sec_link, detectResult& detect); int set_server_callback(OnServerErrFn fn); @@ -209,7 +206,6 @@ class NetworkAgent int get_camera_url(std::string dev_id, std::function callback); int get_design_staffpick(int offset, int limit, std::function callback); int start_publish(PublishParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, std::string* out); - int get_profile_3mf(BBLProfile* profile); int get_model_publish_url(std::string* url); int get_subtask(BBLModelTask* task, OnGetSubTaskFn getsub_fn); int get_model_mall_home_url(std::string* url); @@ -281,7 +277,6 @@ class NetworkAgent static func_build_login_cmd build_login_cmd_ptr; static func_build_logout_cmd build_logout_cmd_ptr; static func_build_login_info build_login_info_ptr; - static func_get_model_id_from_desgin_id get_model_id_from_desgin_id_ptr; static func_ping_bind ping_bind_ptr; static func_bind_detect bind_detect_ptr; static func_set_server_callback set_server_callback_ptr; @@ -318,7 +313,6 @@ class NetworkAgent static func_get_camera_url get_camera_url_ptr; static func_get_design_staffpick get_design_staffpick_ptr; static func_start_pubilsh start_publish_ptr; - static func_get_profile_3mf get_profile_3mf_ptr; static func_get_model_publish_url get_model_publish_url_ptr; static func_get_subtask get_subtask_ptr; static func_get_model_mall_home_url get_model_mall_home_url_ptr; From aef4dba5122643d845ba6f96b15d03301e59be0f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 26 Apr 2025 17:44:04 +0800 Subject: [PATCH 002/127] Support both old and new version of BBL network plugin --- src/slic3r/CMakeLists.txt | 1 + src/slic3r/GUI/DeviceManager.cpp | 23 +++-- src/slic3r/GUI/DeviceManager.hpp | 6 +- src/slic3r/GUI/GUI_App.cpp | 4 +- src/slic3r/Utils/NetworkAgent.cpp | 121 +++++++++++++++++++++++--- src/slic3r/Utils/NetworkAgent.hpp | 16 +++- src/slic3r/Utils/bambu_networking.hpp | 60 ++++++++++++- 7 files changed, 204 insertions(+), 27 deletions(-) diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 628aab75b51..db7ecef38fd 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -574,6 +574,7 @@ set(SLIC3R_GUI_SOURCES Utils/ElegooLink.hpp Utils/ElegooLink.cpp Utils/WebSocketClient.hpp + Utils/bambu_networking.hpp ) if (WIN32) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index e1618ac2c06..e5c7dac1afc 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -2623,29 +2623,38 @@ bool MachineObject::is_camera_busy_off() return false; } -int MachineObject::publish_json(std::string json_str, int qos) +int MachineObject::publish_json(std::string json_str, int qos, int flag) { + int rtn = 0; if (is_lan_mode_printer()) { - return local_publish_json(json_str, qos); + rtn = local_publish_json(json_str, qos, flag); } else { - return cloud_publish_json(json_str, qos); + rtn = cloud_publish_json(json_str, qos, flag); } + + if (rtn == 0) { + BOOST_LOG_TRIVIAL(info) << "publish_json: " << json_str << " code: " << rtn; + } else { + BOOST_LOG_TRIVIAL(error) << "publish_json: " << json_str << " code: " << rtn; + } + + return rtn; } -int MachineObject::cloud_publish_json(std::string json_str, int qos) +int MachineObject::cloud_publish_json(std::string json_str, int qos, int flag) { int result = -1; if (m_agent) - result = m_agent->send_message(dev_id, json_str, qos); + result = m_agent->send_message(dev_id, json_str, qos, flag); return result; } -int MachineObject::local_publish_json(std::string json_str, int qos) +int MachineObject::local_publish_json(std::string json_str, int qos, int flag) { int result = -1; if (m_agent) { - result = m_agent->send_message_to_printer(dev_id, json_str, qos); + result = m_agent->send_message_to_printer(dev_id, json_str, qos, flag); } return result; } diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 0d86d3e2658..dce43fd9625 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -958,9 +958,9 @@ class MachineObject /* Msg for display MsgFn */ typedef std::function MsgFn; - int publish_json(std::string json_str, int qos = 0); - int cloud_publish_json(std::string json_str, int qos = 0); - int local_publish_json(std::string json_str, int qos = 0); + int publish_json(std::string json_str, int qos = 0, int flag = 0); + int cloud_publish_json(std::string json_str, int qos = 0, int flag = 0); + int local_publish_json(std::string json_str, int qos = 0, int flag = 0); int parse_json(std::string payload, bool key_filed_only = false); int publish_gcode(std::string gcode_str); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index dbbf21ad2d3..d9818d9f626 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1166,7 +1166,7 @@ std::string GUI_App::get_plugin_url(std::string name, std::string country_code) { std::string url = get_http_url(country_code); - std::string curr_version = SLIC3R_VERSION; + std::string curr_version = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BAMBU_NETWORK_AGENT_VERSION; std::string using_version = curr_version.substr(0, 9) + "00"; if (name == "cameratools") using_version = curr_version.substr(0, 6) + "00.00"; @@ -1542,7 +1542,7 @@ bool GUI_App::check_networking_version() if (!network_ver.empty()) { BOOST_LOG_TRIVIAL(info) << "get_network_agent_version=" << network_ver; } - std::string studio_ver = SLIC3R_VERSION; + std::string studio_ver = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BAMBU_NETWORK_AGENT_VERSION; if (network_ver.length() >= 8) { if (network_ver.substr(0,8) == studio_ver.substr(0,8)) { m_networking_compatible = true; diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 9eae4ea4345..eb80e952177 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -26,6 +26,15 @@ static void* netwoking_module = NULL; static void* source_module = NULL; #endif +bool NetworkAgent::use_legacy_network = true; + +typedef int (*func_start_print_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); +typedef int (*func_start_local_print_with_record_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); +typedef int (*func_start_send_gcode_to_sdcard_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn); +typedef int (*func_start_local_print_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn); +typedef int (*func_start_sdcard_print_legacy)(void* agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn); +typedef int (*func_send_message_legacy)(void* agent, std::string dev_id, std::string json_str, int qos); +typedef int (*func_send_message_to_printer_legacy)(void* agent, std::string dev_id, std::string json_str, int qos); func_check_debug_consistent NetworkAgent::check_debug_consistent_ptr = nullptr; func_get_version NetworkAgent::get_version_ptr = nullptr; @@ -62,6 +71,8 @@ func_send_message NetworkAgent::send_message_ptr = nullptr; func_connect_printer NetworkAgent::connect_printer_ptr = nullptr; func_disconnect_printer NetworkAgent::disconnect_printer_ptr = nullptr; func_send_message_to_printer NetworkAgent::send_message_to_printer_ptr = nullptr; +func_check_cert NetworkAgent::check_cert_ptr = nullptr; +func_install_device_cert NetworkAgent::install_device_cert_ptr = nullptr; func_start_discovery NetworkAgent::start_discovery_ptr = nullptr; func_change_user NetworkAgent::change_user_ptr = nullptr; func_is_user_login NetworkAgent::is_user_login_ptr = nullptr; @@ -128,6 +139,47 @@ func_get_model_mall_rating_result NetworkAgent::get_model_mall_rating_result_p func_get_mw_user_preference NetworkAgent::get_mw_user_preference_ptr = nullptr; func_get_mw_user_4ulist NetworkAgent::get_mw_user_4ulist_ptr = nullptr; +static PrintParams_Legacy as_legacy(PrintParams& param) +{ + PrintParams_Legacy l; + + l.dev_id = std::move(param.dev_id); + l.task_name = std::move(param.task_name); + l.project_name = std::move(param.project_name); + l.preset_name = std::move(param.preset_name); + l.filename = std::move(param.filename); + l.config_filename = std::move(param.config_filename); + l.plate_index = param.plate_index; + l.ftp_folder = std::move(param.ftp_folder); + l.ftp_file = std::move(param.ftp_file); + l.ftp_file_md5 = std::move(param.ftp_file_md5); + l.ams_mapping = std::move(param.ams_mapping); + l.ams_mapping_info = std::move(param.ams_mapping_info); + l.connection_type = std::move(param.connection_type); + l.comments = std::move(param.comments); + l.origin_profile_id = param.origin_profile_id; + l.stl_design_id = param.stl_design_id; + l.origin_model_id = std::move(param.origin_model_id); + l.print_type = std::move(param.print_type); + l.dst_file = std::move(param.dst_file); + l.dev_name = std::move(param.dev_name); + l.dev_ip = std::move(param.dev_ip); + l.use_ssl_for_ftp = param.use_ssl_for_ftp; + l.use_ssl_for_mqtt = param.use_ssl_for_mqtt; + l.username = std::move(param.username); + l.password = std::move(param.password); + l.task_bed_leveling = param.task_bed_leveling; + l.task_flow_cali = param.task_flow_cali; + l.task_vibration_cali = param.task_vibration_cali; + l.task_layer_inspect = param.task_layer_inspect; + l.task_record_timelapse = param.task_record_timelapse; + l.task_use_ams = param.task_use_ams; + l.task_bed_type = std::move(param.task_bed_type); + l.extra_options = std::move(param.extra_options); + + return l; +} + NetworkAgent::NetworkAgent(std::string log_dir) { if (create_agent_ptr) { @@ -159,7 +211,7 @@ std::string NetworkAgent::get_libpath_in_current_directory(std::string library_n std::string file_name_string(size_needed, 0); ::WideCharToMultiByte(0, 0, file_name, wcslen(file_name), file_name_string.data(), size_needed, nullptr, nullptr); - std::size_t found = file_name_string.find("bambu-studio.exe"); + std::size_t found = file_name_string.find("orca-slicer.exe"); if (found == (file_name_string.size() - 16)) { lib_path = library_name + ".dll"; lib_path = file_name_string.replace(found, 16, lib_path); @@ -272,6 +324,8 @@ int NetworkAgent::initialize_network_module(bool using_backup) connect_printer_ptr = reinterpret_cast(get_network_function("bambu_network_connect_printer")); disconnect_printer_ptr = reinterpret_cast(get_network_function("bambu_network_disconnect_printer")); send_message_to_printer_ptr = reinterpret_cast(get_network_function("bambu_network_send_message_to_printer")); + check_cert_ptr = reinterpret_cast(get_network_function("bambu_network_update_cert")); + install_device_cert_ptr = reinterpret_cast(get_network_function("bambu_network_install_device_cert")); start_discovery_ptr = reinterpret_cast(get_network_function("bambu_network_start_discovery")); change_user_ptr = reinterpret_cast(get_network_function("bambu_network_change_user")); is_user_login_ptr = reinterpret_cast(get_network_function("bambu_network_is_user_login")); @@ -394,6 +448,7 @@ int NetworkAgent::unload_network_module() connect_printer_ptr = nullptr; disconnect_printer_ptr = nullptr; send_message_to_printer_ptr = nullptr; + check_cert_ptr = nullptr; start_discovery_ptr = nullptr; change_user_ptr = nullptr; is_user_login_ptr = nullptr; @@ -847,11 +902,15 @@ int NetworkAgent::stop_device_subscribe() return ret; } -int NetworkAgent::send_message(std::string dev_id, std::string json_str, int qos) +int NetworkAgent::send_message(std::string dev_id, std::string json_str, int qos, int flag) { int ret = 0; if (network_agent && send_message_ptr) { - ret = send_message_ptr(network_agent, dev_id, json_str, qos); + if (use_legacy_network) { + ret = (reinterpret_cast(send_message_ptr))(network_agent, dev_id, json_str, qos); + } else { + ret = send_message_ptr(network_agent, dev_id, json_str, qos, flag); + } if (ret) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_id=%3%, json_str=%4%, qos=%5%")%network_agent %ret %dev_id %json_str %qos; } @@ -881,11 +940,15 @@ int NetworkAgent::disconnect_printer() return ret; } -int NetworkAgent::send_message_to_printer(std::string dev_id, std::string json_str, int qos) +int NetworkAgent::send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) { int ret = 0; if (network_agent && send_message_to_printer_ptr) { - ret = send_message_to_printer_ptr(network_agent, dev_id, json_str, qos); + if (use_legacy_network) { + ret = (reinterpret_cast(send_message_to_printer_ptr))(network_agent, dev_id, json_str, qos); + } else { + ret = send_message_to_printer_ptr(network_agent, dev_id, json_str, qos, flag); + } if (ret) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_id=%3%, json_str=%4%, qos=%5%") %network_agent %ret %dev_id %json_str %qos; @@ -893,6 +956,24 @@ int NetworkAgent::send_message_to_printer(std::string dev_id, std::string json_s return ret; } +int NetworkAgent::check_cert() +{ + int ret = 0; + if (network_agent && check_cert_ptr) { + ret = check_cert_ptr(network_agent); + if (ret) + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%") % network_agent % ret; + } + return ret; +} + +void NetworkAgent::install_device_cert(std::string dev_id, bool lan_only) +{ + if (network_agent && install_device_cert_ptr) { + install_device_cert_ptr(network_agent, dev_id, lan_only); + } +} + bool NetworkAgent::start_discovery(bool start, bool sending) { bool ret = false; @@ -1089,7 +1170,11 @@ int NetworkAgent::start_print(PrintParams params, OnUpdateStatusFn update_fn, Wa { int ret = 0; if (network_agent && start_print_ptr) { - ret = start_print_ptr(network_agent, params, update_fn, cancel_fn, wait_fn); + if (use_legacy_network) { + ret = (reinterpret_cast(start_print_ptr))(network_agent, as_legacy(params), update_fn, cancel_fn, wait_fn); + } else { + ret = start_print_ptr(network_agent, params, update_fn, cancel_fn, wait_fn); + } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%") %network_agent %ret %params.dev_id %params.task_name %params.project_name; } @@ -1100,7 +1185,11 @@ int NetworkAgent::start_local_print_with_record(PrintParams params, OnUpdateStat { int ret = 0; if (network_agent && start_local_print_with_record_ptr) { - ret = start_local_print_with_record_ptr(network_agent, params, update_fn, cancel_fn, wait_fn); + if (use_legacy_network) { + ret = (reinterpret_cast(start_local_print_with_record_ptr))(network_agent, as_legacy(params), update_fn, cancel_fn, wait_fn); + } else { + ret = start_local_print_with_record_ptr(network_agent, params, update_fn, cancel_fn, wait_fn); + } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%") %network_agent %ret %params.dev_id %params.task_name %params.project_name; } @@ -1111,7 +1200,11 @@ int NetworkAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStatusF { int ret = 0; if (network_agent && start_send_gcode_to_sdcard_ptr) { - ret = start_send_gcode_to_sdcard_ptr(network_agent, params, update_fn, cancel_fn, wait_fn); + if (use_legacy_network) { + ret = (reinterpret_cast(start_send_gcode_to_sdcard_ptr))(network_agent, as_legacy(params), update_fn, cancel_fn, wait_fn); + } else { + ret = start_send_gcode_to_sdcard_ptr(network_agent, params, update_fn, cancel_fn, wait_fn); + } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%") % network_agent % ret % params.dev_id % params.task_name % params.project_name; } @@ -1122,7 +1215,11 @@ int NetworkAgent::start_local_print(PrintParams params, OnUpdateStatusFn update_ { int ret = 0; if (network_agent && start_local_print_ptr) { - ret = start_local_print_ptr(network_agent, params, update_fn, cancel_fn); + if (use_legacy_network) { + ret = (reinterpret_cast(start_local_print_ptr))(network_agent, as_legacy(params), update_fn, cancel_fn); + } else { + ret = start_local_print_ptr(network_agent, params, update_fn, cancel_fn); + } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%") %network_agent %ret %params.dev_id %params.task_name %params.project_name; } @@ -1133,7 +1230,11 @@ int NetworkAgent::start_sdcard_print(PrintParams params, OnUpdateStatusFn update { int ret = 0; if (network_agent && start_sdcard_print_ptr) { - ret = start_sdcard_print_ptr(network_agent, params, update_fn, cancel_fn); + if (use_legacy_network) { + ret = (reinterpret_cast(start_sdcard_print_ptr))(network_agent, as_legacy(params), update_fn, cancel_fn); + } else { + ret = start_sdcard_print_ptr(network_agent, params, update_fn, cancel_fn); + } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%") % network_agent % ret % params.dev_id % params.task_name % params.project_name; } diff --git a/src/slic3r/Utils/NetworkAgent.hpp b/src/slic3r/Utils/NetworkAgent.hpp index c889c33817f..fe5d155e7be 100644 --- a/src/slic3r/Utils/NetworkAgent.hpp +++ b/src/slic3r/Utils/NetworkAgent.hpp @@ -38,10 +38,12 @@ typedef int (*func_del_subscribe)(void *agent, std::vector dev_list typedef void (*func_enable_multi_machine)(void *agent, bool enable); typedef int (*func_start_device_subscribe)(void* agent); typedef int (*func_stop_device_subscribe)(void* agent); -typedef int (*func_send_message)(void *agent, std::string dev_id, std::string json_str, int qos); +typedef int (*func_send_message)(void *agent, std::string dev_id, std::string json_str, int qos, int flag); typedef int (*func_connect_printer)(void *agent, std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); typedef int (*func_disconnect_printer)(void *agent); -typedef int (*func_send_message_to_printer)(void *agent, std::string dev_id, std::string json_str, int qos); +typedef int (*func_send_message_to_printer)(void *agent, std::string dev_id, std::string json_str, int qos, int flag); +typedef int (*func_check_cert)(void* agent); +typedef void (*func_install_device_cert)(void* agent, std::string dev_id, bool lan_only); typedef bool (*func_start_discovery)(void *agent, bool start, bool sending); typedef int (*func_change_user)(void *agent, std::string user_info); typedef bool (*func_is_user_login)(void *agent); @@ -110,6 +112,7 @@ typedef int (*func_get_model_mall_rating_result)(void *agent, int job_id, std::s typedef int (*func_get_mw_user_preference)(void *agent, std::function callback); typedef int (*func_get_mw_user_4ulist)(void *agent, int seed, int limit, std::function callback); + //the NetworkAgent class class NetworkAgent { @@ -125,6 +128,7 @@ class NetworkAgent #endif static std::string get_version(); static void* get_network_function(const char* name); + static bool use_legacy_network; NetworkAgent(std::string log_dir); ~NetworkAgent(); @@ -155,10 +159,12 @@ class NetworkAgent void enable_multi_machine(bool enable); int start_device_subscribe(); int stop_device_subscribe(); - int send_message(std::string dev_id, std::string json_str, int qos); + int send_message(std::string dev_id, std::string json_str, int qos, int flag); int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); int disconnect_printer(); - int send_message_to_printer(std::string dev_id, std::string json_str, int qos); + int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag); + int check_cert(); + void install_device_cert(std::string dev_id, bool lan_only); bool start_discovery(bool start, bool sending); int change_user(std::string user_info); bool is_user_login(); @@ -266,6 +272,8 @@ class NetworkAgent static func_connect_printer connect_printer_ptr; static func_disconnect_printer disconnect_printer_ptr; static func_send_message_to_printer send_message_to_printer_ptr; + static func_check_cert check_cert_ptr; + static func_install_device_cert install_device_cert_ptr; static func_start_discovery start_discovery_ptr; static func_change_user change_user_ptr; static func_is_user_login is_user_login_ptr; diff --git a/src/slic3r/Utils/bambu_networking.hpp b/src/slic3r/Utils/bambu_networking.hpp index 0c7b4fddb12..1ccf786bbc0 100644 --- a/src/slic3r/Utils/bambu_networking.hpp +++ b/src/slic3r/Utils/bambu_networking.hpp @@ -36,6 +36,7 @@ namespace BBL { #define BAMBU_NETWORK_ERR_PARSE_CONFIG_FAILED -23 #define BAMBU_NETWORK_ERR_NO_CORRESPONDING_BUCKET -24 #define BAMBU_NETWORK_ERR_GET_INSTANCE_ID_FAILED -25 +#define BAMBU_NETWORK_SIGNED_ERROR -26 //bind error #define BAMBU_NETWORK_ERR_BIND_CREATE_SOCKET_FAILED -1010 //failed to create socket @@ -78,6 +79,7 @@ namespace BBL { #define BAMBU_NETWORK_ERR_PRINT_SP_PATCH_PROJECT_FAILED -3110 //failed to patch project #define BAMBU_NETWORK_ERR_PRINT_SP_POST_TASK_FAILED -3120 //failed to post task #define BAMBU_NETWORK_ERR_PRINT_SP_WAIT_PRINTER_FAILED -3130 //failed to wait the ack from printer +#define BAMBU_NETOWRK_ERR_PRINT_SP_ENC_FLAG_NOT_READY -3140 //enc parse not ready //start_local_print error #define BAMBU_NETWORK_ERR_PRINT_LP_FILE_OVER_SIZE -4010 //the size of the uploaded file cannot exceed 1 GB @@ -95,7 +97,8 @@ namespace BBL { #define BAMBU_NETWORK_LIBRARY "bambu_networking" #define BAMBU_NETWORK_AGENT_NAME "bambu_network_agent" -#define BAMBU_NETWORK_AGENT_VERSION "01.10.01.01" +#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.01" +#define BAMBU_NETWORK_AGENT_VERSION "02.00.02.50" //iot preset type strings #define IOT_PRINTER_TYPE_STRING "printer" @@ -186,6 +189,48 @@ struct detectResult { std::string connect_type; }; +/* print job*/ +struct PrintParams_Legacy { + /* basic info */ + std::string dev_id; + std::string task_name; + std::string project_name; + std::string preset_name; + std::string filename; + std::string config_filename; + int plate_index; + std::string ftp_folder; + std::string ftp_file; + std::string ftp_file_md5; + std::string ams_mapping; + std::string ams_mapping_info; + std::string connection_type; + std::string comments; + int origin_profile_id = 0; + int stl_design_id = 0; + std::string origin_model_id; + std::string print_type; + std::string dst_file; + std::string dev_name; + + /* access options */ + std::string dev_ip; + bool use_ssl_for_ftp; + bool use_ssl_for_mqtt; + std::string username; + std::string password; + + /*user options */ + bool task_bed_leveling; /* bed leveling of task */ + bool task_flow_cali; /* flow calibration of task */ + bool task_vibration_cali; /* vibration calibration of task */ + bool task_layer_inspect; /* first layer inspection of task */ + bool task_record_timelapse; /* record timelapse of task */ + bool task_use_ams; + std::string task_bed_type; + std::string extra_options; +}; + /* print job*/ struct PrintParams { /* basic info */ @@ -200,7 +245,9 @@ struct PrintParams { std::string ftp_file; std::string ftp_file_md5; std::string ams_mapping; + std::string ams_mapping2; std::string ams_mapping_info; + std::string nozzles_info; std::string connection_type; std::string comments; int origin_profile_id = 0; @@ -226,6 +273,9 @@ struct PrintParams { bool task_use_ams; std::string task_bed_type; std::string extra_options; + int auto_bed_leveling{ 0 }; + int auto_flow_cali{ 0 }; + int auto_offset_cali{ 0 }; }; struct TaskQueryParams @@ -253,6 +303,14 @@ struct CertificateInformation { std::string serial_number; }; + +enum class MessageFlag : int +{ + MSG_FLAG_NONE = 0, + MSG_SIGN = 1 << 0, + MSG_ENCRYPT = 1 << 1, +}; + } #endif From 12d5ffb8e5b6d3a7ac8f64d202798e4f7de9e523 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 1 May 2025 14:00:52 +0800 Subject: [PATCH 003/127] Store dummy filament map data in bbl 3mf --- src/libslic3r/Format/bbs_3mf.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 38f4f34307e..ca519db49be 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -291,6 +291,8 @@ static constexpr const char* FIRST_LAYER_PRINT_SEQUENCE_ATTR = "first_layer_prin static constexpr const char* OTHER_LAYERS_PRINT_SEQUENCE_ATTR = "other_layers_print_sequence"; static constexpr const char* OTHER_LAYERS_PRINT_SEQUENCE_NUMS_ATTR = "other_layers_print_sequence_nums"; static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode"; +static constexpr const char* FILAMENT_MAP_MODE_ATTR = "filament_map_mode"; +static constexpr const char* FILAMENT_MAP_ATTR = "filament_maps"; static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; static constexpr const char* NO_LIGHT_THUMBNAIL_FILE_ATTR = "thumbnail_no_light_file"; @@ -5598,7 +5600,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _add_project_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config, Model& model); //BBS: add project embedded preset files bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector project_presets); - bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false); + bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false); bool _add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model); bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config); bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr); @@ -6114,7 +6116,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // This file contains all the attributes of all ModelObjects and their ModelVolumes (names, parameter overrides). // As there is just a single Indexed Triangle Set data stored per ModelObject, offsets of volumes into their respective Indexed Triangle Set data // is stored here as well. - if (!_add_model_config_file_to_archive(archive, model, plate_data_list, objects_data, export_plate_idx, m_save_gcode, m_use_loaded_id)) { + if (!_add_model_config_file_to_archive(archive, model, plate_data_list, objects_data, *config, export_plate_idx, m_save_gcode, m_use_loaded_id)) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_model_config_file_to_archive failed\n"); return false; } @@ -7445,7 +7447,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx, bool save_gcode, bool use_loaded_id) + bool _BBS_3MF_Exporter::_add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config, int export_plate_idx, bool save_gcode, bool use_loaded_id) { std::stringstream stream; // Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back @@ -7625,6 +7627,20 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (spiral_mode_opt) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SPIRAL_VASE_MODE << "\" " << VALUE_ATTR << "=\"" << spiral_mode_opt->getBool() << "\"/>\n"; + // TODO: Orca: hack + //filament map related + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << FILAMENT_MAP_MODE_ATTR << "\" " << VALUE_ATTR << "=\"" << "Auto For Flush" << "\"/>\n"; + + // filament map override global settings only when group mode overrides the global settings + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << FILAMENT_MAP_ATTR << "\" " << VALUE_ATTR << "=\""; + const size_t filaments_count = dynamic_cast(config.option("filament_colour"))->values.size(); + for (int i = 0; i < filaments_count; ++i) { + stream << "1"; // Orca hack: for now, all filaments are mapped to extruder 1 + if (i != (filaments_count - 1)) + stream << " "; + } + stream << "\"/>\n"; + if (save_gcode) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << GCODE_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << xml_escape(plate_data->gcode_file) << "\"/>\n"; if (!plate_data->gcode_file.empty()) { @@ -7793,6 +7809,16 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SUPPORT_USED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_support_used << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << LABEL_OBJECT_ENABLED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_label_object_enabled << "\"/>\n"; + // TODO: Orca: hack + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << FILAMENT_MAP_ATTR << "\" " << VALUE_ATTR << "=\""; + const size_t filaments_count = dynamic_cast(config.option("filament_colour"))->values.size(); + for (int i = 0; i < filaments_count; ++i) { + stream << "1"; // Orca hack: for now, all filaments are mapped to extruder 1 + if (i != (filaments_count - 1)) + stream << " "; + } + stream << "\"/>\n"; + for (auto it = plate_data->objects_and_instances.begin(); it != plate_data->objects_and_instances.end(); it++) { int obj_id = it->first; From 7fe421b1b3920bed5837e0a4dcd5114bfcde3e55 Mon Sep 17 00:00:00 2001 From: tao wang Date: Fri, 7 Jun 2024 14:18:05 +0800 Subject: [PATCH 004/127] ENH:support new amsmapping data jira:[for 2 extruder] Change-Id: Ie03eae17d600bc68451511a0179f20d1919ff6ea (cherry picked from commit 0848c26da97c7b74e98645b9a0873fe928fdf631) --- src/libslic3r/ProjectTask.hpp | 4 +++ src/slic3r/GUI/DeviceManager.cpp | 50 ++++++++++++++++++++++---------- src/slic3r/GUI/Jobs/PrintJob.cpp | 1 + src/slic3r/GUI/Jobs/PrintJob.hpp | 1 + src/slic3r/GUI/SelectMachine.cpp | 40 ++++++++++++++++++++----- src/slic3r/GUI/SelectMachine.hpp | 2 +- 6 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/libslic3r/ProjectTask.hpp b/src/libslic3r/ProjectTask.hpp index 05f39f9b2c9..ef2033eefdc 100644 --- a/src/libslic3r/ProjectTask.hpp +++ b/src/libslic3r/ProjectTask.hpp @@ -49,6 +49,10 @@ struct FilamentInfo int ctype = 0; std::vector colors = std::vector(); int mapping_result = 0; + + /*for new ams mapping*/ + std::string ams_id; + std::string slot_id; }; class BBLSliceInfo { diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index e5c7dac1afc..455f023f369 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -810,6 +810,9 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std // tray_index : tray_color std::map tray_filaments; for (auto ams = amsList.begin(); ams != amsList.end(); ams++) { + + std::string ams_id = ams->second->id; + for (auto tray = ams->second->trayList.begin(); tray != ams->second->trayList.end(); tray++) { int ams_id = atoi(ams->first.c_str()); int tray_id = atoi(tray->first.c_str()); @@ -828,6 +831,11 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std info.filament_id = tray->second->setting_id; info.ctype = tray->second->ctype; info.colors = tray->second->cols; + + /*for new ams mapping*/ + info.ams_id = ams->first.c_str(); + info.slot_id = tray->first.c_str(); + tray_filaments.emplace(std::make_pair(tray_index, info)); } } @@ -835,27 +843,28 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std // tray info list std::vector tray_info_list; - for (auto it = amsList.begin(); it != amsList.end(); it++) { - for (int i = 0; i < 4; i++) { + int flament_index_id = 0; + for (auto ams = amsList.begin(); ams != amsList.end(); ams++) { + for (auto tray = ams->second->trayList.begin(); tray != ams->second->trayList.end(); tray++) { + FilamentInfo info; - auto tray_it = it->second->trayList.find(std::to_string(i)); - if (tray_it != it->second->trayList.end()) { - info.id = atoi(tray_it->first.c_str()) + atoi(it->first.c_str()) * 4; - info.tray_id = atoi(tray_it->first.c_str()) + atoi(it->first.c_str()) * 4; - info.color = tray_it->second->color; - info.type = tray_it->second->get_filament_type(); - info.ctype = tray_it->second->ctype; - info.colors = tray_it->second->cols; - } - else { - info.id = -1; - info.tray_id = -1; - } + info.id = flament_index_id; + info.tray_id = flament_index_id; + info.color = tray->second->color; + info.type = tray->second->get_filament_type(); + info.ctype = tray->second->ctype; + info.colors = tray->second->cols; + + + /*for new ams mapping*/ + info.ams_id = ams->second->id; + info.slot_id = tray->second->id; + tray_info_list.push_back(info); + flament_index_id++; } } - // is_support_ams_mapping if (!is_support_ams_mapping()) { BOOST_LOG_TRIVIAL(info) << "ams_mapping: do not support, use order mapping"; @@ -987,6 +996,11 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std result[picked_src_idx].filament_id = tray->second.filament_id; result[picked_src_idx].ctype = tray->second.ctype; result[picked_src_idx].colors = tray->second.colors; + + + /*for new ams mapping*/ + result[picked_src_idx].ams_id = tray->second.ams_id; + result[picked_src_idx].slot_id = tray->second.slot_id; } else { FilamentInfo info; @@ -1028,6 +1042,10 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std result[i].type = tray_info_list[i].type; result[i].ctype = tray_info_list[i].ctype; result[i].colors = tray_info_list[i].colors; + + /*for new ams mapping*/ + result[i].ams_id = tray_info_list[i].ams_id; + result[i].slot_id = tray_info_list[i].slot_id; } } } diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index abcca932791..83a59672c62 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -231,6 +231,7 @@ void PrintJob::process(Ctl &ctl) params.task_layer_inspect = this->task_layer_inspect; params.task_record_timelapse= this->task_record_timelapse; params.ams_mapping = this->task_ams_mapping; + params.ams_mapping2 = this->task_ams_mapping2; params.ams_mapping_info = this->task_ams_mapping_info; params.connection_type = this->connection_type; params.task_use_ams = this->task_use_ams; diff --git a/src/slic3r/GUI/Jobs/PrintJob.hpp b/src/slic3r/GUI/Jobs/PrintJob.hpp index 7806a8623b5..9d7639aeb43 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.hpp +++ b/src/slic3r/GUI/Jobs/PrintJob.hpp @@ -61,6 +61,7 @@ class PrintJob : public Job std::string m_access_code; std::string task_bed_type; std::string task_ams_mapping; + std::string task_ams_mapping2; std::string task_ams_mapping_info; std::string connection_type; std::string m_print_type; diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 9c35d76f449..e7e893d4f80 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1840,8 +1840,9 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_) if (result == 0) { print_ams_mapping_result(m_ams_mapping_result); std::string ams_array; + std::string ams_array2; std::string mapping_info; - get_ams_mapping_result(ams_array, mapping_info); + get_ams_mapping_result(ams_array, ams_array2, mapping_info); if (ams_array.empty()) { reset_ams_material(); BOOST_LOG_TRIVIAL(info) << "ams_mapping_array=[]"; @@ -1867,7 +1868,7 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_) return true; } -bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, std::string &ams_mapping_info) +bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, std::string& mapping_array_str2, std::string &ams_mapping_info) { if (m_ams_mapping_result.empty()) return false; @@ -1884,17 +1885,28 @@ bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, if (invalid_count == m_ams_mapping_result.size()) { return false; } else { - json j = json::array(); - json mapping_info_json = json::array(); + + json mapping_v0_json = json::array(); + json mapping_v1_json = json::array(); + + json mapping_info_json = json::array(); for (int i = 0; i < wxGetApp().preset_bundle->filament_presets.size(); i++) { + int tray_id = -1; + + json mapping_item_v1; + mapping_item_v1["ams_id"] = 0xff; + mapping_item_v1["slot_id"] = 0xff; + json mapping_item; mapping_item["ams"] = tray_id; mapping_item["targetColor"] = ""; mapping_item["filamentId"] = ""; mapping_item["filamentType"] = ""; + + for (int k = 0; k < m_ams_mapping_result.size(); k++) { if (m_ams_mapping_result[k].id == i) { tray_id = m_ams_mapping_result[k].tray_id; @@ -1907,12 +1919,23 @@ bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, //convert #RRGGBB to RRGGBBAA mapping_item["sourceColor"] = m_filaments[k].color; mapping_item["targetColor"] = m_ams_mapping_result[k].color; + + + /*new ams mapping data*/ + + mapping_item_v1["ams_id"] = m_ams_mapping_result[k].ams_id; + mapping_item_v1["slot_id"] = m_ams_mapping_result[k].slot_id; } } - j.push_back(tray_id); + mapping_v0_json.push_back(tray_id); + mapping_v1_json.push_back(mapping_item_v1); mapping_info_json.push_back(mapping_item); } - mapping_array_str = j.dump(); + + + mapping_array_str = mapping_v0_json.dump(); + mapping_array_str2 = mapping_v1_json.dump(); + ams_mapping_info = mapping_info_json.dump(); return valid_mapping_result; } @@ -2745,9 +2768,10 @@ void SelectMachineDialog::on_send_print() // get ams_mapping_result std::string ams_mapping_array; + std::string ams_mapping_array2; std::string ams_mapping_info; if (m_checkbox_list["use_ams"]->GetValue()) - get_ams_mapping_result(ams_mapping_array, ams_mapping_info); + get_ams_mapping_result(ams_mapping_array,ams_mapping_array2, ams_mapping_info); else { json mapping_info_json = json::array(); json item; @@ -2840,9 +2864,11 @@ void SelectMachineDialog::on_send_print() if (obj_->is_support_ams_mapping()) { m_print_job->task_ams_mapping = ams_mapping_array; + m_print_job->task_ams_mapping2= ams_mapping_array2; m_print_job->task_ams_mapping_info = ams_mapping_info; } else { m_print_job->task_ams_mapping = ""; + m_print_job->task_ams_mapping2 = ""; m_print_job->task_ams_mapping_info = ""; } diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index 6752e2a8691..a399ca7930e 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -530,7 +530,7 @@ class SelectMachineDialog : public DPIDialog void set_print_type(PrintFromType type) {m_print_type = type;}; bool Show(bool show); bool do_ams_mapping(MachineObject* obj_); - bool get_ams_mapping_result(std::string& mapping_array_str, std::string& ams_mapping_info); + bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info); PrintFromType get_print_type() {return m_print_type;}; wxString format_steel_name(std::string name); From e4d8c2e4408cc4deb59ad02859330e0f619547c4 Mon Sep 17 00:00:00 2001 From: tao wang Date: Tue, 18 Jun 2024 20:09:11 +0800 Subject: [PATCH 005/127] NEW:support new mapping type jira:[support new mapping] Change-Id: I88e5d3b6966d4ed1e8098d13fe9335fecf6e01c4 (cherry picked from commit c0932e16ff9fcae0e900c6e0cac9a5b496d0cc0e) --- resources/images/rename_edit.svg | 10 + src/slic3r/GUI/AmsMappingPopup.cpp | 158 ++++---- src/slic3r/GUI/AmsMappingPopup.hpp | 9 + src/slic3r/GUI/DeviceManager.cpp | 55 ++- src/slic3r/GUI/DeviceManager.hpp | 29 +- src/slic3r/GUI/SelectMachine.cpp | 599 +++++++++++++++++------------ src/slic3r/GUI/SelectMachine.hpp | 47 ++- 7 files changed, 560 insertions(+), 347 deletions(-) create mode 100644 resources/images/rename_edit.svg diff --git a/resources/images/rename_edit.svg b/resources/images/rename_edit.svg new file mode 100644 index 00000000000..03e40f40c7b --- /dev/null +++ b/resources/images/rename_edit.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/slic3r/GUI/AmsMappingPopup.cpp b/src/slic3r/GUI/AmsMappingPopup.cpp index 3403f1ec518..2b233aba0e7 100644 --- a/src/slic3r/GUI/AmsMappingPopup.cpp +++ b/src/slic3r/GUI/AmsMappingPopup.cpp @@ -286,19 +286,19 @@ void MaterialItem::doRender(wxDC &dc) AmsMapingPopup::AmsMapingPopup(wxWindow *parent) : PopupWindow(parent, wxBORDER_NONE) { - SetSize(wxSize(FromDIP(252), -1)); - SetMinSize(wxSize(FromDIP(252), -1)); - SetMaxSize(wxSize(FromDIP(252), -1)); Bind(wxEVT_PAINT, &AmsMapingPopup::paintEvent, this); - #if __APPLE__ Bind(wxEVT_LEFT_DOWN, &AmsMapingPopup::on_left_down, this); #endif SetBackgroundColour(*wxWHITE); - m_sizer_main = new wxBoxSizer(wxVERTICAL); - //m_sizer_main->Add(0, 0, 1, wxEXPAND, 0); + + m_sizer_main = new wxBoxSizer(wxVERTICAL); + m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); + m_sizer_ams_left = new wxBoxSizer(wxVERTICAL); + m_sizer_ams_right = new wxBoxSizer(wxVERTICAL); + auto title_panel = new wxPanel(this, wxID_ANY); title_panel->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); @@ -307,7 +307,6 @@ void MaterialItem::doRender(wxDC &dc) wxBoxSizer *title_sizer_h= new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer *title_sizer_v = new wxBoxSizer(wxVERTICAL); auto title_text = new wxStaticText(title_panel, wxID_ANY, _L("AMS Slots")); @@ -319,19 +318,15 @@ void MaterialItem::doRender(wxDC &dc) title_panel->Layout(); title_panel->Fit(); - m_sizer_list = new wxBoxSizer(wxVERTICAL); - for (auto i = 0; i < AMS_TOTAL_COUNT; i++) { - auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL); - /*auto ams_mapping_item_container = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ams_mapping_container", this, 78), wxDefaultPosition, - wxSize(FromDIP(230), FromDIP(78)), 0);*/ - auto ams_mapping_item_container = new MappingContainer(this); - ams_mapping_item_container->SetSizer(sizer_mapping_list); - ams_mapping_item_container->Layout(); - //ams_mapping_item_container->Hide(); - m_amsmapping_container_sizer_list.push_back(sizer_mapping_list); - m_amsmapping_container_list.push_back(ams_mapping_item_container); - m_sizer_list->Add(ams_mapping_item_container, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxBOTTOM, FromDIP(5)); - } + auto left_ams_title_text = new wxStaticText(this, wxID_ANY, _L("Left Ams")); + auto right_ams_title_text = new wxStaticText(this, wxID_ANY, _L("Right Ams")); + + m_sizer_ams_left->Add(left_ams_title_text, 0, wxALIGN_CENTER, 0); + m_sizer_ams_right->Add(right_ams_title_text, 0, wxALIGN_CENTER, 0); + + m_sizer_ams->Add(m_sizer_ams_left, 0, wxEXPAND | wxALL, FromDIP(0)); + m_sizer_ams->Add(m_sizer_ams_right, 0, wxEXPAND | wxALL, FromDIP(0)); + m_warning_text = new wxStaticText(this, wxID_ANY, wxEmptyString); m_warning_text->SetForegroundColour(wxColour(0xFF, 0x6F, 0x00)); @@ -342,9 +337,7 @@ void MaterialItem::doRender(wxDC &dc) m_warning_text->Wrap(FromDIP(248)); m_sizer_main->Add(title_panel, 0, wxEXPAND | wxALL, FromDIP(2)); - m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(5)); - m_sizer_main->Add(m_sizer_list, 0, wxEXPAND | wxALL, FromDIP(0)); - m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(5)); + m_sizer_main->Add(m_sizer_ams, 0, wxEXPAND | wxALL, FromDIP(2)); m_sizer_main->Add(m_warning_text, 0, wxEXPAND | wxALL, FromDIP(6)); SetSizer(m_sizer_main); @@ -456,73 +449,92 @@ void AmsMapingPopup::update_ams_data_multi_machines() void AmsMapingPopup::update_ams_data(std::map amsList) { - m_has_unmatch_filament = false; - //m_mapping_item_list.clear(); + std::map::iterator ams_iter; + BOOST_LOG_TRIVIAL(trace) << "ams_mapping total count " << amsList.size(); + for (auto& ams_container : m_amsmapping_container_list) { - ams_container->Hide(); + ams_container->Destroy(); } + m_amsmapping_container_list.clear(); + m_amsmapping_container_sizer_list.clear(); + m_mapping_item_list.clear(); - for (wxWindow *mitem : m_mapping_item_list) { - mitem->Destroy(); - mitem = nullptr; - } - m_mapping_item_list.clear(); + for (ams_iter = amsList.begin(); ams_iter != amsList.end(); ams_iter++) { - if (m_amsmapping_container_sizer_list.size() > 0) { - for (wxBoxSizer *siz : m_amsmapping_container_sizer_list) { - siz->Clear(true); - } - } - - std::map::iterator ams_iter; + int ams_indx = atoi(ams_iter->first.c_str()); + int ams_type = ams_iter->second->type; + int nozzle_id = ams_iter->second->nozzle; - BOOST_LOG_TRIVIAL(trace) << "ams_mapping total count " << amsList.size(); - int m_amsmapping_container_list_index = 0; + if (ams_type == 1) { - for (ams_iter = amsList.begin(); ams_iter != amsList.end(); ams_iter++) { - - BOOST_LOG_TRIVIAL(trace) << "ams_mapping ams id " << ams_iter->first.c_str(); + auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL); + auto ams_mapping_item_container = new MappingContainer(this); + ams_mapping_item_container->SetSizer(sizer_mapping_list); + ams_mapping_item_container->Layout(); + + m_has_unmatch_filament = false; - auto ams_indx = atoi(ams_iter->first.c_str()); - Ams *ams_group = ams_iter->second; - std::vector tray_datas; - std::map::iterator tray_iter; + BOOST_LOG_TRIVIAL(trace) << "ams_mapping ams id " << ams_iter->first.c_str(); - for (tray_iter = ams_group->trayList.begin(); tray_iter != ams_group->trayList.end(); tray_iter++) { - AmsTray *tray_data = tray_iter->second; - TrayData td; + Ams* ams_group = ams_iter->second; + std::vector tray_datas; + std::map::iterator tray_iter; - td.id = ams_indx * AMS_TOTAL_COUNT + atoi(tray_data->id.c_str()); + for (tray_iter = ams_group->trayList.begin(); tray_iter != ams_group->trayList.end(); tray_iter++) { + AmsTray* tray_data = tray_iter->second; + TrayData td; - if (!tray_data->is_exists) { - td.type = EMPTY; - } else { - if (!tray_data->is_tray_info_ready()) { - td.type = THIRD; - } else { - td.type = NORMAL; - td.colour = AmsTray::decode_color(tray_data->color); - td.name = tray_data->get_display_filament_type(); - td.filament_type = tray_data->get_filament_type(); - td.ctype = tray_data->ctype; - for (auto col : tray_data->cols) { - td.material_cols.push_back(AmsTray::decode_color(col)); + td.id = ams_indx * AMS_TOTAL_COUNT + atoi(tray_data->id.c_str()); + + if (!tray_data->is_exists) { + td.type = EMPTY; + } + else { + if (!tray_data->is_tray_info_ready()) { + td.type = THIRD; + } + else { + td.type = NORMAL; + td.colour = AmsTray::decode_color(tray_data->color); + td.name = tray_data->get_display_filament_type(); + td.filament_type = tray_data->get_filament_type(); + td.ctype = tray_data->ctype; + for (auto col : tray_data->cols) { + td.material_cols.push_back(AmsTray::decode_color(col)); + } } + + td.ams_id = std::stoi(ams_iter->second->id); + td.slot_id = std::stoi(tray_iter->second->id); } + + tray_datas.push_back(td); } - tray_datas.push_back(td); - } + ams_mapping_item_container->Show(); + add_ams_mapping(tray_datas, ams_mapping_item_container, sizer_mapping_list); + + + m_amsmapping_container_sizer_list.push_back(sizer_mapping_list); + m_amsmapping_container_list.push_back(ams_mapping_item_container); - m_amsmapping_container_list[m_amsmapping_container_list_index]->Show(); - add_ams_mapping(tray_datas, m_amsmapping_container_list[m_amsmapping_container_list_index], m_amsmapping_container_sizer_list[m_amsmapping_container_list_index]); - m_amsmapping_container_list_index++; + //main nozzle = right nozzle + if (nozzle_id == 0) { + m_sizer_ams_right->Add(ams_mapping_item_container, 0, wxALIGN_CENTER, 0); + } + else if (nozzle_id == 1) { + m_sizer_ams_left->Add(ams_mapping_item_container, 0, wxALIGN_CENTER, 0); + } + + + //m_warning_text->Show(m_has_unmatch_filament); + } } + /*extra tray*/ - m_warning_text->Show(m_has_unmatch_filament); Layout(); Fit(); } @@ -583,6 +595,9 @@ void AmsMapingPopup::add_ams_mapping(std::vector tray_data, wxWindow* // set button MappingItem *m_mapping_item = new MappingItem(container); + m_mapping_item->m_ams_id = tray_data[i].ams_id; + m_mapping_item->m_slot_id = tray_data[i].slot_id; + m_mapping_item->SetSize(wxSize(FromDIP(68 * 0.7), FromDIP(100 * 0.6))); m_mapping_item->SetMinSize(wxSize(FromDIP(68 * 0.7), FromDIP(100 * 0.6))); m_mapping_item->SetMaxSize(wxSize(FromDIP(68 * 0.7), FromDIP(100 * 0.6))); @@ -675,7 +690,8 @@ void MappingItem::send_event(int fliament_id) wxCommandEvent event(EVT_SET_FINISH_MAPPING); event.SetInt(m_tray_data.id); - wxString param = wxString::Format("%d|%d|%d|%d|%s|%d", m_coloul.Red(), m_coloul.Green(), m_coloul.Blue(), m_coloul.Alpha(), number, fliament_id); + wxString param = wxString::Format("%d|%d|%d|%d|%s|%d|%d|%d", m_coloul.Red(), m_coloul.Green(), m_coloul.Blue(), m_coloul.Alpha(), number, fliament_id, + m_tray_data.ams_id, m_tray_data.slot_id); event.SetString(param); event.SetEventObject(this->GetParent()->GetParent()); wxPostEvent(this->GetParent()->GetParent()->GetParent(), event); diff --git a/src/slic3r/GUI/AmsMappingPopup.hpp b/src/slic3r/GUI/AmsMappingPopup.hpp index 75f274ba0bd..7c64cba2f2e 100644 --- a/src/slic3r/GUI/AmsMappingPopup.hpp +++ b/src/slic3r/GUI/AmsMappingPopup.hpp @@ -60,6 +60,9 @@ struct TrayData std::string filament_type; wxColour colour; std::vector material_cols = std::vector(); + + int ams_id = 0; + int slot_id = 0; }; class MaterialItem: public wxPanel @@ -116,6 +119,9 @@ class MappingItem : public wxPanel ScalableBitmap m_transparent_mapping_item; bool m_unmatch{false}; + int m_ams_id{255}; + int m_slot_id{255}; + void msw_rescale(); void paintEvent(wxPaintEvent &evt); void render(wxDC &dc); @@ -150,6 +156,9 @@ class AmsMapingPopup : public PopupWindow int m_current_filament_id; std::string m_tag_material; wxBoxSizer *m_sizer_main{nullptr}; + wxBoxSizer *m_sizer_ams{nullptr}; + wxBoxSizer *m_sizer_ams_left{nullptr}; + wxBoxSizer *m_sizer_ams_right{nullptr}; wxBoxSizer *m_sizer_list{nullptr}; wxWindow *m_parent_item{nullptr}; diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 455f023f369..3f2d1131a35 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -3942,11 +3942,24 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) for (auto it = j_ams.begin(); it != j_ams.end(); it++) { if (!it->contains("id")) continue; std::string ams_id = (*it)["id"].get(); + + int nozzle_id = 0; // Default nozzle id + int type_id = 1; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s + + if (it->contains("nozzle")) { + nozzle_id = (*it)["nozzle"].get(); + } + + if (it->contains("type")) { + type_id = (*it)["type"].get(); + } + ams_id_set.erase(ams_id); Ams* curr_ams = nullptr; auto ams_it = amsList.find(ams_id); if (ams_it == amsList.end()) { - Ams* new_ams = new Ams(ams_id); + Ams* new_ams = new Ams(ams_id, nozzle_id, type_id); + try { if (!ams_id.empty()) { int ams_id_int = atoi(ams_id.c_str()); @@ -4773,7 +4786,47 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } } + + /*parse np*/ + try + { + if (jj.contains("cfg") && jj.contains("fun") && jj.contains("aux") && jj.contains("stat")) { + is_enable_np = true; + } + else { + is_enable_np = false; + } + + if (jj.contains("device")) { + json const & device = jj["device"]; + + if (device.contains("nozzle")) { + json const & nozzle = device["nozzle"]; + + m_np_nozzle_data = NozzleData(); + m_np_nozzle_data.info = nozzle["info"].get(); + + + for (const auto& noz : nozzle.items()) { + std::string nozzle_id = noz.key(); + json const & ndata = noz.value(); + + Nozzle n; + if (ndata.contains("info")) {n.info = ndata["info"].get(); } + if (ndata.contains("snow")) {n.info = ndata["snow"].get(); } + if (ndata.contains("spre")) {n.info = ndata["spre"].get(); } + if (ndata.contains("star")) {n.info = ndata["star"].get(); } + if (ndata.contains("stat")) {n.info = ndata["stat"].get(); } + if (ndata.contains("temp")) {n.info = ndata["temp"].get(); } + m_np_nozzle_data.nozzle[nozzle_id] = n; + } + } + } + } + catch (...) + {} } + if (!key_field_only) { try { if (j.contains("camera")) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index dce43fd9625..1a9e0be246c 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -135,6 +135,21 @@ enum ManualPaCaliMethod { PA_PATTERN, }; +struct Nozzle +{ + int info{0}; + int snow{0}; + int spre{0}; + int star{0}; + int stat{0}; + int temp{0}; +}; + +struct NozzleData +{ + std::map nozzle; /*0 - main nozzle 1 - slave nozzle*/ + int info{0}; +}; struct RatingInfo { bool request_successful; @@ -226,8 +241,10 @@ class AmsTray { class Ams { public: - Ams(std::string ams_id) { + Ams(std::string ams_id, int nozzle_id, int type_id) { id = ams_id; + nozzle = nozzle_id; + type = type_id; } std::string id; int humidity = 5; @@ -235,6 +252,9 @@ class Ams { bool tray_read_opt{false}; bool is_exists{false}; std::map trayList; + + int nozzle; + int type{1}; //0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s }; enum PrinterFirmwareType { @@ -330,7 +350,6 @@ class MachineObject // type, time stamp, delay std::vector> message_delay; - public: enum LIGHT_EFFECT { @@ -484,6 +503,7 @@ class MachineObject /* ams properties */ std::map amsList; // key: ams[id], start with 0 AmsTray vt_tray; // virtual tray + std::vector vt_trays; // virtual tray for new long ams_exist_bits = 0; long tray_exist_bits = 0; long tray_is_bbl_bits = 0; @@ -977,6 +997,10 @@ class MachineObject bool is_firmware_info_valid(); std::string get_string_from_fantype(FanType type); + /*for more extruder*/ + bool is_enable_np{ false }; + NozzleData m_np_nozzle_data; + /* Device Filament Check */ std::set m_checked_filament; std::string m_printer_preset_name; @@ -985,6 +1009,7 @@ class MachineObject int get_flag_bits(std::string str, int start, int count = 1); int get_flag_bits(int num, int start, int count = 1); void update_printer_preset_name(const std::string &nozzle_diameter_str); + }; class DeviceManager diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index e7e893d4f80..0f1ae0295b8 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -968,6 +968,9 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) SetDoubleBuffered(true); #endif //__WINDOWS__ + SetMinSize(wxSize(FromDIP(688), -1)); + SetMaxSize(wxSize(FromDIP(688), -1)); + // bind Bind(wxEVT_CLOSE_WINDOW, &SelectMachineDialog::on_cancel, this); @@ -984,54 +987,77 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) SetBackgroundColour(m_colour_def_color); m_sizer_main = new wxBoxSizer(wxVERTICAL); - - m_sizer_main->SetMinSize(wxSize(0, -1)); m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); - m_scrollable_view = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_sizer_scrollable_view = new wxBoxSizer(wxVERTICAL); - m_scrollable_region = new wxPanel(m_scrollable_view, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - m_sizer_scrollable_region = new wxBoxSizer(wxVERTICAL); + m_basic_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_basic_panel->SetBackgroundColour(*wxWHITE); + m_basicl_sizer = new wxBoxSizer(wxHORIZONTAL); + + /*basic info*/ + + /*thumbnail*/ + auto m_sizer_thumbnail_area = new wxBoxSizer(wxHORIZONTAL); + + auto m_panel_image = new wxPanel(m_basic_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_panel_image->SetBackgroundColour(m_colour_def_color); + m_sizer_thumbnail = new wxBoxSizer(wxHORIZONTAL); + m_thumbnailPanel = new ThumbnailPanel(m_panel_image); + m_thumbnailPanel->SetSize(wxSize(FromDIP(198), FromDIP(198))); + m_thumbnailPanel->SetMinSize(wxSize(FromDIP(198), FromDIP(198))); + m_thumbnailPanel->SetMaxSize(wxSize(FromDIP(198), FromDIP(198))); + m_thumbnailPanel->SetBackgroundColour(*wxWHITE); + m_sizer_thumbnail->Add(m_thumbnailPanel, 0, wxALIGN_CENTER, 0); + m_panel_image->SetSizer(m_sizer_thumbnail); + m_panel_image->Layout(); + + m_sizer_thumbnail_area->Add(m_panel_image, 0, wxALIGN_CENTER, 0); + m_sizer_thumbnail_area->Layout(); + + /*basic info right*/ + auto sizer_basic_right_info = new wxBoxSizer(wxVERTICAL); + /*rename*/ + auto sizer_rename = new wxBoxSizer(wxHORIZONTAL); - //rename normal - m_rename_switch_panel = new wxSimplebook(m_scrollable_region); - m_rename_switch_panel->SetSize(wxSize(FromDIP(420), FromDIP(25))); - m_rename_switch_panel->SetMinSize(wxSize(FromDIP(420), FromDIP(25))); - m_rename_switch_panel->SetMaxSize(wxSize(FromDIP(420), FromDIP(25))); + m_rename_switch_panel = new wxSimplebook(m_basic_panel); + m_rename_switch_panel->SetBackgroundColour(*wxWHITE); + m_rename_switch_panel->SetSize(wxSize(FromDIP(360), FromDIP(25))); + m_rename_switch_panel->SetMinSize(wxSize(FromDIP(360), FromDIP(25))); + m_rename_switch_panel->SetMaxSize(wxSize(FromDIP(360), FromDIP(25))); m_rename_normal_panel = new wxPanel(m_rename_switch_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_rename_normal_panel->SetBackgroundColour(*wxWHITE); rename_sizer_v = new wxBoxSizer(wxVERTICAL); rename_sizer_h = new wxBoxSizer(wxHORIZONTAL); - m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); + m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END); m_rename_text->SetFont(::Label::Body_13); - m_rename_text->SetMaxSize(wxSize(FromDIP(390), -1)); - m_rename_button = new ScalableButton(m_rename_normal_panel, wxID_ANY, "ams_editable"); - ams_editable = new ScalableBitmap(this, "ams_editable", 13); - ams_editable_light = new ScalableBitmap(this, "ams_editable_light", 13); - m_rename_button->SetBackgroundColour(*wxWHITE); - - rename_sizer_h->Add(m_rename_text, 0, wxALIGN_CENTER, 0); + m_rename_text->SetBackgroundColour(*wxWHITE); + m_rename_text->SetMaxSize(wxSize(FromDIP(340), -1)); + rename_editable = new ScalableBitmap(this, "rename_edit", 20); + rename_editable_light = new ScalableBitmap(this, "rename_edit", 20); + m_rename_button = new wxStaticBitmap(m_rename_normal_panel, wxID_ANY, rename_editable->bmp(), wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), 0); + m_rename_button->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); }); + m_rename_button->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); }); + + rename_sizer_h->Add(m_rename_text, 0, wxALIGN_CENTER|wxTOP, FromDIP(2)); rename_sizer_h->Add(m_rename_button, 0, wxALIGN_CENTER, 0); - rename_sizer_v->Add(rename_sizer_h, 1, wxALIGN_CENTER, 0); + rename_sizer_v->Add(rename_sizer_h, 1, wxTOP, 0); m_rename_normal_panel->SetSizer(rename_sizer_v); m_rename_normal_panel->Layout(); rename_sizer_v->Fit(m_rename_normal_panel); - //rename edit auto m_rename_edit_panel = new wxPanel(m_rename_switch_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_rename_edit_panel->SetBackgroundColour(*wxWHITE); auto rename_edit_sizer_v = new wxBoxSizer(wxVERTICAL); m_rename_input = new ::TextInput(m_rename_edit_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); m_rename_input->GetTextCtrl()->SetFont(::Label::Body_13); - m_rename_input->SetSize(wxSize(FromDIP(380), FromDIP(24))); - m_rename_input->SetMinSize(wxSize(FromDIP(380), FromDIP(24))); - m_rename_input->SetMaxSize(wxSize(FromDIP(380), FromDIP(24))); + m_rename_input->SetSize(wxSize(FromDIP(360), FromDIP(24))); + m_rename_input->SetMinSize(wxSize(FromDIP(360), FromDIP(24))); + m_rename_input->SetMaxSize(wxSize(FromDIP(360), FromDIP(24))); m_rename_input->Bind(wxEVT_TEXT_ENTER, [this](auto& e) {on_rename_enter();}); m_rename_input->Bind(wxEVT_KILL_FOCUS, [this](auto& e) { if (!m_rename_input->HasFocus() && !m_rename_text->HasFocus()) @@ -1045,7 +1071,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_rename_edit_panel->Layout(); rename_edit_sizer_v->Fit(m_rename_edit_panel); - m_rename_button->Bind(wxEVT_BUTTON, &SelectMachineDialog::on_rename_click, this); + m_rename_button->Bind(wxEVT_LEFT_DOWN, &SelectMachineDialog::on_rename_click, this); m_rename_switch_panel->AddPage(m_rename_normal_panel, wxEmptyString, true); m_rename_switch_panel->AddPage(m_rename_edit_panel, wxEmptyString, false); @@ -1065,91 +1091,124 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) } }); - auto m_sizer_thumbnail_area = new wxBoxSizer(wxHORIZONTAL); - auto last_plate_panel = new wxWindow(m_scrollable_region, wxID_ANY); - last_plate_panel->SetBackgroundColour(*wxWHITE); + /*weight & time*/ + wxBoxSizer *m_sizer_basic_weight_time = new wxBoxSizer(wxHORIZONTAL); + + print_time = new ScalableBitmap(this, "print-time", 18); + timeimg = new wxStaticBitmap(m_basic_panel, wxID_ANY, print_time->bmp(), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0); + m_stext_time = new Label(m_basic_panel, wxEmptyString); + m_stext_time->SetFont(Label::Body_13); + + print_weight = new ScalableBitmap(this, "print-weight", 18); + weightimg = new wxStaticBitmap(m_basic_panel, wxID_ANY, print_weight->bmp(), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0); + m_stext_weight = new Label(m_basic_panel, wxEmptyString); + m_stext_weight->SetFont(Label::Body_13); + + m_sizer_basic_weight_time->Add(timeimg, 0, wxALIGN_CENTER, 0); + m_sizer_basic_weight_time->Add(m_stext_time, 0, wxALIGN_CENTER|wxLEFT, FromDIP(6)); + m_sizer_basic_weight_time->Add(weightimg, 0, wxALIGN_CENTER|wxLEFT, FromDIP(30)); + m_sizer_basic_weight_time->Add(m_stext_weight, 0, wxALIGN_CENTER|wxLEFT, FromDIP(6)); + + /*bed type*/ + auto m_text_bed_type = new Label(m_basic_panel, "Plate: Textured PEI"); + m_text_bed_type->SetFont(Label::Body_13); + + /*last & next page*/ + + auto last_plate_sizer = new wxBoxSizer(wxVERTICAL); - last_plate_panel->SetMinSize(wxSize(FromDIP(32), FromDIP(32))); - m_bitmap_last_plate = new wxStaticBitmap(last_plate_panel, wxID_ANY, create_scaled_bitmap("go_last_plate", this, 32), wxDefaultPosition, wxSize(FromDIP(32), FromDIP(32)), 0); + m_bitmap_last_plate = new wxStaticBitmap(m_basic_panel, wxID_ANY, create_scaled_bitmap("go_last_plate", this, 25), wxDefaultPosition, wxSize(FromDIP(25), FromDIP(25)), 0); last_plate_sizer->Add(m_bitmap_last_plate, 0, wxALIGN_CENTER, 0); - last_plate_panel->SetSizer(last_plate_sizer); - - m_panel_image = new wxPanel(m_scrollable_region, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - m_panel_image->SetBackgroundColour(m_colour_def_color); - m_sizer_thumbnail = new wxBoxSizer(wxHORIZONTAL); - m_thumbnailPanel = new ThumbnailPanel(m_panel_image); - m_thumbnailPanel->SetSize(wxSize(FromDIP(256), FromDIP(256))); - m_thumbnailPanel->SetMinSize(wxSize(FromDIP(256), FromDIP(256))); - m_thumbnailPanel->SetMaxSize(wxSize(FromDIP(256), FromDIP(256))); - m_thumbnailPanel->SetBackgroundColour(*wxRED); - m_sizer_thumbnail->Add(m_thumbnailPanel, 0, wxALIGN_CENTER, 0); - m_panel_image->SetSizer(m_sizer_thumbnail); - m_panel_image->Layout(); - auto next_plate_panel = new wxWindow(m_scrollable_region, wxID_ANY); - next_plate_panel->SetBackgroundColour(*wxWHITE); auto next_plate_sizer = new wxBoxSizer(wxVERTICAL); - next_plate_panel->SetMinSize(wxSize(FromDIP(32), FromDIP(32))); - m_bitmap_next_plate = new wxStaticBitmap(next_plate_panel, wxID_ANY, create_scaled_bitmap("go_next_plate", this, 32), wxDefaultPosition, wxSize(FromDIP(32), FromDIP(32)), 0); + m_bitmap_next_plate = new wxStaticBitmap(m_basic_panel, wxID_ANY, create_scaled_bitmap("go_next_plate", this, 25), wxDefaultPosition, wxSize(FromDIP(25), FromDIP(25)), 0); next_plate_sizer->Add(m_bitmap_next_plate, 0, wxALIGN_CENTER, 0); - next_plate_panel->SetSizer(next_plate_sizer); - m_sizer_thumbnail_area->Add(last_plate_panel, 0, wxALIGN_CENTER, 0); - m_sizer_thumbnail_area->Add(m_panel_image, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(24)); - m_sizer_thumbnail_area->Add(next_plate_panel, 0, wxALIGN_CENTER, 0); + sizer_rename->Add(m_rename_switch_panel, 0, wxALIGN_CENTER, 0); + sizer_rename->Add(0, 0, 0, wxEXPAND, 0); + sizer_rename->Add(m_bitmap_last_plate, 0, wxALIGN_CENTER, 0); + sizer_rename->Add(m_bitmap_next_plate, 0, wxALIGN_CENTER, 0); + + /*printer combobox*/ + wxBoxSizer* m_sizer_printer = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_split_printer = new wxBoxSizer(wxHORIZONTAL); + m_stext_printer_title = new Label(m_basic_panel, _L("Printer")); + m_stext_printer_title->SetFont(::Label::Body_14); + m_stext_printer_title->SetForegroundColour(0x909090); + auto m_split_line = new wxPanel(m_basic_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + m_split_line->SetBackgroundColour(0xeeeeee); + m_split_line->SetMinSize(wxSize(-1, 1)); + m_split_line->SetMaxSize(wxSize(-1, 1)); + sizer_split_printer->Add(0, 0, 0, wxEXPAND, 0); + sizer_split_printer->Add(m_stext_printer_title, 0, wxALIGN_CENTER, 0); + sizer_split_printer->Add(m_split_line, 1, wxALIGN_CENTER_VERTICAL, 0); + + + m_comboBox_printer = new ::ComboBox(m_basic_panel, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(300), -1), 0, nullptr, wxCB_READONLY); + m_comboBox_printer->SetMinSize(wxSize(FromDIP(300), -1)); + m_comboBox_printer->SetMaxSize(wxSize(FromDIP(300), -1)); + m_comboBox_printer->Bind(wxEVT_COMBOBOX, &SelectMachineDialog::on_selection_changed, this); - wxBoxSizer *m_sizer_basic = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer *m_sizer_basic_weight = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer *m_sizer_basic_time = new wxBoxSizer(wxHORIZONTAL); - print_time = new ScalableBitmap(this, "print-time", 18); - timeimg = new wxStaticBitmap(m_scrollable_region, wxID_ANY, print_time->bmp(), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0); - m_sizer_basic_weight->Add(timeimg, 1, wxEXPAND | wxALL, FromDIP(5)); - m_stext_time = new wxStaticText(m_scrollable_region, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT); - m_sizer_basic_weight->Add(m_stext_time, 0, wxALL, FromDIP(5)); - m_sizer_basic->Add(m_sizer_basic_weight, 0, wxALIGN_CENTER, 0); - m_sizer_basic->Add(0, 0, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); + m_btn_bg_enable = StateColor(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), + std::pair(wxColour(0, 174, 66), StateColor::Normal)); - print_weight = new ScalableBitmap(this, "print-weight", 18); - weightimg = new wxStaticBitmap(m_scrollable_region, wxID_ANY, print_weight->bmp(), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0); - m_sizer_basic_time->Add(weightimg, 1, wxEXPAND | wxALL, FromDIP(5)); - m_stext_weight = new wxStaticText(m_scrollable_region, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - m_sizer_basic_time->Add(m_stext_weight, 0, wxALL, FromDIP(5)); - m_sizer_basic->Add(m_sizer_basic_time, 0, wxALIGN_CENTER, 0); - - wxBoxSizer* m_sizer_material_area = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* m_sizer_material_tips = new wxBoxSizer(wxHORIZONTAL); - - enable_ams_mapping = new ScalableBitmap(this, "enable_ams", 16); - img_amsmapping_tip = new wxStaticBitmap(m_scrollable_region, wxID_ANY, enable_ams_mapping->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); - m_sizer_material_tips->Add(img_amsmapping_tip, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); - - img_amsmapping_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { - wxPoint img_pos = img_amsmapping_tip->ClientToScreen(wxPoint(0, 0)); - wxPoint popup_pos(img_pos.x, img_pos.y + img_amsmapping_tip->GetRect().height); - m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); - m_mapping_tutorial_popup.Popup(); - - if (m_mapping_tutorial_popup.ClientToScreen(wxPoint(0, 0)).y < img_pos.y) { - m_mapping_tutorial_popup.Dismiss(); - popup_pos = wxPoint(img_pos.x, img_pos.y - m_mapping_tutorial_popup.GetRect().height); - m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); - m_mapping_tutorial_popup.Popup(); - } - }); + m_button_refresh = new Button(m_basic_panel, _L("Refresh")); + m_button_refresh->SetBackgroundColor(m_btn_bg_enable); + m_button_refresh->SetBorderColor(m_btn_bg_enable); + m_button_refresh->SetTextColor(StateColor::darkModeColorFor("#FFFFFE")); + m_button_refresh->SetSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); + m_button_refresh->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); + m_button_refresh->SetCornerRadius(FromDIP(10)); + m_button_refresh->Bind(wxEVT_BUTTON, &SelectMachineDialog::on_refresh, this); + + m_sizer_printer->Add(m_comboBox_printer, 0, wxEXPAND, 0); + m_sizer_printer->Add(m_button_refresh, 0, wxALL | wxLEFT, FromDIP(5)); + + m_text_printer_msg = new wxStaticText(m_basic_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + m_text_printer_msg->SetMinSize(wxSize(FromDIP(420), -1)); + m_text_printer_msg->SetMaxSize(wxSize(FromDIP(420), -1)); + m_text_printer_msg->SetFont(::Label::Body_13); + m_text_printer_msg->Hide(); + + + sizer_basic_right_info->Add(sizer_rename, 0, wxTOP, 0); + sizer_basic_right_info->Add(0, 0, 0, wxTOP, FromDIP(5)); + sizer_basic_right_info->Add(m_sizer_basic_weight_time, 0, wxTOP, 0); + sizer_basic_right_info->Add(0, 0, 0, wxTOP, FromDIP(10)); + sizer_basic_right_info->Add(m_text_bed_type, 0, wxTOP, 0); + sizer_basic_right_info->Add(0, 0, 0, wxTOP, FromDIP(15)); + sizer_basic_right_info->Add(sizer_split_printer, 1, wxEXPAND, 0); + sizer_basic_right_info->Add(0, 0, 0, wxTOP, FromDIP(8)); + sizer_basic_right_info->Add(m_sizer_printer, 0, wxTOP, 0); + sizer_basic_right_info->Add(0, 0, 0, wxTOP, FromDIP(4)); + sizer_basic_right_info->Add(m_text_printer_msg, 0, wxLEFT, 0); + + + m_basicl_sizer->Add(m_sizer_thumbnail_area, 0, wxLEFT, 0); + m_basicl_sizer->Add(0, 0, 0, wxLEFT, FromDIP(8)); + m_basicl_sizer->Add(sizer_basic_right_info, 0, wxLEFT, 0); + - img_amsmapping_tip->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { - m_mapping_tutorial_popup.Dismiss(); - }); - m_sizer_material = new wxGridSizer(0, 4, 0, FromDIP(5)); + m_basic_panel->SetSizer(m_basicl_sizer); + m_basic_panel->Layout(); - m_sizer_material_area->Add(m_sizer_material_tips, 0, wxALIGN_CENTER|wxLEFT, FromDIP(8)); - m_sizer_material_area->Add(m_sizer_material, 0, wxLEFT, FromDIP(15)); + /*filaments info*/ + wxBoxSizer* sizer_split_filament = new wxBoxSizer(wxHORIZONTAL); - m_sizer_backup = new wxBoxSizer(wxHORIZONTAL); + auto m_stext_filament_title = new Label(this, _L("Filament")); + m_stext_filament_title->SetFont(::Label::Body_14); + m_stext_filament_title->SetForegroundColour(0x909090); + + auto m_split_line_filament = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_split_line_filament->SetBackgroundColour(0xeeeeee); + m_split_line_filament->SetMinSize(wxSize(-1, 1)); + m_split_line_filament->SetMaxSize(wxSize(-1, 1)); + + m_sizer_autorefill = new wxBoxSizer(wxHORIZONTAL); m_ams_backup_tip = new Label(this, _L("Auto Refill")); m_ams_backup_tip->SetFont(::Label::Head_12); m_ams_backup_tip->SetForegroundColour(wxColour(0x009688)); @@ -1157,9 +1216,9 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) img_ams_backup = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("automatic_material_renewal", this, 16), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); img_ams_backup->SetBackgroundColour(*wxWHITE); - m_sizer_backup->Add(0, 0, 1, wxEXPAND, 0); - m_sizer_backup->Add(img_ams_backup, 0, wxALL, FromDIP(3)); - m_sizer_backup->Add(m_ams_backup_tip, 0, wxTOP, FromDIP(5)); + m_sizer_autorefill->Add(0, 0, 1, wxEXPAND, 0); + m_sizer_autorefill->Add(img_ams_backup, 0, wxALL, FromDIP(3)); + m_sizer_autorefill->Add(m_ams_backup_tip, 0, wxTOP, FromDIP(5)); m_ams_backup_tip->Hide(); img_ams_backup->Hide(); @@ -1170,71 +1229,135 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_ams_backup_tip->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); }); img_ams_backup->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); }); - m_ams_backup_tip->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { if (!m_is_in_sending_mode) {popup_filament_backup(); on_rename_enter();} }); - img_ams_backup->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {if (!m_is_in_sending_mode) popup_filament_backup();on_rename_enter(); }); + m_ams_backup_tip->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { if (!m_is_in_sending_mode) { popup_filament_backup(); on_rename_enter(); } }); + img_ams_backup->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {if (!m_is_in_sending_mode) popup_filament_backup(); on_rename_enter(); }); - m_statictext_ams_msg = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); - m_statictext_ams_msg->SetFont(::Label::Body_13); - m_statictext_ams_msg->Hide(); + sizer_split_filament->Add(0, 0, 0, wxEXPAND, 0); + sizer_split_filament->Add(m_stext_filament_title, 0, wxALIGN_CENTER, 0); + sizer_split_filament->Add(m_split_line_filament, 1, wxALIGN_CENTER_VERTICAL, 0); + sizer_split_filament->Add(m_sizer_autorefill, 0, wxALIGN_CENTER, 0); + + //wxBoxSizer* m_sizer_ams_mapping_tips = new wxBoxSizer(wxHORIZONTAL); + + - m_line_materia = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); - m_line_materia->SetForegroundColour(wxColour(238, 238, 238)); - m_line_materia->SetBackgroundColour(wxColour(238, 238, 238)); + /* ams_mapping_help_icon = new ScalableBitmap(this, "enable_ams", 16); + img_amsmapping_tip = new wxStaticBitmap(this, wxID_ANY, ams_mapping_help_icon->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); + m_sizer_ams_mapping_tips->Add(img_amsmapping_tip, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); + + img_amsmapping_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { + wxPoint img_pos = img_amsmapping_tip->ClientToScreen(wxPoint(0, 0)); + wxPoint popup_pos(img_pos.x, img_pos.y + img_amsmapping_tip->GetRect().height); + m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); + m_mapping_tutorial_popup.Popup(); + + if (m_mapping_tutorial_popup.ClientToScreen(wxPoint(0, 0)).y < img_pos.y) { + m_mapping_tutorial_popup.Dismiss(); + popup_pos = wxPoint(img_pos.x, img_pos.y - m_mapping_tutorial_popup.GetRect().height); + m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); + m_mapping_tutorial_popup.Popup(); + } + }); - wxBoxSizer *m_sizer_printer = new wxBoxSizer(wxHORIZONTAL); + img_amsmapping_tip->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { + m_mapping_tutorial_popup.Dismiss(); + }); - m_stext_printer_title = new wxStaticText(this, wxID_ANY, _L("Printer"), wxDefaultPosition, wxSize(-1, -1), 0); - m_stext_printer_title->SetFont(::Label::Head_14); - m_stext_printer_title->Wrap(-1); - m_stext_printer_title->SetForegroundColour(m_colour_bold_color); - m_stext_printer_title->SetBackgroundColour(m_colour_def_color); + - m_sizer_printer->Add(m_stext_printer_title, 0, wxALL | wxLEFT, FromDIP(5)); - m_sizer_printer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(12)); - m_comboBox_printer = new ::ComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(250), -1), 0, nullptr, wxCB_READONLY); - m_comboBox_printer->Bind(wxEVT_COMBOBOX, &SelectMachineDialog::on_selection_changed, this); + m_sizer_filament->Add(m_sizer_ams_mapping_tips, 0, wxALIGN_CENTER|wxLEFT, FromDIP(8));*/ - m_sizer_printer->Add(m_comboBox_printer, 1, wxEXPAND | wxRIGHT, FromDIP(5)); - m_btn_bg_enable = StateColor(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), - std::pair(wxColour(0, 150, 136), StateColor::Normal)); + /*filament area*/ + /*1 extruder*/ + m_filament_panel = new wxPanel(this, wxID_ANY); + m_filament_panel->SetBackgroundColour(wxColour(0xf8f8f8)); + m_filament_panel->SetMinSize(wxSize(FromDIP(637), -1)); + m_filament_panel->SetMaxSize(wxSize(FromDIP(637), -1)); + m_filament_panel_sizer = new wxBoxSizer(wxVERTICAL); + + m_sizer_ams_mapping = new wxGridSizer(0, 10, FromDIP(7), FromDIP(7)); + m_filament_panel_sizer->Add(m_sizer_ams_mapping, 0, wxEXPAND|wxALL, FromDIP(10)); + m_filament_panel->SetSizer(m_filament_panel_sizer); + m_filament_panel->Layout(); + m_filament_panel->Fit(); + + /*left & right extruder*/ + m_sizer_filament_2extruder = new wxBoxSizer(wxHORIZONTAL); + m_filament_left_panel = new wxPanel(this, wxID_ANY); + m_filament_right_panel = new wxPanel(this, wxID_ANY); + m_filament_left_panel->SetBackgroundColour(wxColour(0xf8f8f8)); + m_filament_right_panel->SetBackgroundColour(wxColour(0xf8f8f8)); + m_filament_left_panel->SetMinSize(wxSize(FromDIP(315), 180)); + m_filament_left_panel->SetMaxSize(wxSize(FromDIP(315), 180)); + m_filament_right_panel->SetMinSize(wxSize(FromDIP(315), 180)); + m_filament_right_panel->SetMaxSize(wxSize(FromDIP(315), 180)); + + m_filament_panel_left_sizer = new wxBoxSizer(wxVERTICAL); + m_sizer_ams_mapping_left = new wxGridSizer(0, 5, FromDIP(7), FromDIP(7)); + m_filament_panel_left_sizer->Add(m_sizer_ams_mapping_left, 0, wxEXPAND | wxALL, FromDIP(10)); + m_filament_left_panel->SetSizer(m_filament_panel_left_sizer); + m_filament_left_panel->Layout(); + m_filament_left_panel->Fit(); + + m_filament_panel_right_sizer = new wxBoxSizer(wxVERTICAL); + m_sizer_ams_mapping_right = new wxGridSizer(0, 5, FromDIP(7), FromDIP(7)); + m_filament_panel_right_sizer->Add(m_sizer_ams_mapping_right, 0, wxEXPAND | wxALL, FromDIP(10)); + m_filament_right_panel->SetSizer(m_filament_panel_right_sizer); + m_filament_right_panel->Layout(); + m_filament_right_panel->Fit(); + + m_sizer_filament_2extruder->Add(m_filament_left_panel, 0, wxALIGN_CENTER, 0); + m_sizer_filament_2extruder->Add(0, 0, 0, wxLEFT, FromDIP(7)); + m_sizer_filament_2extruder->Add(m_filament_right_panel, 0, wxALIGN_CENTER, 0); + m_sizer_filament_2extruder->Layout(); + + m_filament_left_panel->Hide(); + m_filament_right_panel->Hide(); + + + + + + m_statictext_ams_msg = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); + m_statictext_ams_msg->SetFont(::Label::Body_13); + m_statictext_ams_msg->Hide(); - m_button_refresh = new Button(this, _L("Refresh")); - m_button_refresh->SetBackgroundColor(m_btn_bg_enable); - m_button_refresh->SetBorderColor(m_btn_bg_enable); - m_button_refresh->SetTextColor(StateColor::darkModeColorFor("#FFFFFE")); - m_button_refresh->SetSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); - m_button_refresh->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); - m_button_refresh->SetCornerRadius(FromDIP(10)); - m_button_refresh->Bind(wxEVT_BUTTON, &SelectMachineDialog::on_refresh, this); - m_sizer_printer->Add(m_button_refresh, 0, wxALL | wxLEFT, FromDIP(5)); - m_statictext_printer_msg = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); - m_statictext_printer_msg->SetFont(::Label::Body_13); - m_statictext_printer_msg->Hide(); - //m_sizer_select = new wxGridSizer(0, 2, 0, 0); - m_sizer_select = new wxWrapSizer(); + /*options*/ + wxBoxSizer* sizer_split_options = new wxBoxSizer(wxHORIZONTAL); + auto m_stext_options_title = new Label(this, _L("Print Options")); + m_stext_options_title->SetFont(::Label::Body_14); + m_stext_options_title->SetForegroundColour(0x909090); + auto m_split_options_line = new wxPanel(this, wxID_ANY); + m_split_options_line->SetBackgroundColour(0xeeeeee); + m_split_options_line->SetSize(wxSize(-1, FromDIP(1))); + m_split_options_line->SetMinSize(wxSize(-1, FromDIP(1))); + m_split_options_line->SetMaxSize(wxSize(-1, FromDIP(1))); + sizer_split_options->Add(0, 0, 0, wxEXPAND, 0); + sizer_split_options->Add(m_stext_options_title, 0, wxALIGN_CENTER, 0); + sizer_split_options->Add(m_split_options_line, 1, wxALIGN_CENTER_VERTICAL, 0); + + + m_sizer_options = new wxBoxSizer(wxHORIZONTAL); select_bed = create_item_checkbox(_L("Bed Leveling"), this, _L("Bed Leveling"), "bed_leveling"); select_flow = create_item_checkbox(_L("Flow Dynamics Calibration"), this, _L("Flow Dynamics Calibration"), "flow_cali"); select_timelapse = create_item_checkbox(_L("Timelapse"), this, _L("Timelapse"), "timelapse"); select_use_ams = create_ams_checkbox(_L("Enable AMS"), this, _L("Enable AMS")); - m_sizer_select->Add(select_bed, 0, wxLEFT | wxRIGHT, WRAP_GAP); - m_sizer_select->Add(select_flow, 0, wxLEFT | wxRIGHT, WRAP_GAP); - m_sizer_select->Add(select_timelapse, 0, wxLEFT | wxRIGHT, WRAP_GAP); - m_sizer_select->Add(select_use_ams, 0, wxLEFT | wxRIGHT, WRAP_GAP); + m_sizer_options->Add(select_bed, 0, wxLEFT | wxRIGHT, WRAP_GAP); + m_sizer_options->Add(select_flow, 0, wxLEFT | wxRIGHT, WRAP_GAP); + m_sizer_options->Add(select_timelapse, 0, wxLEFT | wxRIGHT, WRAP_GAP); + m_sizer_options->Add(select_use_ams, 0, wxLEFT | wxRIGHT, WRAP_GAP); select_bed->Show(false); select_flow->Show(false); select_timelapse->Show(false); select_use_ams->Show(false); - m_sizer_select->Layout(); + m_sizer_options->Layout(); - // line schedule - m_line_schedule = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); - m_line_schedule->SetBackgroundColour(wxColour(238, 238, 238)); m_simplebook = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_DIALOG_SIMBOOK_SIZE, 0); @@ -1259,7 +1382,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_button_ensure->SetSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); m_button_ensure->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); m_button_ensure->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE); - m_button_ensure->SetCornerRadius(FromDIP(12)); + m_button_ensure->SetCornerRadius(FromDIP(5)); m_button_ensure->Bind(wxEVT_BUTTON, &SelectMachineDialog::on_ok_btn, this); m_sizer_pcont->Add(0, 0, 1, wxEXPAND, 0); @@ -1384,37 +1507,25 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3)); sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5); - m_sizer_scrollable_region->Add(m_rename_switch_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_scrollable_region->Add(0, 0, 0, wxTOP, FromDIP(8)); - m_sizer_scrollable_region->Add(m_sizer_thumbnail_area, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_scrollable_region->Add(0, 0, 0, wxTOP, FromDIP(10)); - m_sizer_scrollable_region->Add(m_sizer_basic, 0, wxALIGN_CENTER_HORIZONTAL, 0); //m_sizer_scrollable_region->Add(m_sizer_material, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_scrollable_region->Add(m_sizer_material_area, 0, wxLEFT, FromDIP(10)); + //m_basic_panel_sizer->Add(m_sizer_material_area, 0, wxLEFT, FromDIP(10)); - m_scrollable_region->SetSizer(m_sizer_scrollable_region); - m_scrollable_region->Layout(); + - m_scrollable_view->SetSizer(m_sizer_scrollable_view); - m_scrollable_view->Layout(); - m_sizer_scrollable_view->Add(m_scrollable_region, 0, wxEXPAND, 0); m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); - m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(13)); - m_sizer_main->Add(m_scrollable_view, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxRIGHT, FromDIP(25)); - m_sizer_main->Add(m_sizer_backup, 0, wxALIGN_CENTER_HORIZONTAL, 0); + m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(12)); + m_sizer_main->Add(m_basic_panel, 0, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15)); + m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(14)); + m_sizer_main->Add(sizer_split_filament, 1, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15)); + m_sizer_main->Add(m_filament_panel, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(15)); + m_sizer_main->Add(m_sizer_filament_2extruder, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(15)); m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(6)); - m_sizer_main->Add(m_statictext_ams_msg, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(6)); - m_sizer_main->Add(m_line_materia, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); - m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(12)); - m_sizer_main->Add(m_sizer_printer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); - m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(11)); - m_sizer_main->Add(m_statictext_printer_msg, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_main->Add(0, 1, 0, wxTOP, FromDIP(16)); - m_sizer_main->Add(m_sizer_select, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, FromDIP(30)); - m_sizer_main->Add(0, 1, 0, wxTOP, FromDIP(10)); - m_sizer_main->Add(m_line_schedule, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30)); + m_sizer_main->Add(m_statictext_ams_msg, 0, wxLEFT, 0); + m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(16)); + m_sizer_main->Add(sizer_split_options, 1, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15)); + m_sizer_main->Add(m_sizer_options, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT| wxRIGHT, FromDIP(15)); + m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(10)); m_sizer_main->Add(m_simplebook, 0, wxALIGN_CENTER_HORIZONTAL, 0); m_sizer_main->Add(m_sw_print_failed_info, 0, wxALIGN_CENTER, 0); m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(18)); @@ -1442,7 +1553,7 @@ void SelectMachineDialog::init_bind() Bind(EVT_SET_FINISH_MAPPING, &SelectMachineDialog::on_set_finish_mapping, this); Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this);e.Skip();}); m_panel_prepare->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this);e.Skip();}); - m_scrollable_region->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this);e.Skip();}); + m_basic_panel->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {check_fcous_state(this);e.Skip();}); m_bitmap_last_plate->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); }); m_bitmap_last_plate->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_ARROW); }); m_bitmap_next_plate->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCURSOR_HAND); }); @@ -1695,7 +1806,7 @@ void SelectMachineDialog::update_select_layout(MachineObject *obj) select_timelapse->Hide(); } - m_sizer_select->Layout(); + m_sizer_options->Layout(); Layout(); Fit(); } @@ -1923,8 +2034,14 @@ bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, /*new ams mapping data*/ - mapping_item_v1["ams_id"] = m_ams_mapping_result[k].ams_id; - mapping_item_v1["slot_id"] = m_ams_mapping_result[k].slot_id; + try + { + mapping_item_v1["ams_id"] = std::stoi(m_ams_mapping_result[k].ams_id); + mapping_item_v1["slot_id"] = std::stoi(m_ams_mapping_result[k].slot_id); + } + catch (...) + { + } } } mapping_v0_json.push_back(tray_id); @@ -1985,12 +2102,12 @@ void SelectMachineDialog::update_ams_status_msg(wxString msg, bool is_warning) void SelectMachineDialog::update_priner_status_msg(wxString msg, bool is_warning) { auto colour = is_warning ? wxColour(0xFF, 0x6F, 0x00) : wxColour(0x6B, 0x6B, 0x6B); - m_statictext_printer_msg->SetForegroundColour(colour); + m_text_printer_msg->SetForegroundColour(colour); if (msg.empty()) { - if (!m_statictext_printer_msg->GetLabel().empty()) { - m_statictext_printer_msg->SetLabel(wxEmptyString); - m_statictext_printer_msg->Hide(); + if (!m_text_printer_msg->GetLabel().empty()) { + m_text_printer_msg->SetLabel(wxEmptyString); + m_text_printer_msg->Hide(); Layout(); Fit(); } @@ -2000,16 +2117,16 @@ void SelectMachineDialog::update_priner_status_msg(wxString msg, bool is_warning auto str_new = msg.utf8_string(); stripWhiteSpace(str_new); - auto str_old = m_statictext_printer_msg->GetLabel().utf8_string(); + auto str_old = m_text_printer_msg->GetLabel().utf8_string(); stripWhiteSpace(str_old); if (str_new != str_old) { - if (m_statictext_printer_msg->GetLabel() != msg) { - m_statictext_printer_msg->SetLabel(msg); - m_statictext_printer_msg->SetMinSize(wxSize(FromDIP(400), -1)); - m_statictext_printer_msg->SetMaxSize(wxSize(FromDIP(400), -1)); - m_statictext_printer_msg->Wrap(FromDIP(400)); - m_statictext_printer_msg->Show(); + if (m_text_printer_msg->GetLabel() != msg) { + m_text_printer_msg->SetLabel(msg); + m_text_printer_msg->SetMinSize(wxSize(FromDIP(420), -1)); + m_text_printer_msg->SetMaxSize(wxSize(FromDIP(420), -1)); + m_text_printer_msg->Wrap(FromDIP(420)); + m_text_printer_msg->Show(); Layout(); Fit(); } @@ -2962,7 +3079,7 @@ void SelectMachineDialog::on_set_finish_mapping(wxCommandEvent &evt) BOOST_LOG_TRIVIAL(info) << "The ams mapping selection result: data is " << selection_data; - if (selection_data_arr.size() == 6) { + if (selection_data_arr.size() == 8) { auto ams_colour = wxColour(wxAtoi(selection_data_arr[0]), wxAtoi(selection_data_arr[1]), wxAtoi(selection_data_arr[2]), wxAtoi(selection_data_arr[3])); int old_filament_id = (int) wxAtoi(selection_data_arr[5]); if (m_print_type == PrintFromType::FROM_NORMAL) {//todo:support sd card @@ -2994,6 +3111,9 @@ void SelectMachineDialog::on_set_finish_mapping(wxCommandEvent &evt) m_ams_mapping_result[i].color = color.ToStdString(); m_ams_mapping_result[i].ctype = ctype; m_ams_mapping_result[i].colors = tray_cols; + + m_ams_mapping_result[i].ams_id = selection_data_arr[6].ToStdString(); + m_ams_mapping_result[i].slot_id = selection_data_arr[7].ToStdString(); } BOOST_LOG_TRIVIAL(trace) << "The ams mapping result: id is " << m_ams_mapping_result[i].id << "tray_id is " << m_ams_mapping_result[i].tray_id; } @@ -3181,7 +3301,7 @@ void SelectMachineDialog::update_user_printer() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl; } -void SelectMachineDialog::on_rename_click(wxCommandEvent& event) +void SelectMachineDialog::on_rename_click(wxMouseEvent& event) { m_is_rename_mode = true; m_rename_input->GetTextCtrl()->SetValue(m_current_project_name); @@ -3768,11 +3888,10 @@ void SelectMachineDialog::on_dpi_changed(const wxRect &suggested_rect) timeimg->SetBitmap(print_time->bmp()); print_weight->msw_rescale(); weightimg->SetBitmap(print_weight->bmp()); - m_rename_button->msw_rescale(); - ams_editable->msw_rescale(); - ams_editable_light->msw_rescale(); - enable_ams_mapping->msw_rescale(); - img_amsmapping_tip->SetBitmap(enable_ams_mapping->bmp()); + rename_editable->msw_rescale(); + rename_editable_light->msw_rescale(); + ams_mapping_help_icon->msw_rescale(); + img_amsmapping_tip->SetBitmap(ams_mapping_help_icon->bmp()); enable_ams->msw_rescale(); img_use_ams_tip->SetBitmap(enable_ams->bmp()); @@ -4006,8 +4125,8 @@ void SelectMachineDialog::reset_and_sync_ams_list() delete item; iter++; } - - m_sizer_material->Clear(); + + m_sizer_ams_mapping->Clear(); m_materialList.clear(); m_filaments.clear(); @@ -4020,8 +4139,8 @@ void SelectMachineDialog::reset_and_sync_ams_list() auto colour_rgb = wxColour((int) rgb[0], (int) rgb[1], (int) rgb[2], (int) rgb[3]); if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size()) continue; - MaterialItem *item = new MaterialItem(m_scrollable_region, colour_rgb, _L(display_materials[extruder])); - m_sizer_material->Add(item, 0, wxALL, FromDIP(4)); + MaterialItem *item = new MaterialItem(m_filament_panel, colour_rgb, _L(display_materials[extruder])); + m_sizer_ams_mapping->Add(item, 0, wxALL, FromDIP(5)); item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent &e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent &e) { @@ -4078,12 +4197,16 @@ void SelectMachineDialog::reset_and_sync_ams_list() } } - if (extruders.size() <= 4) { - m_sizer_material->SetCols(extruders.size()); - } else { - m_sizer_material->SetCols(4); + /*if (extruders.size() <= 10) { + m_sizer_ams_mapping->SetCols(extruders.size()); } + else { + m_sizer_ams_mapping->SetCols(10); + }*/ + m_sizer_ams_mapping->SetCols(8); + m_sizer_ams_mapping->Layout(); + m_filament_panel_sizer->Layout(); // reset_ams_material();//show "-" } @@ -4354,16 +4477,12 @@ void SelectMachineDialog::set_default_normal(const ThumbnailData &data) image.SetAlpha((int)c, (int)r, px[3]); } } - image = image.Rescale(FromDIP(256), FromDIP(256)); + image = image.Rescale(FromDIP(198), FromDIP(198)); m_thumbnailPanel->set_thumbnail(image); } - m_scrollable_region->Layout(); - m_scrollable_region->Fit(); - - m_scrollable_view->SetSize(m_scrollable_region->GetSize()); - m_scrollable_view->SetMinSize(m_scrollable_region->GetSize()); - m_scrollable_view->SetMaxSize(m_scrollable_region->GetSize()); + m_basic_panel->Layout(); + m_basic_panel->Fit(); //disable pei bed DeviceManager* dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager(); @@ -4375,16 +4494,7 @@ void SelectMachineDialog::set_default_normal(const ThumbnailData &data) auto dialogSize = this->GetSize(); #ifdef __WINDOWS__ - if (screenSize.GetHeight() < dialogSize.GetHeight()) { - m_need_adaptation_screen = true; - m_scrollable_view->SetScrollRate(0, 5); - m_scrollable_view->SetSize(wxSize(-1, FromDIP(220))); - m_scrollable_view->SetMinSize(wxSize(-1, FromDIP(220))); - m_scrollable_view->SetMaxSize(wxSize(-1, FromDIP(220))); - } - else { - m_scrollable_view->SetScrollRate(0, 0); - } + #endif // __WXOSX_MAC__ // basic info auto aprint_stats = m_plater->get_partplate_list().get_current_fff_print().print_statistics(); @@ -4416,7 +4526,7 @@ void SelectMachineDialog::set_default_from_sdcard() if (data.pixels.size() > 0) { wxMemoryInputStream mis((unsigned char*)data.pixels.data(), data.pixels.size()); wxImage image = wxImage(mis); - image = image.Rescale(FromDIP(256), FromDIP(256)); + image = image.Rescale(FromDIP(198), FromDIP(198)); m_thumbnailPanel->set_thumbnail(image); } @@ -4443,7 +4553,7 @@ void SelectMachineDialog::set_default_from_sdcard() } m_ams_mapping_result.clear(); - m_sizer_material->Clear(); + m_sizer_ams_mapping->Clear(); m_materialList.clear(); m_filaments.clear(); @@ -4451,8 +4561,8 @@ void SelectMachineDialog::set_default_from_sdcard() for (auto i = 0; i < m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size(); i++) { FilamentInfo fo = m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info[i]; - MaterialItem* item = new MaterialItem(m_scrollable_region, wxColour(fo.color), fo.type); - m_sizer_material->Add(item, 0, wxALL, FromDIP(4)); + MaterialItem* item = new MaterialItem(m_filament_panel, wxColour(fo.color), fo.type); + m_sizer_ams_mapping->Add(item, 0, wxALL, FromDIP(5)); item->Bind(wxEVT_LEFT_UP, [this, item, materials](wxMouseEvent& e) {}); item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, fo](wxMouseEvent& e) { @@ -4509,38 +4619,21 @@ void SelectMachineDialog::set_default_from_sdcard() } if (m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size() <= 4) { - m_sizer_material->SetCols(m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size()); + m_sizer_ams_mapping->SetCols(m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size()); } else { - m_sizer_material->SetCols(4); + m_sizer_ams_mapping->SetCols(4); } - m_scrollable_region->Layout(); - m_scrollable_region->Fit(); + m_basic_panel->Layout(); + m_basic_panel->Fit(); - m_scrollable_view->SetSize(m_scrollable_region->GetSize()); - m_scrollable_view->SetMinSize(m_scrollable_region->GetSize()); - m_scrollable_view->SetMaxSize(m_scrollable_region->GetSize()); set_flow_calibration_state(true); wxSize screenSize = wxGetDisplaySize(); auto dialogSize = this->GetSize(); -#ifdef __WINDOWS__ - if (screenSize.GetHeight() < dialogSize.GetHeight()) { - m_need_adaptation_screen = true; - m_scrollable_view->SetScrollRate(0, 5); - m_scrollable_view->SetSize(wxSize(-1, FromDIP(220))); - m_scrollable_view->SetMinSize(wxSize(-1, FromDIP(220))); - m_scrollable_view->SetMaxSize(wxSize(-1, FromDIP(220))); - } - else { - m_scrollable_view->SetScrollRate(0, 0); - } -#endif // __WXOSX_MAC__ - - reset_ams_material(); // basic info @@ -4559,32 +4652,32 @@ void SelectMachineDialog::set_default_from_sdcard() void SelectMachineDialog::update_page_turn_state(bool show) { - m_bitmap_last_plate->Show(show); - m_bitmap_next_plate->Show(show); + /* m_bitmap_last_plate->Show(show); + m_bitmap_next_plate->Show(show); - if (show) { - if (m_print_plate_idx <= 0) { m_bitmap_last_plate->Hide(); } - else { m_bitmap_last_plate->Show(); } + if (show) { + if (m_print_plate_idx <= 0) { m_bitmap_last_plate->Hide(); } + else { m_bitmap_last_plate->Show(); } - if ((m_print_plate_idx + 1) >= m_print_plate_total) { m_bitmap_next_plate->Hide(); } - else { m_bitmap_next_plate->Show(); } + if ((m_print_plate_idx + 1) >= m_print_plate_total) { m_bitmap_next_plate->Hide(); } + else { m_bitmap_next_plate->Show(); } - if (m_print_plate_total == 1) { - m_bitmap_last_plate->Show(false); - m_bitmap_next_plate->Show(false); - } - } + if (m_print_plate_total == 1) { + m_bitmap_last_plate->Show(false); + m_bitmap_next_plate->Show(false); + } + }*/ } void SelectMachineDialog::sys_color_changed() { if (wxGetApp(). dark_mode()) { //rename_button->SetIcon("ams_editable_light"); - m_rename_button->SetBitmap(ams_editable_light->bmp()); + m_rename_button->SetBitmap(rename_editable_light->bmp()); } else { - m_rename_button->SetBitmap(ams_editable->bmp()); + m_rename_button->SetBitmap(rename_editable->bmp()); } m_rename_button->Refresh(); } diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index a399ca7930e..e43bbe7a2d0 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -347,7 +347,6 @@ class SelectMachineDialog : public DPIDialog bool m_is_in_sending_mode{ false }; bool m_ams_mapping_res{ false }; bool m_ams_mapping_valid{ false }; - bool m_need_adaptation_screen{ false }; bool m_export_3mf_cancel{ false }; bool m_is_canceled{ false }; bool m_is_rename_mode{ false }; @@ -385,18 +384,17 @@ class SelectMachineDialog : public DPIDialog AmsTutorialPopup m_mapping_tutorial_popup{ nullptr }; MaterialHash m_materialList; Plater * m_plater{nullptr}; - wxWrapSizer* m_sizer_select{ nullptr }; + wxBoxSizer* m_sizer_options{ nullptr }; wxBoxSizer* m_sizer_thumbnail{ nullptr }; - wxGridSizer* m_sizer_material{ nullptr }; + wxBoxSizer* m_sizer_main{ nullptr }; - wxBoxSizer* m_sizer_scrollable_view{ nullptr }; - wxBoxSizer* m_sizer_scrollable_region{ nullptr }; + wxBoxSizer* m_basicl_sizer{ nullptr }; wxBoxSizer* rename_sizer_v{ nullptr }; wxBoxSizer* rename_sizer_h{ nullptr }; - wxBoxSizer* m_sizer_backup{ nullptr }; + wxBoxSizer* m_sizer_autorefill{ nullptr }; Button* m_button_refresh{ nullptr }; Button* m_button_ensure{ nullptr }; - ScalableButton * m_rename_button{nullptr}; + wxStaticBitmap * m_rename_button{nullptr}; ComboBox* m_comboBox_printer{ nullptr }; wxStaticBitmap* m_staticbitmap{ nullptr }; wxStaticBitmap* m_bitmap_last_plate{ nullptr }; @@ -408,15 +406,12 @@ class SelectMachineDialog : public DPIDialog wxWindow* select_timelapse{ nullptr }; wxWindow* select_use_ams{ nullptr }; wxPanel* m_panel_status{ nullptr }; - wxPanel* m_scrollable_region; + wxPanel* m_basic_panel; wxPanel* m_rename_normal_panel{nullptr}; - wxPanel* m_line_schedule{nullptr}; wxPanel* m_panel_sending{nullptr}; wxPanel* m_panel_prepare{nullptr}; wxPanel* m_panel_finish{nullptr}; wxPanel* m_line_top{ nullptr }; - wxPanel* m_panel_image{ nullptr }; - wxPanel* m_line_materia{ nullptr }; Label* m_st_txt_error_code{nullptr}; Label* m_st_txt_error_desc{nullptr}; Label* m_st_txt_extra_info{nullptr}; @@ -425,26 +420,25 @@ class SelectMachineDialog : public DPIDialog wxSimplebook* m_rename_switch_panel{nullptr}; wxSimplebook* m_simplebook{nullptr}; wxStaticText* m_rename_text{nullptr}; - wxStaticText* m_stext_printer_title{nullptr}; - wxStaticText* m_stext_time{ nullptr }; - wxStaticText* m_stext_weight{ nullptr }; + Label* m_stext_printer_title{nullptr}; + Label* m_stext_time{ nullptr }; + Label* m_stext_weight{ nullptr }; wxStaticText* m_statictext_ams_msg{ nullptr }; - wxStaticText* m_statictext_printer_msg{ nullptr }; + wxStaticText* m_text_printer_msg{ nullptr }; wxStaticText* m_staticText_bed_title{ nullptr }; wxStaticText* m_stext_sending{ nullptr }; wxStaticText* m_statictext_finish{nullptr}; TextInput* m_rename_input{nullptr}; wxTimer* m_refresh_timer{ nullptr }; - wxScrolledWindow* m_scrollable_view; wxScrolledWindow* m_sw_print_failed_info{nullptr}; wxHyperlinkCtrl* m_hyperlink{nullptr}; - ScalableBitmap * ams_editable{nullptr}; - ScalableBitmap * ams_editable_light{nullptr}; + ScalableBitmap * rename_editable{nullptr}; + ScalableBitmap * rename_editable_light{nullptr}; wxStaticBitmap * timeimg{nullptr}; ScalableBitmap * print_time{nullptr}; wxStaticBitmap * weightimg{nullptr}; ScalableBitmap * print_weight{nullptr}; - ScalableBitmap * enable_ams_mapping{nullptr}; + ScalableBitmap * ams_mapping_help_icon{nullptr}; wxStaticBitmap * img_use_ams_tip{nullptr}; wxStaticBitmap * img_ams_backup{nullptr}; ScalableBitmap * enable_ams{nullptr}; @@ -455,6 +449,19 @@ class SelectMachineDialog : public DPIDialog std::vector m_cur_colors_in_thumbnail; std::vector m_edge_pixels; + wxPanel* m_filament_panel; + wxPanel* m_filament_left_panel; + wxPanel* m_filament_right_panel; + + wxBoxSizer* m_filament_panel_sizer; + wxBoxSizer* m_filament_panel_left_sizer; + wxBoxSizer* m_filament_panel_right_sizer; + wxBoxSizer* m_sizer_filament_2extruder; + + wxGridSizer* m_sizer_ams_mapping{ nullptr }; + wxGridSizer* m_sizer_ams_mapping_left{ nullptr }; + wxGridSizer* m_sizer_ams_mapping_right{ nullptr }; + public: SelectMachineDialog(Plater *plater = nullptr); ~SelectMachineDialog(); @@ -478,7 +485,7 @@ class SelectMachineDialog : public DPIDialog void reset_ams_material(); void update_show_status(); void update_ams_check(MachineObject* obj); - void on_rename_click(wxCommandEvent& event); + void on_rename_click(wxMouseEvent& event); void on_rename_enter(); void update_printer_combobox(wxCommandEvent& event); void on_cancel(wxCloseEvent& event); From 461d42635f55c55ab1d3a5db52a5ddc827b631c1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 1 May 2025 16:23:56 +0800 Subject: [PATCH 006/127] Add option to toggle between legacy and new network plugins --- src/libslic3r/AppConfig.cpp | 3 +++ src/slic3r/GUI/GUI_App.cpp | 14 ++++++++++++++ src/slic3r/GUI/Preferences.cpp | 8 ++++++++ src/slic3r/GUI/Preferences.hpp | 1 + 4 files changed, 26 insertions(+) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 588d1e0c0a1..4cb3c79207c 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -254,6 +254,9 @@ void AppConfig::set_defaults() if (get("stealth_mode").empty()) { set_bool("stealth_mode", false); } + if (get("legacy_networking").empty()) { + set_bool("legacy_networking", true); + } if(get("check_stable_update_only").empty()) { set_bool("check_stable_update_only", false); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index d9818d9f626..a3ae80e339e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2516,6 +2516,20 @@ bool GUI_App::on_init_inner() std::map extra_headers = get_extra_header(); Slic3r::Http::set_extra_headers(extra_headers); + // Orca: select network plugin version + NetworkAgent::use_legacy_network = app_config->get_bool("legacy_networking"); + // Force legacy network plugin if debugger attached + // See https://github.com/bambulab/BambuStudio/issues/6726 + if (!NetworkAgent::use_legacy_network) { + bool debugger_attached = false; +#ifdef __WINDOWS__ + debugger_attached = IsDebuggerPresent(); +#endif + if (debugger_attached) { + NetworkAgent::use_legacy_network = true; + wxMessageBox("Force using legacy bambu networking plugin because debugger is attached! If the app terminates itself immediately, please delete installed plugin and try again!"); + } + } copy_network_if_available(); on_init_network(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 6cd76cfda46..79a93c759ac 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -804,6 +804,7 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxWindow *pa if (pbool) { GUI::wxGetApp().CallAfter([] { GUI::wxGetApp().ShowDownNetPluginDlg(); }); } + if (m_legacy_networking_ckeckbox != nullptr) { m_legacy_networking_ckeckbox->Enable(pbool); } } #endif // __WXMSW__ @@ -834,6 +835,11 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxWindow *pa //// for debug mode if (param == "developer_mode") { m_developer_mode_ckeckbox = checkbox; } if (param == "internal_developer_mode") { m_internal_developer_mode_ckeckbox = checkbox; } + if (param == "legacy_networking") { + m_legacy_networking_ckeckbox = checkbox; + bool pbool = app_config->get_bool("installed_networking"); + checkbox->Enable(pbool); + } checkbox->SetToolTip(tooltip); @@ -1199,6 +1205,7 @@ wxWindow* PreferencesDialog::create_general_page() auto item_stealth_mode = create_item_checkbox(_L("Stealth Mode"), page, _L("This stops the transmission of data to Bambu's cloud services. Users who don't use BBL machines or use LAN mode only can safely turn on this function."), 50, "stealth_mode"); auto item_enable_plugin = create_item_checkbox(_L("Enable network plugin"), page, _L("Enable network plugin"), 50, "installed_networking"); + auto item_legacy_network_plugin = create_item_checkbox(_L("Use legacy network plugin (Take effect after restarting Orca)"), page, _L("Disable to use latest network plugin that support new BambuLab firmwares."), 50, "legacy_networking"); auto item_check_stable_version_only = create_item_checkbox(_L("Check for stable updates only"), page, _L("Check for stable updates only"), 50, "check_stable_update_only"); std::vector Units = {_L("Metric") + " (mm, g)", _L("Imperial") + " (in, oz)"}; @@ -1322,6 +1329,7 @@ wxWindow* PreferencesDialog::create_general_page() sizer_page->Add(item_check_stable_version_only, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_stealth_mode, 0, wxTOP, FromDIP(3)); sizer_page->Add(item_enable_plugin, 0, wxTOP, FromDIP(3)); + sizer_page->Add(item_legacy_network_plugin, 0, wxTOP, FromDIP(3)); #ifdef _WIN32 sizer_page->Add(title_associate_file, 0, wxTOP| wxEXPAND, FromDIP(20)); sizer_page->Add(item_associate_3mf, 0, wxTOP, FromDIP(3)); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 5977397e168..e65ae52d35a 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -93,6 +93,7 @@ class PreferencesDialog : public DPIDialog ::CheckBox * m_internal_developer_mode_ckeckbox = {nullptr}; ::CheckBox * m_dark_mode_ckeckbox = {nullptr}; ::TextInput *m_backup_interval_textinput = {nullptr}; + ::CheckBox * m_legacy_networking_ckeckbox = {nullptr}; wxString m_developer_mode_def; wxString m_internal_developer_mode_def; From f5d58bb9f0a0e361826aa362014fea607c45949d Mon Sep 17 00:00:00 2001 From: tao wang Date: Tue, 1 Apr 2025 16:51:00 +0800 Subject: [PATCH 007/127] ENH:support printing all plate jira:[none] Change-Id: I528129705ad2b6e81cb7d0b625d3a9228baf9cf1 (cherry picked from commit 00f4fbb5a6723ba4977cb18802c65bf8dedf6e29) --- resources/printers/C11.json | 5 +++++ resources/printers/C12.json | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/resources/printers/C11.json b/resources/printers/C11.json index a2cbbb078a5..83c403b44a1 100644 --- a/resources/printers/C11.json +++ b/resources/printers/C11.json @@ -84,5 +84,10 @@ }, "support_user_preset":true } + }, + "01.07.50.00": { + "print": { + "support_print_all": true + } } } diff --git a/resources/printers/C12.json b/resources/printers/C12.json index 5cc12a1a66f..66f7f3a9745 100644 --- a/resources/printers/C12.json +++ b/resources/printers/C12.json @@ -76,5 +76,10 @@ }, "support_user_preset":true } + }, + "01.07.50.00": { + "print": { + "support_print_all": true + } } } From 569814d77cebf95f64e25e9e5c5c2285ed6ec994 Mon Sep 17 00:00:00 2001 From: tao wang Date: Wed, 16 Oct 2024 13:11:15 +0800 Subject: [PATCH 008/127] ENH:Hide multi disk switching jira:[for demo] Change-Id: I4cbfde15ec2b6f7e8aa68e8654ebea0e9cb09b9c (cherry picked from commit 370be63709f1d8f3bdaa923023b71afed0391edb) --- src/slic3r/GUI/SelectMachine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 0f1ae0295b8..69d52e544c4 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1119,10 +1119,12 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) auto last_plate_sizer = new wxBoxSizer(wxVERTICAL); m_bitmap_last_plate = new wxStaticBitmap(m_basic_panel, wxID_ANY, create_scaled_bitmap("go_last_plate", this, 25), wxDefaultPosition, wxSize(FromDIP(25), FromDIP(25)), 0); + m_bitmap_last_plate->Hide(); last_plate_sizer->Add(m_bitmap_last_plate, 0, wxALIGN_CENTER, 0); auto next_plate_sizer = new wxBoxSizer(wxVERTICAL); m_bitmap_next_plate = new wxStaticBitmap(m_basic_panel, wxID_ANY, create_scaled_bitmap("go_next_plate", this, 25), wxDefaultPosition, wxSize(FromDIP(25), FromDIP(25)), 0); + m_bitmap_next_plate->Hide(); next_plate_sizer->Add(m_bitmap_next_plate, 0, wxALIGN_CENTER, 0); sizer_rename->Add(m_rename_switch_panel, 0, wxALIGN_CENTER, 0); From 7c60219ab16fe4a436d76860834cc9444f461332 Mon Sep 17 00:00:00 2001 From: tao wang Date: Wed, 1 Jan 2025 17:44:36 +0800 Subject: [PATCH 009/127] FIX:fixed the issue of multiple plates object card not flip pages jira:[STUDIO-9373] Change-Id: I520b2626da8dc3acc066b2ea26a5f8d3c27f64fb (cherry picked from commit aee0cb382ba40607c278dbd68e5134fa26a2027c) --- src/slic3r/GUI/SelectMachine.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 69d52e544c4..3cb97862583 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -4075,8 +4075,7 @@ void SelectMachineDialog::set_default() set_default_normal(m_plater->get_partplate_list().get_curr_plate()->thumbnail_data); } else if (m_print_type == PrintFromType::FROM_SDCARD_VIEW) { - //todo:unify_deal_thumbnail_data(input_data, no_light_data);this include m_print_type = PrintFromType::FROM_SDCARD_VIEW - //and notice update_page_turn_state(true) + update_page_turn_state(true); set_default_from_sdcard(); } @@ -4654,21 +4653,21 @@ void SelectMachineDialog::set_default_from_sdcard() void SelectMachineDialog::update_page_turn_state(bool show) { - /* m_bitmap_last_plate->Show(show); + m_bitmap_last_plate->Show(show); m_bitmap_next_plate->Show(show); if (show) { - if (m_print_plate_idx <= 0) { m_bitmap_last_plate->Hide(); } - else { m_bitmap_last_plate->Show(); } + if (m_print_plate_idx <= 0) { m_bitmap_last_plate->Disable(); } + else { m_bitmap_last_plate->Enable(); } - if ((m_print_plate_idx + 1) >= m_print_plate_total) { m_bitmap_next_plate->Hide(); } - else { m_bitmap_next_plate->Show(); } + if ((m_print_plate_idx + 1) >= m_print_plate_total) { m_bitmap_next_plate->Disable(); } + else { m_bitmap_next_plate->Enable(); } if (m_print_plate_total == 1) { m_bitmap_last_plate->Show(false); m_bitmap_next_plate->Show(false); } - }*/ + } } void SelectMachineDialog::sys_color_changed() From b9729f872ae37fdd54f5b56f3a8e712776654f73 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 5 May 2025 17:17:03 +0800 Subject: [PATCH 010/127] Fix crash when start print from sdcard --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7c2c72800aa..cb2a37f6098 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -7813,7 +7813,7 @@ wxString Plater::priv::get_export_gcode_filename(const wxString& extension, bool } } else { if (only_filename) { - if(m_project_name == _L("Untitled")) + if(!model.objects.empty() && m_project_name == _L("Untitled")) return wxString(fs::path(model.objects.front()->name).replace_extension().c_str()) + from_u8(plate_index_str) + extension; if (export_all) From 78a09d9be6f4ba70ebaa6721fb0f8f29c5e6caee Mon Sep 17 00:00:00 2001 From: "hang.xu" Date: Mon, 12 Aug 2024 17:27:40 +0800 Subject: [PATCH 011/127] FIX: Add bed type in send print page jira: STUDIO-7824 Change-Id: I64d9ed41b862ed4e3b8c21218c289132d767105e (cherry picked from commit 7bb5060b739b3a95fe889ae64e8d7289e2c928d9) --- src/slic3r/GUI/SelectMachine.cpp | 27 ++++++++++++++++++++++++++- src/slic3r/GUI/SelectMachine.hpp | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 3cb97862583..ef4c39ac9a0 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1111,7 +1111,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_sizer_basic_weight_time->Add(m_stext_weight, 0, wxALIGN_CENTER|wxLEFT, FromDIP(6)); /*bed type*/ - auto m_text_bed_type = new Label(m_basic_panel, "Plate: Textured PEI"); + m_text_bed_type = new Label(m_basic_panel); m_text_bed_type->SetFont(Label::Body_13); /*last & next page*/ @@ -4685,6 +4685,31 @@ void SelectMachineDialog::sys_color_changed() bool SelectMachineDialog::Show(bool show) { + show_status(PrintDialogStatus::PrintStatusInit); + + const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type"); + PresetBundle& preset_bundle = *wxGetApp().preset_bundle; + auto cur_preset_name = preset_bundle.printers.get_edited_preset().name; + auto name = wxGetApp().app_config->get_section("user_bed_type_list"); + std::string plate_name = ""; + for (auto it : name) { + if (it.first == cur_preset_name) { + plate_name = it.second; + break; + } + } + if (bed_type_def != nullptr){ + for (auto it : bed_type_def->enum_labels) { + if (it.find(plate_name) != std::string::npos) { + plate_name = it; + break; + } + } + } + + plate_name = "Plate: " + plate_name; + m_text_bed_type->SetLabelText(plate_name); + // set default value when show this dialog if (show) { m_refresh_timer->Start(LIST_REFRESH_INTERVAL); diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index e43bbe7a2d0..ac43251511a 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -360,6 +360,7 @@ class SelectMachineDialog : public DPIDialog wxColour m_colour_def_color{wxColour(255, 255, 255)}; wxColour m_colour_bold_color{wxColour(38, 46, 48)}; StateColor m_btn_bg_enable; + Label* m_text_bed_type; std::shared_ptr m_token = std::make_shared(0); std::map m_checkbox_list; From c5c3fdc321c9990745d1e9062be033bf82370fdf Mon Sep 17 00:00:00 2001 From: "hang.xu" Date: Fri, 16 Aug 2024 11:50:18 +0800 Subject: [PATCH 012/127] FIX: Bed type display jira: none Change-Id: Ibac2a7a80d6841ebea639e0a58547413df6f5c74 (cherry picked from commit 2c3fa062c92da50f839432a43356d491c2e5bbba) --- src/slic3r/GUI/SelectMachine.cpp | 37 +++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index ef4c39ac9a0..f99f93a609a 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -4687,28 +4687,35 @@ bool SelectMachineDialog::Show(bool show) { show_status(PrintDialogStatus::PrintStatusInit); - const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type"); PresetBundle& preset_bundle = *wxGetApp().preset_bundle; auto cur_preset_name = preset_bundle.printers.get_edited_preset().name; - auto name = wxGetApp().app_config->get_section("user_bed_type_list"); - std::string plate_name = ""; - for (auto it : name) { - if (it.first == cur_preset_name) { - plate_name = it.second; - break; - } - } - if (bed_type_def != nullptr){ - for (auto it : bed_type_def->enum_labels) { - if (it.find(plate_name) != std::string::npos) { - plate_name = it; + + if (wxGetApp().app_config->has_section("user_bed_type_list")) { + std::string plate_name = ""; + auto name = wxGetApp().app_config->get_section("user_bed_type_list"); + for (auto it : name) { + if (it.first == cur_preset_name) { + plate_name = it.second; break; } } + const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type"); + if (bed_type_def != nullptr) { + for (auto it : bed_type_def->enum_labels) { + if (it.find(plate_name) != std::string::npos) { + plate_name = it; + break; + } + } + } + plate_name = "Plate: " + plate_name; + m_text_bed_type->SetLabelText(plate_name); + m_text_bed_type->Show(); + } + else{ + m_text_bed_type->Hide(); } - plate_name = "Plate: " + plate_name; - m_text_bed_type->SetLabelText(plate_name); // set default value when show this dialog if (show) { From c4c670c995f2c804d9e0bf44ba29e6f038ac03d2 Mon Sep 17 00:00:00 2001 From: tao wang Date: Thu, 17 Oct 2024 10:08:47 +0800 Subject: [PATCH 013/127] FIX:fix the issue of macOS crashing easily jira:[udesk 7578206] Change-Id: If5e0b2d0969ca70815a5d2c9cca71654c9e1817b (cherry picked from commit 8dfa6839e5e3a9bebb03616ff6d0c0c1699ad22f) --- src/slic3r/GUI/SelectMachine.cpp | 48 +++++++++++++++----------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index f99f93a609a..caa5464dbac 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -4685,6 +4685,22 @@ void SelectMachineDialog::sys_color_changed() bool SelectMachineDialog::Show(bool show) { + if (show) { + m_refresh_timer->Start(LIST_REFRESH_INTERVAL); + } else { + m_refresh_timer->Stop(); + + DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (dev) { + MachineObject *obj_ = dev->get_selected_machine(); + if (obj_ && obj_->connection_type() == "cloud" /*&& m_print_type == FROM_SDCARD_VIEW*/) { + if (obj_->is_connected()) { obj_->disconnect(); } + } + } + + return DPIDialog::Show(false); + } + show_status(PrintDialogStatus::PrintStatusInit); PresetBundle& preset_bundle = *wxGetApp().preset_bundle; @@ -4715,34 +4731,16 @@ bool SelectMachineDialog::Show(bool show) else{ m_text_bed_type->Hide(); } - // set default value when show this dialog - if (show) { - m_refresh_timer->Start(LIST_REFRESH_INTERVAL); - show_status(PrintDialogStatus::PrintStatusInit); - wxGetApp().UpdateDlgDarkUI(this); - wxGetApp().reset_to_active(); - set_default(); - update_user_machine_list(); - - Layout(); - Fit(); - CenterOnParent(); - } - else { - m_refresh_timer->Stop(); - DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (dev) { - MachineObject* obj_ = dev->get_selected_machine(); - if (obj_ && obj_->connection_type() == "cloud" /*&& m_print_type == FROM_SDCARD_VIEW*/) { - if (obj_->is_connected()) { - obj_->disconnect(); - } + wxGetApp().UpdateDlgDarkUI(this); + wxGetApp().reset_to_active(); + set_default(); + update_user_machine_list(); - } - } - } + Layout(); + Fit(); + CenterOnParent(); return DPIDialog::Show(show); } From d40be52f186a457c7636d84a1843fd6f7eec2c1c Mon Sep 17 00:00:00 2001 From: "xun.zhang" Date: Mon, 25 Nov 2024 20:54:24 +0800 Subject: [PATCH 014/127] FIX: wrong curr bed type in print page 1.Get bed type from project config jira:NONE Signed-off-by: xun.zhang Change-Id: I1f1b9185dd4592b5fd3b03f07e8cde7b7d26510e (cherry picked from commit 1c90355199384903f166730c5bb43c6a6baaa1cf) --- src/slic3r/GUI/SelectMachine.cpp | 37 ++++++++++++-------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index caa5464dbac..0cd31183831 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -4704,33 +4704,24 @@ bool SelectMachineDialog::Show(bool show) show_status(PrintDialogStatus::PrintStatusInit); PresetBundle& preset_bundle = *wxGetApp().preset_bundle; - auto cur_preset_name = preset_bundle.printers.get_edited_preset().name; - - if (wxGetApp().app_config->has_section("user_bed_type_list")) { - std::string plate_name = ""; - auto name = wxGetApp().app_config->get_section("user_bed_type_list"); - for (auto it : name) { - if (it.first == cur_preset_name) { - plate_name = it.second; - break; - } - } - const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type"); - if (bed_type_def != nullptr) { - for (auto it : bed_type_def->enum_labels) { - if (it.find(plate_name) != std::string::npos) { - plate_name = it; - break; - } - } - } + const auto& project_config = preset_bundle.project_config; + + const t_config_enum_values &enum_keys_map = ConfigOptionEnum::get_enum_values(); + const ConfigOptionEnum* bed_type=project_config.option>("curr_bed_type"); + std::string plate_name; + for (auto& elem : enum_keys_map) { + if (elem.second == bed_type->value) + plate_name = elem.first; + } + + if (plate_name.empty()) { + m_text_bed_type->Hide(); + } + else { plate_name = "Plate: " + plate_name; m_text_bed_type->SetLabelText(plate_name); m_text_bed_type->Show(); } - else{ - m_text_bed_type->Hide(); - } // set default value when show this dialog wxGetApp().UpdateDlgDarkUI(this); From dad7320f4b93d7821a64de5b0a50dbf47d95ab12 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 6 May 2025 22:58:57 +0800 Subject: [PATCH 015/127] Fix setting AMS calib profile ENH: calib support multi_extruder 1. backend support multi_extrude data structure 2. Compatible with third-party calibration (cherry picked from commit bambulab/BambuStudio@21e6271e59ea8e4924866275566617d14a4b2b6e) Co-authored-by: zhimin.zeng --- src/libslic3r/PrintConfig.hpp | 6 +++ src/libslic3r/calib.hpp | 32 +++++++++++++- src/slic3r/GUI/CaliHistoryDialog.cpp | 25 +++++++---- src/slic3r/GUI/CalibrationWizard.cpp | 32 +++++++------- src/slic3r/GUI/DeviceManager.cpp | 62 ++++++++++++++++++++++++---- src/slic3r/GUI/DeviceManager.hpp | 18 ++++---- src/slic3r/GUI/StatusPanel.cpp | 6 ++- src/slic3r/Utils/CalibUtils.cpp | 8 ++-- src/slic3r/Utils/CalibUtils.hpp | 11 +++-- 9 files changed, 148 insertions(+), 52 deletions(-) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f99b560592c..c8d1f6a218f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -317,6 +317,12 @@ enum ZHopType { zhtCount }; +enum NozzleVolumeType { + nvtNormal = 0, + nvtBigTraffic, + nvtMaxNozzleVolumeType = nvtBigTraffic +}; + enum RetractLiftEnforceType { rletAllSurfaces = 0, rletTopOnly, diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index c9a950d8860..e862cf7b5c1 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -32,6 +32,7 @@ enum class CalibState { Start = 0, Preset, Calibration, CoarseSave, FineCalibrat struct Calib_Params { Calib_Params() : mode(CalibMode::Calib_None){}; + int extruder_id = 0; double start, end, step; bool print_numbers; double freqStartX, freqEndX, freqStartY, freqEndY; @@ -52,8 +53,12 @@ class X1CCalibInfos public: struct X1CCalibInfo { + int extruder_id = -1; int tray_id; + int ams_id = 0; + int slot_id = 0; int bed_temp; + NozzleVolumeType nozzle_volume_type = NozzleVolumeType::nvtNormal; int nozzle_temp; float nozzle_diameter; std::string filament_id; @@ -102,7 +107,11 @@ class PACalibResult CALI_RESULT_PROBLEM = 1, CALI_RESULT_FAILED = 2, }; - int tray_id; + int extruder_id = -1; + NozzleVolumeType nozzle_volume_type; + int tray_id = 0; + int ams_id = 0; + int slot_id = 0; int cali_idx = -1; float nozzle_diameter; std::string filament_id; @@ -115,12 +124,31 @@ class PACalibResult struct PACalibIndexInfo { - int tray_id; + int extruder_id = -1; + NozzleVolumeType nozzle_volume_type; + int tray_id = 0; + int ams_id = 0; + int slot_id = 0; int cali_idx; float nozzle_diameter; std::string filament_id; }; +struct PACalibExtruderInfo +{ + int extruder_id; + NozzleVolumeType nozzle_volume_type; + float nozzle_diameter; + std::string filament_id = ""; +}; + +struct PACalibTabInfo +{ + float pa_calib_tab_nozzle_dia; + int extruder_id; + NozzleVolumeType nozzle_volume_type; +}; + class FlowRatioCalibResult { public: diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 7224ec34e2f..fd68b4bbf95 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -11,7 +11,7 @@ namespace Slic3r { namespace GUI { - + #define HISTORY_WINDOW_SIZE wxSize(FromDIP(700), FromDIP(600)) #define EDIT_HISTORY_DIALOG_INPUT_SIZE wxSize(FromDIP(160), FromDIP(24)) #define NEW_HISTORY_DIALOG_INPUT_SIZE wxSize(FromDIP(250), FromDIP(24)) @@ -217,20 +217,22 @@ void HistoryWindow::update(MachineObject* obj) void HistoryWindow::on_select_nozzle(wxCommandEvent& evt) { reqeust_history_result(curr_obj); - + } void HistoryWindow::reqeust_history_result(MachineObject* obj) { if (curr_obj) { - // reset + // reset curr_obj->reset_pa_cali_history_result(); m_calib_results_history.clear(); sync_history_data(); float nozzle_value = get_nozzle_value(); if (nozzle_value > 0) { - CalibUtils::emit_get_PA_calib_infos(nozzle_value); + PACalibExtruderInfo cali_info; + cali_info.nozzle_diameter = nozzle_value; + CalibUtils::emit_get_PA_calib_infos(cali_info); m_tips->SetLabel(_L("Refreshing the historical Flow Dynamics Calibration records")); BOOST_LOG_TRIVIAL(info) << "request calib history"; } @@ -303,7 +305,12 @@ void HistoryWindow::sync_history_data() { gbSizer->SetEmptyCellSize({ 0,0 }); m_history_data_panel->Layout(); m_history_data_panel->Fit(); - CalibUtils::delete_PA_calib_result({ result.tray_id, result.cali_idx, result.nozzle_diameter, result.filament_id }); + PACalibIndexInfo cali_info; + cali_info.tray_id = result.tray_id; + cali_info.cali_idx = result.cali_idx; + cali_info.nozzle_diameter = result.nozzle_diameter; + cali_info.filament_id = result.filament_id; + CalibUtils::delete_PA_calib_result(cali_info); }); auto edit_button = new Button(m_history_data_panel, _L("Edit")); @@ -468,7 +475,7 @@ void EditCalibrationHistoryDialog::on_save(wxCommandEvent& event) { return; m_new_result.name = m_name_value->GetTextCtrl()->GetValue().ToUTF8().data(); - + float k = 0.0f; if (!CalibUtils::validate_input_k_value(m_k_value->GetTextCtrl()->GetValue(), &k)) { MessageDialog msg_dlg(nullptr, wxString::Format(_L("Please input a valid value (K in %.1f~%.1f)"), MIN_PA_K_VALUE, MAX_PA_K_VALUE), wxEmptyString, wxICON_WARNING | wxOK); @@ -620,7 +627,7 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const m_comboBox_nozzle_diameter->SetSelection(i); } } - + // Nozzle Diameter flex_sizer->Add(nozzle_diameter_title); flex_sizer->Add(m_comboBox_nozzle_diameter); @@ -628,7 +635,7 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const Label *k_title = new Label(top_panel, _L("Factor K")); auto k_str = wxString::Format("%.3f", m_new_result.k_value); m_k_value = new TextInput(top_panel, k_str, "", "", wxDefaultPosition, NEW_HISTORY_DIALOG_INPUT_SIZE, wxTE_PROCESS_ENTER); - + // Factor K flex_sizer->Add(k_title); flex_sizer->Add(m_k_value); @@ -703,7 +710,7 @@ void NewCalibrationHistoryDialog::on_ok(wxCommandEvent &event) m_new_result.k_value = k; m_new_result.tray_id = -1; m_new_result.cali_idx = -1; - + m_new_result.nozzle_diameter = nozzle_value; m_new_result.filament_id = filament_id; m_new_result.setting_id = setting_id; diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index 3e0f7e6eb03..169e18cd09c 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -46,7 +46,7 @@ bool is_pa_params_valid(const Calib_Params& params) } CalibrationWizard::CalibrationWizard(wxWindow* parent, CalibMode mode, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) - : wxPanel(parent, id, pos, size, style) + : wxPanel(parent, id, pos, size, style) , m_mode(mode) { SetBackgroundColour(wxColour(0xEEEEEE)); @@ -58,8 +58,8 @@ CalibrationWizard::CalibrationWizard(wxWindow* parent, CalibMode mode, wxWindowI m_scrolledWindow->SetBackgroundColour(*wxWHITE); wxBoxSizer* padding_sizer = new wxBoxSizer(wxHORIZONTAL); - padding_sizer->Add(0, 0, 1); - + padding_sizer->Add(0, 0, 1); + m_all_pages_sizer = new wxBoxSizer(wxVERTICAL); padding_sizer->Add(m_all_pages_sizer, 0); @@ -320,7 +320,7 @@ void CalibrationWizard::back_preset_info(MachineObject *obj, bool cali_finish, b wxGetApp().app_config->save_printer_cali_infos(printer_cali_info, back_cali_flag); } -void CalibrationWizard::msw_rescale() +void CalibrationWizard::msw_rescale() { for (int i = 0; i < m_page_steps.size(); i++) { if (m_page_steps[i]->page) @@ -402,7 +402,7 @@ void PressureAdvanceWizard::create_pages() preset_step = new CalibrationWizardPageStep(new CalibrationPresetPage(m_scrolledWindow, m_mode, false)); cali_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode)); save_step = new CalibrationWizardPageStep(new CalibrationPASavePage(m_scrolledWindow)); - + m_all_pages_sizer->Add(start_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); m_all_pages_sizer->Add(preset_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); m_all_pages_sizer->Add(cali_step->page, 1, wxEXPAND | wxALL, FromDIP(25)); @@ -477,7 +477,9 @@ void PressureAdvanceWizard::update(MachineObject* obj) if (!m_show_result_dialog) { if (obj->cali_version != -1 && obj->cali_version != cali_version) { cali_version = obj->cali_version; - CalibUtils::emit_get_PA_calib_info(obj->nozzle_diameter, ""); + PACalibExtruderInfo cali_info; + cali_info.nozzle_diameter = obj->nozzle_diameter; + CalibUtils::emit_get_PA_calib_info(cali_info); } } } @@ -620,7 +622,7 @@ void PressureAdvanceWizard::on_cali_start() BOOST_LOG_TRIVIAL(error) << "CaliPreset: get preset info error"; return; } - + CalibInfo calib_info; calib_info.dev_id = curr_obj->dev_id; calib_info.select_ams = "[" + std::to_string(selected_filaments.begin()->first) + "]"; @@ -656,10 +658,10 @@ void PressureAdvanceWizard::on_cali_start() pa_cali_method = ManualPaCaliMethod::PA_LINE; else if (calib_info.params.mode == CalibMode::Calib_PA_Pattern) pa_cali_method = ManualPaCaliMethod::PA_PATTERN; - + cali_page->set_pa_cali_image(int(pa_cali_method)); curr_obj->manual_pa_cali_method = pa_cali_method; - + if (curr_obj->get_printer_series() != PrinterSeries::SERIES_X1 && curr_obj->pa_calib_tab.size() >= MAX_PA_HISTORY_RESULTS_NUMS) { MessageDialog msg_dlg(nullptr, wxString::Format(_L("This machine type can only hold 16 history results per nozzle. " "You can delete the existing historical results and then start calibration. " @@ -740,7 +742,7 @@ void PressureAdvanceWizard::on_cali_save() auto iter = std::find_if(curr_obj->pa_calib_tab.begin(), curr_obj->pa_calib_tab.end(), [&new_pa_cali_result](const PACalibResult &item) { return item.name == new_pa_cali_result.name && item.filament_id == item.filament_id; }); - + if (iter != curr_obj->pa_calib_tab.end()) { MessageDialog msg_dlg(nullptr, @@ -819,7 +821,7 @@ void FlowRateWizard::create_pages() coarse_save_step = new CalibrationWizardPageStep(new CalibrationFlowCoarseSavePage(m_scrolledWindow)); cali_fine_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode, CaliPageType::CALI_PAGE_FINE_CALI)); fine_save_step = new CalibrationWizardPageStep(new CalibrationFlowFineSavePage(m_scrolledWindow)); - + // auto cali_step = new CalibrationWizardPageStep(new CalibrationCaliPage(m_scrolledWindow, m_mode)); save_step = new CalibrationWizardPageStep(new CalibrationFlowX1SavePage(m_scrolledWindow)); @@ -897,7 +899,7 @@ void FlowRateWizard::on_cali_action(wxCommandEvent& evt) else if (action == CaliPageActionType::CALI_ACTION_CALI) { if (m_cali_method == CalibrationMethod::CALI_METHOD_AUTO) { on_cali_start(); - } + } else if (m_cali_method == CalibrationMethod::CALI_METHOD_MANUAL) { CaliPresetStage stage = CaliPresetStage::CALI_MANULA_STAGE_NONE; float cali_value = 0.0f; @@ -908,7 +910,7 @@ void FlowRateWizard::on_cali_action(wxCommandEvent& evt) m_curr_step->chain(cali_fine_step); } // automatically jump to next step when print job is sending finished. - } + } else { on_cali_start(); } @@ -1307,7 +1309,7 @@ void FlowRateWizard::cache_coarse_info(MachineObject *obj) wxString out_name; coarse_page->get_result(&obj->cache_flow_ratio, &out_name); - + back_preset_info(obj, false); } @@ -1317,7 +1319,7 @@ MaxVolumetricSpeedWizard::MaxVolumetricSpeedWizard(wxWindow* parent, wxWindowID create_pages(); } -void MaxVolumetricSpeedWizard::create_pages() +void MaxVolumetricSpeedWizard::create_pages() { start_step = new CalibrationWizardPageStep(new CalibrationMaxVolumetricSpeedStartPage(m_scrolledWindow)); preset_step = new CalibrationWizardPageStep(new MaxVolumetricSpeedPresetPage(m_scrolledWindow, m_mode, true)); diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 3f2d1131a35..e3bc7707bd7 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -2169,6 +2169,10 @@ int MachineObject::command_start_pa_calibration(const X1CCalibInfos &pa_data, in j["print"]["filaments"][i]["filament_id"] = pa_data.calib_datas[i].filament_id; j["print"]["filaments"][i]["setting_id"] = pa_data.calib_datas[i].setting_id; j["print"]["filaments"][i]["nozzle_temp"] = pa_data.calib_datas[i].nozzle_temp; + j["print"]["filaments"][i]["ams_id"] = pa_data.calib_datas[i].ams_id; + j["print"]["filaments"][i]["slot_id"] = pa_data.calib_datas[i].slot_id; + j["print"]["filaments"][i]["nozzle_volume_type"] = int(pa_data.calib_datas[i].nozzle_volume_type); + j["print"]["filaments"][i]["nozzle_diameter"] = pa_data.calib_datas[i].nozzle_diameter; j["print"]["filaments"][i]["max_volumetric_speed"] = std::to_string(pa_data.calib_datas[i].max_volumetric_speed); if (i > 0) filament_ids += ","; @@ -2206,6 +2210,10 @@ int MachineObject::command_set_pa_calibration(const std::vector & if (pa_calib_values[i].cali_idx >= 0) j["print"]["filaments"][i]["cali_idx"] = pa_calib_values[i].cali_idx; j["print"]["filaments"][i]["tray_id"] = pa_calib_values[i].tray_id; + j["print"]["filaments"][i]["extruder_id"] = pa_calib_values[i].extruder_id; + j["print"]["filaments"][i]["nozzle_volume_type"] = int(pa_calib_values[i].nozzle_volume_type); + j["print"]["filaments"][i]["ams_id"] = pa_calib_values[i].ams_id; + j["print"]["filaments"][i]["slot_id"] = pa_calib_values[i].slot_id; j["print"]["filaments"][i]["filament_id"] = pa_calib_values[i].filament_id; j["print"]["filaments"][i]["setting_id"] = pa_calib_values[i].setting_id; j["print"]["filaments"][i]["name"] = pa_calib_values[i].name; @@ -2228,6 +2236,8 @@ int MachineObject::command_delete_pa_calibration(const PACalibIndexInfo& pa_cali json j; j["print"]["command"] = "extrusion_cali_del"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["extruder_id"] = pa_calib.extruder_id; + j["print"]["nozzle_volume_type"] = int(pa_calib.nozzle_volume_type); j["print"]["filament_id"] = pa_calib.filament_id; j["print"]["cali_idx"] = pa_calib.cali_idx; j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(pa_calib.nozzle_diameter); @@ -2236,15 +2246,17 @@ int MachineObject::command_delete_pa_calibration(const PACalibIndexInfo& pa_cali return this->publish_json(j.dump()); } -int MachineObject::command_get_pa_calibration_tab(float nozzle_diameter, const std::string &filament_id) +int MachineObject::command_get_pa_calibration_tab(const PACalibExtruderInfo &calib_info) { reset_pa_cali_history_result(); json j; j["print"]["command"] = "extrusion_cali_get"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - j["print"]["filament_id"] = filament_id; - j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(nozzle_diameter); + j["print"]["filament_id"] = calib_info.filament_id; + j["print"]["extruder_id"] = calib_info.extruder_id; + j["print"]["nozzle_volume_type"] = int(calib_info.nozzle_volume_type); + j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(calib_info.nozzle_diameter); BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_get: " << j.dump(); return this->publish_json(j.dump()); @@ -2267,6 +2279,8 @@ int MachineObject::commnad_select_pa_calibration(const PACalibIndexInfo& pa_cali j["print"]["command"] = "extrusion_cali_sel"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["tray_id"] = pa_calib_info.tray_id; + j["print"]["ams_id"] = pa_calib_info.ams_id; + j["print"]["slot_id"] = pa_calib_info.slot_id; j["print"]["cali_idx"] = pa_calib_info.cali_idx; j["print"]["filament_id"] = pa_calib_info.filament_id; j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(pa_calib_info.nozzle_diameter); @@ -3943,7 +3957,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (!it->contains("id")) continue; std::string ams_id = (*it)["id"].get(); - int nozzle_id = 0; // Default nozzle id + int nozzle_id = 0; // Default nozzle id int type_id = 1; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s if (it->contains("nozzle")) { @@ -3953,7 +3967,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (it->contains("type")) { type_id = (*it)["type"].get(); } - + ams_id_set.erase(ams_id); Ams* curr_ams = nullptr; auto ams_it = amsList.find(ams_id); @@ -4640,10 +4654,10 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("nozzle_diameter")) { if (jj["nozzle_diameter"].is_number_float()) { - pa_calib_tab_nozzle_dia = jj["nozzle_diameter"].get(); + pa_calib_tab_info.pa_calib_tab_nozzle_dia = jj["nozzle_diameter"].get(); } else if (jj["nozzle_diameter"].is_string()) { - pa_calib_tab_nozzle_dia = string_to_float(jj["nozzle_diameter"].get()); + pa_calib_tab_info.pa_calib_tab_nozzle_dia = string_to_float(jj["nozzle_diameter"].get()); } else { assert(false); @@ -4653,6 +4667,14 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) assert(false); } + if (jj.contains("extruder_id")) { + pa_calib_tab_info.extruder_id = jj["extruder_id"].get(); + } + + if (jj.contains("nozzle_volume_type")) { + pa_calib_tab_info.nozzle_volume_type = NozzleVolumeType(jj["nozzle_volume_type"].get()); + } + if (jj.contains("filaments") && jj["filaments"].is_array()) { try { #ifdef CALI_DEBUG @@ -4727,6 +4749,30 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) pa_calib_result.nozzle_diameter = string_to_float(jj["nozzle_diameter"].get()); } + if (it->contains("ams_id")) { + pa_calib_result.ams_id = (*it)["ams_id"].get(); + } else { + pa_calib_result.ams_id = 0; + } + + if (it->contains("slot_id")) { + pa_calib_result.slot_id = (*it)["slot_id"].get(); + } else { + pa_calib_result.slot_id = 0; + } + + if (it->contains("extruder_id")) { + pa_calib_result.extruder_id = (*it)["extruder_id"].get(); + } else { + pa_calib_result.extruder_id = -1; + } + + if (it->contains("nozzle_volume_type")) { + pa_calib_result.nozzle_volume_type = NozzleVolumeType((*it)["nozzle_volume_type"].get()); + } else { + pa_calib_result.nozzle_volume_type = NozzleVolumeType::nvtNormal; + } + if ((*it)["k_value"].is_number_float()) pa_calib_result.k_value = (*it)["k_value"].get(); else if ((*it)["k_value"].is_string()) @@ -4799,7 +4845,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("device")) { json const & device = jj["device"]; - + if (device.contains("nozzle")) { json const & nozzle = device["nozzle"]; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 1a9e0be246c..c55a9860b23 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -406,8 +406,8 @@ class MachineObject }; enum ActiveState { - NotActive, - Active, + NotActive, + Active, UpdateToDate }; @@ -473,7 +473,7 @@ class MachineObject std::string product_name; // set by iot service, get /user/print std::vector filam_bak; - + std::string bind_user_name; std::string bind_user_id; @@ -658,14 +658,16 @@ class MachineObject ManualPaCaliMethod manual_pa_cali_method = ManualPaCaliMethod::PA_LINE; bool has_get_pa_calib_tab{ false }; std::vector pa_calib_tab; - float pa_calib_tab_nozzle_dia; + PACalibTabInfo pa_calib_tab_info; bool get_pa_calib_result { false }; std::vector pa_calib_results; bool get_flow_calib_result { false }; std::vector flow_ratio_results; void reset_pa_cali_history_result() { - pa_calib_tab_nozzle_dia = 0.4f; + pa_calib_tab_info.pa_calib_tab_nozzle_dia = 0.4f; + pa_calib_tab_info.extruder_id = -1; + pa_calib_tab_info.nozzle_volume_type = NozzleVolumeType::nvtNormal; has_get_pa_calib_tab = false; pa_calib_tab.clear(); } @@ -727,7 +729,7 @@ class MachineObject enum LiveviewLocal { LVL_None, LVL_Disable, - LVL_Local, + LVL_Local, LVL_Rtsps, LVL_Rtsp } liveview_local{ LVL_None }; @@ -839,7 +841,7 @@ class MachineObject RatingInfo* rating_info { nullptr }; int request_model_result = 0; bool get_model_mall_result_need_retry = false; - + std::string obj_subtask_id; // subtask_id == 0 for sdcard std::string subtask_name; bool is_sdcard_printing(); @@ -928,7 +930,7 @@ class MachineObject int command_start_pa_calibration(const X1CCalibInfos& pa_data, int mode = 0); // 0: automatic mode; 1: manual mode. default: automatic mode int command_set_pa_calibration(const std::vector& pa_calib_values, bool is_auto_cali); int command_delete_pa_calibration(const PACalibIndexInfo& pa_calib); - int command_get_pa_calibration_tab(float nozzle_diameter, const std::string &filament_id = ""); + int command_get_pa_calibration_tab(const PACalibExtruderInfo& calib_info); int command_get_pa_calibration_result(float nozzle_diameter); int commnad_select_pa_calibration(const PACalibIndexInfo& pa_calib_info); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 733a7debe14..a6c88a494d4 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2583,7 +2583,9 @@ void StatusPanel::update_ams(MachineObject *obj) if (obj->cali_version != -1 && last_cali_version != obj->cali_version) { last_cali_version = obj->cali_version; - CalibUtils::emit_get_PA_calib_info(obj->nozzle_diameter, ""); + PACalibExtruderInfo cali_info; + cali_info.nozzle_diameter = obj->nozzle_diameter; + CalibUtils::emit_get_PA_calib_info(cali_info); } bool is_support_virtual_tray = obj->ams_support_virtual_tray; @@ -3788,7 +3790,7 @@ void StatusPanel::on_ext_spool_edit(wxCommandEvent &event) m_filament_setting_dlg->set_colors(cols); } - + m_filament_setting_dlg->m_is_third = !MachineObject::is_bbl_filament(obj->vt_tray.tag_uid); if (!m_filament_setting_dlg->m_is_third) { sn_number = obj->vt_tray.uuid; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 2cd3581af72..f67e6f95348 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -373,7 +373,7 @@ bool CalibUtils::get_PA_calib_results(std::vector& pa_calib_resul return pa_calib_results.size() > 0; } -void CalibUtils::emit_get_PA_calib_infos(float nozzle_diameter) +void CalibUtils::emit_get_PA_calib_infos(const PACalibExtruderInfo &cali_info) { DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) @@ -383,7 +383,7 @@ void CalibUtils::emit_get_PA_calib_infos(float nozzle_diameter) if (obj_ == nullptr) return; - obj_->command_get_pa_calibration_tab(nozzle_diameter); + obj_->command_get_pa_calibration_tab(cali_info); } bool CalibUtils::get_PA_calib_tab(std::vector &pa_calib_infos) @@ -402,7 +402,7 @@ bool CalibUtils::get_PA_calib_tab(std::vector &pa_calib_infos) return obj_->has_get_pa_calib_tab; } -void CalibUtils::emit_get_PA_calib_info(float nozzle_diameter, const std::string &filament_id) +void CalibUtils::emit_get_PA_calib_info(const PACalibExtruderInfo &cali_info) { DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev) return; @@ -410,7 +410,7 @@ void CalibUtils::emit_get_PA_calib_info(float nozzle_diameter, const std::string MachineObject *obj_ = dev->get_selected_machine(); if (obj_ == nullptr) return; - obj_->command_get_pa_calibration_tab(nozzle_diameter, filament_id); + obj_->command_get_pa_calibration_tab(cali_info); } bool CalibUtils::get_PA_calib_info(PACalibResult & pa_calib_info) { diff --git a/src/slic3r/Utils/CalibUtils.hpp b/src/slic3r/Utils/CalibUtils.hpp index 2fd42a2547d..c1137ae584e 100644 --- a/src/slic3r/Utils/CalibUtils.hpp +++ b/src/slic3r/Utils/CalibUtils.hpp @@ -16,6 +16,9 @@ extern const float MAX_PA_K_VALUE; class CalibInfo { public: + int extruder_id = 0; + int ams_id = 0; + int slot_id = 0; Calib_Params params; Preset* printer_prest; Preset* filament_prest; @@ -35,14 +38,14 @@ class CalibUtils static CalibMode get_calib_mode_by_name(const std::string name, int &cali_stage); static void calib_PA(const X1CCalibInfos& calib_infos, int mode, wxString& error_message); - + static void emit_get_PA_calib_results(float nozzle_diameter); static bool get_PA_calib_results(std::vector &pa_calib_results); - - static void emit_get_PA_calib_infos(float nozzle_diameter); + + static void emit_get_PA_calib_infos(const PACalibExtruderInfo &cali_info); static bool get_PA_calib_tab(std::vector &pa_calib_infos); - static void emit_get_PA_calib_info(float nozzle_diameter, const std::string &filament_id); + static void emit_get_PA_calib_info(const PACalibExtruderInfo& cali_info); static bool get_PA_calib_info(PACalibResult &pa_calib_info); static void set_PA_calib_result(const std::vector& pa_calib_values, bool is_auto_cali); From afb1d3df6f19c2ba9a37bebe10f405fdaca683ab Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 09:47:56 +0800 Subject: [PATCH 016/127] refactoring the modules of amscontrol adapted from bambulab/BambuStudio@b78fa4c11c4a11bec5f4b35ea477005d32651dbb Co-authored-by: tao wang --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/AMSMaterialsSetting.cpp | 2 +- src/slic3r/GUI/StatusPanel.cpp | 31 +- src/slic3r/GUI/StatusPanel.hpp | 2 +- src/slic3r/GUI/Widgets/AMSControl.cpp | 2368 +---------------------- src/slic3r/GUI/Widgets/AMSControl.hpp | 558 +----- src/slic3r/GUI/Widgets/AMSItem.cpp | 2385 ++++++++++++++++++++++++ src/slic3r/GUI/Widgets/AMSItem.hpp | 584 ++++++ 8 files changed, 3005 insertions(+), 2927 deletions(-) create mode 100644 src/slic3r/GUI/Widgets/AMSItem.cpp create mode 100644 src/slic3r/GUI/Widgets/AMSItem.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index a9b9f393a4b..5bf0eab0ced 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -58,6 +58,8 @@ set(SLIC3R_GUI_SOURCES GUI/Widgets/TempInput.hpp GUI/Widgets/AMSControl.cpp GUI/Widgets/AMSControl.hpp + GUI/Widgets/AMSItem.cpp + GUI/Widgets/AMSItem.hpp GUI/Widgets/FanControl.cpp GUI/Widgets/FanControl.hpp GUI/Widgets/Scrollbar.cpp diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 9b6149d6622..858947854a5 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -576,7 +576,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) // set filament if (m_is_third) { if (is_virtual_tray()) { - obj->command_ams_filament_settings(255, VIRTUAL_TRAY_ID, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + obj->command_ams_filament_settings(ams_id, VIRTUAL_TRAY_ID, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else { obj->command_ams_filament_settings(ams_id, tray_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index a6c88a494d4..27560b1b040 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -828,6 +828,9 @@ StatusBasePanel::StatusBasePanel(wxWindow *parent, wxWindowID id, const wxPoint : wxScrolledWindow(parent, id, pos, size, wxHSCROLL | wxVSCROLL) { this->SetScrollRate(5, 5); + Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) return; + obj = dev->get_selected_machine(); init_bitmaps(); @@ -2629,10 +2632,13 @@ void StatusPanel::update_ams(MachineObject *obj) if (m_filament_setting_dlg) m_filament_setting_dlg->update(); std::vector ams_info; + ams_info.clear(); for (auto ams = obj->amsList.begin(); ams != obj->amsList.end(); ams++) { AMSinfo info; info.ams_id = ams->first; - if (ams->second->is_exists && info.parse_ams_info(obj, ams->second, obj->ams_calibrate_remain_flag, obj->is_support_ams_humidity)) ams_info.push_back(info); + if (ams->second->is_exists && info.parse_ams_info(obj, ams->second, obj->ams_calibrate_remain_flag, obj->is_support_ams_humidity)) { + ams_info.push_back(info); + } } //if (obj->ams_exist_bits != last_ams_exist_bits || obj->tray_exist_bits != last_tray_exist_bits || obj->tray_is_bbl_bits != last_tray_is_bbl_bits || // obj->tray_read_done_bits != last_read_done_bits || obj->ams_version != last_ams_version) { @@ -3680,9 +3686,17 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) if (obj) { m_filament_setting_dlg->obj = obj; - std::string ams_id = m_ams_control->GetCurentAms(); + std::string ams_id; int ams_id_int = 0; int tray_id_int = 0; + int tray_id = event.GetInt(); + if (tray_id == VIRTUAL_TRAY_ID) { + ams_id = std::to_string(tray_id); + } + else{ + ams_id = std::to_string(tray_id / 4); + } + if (ams_id.compare(std::to_string(VIRTUAL_TRAY_ID)) == 0) { tray_id_int = VIRTUAL_TRAY_ID; m_filament_setting_dlg->ams_id = ams_id_int; @@ -3694,10 +3708,10 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); m_filament_setting_dlg->Popup(wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString, k_val, n_val); } else { - std::string tray_id = event.GetString().ToStdString(); // m_ams_control->GetCurrentCan(ams_id); + //std::string tray_id = event.GetString().ToStdString(); // m_ams_control->GetCurrentCan(ams_id); try { - ams_id_int = atoi(ams_id.c_str()); - tray_id_int = atoi(tray_id.c_str()); + ams_id_int = tray_id / 4; + tray_id_int = tray_id % 4; m_filament_setting_dlg->ams_id = ams_id_int; m_filament_setting_dlg->tray_id = tray_id_int; @@ -3707,9 +3721,9 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) std::string temp_min; wxString k_val; wxString n_val; - auto it = obj->amsList.find(ams_id); + auto it = obj->amsList.find(std::to_string(ams_id_int)); if (it != obj->amsList.end()) { - auto tray_it = it->second->trayList.find(tray_id); + auto tray_it = it->second->trayList.find(std::to_string(tray_id)); if (tray_it != it->second->trayList.end()) { k_val = wxString::Format("%.3f", tray_it->second->k); n_val = wxString::Format("%.3f", tray_it->second->n); @@ -3762,7 +3776,10 @@ void StatusPanel::on_ext_spool_edit(wxCommandEvent &event) current_position_y = current_position_y + m_filament_setting_dlg->GetSize().GetHeight() > drect ? drect - m_filament_setting_dlg->GetSize().GetHeight() : current_position_y; if (obj) { + int tray_id = event.GetInt(); + int ams_id = tray_id; m_filament_setting_dlg->obj = obj; + m_filament_setting_dlg->ams_id = ams_id; try { m_filament_setting_dlg->tray_id = VIRTUAL_TRAY_ID; std::string sn_number; diff --git a/src/slic3r/GUI/StatusPanel.hpp b/src/slic3r/GUI/StatusPanel.hpp index e34bf908aad..287858de9a6 100644 --- a/src/slic3r/GUI/StatusPanel.hpp +++ b/src/slic3r/GUI/StatusPanel.hpp @@ -435,6 +435,7 @@ class StatusBasePanel : public wxScrolledWindow ~StatusBasePanel(); + MachineObject* obj{nullptr}; void init_bitmaps(); wxBoxSizer *create_monitoring_page(); wxBoxSizer *create_machine_control_page(wxWindow *parent); @@ -640,7 +641,6 @@ class StatusPanel : public StatusBasePanel STATE_COUNT = 4 }; - MachineObject *obj {nullptr}; BBLSubTask * last_subtask{nullptr}; std::string last_profile_id; std::string last_task_id; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 0c8d306f433..87580d42d4e 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -4,2370 +4,14 @@ #include "../I18N.hpp" #include "../GUI_App.hpp" -#include - #include #include -#include "CalibUtils.hpp" - -namespace Slic3r { namespace GUI { - -static const wxColour AMS_TRAY_DEFAULT_COL = wxColour(255, 255, 255); - -wxDEFINE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_LOAD, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_SETTINGS, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_FILAMENT_BACKUP, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent); -wxDEFINE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_GUIDE_WIKI, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_RETRY, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_SHOW_HUMIDITY_TIPS, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_UNSELETED_VAMS, wxCommandEvent); -wxDEFINE_EVENT(EVT_CLEAR_SPEED_CONTROL, wxCommandEvent); - -bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, bool humidity_flag) -{ - if (!ams) return false; - this->ams_id = ams->id; - - if (humidity_flag) { - this->ams_humidity = ams->humidity; - } - else { - this->ams_humidity = -1; - } - - cans.clear(); - for (int i = 0; i < 4; i++) { - auto it = ams->trayList.find(std::to_string(i)); - Caninfo info; - // tray is exists - if (it != ams->trayList.end() && it->second->is_exists) { - if (it->second->is_tray_info_ready()) { - info.can_id = it->second->id; - info.ctype = it->second->ctype; - info.material_name = it->second->get_display_filament_type(); - if (!it->second->color.empty()) { - info.material_colour = AmsTray::decode_color(it->second->color); - } else { - // set to white by default - info.material_colour = AMS_TRAY_DEFAULT_COL; - } - - for (std::string cols:it->second->cols) { - info.material_cols.push_back(AmsTray::decode_color(cols)); - } - - if (MachineObject::is_bbl_filament(it->second->tag_uid)) { - info.material_state = AMSCanType::AMS_CAN_TYPE_BRAND; - } else { - info.material_state = AMSCanType::AMS_CAN_TYPE_THIRDBRAND; - } - - if (!MachineObject::is_bbl_filament(it->second->tag_uid) || !remain_flag) { - info.material_remain = 100; - } else { - info.material_remain = it->second->remain < 0 ? 0 : it->second->remain; - info.material_remain = it->second->remain > 100 ? 100 : info.material_remain; - } - - - } else { - info.can_id = it->second->id; - info.material_name = ""; - info.ctype = 0; - info.material_colour = AMS_TRAY_DEFAULT_COL; - info.material_state = AMSCanType::AMS_CAN_TYPE_THIRDBRAND; - wxColour(255, 255, 255); - } - - if (it->second->is_tray_info_ready() && obj->cali_version >= 0) { - CalibUtils::get_pa_k_n_value_by_cali_idx(obj, it->second->cali_idx, info.k, info.n); - } - else { - info.k = it->second->k; - info.n = it->second->n; - } - } else { - info.can_id = i; - info.material_state = AMSCanType::AMS_CAN_TYPE_EMPTY; - } - cans.push_back(info); - } - return true; -} - -/************************************************* -Description:AMSrefresh -**************************************************/ - -AMSrefresh::AMSrefresh() { SetFont(Label::Body_10);} - -AMSrefresh::AMSrefresh(wxWindow *parent, wxString number, Caninfo info, const wxPoint &pos, const wxSize &size) : AMSrefresh() -{ - m_info = info; - m_can_id = number.ToStdString(); - create(parent, wxID_ANY, pos, size); -} - -AMSrefresh::AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint &pos, const wxSize &size) : AMSrefresh() -{ - m_info = info; - m_can_id = wxString::Format("%d", number).ToStdString(); - create(parent, wxID_ANY, pos, size); -} - - AMSrefresh::~AMSrefresh() - { - if (m_playing_timer) { - m_playing_timer->Stop(); - delete m_playing_timer; - m_playing_timer = nullptr; - } - } - -void AMSrefresh::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) -{ - wxWindow::Create(parent, id, pos, size, wxBORDER_NONE); - SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - - Bind(wxEVT_TIMER, &AMSrefresh::on_timer, this); - Bind(wxEVT_PAINT, &AMSrefresh::paintEvent, this); - Bind(wxEVT_ENTER_WINDOW, &AMSrefresh::OnEnterWindow, this); - Bind(wxEVT_LEAVE_WINDOW, &AMSrefresh::OnLeaveWindow, this); - Bind(wxEVT_LEFT_DOWN, &AMSrefresh::OnClick, this); - - m_bitmap_normal = ScalableBitmap(this, "ams_refresh_normal", 30); - m_bitmap_selected = ScalableBitmap(this, "ams_refresh_selected", 30); - - m_bitmap_ams_rfid_0 = ScalableBitmap(this, "ams_rfid_0", 30); - m_bitmap_ams_rfid_1 = ScalableBitmap(this, "ams_rfid_1", 30); - m_bitmap_ams_rfid_2 = ScalableBitmap(this, "ams_rfid_2", 30); - m_bitmap_ams_rfid_3 = ScalableBitmap(this, "ams_rfid_3", 30); - m_bitmap_ams_rfid_4 = ScalableBitmap(this, "ams_rfid_4", 30); - m_bitmap_ams_rfid_5 = ScalableBitmap(this, "ams_rfid_5", 30); - m_bitmap_ams_rfid_6 = ScalableBitmap(this, "ams_rfid_6", 30); - m_bitmap_ams_rfid_7 = ScalableBitmap(this, "ams_rfid_7", 30); - - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_0); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_1); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_2); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_3); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_4); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_5); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_6); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_7); - - m_playing_timer = new wxTimer(); - m_playing_timer->SetOwner(this); - wxPostEvent(this, wxTimerEvent()); - - SetSize(AMS_REFRESH_SIZE); - SetMinSize(AMS_REFRESH_SIZE); - SetMaxSize(AMS_REFRESH_SIZE); -} - -void AMSrefresh::on_timer(wxTimerEvent &event) -{ - //if (m_rotation_angle >= m_rfid_bitmap_list.size()) { - // m_rotation_angle = 0; - //} else { - // m_rotation_angle++; - //} - Refresh(); -} - -void AMSrefresh::PlayLoading() -{ - if (m_play_loading | m_disable_mode) return; - m_play_loading = true; - //m_rotation_angle = 0; - m_playing_timer->Start(AMS_REFRESH_PLAY_LOADING_TIMER); - Refresh(); -} - -void AMSrefresh::StopLoading() -{ - if (!m_play_loading | m_disable_mode) return; - m_playing_timer->Stop(); - m_play_loading = false; - Refresh(); -} - -void AMSrefresh::OnEnterWindow(wxMouseEvent &evt) -{ - m_selected = true; - Refresh(); -} - -void AMSrefresh::OnLeaveWindow(wxMouseEvent &evt) -{ - m_selected = false; - Refresh(); -} - -void AMSrefresh::OnClick(wxMouseEvent &evt) { - post_event(wxCommandEvent(EVT_AMS_REFRESH_RFID)); -} - -void AMSrefresh::post_event(wxCommandEvent &&event) -{ - if (m_disable_mode) - return; - event.SetString(m_info.can_id); - event.SetEventObject(m_parent); - wxPostEvent(m_parent, event); - event.Skip(); -} - -void AMSrefresh::paintEvent(wxPaintEvent &evt) -{ - wxSize size = GetSize(); - wxPaintDC dc(this); - - auto colour = StateColor::darkModeColorFor(AMS_CONTROL_GRAY700); - if (!wxWindow::IsEnabled()) { colour = AMS_CONTROL_GRAY500; } - - auto pot = wxPoint((size.x - m_bitmap_selected.GetBmpSize().x) / 2, (size.y - m_bitmap_selected.GetBmpSize().y) / 2); - - if (!m_disable_mode) { - if (!m_play_loading) { - dc.DrawBitmap(m_selected ? m_bitmap_selected.bmp() : m_bitmap_normal.bmp(), pot); - } - else { - /* m_bitmap_rotation = ScalableBitmap(this, "ams_refresh_normal", 30); - auto image = m_bitmap_rotation.bmp().ConvertToImage(); - wxPoint offset; - auto loading_img = image.Rotate(m_rotation_angle, wxPoint(image.GetWidth() / 2, image.GetHeight() / 2), true, &offset); - ScalableBitmap loading_bitmap; - loading_bitmap.bmp() = wxBitmap(loading_img); - dc.DrawBitmap(loading_bitmap.bmp(), offset.x , offset.y);*/ - m_rotation_angle++; - if (m_rotation_angle >= m_rfid_bitmap_list.size()) { - m_rotation_angle = 0; - } - if (m_rfid_bitmap_list.size() <= 0)return; - dc.DrawBitmap(m_rfid_bitmap_list[m_rotation_angle].bmp(), pot); - } - } - - dc.SetPen(wxPen(colour)); - dc.SetBrush(wxBrush(colour)); - dc.SetFont(Label::Body_11); - dc.SetTextForeground(colour); - auto tsize = dc.GetTextExtent(m_refresh_id); - pot = wxPoint((size.x - tsize.x) / 2, (size.y - tsize.y) / 2); - dc.DrawText(m_refresh_id, pot); -} - -void AMSrefresh::Update(std::string ams_id, Caninfo info) -{ - m_ams_id = ams_id; - m_info = info; - - if (!m_ams_id.empty() && !m_can_id.empty()) { - auto aid = atoi(m_ams_id.c_str()); - auto tid = atoi(m_can_id.c_str()); - auto tray_id = aid * 4 + tid; - m_refresh_id = wxGetApp().transition_tridid(tray_id); - } - StopLoading(); -} - -void AMSrefresh::msw_rescale() { - m_bitmap_normal = ScalableBitmap(this, "ams_refresh_normal", 30); - m_bitmap_selected = ScalableBitmap(this, "ams_refresh_selected", 30); - m_bitmap_ams_rfid_0 = ScalableBitmap(this, "ams_rfid_0", 30); - m_bitmap_ams_rfid_1 = ScalableBitmap(this, "ams_rfid_1", 30); - m_bitmap_ams_rfid_2 = ScalableBitmap(this, "ams_rfid_2", 30); - m_bitmap_ams_rfid_3 = ScalableBitmap(this, "ams_rfid_3", 30); - m_bitmap_ams_rfid_4 = ScalableBitmap(this, "ams_rfid_4", 30); - m_bitmap_ams_rfid_5 = ScalableBitmap(this, "ams_rfid_5", 30); - m_bitmap_ams_rfid_6 = ScalableBitmap(this, "ams_rfid_6", 30); - m_bitmap_ams_rfid_7 = ScalableBitmap(this, "ams_rfid_7", 30); - - m_rfid_bitmap_list.clear(); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_0); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_1); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_2); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_3); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_4); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_5); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_6); - m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_7); -} - -void AMSrefresh::DoSetSize(int x, int y, int width, int height, int sizeFlags) -{ - wxWindow::DoSetSize(x, y, width, height, sizeFlags); -} - -/************************************************* -Description:AMSextruder -**************************************************/ -void AMSextruderImage::TurnOn(wxColour col) -{ - m_colour = col; - Refresh(); -} - -void AMSextruderImage::TurnOff() -{ - m_colour = AMS_EXTRUDER_DEF_COLOUR; - Refresh(); -} - -void AMSextruderImage::msw_rescale() -{ - //m_ams_extruder.SetSize(AMS_EXTRUDER_BITMAP_SIZE); - //auto image = m_ams_extruder.ConvertToImage(); - m_ams_extruder = ScalableBitmap(this, "monitor_ams_extruder", 55); - Refresh(); -} - -void AMSextruderImage::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSextruderImage::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void AMSextruderImage::doRender(wxDC &dc) -{ - auto size = GetSize(); - dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(m_colour); - dc.DrawRectangle(0, FromDIP(18), size.x, size.y - FromDIP(18) - FromDIP(5)); - dc.DrawBitmap(m_ams_extruder.bmp(), wxPoint((size.x - m_ams_extruder.GetBmpSize().x) / 2, (size.y - m_ams_extruder.GetBmpSize().y) / 2)); -} - - -AMSextruderImage::AMSextruderImage(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) -{ - wxWindow::Create(parent, id, pos, AMS_EXTRUDER_BITMAP_SIZE); - SetBackgroundColour(*wxWHITE); - - m_ams_extruder = ScalableBitmap(this, "monitor_ams_extruder",55); - SetSize(AMS_EXTRUDER_BITMAP_SIZE); - SetMinSize(AMS_EXTRUDER_BITMAP_SIZE); - SetMaxSize(AMS_EXTRUDER_BITMAP_SIZE); - - - Bind(wxEVT_PAINT, &AMSextruderImage::paintEvent, this); -} - -AMSextruderImage::~AMSextruderImage() {} - - - -AMSextruder::AMSextruder(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { create(parent, id, pos, size); } - - AMSextruder::~AMSextruder() {} -void AMSextruder::TurnOn(wxColour col) -{ - m_amsSextruder->TurnOn(col); -} - -void AMSextruder::TurnOff() -{ - m_amsSextruder->TurnOff(); -} - -void AMSextruder::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) -{ - wxWindow::Create(parent, id, pos, AMS_EXTRUDER_SIZE, wxBORDER_NONE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); - - wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL); - - m_bitmap_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, AMS_EXTRUDER_BITMAP_SIZE, wxTAB_TRAVERSAL); - m_bitmap_panel->SetBackgroundColour(AMS_EXTRUDER_DEF_COLOUR); - m_bitmap_panel->SetDoubleBuffered(true); - m_bitmap_sizer = new wxBoxSizer(wxHORIZONTAL); - - m_amsSextruder = new AMSextruderImage(m_bitmap_panel, wxID_ANY, wxDefaultPosition, AMS_EXTRUDER_BITMAP_SIZE); - m_bitmap_sizer->Add(m_amsSextruder, 0, wxALIGN_CENTER, 0); - - m_bitmap_panel->SetSizer(m_bitmap_sizer); - m_bitmap_panel->Layout(); - m_sizer_body->Add( 0, 0, 1, wxEXPAND, 0 ); - m_sizer_body->Add(m_bitmap_panel, 0, wxALIGN_CENTER, 0); - - SetSizer(m_sizer_body); - - Bind(wxEVT_PAINT, &AMSextruder::paintEvent, this); - Layout(); -} - -void AMSextruder::OnVamsLoading(bool load, wxColour col) -{ - m_vams_loading = load; - if (load)m_current_colur = col; - Refresh(); -} - -void AMSextruder::OnAmsLoading(bool load, wxColour col /*= AMS_CONTROL_GRAY500*/) -{ - m_ams_loading = load; - if (load)m_current_colur = col; - Refresh(); -} - -void AMSextruder::paintEvent(wxPaintEvent& evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSextruder::render(wxDC& dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif - -} - -void AMSextruder::doRender(wxDC& dc) -{ - //m_current_colur = - wxSize size = GetSize(); - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - - if (!m_none_ams_mode) { - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - } - - if (m_has_vams) { - dc.DrawRoundedRectangle(-size.x / 2, size.y * 0.1, size.x, size.y, 4); - - if (m_vams_loading) { - - if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID)); } - else { dc.SetPen(wxPen(m_current_colur, 6, wxPENSTYLE_SOLID)); } - dc.DrawRoundedRectangle(-size.x / 2, size.y * 0.1, size.x, size.y, 4); - - if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { - dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); - dc.DrawRoundedRectangle(-size.x / 2 - FromDIP(3), size.y * 0.1 + FromDIP(3), size.x, size.y, 3); - dc.DrawRoundedRectangle(-size.x / 2 + FromDIP(3), size.y * 0.1 - FromDIP(3), size.x, size.y, 5); - } - } - - if (m_ams_loading && !m_none_ams_mode) { - if (m_current_colur.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID));} - else {dc.SetPen(wxPen(m_current_colur, 6, wxPENSTYLE_SOLID));} - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - - if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { - dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); - dc.DrawLine(size.x / 2 - FromDIP(4), -1, size.x / 2 - FromDIP(3), size.y * 0.6 - 1); - dc.DrawLine(size.x / 2 + FromDIP(3), -1, size.x / 2 + FromDIP(3), size.y * 0.6 - 1); - } - } - } - else { - if (m_ams_loading) { - if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID)); } - else { dc.SetPen(wxPen(m_current_colur, 6, wxPENSTYLE_SOLID)); } - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - - if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { - dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); - dc.DrawLine(size.x / 2 - FromDIP(4), -1, size.x / 2 - FromDIP(3), size.y * 0.6 - 1); - dc.DrawLine(size.x / 2 + FromDIP(3), -1, size.x / 2 + FromDIP(3), size.y * 0.6 - 1); - } - } - } - -} - -void AMSextruder::msw_rescale() -{ - m_amsSextruder->msw_rescale(); - Layout(); - Update(); - Refresh(); -} - -/************************************************* -Description:AMSVirtualRoad -**************************************************/ - -AMSVirtualRoad::AMSVirtualRoad(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) { create(parent, id, pos, size); } - -AMSVirtualRoad::~AMSVirtualRoad() {} - -void AMSVirtualRoad::OnVamsLoading(bool load, wxColour col) -{ - m_vams_loading = load; - if (load)m_current_color = col; - Refresh(); -} - -void AMSVirtualRoad::create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) -{ - wxWindow::Create(parent, id, pos, wxDefaultSize, wxBORDER_NONE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); - Layout(); - Bind(wxEVT_PAINT, &AMSVirtualRoad::paintEvent, this); -} - -void AMSVirtualRoad::paintEvent(wxPaintEvent& evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSVirtualRoad::render(wxDC& dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void AMSVirtualRoad::doRender(wxDC& dc) -{ - if (!m_has_vams) return; - - wxSize size = GetSize(); - if (m_vams_loading) { - if (m_current_color.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID)); } - else { dc.SetPen(wxPen(m_current_color, 6, wxPENSTYLE_SOLID)); } - } - else { - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - } - - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(size.x / 2, -size.y / 1.1 + FromDIP(1), size.x, size.y, 4); - - if ((m_current_color == *wxWHITE || m_current_color.Alpha() == 0) && !wxGetApp().dark_mode()) { - dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); - dc.DrawRoundedRectangle(size.x / 2 - FromDIP(3), -size.y / 1.1 + FromDIP(4), size.x, size.y, 5); - dc.DrawRoundedRectangle(size.x / 2 + FromDIP(3), -size.y / 1.1 - FromDIP(2), size.x, size.y, 3); - } -} - - -void AMSVirtualRoad::msw_rescale() -{ - Layout(); - Update(); - Refresh(); -} - - -/************************************************* -Description:AMSLib -**************************************************/ -AMSLib::AMSLib(wxWindow *parent, Caninfo info) -{ - m_border_color = (wxColour(130, 130, 128)); - m_road_def_color = AMS_CONTROL_GRAY500; - wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - create(parent); - - Bind(wxEVT_PAINT, &AMSLib::paintEvent, this); - Bind(wxEVT_ENTER_WINDOW, &AMSLib::on_enter_window, this); - Bind(wxEVT_LEAVE_WINDOW, &AMSLib::on_leave_window, this); - Bind(wxEVT_LEFT_DOWN, &AMSLib::on_left_down, this); - - Update(info, false); -} - -void AMSLib::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) -{ - wxWindow::Create(parent, id, pos, size); - - SetSize(AMS_CAN_LIB_SIZE); - SetMinSize(AMS_CAN_LIB_SIZE); - SetMaxSize(AMS_CAN_LIB_SIZE); - - auto m_sizer_body = new wxBoxSizer(wxVERTICAL); - - wxBoxSizer *m_sizer_edit = new wxBoxSizer(wxHORIZONTAL); - - m_bitmap_editable = ScalableBitmap(this, "ams_editable", 14); - m_bitmap_editable_light = ScalableBitmap(this, "ams_editable_light", 14); - m_bitmap_readonly = ScalableBitmap(this, "ams_readonly", 14); - m_bitmap_readonly_light = ScalableBitmap(this, "ams_readonly_light", 14); - m_bitmap_transparent = ScalableBitmap(this, "transparent_ams_lib", 68); - - m_bitmap_extra_tray_left = ScalableBitmap(this, "extra_ams_tray_left", 80); - m_bitmap_extra_tray_right = ScalableBitmap(this, "extra_ams_tray_right", 80); - - m_bitmap_extra_tray_left_hover = ScalableBitmap(this, "extra_ams_tray_left_hover", 80); - m_bitmap_extra_tray_right_hover = ScalableBitmap(this, "extra_ams_tray_right_hover", 80); - - m_bitmap_extra_tray_left_selected = ScalableBitmap(this, "extra_ams_tray_left_selected", 80); - m_bitmap_extra_tray_right_selected = ScalableBitmap(this, "extra_ams_tray_right_selected", 80); - - - m_sizer_body->Add(0, 0, 1, wxEXPAND, 0); - m_sizer_body->Add(m_sizer_edit, 0, wxALIGN_CENTER, 0); - m_sizer_body->Add(0, 0, 0, wxBOTTOM, GetSize().y * 0.12); - SetSizer(m_sizer_body); - Layout(); -} - -void AMSLib::on_enter_window(wxMouseEvent &evt) -{ - m_hover = true; - Refresh(); -} - -void AMSLib::on_leave_window(wxMouseEvent &evt) -{ - m_hover = false; - Refresh(); -} - -void AMSLib::on_left_down(wxMouseEvent &evt) -{ - if (m_info.material_state != AMSCanType::AMS_CAN_TYPE_EMPTY && m_info.material_state != AMSCanType::AMS_CAN_TYPE_NONE) { - auto size = GetSize(); - auto pos = evt.GetPosition(); - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND || m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND || - m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { +#include - auto left = FromDIP(10); - auto right = size.x - FromDIP(10); - auto top = 0; - auto bottom = 0; +#include "CalibUtils.hpp" - if (m_ams_model == AMSModel::GENERIC_AMS) { - top = (size.y - FromDIP(15) - m_bitmap_editable_light.GetBmpSize().y); - bottom = size.y - FromDIP(15); - } - else if (m_ams_model == AMSModel::EXTRA_AMS) { - top = (size.y - FromDIP(20) - m_bitmap_editable_light.GetBmpSize().y); - bottom = size.y - FromDIP(20); - } - - if (pos.x >= left && pos.x <= right && pos.y >= top && top <= bottom) { - if (m_selected) { - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { - post_event(wxCommandEvent(EVT_VAMS_ON_FILAMENT_EDIT)); - } - else { - post_event(wxCommandEvent(EVT_AMS_ON_FILAMENT_EDIT)); - } - } else { - BOOST_LOG_TRIVIAL(trace) << "current amslib is not selected"; - } - } - } - } -} - - -void AMSLib::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSLib::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif - - // text - if (m_ams_model == AMSModel::GENERIC_AMS) { - render_generic_text(dc); - } - else if (m_ams_model == AMSModel::EXTRA_AMS) { - render_extra_text(dc); - } -} - -void AMSLib::render_extra_text(wxDC& dc) -{ - auto tmp_lib_colour = m_info.material_colour; - - change_the_opacity(tmp_lib_colour); - auto temp_text_colour = AMS_CONTROL_GRAY800; - - if (tmp_lib_colour.GetLuminance() < 0.6) { - temp_text_colour = AMS_CONTROL_WHITE_COLOUR; - } - else { - temp_text_colour = AMS_CONTROL_GRAY800; - } - - if (m_info.material_remain < 50) { - temp_text_colour = AMS_CONTROL_GRAY800; - } - - if (tmp_lib_colour.Alpha() == 0) { - temp_text_colour = AMS_CONTROL_GRAY800; - } - - dc.SetFont(::Label::Body_13); - dc.SetTextForeground(temp_text_colour); - - auto libsize = GetSize(); - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND - || m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND - || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { - - if (m_info.material_name.empty()) { - auto tsize = dc.GetMultiLineTextExtent("?"); - auto pot = wxPoint(0, 0); - pot = wxPoint((libsize.x - tsize.x) / 2 + FromDIP(2), (libsize.y - tsize.y) / 2 - FromDIP(5)); - dc.DrawText(L("?"), pot); - } - else { - auto tsize = dc.GetMultiLineTextExtent(m_info.material_name); - std::vector split_char_arr = { " ", "-" }; - bool has_split = false; - std::string has_split_char = " "; - - for (std::string split_char : split_char_arr) { - if (m_info.material_name.find(split_char) != std::string::npos) { - has_split = true; - has_split_char = split_char; - } - } - - - if (has_split) { - dc.SetFont(::Label::Body_10); - auto line_top = m_info.material_name.substr(0, m_info.material_name.find(has_split_char)); - auto line_bottom = m_info.material_name.substr(m_info.material_name.find(has_split_char)); - - auto line_top_tsize = dc.GetMultiLineTextExtent(line_top); - auto line_bottom_tsize = dc.GetMultiLineTextExtent(line_bottom); - - auto pot_top = wxPoint((libsize.x - line_top_tsize.x) / 2 + FromDIP(3), (libsize.y - line_top_tsize.y) / 2 - line_top_tsize.y); - dc.DrawText(line_top, pot_top); - - auto pot_bottom = wxPoint((libsize.x - line_bottom_tsize.x) / 2 + FromDIP(3), (libsize.y - line_bottom_tsize.y) / 2); - dc.DrawText(line_bottom, pot_bottom); - - - } - else { - dc.SetFont(::Label::Body_10); - auto pot = wxPoint(0, 0); - if (m_obj ) { - pot = wxPoint((libsize.x - tsize.x) / 2 + FromDIP(6), (libsize.y - tsize.y) / 2 - FromDIP(5)); - } - dc.DrawText(m_info.material_name, pot); - } - } - } - - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_EMPTY) { - auto tsize = dc.GetMultiLineTextExtent(_L("/")); - auto pot = wxPoint((libsize.x - tsize.x) / 2 + FromDIP(2), (libsize.y - tsize.y) / 2 + FromDIP(3)); - dc.DrawText(_L("/"), pot); - } -} - -void AMSLib::render_generic_text(wxDC &dc) -{ - bool show_k_value = true; - if (m_obj && (m_obj->cali_version >= 0) && (abs(m_info.k - 0) < 1e-3)) { - show_k_value = false; - } - - auto tmp_lib_colour = m_info.material_colour; - change_the_opacity(tmp_lib_colour); - - auto temp_text_colour = AMS_CONTROL_GRAY800; - - if (tmp_lib_colour.GetLuminance() < 0.6) { - temp_text_colour = AMS_CONTROL_WHITE_COLOUR; - } - else { - temp_text_colour = AMS_CONTROL_GRAY800; - } - - if (m_info.material_remain < 50) { - temp_text_colour = AMS_CONTROL_GRAY800; - } - - if (tmp_lib_colour.Alpha() == 0) { - temp_text_colour = AMS_CONTROL_GRAY800; - } - - dc.SetFont(::Label::Body_13); - dc.SetTextForeground(temp_text_colour); - auto alpha = m_info.material_colour.Alpha(); - if (alpha != 0 && alpha != 255 && alpha != 254) { - dc.SetTextForeground(*wxBLACK); - } - - auto libsize = GetSize(); - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND - || m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND - || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { - - if (m_info.material_name.empty() /*&& m_info.material_state != AMSCanType::AMS_CAN_TYPE_VIRTUAL*/) { - auto tsize = dc.GetMultiLineTextExtent("?"); - auto pot = wxPoint(0, 0); - - if (m_obj && show_k_value) { - pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9)); - } - else { - pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); - } - dc.DrawText(L("?"), pot); - - } - else { - auto tsize = dc.GetMultiLineTextExtent(m_info.material_name); - std::vector split_char_arr = { " ", "-" }; - bool has_split = false; - std::string has_split_char = " "; - - for (std::string split_char : split_char_arr) { - if (m_info.material_name.find(split_char) != std::string::npos) { - has_split = true; - has_split_char = split_char; - } - } - - - if (has_split) { - dc.SetFont(::Label::Body_12); - - auto line_top = m_info.material_name.substr(0, m_info.material_name.find(has_split_char)); - auto line_bottom = m_info.material_name.substr(m_info.material_name.find(has_split_char)); - - auto line_top_tsize = dc.GetMultiLineTextExtent(line_top); - auto line_bottom_tsize = dc.GetMultiLineTextExtent(line_bottom); - - if (!m_show_kn) { - auto pot_top = wxPoint((libsize.x - line_top_tsize.x) / 2, (libsize.y - line_top_tsize.y) / 2 - line_top_tsize.y + FromDIP(6)); - dc.DrawText(line_top, pot_top); - - - auto pot_bottom = wxPoint((libsize.x - line_bottom_tsize.x) / 2, (libsize.y - line_bottom_tsize.y) / 2 + FromDIP(4)); - dc.DrawText(line_bottom, pot_bottom); - } - else { - auto pot_top = wxPoint((libsize.x - line_top_tsize.x) / 2, (libsize.y - line_top_tsize.y) / 2 - line_top_tsize.y - FromDIP(6)); - dc.DrawText(line_top, pot_top); - - auto pot_bottom = wxPoint((libsize.x - line_bottom_tsize.x) / 2, (libsize.y - line_bottom_tsize.y) / 2 - FromDIP(8)); - dc.DrawText(line_bottom, pot_bottom); - } - - - } - else { - auto pot = wxPoint(0, 0); - if (m_obj && show_k_value) { - pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9)); - } else { - pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); - } - dc.DrawText(m_info.material_name, pot); - } - } - - //draw k&n - if (m_obj && show_k_value) { - if (m_show_kn) { - wxString str_k = wxString::Format("K %1.3f", m_info.k); - wxString str_n = wxString::Format("N %1.3f", m_info.n); - dc.SetFont(::Label::Body_11); - auto tsize = dc.GetMultiLineTextExtent(str_k); - auto pot_k = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9) + tsize.y); - dc.DrawText(str_k, pot_k); - } - } - } - - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_EMPTY) { - auto tsize = dc.GetMultiLineTextExtent(_L("Empty")); - auto pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); - dc.DrawText(_L("Empty"), pot); - } -} - -void AMSLib::doRender(wxDC &dc) -{ - if (m_ams_model == AMSModel::GENERIC_AMS) { - render_generic_lib(dc); - } - else if (m_ams_model == AMSModel::EXTRA_AMS) { - render_extra_lib(dc); - } -} - -void AMSLib::render_extra_lib(wxDC& dc) -{ - wxSize size = GetSize(); - - ScalableBitmap tray_bitmap = m_can_index <= 1 ? m_bitmap_extra_tray_left : m_bitmap_extra_tray_right; - ScalableBitmap tray_bitmap_hover = m_can_index <= 1 ? m_bitmap_extra_tray_left_hover : m_bitmap_extra_tray_right_hover; - ScalableBitmap tray_bitmap_selected = m_can_index <= 1 ? m_bitmap_extra_tray_left_selected : m_bitmap_extra_tray_right_selected; - - - auto tmp_lib_colour = m_info.material_colour; - change_the_opacity(tmp_lib_colour); - - auto temp_bitmap_third = m_bitmap_editable_light; - auto temp_bitmap_brand = m_bitmap_readonly_light; - - //draw road - - - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - - if (m_pass_road) { - dc.SetPen(wxPen(m_info.material_colour, 6, wxPENSTYLE_SOLID)); - } - - if (m_can_index == 0 || m_can_index == 3) { - dc.DrawLine(size.x / 2, size.y / 2, size.x / 2, size.y); - } - else { - dc.DrawLine(size.x / 2, size.y / 2, size.x / 2, 0); - } - - - //draw def background - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(AMS_CONTROL_DEF_LIB_BK_COLOUR)); - dc.DrawRoundedRectangle(FromDIP(10), FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20), 0); - - if (tmp_lib_colour.GetLuminance() < 0.6) { - temp_bitmap_third = m_bitmap_editable_light; - temp_bitmap_brand = m_bitmap_readonly_light; - } - else { - temp_bitmap_third = m_bitmap_editable; - temp_bitmap_brand = m_bitmap_readonly; - } - - if (m_info.material_remain < 50) { - temp_bitmap_third = m_bitmap_editable; - temp_bitmap_brand = m_bitmap_readonly; - } - - if (tmp_lib_colour.Alpha() == 0) { - temp_bitmap_third = m_bitmap_editable; - temp_bitmap_brand = m_bitmap_readonly; - } - - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - if (m_info.material_cols.size() > 1) { - int left = FromDIP(10); - int gwidth = std::round(size.x / (m_info.material_cols.size() - 1)); - //gradient - if (m_info.ctype == 0) { - for (int i = 0; i < m_info.material_cols.size() - 1; i++) { - auto rect = wxRect(left, FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20)); - dc.GradientFillLinear(rect, m_info.material_cols[i], m_info.material_cols[i + 1], wxEAST); - left += gwidth; - } - } - else { - int cols_size = m_info.material_cols.size(); - for (int i = 0; i < cols_size; i++) { - dc.SetBrush(wxBrush(m_info.material_cols[i])); - float x = FromDIP(10) + ((float)size.x - FromDIP(20)) * i / cols_size; - dc.DrawRoundedRectangle(x, FromDIP(10), ((float)size.x - FromDIP(20)) / cols_size, size.y - FromDIP(20), 0); - } - dc.SetBrush(wxBrush(tmp_lib_colour)); - } - } - else { - dc.SetBrush(wxBrush(tmp_lib_colour)); - dc.DrawRoundedRectangle(FromDIP(10), FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20), 0); - } - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(tmp_lib_colour)); - if (!m_disable_mode) { - // edit icon - if (m_info.material_state != AMSCanType::AMS_CAN_TYPE_EMPTY && m_info.material_state != AMSCanType::AMS_CAN_TYPE_NONE) - { - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) - dc.DrawBitmap(temp_bitmap_third.bmp(), (size.x - temp_bitmap_third.GetBmpSize().x) / 2 + FromDIP(2), (size.y - FromDIP(18) - temp_bitmap_third.GetBmpSize().y)); - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND) - dc.DrawBitmap(temp_bitmap_brand.bmp(), (size.x - temp_bitmap_brand.GetBmpSize().x) / 2 + FromDIP(2), (size.y - FromDIP(18) - temp_bitmap_brand.GetBmpSize().y)); - } - } - - // selected & hover - if (m_selected) { - dc.DrawBitmap(tray_bitmap_selected.bmp(), (size.x - tray_bitmap_selected.GetBmpSize().x) / 2, (size.y - tray_bitmap_selected.GetBmpSize().y) / 2); - } - else if (!m_selected && m_hover) { - dc.DrawBitmap(tray_bitmap_hover.bmp(), (size.x - tray_bitmap_hover.GetBmpSize().x) / 2, (size.y - tray_bitmap_hover.GetBmpSize().y) / 2); - } - else { - dc.DrawBitmap(tray_bitmap.bmp(), (size.x - tray_bitmap.GetBmpSize().x) / 2, (size.y - tray_bitmap.GetBmpSize().y) / 2); - } -} - - -void AMSLib::render_generic_lib(wxDC &dc) -{ - wxSize size = GetSize(); - auto tmp_lib_colour = m_info.material_colour; - change_the_opacity(tmp_lib_colour); - - auto temp_bitmap_third = m_bitmap_editable_light; - auto temp_bitmap_brand = m_bitmap_readonly_light; - - //draw def background - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(AMS_CONTROL_DEF_LIB_BK_COLOUR)); - dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4), size.x - FromDIP(8), size.y - FromDIP(8), m_radius); - - if (tmp_lib_colour.GetLuminance() < 0.6) { - temp_bitmap_third = m_bitmap_editable_light; - temp_bitmap_brand = m_bitmap_readonly_light; - } - else { - temp_bitmap_third = m_bitmap_editable; - temp_bitmap_brand = m_bitmap_readonly; - } - - if (m_info.material_remain < 50) { - temp_bitmap_third = m_bitmap_editable; - temp_bitmap_brand = m_bitmap_readonly; - } - - if (tmp_lib_colour.Alpha() == 0) { - temp_bitmap_third = m_bitmap_editable; - temp_bitmap_brand = m_bitmap_readonly; - } - - // selected - if (m_selected) { - dc.SetPen(wxPen(tmp_lib_colour, 2, wxPENSTYLE_SOLID)); - if (tmp_lib_colour.Alpha() == 0) { - dc.SetPen(wxPen(wxColour(tmp_lib_colour.Red(), tmp_lib_colour.Green(),tmp_lib_colour.Blue(),128), 2, wxPENSTYLE_SOLID)); - } - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - if (m_radius == 0) { - dc.DrawRectangle(0, 0, size.x, size.y); - } - else { - dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), m_radius); - } - - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(tmp_lib_colour)); - } - - if (!m_selected && m_hover) { - dc.SetPen(wxPen(AMS_CONTROL_BRAND_COLOUR, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - if (m_radius == 0) { - dc.DrawRectangle(0, 0, size.x, size.y); - } - else { - dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), m_radius); - } - - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(tmp_lib_colour)); - } - else { - dc.SetPen(wxPen(tmp_lib_colour, 1, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(tmp_lib_colour)); - } - - //draw remain - auto alpha = m_info.material_colour.Alpha(); - int height = size.y - FromDIP(8); - int curr_height = height * float(m_info.material_remain * 1.0 / 100.0); - dc.SetFont(::Label::Body_13); - - int top = height - curr_height; - - if (curr_height >= FromDIP(6)) { - - //transparent - - if (alpha == 0) { - dc.DrawBitmap(m_bitmap_transparent.bmp(), FromDIP(4), FromDIP(4)); - } - else if (alpha != 255 && alpha != 254) { - if (transparent_changed) { - std::string rgb = (tmp_lib_colour.GetAsString(wxC2S_HTML_SYNTAX)).ToStdString(); - if (rgb.size() == 9) { - //delete alpha value - rgb = rgb.substr(0, rgb.size() - 2); - } - float alpha_f = 0.7 * tmp_lib_colour.Alpha() / 255.0; - std::vector replace; - replace.push_back(rgb); - std::string fill_replace = "fill-opacity=\"" + std::to_string(alpha_f); - replace.push_back(fill_replace); - m_bitmap_transparent = ScalableBitmap(this, "transparent_ams_lib", 68, false, false, true, replace); - transparent_changed = false; - - } - dc.DrawBitmap(m_bitmap_transparent.bmp(), FromDIP(4), FromDIP(4)); - } - //gradient - if (m_info.material_cols.size() > 1) { - int left = FromDIP(4); - float total_width = size.x - FromDIP(8); - int gwidth = std::round(total_width / (m_info.material_cols.size() - 1)); - //gradient - if (m_info.ctype == 0) { - for (int i = 0; i < m_info.material_cols.size() - 1; i++) { - - if ((left + gwidth) > (size.x - FromDIP(8))) { - gwidth = (size.x - FromDIP(4)) - left; - } - - auto rect = wxRect(left, height - curr_height + FromDIP(4), gwidth, curr_height); - dc.GradientFillLinear(rect, m_info.material_cols[i], m_info.material_cols[i + 1], wxEAST); - left += gwidth; - } - } - else { - //multicolour - gwidth = std::round(total_width / m_info.material_cols.size()); - for (int i = 0; i < m_info.material_cols.size(); i++) { - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(m_info.material_cols[i])); - if (i == 0 || i == m_info.material_cols.size() - 1) { -#ifdef __APPLE__ - dc.DrawRoundedRectangle(left + gwidth * i, height - curr_height + FromDIP(4), gwidth, curr_height, m_radius); -#else - dc.DrawRoundedRectangle(left + gwidth * i, height - curr_height + FromDIP(4), gwidth, curr_height, m_radius - 1); -#endif - //add rectangle - int dr_gwidth = std::round(gwidth * 0.6); - if (i == 0) { - dc.DrawRectangle(left + gwidth - dr_gwidth, height - curr_height + FromDIP(4), dr_gwidth, curr_height); - } - else { - dc.DrawRectangle(left + gwidth*i, height - curr_height + FromDIP(4), dr_gwidth, curr_height); - } - } - else { - dc.DrawRectangle(left + gwidth * i, height - curr_height + FromDIP(4), gwidth, curr_height); - } - } - //reset pen and brush - if (m_selected || m_hover) { - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(tmp_lib_colour)); - } - else { - dc.SetPen(wxPen(tmp_lib_colour, 1, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(tmp_lib_colour)); - } - } - } - else { - auto brush = dc.GetBrush(); - if (alpha != 0 && alpha != 255 && alpha != 254) dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); -#ifdef __APPLE__ - dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(8), curr_height, m_radius); -#else - dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(8), curr_height, m_radius - 1); -#endif - dc.SetBrush(brush); - } - } - - if (top > 2) { - if (curr_height >= FromDIP(6)) { - dc.DrawRectangle(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(8), FromDIP(2)); - if (alpha != 255 && alpha != 254) { - dc.SetPen(wxPen(*wxWHITE)); - dc.SetBrush(wxBrush(*wxWHITE)); -#ifdef __APPLE__ - dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) , size.x - FromDIP(8), top, m_radius); -#else - dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) , size.x - FromDIP(8), top, m_radius - 1); -#endif - } - if (tmp_lib_colour.Red() > 238 && tmp_lib_colour.Green() > 238 && tmp_lib_colour.Blue() > 238) { - dc.SetPen(wxPen(wxColour(130, 129, 128), 1, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawLine(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(4), FromDIP(4) + top); - } - } - else { - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - if (tmp_lib_colour.Red() > 238 && tmp_lib_colour.Green() > 238 && tmp_lib_colour.Blue() > 238) { - dc.SetPen(wxPen(wxColour(130, 129, 128), 2, wxPENSTYLE_SOLID)); - } - else { - dc.SetPen(wxPen(tmp_lib_colour, 2, wxPENSTYLE_SOLID)); - } - -#ifdef __APPLE__ - dc.DrawLine(FromDIP(5), FromDIP(4) + height - FromDIP(2), size.x - FromDIP(5), FromDIP(4) + height - FromDIP(2)); - dc.DrawLine(FromDIP(6), FromDIP(4) + height - FromDIP(1), size.x - FromDIP(6), FromDIP(4) + height - FromDIP(1)); -#else - dc.DrawLine(FromDIP(4), FromDIP(4) + height - FromDIP(2), size.x - FromDIP(4), FromDIP(4) + height - FromDIP(2)); - dc.DrawLine(FromDIP(5), FromDIP(4) + height - FromDIP(1), size.x - FromDIP(5), FromDIP(4) + height - FromDIP(1)); -#endif - } - } - - //border - dc.SetPen(wxPen(wxColour(130, 130, 128), 1, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); -#ifdef __APPLE__ - dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4), size.x - FromDIP(7), size.y - FromDIP(7), m_radius); -#else - dc.DrawRoundedRectangle(FromDIP(3), FromDIP(3), size.x - FromDIP(6), size.y - FromDIP(6), m_radius); -#endif - - if (!m_disable_mode) { - // edit icon - if (m_info.material_state != AMSCanType::AMS_CAN_TYPE_EMPTY && m_info.material_state != AMSCanType::AMS_CAN_TYPE_NONE) - { - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) - dc.DrawBitmap(temp_bitmap_third.bmp(), (size.x - temp_bitmap_third.GetBmpSize().x) / 2, (size.y - FromDIP(10) - temp_bitmap_third.GetBmpSize().y)); - if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND) - dc.DrawBitmap(temp_bitmap_brand.bmp(), (size.x - temp_bitmap_brand.GetBmpSize().x) / 2, (size.y - FromDIP(10) - temp_bitmap_brand.GetBmpSize().y)); - } - } -} - -void AMSLib::on_pass_road(bool pass) -{ - if (m_pass_road != pass) { - m_pass_road = pass; - Refresh(); - } -} - -void AMSLib::Update(Caninfo info, bool refresh) -{ - DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return; - if (dev->get_selected_machine() && dev->get_selected_machine() != m_obj) { - m_obj = dev->get_selected_machine(); - } - if (info.material_colour.Alpha() != 0 && info.material_colour.Alpha() != 255 && info.material_colour.Alpha() != 254 && m_info.material_colour != info.material_colour) { - transparent_changed = true; - } - m_info = info; - Layout(); - if (refresh) Refresh(); -} - -wxColour AMSLib::GetLibColour() { return m_info.material_colour; } - -void AMSLib::OnSelected() -{ - if (!wxWindow::IsEnabled()) return; - if (m_unable_selected) return; - - post_event(wxCommandEvent(EVT_AMS_ON_SELECTED)); - m_selected = true; - Refresh(); -} - -void AMSLib::post_event(wxCommandEvent &&event) -{ - event.SetString(m_info.can_id); - event.SetEventObject(m_parent); - wxPostEvent(m_parent, event); - event.Skip(); -} - -void AMSLib::UnSelected() -{ - m_selected = false; - Refresh(); -} - -bool AMSLib::Enable(bool enable) { return wxWindow::Enable(enable); } - -void AMSLib::msw_rescale() -{ - m_bitmap_transparent.msw_rescale(); -} - -/************************************************* -Description:AMSRoad -**************************************************/ -AMSRoad::AMSRoad() : m_road_def_color(AMS_CONTROL_GRAY500), m_road_color(AMS_CONTROL_GRAY500) {} -AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos, const wxSize &size) - : AMSRoad() -{ - m_info = info; - m_canindex = canindex; - // road type - auto mode = AMSRoadMode::AMS_ROAD_MODE_END; - if (m_canindex == 0 && maxcan == 1) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_NONE; - } else if (m_canindex == 0 && maxcan > 1) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_END; - } else if (m_canindex < (maxcan - 1)) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT; - } else if (m_canindex == (maxcan - 1)) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT; - } else if (m_canindex == -1 && maxcan == -1) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY; - } - else { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_NONE_ANY_ROAD; - } - - for (int i = 1; i <= 5; i++) { - ams_humidity_img.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 32)); - } - - for (int i = 1; i <= 5; i++) { - ams_humidity_img.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 32)); - } - if (m_rode_mode != AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { - create(parent, id, pos, size); - } - else { - wxSize virtual_size(size.x - 1, size.y + 2); - create(parent, id, pos, virtual_size); - - } - - Bind(wxEVT_PAINT, &AMSRoad::paintEvent, this); - wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - - Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { - if (m_canindex == 3 && m_show_humidity) { - auto mouse_pos = ClientToScreen(e.GetPosition()); - auto rect = ClientToScreen(wxPoint(0, 0)); - - if (mouse_pos.x > rect.x + GetSize().x - FromDIP(40) && - mouse_pos.y > rect.y + GetSize().y - FromDIP(40)) { - wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); - wxPostEvent(GetParent()->GetParent(), show_event); - -#ifdef __WXMSW__ - wxCommandEvent close_event(EVT_CLEAR_SPEED_CONTROL); - wxPostEvent(GetParent()->GetParent(), close_event); -#endif // __WXMSW__ - - } - } - }); -} - -void AMSRoad::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size); } - -void AMSRoad::Update(AMSinfo amsinfo, Caninfo info, int canindex, int maxcan) -{ - m_amsinfo = amsinfo; - m_info = info; - m_canindex = canindex; - if (m_canindex == 0 && maxcan == 1) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_END_ONLY; - } else if (m_canindex == 0 && maxcan > 1) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_END; - } else if (m_canindex < (maxcan - 1)) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT; - } else if (m_canindex == (maxcan - 1)) { - m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT; - } - m_pass_rode_mode.push_back(AMSPassRoadMode::AMS_ROAD_MODE_NONE); - Refresh(); -} - -void AMSRoad::OnVamsLoading(bool load, wxColour col /*= AMS_CONTROL_GRAY500*/) -{ - m_vams_loading = load; - if(load)m_road_color = col; - Refresh(); -} - -void AMSRoad::SetPassRoadColour(wxColour col) { m_road_color = col; } - -void AMSRoad::SetMode(AMSRoadMode mode) -{ - m_rode_mode = mode; - Refresh(); -} - -void AMSRoad::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSRoad::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void AMSRoad::doRender(wxDC &dc) -{ - wxSize size = GetSize(); - - dc.SetPen(wxPen(m_road_def_color, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - // left mode - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT) { dc.DrawRoundedRectangle(-10, -10, size.x / 2 + 10, size.y * 0.6 + 10, 4); } - - // left right mode - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT) { - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - dc.DrawLine(0, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); - } - - // end mode - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END) { - dc.SetBrush(wxBrush(m_road_def_color)); - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); - dc.DrawLine(size.x / 2, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); - } - - // end mode only - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { - dc.SetBrush(wxBrush(m_road_def_color)); - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); - } - - // end none - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_NONE) { - dc.SetBrush(wxBrush(m_road_def_color)); - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); - dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); - // dc.DrawLine(size.x / 2, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); - } - - //virtual road - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { - dc.SetBrush(wxBrush(m_road_def_color)); - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y - 1); - } - - // mode none - // if (m_pass_rode_mode.size() == 1 && m_pass_rode_mode[0] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) return; - - if (m_road_color.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, m_passroad_width, wxPENSTYLE_SOLID));} - else {dc.SetPen(wxPen(m_road_color, m_passroad_width, wxPENSTYLE_SOLID));} - - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - - // left pass mode - for (auto pass_mode : m_pass_rode_mode) { - switch (pass_mode) { - case AMSPassRoadMode::AMS_ROAD_MODE_LEFT: dc.DrawRoundedRectangle(-10, -10, size.x / 2 + 10, size.y * 0.6 + 10, 4); break; - - case AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT: dc.DrawLine(0, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); break; - - case AMSPassRoadMode::AMS_ROAD_MODE_END_TOP: dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); break; - - case AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM: dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); break; - - case AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT: dc.DrawLine(size.x / 2, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); break; - - default: break; - } - } - - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY && m_vams_loading) { - dc.DrawLine(size.x / 2, -1, size.x / 2, size.y - 1); - } - - // end mode - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { - dc.SetPen(wxPen(m_road_def_color, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(m_road_def_color)); - dc.DrawRoundedRectangle(size.x * 0.37 / 2, size.y * 0.6 - size.y / 6, size.x * 0.63, size.y / 3, m_radius); - } - - if (m_canindex == 3) { - - if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) {m_show_humidity = true;} - else {m_show_humidity = false;} - - if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) { - - int hum_index = m_amsinfo.ams_humidity - 1; - if (wxGetApp().dark_mode()) { - hum_index += 5; - } - - if (hum_index >= 0) { - dc.DrawBitmap(ams_humidity_img[hum_index].bmp(), wxPoint(size.x - FromDIP(33), size.y - FromDIP(33))); - } - } - else { - //to do ... - } - } -} - -void AMSRoad::UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step) {} - -void AMSRoad::OnPassRoad(std::vector prord_list) -{ - // AMS_ROAD_MODE_NONE, AMS_ROAD_MODE_LEFT, AMS_ROAD_MODE_LEFT_RIGHT, AMS_ROAD_MODE_END_TOP, AMS_ROAD_MODE_END_BOTTOM, AMS_ROAD_MODE_END_RIGHT, - // AMS_ROAD_MODE_LEFT, AMS_ROAD_MODE_LEFT_RIGHT, AMS_ROAD_MODE_END, - - m_pass_rode_mode.clear(); - auto left_types = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE, AMSPassRoadMode::AMS_ROAD_MODE_LEFT}; - auto left_right_types = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE, AMSPassRoadMode::AMS_ROAD_MODE_LEFT, AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT}; - auto end_types = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE, AMSPassRoadMode::AMS_ROAD_MODE_END_TOP, AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM, - AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT}; - - // left - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT) { - for (auto i = 0; i < prord_list.size(); i++) { - std::vector::iterator iter = std::find(left_types.begin(), left_types.end(), prord_list[i]); - if (iter != left_types.end()) m_pass_rode_mode.push_back(prord_list[i]); - - if (prord_list[i] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) { - m_pass_rode_mode = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE}; - break; - } - } - } - - // left right - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT) { - for (auto i = 0; i < prord_list.size(); i++) { - std::vector::iterator iter = std::find(left_right_types.begin(), left_right_types.end(), prord_list[i]); - if (iter != left_right_types.end()) m_pass_rode_mode.push_back(prord_list[i]); - - if (prord_list[i] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) { - m_pass_rode_mode = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE}; - break; - } - } - } - - // left end - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { - for (auto i = 0; i < prord_list.size(); i++) { - std::vector::iterator iter = std::find(end_types.begin(), end_types.end(), prord_list[i]); - if (iter != end_types.end()) m_pass_rode_mode.push_back(prord_list[i]); - - if (prord_list[i] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) { - m_pass_rode_mode = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE}; - break; - } - } - } -} - -/************************************************* -Description:AMSControl -**************************************************/ -AMSItem::AMSItem() {} - -AMSItem::AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSItem() -{ - m_amsinfo = amsinfo; - m_cube_size = cube_size; - create(parent, id, pos, AMS_ITEM_SIZE); - Bind(wxEVT_PAINT, &AMSItem::paintEvent, this); - Bind(wxEVT_ENTER_WINDOW, &AMSItem::OnEnterWindow, this); - Bind(wxEVT_LEAVE_WINDOW, &AMSItem::OnLeaveWindow, this); -} - -void AMSItem::Open() -{ - m_open = true; - Show(); -} - -void AMSItem::Close() -{ - m_open = false; - Hide(); -} - -void AMSItem::Update(AMSinfo amsinfo) -{ - m_amsinfo = amsinfo; -} - -void AMSItem::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) -{ - m_ts_bitmap_cube = new ScalableBitmap(this, "ts_bitmap_cube", 14); - wxWindow::Create(parent, id, pos, size); - SetMinSize(AMS_ITEM_SIZE); - SetMaxSize(AMS_ITEM_SIZE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); - Refresh(); -} - -void AMSItem::OnEnterWindow(wxMouseEvent &evt) -{ - // m_hover = true; - // Refresh(); -} - -void AMSItem::OnLeaveWindow(wxMouseEvent &evt) -{ - // m_hover = false; - // Refresh(); -} - -void AMSItem::OnSelected() -{ - if (!wxWindow::IsEnabled()) { return; } - m_selected = true; - Refresh(); -} - -void AMSItem::UnSelected() -{ - m_selected = false; - Refresh(); -} - -bool AMSItem::Enable(bool enable) { return wxWindow::Enable(enable); } - -void AMSItem::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSItem::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void AMSItem::doRender(wxDC &dc) -{ - wxSize size = GetSize(); - dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); - dc.SetBrush(wxBrush(StateColor::darkModeColorFor(m_background_colour))); - dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); - - auto left = m_padding; - for (std::vector::iterator iter = m_amsinfo.cans.begin(); iter != m_amsinfo.cans.end(); iter++) { - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - - if (wxWindow::IsEnabled()) { - wxColour color = iter->material_colour; - change_the_opacity(color); - dc.SetBrush(wxBrush(color)); - } else { - dc.SetBrush(AMS_CONTROL_DISABLE_COLOUR); - } - - if (iter->material_cols.size() > 1) { - int fleft = left; - float total_width = AMS_ITEM_CUBE_SIZE.x; - int gwidth = std::round(total_width / (iter->material_cols.size() - 1)); - if (iter->ctype == 0) { - for (int i = 0; i < iter->material_cols.size() - 1; i++) { - - if ((fleft + gwidth) > (AMS_ITEM_CUBE_SIZE.x)) { - gwidth = (fleft + AMS_ITEM_CUBE_SIZE.x) - fleft; - } - - auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); - dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); - fleft += gwidth; - } - } else { - int cols_size = iter->material_cols.size(); - for (int i = 0; i < cols_size; i++) { - dc.SetBrush(wxBrush(iter->material_cols[i])); - float x = left + total_width * i / cols_size; - dc.DrawRoundedRectangle(x, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, total_width / cols_size, AMS_ITEM_CUBE_SIZE.y , 0); - } - } - - dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRoundedRectangle(left - 1, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2 - 1, AMS_ITEM_CUBE_SIZE.x + 2, AMS_ITEM_CUBE_SIZE.y + 2, 2); - - }else { - if (iter->material_colour.Alpha() == 0) { - dc.DrawBitmap(m_ts_bitmap_cube->bmp(),left,(size.y - AMS_ITEM_CUBE_SIZE.y) / 2); - } - else { - wxRect rect(left, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, AMS_ITEM_CUBE_SIZE.x, AMS_ITEM_CUBE_SIZE.y); - if(iter->material_state==AMSCanType::AMS_CAN_TYPE_EMPTY){ - dc.SetPen(wxPen(wxColor(0, 0, 0))); - dc.DrawRoundedRectangle(rect, 2); - - dc.DrawLine(rect.GetRight()-1, rect.GetTop()+1, rect.GetLeft()+1, rect.GetBottom()-1); - } - else { - dc.DrawRoundedRectangle(rect, 2); - } - } - - } - - - left += AMS_ITEM_CUBE_SIZE.x; - left += m_space; - } - - auto border_colour = AMS_CONTROL_BRAND_COLOUR; - if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } - - if (m_hover) { - dc.SetPen(wxPen(border_colour, 2)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); - - } - - if (m_selected) { - dc.SetPen(wxPen(border_colour, 2)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); - } -} - -void AMSItem::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } - -/************************************************* -Description:AmsCan -**************************************************/ - -AmsCans::AmsCans() {} - -AmsCans::AmsCans(wxWindow *parent,AMSinfo info, AMSModel model) : AmsCans() -{ - m_bitmap_extra_framework = ScalableBitmap(this, "ams_extra_framework_mid", 140); - - SetDoubleBuffered(true); - m_ams_model = model; - m_info = info; - - wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE); - create(parent); - Bind(wxEVT_PAINT, &AmsCans::paintEvent, this); -} - -void AmsCans::create(wxWindow *parent) -{ - Freeze(); - SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - - if (m_ams_model == AMSModel::GENERIC_AMS) { - sizer_can = new wxBoxSizer(wxHORIZONTAL); - for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { - AddCan(*it, m_can_count, m_info.cans.size(), sizer_can); - m_can_count++; - } - SetSizer(sizer_can); - } - else if(m_ams_model == AMSModel::EXTRA_AMS) { - sizer_can = new wxBoxSizer(wxVERTICAL); - sizer_can_middle = new wxBoxSizer(wxHORIZONTAL); - sizer_can_left = new wxBoxSizer(wxVERTICAL); - sizer_can_right = new wxBoxSizer(wxVERTICAL); - - sizer_can_left->Add(0,0,0,wxTOP,FromDIP(8)); - - for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { - if (m_can_count <= 1) { - AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_left); - if (m_can_count == 0) { - sizer_can_left->Add(0,0,0,wxTOP,FromDIP(20)); - } - } - else { - AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_right); - if (m_can_count == 2) { - sizer_can_right->Prepend(0, 0, 0, wxTOP, FromDIP(20)); - } - } - - m_can_count++; - } - - sizer_can_right->Prepend(0,0,0,wxTOP,FromDIP(8)); - sizer_can_middle->Add(0, 0, 0, wxLEFT, FromDIP(8)); - sizer_can_middle->Add(sizer_can_left, 0, wxALL, 0); - sizer_can_middle->Add( 0, 0, 0, wxLEFT, FromDIP(20) ); - sizer_can_middle->Add(sizer_can_right, 0, wxALL, 0); - sizer_can->Add(sizer_can_middle, 1, wxALIGN_CENTER, 0); - SetSizer(sizer_can); - } - - Layout(); - Fit(); - Thaw(); -} - -void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer) -{ - - auto amscan = new wxWindow(this, wxID_ANY); - amscan->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - - wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); - - - auto m_panel_refresh = new AMSrefresh(amscan, m_can_count, caninfo); - auto m_panel_lib = new AMSLib(amscan, caninfo); - - m_panel_lib->Bind(wxEVT_LEFT_DOWN, [this, canindex](wxMouseEvent& ev) { - m_canlib_selection = canindex; - // m_canlib_id = caninfo.can_id; - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - if (lib->canLib->m_can_index == m_canlib_selection) { - wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); - evt.SetString(m_info.ams_id); - wxPostEvent(GetParent()->GetParent(), evt); - lib->canLib->OnSelected(); - } - else { - lib->canLib->UnSelected(); - } - } - ev.Skip(); - }); - - - m_panel_lib->m_ams_model = m_ams_model; - m_panel_lib->m_info.can_id = caninfo.can_id; - m_panel_lib->m_can_index = canindex; - - - auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); - - if (m_ams_model == AMSModel::GENERIC_AMS) { - m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(14)); - m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); - m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); - m_sizer_ams->Add(m_panel_road, 0, wxALL, 0); - } - else if (m_ams_model == AMSModel::EXTRA_AMS) - { - m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); - m_panel_road->Hide(); - - if (canindex <= 1) { - m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); - m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); - } - else { - m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); - m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); - } - } - - - amscan->SetSizer(m_sizer_ams); - amscan->Layout(); - amscan->Fit(); - - if (m_ams_model == AMSModel::GENERIC_AMS) { - sizer->Add(amscan, 0, wxALL, 0); - } - else if (m_ams_model == AMSModel::EXTRA_AMS) - { - if (canindex > 1) { - sizer->Prepend(amscan, 0, wxALL, 0); - } - else { - sizer->Add(amscan, 0, wxALL, 0); - } - } - - Canrefreshs* canrefresh = new Canrefreshs; - canrefresh->canID = caninfo.can_id; - canrefresh->canrefresh = m_panel_refresh; - m_can_refresh_list.Add(canrefresh); - - CanLibs* canlib = new CanLibs; - canlib->canID = caninfo.can_id; - canlib->canLib = m_panel_lib; - m_can_lib_list.Add(canlib); - - CanRoads* canroad = new CanRoads; - canroad->canID = caninfo.can_id; - canroad->canRoad = m_panel_road; - m_can_road_list.Add(canroad); -} - -void AmsCans::Update(AMSinfo info) -{ - m_info = info; - m_can_count = info.cans.size(); - - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - if (i < m_can_count) { - refresh->canrefresh->Update(info.ams_id, info.cans[i]); - refresh->canrefresh->Show(); - } else { - refresh->canrefresh->Hide(); - } - } - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (i < m_can_count) { - lib->canLib->Update(info.cans[i]); - lib->canLib->Show(); - } else { - lib->canLib->Hide(); - } - } - - if (m_ams_model == AMSModel::GENERIC_AMS) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads* road = m_can_road_list[i]; - if (i < m_can_count) { - road->canRoad->Update(m_info, info.cans[i], i, m_can_count); - road->canRoad->Show(); - } - else { - road->canRoad->Hide(); - } - } - } - Layout(); -} - -void AmsCans::SetDefSelectCan() -{ - if (m_can_lib_list.GetCount() > 0) { - CanLibs* lib = m_can_lib_list[0]; - m_canlib_selection =lib->canLib->m_can_index; - m_canlib_id = lib->canLib->m_info.can_id; - SelectCan(m_canlib_id); - } -} - - -void AmsCans::SelectCan(std::string canid) -{ - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (lib->canLib->m_info.can_id == canid) { - m_canlib_selection = lib->canLib->m_can_index; - } - } - - m_canlib_id = canid; - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (lib->canLib->m_info.can_id == m_canlib_id) { - wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); - evt.SetString(m_info.ams_id); - wxPostEvent(GetParent()->GetParent(), evt); - lib->canLib->OnSelected(); - } else { - lib->canLib->UnSelected(); - } - } -} - -wxColour AmsCans::GetTagColr(wxString canid) -{ - auto tag_colour = *wxWHITE; - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - if (canid == lib->canLib->m_info.can_id) tag_colour = lib->canLib->GetLibColour(); - } - return tag_colour; -} - -void AmsCans::SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) -{ - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP1) { - SetAmsStep(canid.ToStdString()); - }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP2) { - SetAmsStep(canid.ToStdString()); - }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP3) { - SetAmsStep(canid.ToStdString()); - }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { - SetAmsStep(""); - } -} - -void AmsCans::SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) -{ - - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - auto pr = std::vector{}; - pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_NONE); - road->canRoad->OnPassRoad(pr); - } - - return; - } - - - auto tag_can_index = -1; - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - if (canid == road->canRoad->m_info.can_id) { tag_can_index = road->canRoad->m_canindex; } - } - if (tag_can_index == -1) return; - - // get colour - auto tag_colour = *wxWHITE; - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (canid == lib->canLib->m_info.can_id) tag_colour = lib->canLib->GetLibColour(); - } - - // unload - if (type == AMSPassRoadType::AMS_ROAD_TYPE_UNLOAD) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - - auto index = road->canRoad->m_canindex; - auto pr = std::vector{}; - - pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } - - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_3) { - if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } - if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } - if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } - if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } - } - - road->canRoad->SetPassRoadColour(tag_colour); - road->canRoad->OnPassRoad(pr); - } - } - - // load - if (type == AMSPassRoadType::AMS_ROAD_TYPE_LOAD) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - - auto index = road->canRoad->m_canindex; - auto pr = std::vector{}; - - if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } - if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } - if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } - if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } - - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } - - road->canRoad->SetPassRoadColour(tag_colour); - road->canRoad->OnPassRoad(pr); - } - } -} - -void AmsCans::SetAmsStep(std::string can_id) -{ - if (m_road_canid != can_id) { - m_road_canid = can_id; - Refresh(); - } -} - -void AmsCans::PlayRridLoading(wxString canid) -{ - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - if (refresh->canrefresh->m_info.can_id == canid) { refresh->canrefresh->PlayLoading(); } - } -} - -std::string AmsCans::GetCurrentCan() -{ - if (m_canlib_selection < 0) - return ""; - - return wxString::Format("%d", m_canlib_selection).ToStdString(); -} - -void AmsCans::paintEvent(wxPaintEvent& evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AmsCans::render(wxDC& dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void AmsCans::doRender(wxDC& dc) -{ - wxSize size = GetSize(); - dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); - - //road for extra - if (m_ams_model == AMSModel::EXTRA_AMS) { - - auto end_top = size.x / 2 - FromDIP(99); - auto passroad_width = 6; - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - - if (m_road_canid.empty()) { - lib->canLib->on_pass_road(false); - } - else { - if (lib->canLib->m_info.can_id == m_road_canid) { - m_road_colour = lib->canLib->m_info.material_colour; - lib->canLib->on_pass_road(true); - } - } - } - - - // A1 - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - - try - { - auto a1_top = size.y / 2 - FromDIP(4); - auto a1_left = m_can_lib_list[0]->canLib->GetScreenPosition().x + m_can_lib_list[0]->canLib->GetSize().x / 2; - auto local_pos1 = GetScreenPosition().x + GetSize().x / 2; - a1_left = size.x / 2 + (a1_left - local_pos1); - dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); - dc.DrawLine(a1_left, a1_top, end_top, a1_top); - - - // A2 - auto a2_top = size.y / 2 + FromDIP(8); - auto a2_left = m_can_lib_list[1]->canLib->GetScreenPosition().x + m_can_lib_list[1]->canLib->GetSize().x / 2; - auto local_pos2 = GetScreenPosition().x + GetSize().x / 2; - a2_left = size.x / 2 + (a2_left - local_pos2); - dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); - dc.DrawLine(a2_left, a2_top, end_top, a2_top); - - // A3 - auto a3_top = size.y / 2 + FromDIP(4); - auto a3_left = m_can_lib_list[2]->canLib->GetScreenPosition().x + m_can_lib_list[2]->canLib->GetSize().x / 2; - auto local_pos3 = GetScreenPosition().x + GetSize().x / 2; - a3_left = size.x / 2 + (a3_left - local_pos3); - dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); - dc.DrawLine(a3_left, a3_top, end_top, a3_top); - - - // A4 - auto a4_top = size.y / 2; - auto a4_left = m_can_lib_list[3]->canLib->GetScreenPosition().x + m_can_lib_list[3]->canLib->GetSize().x / 2; - auto local_pos4 = GetScreenPosition().x + GetSize().x / 2; - a4_left = size.x / 2 + (a4_left - local_pos4); - dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); - dc.DrawLine(a4_left, a4_top, end_top, a4_top); - - - if (!m_road_canid.empty()) { - if (m_road_canid == "0") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); - dc.DrawLine(a1_left, a1_top, end_top, a1_top); - } - - if (m_road_canid == "1") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); - dc.DrawLine(a2_left, a2_top, end_top, a2_top); - } - - if (m_road_canid == "2") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); - dc.DrawLine(a3_left, a3_top, end_top, a3_top); - } - - if (m_road_canid == "3") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); - dc.DrawLine(a4_left, a4_top, end_top, a4_top); - } - } - - //to Extruder - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - - dc.DrawLine(end_top, a1_top, end_top, size.y); - - if (!m_road_canid.empty()) { - if (!m_road_canid.empty()) { - if (m_road_canid == "0") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a1_top, end_top, size.y); - } - else if (m_road_canid == "1") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a2_top, end_top, size.y); - } - else if (m_road_canid == "2") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a3_top, end_top, size.y); - } - else if (m_road_canid == "3") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a4_top, end_top, size.y); - } - } - } - } - catch (...){} - } -} - -void AmsCans::StopRridLoading(wxString canid) -{ - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - if (refresh->canrefresh->m_info.can_id == canid) { refresh->canrefresh->StopLoading(); } - } -} - -void AmsCans::msw_rescale() -{ - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - refresh->canrefresh->msw_rescale(); - } - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - lib->canLib->msw_rescale(); - } -} - -void AmsCans::show_sn_value(bool show) -{ - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - lib->canLib->show_kn_value(show); - } -} +namespace Slic3r { namespace GUI { /************************************************* @@ -2618,7 +262,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons auto vams_panel = new wxWindow(m_panel_virtual, wxID_ANY); vams_panel->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - m_vams_lib = new AMSLib(vams_panel, m_vams_info); + m_vams_lib = new AMSLib(vams_panel, "0", m_vams_info); m_vams_road = new AMSRoad(vams_panel, wxID_ANY, m_vams_info, -1, -1, wxDefaultPosition, AMS_CAN_ROAD_SIZE); m_vams_lib->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { @@ -3254,7 +898,7 @@ void AMSControl::Reset() UpdateAms(ams_info, true); m_current_show_ams = ""; m_current_ams = ""; - m_current_senect = ""; + m_current_select = ""; } void AMSControl::show_noams_mode() @@ -3461,7 +1105,7 @@ void AMSControl::SwitchAms(std::string ams_id) AmsItems *item = m_ams_item_list[i]; if (item->amsItem->m_amsinfo.ams_id == m_current_show_ams) { item->amsItem->OnSelected(); - m_current_senect = ams_id; + m_current_select = ams_id; //bool ready_selected = false; //for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index afcee66365d..e5c5e08942a 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -5,6 +5,7 @@ #include "StaticBox.hpp" #include "StepCtrl.hpp" #include "Button.hpp" +#include "AMSItem.hpp" #include "../DeviceManager.hpp" #include "slic3r/GUI/Event.hpp" #include "slic3r/GUI/AmsMappingPopup.hpp" @@ -13,547 +14,9 @@ #include #include -#define AMS_CONTROL_BRAND_COLOUR wxColour(0, 150, 136) -#define AMS_CONTROL_GRAY700 wxColour(107, 107, 107) -#define AMS_CONTROL_GRAY800 wxColour(50, 58, 61) -#define AMS_CONTROL_GRAY500 wxColour(172, 172, 172) -#define AMS_CONTROL_DISABLE_COLOUR wxColour(206, 206, 206) -#define AMS_CONTROL_DISABLE_TEXT_COLOUR wxColour(144, 144, 144) -#define AMS_CONTROL_WHITE_COLOUR wxColour(255, 255, 255) -#define AMS_CONTROL_BLACK_COLOUR wxColour(0, 0, 0) -#define AMS_CONTROL_DEF_BLOCK_BK_COLOUR wxColour(238, 238, 238) -#define AMS_CONTROL_DEF_LIB_BK_COLOUR wxColour(248, 248, 248) -#define AMS_EXTRUDER_DEF_COLOUR wxColour(234, 234, 234) -#define AMS_CONTROL_MAX_COUNT 4 -#define AMS_CONTRO_CALIBRATION_BUTTON_SIZE wxSize(FromDIP(150), FromDIP(28)) - -// enum AMSRoadMode{ -// AMS_ROAD_MODE_LEFT, -// AMS_ROAD_MODE_LEFT_RIGHT, -// AMS_ROAD_MODE_END, -//}; namespace Slic3r { namespace GUI { -enum AMSModel { - NO_AMS = 0, - GENERIC_AMS = 1, - EXTRA_AMS = 2 -}; - -enum ActionButton { - ACTION_BTN_CALI = 0, - ACTION_BTN_LOAD = 1, - ACTION_BTN_UNLOAD = 2, - ACTION_BTN_COUNT = 3 -}; - -enum class AMSRoadMode : int { - AMS_ROAD_MODE_LEFT, - AMS_ROAD_MODE_LEFT_RIGHT, - AMS_ROAD_MODE_END, - AMS_ROAD_MODE_END_ONLY, - AMS_ROAD_MODE_NONE, - AMS_ROAD_MODE_NONE_ANY_ROAD, - AMS_ROAD_MODE_VIRTUAL_TRAY -}; - -enum class AMSPassRoadMode : int { - AMS_ROAD_MODE_NONE, - AMS_ROAD_MODE_LEFT, - AMS_ROAD_MODE_LEFT_RIGHT, - AMS_ROAD_MODE_END_TOP, - AMS_ROAD_MODE_END_RIGHT, - AMS_ROAD_MODE_END_BOTTOM, -}; - -enum class AMSAction : int { - AMS_ACTION_NONE, - AMS_ACTION_LOAD, - AMS_ACTION_UNLOAD, - AMS_ACTION_CALI, - AMS_ACTION_PRINTING, - AMS_ACTION_NORMAL, - AMS_ACTION_NOAMS, -}; - -enum class AMSPassRoadSTEP : int { - AMS_ROAD_STEP_NONE, - AMS_ROAD_STEP_1, // lib -> extrusion - AMS_ROAD_STEP_2, // extrusion->buffer - AMS_ROAD_STEP_3, // extrusion - - AMS_ROAD_STEP_COMBO_LOAD_STEP1, - AMS_ROAD_STEP_COMBO_LOAD_STEP2, - AMS_ROAD_STEP_COMBO_LOAD_STEP3, -}; - -enum class AMSPassRoadType : int { - AMS_ROAD_TYPE_NONE, - AMS_ROAD_TYPE_LOAD, - AMS_ROAD_TYPE_UNLOAD, -}; - -enum class AMSCanType : int { - AMS_CAN_TYPE_NONE, - AMS_CAN_TYPE_BRAND, - AMS_CAN_TYPE_THIRDBRAND, - AMS_CAN_TYPE_EMPTY, - AMS_CAN_TYPE_VIRTUAL, -}; - -enum FilamentStep { - STEP_IDLE, - STEP_HEAT_NOZZLE, - STEP_CUT_FILAMENT, - STEP_PULL_CURR_FILAMENT, - STEP_PUSH_NEW_FILAMENT, - STEP_PURGE_OLD_FILAMENT, - STEP_FEED_FILAMENT, - STEP_CONFIRM_EXTRUDED, - STEP_CHECK_POSITION, - STEP_COUNT, -}; - -enum FilamentStepType { - STEP_TYPE_LOAD = 0, - STEP_TYPE_UNLOAD = 1, - STEP_TYPE_VT_LOAD = 2, -}; - -#define AMS_ITEM_CUBE_SIZE wxSize(FromDIP(14), FromDIP(14)) -#define AMS_ITEM_SIZE wxSize(FromDIP(82), FromDIP(27)) -#define AMS_ITEM_HUMIDITY_SIZE wxSize(FromDIP(120), FromDIP(27)) -#define AMS_CAN_LIB_SIZE wxSize(FromDIP(58), FromDIP(80)) -#define AMS_CAN_ROAD_SIZE wxSize(FromDIP(66), FromDIP(70)) -#define AMS_CAN_ITEM_HEIGHT_SIZE FromDIP(27) -#define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(196)) -#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) -#define AMS_STEP_SIZE wxSize(FromDIP(172), FromDIP(196)) -#define AMS_REFRESH_SIZE wxSize(FromDIP(30), FromDIP(30)) -#define AMS_EXTRUDER_SIZE wxSize(FromDIP(86), FromDIP(72)) -#define AMS_EXTRUDER_BITMAP_SIZE wxSize(FromDIP(36), FromDIP(55)) - -struct Caninfo -{ - std::string can_id; - wxString material_name; - wxColour material_colour = {*wxWHITE}; - AMSCanType material_state; - int ctype=0; - int material_remain = 100; - float k = 0.0f; - float n = 0.0f; - std::vector material_cols; -}; - -struct AMSinfo -{ -public: - std::string ams_id; - std::vector cans; - std::string current_can_id; - AMSPassRoadSTEP current_step; - AMSAction current_action; - int curreent_filamentstep; - int ams_humidity = 0; - - bool parse_ams_info(MachineObject* obj, Ams *ams, bool remain_flag = false, bool humidity_flag = false); -}; - -/************************************************* -Description:AMSrefresh -**************************************************/ -#define AMS_REFRESH_PLAY_LOADING_TIMER 100 -class AMSrefresh : public wxWindow -{ -public: - AMSrefresh(); - AMSrefresh(wxWindow *parent, wxString number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - ~AMSrefresh(); - void PlayLoading(); - void StopLoading(); - void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); - void on_timer(wxTimerEvent &event); - void OnEnterWindow(wxMouseEvent &evt); - void OnLeaveWindow(wxMouseEvent &evt); - void OnClick(wxMouseEvent &evt); - void post_event(wxCommandEvent &&event); - void paintEvent(wxPaintEvent &evt); - void Update(std::string ams_id, Caninfo info); - void msw_rescale(); - void set_disable_mode(bool disable) { m_disable_mode = disable; } - Caninfo m_info; - - -protected: - wxTimer *m_playing_timer= {nullptr}; - int m_rotation_angle = 0; - bool m_play_loading = {false}; - bool m_selected = {false}; - - std::string m_ams_id; - std::string m_can_id; - - ScalableBitmap m_bitmap_normal; - ScalableBitmap m_bitmap_selected; - ScalableBitmap m_bitmap_ams_rfid_0; - ScalableBitmap m_bitmap_ams_rfid_1; - ScalableBitmap m_bitmap_ams_rfid_2; - ScalableBitmap m_bitmap_ams_rfid_3; - ScalableBitmap m_bitmap_ams_rfid_4; - ScalableBitmap m_bitmap_ams_rfid_5; - ScalableBitmap m_bitmap_ams_rfid_6; - ScalableBitmap m_bitmap_ams_rfid_7; - std::vector m_rfid_bitmap_list; - - wxString m_refresh_id; - wxBoxSizer * m_size_body; - virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); - - bool m_disable_mode{ false }; -}; - -/************************************************* -Description:AMSextruder -**************************************************/ -class AMSextruderImage: public wxWindow -{ -public: - void TurnOn(wxColour col); - void TurnOff(); - void msw_rescale(); - void paintEvent(wxPaintEvent &evt); - - void render(wxDC &dc); - bool m_turn_on = {false}; - wxColour m_colour; - ScalableBitmap m_ams_extruder; - void doRender(wxDC &dc); - AMSextruderImage(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - ~AMSextruderImage(); -}; - - -class AMSextruder : public wxWindow -{ -public: - void TurnOn(wxColour col); - void TurnOff(); - void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); - void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); - void OnAmsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); - void paintEvent(wxPaintEvent& evt); - void render(wxDC& dc); - void doRender(wxDC& dc); - void msw_rescale(); - void has_ams(bool hams) {m_has_vams = hams; Refresh();}; - void no_ams_mode(bool mode) {m_none_ams_mode = mode; Refresh();}; - - bool m_none_ams_mode{true}; - bool m_has_vams{false}; - bool m_vams_loading{false}; - bool m_ams_loading{false}; - wxColour m_current_colur; - - wxBoxSizer * m_bitmap_sizer{nullptr}; - wxPanel * m_bitmap_panel{nullptr}; - AMSextruderImage *m_amsSextruder{nullptr}; - ScalableBitmap monitor_ams_extruder; - AMSextruder(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - ~AMSextruder(); -}; - -class AMSVirtualRoad : public wxWindow -{ -public: - AMSVirtualRoad(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); - ~AMSVirtualRoad(); - -private: - bool m_has_vams{ true }; - bool m_vams_loading{ false }; - wxColour m_current_color; - -public: - void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); - void SetHasVams(bool hvams) { m_has_vams = hvams; }; - void create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size); - void paintEvent(wxPaintEvent& evt); - void render(wxDC& dc); - void doRender(wxDC& dc); - void msw_rescale(); -}; - -/************************************************* -Description:AMSLib -**************************************************/ -class AMSLib : public wxWindow -{ -public: - AMSLib(wxWindow *parent, Caninfo info); - void create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); -public: - wxColour GetLibColour(); - Caninfo m_info; - MachineObject* m_obj = {nullptr}; - int m_can_index = 0; - AMSModel m_ams_model; - - void Update(Caninfo info, bool refresh = true); - void UnableSelected() { m_unable_selected = true; }; - void EableSelected() { m_unable_selected = false; }; - void OnSelected(); - void UnSelected(); - bool is_selected() {return m_selected;}; - void post_event(wxCommandEvent &&event); - void show_kn_value(bool show) { m_show_kn = show; }; - void support_cali(bool sup) { m_support_cali = sup; Refresh(); }; - virtual bool Enable(bool enable = true); - void set_disable_mode(bool disable) { m_disable_mode = disable; } - void msw_rescale(); - void on_pass_road(bool pass); - -protected: - wxStaticBitmap *m_edit_bitmp = {nullptr}; - wxStaticBitmap *m_edit_bitmp_light = {nullptr}; - ScalableBitmap m_bitmap_editable; - ScalableBitmap m_bitmap_editable_light; - ScalableBitmap m_bitmap_readonly; - ScalableBitmap m_bitmap_readonly_light; - ScalableBitmap m_bitmap_transparent; - - ScalableBitmap m_bitmap_extra_tray_left; - ScalableBitmap m_bitmap_extra_tray_right; - - ScalableBitmap m_bitmap_extra_tray_left_hover; - ScalableBitmap m_bitmap_extra_tray_right_hover; - - ScalableBitmap m_bitmap_extra_tray_left_selected; - ScalableBitmap m_bitmap_extra_tray_right_selected; - - bool m_unable_selected = {false}; - bool m_enable = {false}; - bool m_selected = {false}; - bool m_hover = {false}; - bool m_show_kn = {false}; - bool m_support_cali = {false}; - bool transparent_changed = {false}; - - double m_radius = {4}; - wxColour m_border_color; - wxColour m_road_def_color; - wxColour m_lib_color; - bool m_disable_mode{ false }; - bool m_pass_road{false}; - - void on_enter_window(wxMouseEvent &evt); - void on_leave_window(wxMouseEvent &evt); - void on_left_down(wxMouseEvent &evt); - void paintEvent(wxPaintEvent &evt); - void render(wxDC &dc); - void render_extra_text(wxDC& dc); - void render_generic_text(wxDC& dc); - void doRender(wxDC& dc); - void render_extra_lib(wxDC& dc); - void render_generic_lib(wxDC& dc); -}; - -/************************************************* -Description:AMSRoad -**************************************************/ -class AMSRoad : public wxWindow -{ -public: - AMSRoad(); - AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - void create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - -public: - AMSinfo m_amsinfo; - Caninfo m_info; - int m_canindex = {0}; - AMSRoadMode m_rode_mode = {AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT}; - std::vector m_pass_rode_mode = {AMSPassRoadMode::AMS_ROAD_MODE_NONE}; - bool m_selected = {false}; - int m_passroad_width = {6}; - double m_radius = {4}; - wxColour m_road_def_color; - wxColour m_road_color; - void Update(AMSinfo amsinfo, Caninfo info, int canindex, int maxcan); - - std::vector ams_humidity_img; - - - int m_humidity = { 0 }; - bool m_show_humidity = { false }; - bool m_vams_loading{false}; - AMSModel m_ams_model; - - void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); - void SetPassRoadColour(wxColour col); - void SetMode(AMSRoadMode mode); - void OnPassRoad(std::vector prord_list); - void UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step); - - void paintEvent(wxPaintEvent &evt); - void render(wxDC &dc); - void doRender(wxDC &dc); -}; - -/************************************************* -Description:AMSItem -**************************************************/ - -class AMSItem : public wxWindow -{ -public: - AMSItem(); - AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size = wxSize(14, 14), const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - - bool m_open = {false}; - void Open(); - void Close(); - - void Update(AMSinfo amsinfo); - void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); - void OnEnterWindow(wxMouseEvent &evt); - void OnLeaveWindow(wxMouseEvent &evt); - void OnSelected(); - void UnSelected(); - virtual bool Enable(bool enable = true); - - AMSinfo m_amsinfo; - -protected: - wxSize m_cube_size; - wxColour m_background_colour = {AMS_CONTROL_DEF_BLOCK_BK_COLOUR}; - int m_padding = {7}; - int m_space = {5}; - bool m_hover = {false}; - bool m_selected = {false}; - ScalableBitmap* m_ts_bitmap_cube; - - void paintEvent(wxPaintEvent &evt); - void render(wxDC &dc); - void doRender(wxDC &dc); - virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); -}; - -/************************************************* -Description:AmsCans -**************************************************/ -class Canrefreshs -{ -public: - wxString canID; - AMSrefresh *canrefresh; -}; - -class CanLibs -{ -public: - wxString canID; - AMSLib * canLib; -}; - -class CanRoads -{ -public: - wxString canID; - AMSRoad *canRoad; -}; - -WX_DEFINE_ARRAY(Canrefreshs *, CanrefreshsHash); -WX_DEFINE_ARRAY(CanLibs *, CanLibsHash); -WX_DEFINE_ARRAY(CanRoads *, CansRoadsHash); - -class AmsCans : public wxWindow -{ -public: - AmsCans(); - AmsCans(wxWindow *parent, AMSinfo info, AMSModel model); - - void Update(AMSinfo info); - void create(wxWindow *parent); - void AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer); - void SetDefSelectCan(); - void SelectCan(std::string canid); - void PlayRridLoading(wxString canid); - void StopRridLoading(wxString canid); - void msw_rescale(); - void show_sn_value(bool show); - void SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step); - void SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step); - void SetAmsStep(std::string can_id); - void paintEvent(wxPaintEvent& evt); - void render(wxDC& dc); - void doRender(wxDC& dc); - wxColour GetTagColr(wxString canid); - std::string GetCurrentCan(); - -public: - ScalableBitmap m_bitmap_extra_framework; - int m_canlib_selection = { -1 }; - int m_selection = { 0 }; - int m_can_count = { 0 }; - AMSModel m_ams_model; - std::string m_canlib_id; - - std::string m_road_canid; - wxColour m_road_colour; - - CanLibsHash m_can_lib_list; - CansRoadsHash m_can_road_list; - CanrefreshsHash m_can_refresh_list; - AMSinfo m_info; - wxBoxSizer * sizer_can = {nullptr}; - wxBoxSizer * sizer_can_middle = {nullptr}; - wxBoxSizer * sizer_can_left = {nullptr}; - wxBoxSizer * sizer_can_right = {nullptr}; - AMSPassRoadSTEP m_step = {AMSPassRoadSTEP ::AMS_ROAD_STEP_NONE}; -}; - -/************************************************* -Description:AMSControl -**************************************************/ -class AmsCansWindow -{ -public: - wxString amsIndex; - AmsCans *amsCans; - bool m_disable_mode{ false }; - - void set_disable_mode(bool disable) { - m_disable_mode = disable; - for (auto can_lib : amsCans->m_can_lib_list) { - can_lib->canLib->set_disable_mode(disable); - } - for (auto can_refresh : amsCans->m_can_refresh_list) { - can_refresh->canrefresh->set_disable_mode(disable); - } - } -}; - -class AmsItems -{ -public: - wxString amsIndex; - AMSItem *amsItem; -}; - -class AMSextruders -{ -public: - wxString amsIndex; - AMSextruder *amsextruder; -}; - -WX_DEFINE_ARRAY(AmsCansWindow *, AmsCansHash); -WX_DEFINE_ARRAY(AmsItems *, AmsItemsHash); -WX_DEFINE_ARRAY(AMSextruders *, AMSextrudersHash); - class AMSControl : public wxSimplebook { public: @@ -696,26 +159,9 @@ class AMSControl : public wxSimplebook virtual bool Enable(bool enable = true); public: - std::string m_current_senect; + std::string m_current_select; }; -wxDECLARE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_LOAD, SimpleEvent); -wxDECLARE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); -wxDECLARE_EVENT(EVT_AMS_SETTINGS, SimpleEvent); -wxDECLARE_EVENT(EVT_AMS_FILAMENT_BACKUP, SimpleEvent); -wxDECLARE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent); -wxDECLARE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_GUIDE_WIKI, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_RETRY, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_SHOW_HUMIDITY_TIPS, wxCommandEvent); -wxDECLARE_EVENT(EVT_AMS_UNSELETED_VAMS, wxCommandEvent); -wxDECLARE_EVENT(EVT_CLEAR_SPEED_CONTROL, wxCommandEvent); - }} // namespace Slic3r::GUI #endif // !slic3r_GUI_amscontrol_hpp_ diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp new file mode 100644 index 00000000000..64a3aa432a3 --- /dev/null +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -0,0 +1,2385 @@ +#include "AMSItem.hpp" +#include "Label.hpp" +#include "../BitmapCache.hpp" +#include "../I18N.hpp" +#include "../GUI_App.hpp" +#include "../Utils/WxFontUtils.hpp" + +#include +#include + +#include + +#include "CalibUtils.hpp" + + + +namespace Slic3r { namespace GUI { + +static const wxColour AMS_TRAY_DEFAULT_COL = wxColour(255, 255, 255); + +wxDEFINE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_LOAD, SimpleEvent); +wxDEFINE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); +wxDEFINE_EVENT(EVT_AMS_SETTINGS, SimpleEvent); +wxDEFINE_EVENT(EVT_AMS_FILAMENT_BACKUP, SimpleEvent); +wxDEFINE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent); +wxDEFINE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_GUIDE_WIKI, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_RETRY, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_SHOW_HUMIDITY_TIPS, wxCommandEvent); +wxDEFINE_EVENT(EVT_AMS_UNSELETED_VAMS, wxCommandEvent); +wxDEFINE_EVENT(EVT_CLEAR_SPEED_CONTROL, wxCommandEvent); + + +bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, bool humidity_flag) +{ + if (!ams) return false; + this->ams_id = ams->id; + + if (humidity_flag) { + this->ams_humidity = ams->humidity; + } + else { + this->ams_humidity = -1; + } + + cans.clear(); + for (int i = 0; i < 4; i++) { + auto it = ams->trayList.find(std::to_string(i)); + Caninfo info; + // tray is exists + if (it != ams->trayList.end() && it->second->is_exists) { + if (it->second->is_tray_info_ready()) { + info.can_id = it->second->id; + info.ctype = it->second->ctype; + info.material_name = it->second->get_display_filament_type(); + if (!it->second->color.empty()) { + info.material_colour = AmsTray::decode_color(it->second->color); + } else { + // set to white by default + info.material_colour = AMS_TRAY_DEFAULT_COL; + } + + for (std::string cols:it->second->cols) { + info.material_cols.push_back(AmsTray::decode_color(cols)); + } + + if (MachineObject::is_bbl_filament(it->second->tag_uid)) { + info.material_state = AMSCanType::AMS_CAN_TYPE_BRAND; + } else { + info.material_state = AMSCanType::AMS_CAN_TYPE_THIRDBRAND; + } + + if (!MachineObject::is_bbl_filament(it->second->tag_uid) || !remain_flag) { + info.material_remain = 100; + } else { + info.material_remain = it->second->remain < 0 ? 0 : it->second->remain; + info.material_remain = it->second->remain > 100 ? 100 : info.material_remain; + } + + + } else { + info.can_id = it->second->id; + info.material_name = ""; + info.ctype = 0; + info.material_colour = AMS_TRAY_DEFAULT_COL; + info.material_state = AMSCanType::AMS_CAN_TYPE_THIRDBRAND; + wxColour(255, 255, 255); + } + + if (it->second->is_tray_info_ready() && obj->cali_version >= 0) { + CalibUtils::get_pa_k_n_value_by_cali_idx(obj, it->second->cali_idx, info.k, info.n); + } + else { + info.k = it->second->k; + info.n = it->second->n; + } + } else { + info.can_id = i; + info.material_state = AMSCanType::AMS_CAN_TYPE_EMPTY; + } + cans.push_back(info); + } + return true; +} + +/************************************************* +Description:AMSrefresh +**************************************************/ + +AMSrefresh::AMSrefresh() { SetFont(Label::Body_10);} + +AMSrefresh::AMSrefresh(wxWindow *parent, wxString number, Caninfo info, const wxPoint &pos, const wxSize &size) : AMSrefresh() +{ + m_info = info; + m_can_id = number.ToStdString(); + create(parent, wxID_ANY, pos, size); +} + +AMSrefresh::AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint &pos, const wxSize &size) : AMSrefresh() +{ + m_info = info; + m_can_id = wxString::Format("%d", number).ToStdString(); + create(parent, wxID_ANY, pos, size); +} + + AMSrefresh::~AMSrefresh() + { + if (m_playing_timer) { + m_playing_timer->Stop(); + delete m_playing_timer; + m_playing_timer = nullptr; + } + } + +void AMSrefresh::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +{ + wxWindow::Create(parent, id, pos, size, wxBORDER_NONE); + SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + + Bind(wxEVT_TIMER, &AMSrefresh::on_timer, this); + Bind(wxEVT_PAINT, &AMSrefresh::paintEvent, this); + Bind(wxEVT_ENTER_WINDOW, &AMSrefresh::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &AMSrefresh::OnLeaveWindow, this); + Bind(wxEVT_LEFT_DOWN, &AMSrefresh::OnClick, this); + + m_bitmap_normal = ScalableBitmap(this, "ams_refresh_normal", 30); + m_bitmap_selected = ScalableBitmap(this, "ams_refresh_selected", 30); + + m_bitmap_ams_rfid_0 = ScalableBitmap(this, "ams_rfid_0", 30); + m_bitmap_ams_rfid_1 = ScalableBitmap(this, "ams_rfid_1", 30); + m_bitmap_ams_rfid_2 = ScalableBitmap(this, "ams_rfid_2", 30); + m_bitmap_ams_rfid_3 = ScalableBitmap(this, "ams_rfid_3", 30); + m_bitmap_ams_rfid_4 = ScalableBitmap(this, "ams_rfid_4", 30); + m_bitmap_ams_rfid_5 = ScalableBitmap(this, "ams_rfid_5", 30); + m_bitmap_ams_rfid_6 = ScalableBitmap(this, "ams_rfid_6", 30); + m_bitmap_ams_rfid_7 = ScalableBitmap(this, "ams_rfid_7", 30); + + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_0); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_1); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_2); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_3); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_4); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_5); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_6); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_7); + + m_playing_timer = new wxTimer(); + m_playing_timer->SetOwner(this); + wxPostEvent(this, wxTimerEvent()); + + SetSize(AMS_REFRESH_SIZE); + SetMinSize(AMS_REFRESH_SIZE); + SetMaxSize(AMS_REFRESH_SIZE); +} + +void AMSrefresh::on_timer(wxTimerEvent &event) +{ + //if (m_rotation_angle >= m_rfid_bitmap_list.size()) { + // m_rotation_angle = 0; + //} else { + // m_rotation_angle++; + //} + Refresh(); +} + +void AMSrefresh::PlayLoading() +{ + if (m_play_loading | m_disable_mode) return; + m_play_loading = true; + //m_rotation_angle = 0; + m_playing_timer->Start(AMS_REFRESH_PLAY_LOADING_TIMER); + Refresh(); +} + +void AMSrefresh::StopLoading() +{ + if (!m_play_loading | m_disable_mode) return; + m_playing_timer->Stop(); + m_play_loading = false; + Refresh(); +} + +void AMSrefresh::OnEnterWindow(wxMouseEvent &evt) +{ + m_selected = true; + Refresh(); +} + +void AMSrefresh::OnLeaveWindow(wxMouseEvent &evt) +{ + m_selected = false; + Refresh(); +} + +void AMSrefresh::OnClick(wxMouseEvent &evt) { + post_event(wxCommandEvent(EVT_AMS_REFRESH_RFID)); +} + +void AMSrefresh::post_event(wxCommandEvent &&event) +{ + if (m_disable_mode) + return; + event.SetString(m_info.can_id); + event.SetEventObject(m_parent); + wxPostEvent(m_parent, event); + event.Skip(); +} + +void AMSrefresh::paintEvent(wxPaintEvent &evt) +{ + wxSize size = GetSize(); + wxPaintDC dc(this); + + auto colour = StateColor::darkModeColorFor(AMS_CONTROL_GRAY700); + if (!wxWindow::IsEnabled()) { colour = AMS_CONTROL_GRAY500; } + + auto pot = wxPoint((size.x - m_bitmap_selected.GetBmpSize().x) / 2, (size.y - m_bitmap_selected.GetBmpSize().y) / 2); + + if (!m_disable_mode) { + if (!m_play_loading) { + dc.DrawBitmap(m_selected ? m_bitmap_selected.bmp() : m_bitmap_normal.bmp(), pot); + } + else { + /* m_bitmap_rotation = ScalableBitmap(this, "ams_refresh_normal", 30); + auto image = m_bitmap_rotation.bmp().ConvertToImage(); + wxPoint offset; + auto loading_img = image.Rotate(m_rotation_angle, wxPoint(image.GetWidth() / 2, image.GetHeight() / 2), true, &offset); + ScalableBitmap loading_bitmap; + loading_bitmap.bmp() = wxBitmap(loading_img); + dc.DrawBitmap(loading_bitmap.bmp(), offset.x , offset.y);*/ + m_rotation_angle++; + if (m_rotation_angle >= m_rfid_bitmap_list.size()) { + m_rotation_angle = 0; + } + if (m_rfid_bitmap_list.size() <= 0)return; + dc.DrawBitmap(m_rfid_bitmap_list[m_rotation_angle].bmp(), pot); + } + } + + dc.SetPen(wxPen(colour)); + dc.SetBrush(wxBrush(colour)); + dc.SetFont(Label::Body_11); + dc.SetTextForeground(colour); + auto tsize = dc.GetTextExtent(m_refresh_id); + pot = wxPoint((size.x - tsize.x) / 2, (size.y - tsize.y) / 2); + dc.DrawText(m_refresh_id, pot); +} + +void AMSrefresh::Update(std::string ams_id, Caninfo info) +{ + m_ams_id = ams_id; + m_info = info; + + if (!m_ams_id.empty() && !m_can_id.empty()) { + auto aid = atoi(m_ams_id.c_str()); + auto tid = atoi(m_can_id.c_str()); + auto tray_id = aid * 4 + tid; + m_refresh_id = wxGetApp().transition_tridid(tray_id); + } + StopLoading(); +} + +void AMSrefresh::msw_rescale() { + m_bitmap_normal = ScalableBitmap(this, "ams_refresh_normal", 30); + m_bitmap_selected = ScalableBitmap(this, "ams_refresh_selected", 30); + m_bitmap_ams_rfid_0 = ScalableBitmap(this, "ams_rfid_0", 30); + m_bitmap_ams_rfid_1 = ScalableBitmap(this, "ams_rfid_1", 30); + m_bitmap_ams_rfid_2 = ScalableBitmap(this, "ams_rfid_2", 30); + m_bitmap_ams_rfid_3 = ScalableBitmap(this, "ams_rfid_3", 30); + m_bitmap_ams_rfid_4 = ScalableBitmap(this, "ams_rfid_4", 30); + m_bitmap_ams_rfid_5 = ScalableBitmap(this, "ams_rfid_5", 30); + m_bitmap_ams_rfid_6 = ScalableBitmap(this, "ams_rfid_6", 30); + m_bitmap_ams_rfid_7 = ScalableBitmap(this, "ams_rfid_7", 30); + + m_rfid_bitmap_list.clear(); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_0); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_1); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_2); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_3); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_4); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_5); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_6); + m_rfid_bitmap_list.push_back(m_bitmap_ams_rfid_7); +} + +void AMSrefresh::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + wxWindow::DoSetSize(x, y, width, height, sizeFlags); +} + +/************************************************* +Description:AMSextruder +**************************************************/ +void AMSextruderImage::TurnOn(wxColour col) +{ + m_colour = col; + Refresh(); +} + +void AMSextruderImage::TurnOff() +{ + m_colour = AMS_EXTRUDER_DEF_COLOUR; + Refresh(); +} + +void AMSextruderImage::msw_rescale() +{ + //m_ams_extruder.SetSize(AMS_EXTRUDER_BITMAP_SIZE); + //auto image = m_ams_extruder.ConvertToImage(); + m_ams_extruder = ScalableBitmap(this, "monitor_ams_extruder", 55); + Refresh(); +} + +void AMSextruderImage::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSextruderImage::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AMSextruderImage::doRender(wxDC &dc) +{ + auto size = GetSize(); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(m_colour); + dc.DrawRectangle(0, FromDIP(18), size.x, size.y - FromDIP(18) - FromDIP(5)); + dc.DrawBitmap(m_ams_extruder.bmp(), wxPoint((size.x - m_ams_extruder.GetBmpSize().x) / 2, (size.y - m_ams_extruder.GetBmpSize().y) / 2)); +} + + +AMSextruderImage::AMSextruderImage(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +{ + wxWindow::Create(parent, id, pos, AMS_EXTRUDER_BITMAP_SIZE); + SetBackgroundColour(*wxWHITE); + + m_ams_extruder = ScalableBitmap(this, "monitor_ams_extruder",55); + SetSize(AMS_EXTRUDER_BITMAP_SIZE); + SetMinSize(AMS_EXTRUDER_BITMAP_SIZE); + SetMaxSize(AMS_EXTRUDER_BITMAP_SIZE); + + + Bind(wxEVT_PAINT, &AMSextruderImage::paintEvent, this); +} + +AMSextruderImage::~AMSextruderImage() {} + + + +AMSextruder::AMSextruder(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { create(parent, id, pos, size); } + + AMSextruder::~AMSextruder() {} + +void AMSextruder::TurnOn(wxColour col) +{ + m_amsSextruder->TurnOn(col); +} + +void AMSextruder::TurnOff() +{ + m_amsSextruder->TurnOff(); +} + +void AMSextruder::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +{ + wxWindow::Create(parent, id, pos, AMS_EXTRUDER_SIZE, wxBORDER_NONE); + SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + + wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL); + + m_bitmap_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, AMS_EXTRUDER_BITMAP_SIZE, wxTAB_TRAVERSAL); + m_bitmap_panel->SetBackgroundColour(AMS_EXTRUDER_DEF_COLOUR); + m_bitmap_panel->SetDoubleBuffered(true); + m_bitmap_sizer = new wxBoxSizer(wxHORIZONTAL); + + m_amsSextruder = new AMSextruderImage(m_bitmap_panel, wxID_ANY, wxDefaultPosition, AMS_EXTRUDER_BITMAP_SIZE); + m_bitmap_sizer->Add(m_amsSextruder, 0, wxALIGN_CENTER, 0); + + m_bitmap_panel->SetSizer(m_bitmap_sizer); + m_bitmap_panel->Layout(); + m_sizer_body->Add( 0, 0, 1, wxEXPAND, 0 ); + m_sizer_body->Add(m_bitmap_panel, 0, wxALIGN_CENTER, 0); + + SetSizer(m_sizer_body); + + Bind(wxEVT_PAINT, &AMSextruder::paintEvent, this); + Layout(); +} + +void AMSextruder::OnVamsLoading(bool load, wxColour col) +{ + m_vams_loading = load; + if (load)m_current_colur = col; + Refresh(); +} + +void AMSextruder::OnAmsLoading(bool load, wxColour col /*= AMS_CONTROL_GRAY500*/) +{ + m_ams_loading = load; + if (load)m_current_colur = col; + Refresh(); +} + +void AMSextruder::paintEvent(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSextruder::render(wxDC& dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif + +} + +void AMSextruder::doRender(wxDC& dc) +{ + //m_current_colur = + wxSize size = GetSize(); + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + + if (!m_none_ams_mode) { + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + } + + if (m_has_vams) { + dc.DrawRoundedRectangle(-size.x / 2, size.y * 0.1, size.x, size.y, 4); + + if (m_vams_loading) { + + if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID)); } + else { dc.SetPen(wxPen(m_current_colur, 6, wxPENSTYLE_SOLID)); } + dc.DrawRoundedRectangle(-size.x / 2, size.y * 0.1, size.x, size.y, 4); + + if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { + dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); + dc.DrawRoundedRectangle(-size.x / 2 - FromDIP(3), size.y * 0.1 + FromDIP(3), size.x, size.y, 3); + dc.DrawRoundedRectangle(-size.x / 2 + FromDIP(3), size.y * 0.1 - FromDIP(3), size.x, size.y, 5); + } + } + + if (m_ams_loading && !m_none_ams_mode) { + if (m_current_colur.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID));} + else {dc.SetPen(wxPen(m_current_colur, 6, wxPENSTYLE_SOLID));} + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + + if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { + dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); + dc.DrawLine(size.x / 2 - FromDIP(4), -1, size.x / 2 - FromDIP(3), size.y * 0.6 - 1); + dc.DrawLine(size.x / 2 + FromDIP(3), -1, size.x / 2 + FromDIP(3), size.y * 0.6 - 1); + } + } + } + else { + if (m_ams_loading) { + if (m_current_colur.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID)); } + else { dc.SetPen(wxPen(m_current_colur, 6, wxPENSTYLE_SOLID)); } + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + + if ((m_current_colur == *wxWHITE || m_current_colur.Alpha() == 0) && !wxGetApp().dark_mode()) { + dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); + dc.DrawLine(size.x / 2 - FromDIP(4), -1, size.x / 2 - FromDIP(3), size.y * 0.6 - 1); + dc.DrawLine(size.x / 2 + FromDIP(3), -1, size.x / 2 + FromDIP(3), size.y * 0.6 - 1); + } + } + } + +} + +void AMSextruder::msw_rescale() +{ + m_amsSextruder->msw_rescale(); + Layout(); + Update(); + Refresh(); +} + +/************************************************* +Description:AMSVirtualRoad +**************************************************/ + +AMSVirtualRoad::AMSVirtualRoad(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) { create(parent, id, pos, size); } + +AMSVirtualRoad::~AMSVirtualRoad() {} + +void AMSVirtualRoad::OnVamsLoading(bool load, wxColour col) +{ + m_vams_loading = load; + if (load)m_current_color = col; + Refresh(); +} + +void AMSVirtualRoad::create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) +{ + wxWindow::Create(parent, id, pos, wxDefaultSize, wxBORDER_NONE); + SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + Layout(); + Bind(wxEVT_PAINT, &AMSVirtualRoad::paintEvent, this); +} + +void AMSVirtualRoad::paintEvent(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSVirtualRoad::render(wxDC& dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AMSVirtualRoad::doRender(wxDC& dc) +{ + if (!m_has_vams) return; + + wxSize size = GetSize(); + if (m_vams_loading) { + if (m_current_color.Alpha() == 0) { dc.SetPen(wxPen(*wxWHITE, 6, wxPENSTYLE_SOLID)); } + else { dc.SetPen(wxPen(m_current_color, 6, wxPENSTYLE_SOLID)); } + } + else { + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + } + + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(size.x / 2, -size.y / 1.1 + FromDIP(1), size.x, size.y, 4); + + if ((m_current_color == *wxWHITE || m_current_color.Alpha() == 0) && !wxGetApp().dark_mode()) { + dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); + dc.DrawRoundedRectangle(size.x / 2 - FromDIP(3), -size.y / 1.1 + FromDIP(4), size.x, size.y, 5); + dc.DrawRoundedRectangle(size.x / 2 + FromDIP(3), -size.y / 1.1 - FromDIP(2), size.x, size.y, 3); + } +} + + +void AMSVirtualRoad::msw_rescale() +{ + Layout(); + Update(); + Refresh(); +} + + +/************************************************* +Description:AMSLib +**************************************************/ +AMSLib::AMSLib(wxWindow *parent, std::string ams_idx, Caninfo info) +{ + m_border_color = (wxColour(130, 130, 128)); + m_road_def_color = AMS_CONTROL_GRAY500; + wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + create(parent); + + Bind(wxEVT_PAINT, &AMSLib::paintEvent, this); + Bind(wxEVT_ENTER_WINDOW, &AMSLib::on_enter_window, this); + Bind(wxEVT_LEAVE_WINDOW, &AMSLib::on_leave_window, this); + Bind(wxEVT_LEFT_DOWN, &AMSLib::on_left_down, this); + + Update(info, ams_idx, false); +} + +AMSLib::~AMSLib() +{ +} + +void AMSLib::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +{ + wxWindow::Create(parent, id, pos, size); + + SetSize(AMS_CAN_LIB_SIZE); + SetMinSize(AMS_CAN_LIB_SIZE); + SetMaxSize(AMS_CAN_LIB_SIZE); + + auto m_sizer_body = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer *m_sizer_edit = new wxBoxSizer(wxHORIZONTAL); + + m_bitmap_editable = ScalableBitmap(this, "ams_editable", 14); + m_bitmap_editable_light = ScalableBitmap(this, "ams_editable_light", 14); + m_bitmap_readonly = ScalableBitmap(this, "ams_readonly", 14); + m_bitmap_readonly_light = ScalableBitmap(this, "ams_readonly_light", 14); + m_bitmap_transparent = ScalableBitmap(this, "transparent_ams_lib", 68); + + m_bitmap_extra_tray_left = ScalableBitmap(this, "extra_ams_tray_left", 80); + m_bitmap_extra_tray_right = ScalableBitmap(this, "extra_ams_tray_right", 80); + + m_bitmap_extra_tray_left_hover = ScalableBitmap(this, "extra_ams_tray_left_hover", 80); + m_bitmap_extra_tray_right_hover = ScalableBitmap(this, "extra_ams_tray_right_hover", 80); + + m_bitmap_extra_tray_left_selected = ScalableBitmap(this, "extra_ams_tray_left_selected", 80); + m_bitmap_extra_tray_right_selected = ScalableBitmap(this, "extra_ams_tray_right_selected", 80); + + + m_sizer_body->Add(0, 0, 1, wxEXPAND, 0); + m_sizer_body->Add(m_sizer_edit, 0, wxALIGN_CENTER, 0); + m_sizer_body->Add(0, 0, 0, wxBOTTOM, GetSize().y * 0.12); + SetSizer(m_sizer_body); + Layout(); +} + +void AMSLib::on_enter_window(wxMouseEvent &evt) +{ + m_hover = true; + Refresh(); +} + +void AMSLib::on_leave_window(wxMouseEvent &evt) +{ + m_hover = false; + Refresh(); +} + +void AMSLib::on_left_down(wxMouseEvent &evt) +{ + if (m_info.material_state != AMSCanType::AMS_CAN_TYPE_EMPTY && m_info.material_state != AMSCanType::AMS_CAN_TYPE_NONE) { + auto size = GetSize(); + auto pos = evt.GetPosition(); + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND || m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND || + m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { + + auto left = FromDIP(10); + auto right = size.x - FromDIP(10); + auto top = 0; + auto bottom = 0; + + if (m_ams_model == AMSModel::GENERIC_AMS) { + top = (size.y - FromDIP(15) - m_bitmap_editable_light.GetBmpSize().y); + bottom = size.y - FromDIP(15); + } + else if (m_ams_model == AMSModel::EXTRA_AMS) { + top = (size.y - FromDIP(20) - m_bitmap_editable_light.GetBmpSize().y); + bottom = size.y - FromDIP(20); + } + + if (pos.x >= left && pos.x <= right && pos.y >= top && top <= bottom) { + if (m_selected) { + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { + post_event(wxCommandEvent(EVT_VAMS_ON_FILAMENT_EDIT)); + } + else { + post_event(wxCommandEvent(EVT_AMS_ON_FILAMENT_EDIT)); + } + } else { + BOOST_LOG_TRIVIAL(trace) << "current amslib is not selected"; + } + } + } + } +} + + +void AMSLib::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSLib::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif + + // text + if (m_ams_model == AMSModel::GENERIC_AMS) { + render_generic_text(dc); + } + else if (m_ams_model == AMSModel::EXTRA_AMS) { + render_extra_text(dc); + } +} + +void AMSLib::render_extra_text(wxDC& dc) +{ + auto tmp_lib_colour = m_info.material_colour; + + change_the_opacity(tmp_lib_colour); + auto temp_text_colour = AMS_CONTROL_GRAY800; + + if (tmp_lib_colour.GetLuminance() < 0.6) { + temp_text_colour = AMS_CONTROL_WHITE_COLOUR; + } + else { + temp_text_colour = AMS_CONTROL_GRAY800; + } + + if (m_info.material_remain < 50) { + temp_text_colour = AMS_CONTROL_GRAY800; + } + + if (tmp_lib_colour.Alpha() == 0) { + temp_text_colour = AMS_CONTROL_GRAY800; + } + + dc.SetFont(::Label::Body_13); + dc.SetTextForeground(temp_text_colour); + + auto libsize = GetSize(); + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND + || m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND + || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { + + if (m_info.material_name.empty()) { + auto tsize = dc.GetMultiLineTextExtent("?"); + auto pot = wxPoint(0, 0); + pot = wxPoint((libsize.x - tsize.x) / 2 + FromDIP(2), (libsize.y - tsize.y) / 2 - FromDIP(5)); + dc.DrawText(L("?"), pot); + } + else { + auto tsize = dc.GetMultiLineTextExtent(m_info.material_name); + std::vector split_char_arr = { " ", "-" }; + bool has_split = false; + std::string has_split_char = " "; + + for (std::string split_char : split_char_arr) { + if (m_info.material_name.find(split_char) != std::string::npos) { + has_split = true; + has_split_char = split_char; + } + } + + + if (has_split) { + dc.SetFont(::Label::Body_10); + auto line_top = m_info.material_name.substr(0, m_info.material_name.find(has_split_char)); + auto line_bottom = m_info.material_name.substr(m_info.material_name.find(has_split_char)); + + auto line_top_tsize = dc.GetMultiLineTextExtent(line_top); + auto line_bottom_tsize = dc.GetMultiLineTextExtent(line_bottom); + + auto pot_top = wxPoint((libsize.x - line_top_tsize.x) / 2 + FromDIP(3), (libsize.y - line_top_tsize.y) / 2 - line_top_tsize.y); + dc.DrawText(line_top, pot_top); + + auto pot_bottom = wxPoint((libsize.x - line_bottom_tsize.x) / 2 + FromDIP(3), (libsize.y - line_bottom_tsize.y) / 2); + dc.DrawText(line_bottom, pot_bottom); + + + } + else { + dc.SetFont(::Label::Body_10); + auto pot = wxPoint(0, 0); + if (m_obj ) { + pot = wxPoint((libsize.x - tsize.x) / 2 + FromDIP(6), (libsize.y - tsize.y) / 2 - FromDIP(5)); + } + dc.DrawText(m_info.material_name, pot); + } + } + } + + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_EMPTY) { + auto tsize = dc.GetMultiLineTextExtent(_L("/")); + auto pot = wxPoint((libsize.x - tsize.x) / 2 + FromDIP(2), (libsize.y - tsize.y) / 2 + FromDIP(3)); + dc.DrawText(_L("/"), pot); + } +} + +void AMSLib::render_generic_text(wxDC &dc) +{ + bool show_k_value = true; + if (m_obj && (m_obj->cali_version >= 0) && (abs(m_info.k - 0) < 1e-3)) { + show_k_value = false; + } + + auto tmp_lib_colour = m_info.material_colour; + change_the_opacity(tmp_lib_colour); + + auto temp_text_colour = AMS_CONTROL_GRAY800; + + if (tmp_lib_colour.GetLuminance() < 0.6) { + temp_text_colour = AMS_CONTROL_WHITE_COLOUR; + } + else { + temp_text_colour = AMS_CONTROL_GRAY800; + } + + if (m_info.material_remain < 50) { + temp_text_colour = AMS_CONTROL_GRAY800; + } + + if (tmp_lib_colour.Alpha() == 0) { + temp_text_colour = AMS_CONTROL_GRAY800; + } + + dc.SetFont(::Label::Body_13); + dc.SetTextForeground(temp_text_colour); + auto alpha = m_info.material_colour.Alpha(); + if (alpha != 0 && alpha != 255 && alpha != 254) { + dc.SetTextForeground(*wxBLACK); + } + + auto libsize = GetSize(); + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND + || m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND + || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) { + + if (m_info.material_name.empty() /*&& m_info.material_state != AMSCanType::AMS_CAN_TYPE_VIRTUAL*/) { + auto tsize = dc.GetMultiLineTextExtent("?"); + auto pot = wxPoint(0, 0); + + if (m_obj && show_k_value) { + pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9)); + } + else { + pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); + } + dc.DrawText(L("?"), pot); + + } + else { + auto tsize = dc.GetMultiLineTextExtent(m_info.material_name); + std::vector split_char_arr = { " ", "-" }; + bool has_split = false; + std::string has_split_char = " "; + + for (std::string split_char : split_char_arr) { + if (m_info.material_name.find(split_char) != std::string::npos) { + has_split = true; + has_split_char = split_char; + } + } + + + if (has_split) { + dc.SetFont(::Label::Body_12); + + auto line_top = m_info.material_name.substr(0, m_info.material_name.find(has_split_char)); + auto line_bottom = m_info.material_name.substr(m_info.material_name.find(has_split_char)); + + auto line_top_tsize = dc.GetMultiLineTextExtent(line_top); + auto line_bottom_tsize = dc.GetMultiLineTextExtent(line_bottom); + + if (!m_show_kn) { + auto pot_top = wxPoint((libsize.x - line_top_tsize.x) / 2, (libsize.y - line_top_tsize.y) / 2 - line_top_tsize.y + FromDIP(6)); + dc.DrawText(line_top, pot_top); + + + auto pot_bottom = wxPoint((libsize.x - line_bottom_tsize.x) / 2, (libsize.y - line_bottom_tsize.y) / 2 + FromDIP(4)); + dc.DrawText(line_bottom, pot_bottom); + } + else { + auto pot_top = wxPoint((libsize.x - line_top_tsize.x) / 2, (libsize.y - line_top_tsize.y) / 2 - line_top_tsize.y - FromDIP(6)); + dc.DrawText(line_top, pot_top); + + auto pot_bottom = wxPoint((libsize.x - line_bottom_tsize.x) / 2, (libsize.y - line_bottom_tsize.y) / 2 - FromDIP(8)); + dc.DrawText(line_bottom, pot_bottom); + } + + + } + else { + auto pot = wxPoint(0, 0); + if (m_obj && show_k_value) { + pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9)); + } else { + pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); + } + dc.DrawText(m_info.material_name, pot); + } + } + + //draw k&n + if (m_obj && show_k_value) { + if (m_show_kn) { + wxString str_k = wxString::Format("K %1.3f", m_info.k); + wxString str_n = wxString::Format("N %1.3f", m_info.n); + dc.SetFont(::Label::Body_11); + auto tsize = dc.GetMultiLineTextExtent(str_k); + auto pot_k = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 - FromDIP(9) + tsize.y); + dc.DrawText(str_k, pot_k); + } + } + } + + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_EMPTY) { + auto tsize = dc.GetMultiLineTextExtent(_L("Empty")); + auto pot = wxPoint((libsize.x - tsize.x) / 2, (libsize.y - tsize.y) / 2 + FromDIP(3)); + dc.DrawText(_L("Empty"), pot); + } +} + +void AMSLib::doRender(wxDC &dc) +{ + if (m_ams_model == AMSModel::GENERIC_AMS) { + render_generic_lib(dc); + } + else if (m_ams_model == AMSModel::EXTRA_AMS) { + render_extra_lib(dc); + } +} + +void AMSLib::render_extra_lib(wxDC& dc) +{ + wxSize size = GetSize(); + + ScalableBitmap tray_bitmap = m_can_index <= 1 ? m_bitmap_extra_tray_left : m_bitmap_extra_tray_right; + ScalableBitmap tray_bitmap_hover = m_can_index <= 1 ? m_bitmap_extra_tray_left_hover : m_bitmap_extra_tray_right_hover; + ScalableBitmap tray_bitmap_selected = m_can_index <= 1 ? m_bitmap_extra_tray_left_selected : m_bitmap_extra_tray_right_selected; + + + auto tmp_lib_colour = m_info.material_colour; + change_the_opacity(tmp_lib_colour); + + auto temp_bitmap_third = m_bitmap_editable_light; + auto temp_bitmap_brand = m_bitmap_readonly_light; + + //draw road + + + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + + if (m_pass_road) { + dc.SetPen(wxPen(m_info.material_colour, 6, wxPENSTYLE_SOLID)); + } + + if (m_can_index == 0 || m_can_index == 3) { + dc.DrawLine(size.x / 2, size.y / 2, size.x / 2, size.y); + } + else { + dc.DrawLine(size.x / 2, size.y / 2, size.x / 2, 0); + } + + + //draw def background + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(AMS_CONTROL_DEF_LIB_BK_COLOUR)); + dc.DrawRoundedRectangle(FromDIP(10), FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20), 0); + + if (tmp_lib_colour.GetLuminance() < 0.6) { + temp_bitmap_third = m_bitmap_editable_light; + temp_bitmap_brand = m_bitmap_readonly_light; + } + else { + temp_bitmap_third = m_bitmap_editable; + temp_bitmap_brand = m_bitmap_readonly; + } + + if (m_info.material_remain < 50) { + temp_bitmap_third = m_bitmap_editable; + temp_bitmap_brand = m_bitmap_readonly; + } + + if (tmp_lib_colour.Alpha() == 0) { + temp_bitmap_third = m_bitmap_editable; + temp_bitmap_brand = m_bitmap_readonly; + } + + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + if (m_info.material_cols.size() > 1) { + int left = FromDIP(10); + int gwidth = std::round(size.x / (m_info.material_cols.size() - 1)); + //gradient + if (m_info.ctype == 0) { + for (int i = 0; i < m_info.material_cols.size() - 1; i++) { + auto rect = wxRect(left, FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20)); + dc.GradientFillLinear(rect, m_info.material_cols[i], m_info.material_cols[i + 1], wxEAST); + left += gwidth; + } + } + else { + int cols_size = m_info.material_cols.size(); + for (int i = 0; i < cols_size; i++) { + dc.SetBrush(wxBrush(m_info.material_cols[i])); + float x = FromDIP(10) + ((float)size.x - FromDIP(20)) * i / cols_size; + dc.DrawRoundedRectangle(x, FromDIP(10), ((float)size.x - FromDIP(20)) / cols_size, size.y - FromDIP(20), 0); + } + dc.SetBrush(wxBrush(tmp_lib_colour)); + } + } + else { + dc.SetBrush(wxBrush(tmp_lib_colour)); + dc.DrawRoundedRectangle(FromDIP(10), FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20), 0); + } + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(tmp_lib_colour)); + if (!m_disable_mode) { + // edit icon + if (m_info.material_state != AMSCanType::AMS_CAN_TYPE_EMPTY && m_info.material_state != AMSCanType::AMS_CAN_TYPE_NONE) + { + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) + dc.DrawBitmap(temp_bitmap_third.bmp(), (size.x - temp_bitmap_third.GetBmpSize().x) / 2 + FromDIP(2), (size.y - FromDIP(18) - temp_bitmap_third.GetBmpSize().y)); + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND) + dc.DrawBitmap(temp_bitmap_brand.bmp(), (size.x - temp_bitmap_brand.GetBmpSize().x) / 2 + FromDIP(2), (size.y - FromDIP(18) - temp_bitmap_brand.GetBmpSize().y)); + } + } + + // selected & hover + if (m_selected) { + dc.DrawBitmap(tray_bitmap_selected.bmp(), (size.x - tray_bitmap_selected.GetBmpSize().x) / 2, (size.y - tray_bitmap_selected.GetBmpSize().y) / 2); + } + else if (!m_selected && m_hover) { + dc.DrawBitmap(tray_bitmap_hover.bmp(), (size.x - tray_bitmap_hover.GetBmpSize().x) / 2, (size.y - tray_bitmap_hover.GetBmpSize().y) / 2); + } + else { + dc.DrawBitmap(tray_bitmap.bmp(), (size.x - tray_bitmap.GetBmpSize().x) / 2, (size.y - tray_bitmap.GetBmpSize().y) / 2); + } +} + + +void AMSLib::render_generic_lib(wxDC &dc) +{ + wxSize size = GetSize(); + auto tmp_lib_colour = m_info.material_colour; + change_the_opacity(tmp_lib_colour); + + auto temp_bitmap_third = m_bitmap_editable_light; + auto temp_bitmap_brand = m_bitmap_readonly_light; + + //draw def background + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(AMS_CONTROL_DEF_LIB_BK_COLOUR)); + dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4), size.x - FromDIP(8), size.y - FromDIP(8), m_radius); + + if (tmp_lib_colour.GetLuminance() < 0.6) { + temp_bitmap_third = m_bitmap_editable_light; + temp_bitmap_brand = m_bitmap_readonly_light; + } + else { + temp_bitmap_third = m_bitmap_editable; + temp_bitmap_brand = m_bitmap_readonly; + } + + if (m_info.material_remain < 50) { + temp_bitmap_third = m_bitmap_editable; + temp_bitmap_brand = m_bitmap_readonly; + } + + if (tmp_lib_colour.Alpha() == 0) { + temp_bitmap_third = m_bitmap_editable; + temp_bitmap_brand = m_bitmap_readonly; + } + + // selected + if (m_selected) { + dc.SetPen(wxPen(tmp_lib_colour, 2, wxPENSTYLE_SOLID)); + if (tmp_lib_colour.Alpha() == 0) { + dc.SetPen(wxPen(wxColour(tmp_lib_colour.Red(), tmp_lib_colour.Green(),tmp_lib_colour.Blue(),128), 2, wxPENSTYLE_SOLID)); + } + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + if (m_radius == 0) { + dc.DrawRectangle(0, 0, size.x, size.y); + } + else { + dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), m_radius); + } + + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(tmp_lib_colour)); + } + + if (!m_selected && m_hover) { + dc.SetPen(wxPen(AMS_CONTROL_BRAND_COLOUR, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + if (m_radius == 0) { + dc.DrawRectangle(0, 0, size.x, size.y); + } + else { + dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), m_radius); + } + + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(tmp_lib_colour)); + } + else { + dc.SetPen(wxPen(tmp_lib_colour, 1, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(tmp_lib_colour)); + } + + //draw remain + auto alpha = m_info.material_colour.Alpha(); + int height = size.y - FromDIP(8); + int curr_height = height * float(m_info.material_remain * 1.0 / 100.0); + dc.SetFont(::Label::Body_13); + + int top = height - curr_height; + + if (curr_height >= FromDIP(6)) { + + //transparent + + if (alpha == 0) { + dc.DrawBitmap(m_bitmap_transparent.bmp(), FromDIP(4), FromDIP(4)); + } + else if (alpha != 255 && alpha != 254) { + if (transparent_changed) { + std::string rgb = (tmp_lib_colour.GetAsString(wxC2S_HTML_SYNTAX)).ToStdString(); + if (rgb.size() == 9) { + //delete alpha value + rgb = rgb.substr(0, rgb.size() - 2); + } + float alpha_f = 0.7 * tmp_lib_colour.Alpha() / 255.0; + std::vector replace; + replace.push_back(rgb); + std::string fill_replace = "fill-opacity=\"" + std::to_string(alpha_f); + replace.push_back(fill_replace); + m_bitmap_transparent = ScalableBitmap(this, "transparent_ams_lib", 68, false, false, true, replace); + transparent_changed = false; + + } + dc.DrawBitmap(m_bitmap_transparent.bmp(), FromDIP(4), FromDIP(4)); + } + //gradient + if (m_info.material_cols.size() > 1) { + int left = FromDIP(4); + float total_width = size.x - FromDIP(8); + int gwidth = std::round(total_width / (m_info.material_cols.size() - 1)); + //gradient + if (m_info.ctype == 0) { + for (int i = 0; i < m_info.material_cols.size() - 1; i++) { + + if ((left + gwidth) > (size.x - FromDIP(8))) { + gwidth = (size.x - FromDIP(4)) - left; + } + + auto rect = wxRect(left, height - curr_height + FromDIP(4), gwidth, curr_height); + dc.GradientFillLinear(rect, m_info.material_cols[i], m_info.material_cols[i + 1], wxEAST); + left += gwidth; + } + } + else { + //multicolour + gwidth = std::round(total_width / m_info.material_cols.size()); + for (int i = 0; i < m_info.material_cols.size(); i++) { + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(m_info.material_cols[i])); + if (i == 0 || i == m_info.material_cols.size() - 1) { +#ifdef __APPLE__ + dc.DrawRoundedRectangle(left + gwidth * i, height - curr_height + FromDIP(4), gwidth, curr_height, m_radius); +#else + dc.DrawRoundedRectangle(left + gwidth * i, height - curr_height + FromDIP(4), gwidth, curr_height, m_radius - 1); +#endif + //add rectangle + int dr_gwidth = std::round(gwidth * 0.6); + if (i == 0) { + dc.DrawRectangle(left + gwidth - dr_gwidth, height - curr_height + FromDIP(4), dr_gwidth, curr_height); + } + else { + dc.DrawRectangle(left + gwidth*i, height - curr_height + FromDIP(4), dr_gwidth, curr_height); + } + } + else { + dc.DrawRectangle(left + gwidth * i, height - curr_height + FromDIP(4), gwidth, curr_height); + } + } + //reset pen and brush + if (m_selected || m_hover) { + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(tmp_lib_colour)); + } + else { + dc.SetPen(wxPen(tmp_lib_colour, 1, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(tmp_lib_colour)); + } + } + } + else { + auto brush = dc.GetBrush(); + if (alpha != 0 && alpha != 255 && alpha != 254) dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); +#ifdef __APPLE__ + dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(8), curr_height, m_radius); +#else + dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(8), curr_height, m_radius - 1); +#endif + dc.SetBrush(brush); + } + } + + if (top > 2) { + if (curr_height >= FromDIP(6)) { + dc.DrawRectangle(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(8), FromDIP(2)); + if (alpha != 255 && alpha != 254) { + dc.SetPen(wxPen(*wxWHITE)); + dc.SetBrush(wxBrush(*wxWHITE)); +#ifdef __APPLE__ + dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) , size.x - FromDIP(8), top, m_radius); +#else + dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4) , size.x - FromDIP(8), top, m_radius - 1); +#endif + } + if (tmp_lib_colour.Red() > 238 && tmp_lib_colour.Green() > 238 && tmp_lib_colour.Blue() > 238) { + dc.SetPen(wxPen(wxColour(130, 129, 128), 1, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawLine(FromDIP(4), FromDIP(4) + top, size.x - FromDIP(4), FromDIP(4) + top); + } + } + else { + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + if (tmp_lib_colour.Red() > 238 && tmp_lib_colour.Green() > 238 && tmp_lib_colour.Blue() > 238) { + dc.SetPen(wxPen(wxColour(130, 129, 128), 2, wxPENSTYLE_SOLID)); + } + else { + dc.SetPen(wxPen(tmp_lib_colour, 2, wxPENSTYLE_SOLID)); + } + +#ifdef __APPLE__ + dc.DrawLine(FromDIP(5), FromDIP(4) + height - FromDIP(2), size.x - FromDIP(5), FromDIP(4) + height - FromDIP(2)); + dc.DrawLine(FromDIP(6), FromDIP(4) + height - FromDIP(1), size.x - FromDIP(6), FromDIP(4) + height - FromDIP(1)); +#else + dc.DrawLine(FromDIP(4), FromDIP(4) + height - FromDIP(2), size.x - FromDIP(4), FromDIP(4) + height - FromDIP(2)); + dc.DrawLine(FromDIP(5), FromDIP(4) + height - FromDIP(1), size.x - FromDIP(5), FromDIP(4) + height - FromDIP(1)); +#endif + } + } + + //border + dc.SetPen(wxPen(wxColour(130, 130, 128), 1, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); +#ifdef __APPLE__ + dc.DrawRoundedRectangle(FromDIP(4), FromDIP(4), size.x - FromDIP(7), size.y - FromDIP(7), m_radius); +#else + dc.DrawRoundedRectangle(FromDIP(3), FromDIP(3), size.x - FromDIP(6), size.y - FromDIP(6), m_radius); +#endif + + if (!m_disable_mode) { + // edit icon + if (m_info.material_state != AMSCanType::AMS_CAN_TYPE_EMPTY && m_info.material_state != AMSCanType::AMS_CAN_TYPE_NONE) + { + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_THIRDBRAND || m_info.material_state == AMSCanType::AMS_CAN_TYPE_VIRTUAL) + dc.DrawBitmap(temp_bitmap_third.bmp(), (size.x - temp_bitmap_third.GetBmpSize().x) / 2, (size.y - FromDIP(10) - temp_bitmap_third.GetBmpSize().y)); + if (m_info.material_state == AMSCanType::AMS_CAN_TYPE_BRAND) + dc.DrawBitmap(temp_bitmap_brand.bmp(), (size.x - temp_bitmap_brand.GetBmpSize().x) / 2, (size.y - FromDIP(10) - temp_bitmap_brand.GetBmpSize().y)); + } + } +} + +void AMSLib::on_pass_road(bool pass) +{ + if (m_pass_road != pass) { + m_pass_road = pass; + Refresh(); + } +} + +void AMSLib::Update(Caninfo info, std::string ams_idx, bool refresh) +{ + DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) return; + if (dev->get_selected_machine() && dev->get_selected_machine() != m_obj) { + m_obj = dev->get_selected_machine(); + } + if (info.material_colour.Alpha() != 0 && info.material_colour.Alpha() != 255 && info.material_colour.Alpha() != 254 && m_info.material_colour != info.material_colour) { + transparent_changed = true; + } + m_info = info; + m_ams_id = ams_idx; + Layout(); + if (refresh) Refresh(); +} + +wxColour AMSLib::GetLibColour() { return m_info.material_colour; } + +void AMSLib::OnSelected() +{ + if (!wxWindow::IsEnabled()) return; + if (m_unable_selected) return; + + post_event(wxCommandEvent(EVT_AMS_ON_SELECTED)); + m_selected = true; + Refresh(); +} + +void AMSLib::post_event(wxCommandEvent &&event) +{ + int tray_id = atoi(m_ams_id.c_str()) * 4 + atoi(m_info.can_id.c_str()); + //event.SetString(m_info.can_id); + event.SetInt(tray_id); + event.SetEventObject(m_parent); + wxPostEvent(m_parent, event); + event.Skip(); +} + +void AMSLib::UnSelected() +{ + m_selected = false; + Refresh(); +} + +bool AMSLib::Enable(bool enable) { return wxWindow::Enable(enable); } + +void AMSLib::msw_rescale() +{ + m_bitmap_transparent.msw_rescale(); +} + +/************************************************* +Description:AMSRoad +**************************************************/ +AMSRoad::AMSRoad() : m_road_def_color(AMS_CONTROL_GRAY500), m_road_color(AMS_CONTROL_GRAY500) {} +AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos, const wxSize &size) + : AMSRoad() +{ + m_info = info; + m_canindex = canindex; + // road type + auto mode = AMSRoadMode::AMS_ROAD_MODE_END; + if (m_canindex == 0 && maxcan == 1) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_NONE; + } else if (m_canindex == 0 && maxcan > 1) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_END; + } else if (m_canindex < (maxcan - 1)) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT; + } else if (m_canindex == (maxcan - 1)) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT; + } else if (m_canindex == -1 && maxcan == -1) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY; + } + else { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_NONE_ANY_ROAD; + } + + for (int i = 1; i <= 5; i++) { + ams_humidity_img.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 32)); + } + + for (int i = 1; i <= 5; i++) { + ams_humidity_img.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 32)); + } + if (m_rode_mode != AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { + create(parent, id, pos, size); + } + else { + wxSize virtual_size(size.x - 1, size.y + 2); + create(parent, id, pos, virtual_size); + + } + + Bind(wxEVT_PAINT, &AMSRoad::paintEvent, this); + wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + + Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { + if (m_canindex == 3 && m_show_humidity) { + auto mouse_pos = ClientToScreen(e.GetPosition()); + auto rect = ClientToScreen(wxPoint(0, 0)); + + if (mouse_pos.x > rect.x + GetSize().x - FromDIP(40) && + mouse_pos.y > rect.y + GetSize().y - FromDIP(40)) { + wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); + wxPostEvent(GetParent()->GetParent(), show_event); + +#ifdef __WXMSW__ + wxCommandEvent close_event(EVT_CLEAR_SPEED_CONTROL); + wxPostEvent(GetParent()->GetParent(), close_event); +#endif // __WXMSW__ + + } + } + }); +} + +void AMSRoad::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size); } + +void AMSRoad::Update(AMSinfo amsinfo, Caninfo info, int canindex, int maxcan) +{ + m_amsinfo = amsinfo; + m_info = info; + m_canindex = canindex; + if (m_canindex == 0 && maxcan == 1) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_END_ONLY; + } else if (m_canindex == 0 && maxcan > 1) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_END; + } else if (m_canindex < (maxcan - 1)) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT; + } else if (m_canindex == (maxcan - 1)) { + m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_LEFT; + } + m_pass_rode_mode.push_back(AMSPassRoadMode::AMS_ROAD_MODE_NONE); + Refresh(); +} + +void AMSRoad::OnVamsLoading(bool load, wxColour col /*= AMS_CONTROL_GRAY500*/) +{ + m_vams_loading = load; + if(load)m_road_color = col; + Refresh(); +} + +void AMSRoad::SetPassRoadColour(wxColour col) { m_road_color = col; } + +void AMSRoad::SetMode(AMSRoadMode mode) +{ + m_rode_mode = mode; + Refresh(); +} + +void AMSRoad::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSRoad::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AMSRoad::doRender(wxDC &dc) +{ + wxSize size = GetSize(); + + dc.SetPen(wxPen(m_road_def_color, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + // left mode + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT) { dc.DrawRoundedRectangle(-10, -10, size.x / 2 + 10, size.y * 0.6 + 10, 4); } + + // left right mode + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT) { + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + dc.DrawLine(0, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); + } + + // end mode + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END) { + dc.SetBrush(wxBrush(m_road_def_color)); + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); + dc.DrawLine(size.x / 2, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); + } + + // end mode only + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { + dc.SetBrush(wxBrush(m_road_def_color)); + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); + } + + // end none + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_NONE) { + dc.SetBrush(wxBrush(m_road_def_color)); + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); + dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); + // dc.DrawLine(size.x / 2, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); + } + + //virtual road + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { + dc.SetBrush(wxBrush(m_road_def_color)); + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y - 1); + } + + // mode none + // if (m_pass_rode_mode.size() == 1 && m_pass_rode_mode[0] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) return; + + if (m_road_color.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, m_passroad_width, wxPENSTYLE_SOLID));} + else {dc.SetPen(wxPen(m_road_color, m_passroad_width, wxPENSTYLE_SOLID));} + + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + + // left pass mode + for (auto pass_mode : m_pass_rode_mode) { + switch (pass_mode) { + case AMSPassRoadMode::AMS_ROAD_MODE_LEFT: dc.DrawRoundedRectangle(-10, -10, size.x / 2 + 10, size.y * 0.6 + 10, 4); break; + + case AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT: dc.DrawLine(0, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); break; + + case AMSPassRoadMode::AMS_ROAD_MODE_END_TOP: dc.DrawLine(size.x / 2, -1, size.x / 2, size.y * 0.6 - 1); break; + + case AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM: dc.DrawLine(size.x / 2, size.y * 0.6, size.x / 2, size.y); break; + + case AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT: dc.DrawLine(size.x / 2, size.y * 0.6 - 1, size.x, size.y * 0.6 - 1); break; + + default: break; + } + } + + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY && m_vams_loading) { + dc.DrawLine(size.x / 2, -1, size.x / 2, size.y - 1); + } + + // end mode + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { + dc.SetPen(wxPen(m_road_def_color, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(m_road_def_color)); + dc.DrawRoundedRectangle(size.x * 0.37 / 2, size.y * 0.6 - size.y / 6, size.x * 0.63, size.y / 3, m_radius); + } + + if (m_canindex == 3) { + + if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) {m_show_humidity = true;} + else {m_show_humidity = false;} + + if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) { + + int hum_index = m_amsinfo.ams_humidity - 1; + if (wxGetApp().dark_mode()) { + hum_index += 5; + } + + if (hum_index >= 0) { + dc.DrawBitmap(ams_humidity_img[hum_index].bmp(), wxPoint(size.x - FromDIP(33), size.y - FromDIP(33))); + } + } + else { + //to do ... + } + } +} + +void AMSRoad::UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step) {} + +void AMSRoad::OnPassRoad(std::vector prord_list) +{ + // AMS_ROAD_MODE_NONE, AMS_ROAD_MODE_LEFT, AMS_ROAD_MODE_LEFT_RIGHT, AMS_ROAD_MODE_END_TOP, AMS_ROAD_MODE_END_BOTTOM, AMS_ROAD_MODE_END_RIGHT, + // AMS_ROAD_MODE_LEFT, AMS_ROAD_MODE_LEFT_RIGHT, AMS_ROAD_MODE_END, + + m_pass_rode_mode.clear(); + auto left_types = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE, AMSPassRoadMode::AMS_ROAD_MODE_LEFT}; + auto left_right_types = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE, AMSPassRoadMode::AMS_ROAD_MODE_LEFT, AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT}; + auto end_types = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE, AMSPassRoadMode::AMS_ROAD_MODE_END_TOP, AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM, + AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT}; + + // left + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT) { + for (auto i = 0; i < prord_list.size(); i++) { + std::vector::iterator iter = std::find(left_types.begin(), left_types.end(), prord_list[i]); + if (iter != left_types.end()) m_pass_rode_mode.push_back(prord_list[i]); + + if (prord_list[i] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) { + m_pass_rode_mode = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE}; + break; + } + } + } + + // left right + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT) { + for (auto i = 0; i < prord_list.size(); i++) { + std::vector::iterator iter = std::find(left_right_types.begin(), left_right_types.end(), prord_list[i]); + if (iter != left_right_types.end()) m_pass_rode_mode.push_back(prord_list[i]); + + if (prord_list[i] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) { + m_pass_rode_mode = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE}; + break; + } + } + } + + // left end + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { + for (auto i = 0; i < prord_list.size(); i++) { + std::vector::iterator iter = std::find(end_types.begin(), end_types.end(), prord_list[i]); + if (iter != end_types.end()) m_pass_rode_mode.push_back(prord_list[i]); + + if (prord_list[i] == AMSPassRoadMode::AMS_ROAD_MODE_NONE) { + m_pass_rode_mode = std::vector{AMSPassRoadMode::AMS_ROAD_MODE_NONE}; + break; + } + } + } +} + + +/************************************************* +Description:AmsCan +**************************************************/ + +AmsCans::AmsCans() {} + +AmsCans::AmsCans(wxWindow *parent,AMSinfo info, AMSModel model) : AmsCans() +{ + m_bitmap_extra_framework = ScalableBitmap(this, "ams_extra_framework_mid", 140); + + SetDoubleBuffered(true); + m_ams_model = model; + m_info = info; + + wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE); + create(parent); + Bind(wxEVT_PAINT, &AmsCans::paintEvent, this); +} + +void AmsCans::create(wxWindow *parent) +{ + Freeze(); + SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + + if (m_ams_model == AMSModel::GENERIC_AMS) { + sizer_can = new wxBoxSizer(wxHORIZONTAL); + for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { + AddCan(*it, m_can_count, m_info.cans.size(), sizer_can); + m_can_count++; + } + SetSizer(sizer_can); + } + else if(m_ams_model == AMSModel::EXTRA_AMS) { + sizer_can = new wxBoxSizer(wxVERTICAL); + sizer_can_middle = new wxBoxSizer(wxHORIZONTAL); + sizer_can_left = new wxBoxSizer(wxVERTICAL); + sizer_can_right = new wxBoxSizer(wxVERTICAL); + + sizer_can_left->Add(0,0,0,wxTOP,FromDIP(8)); + + for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { + if (m_can_count <= 1) { + AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_left); + if (m_can_count == 0) { + sizer_can_left->Add(0,0,0,wxTOP,FromDIP(20)); + } + } + else { + AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_right); + if (m_can_count == 2) { + sizer_can_right->Prepend(0, 0, 0, wxTOP, FromDIP(20)); + } + } + + m_can_count++; + } + + sizer_can_right->Prepend(0,0,0,wxTOP,FromDIP(8)); + sizer_can_middle->Add(0, 0, 0, wxLEFT, FromDIP(8)); + sizer_can_middle->Add(sizer_can_left, 0, wxALL, 0); + sizer_can_middle->Add( 0, 0, 0, wxLEFT, FromDIP(20) ); + sizer_can_middle->Add(sizer_can_right, 0, wxALL, 0); + sizer_can->Add(sizer_can_middle, 1, wxALIGN_CENTER, 0); + SetSizer(sizer_can); + } + + Layout(); + Fit(); + Thaw(); +} + +void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer) +{ + + auto amscan = new wxWindow(this, wxID_ANY); + amscan->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + + wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); + + + auto m_panel_refresh = new AMSrefresh(amscan, m_can_count, caninfo); + auto m_panel_lib = new AMSLib(amscan, m_info.ams_id, caninfo); + + m_panel_lib->Bind(wxEVT_LEFT_DOWN, [this, canindex](wxMouseEvent& ev) { + m_canlib_selection = canindex; + // m_canlib_id = caninfo.can_id; + + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs* lib = m_can_lib_list[i]; + if (lib->canLib->m_can_index == m_canlib_selection) { + wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); + evt.SetString(m_info.ams_id); + wxPostEvent(GetParent()->GetParent(), evt); + lib->canLib->OnSelected(); + } + else { + lib->canLib->UnSelected(); + } + } + ev.Skip(); + }); + + + m_panel_lib->m_ams_model = m_ams_model; + m_panel_lib->m_info.can_id = caninfo.can_id; + m_panel_lib->m_can_index = canindex; + + + auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); + + if (m_ams_model == AMSModel::GENERIC_AMS) { + m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(14)); + m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); + m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); + m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); + m_sizer_ams->Add(m_panel_road, 0, wxALL, 0); + } + else if (m_ams_model == AMSModel::EXTRA_AMS) + { + m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); + m_panel_road->Hide(); + + if (canindex <= 1) { + m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); + m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); + } + else { + m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); + m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); + } + } + + + amscan->SetSizer(m_sizer_ams); + amscan->Layout(); + amscan->Fit(); + + if (m_ams_model == AMSModel::GENERIC_AMS) { + sizer->Add(amscan, 0, wxALL, 0); + } + else if (m_ams_model == AMSModel::EXTRA_AMS) + { + if (canindex > 1) { + sizer->Prepend(amscan, 0, wxALL, 0); + } + else { + sizer->Add(amscan, 0, wxALL, 0); + } + } + + Canrefreshs* canrefresh = new Canrefreshs; + canrefresh->canID = caninfo.can_id; + canrefresh->canrefresh = m_panel_refresh; + m_can_refresh_list.Add(canrefresh); + + CanLibs* canlib = new CanLibs; + canlib->canID = caninfo.can_id; + canlib->canLib = m_panel_lib; + m_can_lib_list.Add(canlib); + + CanRoads* canroad = new CanRoads; + canroad->canID = caninfo.can_id; + canroad->canRoad = m_panel_road; + m_can_road_list.Add(canroad); +} + +void AmsCans::Update(AMSinfo info) +{ + m_info = info; + m_can_count = info.cans.size(); + + for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { + Canrefreshs *refresh = m_can_refresh_list[i]; + if (i < m_can_count) { + refresh->canrefresh->Update(info.ams_id, info.cans[i]); + refresh->canrefresh->Show(); + } else { + refresh->canrefresh->Hide(); + } + } + + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs *lib = m_can_lib_list[i]; + if (i < m_can_count) { + lib->canLib->Update(info.cans[i], info.ams_id); + lib->canLib->Show(); + } else { + lib->canLib->Hide(); + } + } + + if (m_ams_model == AMSModel::GENERIC_AMS) { + for (auto i = 0; i < m_can_road_list.GetCount(); i++) { + CanRoads* road = m_can_road_list[i]; + if (i < m_can_count) { + road->canRoad->Update(m_info, info.cans[i], i, m_can_count); + road->canRoad->Show(); + } + else { + road->canRoad->Hide(); + } + } + } + Layout(); +} + +void AmsCans::SetDefSelectCan() +{ + if (m_can_lib_list.GetCount() > 0) { + CanLibs* lib = m_can_lib_list[0]; + m_canlib_selection =lib->canLib->m_can_index; + m_canlib_id = lib->canLib->m_info.can_id; + SelectCan(m_canlib_id); + } +} + + +void AmsCans::SelectCan(std::string canid) +{ + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs *lib = m_can_lib_list[i]; + if (lib->canLib->m_info.can_id == canid) { + m_canlib_selection = lib->canLib->m_can_index; + } + } + + m_canlib_id = canid; + + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs *lib = m_can_lib_list[i]; + if (lib->canLib->m_info.can_id == m_canlib_id) { + wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); + evt.SetString(m_info.ams_id); + wxPostEvent(GetParent()->GetParent(), evt); + lib->canLib->OnSelected(); + } else { + lib->canLib->UnSelected(); + } + } +} + +wxColour AmsCans::GetTagColr(wxString canid) +{ + auto tag_colour = *wxWHITE; + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs* lib = m_can_lib_list[i]; + if (canid == lib->canLib->m_info.can_id) tag_colour = lib->canLib->GetLibColour(); + } + return tag_colour; +} + +void AmsCans::SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) +{ + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP1) { + SetAmsStep(canid.ToStdString()); + }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP2) { + SetAmsStep(canid.ToStdString()); + }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP3) { + SetAmsStep(canid.ToStdString()); + }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { + SetAmsStep(""); + } +} + +void AmsCans::SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) +{ + + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { + for (auto i = 0; i < m_can_road_list.GetCount(); i++) { + CanRoads *road = m_can_road_list[i]; + auto pr = std::vector{}; + pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_NONE); + road->canRoad->OnPassRoad(pr); + } + + return; + } + + + auto tag_can_index = -1; + for (auto i = 0; i < m_can_road_list.GetCount(); i++) { + CanRoads *road = m_can_road_list[i]; + if (canid == road->canRoad->m_info.can_id) { tag_can_index = road->canRoad->m_canindex; } + } + if (tag_can_index == -1) return; + + // get colour + auto tag_colour = *wxWHITE; + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs *lib = m_can_lib_list[i]; + if (canid == lib->canLib->m_info.can_id) tag_colour = lib->canLib->GetLibColour(); + } + + // unload + if (type == AMSPassRoadType::AMS_ROAD_TYPE_UNLOAD) { + for (auto i = 0; i < m_can_road_list.GetCount(); i++) { + CanRoads *road = m_can_road_list[i]; + + auto index = road->canRoad->m_canindex; + auto pr = std::vector{}; + + pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } + + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_3) { + if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } + if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } + if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } + if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } + } + + road->canRoad->SetPassRoadColour(tag_colour); + road->canRoad->OnPassRoad(pr); + } + } + + // load + if (type == AMSPassRoadType::AMS_ROAD_TYPE_LOAD) { + for (auto i = 0; i < m_can_road_list.GetCount(); i++) { + CanRoads *road = m_can_road_list[i]; + + auto index = road->canRoad->m_canindex; + auto pr = std::vector{}; + + if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } + if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } + if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } + if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } + + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } + + road->canRoad->SetPassRoadColour(tag_colour); + road->canRoad->OnPassRoad(pr); + } + } +} + +void AmsCans::SetAmsStep(std::string can_id) +{ + if (m_road_canid != can_id) { + m_road_canid = can_id; + Refresh(); + } +} + +void AmsCans::PlayRridLoading(wxString canid) +{ + for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { + Canrefreshs *refresh = m_can_refresh_list[i]; + if (refresh->canrefresh->m_info.can_id == canid) { refresh->canrefresh->PlayLoading(); } + } +} + +std::string AmsCans::GetCurrentCan() +{ + if (m_canlib_selection < 0) + return ""; + + return wxString::Format("%d", m_canlib_selection).ToStdString(); +} + +void AmsCans::paintEvent(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AmsCans::render(wxDC& dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AmsCans::doRender(wxDC& dc) +{ + wxSize size = GetSize(); + dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); + + //road for extra + if (m_ams_model == AMSModel::EXTRA_AMS) { + + auto end_top = size.x / 2 - FromDIP(99); + auto passroad_width = 6; + + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs* lib = m_can_lib_list[i]; + + if (m_road_canid.empty()) { + lib->canLib->on_pass_road(false); + } + else { + if (lib->canLib->m_info.can_id == m_road_canid) { + m_road_colour = lib->canLib->m_info.material_colour; + lib->canLib->on_pass_road(true); + } + } + } + + + // A1 + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + + try + { + auto a1_top = size.y / 2 - FromDIP(4); + auto a1_left = m_can_lib_list[0]->canLib->GetScreenPosition().x + m_can_lib_list[0]->canLib->GetSize().x / 2; + auto local_pos1 = GetScreenPosition().x + GetSize().x / 2; + a1_left = size.x / 2 + (a1_left - local_pos1); + dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); + dc.DrawLine(a1_left, a1_top, end_top, a1_top); + + + // A2 + auto a2_top = size.y / 2 + FromDIP(8); + auto a2_left = m_can_lib_list[1]->canLib->GetScreenPosition().x + m_can_lib_list[1]->canLib->GetSize().x / 2; + auto local_pos2 = GetScreenPosition().x + GetSize().x / 2; + a2_left = size.x / 2 + (a2_left - local_pos2); + dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); + dc.DrawLine(a2_left, a2_top, end_top, a2_top); + + // A3 + auto a3_top = size.y / 2 + FromDIP(4); + auto a3_left = m_can_lib_list[2]->canLib->GetScreenPosition().x + m_can_lib_list[2]->canLib->GetSize().x / 2; + auto local_pos3 = GetScreenPosition().x + GetSize().x / 2; + a3_left = size.x / 2 + (a3_left - local_pos3); + dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); + dc.DrawLine(a3_left, a3_top, end_top, a3_top); + + + // A4 + auto a4_top = size.y / 2; + auto a4_left = m_can_lib_list[3]->canLib->GetScreenPosition().x + m_can_lib_list[3]->canLib->GetSize().x / 2; + auto local_pos4 = GetScreenPosition().x + GetSize().x / 2; + a4_left = size.x / 2 + (a4_left - local_pos4); + dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); + dc.DrawLine(a4_left, a4_top, end_top, a4_top); + + + if (!m_road_canid.empty()) { + if (m_road_canid == "0") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); + dc.DrawLine(a1_left, a1_top, end_top, a1_top); + } + + if (m_road_canid == "1") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); + dc.DrawLine(a2_left, a2_top, end_top, a2_top); + } + + if (m_road_canid == "2") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); + dc.DrawLine(a3_left, a3_top, end_top, a3_top); + } + + if (m_road_canid == "3") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); + dc.DrawLine(a4_left, a4_top, end_top, a4_top); + } + } + + //to Extruder + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + + dc.DrawLine(end_top, a1_top, end_top, size.y); + + if (!m_road_canid.empty()) { + if (!m_road_canid.empty()) { + if (m_road_canid == "0") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a1_top, end_top, size.y); + } + else if (m_road_canid == "1") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a2_top, end_top, size.y); + } + else if (m_road_canid == "2") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a3_top, end_top, size.y); + } + else if (m_road_canid == "3") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a4_top, end_top, size.y); + } + } + } + } + catch (...){} + } +} + +void AmsCans::StopRridLoading(wxString canid) +{ + for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { + Canrefreshs *refresh = m_can_refresh_list[i]; + if (refresh->canrefresh->m_info.can_id == canid) { refresh->canrefresh->StopLoading(); } + } +} + +void AmsCans::msw_rescale() +{ + for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { + Canrefreshs *refresh = m_can_refresh_list[i]; + refresh->canrefresh->msw_rescale(); + } + + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs* lib = m_can_lib_list[i]; + lib->canLib->msw_rescale(); + } +} + +void AmsCans::show_sn_value(bool show) +{ + for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { + CanLibs* lib = m_can_lib_list[i]; + lib->canLib->show_kn_value(show); + } +} + +/************************************************* +Description:AMSItem +**************************************************/ +AMSItem::AMSItem() {} + +AMSItem::AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSItem() +{ + m_amsinfo = amsinfo; + m_cube_size = cube_size; + create(parent, id, pos, AMS_ITEM_SIZE); + Bind(wxEVT_PAINT, &AMSItem::paintEvent, this); + Bind(wxEVT_ENTER_WINDOW, &AMSItem::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &AMSItem::OnLeaveWindow, this); +} + +void AMSItem::Open() +{ + m_open = true; + Show(); +} + +void AMSItem::Close() +{ + m_open = false; + Hide(); +} + +void AMSItem::Update(AMSinfo amsinfo) +{ + m_amsinfo = amsinfo; +} + +void AMSItem::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +{ + m_ts_bitmap_cube = new ScalableBitmap(this, "ts_bitmap_cube", 14); + wxWindow::Create(parent, id, pos, size); + SetMinSize(AMS_ITEM_SIZE); + SetMaxSize(AMS_ITEM_SIZE); + SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + Refresh(); +} + +void AMSItem::OnEnterWindow(wxMouseEvent &evt) +{ + // m_hover = true; + // Refresh(); +} + +void AMSItem::OnLeaveWindow(wxMouseEvent &evt) +{ + // m_hover = false; + // Refresh(); +} + +void AMSItem::OnSelected() +{ + if (!wxWindow::IsEnabled()) { return; } + m_selected = true; + Refresh(); +} + +void AMSItem::UnSelected() +{ + m_selected = false; + Refresh(); +} + +bool AMSItem::Enable(bool enable) { return wxWindow::Enable(enable); } + +void AMSItem::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSItem::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AMSItem::doRender(wxDC &dc) +{ + wxSize size = GetSize(); + dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(m_background_colour))); + dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); + + auto left = m_padding; + for (std::vector::iterator iter = m_amsinfo.cans.begin(); iter != m_amsinfo.cans.end(); iter++) { + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + + if (wxWindow::IsEnabled()) { + wxColour color = iter->material_colour; + change_the_opacity(color); + dc.SetBrush(wxBrush(color)); + } else { + dc.SetBrush(AMS_CONTROL_DISABLE_COLOUR); + } + + if (iter->material_cols.size() > 1) { + int fleft = left; + float total_width = AMS_ITEM_CUBE_SIZE.x; + int gwidth = std::round(total_width / (iter->material_cols.size() - 1)); + if (iter->ctype == 0) { + for (int i = 0; i < iter->material_cols.size() - 1; i++) { + + if ((fleft + gwidth) > (AMS_ITEM_CUBE_SIZE.x)) { + gwidth = (fleft + AMS_ITEM_CUBE_SIZE.x) - fleft; + } + + auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); + dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); + fleft += gwidth; + } + } else { + int cols_size = iter->material_cols.size(); + for (int i = 0; i < cols_size; i++) { + dc.SetBrush(wxBrush(iter->material_cols[i])); + float x = left + total_width * i / cols_size; + dc.DrawRoundedRectangle(x, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, total_width / cols_size, AMS_ITEM_CUBE_SIZE.y , 0); + } + } + + dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(left - 1, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2 - 1, AMS_ITEM_CUBE_SIZE.x + 2, AMS_ITEM_CUBE_SIZE.y + 2, 2); + + }else { + if (iter->material_colour.Alpha() == 0) { + dc.DrawBitmap(m_ts_bitmap_cube->bmp(),left,(size.y - AMS_ITEM_CUBE_SIZE.y) / 2); + } + else { + wxRect rect(left, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, AMS_ITEM_CUBE_SIZE.x, AMS_ITEM_CUBE_SIZE.y); + if(iter->material_state==AMSCanType::AMS_CAN_TYPE_EMPTY){ + dc.SetPen(wxPen(wxColor(0, 0, 0))); + dc.DrawRoundedRectangle(rect, 2); + + dc.DrawLine(rect.GetRight()-1, rect.GetTop()+1, rect.GetLeft()+1, rect.GetBottom()-1); + } + else { + dc.DrawRoundedRectangle(rect, 2); + } + } + + } + + + left += AMS_ITEM_CUBE_SIZE.x; + left += m_space; + } + + auto border_colour = AMS_CONTROL_BRAND_COLOUR; + if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } + + if (m_hover) { + dc.SetPen(wxPen(border_colour, 2)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); + + } + + if (m_selected) { + dc.SetPen(wxPen(border_colour, 2)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); + } +} + +void AMSItem::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } + +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp new file mode 100644 index 00000000000..bdd13459d06 --- /dev/null +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -0,0 +1,584 @@ +#ifndef slic3r_GUI_AMSITEM_hpp_ +#define slic3r_GUI_AMSITEM_hpp_ + +#include "../wxExtensions.hpp" +#include "StaticBox.hpp" +#include "StepCtrl.hpp" +#include "Button.hpp" +#include "../DeviceManager.hpp" +#include "slic3r/GUI/Event.hpp" +#include "slic3r/GUI/AmsMappingPopup.hpp" +#include +#include +#include +#include + + +#define AMS_CONTROL_BRAND_COLOUR wxColour(0, 150, 136) +#define AMS_CONTROL_GRAY700 wxColour(107, 107, 107) +#define AMS_CONTROL_GRAY800 wxColour(50, 58, 61) +#define AMS_CONTROL_GRAY500 wxColour(172, 172, 172) +#define AMS_CONTROL_DISABLE_COLOUR wxColour(206, 206, 206) +#define AMS_CONTROL_DISABLE_TEXT_COLOUR wxColour(144, 144, 144) +#define AMS_CONTROL_WHITE_COLOUR wxColour(255, 255, 255) +#define AMS_CONTROL_BLACK_COLOUR wxColour(0, 0, 0) +#define AMS_CONTROL_DEF_BLOCK_BK_COLOUR wxColour(238, 238, 238) +#define AMS_CONTROL_DEF_LIB_BK_COLOUR wxColour(248, 248, 248) +#define AMS_EXTRUDER_DEF_COLOUR wxColour(234, 234, 234) +#define AMS_CONTROL_MAX_COUNT 4 +#define AMS_CONTRO_CALIBRATION_BUTTON_SIZE wxSize(FromDIP(150), FromDIP(28)) + +// enum AMSRoadMode{ +// AMS_ROAD_MODE_LEFT, +// AMS_ROAD_MODE_LEFT_RIGHT, +// AMS_ROAD_MODE_END, +//}; + +namespace Slic3r { namespace GUI { + + +enum AMSModel { + NO_AMS = 0, + GENERIC_AMS = 1, + EXTRA_AMS = 2 +}; + +enum ActionButton { + ACTION_BTN_CALI = 0, + ACTION_BTN_LOAD = 1, + ACTION_BTN_UNLOAD = 2, + ACTION_BTN_COUNT = 3 +}; + +enum class AMSRoadMode : int { + AMS_ROAD_MODE_LEFT, + AMS_ROAD_MODE_LEFT_RIGHT, + AMS_ROAD_MODE_END, + AMS_ROAD_MODE_END_ONLY, + AMS_ROAD_MODE_NONE, + AMS_ROAD_MODE_NONE_ANY_ROAD, + AMS_ROAD_MODE_VIRTUAL_TRAY +}; + +enum class AMSPassRoadMode : int { + AMS_ROAD_MODE_NONE, + AMS_ROAD_MODE_LEFT, + AMS_ROAD_MODE_LEFT_RIGHT, + AMS_ROAD_MODE_END_TOP, + AMS_ROAD_MODE_END_RIGHT, + AMS_ROAD_MODE_END_BOTTOM, +}; + +enum class AMSAction : int { + AMS_ACTION_NONE, + AMS_ACTION_LOAD, + AMS_ACTION_UNLOAD, + AMS_ACTION_CALI, + AMS_ACTION_PRINTING, + AMS_ACTION_NORMAL, + AMS_ACTION_NOAMS, +}; + +enum class AMSPassRoadSTEP : int { + AMS_ROAD_STEP_NONE, + AMS_ROAD_STEP_1, // lib -> extrusion + AMS_ROAD_STEP_2, // extrusion->buffer + AMS_ROAD_STEP_3, // extrusion + + AMS_ROAD_STEP_COMBO_LOAD_STEP1, + AMS_ROAD_STEP_COMBO_LOAD_STEP2, + AMS_ROAD_STEP_COMBO_LOAD_STEP3, +}; + +enum class AMSPassRoadType : int { + AMS_ROAD_TYPE_NONE, + AMS_ROAD_TYPE_LOAD, + AMS_ROAD_TYPE_UNLOAD, +}; + +enum class AMSCanType : int { + AMS_CAN_TYPE_NONE, + AMS_CAN_TYPE_BRAND, + AMS_CAN_TYPE_THIRDBRAND, + AMS_CAN_TYPE_EMPTY, + AMS_CAN_TYPE_VIRTUAL, +}; + +enum FilamentStep { + STEP_IDLE, + STEP_HEAT_NOZZLE, + STEP_CUT_FILAMENT, + STEP_PULL_CURR_FILAMENT, + STEP_PUSH_NEW_FILAMENT, + STEP_PURGE_OLD_FILAMENT, + STEP_FEED_FILAMENT, + STEP_CONFIRM_EXTRUDED, + STEP_CHECK_POSITION, + STEP_COUNT, +}; + +enum FilamentStepType { + STEP_TYPE_LOAD = 0, + STEP_TYPE_UNLOAD = 1, + STEP_TYPE_VT_LOAD = 2, +}; + +#define AMS_ITEM_CUBE_SIZE wxSize(FromDIP(14), FromDIP(14)) +#define AMS_ITEM_SIZE wxSize(FromDIP(82), FromDIP(27)) +#define AMS_ITEM_HUMIDITY_SIZE wxSize(FromDIP(120), FromDIP(27)) +#define AMS_CAN_LIB_SIZE wxSize(FromDIP(58), FromDIP(80)) +#define AMS_CAN_ROAD_SIZE wxSize(FromDIP(66), FromDIP(70)) +#define AMS_CAN_ITEM_HEIGHT_SIZE FromDIP(27) +#define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(196)) +#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) +#define AMS_STEP_SIZE wxSize(FromDIP(172), FromDIP(196)) +#define AMS_REFRESH_SIZE wxSize(FromDIP(30), FromDIP(30)) +#define AMS_EXTRUDER_SIZE wxSize(FromDIP(86), FromDIP(72)) +#define AMS_EXTRUDER_BITMAP_SIZE wxSize(FromDIP(36), FromDIP(55)) + +struct Caninfo +{ + std::string can_id; + wxString material_name; + wxColour material_colour = {*wxWHITE}; + AMSCanType material_state; + int ctype=0; + int material_remain = 100; + float k = 0.0f; + float n = 0.0f; + std::vector material_cols; +}; + +struct AMSinfo +{ +public: + std::string ams_id; + std::vector cans; + std::string current_can_id; + AMSPassRoadSTEP current_step; + AMSAction current_action; + int curreent_filamentstep; + int ams_humidity = 0; + + bool parse_ams_info(MachineObject* obj, Ams *ams, bool remain_flag = false, bool humidity_flag = false); +}; + +/************************************************* +Description:AMSrefresh +**************************************************/ +#define AMS_REFRESH_PLAY_LOADING_TIMER 100 +class AMSrefresh : public wxWindow +{ +public: + AMSrefresh(); + AMSrefresh(wxWindow *parent, wxString number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + ~AMSrefresh(); + void PlayLoading(); + void StopLoading(); + void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); + void on_timer(wxTimerEvent &event); + void OnEnterWindow(wxMouseEvent &evt); + void OnLeaveWindow(wxMouseEvent &evt); + void OnClick(wxMouseEvent &evt); + void post_event(wxCommandEvent &&event); + void paintEvent(wxPaintEvent &evt); + void Update(std::string ams_id, Caninfo info); + void msw_rescale(); + void set_disable_mode(bool disable) { m_disable_mode = disable; } + Caninfo m_info; + + +protected: + wxTimer *m_playing_timer= {nullptr}; + int m_rotation_angle = 0; + bool m_play_loading = {false}; + bool m_selected = {false}; + + std::string m_ams_id; + std::string m_can_id; + + ScalableBitmap m_bitmap_normal; + ScalableBitmap m_bitmap_selected; + ScalableBitmap m_bitmap_ams_rfid_0; + ScalableBitmap m_bitmap_ams_rfid_1; + ScalableBitmap m_bitmap_ams_rfid_2; + ScalableBitmap m_bitmap_ams_rfid_3; + ScalableBitmap m_bitmap_ams_rfid_4; + ScalableBitmap m_bitmap_ams_rfid_5; + ScalableBitmap m_bitmap_ams_rfid_6; + ScalableBitmap m_bitmap_ams_rfid_7; + std::vector m_rfid_bitmap_list; + + wxString m_refresh_id; + wxBoxSizer * m_size_body; + virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); + + bool m_disable_mode{ false }; +}; + +/************************************************* +Description:AMSextruder +**************************************************/ +class AMSextruderImage: public wxWindow +{ +public: + void TurnOn(wxColour col); + void TurnOff(); + void msw_rescale(); + void paintEvent(wxPaintEvent &evt); + + void render(wxDC &dc); + bool m_turn_on = {false}; + wxColour m_colour; + ScalableBitmap m_ams_extruder; + void doRender(wxDC &dc); + AMSextruderImage(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + ~AMSextruderImage(); +}; + + +class AMSextruder : public wxWindow +{ +public: + void TurnOn(wxColour col); + void TurnOff(); + void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); + void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); + void OnAmsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); + void paintEvent(wxPaintEvent& evt); + void render(wxDC& dc); + void doRender(wxDC& dc); + void msw_rescale(); + void has_ams(bool hams) {m_has_vams = hams; Refresh();}; + void no_ams_mode(bool mode) {m_none_ams_mode = mode; Refresh();}; + + bool m_none_ams_mode{true}; + bool m_has_vams{false}; + bool m_vams_loading{false}; + bool m_ams_loading{false}; + wxColour m_current_colur; + + wxBoxSizer * m_bitmap_sizer{nullptr}; + wxPanel * m_bitmap_panel{nullptr}; + AMSextruderImage *m_amsSextruder{nullptr}; + ScalableBitmap monitor_ams_extruder; + AMSextruder(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + ~AMSextruder(); +}; + +class AMSVirtualRoad : public wxWindow +{ +public: + AMSVirtualRoad(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); + ~AMSVirtualRoad(); + +private: + bool m_has_vams{ true }; + bool m_vams_loading{ false }; + wxColour m_current_color; + +public: + void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); + void SetHasVams(bool hvams) { m_has_vams = hvams; }; + void create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size); + void paintEvent(wxPaintEvent& evt); + void render(wxDC& dc); + void doRender(wxDC& dc); + void msw_rescale(); +}; + +/************************************************* +Description:AMSLib +**************************************************/ +class AMSLib : public wxWindow +{ +public: + AMSLib(wxWindow *parent, std::string ams_idx, Caninfo info); + ~AMSLib(); + void create(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); +public: + wxColour GetLibColour(); + Caninfo m_info; + MachineObject* m_obj = { nullptr }; + + std::string m_ams_id; + std::string m_slot_id; + + int m_can_index = 0; + AMSModel m_ams_model; + + void Update(Caninfo info, std::string ams_idx, bool refresh = true); + void UnableSelected() { m_unable_selected = true; }; + void EableSelected() { m_unable_selected = false; }; + void OnSelected(); + void UnSelected(); + bool is_selected() {return m_selected;}; + void post_event(wxCommandEvent &&event); + void show_kn_value(bool show) { m_show_kn = show; }; + void support_cali(bool sup) { m_support_cali = sup; Refresh(); }; + virtual bool Enable(bool enable = true); + void set_disable_mode(bool disable) { m_disable_mode = disable; } + void msw_rescale(); + void on_pass_road(bool pass); + +protected: + wxStaticBitmap *m_edit_bitmp = {nullptr}; + wxStaticBitmap *m_edit_bitmp_light = {nullptr}; + ScalableBitmap m_bitmap_editable; + ScalableBitmap m_bitmap_editable_light; + ScalableBitmap m_bitmap_readonly; + ScalableBitmap m_bitmap_readonly_light; + ScalableBitmap m_bitmap_transparent; + + ScalableBitmap m_bitmap_extra_tray_left; + ScalableBitmap m_bitmap_extra_tray_right; + + ScalableBitmap m_bitmap_extra_tray_left_hover; + ScalableBitmap m_bitmap_extra_tray_right_hover; + + ScalableBitmap m_bitmap_extra_tray_left_selected; + ScalableBitmap m_bitmap_extra_tray_right_selected; + + bool m_unable_selected = {false}; + bool m_enable = {false}; + bool m_selected = {false}; + bool m_hover = {false}; + bool m_show_kn = {false}; + bool m_support_cali = {false}; + bool transparent_changed = {false}; + + double m_radius = {4}; + wxColour m_border_color; + wxColour m_road_def_color; + wxColour m_lib_color; + bool m_disable_mode{ false }; + bool m_pass_road{false}; + + void on_enter_window(wxMouseEvent &evt); + void on_leave_window(wxMouseEvent &evt); + void on_left_down(wxMouseEvent &evt); + void paintEvent(wxPaintEvent &evt); + void render(wxDC &dc); + void render_extra_text(wxDC& dc); + void render_generic_text(wxDC& dc); + void doRender(wxDC& dc); + void render_extra_lib(wxDC& dc); + void render_generic_lib(wxDC& dc); +}; + +/************************************************* +Description:AMSRoad +**************************************************/ +class AMSRoad : public wxWindow +{ +public: + AMSRoad(); + AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + void create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + +public: + AMSinfo m_amsinfo; + Caninfo m_info; + int m_canindex = {0}; + AMSRoadMode m_rode_mode = {AMSRoadMode::AMS_ROAD_MODE_LEFT_RIGHT}; + std::vector m_pass_rode_mode = {AMSPassRoadMode::AMS_ROAD_MODE_NONE}; + bool m_selected = {false}; + int m_passroad_width = {6}; + double m_radius = {4}; + wxColour m_road_def_color; + wxColour m_road_color; + void Update(AMSinfo amsinfo, Caninfo info, int canindex, int maxcan); + + std::vector ams_humidity_img; + + + int m_humidity = { 0 }; + bool m_show_humidity = { false }; + bool m_vams_loading{false}; + AMSModel m_ams_model; + + void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); + void SetPassRoadColour(wxColour col); + void SetMode(AMSRoadMode mode); + void OnPassRoad(std::vector prord_list); + void UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step); + + void paintEvent(wxPaintEvent &evt); + void render(wxDC &dc); + void doRender(wxDC &dc); +}; + +/************************************************* +Description:AMSItem +**************************************************/ + +class AMSItem : public wxWindow +{ +public: + AMSItem(); + AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size = wxSize(14, 14), const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + + bool m_open = {false}; + void Open(); + void Close(); + + void Update(AMSinfo amsinfo); + void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); + void OnEnterWindow(wxMouseEvent &evt); + void OnLeaveWindow(wxMouseEvent &evt); + void OnSelected(); + void UnSelected(); + virtual bool Enable(bool enable = true); + + AMSinfo m_amsinfo; + +protected: + wxSize m_cube_size; + wxColour m_background_colour = {AMS_CONTROL_DEF_BLOCK_BK_COLOUR}; + int m_padding = {7}; + int m_space = {5}; + bool m_hover = {false}; + bool m_selected = {false}; + ScalableBitmap* m_ts_bitmap_cube; + + void paintEvent(wxPaintEvent &evt); + void render(wxDC &dc); + void doRender(wxDC &dc); + virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); +}; + +/************************************************* +Description:AmsCans +**************************************************/ +class Canrefreshs +{ +public: + wxString canID; + AMSrefresh *canrefresh; +}; + +class CanLibs +{ +public: + wxString canID; + AMSLib * canLib; +}; + +class CanRoads +{ +public: + wxString canID; + AMSRoad *canRoad; +}; + +WX_DEFINE_ARRAY(Canrefreshs *, CanrefreshsHash); +WX_DEFINE_ARRAY(CanLibs *, CanLibsHash); +WX_DEFINE_ARRAY(CanRoads *, CansRoadsHash); + +class AmsCans : public wxWindow +{ +public: + AmsCans(); + AmsCans(wxWindow *parent, AMSinfo info, AMSModel model); + + void Update(AMSinfo info); + void create(wxWindow *parent); + void AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer); + void SetDefSelectCan(); + void SelectCan(std::string canid); + void PlayRridLoading(wxString canid); + void StopRridLoading(wxString canid); + void msw_rescale(); + void show_sn_value(bool show); + void SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step); + void SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step); + void SetAmsStep(std::string can_id); + void paintEvent(wxPaintEvent& evt); + void render(wxDC& dc); + void doRender(wxDC& dc); + wxColour GetTagColr(wxString canid); + std::string GetCurrentCan(); + +public: + ScalableBitmap m_bitmap_extra_framework; + int m_canlib_selection = { -1 }; + int m_selection = { 0 }; + int m_can_count = { 0 }; + AMSModel m_ams_model; + std::string m_canlib_id; + + std::string m_road_canid; + wxColour m_road_colour; + + CanLibsHash m_can_lib_list; + CansRoadsHash m_can_road_list; + CanrefreshsHash m_can_refresh_list; + AMSinfo m_info; + wxBoxSizer * sizer_can = {nullptr}; + wxBoxSizer * sizer_can_middle = {nullptr}; + wxBoxSizer * sizer_can_left = {nullptr}; + wxBoxSizer * sizer_can_right = {nullptr}; + AMSPassRoadSTEP m_step = {AMSPassRoadSTEP ::AMS_ROAD_STEP_NONE}; +}; + +/************************************************* +Description:AmsCansWindow +**************************************************/ +class AmsCansWindow +{ +public: + wxString amsIndex; + AmsCans *amsCans; + bool m_disable_mode{ false }; + + void set_disable_mode(bool disable) { + m_disable_mode = disable; + for (auto can_lib : amsCans->m_can_lib_list) { + can_lib->canLib->set_disable_mode(disable); + } + for (auto can_refresh : amsCans->m_can_refresh_list) { + can_refresh->canrefresh->set_disable_mode(disable); + } + } +}; + +class AmsItems +{ +public: + wxString amsIndex; + AMSItem *amsItem; +}; + +class AMSextruders +{ +public: + wxString amsIndex; + AMSextruder *amsextruder; +}; + +WX_DEFINE_ARRAY(AmsCansWindow *, AmsCansHash); +WX_DEFINE_ARRAY(AmsItems *, AmsItemsHash); +WX_DEFINE_ARRAY(AMSextruders *, AMSextrudersHash); + + +wxDECLARE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_LOAD, SimpleEvent); +wxDECLARE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); +wxDECLARE_EVENT(EVT_AMS_SETTINGS, SimpleEvent); +wxDECLARE_EVENT(EVT_AMS_FILAMENT_BACKUP, SimpleEvent); +wxDECLARE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent); +wxDECLARE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_GUIDE_WIKI, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_RETRY, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_SHOW_HUMIDITY_TIPS, wxCommandEvent); +wxDECLARE_EVENT(EVT_AMS_UNSELETED_VAMS, wxCommandEvent); +wxDECLARE_EVENT(EVT_CLEAR_SPEED_CONTROL, wxCommandEvent); + +}} // namespace Slic3r::GUI + +#endif // !slic3r_GUI_amscontrol_hpp_ From d77ef4c8a397427f8d63860762c3b84587bce419 Mon Sep 17 00:00:00 2001 From: "tao.wang" Date: Mon, 22 Jul 2024 21:24:37 +0800 Subject: [PATCH 017/127] FIX:fixed some amscontrol issue jira:[for fix amscontrol issue] Change-Id: Id62ffd047403bf80f6aba732b8ce31d782bcea57 (cherry picked from commit 55898ab88ee844dd7da17d992ad8f79e439f96a0) --- src/slic3r/GUI/AMSMaterialsSetting.hpp | 1 + src/slic3r/GUI/StatusPanel.cpp | 46 ++++++++++++-------------- src/slic3r/GUI/Widgets/AMSControl.cpp | 3 +- src/slic3r/GUI/Widgets/AMSItem.cpp | 15 ++++++--- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.hpp b/src/slic3r/GUI/AMSMaterialsSetting.hpp index c058ac769f4..871c6ac26bd 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.hpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.hpp @@ -118,6 +118,7 @@ class AMSMaterialsSetting : public DPIDialog void on_picker_color(wxCommandEvent& color); MachineObject* obj{ nullptr }; int ams_id { 0 }; /* 0 ~ 3 */ + int slot_id { 0 }; /* 0 ~ 3 */ int tray_id { 0 }; /* 0 ~ 3 */ std::string ams_filament_id; diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 27560b1b040..5a437481039 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3686,34 +3686,26 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) if (obj) { m_filament_setting_dlg->obj = obj; - std::string ams_id; - int ams_id_int = 0; - int tray_id_int = 0; - int tray_id = event.GetInt(); - if (tray_id == VIRTUAL_TRAY_ID) { - ams_id = std::to_string(tray_id); - } - else{ - ams_id = std::to_string(tray_id / 4); - } - if (ams_id.compare(std::to_string(VIRTUAL_TRAY_ID)) == 0) { - tray_id_int = VIRTUAL_TRAY_ID; + int ams_id = event.GetInt(); + int slot_id = event.GetString().IsEmpty() ? 0 : std::stoi(event.GetString().ToStdString()); + + /* if (ams_id.compare(std::to_string(VIRTUAL_TRAY_MAIN_ID)) == 0) { + tray_id_int = VIRTUAL_TRAY_MAIN_ID; m_filament_setting_dlg->ams_id = ams_id_int; m_filament_setting_dlg->tray_id = tray_id_int; wxString k_val; wxString n_val; - k_val = wxString::Format("%.3f", obj->vt_tray.k); - n_val = wxString::Format("%.3f", obj->vt_tray.n); + k_val = wxString::Format("%.3f", obj->vt_slot[0].k); + n_val = wxString::Format("%.3f", obj->vt_slot[0].n); m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); m_filament_setting_dlg->Popup(wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString, k_val, n_val); - } else { + } else {*/ //std::string tray_id = event.GetString().ToStdString(); // m_ams_control->GetCurrentCan(ams_id); try { - ams_id_int = tray_id / 4; - tray_id_int = tray_id % 4; - m_filament_setting_dlg->ams_id = ams_id_int; - m_filament_setting_dlg->tray_id = tray_id_int; + m_filament_setting_dlg->ams_id = ams_id; + m_filament_setting_dlg->slot_id = slot_id; + //m_filament_setting_dlg->tray_id = 254; std::string sn_number; std::string filament; @@ -3721,9 +3713,9 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) std::string temp_min; wxString k_val; wxString n_val; - auto it = obj->amsList.find(std::to_string(ams_id_int)); + auto it = obj->amsList.find(std::to_string(ams_id)); if (it != obj->amsList.end()) { - auto tray_it = it->second->trayList.find(std::to_string(tray_id)); + auto tray_it = it->second->trayList.find(std::to_string(slot_id)); if (tray_it != it->second->trayList.end()) { k_val = wxString::Format("%.3f", tray_it->second->k); n_val = wxString::Format("%.3f", tray_it->second->n); @@ -3761,7 +3753,7 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) catch (...) { ; } - } + //} } } @@ -3776,12 +3768,16 @@ void StatusPanel::on_ext_spool_edit(wxCommandEvent &event) current_position_y = current_position_y + m_filament_setting_dlg->GetSize().GetHeight() > drect ? drect - m_filament_setting_dlg->GetSize().GetHeight() : current_position_y; if (obj) { - int tray_id = event.GetInt(); - int ams_id = tray_id; m_filament_setting_dlg->obj = obj; + + int ams_id = event.GetInt(); + int slot_id = event.GetString().IsEmpty() ? 0 : std::stoi(event.GetString().ToStdString()); + m_filament_setting_dlg->ams_id = ams_id; + m_filament_setting_dlg->slot_id = slot_id; + m_filament_setting_dlg->tray_id = VIRTUAL_TRAY_ID; + try { - m_filament_setting_dlg->tray_id = VIRTUAL_TRAY_ID; std::string sn_number; std::string filament; std::string temp_max; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 87580d42d4e..7b43f19affe 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -262,7 +262,8 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons auto vams_panel = new wxWindow(m_panel_virtual, wxID_ANY); vams_panel->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - m_vams_lib = new AMSLib(vams_panel, "0", m_vams_info); + m_vams_lib = new AMSLib(vams_panel, m_vams_info.can_id, m_vams_info); + m_vams_lib->m_slot_id = m_vams_info.can_id; m_vams_road = new AMSRoad(vams_panel, wxID_ANY, m_vams_info, -1, -1, wxDefaultPosition, AMS_CAN_ROAD_SIZE); m_vams_lib->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 64a3aa432a3..a82d4bfd3cf 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -100,7 +100,8 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo info.n = it->second->n; } } else { - info.can_id = i; + //info.can_id = i; + info.can_id = std::to_string(i); info.material_state = AMSCanType::AMS_CAN_TYPE_EMPTY; } cans.push_back(info); @@ -1332,9 +1333,10 @@ void AMSLib::Update(Caninfo info, std::string ams_idx, bool refresh) if (info.material_colour.Alpha() != 0 && info.material_colour.Alpha() != 255 && info.material_colour.Alpha() != 254 && m_info.material_colour != info.material_colour) { transparent_changed = true; } + m_info = info; m_ams_id = ams_idx; - Layout(); + m_slot_id = info.can_id; if (refresh) Refresh(); } @@ -1352,9 +1354,10 @@ void AMSLib::OnSelected() void AMSLib::post_event(wxCommandEvent &&event) { - int tray_id = atoi(m_ams_id.c_str()) * 4 + atoi(m_info.can_id.c_str()); + //int tray_id = atoi(m_ams_id.c_str()) * 4 + atoi(m_info.can_id.c_str()); //event.SetString(m_info.can_id); - event.SetInt(tray_id); + event.SetString(m_slot_id); + event.SetInt(std::stoi(m_ams_id)); event.SetEventObject(m_parent); wxPostEvent(m_parent, event); event.Skip(); @@ -1759,7 +1762,9 @@ void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size }); - m_panel_lib->m_ams_model = m_ams_model; + m_panel_lib->m_ams_model = m_ams_model; + m_panel_lib->m_ams_id = m_info.ams_id; + m_panel_lib->m_slot_id = caninfo.can_id; m_panel_lib->m_info.can_id = caninfo.can_id; m_panel_lib->m_can_index = canindex; From 693cf5f2f412be87bd5c9a963bad933e1d451754 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Tue, 5 Nov 2024 12:24:58 +0800 Subject: [PATCH 018/127] FIX: the default value is not correct and the pa profile not display in AMS setting dialog after switch nozzle diameter jira: 8620 Change-Id: If40bfe41ae13f5199f09baae3af09757498f1edf (cherry picked from commit f3064e223df468eb9901e65c8f0abab2dae91f15) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 858947854a5..979528e62e8 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -1127,6 +1127,10 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) m_input_k_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[cali_select_idx].k_value)); m_input_n_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[cali_select_idx].n_coef)); } + else { + m_input_k_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[0].k_value)); + m_input_n_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[0].n_coef)); + } } else { if (!ams_filament_id.empty()) { From 89a225a0e1220e47a9e9c214e40d51622b0eced2 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Fri, 27 Sep 2024 18:44:03 +0800 Subject: [PATCH 019/127] ENH: add default item for pa jira: none Change-Id: I4ad3bd094325bdbd1e6b013a91766214951dc032 (cherry picked from commit 0c772105f946121c292f92ab3ca1d050b898311b) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 83 +++++++++++++++++++------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 979528e62e8..c4a4be0e639 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -13,6 +13,31 @@ namespace Slic3r { namespace GUI { wxDEFINE_EVENT(EVT_SELECTED_COLOR, wxCommandEvent); +static void get_default_k_n_value(const std::string &filament_id, float &k, float &n) +{ + if (filament_id.compare("GFG00") == 0) { + // PETG + k = 0.04; + n = 1.0; + } else if (filament_id.compare("GFB00") == 0 || filament_id.compare("GFB50") == 0) { + // ABS + k = 0.04; + n = 1.0; + } else if (filament_id.compare("GFU01") == 0) { + // TPU + k = 0.2; + n = 1.0; + } else if (filament_id.compare("GFB01") == 0) { + // ASA + k = 0.04; + n = 1.0; + } else { + // PLA , other + k = 0.02; + n = 1.0; + } +} + static std::string float_to_string_with_precision(float value, int precision = 3) { std::stringstream stream; @@ -76,7 +101,7 @@ void AMSMaterialsSetting::create() m_sizer_button->Add(m_button_close, 0, wxALIGN_CENTER, 0); m_sizer_main->Add(m_panel_normal, 0, wxALL, FromDIP(2)); - + m_sizer_main->Add(m_panel_kn, 0, wxALL, FromDIP(2)); m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(24)); @@ -353,7 +378,7 @@ void AMSMaterialsSetting::create_panel_kn(wxWindow* parent) parent->SetSizer(sizer); } -void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt) +void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt) { auto size = GetSize(); wxPaintDC dc(this); @@ -368,7 +393,7 @@ AMSMaterialsSetting::~AMSMaterialsSetting() m_comboBox_cali_result->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_cali_result), NULL, this); } -void AMSMaterialsSetting::input_min_finish() +void AMSMaterialsSetting::input_min_finish() { if (m_input_nozzle_min->GetTextCtrl()->GetValue().empty()) return; @@ -423,7 +448,7 @@ void AMSMaterialsSetting::enable_confirm_button(bool en) } if (!m_is_third) { - m_tip_readonly->Hide(); + m_tip_readonly->Hide(); } else { if (!obj->is_support_filament_setting_inprinting) { @@ -530,7 +555,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) std::string vendor_name = vendor->values[0]; DeviceManager::check_filaments_in_blacklist(vendor_name, filamnt_type, in_blacklist, action, info); } - + if (in_blacklist) { if (action == "prohibition") { @@ -582,7 +607,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) obj->command_ams_filament_settings(ams_id, tray_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } } - + //reset param wxString k_text = m_input_k_val->GetTextCtrl()->GetValue(); wxString n_text = m_input_n_val->GetTextCtrl()->GetValue(); @@ -710,7 +735,7 @@ void AMSMaterialsSetting::on_picker_color(wxCommandEvent& event) set_color(wxColour(color_num>>24&0xFF, color_num>>16&0xFF, color_num>>8&0xFF, color_num&0xFF)); } -void AMSMaterialsSetting::on_clr_picker(wxMouseEvent &event) +void AMSMaterialsSetting::on_clr_picker(wxMouseEvent &event) { if(!m_is_third) return; @@ -769,8 +794,8 @@ void AMSMaterialsSetting::update_widgets() Layout(); } -bool AMSMaterialsSetting::Show(bool show) -{ +bool AMSMaterialsSetting::Show(bool show) +{ if (show) { m_button_confirm->SetMinSize(AMS_MATERIALS_SETTING_BUTTON_SIZE); m_input_nozzle_max->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20))); @@ -794,7 +819,7 @@ bool AMSMaterialsSetting::Show(bool show) Fit(); wxGetApp().UpdateDarkUI(this); } - return DPIDialog::Show(show); + return DPIDialog::Show(show); } void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_min, wxString temp_max, wxString k, wxString n) @@ -820,7 +845,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi stream << std::fixed << std::setprecision(1) << obj->nozzle_diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); - + if (preset_bundle) { BOOST_LOG_TRIVIAL(trace) << "system_preset_bundle filament number=" << preset_bundle->filaments.size(); for (auto filament_it = preset_bundle->filaments.begin(); filament_it != preset_bundle->filaments.end(); filament_it++) { @@ -832,7 +857,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi if (preset_bundle->filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) { continue; } - + ConfigOption * printer_opt = filament_it->config.option("compatible_printers"); ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); for (auto printer_str : printer_strs->values) { @@ -867,7 +892,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi if (filament_it->filament_id == ams_filament_id) { selection_idx = idx; bambu_filament_name = filament_it->alias; - + // update if nozzle_temperature_range is found ConfigOption *opt_min = filament_it->config.option("nozzle_temperature_range_low"); @@ -891,7 +916,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi } } } - + } } @@ -913,7 +938,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi else { m_readonly_filament->SetLabel(bambu_filament_name); } - + m_input_nozzle_min->GetTextCtrl()->SetValue(temp_min); m_input_nozzle_max->GetTextCtrl()->SetValue(temp_max); } @@ -934,7 +959,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi } m_button_reset->Show(); - //m_button_confirm->Show(); + //m_button_confirm->Show(); } m_comboBox_filament->Set(filament_items); @@ -1093,8 +1118,16 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) wxArrayString items; m_pa_profile_items.clear(); m_comboBox_cali_result->SetValue(wxEmptyString); - + if (obj->cali_version >= 0) { + // add default item + PACalibResult default_item; + default_item.filament_id = ams_filament_id; + default_item.cali_idx = -1; + get_default_k_n_value(ams_filament_id, default_item.k_value, default_item.n_coef); + m_pa_profile_items.emplace_back(default_item); + items.push_back(_L("Default")); + m_input_k_val->GetTextCtrl()->SetValue(wxEmptyString); std::vector cali_history = this->obj->pa_calib_tab; for (auto cali_item : cali_history) { @@ -1111,6 +1144,9 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (cali_select_idx >= 0) { m_comboBox_cali_result->SetSelection(cali_select_idx); } + else { + m_comboBox_cali_result->SetSelection(0); + } } else { Ams* selected_ams = this->obj->amsList[std::to_string(ams_id)]; @@ -1121,8 +1157,11 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (cali_select_idx >= 0) { m_comboBox_cali_result->SetSelection(cali_select_idx); } + else { + m_comboBox_cali_result->SetSelection(0); + } } - + if (cali_select_idx >= 0) { m_input_k_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[cali_select_idx].k_value)); m_input_n_val->GetTextCtrl()->SetValue(float_to_string_with_precision(m_pa_profile_items[cali_select_idx].n_coef)); @@ -1144,8 +1183,8 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) } } -void AMSMaterialsSetting::on_dpi_changed(const wxRect &suggested_rect) -{ +void AMSMaterialsSetting::on_dpi_changed(const wxRect &suggested_rect) +{ m_input_nozzle_max->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20))); m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20))); //m_clr_picker->msw_rescale(); @@ -1158,7 +1197,7 @@ void AMSMaterialsSetting::on_dpi_changed(const wxRect &suggested_rect) m_button_confirm->SetCornerRadius(FromDIP(12)); m_button_close->SetMinSize(AMS_MATERIALS_SETTING_BUTTON_SIZE); m_button_close->SetCornerRadius(FromDIP(12)); - this->Refresh(); + this->Refresh(); } ColorPicker::ColorPicker(wxWindow* parent, wxWindowID id, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/) @@ -1607,7 +1646,7 @@ void ColorPickerPopup::paintEvent(wxPaintEvent& evt) void ColorPickerPopup::OnDismiss() {} -void ColorPickerPopup::Popup() +void ColorPickerPopup::Popup() { PopupWindow::Popup(); } From 319827daec24c0f3e523aa50544d7c701161276b Mon Sep 17 00:00:00 2001 From: tao wang Date: Mon, 15 Jul 2024 21:54:21 +0800 Subject: [PATCH 020/127] ENH:support parse new print data jira:[for new print data] Change-Id: Iac6747e9ade690fcdf3b7b11239fe183bc7c3796 (cherry picked from commit 6c02c7bc8c77a481253e6c574f7bc13ff2cfcbdc) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 10 +- src/slic3r/GUI/CaliHistoryDialog.cpp | 6 +- src/slic3r/GUI/CalibrationWizard.cpp | 2 +- src/slic3r/GUI/CalibrationWizardCaliPage.cpp | 4 +- .../GUI/CalibrationWizardPresetPage.cpp | 4 +- src/slic3r/GUI/CalibrationWizardStartPage.cpp | 8 +- src/slic3r/GUI/DeviceManager.cpp | 361 +++++++++++++----- src/slic3r/GUI/DeviceManager.hpp | 56 ++- src/slic3r/GUI/PrintOptionsDialog.cpp | 11 +- src/slic3r/GUI/SelectMachine.cpp | 24 +- src/slic3r/GUI/StatusPanel.cpp | 12 +- src/slic3r/Utils/CalibUtils.cpp | 12 +- 12 files changed, 359 insertions(+), 151 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index c4a4be0e639..d9e3279d818 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -518,7 +518,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { else { PACalibIndexInfo select_index_info; select_index_info.tray_id = tray_id; - select_index_info.nozzle_diameter = obj->nozzle_diameter; + select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; select_index_info.cali_idx = -1; select_index_info.filament_id = ams_filament_id; CalibUtils::select_PA_calib_result(select_index_info); @@ -640,7 +640,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = tray_id; - select_index_info.nozzle_diameter = obj->nozzle_diameter; + select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); if (m_pa_profile_items.size() > 0 && cali_select_id >= 0) { @@ -679,7 +679,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = cali_tray_id; - select_index_info.nozzle_diameter = obj->nozzle_diameter; + select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); if (m_pa_profile_items.size() > 0 && cali_select_id >= 0) { @@ -842,7 +842,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi std::set filament_id_set; PresetBundle * preset_bundle = wxGetApp().preset_bundle; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << obj->nozzle_diameter; + stream << std::fixed << std::setprecision(1) << obj->m_nozzle_data.nozzles[0].diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); @@ -1008,7 +1008,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (preset_bundle) { std::ostringstream stream; if (obj) - stream << std::fixed << std::setprecision(1) << obj->nozzle_diameter; + stream << std::fixed << std::setprecision(1) << obj->m_nozzle_data.nozzles[0].diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index fd68b4bbf95..9c344338b99 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -180,7 +180,7 @@ void HistoryWindow::on_device_connected(MachineObject* obj) int selection = 1; for (int i = 0; i < nozzle_diameter_list.size(); i++) { m_comboBox_nozzle_dia->AppendString(wxString::Format("%1.1f mm", nozzle_diameter_list[i])); - if (abs(curr_obj->nozzle_diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(curr_obj->m_nozzle_data.nozzles[0].diameter - nozzle_diameter_list[i]) < 1e-3) { selection = i; } } @@ -506,7 +506,7 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject std::set filament_id_set; std::set printer_names; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << obj->nozzle_diameter; + stream << std::fixed << std::setprecision(1) << obj->m_nozzle_data.nozzles[0].diameter; std::string nozzle_diameter_str = stream.str(); for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) { @@ -623,7 +623,7 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const static std::array nozzle_diameter_list = {0.2f, 0.4f, 0.6f, 0.8f}; for (int i = 0; i < nozzle_diameter_list.size(); i++) { m_comboBox_nozzle_diameter->AppendString(wxString::Format("%1.1f mm", nozzle_diameter_list[i])); - if (abs(obj->nozzle_diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(obj->m_nozzle_data.nozzles[0].diameter - nozzle_diameter_list[i]) < 1e-3) { m_comboBox_nozzle_diameter->SetSelection(i); } } diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index 169e18cd09c..c37c3608a89 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -478,7 +478,7 @@ void PressureAdvanceWizard::update(MachineObject* obj) if (obj->cali_version != -1 && obj->cali_version != cali_version) { cali_version = obj->cali_version; PACalibExtruderInfo cali_info; - cali_info.nozzle_diameter = obj->nozzle_diameter; + cali_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; CalibUtils::emit_get_PA_calib_info(cali_info); } } diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp index cd63eaf38ab..8f438864d53 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp @@ -495,8 +495,8 @@ float CalibrationCaliPage::get_selected_calibration_nozzle_dia(MachineObject* ob return obj->cali_selected_nozzle_dia; // return default nozzle if nozzle diameter is set - if (obj->nozzle_diameter > 1e-3 && obj->nozzle_diameter < 10.0f) - return obj->nozzle_diameter; + if (obj->m_nozzle_data.nozzles[0].diameter > 1e-3 && obj->m_nozzle_data.nozzles[0].diameter < 10.0f) + return obj->m_nozzle_data.nozzles[0].diameter; // return 0.4 by default return 0.4; diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index 11d4f89eb20..20407be8e56 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -1505,7 +1505,7 @@ void CalibrationPresetPage::init_with_machine(MachineObject* obj) // set nozzle value from machine bool nozzle_is_set = false; for (int i = 0; i < NOZZLE_LIST_COUNT; i++) { - if (abs(obj->nozzle_diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(obj->m_nozzle_data.nozzles[0].diameter - nozzle_diameter_list[i]) < 1e-3) { if (m_comboBox_nozzle_dia->GetCount() > i) { m_comboBox_nozzle_dia->SetSelection(i); nozzle_is_set = true; @@ -1836,7 +1836,7 @@ Preset* CalibrationPresetPage::get_printer_preset(MachineObject* obj, float nozz std::string model_id = printer_it->get_current_printer_type(preset_bundle); std::string printer_type = obj->printer_type; - if (obj->is_support_p1s_plus) { printer_type = "C12"; } + if (obj->is_support_upgrade_kit && obj->installed_upgrade_kit) { printer_type = "C12"; } if (model_id.compare(printer_type) == 0 && printer_nozzle_vals && abs(printer_nozzle_vals->get_at(0) - nozzle_value) < 1e-3) { diff --git a/src/slic3r/GUI/CalibrationWizardStartPage.cpp b/src/slic3r/GUI/CalibrationWizardStartPage.cpp index c2e6c683b2a..02e9d911efc 100644 --- a/src/slic3r/GUI/CalibrationWizardStartPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardStartPage.cpp @@ -167,9 +167,8 @@ void CalibrationPAStartPage::on_device_connected(MachineObject* obj) m_action_panel->bind_button(CaliPageActionType::CALI_ACTION_AUTO_CALI, false); } - // is support auto cali - bool is_support_pa_auto = (obj->home_flag >> 16 & 1) == 1; - if (!is_support_pa_auto) { + + if (!obj->is_support_pa_calibration) { m_action_panel->show_button(CaliPageActionType::CALI_ACTION_AUTO_CALI, false); } } @@ -318,8 +317,7 @@ void CalibrationFlowRateStartPage::on_device_connected(MachineObject* obj) } //is support auto cali - bool is_support_flow_rate_auto = (obj->home_flag >> 15 & 1) == 1; - if (!is_support_flow_rate_auto) { + if (!obj->is_support_flow_calibration) { m_action_panel->show_button(CaliPageActionType::CALI_ACTION_AUTO_CALI, false); } } diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index e3bc7707bd7..ad14ba8205d 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -536,8 +536,6 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string reset(); /* temprature fields */ - nozzle_temp = 0.0f; - nozzle_temp_target = 0.0f; bed_temp = 0.0f; bed_temp_target = 0.0f; chamber_temp = 0.0f; @@ -584,6 +582,12 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string printing_speed_lvl = PrintingSpeedLevel::SPEED_LEVEL_INVALID; has_ipcam = true; // default true + + m_nozzle_data.current_nozzle_id = 0; + m_nozzle_data.target_nozzle_id = 0; + m_nozzle_data.total_nozzle_count = 1; + Nozzle nozzle; + m_nozzle_data.nozzles.push_back(nozzle); } MachineObject::~MachineObject() @@ -1393,7 +1397,7 @@ void MachineObject::parse_state_changed_event() void MachineObject::parse_status(int flag) { - is_220V_voltage = ((flag >> 3) & 0x1) != 0; + is_220V_voltage = ((flag >> 3) & 0x1) != 0; if (xcam_auto_recovery_hold_count > 0) xcam_auto_recovery_hold_count--; else { @@ -1409,35 +1413,38 @@ void MachineObject::parse_status(int flag) ams_auto_switch_filament_flag = ((flag >> 10) & 0x1) != 0; } + is_support_flow_calibration = ((flag >> 15) & 0x1) != 0; + is_support_pa_calibration = ((flag >> 16) & 0x1) != 0; + if (xcam_prompt_sound_hold_count > 0) xcam_prompt_sound_hold_count--; else { xcam_allow_prompt_sound = ((flag >> 17) & 0x1) != 0; } - if (((flag >> 18) & 0x1) != 0) { - is_support_prompt_sound = true; - } - + is_support_prompt_sound = ((flag >> 18) & 0x1) != 0; is_support_filament_tangle_detect = ((flag >> 19) & 0x1) != 0; - is_support_user_preset = ((flag >> 22) & 0x1) != 0; + if (xcam_filament_tangle_detect_count > 0) xcam_filament_tangle_detect_count--; else { xcam_filament_tangle_detect = ((flag >> 20) & 0x1) != 0; } - if(!is_support_motor_noise_cali){ + /*if(!is_support_motor_noise_cali){ is_support_motor_noise_cali = ((flag >> 21) & 0x1) != 0; - } + }*/ + is_support_motor_noise_cali = ((flag >> 21) & 0x1) != 0; + + is_support_user_preset = ((flag >> 22) & 0x1) != 0; is_support_nozzle_blob_detection = ((flag >> 25) & 0x1) != 0; nozzle_blob_detection_enabled = ((flag >> 24) & 0x1) != 0; is_support_air_print_detection = ((flag >> 29) & 0x1) != 0; ams_air_print_status = ((flag >> 28) & 0x1) != 0; - - if (!is_support_p1s_plus) { + + /*if (!is_support_p1s_plus) { auto supported_plus = ((flag >> 27) & 0x1) != 0; auto installed_plus = ((flag >> 26) & 0x1) != 0; @@ -1447,7 +1454,10 @@ void MachineObject::parse_status(int flag) else { is_support_p1s_plus = false; } - } + }*/ + + is_support_upgrade_kit = ((flag >> 27) & 0x1) != 0; + installed_upgrade_kit = ((flag >> 26) & 0x1) != 0; sdcard_state = MachineObject::SdcardState((flag >> 8) & 0x11); @@ -1836,28 +1846,6 @@ int MachineObject::command_ams_user_settings(int ams_id, bool start_read_opt, bo return this->publish_json(j.dump()); } -int MachineObject::command_ams_user_settings(int ams_id, AmsOptionType op, bool value) -{ - json j; - j["print"]["command"] = "ams_user_setting"; - j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - j["print"]["ams_id"] = ams_id; - if (op == AmsOptionType::AMS_OP_STARTUP_READ) { - j["print"]["startup_read_option"] = value; - ams_power_on_flag = value; - } else if (op == AmsOptionType::AMS_OP_TRAY_READ) { - j["print"]["tray_read_option"] = value; - ams_insert_flag = value; - } else if (op == AmsOptionType::AMS_OP_CALIBRATE_REMAIN) { - j["print"]["calibrate_remain_flag"] = value; - ams_calibrate_remain_flag = value; - } else { - return -1; - } - ams_user_setting_hold_count = HOLD_COUNT_MAX; - return this->publish_json(j.dump()); -} - int MachineObject::command_ams_calibrate(int ams_id) { std::string gcode_cmd = (boost::format("M620 C%1% \n") % ams_id).str(); @@ -2546,7 +2534,6 @@ void MachineObject::reset() last_mc_print_stage = -1; m_new_ver_list_exist = false; extruder_axis_status = LOAD; - nozzle_diameter = 0.0f; network_wired = false; dev_connection_name = ""; subscribe_counter = 3; @@ -2994,7 +2981,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("support_flow_calibration")) { if (jj["support_flow_calibration"].is_boolean()) { - is_support_flow_calibration = jj["support_flow_calibration"].get(); + is_support_auto_flow_calibration = jj["support_flow_calibration"].get(); } } @@ -3063,11 +3050,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } - //if (jj.contains("support_filament_tangle_detect")) { - // if (jj["support_filament_tangle_detect"].is_boolean()) { - // is_support_filament_tangle_detect = jj["support_filament_tangle_detect"].get(); - // } - //} + if (jj.contains("support_filament_tangle_detect")) { + if (jj["support_filament_tangle_detect"].is_boolean()) { + is_support_filament_tangle_detect = jj["support_filament_tangle_detect"].get(); + } + } if (jj.contains("support_1080dpi")) { if (jj["support_1080dpi"].is_boolean()) { @@ -3347,7 +3334,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) curr_task->task_progress = mc_print_percent; curr_task->printing_status = print_status; curr_task->task_id = jj["subtask_id"].get(); - } } @@ -3373,12 +3359,16 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } if (jj.contains("nozzle_temper")) { if (jj["nozzle_temper"].is_number()) { - nozzle_temp = jj["nozzle_temper"].get(); + if (m_nozzle_data.nozzles.size() == 1) { + m_nozzle_data.nozzles[0].temp = jj["nozzle_temper"].get(); + } } } if (jj.contains("nozzle_target_temper")) { if (jj["nozzle_target_temper"].is_number()) { - nozzle_temp_target = jj["nozzle_target_temper"].get(); + if (m_nozzle_data.nozzles.size() == 1) { + m_nozzle_data.nozzles[0].target_temp = jj["nozzle_temper"].get(); + } } } if (jj.contains("chamber_temper")) { @@ -3554,15 +3544,17 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (nozzle_setting_hold_count > 0) { nozzle_setting_hold_count--; } else { + float nozzle_diameter = 0.0f; if (jj["nozzle_diameter"].is_number_float()) { nozzle_diameter = jj["nozzle_diameter"].get(); } else if (jj["nozzle_diameter"].is_string()) { nozzle_diameter = string_to_float(jj["nozzle_diameter"].get()); } - } - + if (nozzle_diameter == 0.0f) {m_nozzle_data.nozzles[0].diameter = 0.4f;} + else {m_nozzle_data.nozzles[0].diameter = round(nozzle_diameter * 10) / 10;} + } } } catch(...) { @@ -3577,13 +3569,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } else { if (jj["nozzle_type"].is_string()) { - nozzle_type = jj["nozzle_type"].get(); + auto nozzle_type = jj["nozzle_type"].get(); + m_nozzle_data.nozzles[0].type = nozzle_type; } } } - else { - nozzle_type = ""; - } } catch (...) { ; @@ -3867,7 +3857,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } PresetBundle *preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << nozzle_diameter; + stream << std::fixed << std::setprecision(1) << DeviceManager::nozzle_diameter_conver(m_nozzle_data.nozzles[0].diameter); std::string nozzle_diameter_str = stream.str(); if (m_printer_preset_name.find(nozzle_diameter_str + " nozzle") == std::string::npos) update_printer_preset_name(nozzle_diameter_str); @@ -4833,44 +4823,12 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } - /*parse np*/ + /*parse new print data*/ try { - if (jj.contains("cfg") && jj.contains("fun") && jj.contains("aux") && jj.contains("stat")) { - is_enable_np = true; - } - else { - is_enable_np = false; - } - - if (jj.contains("device")) { - json const & device = jj["device"]; - - if (device.contains("nozzle")) { - json const & nozzle = device["nozzle"]; - - m_np_nozzle_data = NozzleData(); - m_np_nozzle_data.info = nozzle["info"].get(); - - - for (const auto& noz : nozzle.items()) { - std::string nozzle_id = noz.key(); - json const & ndata = noz.value(); - - Nozzle n; - if (ndata.contains("info")) {n.info = ndata["info"].get(); } - if (ndata.contains("snow")) {n.info = ndata["snow"].get(); } - if (ndata.contains("spre")) {n.info = ndata["spre"].get(); } - if (ndata.contains("star")) {n.info = ndata["star"].get(); } - if (ndata.contains("stat")) {n.info = ndata["stat"].get(); } - if (ndata.contains("temp")) {n.info = ndata["temp"].get(); } - m_np_nozzle_data.nozzle[nozzle_id] = n; - } - } - } + parse_new_info(jj); } - catch (...) - {} + catch (...){} } if (!key_field_only) { @@ -5386,9 +5344,199 @@ void MachineObject::update_printer_preset_name(const std::string &nozzle_diamete BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " update printer preset name failed "; } +void MachineObject::parse_new_info(json print) +{ + if (print.contains("cfg") && print.contains("fun") && print.contains("aux") && print.contains("stat")) { + is_enable_np = true; + BOOST_LOG_TRIVIAL(info) << "using new print data for parsing"; + } + else { + is_enable_np = false; + return; + } + + /*cfg*/ + std::string cfg = print["cfg"].get(); + + BOOST_LOG_TRIVIAL(info) << "new print data cfg = " << cfg; + + if(!cfg.empty()){ + if (ams_user_setting_hold_count > 0) ams_user_setting_hold_count--; + if (camera_recording_hold_count > 0) camera_recording_hold_count--; + if (camera_resolution_hold_count > 0) camera_resolution_hold_count--; + if (camera_timelapse_hold_count > 0) camera_timelapse_hold_count--; + //if (xcam_buildplate_marker_hold_count > 0) xcam_buildplate_marker_hold_count--;first_layer_inspector + if (xcam_first_layer_hold_count > 0) xcam_first_layer_hold_count--; + if (xcam_ai_monitoring_hold_count > 0) xcam_ai_monitoring_hold_count--; + if (xcam_auto_recovery_hold_count > 0) xcam_auto_recovery_hold_count--; + if (ams_print_option_count > 0) ams_print_option_count--; + if (xcam_prompt_sound_hold_count > 0) xcam_prompt_sound_hold_count--; + if (xcam_filament_tangle_detect_count > 0)xcam_filament_tangle_detect_count--; + if (nozzle_setting_hold_count > 0)nozzle_setting_hold_count--; + + + + ams_insert_flag = get_flag_bits(cfg, 0); + ams_power_on_flag = get_flag_bits(cfg, 1); + upgrade_force_upgrade = get_flag_bits(cfg, 2); + camera_recording_when_printing = get_flag_bits(cfg, 3); + camera_resolution = get_flag_bits(cfg, 4) == 0 ? "720p" : "1080p"; + //liveview_local = get_flag_bits(cfg, 5); todo zhanma + camera_timelapse = get_flag_bits(cfg, 6); + tutk_state = get_flag_bits(cfg, 7) == 1 ? "disable" : ""; + chamber_light = get_flag_bits(cfg, 8) == 1 ? LIGHT_EFFECT::LIGHT_EFFECT_ON : LIGHT_EFFECT::LIGHT_EFFECT_OFF; + printing_speed_lvl = (PrintingSpeedLevel)get_flag_bits(cfg, 9, 3); + //is_support_build_plate_marker_detect = get_flag_bits(cfg, 12); todo yangcong + + xcam_first_layer_inspector = get_flag_bits(cfg, 13); + + switch (get_flag_bits(cfg, 14, 2)) + { + case 0: + xcam_ai_monitoring_sensitivity = "never_halt"; + break; + case 1: + xcam_ai_monitoring_sensitivity = "low"; + break; + case 2: + xcam_ai_monitoring_sensitivity = "medium"; + break; + case 3: + xcam_ai_monitoring_sensitivity = "high"; + break; + } + + xcam_ai_monitoring = get_flag_bits(cfg, 16); + xcam_auto_recovery_step_loss = get_flag_bits(cfg, 17); + ams_calibrate_remain_flag = get_flag_bits(cfg, 18); + ams_auto_switch_filament_flag = get_flag_bits(cfg, 19); + xcam_allow_prompt_sound = get_flag_bits(cfg, 23); + xcam_filament_tangle_detect = get_flag_bits(cfg, 24); + nozzle_blob_detection_enabled = get_flag_bits(cfg, 25); + installed_upgrade_kit = get_flag_bits(cfg, 26); + } + + /*fun*/ + std::string fun = print["fun"].get(); + BOOST_LOG_TRIVIAL(info) << "new print data fun = " << fun; + + if (!fun.empty()) { + + is_support_agora = get_flag_bits(fun, 1); + if (is_support_agora) is_support_tunnel_mqtt = false; + + is_220V_voltage = get_flag_bits(fun, 3) == 0?false:true; + is_support_flow_calibration = get_flag_bits(fun, 6); + is_support_pa_calibration = get_flag_bits(fun, 7); + is_support_prompt_sound = get_flag_bits(fun, 8); + is_support_filament_tangle_detect = get_flag_bits(fun, 9); + is_support_motor_noise_cali = get_flag_bits(fun, 10); + is_support_user_preset = get_flag_bits(fun, 11); + is_support_nozzle_blob_detection = get_flag_bits(fun, 13); + is_support_upgrade_kit = get_flag_bits(cfg, 14); + } + + /*aux*/ + std::string aux = print["aux"].get(); + + BOOST_LOG_TRIVIAL(info) << "new print data aux = " << aux; + + if (!aux.empty()) { + //ams_exist_bits = get_flag_bits(aux, 8, 3); //todo yangcong + sdcard_state = MachineObject::SdcardState(get_flag_bits(aux, 12, 2)); + } + + /*stat*/ + std::string stat = print["stat"].get(); + + BOOST_LOG_TRIVIAL(info) << "new print data stat = " << stat; + + if (!stat.empty()) { + //sdcard_state = get_flag_bits(aux, 12, 2); todo yangcong + camera_recording = get_flag_bits(stat, 7); + } + + /*device*/ + if (print.contains("device")) { + json const& device = print["device"]; + + if (device.contains("type")) { + int type = device["type"]; //FDM:1<<0 Laser:1<< Cut:1<<2 + } + + if (device.contains("bed_temp")) { + bed_temp = get_flag_bits(device["bed_temp"].get(), 0, 15); + bed_temp_target = get_flag_bits(device["bed_temp"].get(), 16, 15); + } + + if (device.contains("cham_temp")) { + chamber_temp = get_flag_bits(device["cham_temp"].get(), 0, 15); + chamber_temp_target = get_flag_bits(device["cham_temp"].get(), 16, 15); + } + + if (device.contains("fan")) { + big_fan1_speed = get_flag_bits(device["fan"].get(), 0, 3); + big_fan2_speed = get_flag_bits(device["fan"].get(), 4, 3); + cooling_fan_speed = get_flag_bits(device["fan"].get(), 8, 3); + heatbreak_fan_speed = get_flag_bits(device["fan"].get(), 12, 3); + } + + if (device.contains("nozzle")) { + json const& nozzle = device["nozzle"]; + + m_nozzle_data = NozzleData(); + m_nozzle_data.current_nozzle_id = get_flag_bits(nozzle["info"].get(), 0, 3); + m_nozzle_data.target_nozzle_id = get_flag_bits(nozzle["info"].get(), 4, 3); + m_nozzle_data.total_nozzle_count = get_flag_bits(nozzle["info"].get(), 8, 3); + + + for (int i = 0; i < m_nozzle_data.total_nozzle_count; i++) { + + Nozzle nozzle_obj; + + std::string nozzle_id = std::to_string(i); + if (nozzle.contains(nozzle_id)) { + auto njon = nozzle[nozzle_id].get(); + + nozzle_obj.type = DeviceManager::nozzle_type_conver(get_flag_bits(njon["info"].get(), 0, 2)); + nozzle_obj.diameter = DeviceManager::nozzle_diameter_conver(get_flag_bits(njon["info"].get(), 3, 3)); + nozzle_obj.ext_has_filament = get_flag_bits(njon["info"].get(), 7); + nozzle_obj.buffer_has_filament = get_flag_bits(njon["info"].get(), 8); + nozzle_obj.flow_type = get_flag_bits(njon["info"].get(), 9, 2); + nozzle_obj.temp = get_flag_bits(njon["temp"].get(), 0, 15); + nozzle_obj.target_temp = get_flag_bits(njon["temp"].get(), 16, 15); + + AmsSlot spre; + spre.ams_id = std::to_string(get_flag_bits(njon["spre"].get(), 0, 8)); + spre.slot_id = std::to_string(get_flag_bits(njon["spre"].get(), 8, 8)); + + AmsSlot snow; + snow.ams_id = std::to_string(get_flag_bits(njon["snow"].get(), 0, 8)); + snow.slot_id = std::to_string(get_flag_bits(njon["snow"].get(), 8, 8)); + + AmsSlot star; + star.ams_id = std::to_string(get_flag_bits(njon["star"].get(), 0, 8)); + star.slot_id = std::to_string(get_flag_bits(njon["star"].get(), 8, 8)); + + nozzle_obj.spre = spre; + nozzle_obj.snow = snow; + nozzle_obj.star = star; + nozzle_obj.ams_stat = get_flag_bits(njon["stat"].get(), 0, 15); + nozzle_obj.rfid_stat = get_flag_bits(njon["stat"].get(), 16, 7); + } + + m_nozzle_data.nozzles.push_back(nozzle_obj); + } + } + } +} + bool DeviceManager::EnableMultiMachine = false; bool DeviceManager::key_field_only = false; +std::vector nozzle_diameter_list{ 0.2f,0.4f,0.6f,0.8f }; +std::vector nozzle_type_list{ "hardened_steel", "stainless_steel" }; + DeviceManager::DeviceManager(NetworkAgent* agent) { m_agent = agent; @@ -5456,6 +5604,45 @@ DeviceManager::~DeviceManager() userMachineList.clear(); } + +float DeviceManager::nozzle_diameter_conver(int diame) +{ + if (diame < nozzle_diameter_list.size() && diame >= 0) { + return nozzle_diameter_list[diame]; + } + return 0.4f; +} + +int DeviceManager::nozzle_diameter_conver(float diame) +{ + int index = -1; + for (int i = 0; i < nozzle_diameter_list.size(); i++) { + if (nozzle_diameter_list[i] == diame) { + index = i; + } + } + return index; +} + +std::string DeviceManager::nozzle_type_conver(int type) +{ + if (type < nozzle_type_list.size() && type >= 0) { + return nozzle_type_list[type]; + } + return ""; +} + +int DeviceManager::nozzle_type_conver(std::string& type) +{ + int index = -1; + for (int i = 0; i < nozzle_type_list.size(); i++) { + if (nozzle_type_list[i] == type) { + index = i; + } + } + return index; +} + void DeviceManager::set_agent(NetworkAgent* agent) { m_agent = agent; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index c55a9860b23..cd51613622d 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -135,20 +135,37 @@ enum ManualPaCaliMethod { PA_PATTERN, }; + +struct AmsSlot +{ + std::string ams_id; + std::string slot_id; +}; + struct Nozzle { - int info{0}; - int snow{0}; - int spre{0}; - int star{0}; - int stat{0}; + std::string type; //0-hardened_steel 1-stainless_steel + float diameter = {0.4f}; // 0-0.2mm 1-0.4mm 2-0.6 mm3-0.8mm + int exist{0}; //0-Not Installed 1-Wrong extruder 2-No enablement 3-Enable + int ext_has_filament{0}; + int buffer_has_filament{0}; + int flow_type{0};//0-common 1-high flow + int temp{0}; + int target_temp{0}; + AmsSlot spre; //tray_pre + AmsSlot snow; //tray_now + AmsSlot star; //tray_tar + int ams_stat{0}; ; + int rfid_stat{0}; ; }; struct NozzleData { - std::map nozzle; /*0 - main nozzle 1 - slave nozzle*/ - int info{0}; + int current_nozzle_id{0}; + int target_nozzle_id{0}; + int total_nozzle_count {0}; + std::vector nozzles; }; struct RatingInfo { @@ -438,9 +455,7 @@ class MachineObject std::string dev_id; bool local_use_ssl_for_mqtt { true }; bool local_use_ssl_for_ftp { true }; - float nozzle_diameter { 0.0f }; int subscribe_counter{3}; - std::string nozzle_type; std::string dev_connection_type; /* lan | cloud */ std::string connection_type() { return dev_connection_type; } std::string dev_connection_name; /* lan | eth */ @@ -563,8 +578,8 @@ class MachineObject int last_online_version = -1; /* temperature */ - float nozzle_temp; - float nozzle_temp_target; + //float nozzle_temp; + //float nozzle_temp_target; float bed_temp; float bed_temp_target; float chamber_temp; @@ -774,7 +789,9 @@ class MachineObject bool is_support_ai_monitoring {false}; bool is_support_lidar_calibration {false}; bool is_support_build_plate_marker_detect{false}; + bool is_support_pa_calibration{false}; bool is_support_flow_calibration{false}; + bool is_support_auto_flow_calibration{false}; bool is_support_print_without_sd{false}; bool is_support_print_all{false}; bool is_support_send_to_sdcard {false}; @@ -797,12 +814,14 @@ class MachineObject bool is_support_motor_noise_cali{false}; bool is_support_wait_sending_finish{false}; bool is_support_user_preset{false}; - bool is_support_p1s_plus{false}; + //bool is_support_p1s_plus{false}; bool is_support_nozzle_blob_detection{false}; bool is_support_air_print_detection{false}; bool is_support_filament_setting_inprinting{false}; bool is_support_agora{false}; + bool is_support_upgrade_kit{false}; + bool installed_upgrade_kit{false}; int nozzle_max_temperature = -1; int bed_temperature_limit = -1; @@ -890,7 +909,6 @@ class MachineObject int command_ams_switch(int tray_index, int old_temp = 210, int new_temp = 210); int command_ams_change_filament(int tray_id, int old_temp = 210, int new_temp = 210); int command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt, bool remain_flag = false); - int command_ams_user_settings(int ams_id, AmsOptionType op, bool value); int command_ams_switch_filament(bool switch_filament); int command_ams_air_print_detect(bool air_print_detect); int command_ams_calibrate(int ams_id); @@ -1000,14 +1018,17 @@ class MachineObject std::string get_string_from_fantype(FanType type); /*for more extruder*/ - bool is_enable_np{ false }; - NozzleData m_np_nozzle_data; + bool is_enable_np{ false }; + NozzleData m_nozzle_data; /* Device Filament Check */ std::set m_checked_filament; std::string m_printer_preset_name; std::map> m_filament_list; // filament_id, pair void update_filament_list(); + + /*for parse new info*/ + void parse_new_info(json print); int get_flag_bits(std::string str, int start, int count = 1); int get_flag_bits(int num, int start, int count = 1); void update_printer_preset_name(const std::string &nozzle_diameter_str); @@ -1034,6 +1055,11 @@ class DeviceManager void keep_alive(); void check_pushing(); + static float nozzle_diameter_conver(int diame); + static int nozzle_diameter_conver(float diame); + static std::string nozzle_type_conver(int type); + static int nozzle_type_conver(std::string& type); + MachineObject* get_default_machine(); MachineObject* get_local_selected_machine(); MachineObject* get_local_machine(std::string dev_id); diff --git a/src/slic3r/GUI/PrintOptionsDialog.cpp b/src/slic3r/GUI/PrintOptionsDialog.cpp index c22b62727a9..e0c9d1026eb 100644 --- a/src/slic3r/GUI/PrintOptionsDialog.cpp +++ b/src/slic3r/GUI/PrintOptionsDialog.cpp @@ -553,8 +553,8 @@ void PrinterPartsDialog::set_nozzle_diameter(wxCommandEvent& evt) auto nozzle_diameter = std::stof(nozzle_diameter_checkbox->GetStringSelection().ToStdString()); nozzle_diameter = round(nozzle_diameter * 10) / 10; - obj->nozzle_diameter = nozzle_diameter; - obj->nozzle_type = nozzle_type; + obj->m_nozzle_data.nozzles[0].diameter = nozzle_diameter; + obj->m_nozzle_data.nozzles[0].type = nozzle_type; obj->command_set_printer_nozzle(nozzle_type, nozzle_diameter); } @@ -578,12 +578,9 @@ bool PrinterPartsDialog::Show(bool show) wxGetApp().UpdateDlgDarkUI(this); CentreOnParent(); - auto type = obj->nozzle_type; - auto diameter = 0.4f; - if (obj->nozzle_diameter > 0) { - diameter = round(obj->nozzle_diameter * 10) / 10; - } + auto type = obj->m_nozzle_data.nozzles[0].type; + auto diameter = obj->m_nozzle_data.nozzles[0].diameter; nozzle_type_checkbox->Clear(); nozzle_diameter_checkbox->Clear(); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 0cd31183831..dfe4d7c8506 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1789,7 +1789,7 @@ wxWindow *SelectMachineDialog::create_item_checkbox(wxString title, wxWindow *pa void SelectMachineDialog::update_select_layout(MachineObject *obj) { - if (obj && obj->is_support_flow_calibration) { + if (obj && obj->is_support_auto_flow_calibration) { select_flow->Show(); } else { select_flow->Hide(); @@ -2450,14 +2450,14 @@ bool SelectMachineDialog::is_same_nozzle_diameters(std::string& tag_nozzle_type, preset_nozzle_type = "stainless_steel"; } - tag_nozzle_type = obj_->nozzle_type; + tag_nozzle_type = obj_->m_nozzle_data.nozzles[0].type; auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); if (opt_nozzle_diameters != nullptr) { for (auto i = 0; i < extruders.size(); i++) { auto extruder = extruders[i] - 1; preset_nozzle_diameters = float(opt_nozzle_diameters->get_at(extruder)); - if (preset_nozzle_diameters != obj_->nozzle_diameter) { + if (preset_nozzle_diameters != obj_->m_nozzle_data.nozzles[0].diameter) { is_same_nozzle_diameters = false; } } @@ -2487,10 +2487,10 @@ bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::s NozzleType nozzle_type = NozzleType::ntUndefine; - if (obj_->nozzle_type == "stainless_steel") { + if (obj_->m_nozzle_data.nozzles[0].type == "stainless_steel") { nozzle_type = NozzleType::ntStainlessSteel; } - else if (obj_->nozzle_type == "hardened_steel") { + else if (obj_->m_nozzle_data.nozzles[0].type == "hardened_steel") { nozzle_type = NozzleType::ntHardenedSteel; } @@ -2511,7 +2511,7 @@ bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::s return is_same_nozzle_type; } else { - tag_nozzle_type = obj_->nozzle_type; + tag_nozzle_type = DeviceManager::nozzle_type_conver(obj_->m_nozzle_data.nozzles[0].type); } iter++; @@ -2540,7 +2540,7 @@ bool SelectMachineDialog::is_same_printer_model() // Orca: ignore P1P -> P1S if (source_model != target_model) { if ((source_model == "C12" && target_model == "C11") || (source_model == "C11" && target_model == "C12") || - (obj_->is_support_p1s_plus && (source_model == "C12"))) { + ((obj_->is_support_upgrade_kit && obj_->installed_upgrade_kit) && (source_model == "C12"))) { return true; } @@ -2549,7 +2549,7 @@ bool SelectMachineDialog::is_same_printer_model() return false; } - if (obj_->is_support_p1s_plus) { + if (obj_->is_support_upgrade_kit && obj_->installed_upgrade_kit) { BOOST_LOG_TRIVIAL(info) << "printer_model: source = " << source_model; BOOST_LOG_TRIVIAL(info) << "printer_model: target = " << obj_->printer_type << " (plus)"; return false; @@ -2704,13 +2704,13 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) std::string filament_type; std::string tag_nozzle_type; - if (!obj_->nozzle_type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) { + if (!obj_->m_nozzle_data.nozzles[0].type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) { if (!is_same_nozzle_diameters(tag_nozzle_type, nozzle_diameter)) { has_slice_warnings = true; // is_printing_block = true; # Removed to allow nozzle overrides (to support non-standard nozzles) wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"),nozzle_diameter, ""); - wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.2f %s"), obj_->nozzle_diameter, ""); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj_->m_nozzle_data.nozzles[0].diameter, ""); confirm_text.push_back(ConfirmBeforeSendInfo(_L("Your nozzle diameter in sliced file is not consistent with memorized nozzle. If you changed your nozzle lately, please go to Device > Printer Parts to change settings.") + "\n " + nozzle_in_preset @@ -2721,9 +2721,9 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) if (!is_same_nozzle_type(filament_type, tag_nozzle_type)){ has_slice_warnings = true; is_printing_block = true; - nozzle_diameter = wxString::Format("%.1f", obj_->nozzle_diameter).ToStdString(); + nozzle_diameter = wxString::Format("%.1f", obj_->m_nozzle_data.nozzles[0].diameter).ToStdString(); - wxString nozzle_in_preset = wxString::Format(_L("Printing high temperature material(%s material) with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->nozzle_type)); + wxString nozzle_in_preset = wxString::Format(_L("Printing high temperature material(%s material) with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->m_nozzle_data.nozzles[0].type)); confirm_text.push_back(ConfirmBeforeSendInfo(nozzle_in_preset, ConfirmBeforeSendInfo::InfoLevel::Warning)); } } diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 5a437481039..6e613fc097a 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2378,7 +2378,7 @@ void StatusPanel::update_temp_ctrl(MachineObject *obj) m_tempCtrl_bed->SetIconNormal(); } - m_tempCtrl_nozzle->SetCurrTemp((int) obj->nozzle_temp); + m_tempCtrl_nozzle->SetCurrTemp((int) obj->m_nozzle_data.nozzles[0].temp); if (obj->nozzle_max_temperature > -1) { if (m_tempCtrl_nozzle) m_tempCtrl_nozzle->SetMaxTemp(obj->nozzle_max_temperature); } @@ -2389,10 +2389,10 @@ void StatusPanel::update_temp_ctrl(MachineObject *obj) if (m_temp_nozzle_timeout > 0) { m_temp_nozzle_timeout--; } else { - if (!nozzle_temp_input) { m_tempCtrl_nozzle->SetTagTemp((int) obj->nozzle_temp_target); } + if (!nozzle_temp_input) { m_tempCtrl_nozzle->SetTagTemp((int) obj->m_nozzle_data.nozzles[0].target_temp); } } - if ((obj->nozzle_temp_target - obj->nozzle_temp) >= TEMP_THRESHOLD_VAL) { + if ((obj->m_nozzle_data.nozzles[0].target_temp - obj->m_nozzle_data.nozzles[0].temp) >= TEMP_THRESHOLD_VAL) { m_tempCtrl_nozzle->SetIconActive(); } else { m_tempCtrl_nozzle->SetIconNormal(); @@ -2587,7 +2587,7 @@ void StatusPanel::update_ams(MachineObject *obj) if (obj->cali_version != -1 && last_cali_version != obj->cali_version) { last_cali_version = obj->cali_version; PACalibExtruderInfo cali_info; - cali_info.nozzle_diameter = obj->nozzle_diameter; + cali_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; CalibUtils::emit_get_PA_calib_info(cali_info); } @@ -3410,7 +3410,7 @@ void StatusPanel::axis_ctrl_e_hint(bool up_down) void StatusPanel::on_axis_ctrl_e_up_10(wxCommandEvent &event) { if (obj) { - if (obj->nozzle_temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) + if (obj->m_nozzle_data.nozzles[0].temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) obj->command_axis_control("E", 1.0, -10.0f, 900); else axis_ctrl_e_hint(true); @@ -3420,7 +3420,7 @@ void StatusPanel::on_axis_ctrl_e_up_10(wxCommandEvent &event) void StatusPanel::on_axis_ctrl_e_down_10(wxCommandEvent &event) { if (obj) { - if (obj->nozzle_temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) + if (obj->m_nozzle_data.nozzles[0].temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) obj->command_axis_control("E", 1.0, 10.0f, 900); else axis_ctrl_e_hint(false); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index f67e6f95348..57c01077a10 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -97,9 +97,9 @@ static bool is_same_nozzle_diameters(const DynamicPrintConfig &full_config, cons auto opt_nozzle_diameters = full_config.option("nozzle_diameter"); if (opt_nozzle_diameters != nullptr) { float preset_nozzle_diameter = opt_nozzle_diameters->get_at(0); - if (preset_nozzle_diameter != obj->nozzle_diameter) { + if (preset_nozzle_diameter != obj->m_nozzle_data.nozzles[0].diameter) { wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"), wxString::Format("%.1f", preset_nozzle_diameter).ToStdString(), to_wstring_name(nozzle_type)); - wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->nozzle_diameter, to_wstring_name(obj->nozzle_type)); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->m_nozzle_data.nozzles[0].diameter, DeviceManager::nozzle_type_conver(obj->m_nozzle_data.nozzles[0].diameter)); error_msg = _L("Your nozzle diameter in preset is not consistent with memorized nozzle diameter. Did you change your nozzle lately?") + "\n " + nozzle_in_preset + "\n " + nozzle_in_printer + "\n"; @@ -119,9 +119,9 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac NozzleType nozzle_type = NozzleType::ntUndefine; - if (obj->nozzle_type == "stainless_steel") { + if (obj->m_nozzle_data.nozzles[0].type == "stainless_steel") { nozzle_type = NozzleType::ntStainlessSteel; - } else if (obj->nozzle_type == "hardened_steel") { + } else if (obj->m_nozzle_data.nozzles[0].type == "hardened_steel") { nozzle_type = NozzleType::ntHardenedSteel; } @@ -131,7 +131,7 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) { BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: printer_nozzle_hrc = " << printer_nozzle_hrc << ", filament_nozzle_hrc = " << filament_nozzle_hrc; std::string filament_type = full_config.opt_string("filament_type", 0); - error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(obj->nozzle_type)); + error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(obj->m_nozzle_data.nozzles[0].type)); error_msg += "\n"; MessageDialog msg_dlg(nullptr, error_msg, wxEmptyString, wxICON_WARNING | wxOK | wxCANCEL); @@ -164,7 +164,7 @@ static bool check_nozzle_diameter_and_type(const DynamicPrintConfig &full_config } // P1P/S - if (obj->nozzle_type.empty()) + if (obj->m_nozzle_data.nozzles[0].type.empty()) return true; if (!is_same_nozzle_diameters(full_config, obj, error_msg)) From 45dd04c8990ceaac0741e47a37c6d7041d33d21e Mon Sep 17 00:00:00 2001 From: "tao.wang" Date: Tue, 23 Jul 2024 20:46:19 +0800 Subject: [PATCH 021/127] ENH:support set ams filament jira:[for 2nozzle setting] Change-Id: Ib9e20bcdf6d8ea1bf5dd5e8624a68730e05e69ad (cherry picked from commit 78c592819473b1291d1bec1126ccbf7d86bb17d5) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 6 +- src/slic3r/GUI/DeviceManager.cpp | 14 ++-- src/slic3r/GUI/StatusPanel.cpp | 100 ++++++++++--------------- 3 files changed, 51 insertions(+), 69 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index d9e3279d818..1ac038a3b2a 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -604,7 +604,11 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) obj->command_ams_filament_settings(ams_id, VIRTUAL_TRAY_ID, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else { - obj->command_ams_filament_settings(ams_id, tray_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + if (obj->is_enable_np) { + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + } else { + obj->command_ams_filament_settings(ams_id, ams_id * 4 + slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + } } } diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index ad14ba8205d..6e0dd4dc88c 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4366,8 +4366,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) ; } } - for (auto &filament_id : need_checked_filament_id) - m_checked_filament.insert(filament_id); + + /*parse new print data*/ + try { + parse_new_info(jj); + } catch (...) {} #pragma endregion } else if (jj["command"].get() == "gcode_line") { //ack of gcode_line @@ -4822,13 +4825,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } } - - /*parse new print data*/ - try - { - parse_new_info(jj); - } - catch (...){} } if (!key_field_only) { diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 6e613fc097a..076d9ca76d4 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3690,70 +3690,52 @@ void StatusPanel::on_filament_edit(wxCommandEvent &event) int ams_id = event.GetInt(); int slot_id = event.GetString().IsEmpty() ? 0 : std::stoi(event.GetString().ToStdString()); - /* if (ams_id.compare(std::to_string(VIRTUAL_TRAY_MAIN_ID)) == 0) { - tray_id_int = VIRTUAL_TRAY_MAIN_ID; - m_filament_setting_dlg->ams_id = ams_id_int; - m_filament_setting_dlg->tray_id = tray_id_int; - wxString k_val; - wxString n_val; - k_val = wxString::Format("%.3f", obj->vt_slot[0].k); - n_val = wxString::Format("%.3f", obj->vt_slot[0].n); - m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); - m_filament_setting_dlg->Popup(wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString, k_val, n_val); - } else {*/ - //std::string tray_id = event.GetString().ToStdString(); // m_ams_control->GetCurrentCan(ams_id); - try { - m_filament_setting_dlg->ams_id = ams_id; - m_filament_setting_dlg->slot_id = slot_id; - //m_filament_setting_dlg->tray_id = 254; - - std::string sn_number; - std::string filament; - std::string temp_max; - std::string temp_min; - wxString k_val; - wxString n_val; - auto it = obj->amsList.find(std::to_string(ams_id)); - if (it != obj->amsList.end()) { - auto tray_it = it->second->trayList.find(std::to_string(slot_id)); - if (tray_it != it->second->trayList.end()) { - k_val = wxString::Format("%.3f", tray_it->second->k); - n_val = wxString::Format("%.3f", tray_it->second->n); - wxColor color = AmsTray::decode_color(tray_it->second->color); - //m_filament_setting_dlg->set_color(color); - - std::vector cols; - for (auto col : tray_it->second->cols) { - cols.push_back( AmsTray::decode_color(col)); - } - m_filament_setting_dlg->set_ctype(tray_it->second->ctype); - m_filament_setting_dlg->ams_filament_id = tray_it->second->setting_id; + try { + m_filament_setting_dlg->ams_id = ams_id; + m_filament_setting_dlg->slot_id = slot_id; - if (m_filament_setting_dlg->ams_filament_id.empty()) { - m_filament_setting_dlg->set_empty_color(color); - } - else { - m_filament_setting_dlg->set_color(color); - m_filament_setting_dlg->set_colors(cols); - } + std::string sn_number; + std::string filament; + std::string temp_max; + std::string temp_min; + wxString k_val; + wxString n_val; + auto it = obj->amsList.find(std::to_string(ams_id)); + if (it != obj->amsList.end()) { + auto tray_it = it->second->trayList.find(std::to_string(slot_id)); + if (tray_it != it->second->trayList.end()) { + k_val = wxString::Format("%.3f", tray_it->second->k); + n_val = wxString::Format("%.3f", tray_it->second->n); + wxColor color = AmsTray::decode_color(tray_it->second->color); + // m_filament_setting_dlg->set_color(color); + + std::vector cols; + for (auto col : tray_it->second->cols) { cols.push_back(AmsTray::decode_color(col)); } + m_filament_setting_dlg->set_ctype(tray_it->second->ctype); + m_filament_setting_dlg->ams_filament_id = tray_it->second->setting_id; + + if (m_filament_setting_dlg->ams_filament_id.empty()) { + m_filament_setting_dlg->set_empty_color(color); + } else { + m_filament_setting_dlg->set_color(color); + m_filament_setting_dlg->set_colors(cols); + } - m_filament_setting_dlg->m_is_third = !MachineObject::is_bbl_filament(tray_it->second->tag_uid); - if (!m_filament_setting_dlg->m_is_third) { - sn_number = tray_it->second->uuid; - filament = tray_it->second->sub_brands; - temp_max = tray_it->second->nozzle_temp_max; - temp_min = tray_it->second->nozzle_temp_min; - } + m_filament_setting_dlg->m_is_third = !MachineObject::is_bbl_filament(tray_it->second->tag_uid); + if (!m_filament_setting_dlg->m_is_third) { + sn_number = tray_it->second->uuid; + filament = tray_it->second->sub_brands; + temp_max = tray_it->second->nozzle_temp_max; + temp_min = tray_it->second->nozzle_temp_min; } } - - m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); - m_filament_setting_dlg->Popup(filament, sn_number, temp_min, temp_max, k_val, n_val); - } - catch (...) { - ; } - //} + + m_filament_setting_dlg->Move(wxPoint(current_position_x, current_position_y)); + m_filament_setting_dlg->Popup(filament, sn_number, temp_min, temp_max, k_val, n_val); + } catch (...) { + ; + } } } From d71b1b57e2fadc0b54001c8eb27fb23cfc6115c0 Mon Sep 17 00:00:00 2001 From: tao wang Date: Wed, 21 Aug 2024 21:16:00 +0800 Subject: [PATCH 022/127] FIX:fixed unable to reset ams filament setting jira:[for reset ams] Change-Id: I9f2f8be4a6e16b05191e4076db4e3f53d7601db4 (cherry picked from commit 3119a84eb2af58b89113f03c4393d1062423f930) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 1ac038a3b2a..7ef83896d27 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -487,10 +487,23 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { if (obj) { // set filament if (is_virtual_tray()) { - obj->command_ams_filament_settings(255, VIRTUAL_TRAY_ID, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + auto tar_tray = VIRTUAL_TRAY_ID; + + if (!obj->is_enable_np) { + tar_tray = VIRTUAL_TRAY_ID; + } + else { + tar_tray = 0; + } + obj->command_ams_filament_settings(ams_id, tar_tray, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else if(m_is_third){ - obj->command_ams_filament_settings(ams_id, tray_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + if (obj->is_enable_np) { + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + } + else { + obj->command_ams_filament_settings(ams_id, ams_id * 4 + slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + } } // set k / n value From 1f08ec6072149540f61040b87488a5fe46e8f647 Mon Sep 17 00:00:00 2001 From: tao wang Date: Thu, 22 Aug 2024 20:29:37 +0800 Subject: [PATCH 023/127] FIX:use old tray_id for set ams filament jira:[ams setting] Change-Id: I965f532fbd590b501b40c2cc812d6d02054b3628 (cherry picked from commit ee3cb45b4d49d05417a6a4735e2cdd5050bc35c5) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 7ef83896d27..401719b5dd2 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -502,7 +502,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else { - obj->command_ams_filament_settings(ams_id, ams_id * 4 + slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } } @@ -620,7 +620,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->is_enable_np) { obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else { - obj->command_ams_filament_settings(ams_id, ams_id * 4 + slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } } } From 500d1835a8cfdd1c48df8d86650b7dad5c3accfe Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Fri, 23 Aug 2024 09:29:17 +0800 Subject: [PATCH 024/127] FIX: add filament_id when reset ams setting jira: none Change-Id: Iedd2eec94bd1e41a51cededc06b304a2e29ef808 (cherry picked from commit 4c6316b98137dc230c6a0c2093ffb290c09ccef7) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 401719b5dd2..7b76a473242 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -484,6 +484,19 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { char col_buf[10]; sprintf(col_buf, "%02X%02X%02XFF", (int)color.Red(), (int)color.Green(), (int)color.Blue()); + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + if (preset_bundle) { + for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { + auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()]; + std::string filament_id = filament_item.filament_id; + if (it->filament_id.compare(filament_id) == 0) { + ams_filament_id = it->filament_id; + ams_setting_id = it->setting_id; + break; + } + } + } + if (obj) { // set filament if (is_virtual_tray()) { From 11cc9643520c0362d51750aa2e71983695f19151 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Mon, 26 Aug 2024 11:49:15 +0800 Subject: [PATCH 025/127] FIX: pa default item add filament_id jira: none Change-Id: Icfc24390e62cc1eca7e670311dc88502cea16fd7 (cherry picked from commit fb72d19a44d3b916920373acb7dd359282c1b750) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 7b76a473242..9bf27eaaf6c 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -484,14 +484,14 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { char col_buf[10]; sprintf(col_buf, "%02X%02X%02XFF", (int)color.Red(), (int)color.Green(), (int)color.Blue()); + std::string selected_ams_id; PresetBundle *preset_bundle = wxGetApp().preset_bundle; if (preset_bundle) { for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { auto filament_item = map_filament_items[m_comboBox_filament->GetValue().ToStdString()]; std::string filament_id = filament_item.filament_id; if (it->filament_id.compare(filament_id) == 0) { - ams_filament_id = it->filament_id; - ams_setting_id = it->setting_id; + selected_ams_id = it->filament_id; break; } } @@ -546,7 +546,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { select_index_info.tray_id = tray_id; select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; select_index_info.cali_idx = -1; - select_index_info.filament_id = ams_filament_id; + select_index_info.filament_id = selected_ams_id; CalibUtils::select_PA_calib_result(select_index_info); } } @@ -712,7 +712,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); - if (m_pa_profile_items.size() > 0 && cali_select_id >= 0) { + if (m_pa_profile_items.size() > 0 && cali_select_id > 0) { select_index_info.cali_idx = m_pa_profile_items[cali_select_id].cali_idx; select_index_info.filament_id = m_pa_profile_items[cali_select_id].filament_id; } @@ -1154,6 +1154,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) PACalibResult default_item; default_item.filament_id = ams_filament_id; default_item.cali_idx = -1; + default_item.filament_id = ams_filament_id; get_default_k_n_value(ams_filament_id, default_item.k_value, default_item.n_coef); m_pa_profile_items.emplace_back(default_item); items.push_back(_L("Default")); From 8a89c159db6fd13bd5f30f4d95fc88feee82694f Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Mon, 26 Aug 2024 15:16:15 +0800 Subject: [PATCH 026/127] FIX: modify for virtual slot when multi_extruder jira: none Change-Id: Ic7284018ecb44e24536788b05dba572b96460e66 (cherry picked from commit 52e890fba1584bf9687a24ee46890c00f531e383) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 11 ++++-- src/slic3r/GUI/CalibrationWizard.cpp | 36 ++++++++++++++++--- src/slic3r/GUI/CalibrationWizard.hpp | 7 ++-- .../GUI/CalibrationWizardPresetPage.cpp | 2 +- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 9bf27eaaf6c..ec27e55cff1 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -667,9 +667,14 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) ; } + auto vt_tray = ams_id; + if (!obj->is_enable_np) { + vt_tray = VIRTUAL_TRAY_ID; + } + if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; - select_index_info.tray_id = tray_id; + select_index_info.tray_id = vt_tray; select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); @@ -685,7 +690,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) CalibUtils::select_PA_calib_result(select_index_info); } else { - obj->command_extrusion_cali_set(VIRTUAL_TRAY_ID, "", "", k, n); + obj->command_extrusion_cali_set(vt_tray, "", "", k, n); } } else { @@ -1169,7 +1174,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) } m_comboBox_cali_result->Set(items); - if (tray_id == VIRTUAL_TRAY_ID) { + if (ams_id == VIRTUAL_TRAY_ID) { AmsTray selected_tray = this->obj->vt_tray; cali_select_idx = CalibUtils::get_selected_calib_idx(m_pa_profile_items,selected_tray.cali_idx); if (cali_select_idx >= 0) { diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index c37c3608a89..bc7500827ad 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -17,7 +17,6 @@ wxDEFINE_EVENT(EVT_CALIBRATION_JOB_FINISHED, wxCommandEvent); static const wxString NA_STR = _L("N/A"); static const float MIN_PA_K_VALUE_STEP = 0.001; static const int MAX_PA_HISTORY_RESULTS_NUMS = 16; - std::map get_cached_selected_filament(MachineObject* obj) { std::map selected_filament_map; if (!obj) return selected_filament_map; @@ -103,6 +102,26 @@ CalibrationWizard::~CalibrationWizard() ; } +void CalibrationWizard::get_tray_ams_and_slot_id(int in_tray_id, int &ams_id, int &slot_id, int &tray_id) +{ + assert(curr_obj); + if (!curr_obj) + return; + + if (in_tray_id == VIRTUAL_TRAY_ID || in_tray_id == VIRTUAL_TRAY_ID) { + ams_id = in_tray_id; + slot_id = 0; + tray_id = ams_id; + if (!curr_obj->is_enable_np) + tray_id = VIRTUAL_TRAY_ID; + } + else { + ams_id = in_tray_id / 4; + slot_id = in_tray_id % 4; + tray_id = in_tray_id; + } +} + void CalibrationWizard::on_cali_job_finished(wxCommandEvent& event) { this->on_cali_job_finished(event.GetString()); @@ -591,7 +610,7 @@ void PressureAdvanceWizard::on_cali_start() } X1CCalibInfos::X1CCalibInfo calib_info; - calib_info.tray_id = item.first; + get_tray_ams_and_slot_id(item.first, calib_info.ams_id, calib_info.slot_id, calib_info.tray_id); calib_info.nozzle_diameter = nozzle_dia; calib_info.filament_id = item.second->filament_id; calib_info.setting_id = item.second->setting_id; @@ -623,9 +642,11 @@ void PressureAdvanceWizard::on_cali_start() return; } + int selected_tray_id = 0; CalibInfo calib_info; calib_info.dev_id = curr_obj->dev_id; - calib_info.select_ams = "[" + std::to_string(selected_filaments.begin()->first) + "]"; + get_tray_ams_and_slot_id(selected_filaments.begin()->first, calib_info.ams_id, calib_info.slot_id, selected_tray_id); + calib_info.select_ams = "[" + std::to_string(selected_tray_id) + "]"; Preset *preset = selected_filaments.begin()->second; Preset * temp_filament_preset = new Preset(preset->type, preset->name + "_temp"); temp_filament_preset->config = preset->config; @@ -991,6 +1012,7 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow X1CCalibInfos::X1CCalibInfo calib_info; calib_info.tray_id = item.first; + get_tray_ams_and_slot_id(item.first, calib_info.ams_id, calib_info.slot_id, calib_info.tray_id); calib_info.nozzle_diameter = nozzle_dia; calib_info.filament_id = item.second->filament_id; calib_info.setting_id = item.second->setting_id; @@ -1041,7 +1063,9 @@ void FlowRateWizard::on_cali_start(CaliPresetStage stage, float cali_value, Flow } if (!selected_filaments.empty()) { - calib_info.select_ams = "[" + std::to_string(selected_filaments.begin()->first) + "]"; + int selected_tray_id = 0; + get_tray_ams_and_slot_id(selected_filaments.begin()->first, calib_info.ams_id, calib_info.slot_id, selected_tray_id); + calib_info.select_ams = "[" + std::to_string(selected_tray_id) + "]"; Preset* preset = selected_filaments.begin()->second; temp_filament_preset = new Preset(preset->type, preset->name + "_temp"); temp_filament_preset->config = preset->config; @@ -1417,7 +1441,9 @@ void MaxVolumetricSpeedWizard::on_cali_start() calib_info.params = params; calib_info.dev_id = curr_obj->dev_id; if (!selected_filaments.empty()) { - calib_info.select_ams = "[" + std::to_string(selected_filaments.begin()->first) + "]"; + int selected_tray_id = 0; + get_tray_ams_and_slot_id(selected_filaments.begin()->first, calib_info.ams_id, calib_info.slot_id, selected_tray_id); + calib_info.select_ams = "[" + std::to_string(selected_tray_id) + "]"; calib_info.filament_prest = selected_filaments.begin()->second; } diff --git a/src/slic3r/GUI/CalibrationWizard.hpp b/src/slic3r/GUI/CalibrationWizard.hpp index 34550b4b7fa..28bf9376926 100644 --- a/src/slic3r/GUI/CalibrationWizard.hpp +++ b/src/slic3r/GUI/CalibrationWizard.hpp @@ -19,7 +19,7 @@ class CalibrationWizardPageStep CalibrationWizardPageStep(CalibrationWizardPage* data) { page = data; } - + CalibrationWizardPageStep* prev { nullptr }; CalibrationWizardPageStep* next { nullptr }; CalibrationWizardPage* page { nullptr }; @@ -57,7 +57,7 @@ class CalibrationWizard : public wxPanel { } virtual void set_cali_method(CalibrationMethod method); - + CalibMode get_calibration_mode() { return m_mode; } bool save_preset(const std::string &old_preset_name, const std::string &new_preset_name, const std::map &key_values, wxString& message); @@ -71,6 +71,7 @@ class CalibrationWizard : public wxPanel { protected: void on_cali_go_home(); + void get_tray_ams_and_slot_id(int in_tray_id, int &ams_id, int &slot_id, int &tray_id); protected: /* wx widgets*/ @@ -89,7 +90,7 @@ class CalibrationWizard : public wxPanel { CalibrationWizardPageStep* preset_step { nullptr }; CalibrationWizardPageStep* cali_step { nullptr }; CalibrationWizardPageStep* save_step { nullptr }; - + CalibrationWizardPageStep* cali_coarse_step { nullptr }; CalibrationWizardPageStep* coarse_save_step { nullptr }; CalibrationWizardPageStep* cali_fine_step { nullptr }; diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index 20407be8e56..ecb7deea446 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -1780,7 +1780,7 @@ void CalibrationPresetPage::update_filament_combobox(std::string ams_id) empty_config.set_key_value("filament_colour", new ConfigOptionStrings{ "" }); empty_config.set_key_value("filament_exist", new ConfigOptionBools{ false }); - /* update virtual tray combo box*/ + // update virtual tray combo box m_virtual_tray_comboBox->update_from_preset(); auto it = std::find_if(filament_ams_list.begin(), filament_ams_list.end(), [](auto& entry) { return entry.first == VIRTUAL_TRAY_ID; From e9e661a9dbfc9658cbe6598d7b8e5619ee712e67 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Tue, 27 Aug 2024 20:18:31 +0800 Subject: [PATCH 027/127] FIX:when ams cali_idx is unknown, use default item 2. use transparent color when reset filament jira: 7946 Change-Id: I129dc0e6b7244cad3b5e61e1bc423938f4b92d7e (cherry picked from commit 7f473c2027e31458664e184645cf46f8e9b5d307) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index ec27e55cff1..2d948b1b460 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -482,7 +482,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { long nozzle_temp_max_int = 0; wxColour color = *wxWHITE; char col_buf[10]; - sprintf(col_buf, "%02X%02X%02XFF", (int)color.Red(), (int)color.Green(), (int)color.Blue()); + sprintf(col_buf, "%02X%02X%02X00", (int)color.Red(), (int)color.Green(), (int)color.Blue()); std::string selected_ams_id; PresetBundle *preset_bundle = wxGetApp().preset_bundle; @@ -1190,12 +1190,12 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) AmsTray* selected_tray = selected_ams->trayList[std::to_string(tray_id)]; if(!selected_tray) return; cali_select_idx = CalibUtils::get_selected_calib_idx(m_pa_profile_items, selected_tray->cali_idx); - if (cali_select_idx >= 0) { - m_comboBox_cali_result->SetSelection(cali_select_idx); - } - else { - m_comboBox_cali_result->SetSelection(0); + if (cali_select_idx < 0) { + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_status_error: cannot find pa profile, ams_id = " << ams_id + << ", slot_id = " << slot_id << ", cali_idx = " << selected_tray->cali_idx; + cali_select_idx = 0; } + m_comboBox_cali_result->SetSelection(cali_select_idx); } if (cali_select_idx >= 0) { From df3fe1491ad3dd7c0e8174f3b81d1b4a2450f00a Mon Sep 17 00:00:00 2001 From: "hang.xu" Date: Thu, 29 Aug 2024 19:01:00 +0800 Subject: [PATCH 028/127] FIX: crash when select filament in device jira: STUDIO-7972 Change-Id: Ice9e7360fbfe0c07bd49bbd696bb3cfb662e94e4 (cherry picked from commit 4c644d47157dd5cc403d6a1640c5874b99b10c4a) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 2d948b1b460..30d5dbf2a2f 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -1185,17 +1185,21 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) } } else { - Ams* selected_ams = this->obj->amsList[std::to_string(ams_id)]; - if(!selected_ams) return; - AmsTray* selected_tray = selected_ams->trayList[std::to_string(tray_id)]; - if(!selected_tray) return; - cali_select_idx = CalibUtils::get_selected_calib_idx(m_pa_profile_items, selected_tray->cali_idx); - if (cali_select_idx < 0) { - BOOST_LOG_TRIVIAL(info) << "extrusion_cali_status_error: cannot find pa profile, ams_id = " << ams_id - << ", slot_id = " << slot_id << ", cali_idx = " << selected_tray->cali_idx; - cali_select_idx = 0; + if (this->obj->amsList.find(std::to_string(ams_id)) != this->obj->amsList.end()) { + Ams* selected_ams = this->obj->amsList[std::to_string(ams_id)]; + if (!selected_ams) + return; + AmsTray* selected_tray = selected_ams->trayList[std::to_string(slot_id)]; + if (!selected_tray) + return; + cali_select_idx = CalibUtils::get_selected_calib_idx(m_pa_profile_items, selected_tray->cali_idx); + if (cali_select_idx < 0) { + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_status_error: cannot find pa profile, ams_id = " << ams_id + << ", slot_id = " << slot_id << ", cali_idx = " << selected_tray->cali_idx; + cali_select_idx = 0; + } + m_comboBox_cali_result->SetSelection(cali_select_idx); } - m_comboBox_cali_result->SetSelection(cali_select_idx); } if (cali_select_idx >= 0) { From 72fa3fbb26e14d8902a7060cfac0e6eb8636635f Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Mon, 14 Oct 2024 18:29:58 +0800 Subject: [PATCH 029/127] FIX: modify color to empty string when reset filament jira: none Change-Id: I3a32dc8307ec5d65c8c5b7b05a5bc1e2d7d2b5b7 (cherry picked from commit a0b563dc8fbddd201198dd073471887d104a58cb) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 30d5dbf2a2f..5b22114fde8 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -483,6 +483,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { wxColour color = *wxWHITE; char col_buf[10]; sprintf(col_buf, "%02X%02X%02X00", (int)color.Red(), (int)color.Green(), (int)color.Blue()); + std::string color_str; // reset use empty string std::string selected_ams_id; PresetBundle *preset_bundle = wxGetApp().preset_bundle; @@ -508,14 +509,14 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { else { tar_tray = 0; } - obj->command_ams_filament_settings(ams_id, tar_tray, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + obj->command_ams_filament_settings(ams_id, tar_tray, ams_filament_id, ams_setting_id, color_str, m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else if(m_is_third){ if (obj->is_enable_np) { - obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, color_str, m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } else { - obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, color_str, m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } } From 2db5cae51fe9e4a82ee1f705f2fb271e608c3a10 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Mon, 14 Oct 2024 20:20:15 +0800 Subject: [PATCH 030/127] FIX: crash when sending print with empty ams_id jira: none Change-Id: I89dc87af28b45c69eac86810444de2519dfccd08 (cherry picked from commit f53e00ec6d9350046df4b9dc70cec75039b6d5d1) --- src/slic3r/GUI/SelectMachine.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index dfe4d7c8506..c1c10444048 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -2038,8 +2038,14 @@ bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, try { - mapping_item_v1["ams_id"] = std::stoi(m_ams_mapping_result[k].ams_id); - mapping_item_v1["slot_id"] = std::stoi(m_ams_mapping_result[k].slot_id); + if (m_ams_mapping_result[k].ams_id.empty() || m_ams_mapping_result[k].slot_id.empty()) { // invalid case + mapping_item_v1["ams_id"] = VIRTUAL_TRAY_ID; + mapping_item_v1["slot_id"] = VIRTUAL_TRAY_ID; + } + else { + mapping_item_v1["ams_id"] = std::stoi(m_ams_mapping_result[k].ams_id); + mapping_item_v1["slot_id"] = std::stoi(m_ams_mapping_result[k].slot_id); + } } catch (...) { From 7c5dee1eda14fb7a06cf65f9d5c337dc6eecea57 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Tue, 5 Nov 2024 20:14:57 +0800 Subject: [PATCH 031/127] ENH: support auto pa cali for multi_extruder printer jira: none Change-Id: I835a0e20de81f9af7c40983e00bdb37ea6c95a68 (cherry picked from commit 4e387d4ace4332a7c2b6c0ab695b80a51597d0c7) --- src/libslic3r/calib.hpp | 1 + src/slic3r/GUI/AMSMaterialsSetting.cpp | 12 + src/slic3r/GUI/CaliHistoryDialog.cpp | 1 + src/slic3r/GUI/CalibrationWizardSavePage.cpp | 261 +++++++++++++++++-- src/slic3r/GUI/CalibrationWizardSavePage.hpp | 5 +- src/slic3r/GUI/DeviceManager.cpp | 47 +++- src/slic3r/GUI/Widgets/Label.cpp | 6 +- src/slic3r/GUI/Widgets/Label.hpp | 4 +- src/slic3r/Utils/CalibUtils.cpp | 10 + src/slic3r/Utils/CalibUtils.hpp | 1 + 10 files changed, 322 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index e862cf7b5c1..b0cea424107 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -140,6 +140,7 @@ struct PACalibExtruderInfo NozzleVolumeType nozzle_volume_type; float nozzle_diameter; std::string filament_id = ""; + bool use_nozzle_volume_type{true}; }; struct PACalibTabInfo diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 5b22114fde8..f7028c42c65 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -1155,6 +1155,15 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) m_pa_profile_items.clear(); m_comboBox_cali_result->SetValue(wxEmptyString); + int extruder_id = obj->get_extruder_id_by_ams_id(std::to_string(ams_id)); + NozzleVolumeType nozzle_volume_type = NozzleVolumeType::nvtNormal; + if (obj->m_extder_data.extders[extruder_id].current_nozzle_flow_type == NozzleFlowType::NONE_FLOWTYPE) { + MessageDialog dlg(nullptr, _L("There are unset nozzle types. Please set the nozzle types of all extruders before synchronizing."), _L("Warning"), wxICON_WARNING | wxOK); + dlg.ShowModal(); + } + else { + nozzle_volume_type = NozzleVolumeType(obj->m_extder_data.extders[extruder_id].current_nozzle_flow_type - 1); + } if (obj->cali_version >= 0) { // add default item PACalibResult default_item; @@ -1169,6 +1178,9 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) std::vector cali_history = this->obj->pa_calib_tab; for (auto cali_item : cali_history) { if (cali_item.filament_id == ams_filament_id) { + if (obj->is_multi_extruders() && (cali_item.extruder_id != extruder_id || cali_item.nozzle_volume_type != nozzle_volume_type)) { + continue; + } items.push_back(from_u8(cali_item.name)); m_pa_profile_items.push_back(cali_item); } diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 9c344338b99..22f84e43e02 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -232,6 +232,7 @@ void HistoryWindow::reqeust_history_result(MachineObject* obj) if (nozzle_value > 0) { PACalibExtruderInfo cali_info; cali_info.nozzle_diameter = nozzle_value; + cali_info.use_nozzle_volume_type = false; CalibUtils::emit_get_PA_calib_infos(cali_info); m_tips->SetLabel(_L("Refreshing the historical Flow Dynamics Calibration records")); BOOST_LOG_TRIVIAL(info) << "request calib history"; diff --git a/src/slic3r/GUI/CalibrationWizardSavePage.cpp b/src/slic3r/GUI/CalibrationWizardSavePage.cpp index 4d9fb67a5e0..3f524e1d302 100644 --- a/src/slic3r/GUI/CalibrationWizardSavePage.cpp +++ b/src/slic3r/GUI/CalibrationWizardSavePage.cpp @@ -6,6 +6,8 @@ namespace Slic3r { namespace GUI { +#define CALIBRATION_SAVE_AMS_NAME_SIZE wxSize(FromDIP(20), FromDIP(24)) +#define CALIBRATION_SAVE_NUMBER_INPUT_SIZE wxSize(FromDIP(100), FromDIP(24)) #define CALIBRATION_SAVE_INPUT_SIZE wxSize(FromDIP(240), FromDIP(24)) #define FLOW_RATE_MAX_VALUE 1.15 @@ -56,7 +58,7 @@ static wxString get_default_name(wxString filament_name, CalibMode mode){ return filament_name; } -static wxString get_tray_name_by_tray_id(int tray_id) +static wxString get_tray_name_by_tray_id(int tray_id) { wxString tray_name; if (tray_id == VIRTUAL_TRAY_ID) { @@ -125,14 +127,14 @@ CaliPASaveAutoPanel::CaliPASaveAutoPanel( const wxPoint& pos, const wxSize& size, long style) - : wxPanel(parent, id, pos, size, style) + : wxPanel(parent, id, pos, size, style) { SetBackgroundColour(*wxWHITE); m_top_sizer = new wxBoxSizer(wxVERTICAL); - + create_panel(this); - + this->SetSizer(m_top_sizer); m_top_sizer->Fit(this); } @@ -200,6 +202,11 @@ std::vector> CaliPASaveAutoPanel::default_naming(std void CaliPASaveAutoPanel::sync_cali_result(const std::vector& cali_result, const std::vector& history_result) { + if (m_obj && m_obj->is_multi_extruders()) { + sync_cali_result_for_multi_extruder(cali_result, history_result); + return; + } + m_history_results = history_result; m_calib_results.clear(); for (auto& item : cali_result) { @@ -391,7 +398,7 @@ void CaliPASaveAutoPanel::save_to_result_from_widgets(wxWindow* window, bool* ou } m_calib_results[tray_id].name = into_u8(name); } - + auto childern = window->GetChildren(); for (auto child : childern) { save_to_result_from_widgets(child, out_is_valid, out_msg); @@ -444,6 +451,230 @@ bool CaliPASaveAutoPanel::get_result(std::vector& out_result) { } } +void CaliPASaveAutoPanel::sync_cali_result_for_multi_extruder(const std::vector& cali_result, const std::vector& history_result) +{ + if (!m_obj) + return; + + m_is_all_failed = true; + bool part_failed = false; + if (cali_result.empty()) + part_failed = true; + + m_history_results = history_result; + m_calib_results.clear(); + for (auto &item : cali_result) { + if (item.confidence == 0) { + int tray_id = 4 * item.ams_id + item.slot_id; + m_calib_results[tray_id] = item; + } + } + m_grid_panel->DestroyChildren(); + auto grid_sizer = new wxBoxSizer(wxHORIZONTAL); + const int COLUMN_GAP = FromDIP(10); + const int ROW_GAP = FromDIP(10); + + wxStaticBoxSizer* left_sizer = new wxStaticBoxSizer(wxVERTICAL, m_grid_panel, "Left extruder"); + wxStaticBoxSizer* right_sizer = new wxStaticBoxSizer(wxVERTICAL, m_grid_panel, "Right extruder"); + grid_sizer->Add(left_sizer); + grid_sizer->AddSpacer(COLUMN_GAP); + grid_sizer->Add(right_sizer); + + wxFlexGridSizer *left_grid_sizer = new wxFlexGridSizer(3, COLUMN_GAP, ROW_GAP); + wxFlexGridSizer *right_grid_sizer = new wxFlexGridSizer(3, COLUMN_GAP, ROW_GAP); + left_sizer->Add(left_grid_sizer); + right_sizer->Add(right_grid_sizer); + + // main extruder + { + left_grid_sizer->Add(new wxStaticText(m_grid_panel, wxID_ANY, ""), 1, wxEXPAND); // fill empty space + + auto brand_title = new Label(m_grid_panel, _L("Name"), 0, CALIBRATION_SAVE_INPUT_SIZE); + brand_title->SetFont(Label::Head_14); + left_grid_sizer->Add(brand_title, 1, wxALIGN_CENTER); + + auto k_title = new Label(m_grid_panel, _L("Factor K"), 0, CALIBRATION_SAVE_NUMBER_INPUT_SIZE); + k_title->SetFont(Label::Head_14); + left_grid_sizer->Add(k_title, 1, wxALIGN_CENTER); + } + + // deputy extruder + { + right_grid_sizer->Add(new wxStaticText(m_grid_panel, wxID_ANY, ""), 1, wxEXPAND); // fill empty space + + auto brand_title = new Label(m_grid_panel, _L("Name"), 0, CALIBRATION_SAVE_INPUT_SIZE); + brand_title->SetFont(Label::Head_14); + right_grid_sizer->Add(brand_title, 1, wxALIGN_CENTER); + + auto k_title = new Label(m_grid_panel, _L("Factor K"), 0, CALIBRATION_SAVE_NUMBER_INPUT_SIZE); + k_title->SetFont(Label::Head_14); + right_grid_sizer->Add(k_title, 1, wxALIGN_CENTER); + } + + std::vector> preset_names; + for (auto &info : m_obj->selected_cali_preset) { + preset_names.push_back({info.tray_id, info.name}); + } + preset_names = default_naming(preset_names); + + bool left_first_add_item = true; + bool right_first_add_item = true; + for (auto &item : cali_result) { + bool result_failed = false; + if (item.confidence != 0) { + result_failed = true; + part_failed = true; + } else { + m_is_all_failed = false; + } + + //wxBoxSizer *item_data_sizer = new wxBoxSizer(wxHORIZONTAL); + auto tray_title = new Label(m_grid_panel, "", 0, CALIBRATION_SAVE_AMS_NAME_SIZE); + tray_title->SetFont(Label::Head_14); + wxString tray_name = get_tray_name_by_tray_id(item.tray_id); + tray_title->SetLabel(tray_name); + + auto k_value = new GridTextInput(m_grid_panel, "", "", CALIBRATION_SAVE_NUMBER_INPUT_SIZE, item.tray_id, GridTextInputType::K); + auto n_value = new GridTextInput(m_grid_panel, "", "", CALIBRATION_SAVE_NUMBER_INPUT_SIZE, item.tray_id, GridTextInputType::N); + k_value->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + n_value->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + auto k_value_failed = new Label(m_grid_panel, _L("Failed")); + auto n_value_failed = new Label(m_grid_panel, _L("Failed")); + + auto comboBox_tray_name = new GridComboBox(m_grid_panel, CALIBRATION_SAVE_INPUT_SIZE, item.tray_id); + auto tray_name_failed = new Label(m_grid_panel, " - "); + wxArrayString selections; + static std::vector filtered_results; + filtered_results.clear(); + for (auto history : history_result) { + if (history.filament_id == item.filament_id + && history.extruder_id == item.extruder_id + && history.nozzle_volume_type == item.nozzle_volume_type + && history.nozzle_diameter == item.nozzle_diameter) { + filtered_results.push_back(history); + selections.push_back(from_u8(history.name)); + } + } + comboBox_tray_name->Set(selections); + + auto set_edit_mode = [this, k_value, n_value, k_value_failed, n_value_failed, comboBox_tray_name, tray_name_failed](std::string str) { + if (str == "normal") { + comboBox_tray_name->Show(); + tray_name_failed->Show(false); + k_value->Show(); + n_value->Show(); + k_value_failed->Show(false); + n_value_failed->Show(false); + } + if (str == "failed") { + comboBox_tray_name->Show(false); + tray_name_failed->Show(); + k_value->Show(false); + n_value->Show(false); + k_value_failed->Show(); + n_value_failed->Show(); + } + + // hide n value + n_value->Hide(); + n_value_failed->Hide(); + + m_grid_panel->Layout(); + m_grid_panel->Update(); + }; + + if (!result_failed) { + set_edit_mode("normal"); + + auto k_str = wxString::Format("%.3f", item.k_value); + auto n_str = wxString::Format("%.3f", item.n_coef); + k_value->GetTextCtrl()->SetValue(k_str); + n_value->GetTextCtrl()->SetValue(n_str); + + for (auto &name : preset_names) { + if (item.tray_id == name.first) { comboBox_tray_name->SetValue(from_u8(name.second)); } + } + + comboBox_tray_name->Bind(wxEVT_COMBOBOX, [this, comboBox_tray_name, k_value, n_value](auto &e) { + int selection = comboBox_tray_name->GetSelection(); + auto history = filtered_results[selection]; + }); + } else { + set_edit_mode("failed"); + } + + if ((m_obj->is_main_extruder_on_left() && item.extruder_id == 0) + || (!m_obj->is_main_extruder_on_left() && item.extruder_id == 1)) { + if (left_first_add_item) { + wxString title_name = left_sizer->GetStaticBox()->GetLabel(); + title_name += " - "; + title_name += get_nozzle_volume_type_name(item.nozzle_volume_type); + left_sizer->GetStaticBox()->SetLabel(title_name); + left_first_add_item = false; + } + + left_grid_sizer->Add(tray_title, 1, wxEXPAND); + + if (comboBox_tray_name->IsShown()) { + left_grid_sizer->Add(comboBox_tray_name, 1, wxEXPAND); + } else { + left_grid_sizer->Add(tray_name_failed, 1, wxEXPAND); + } + + if (k_value->IsShown()) { + left_grid_sizer->Add(k_value, 1, wxEXPAND); + } else { + left_grid_sizer->Add(k_value_failed, 1, wxEXPAND); + } + } + else { + if (right_first_add_item) { + wxString title_name = right_sizer->GetStaticBox()->GetLabel(); + title_name += " - "; + title_name += get_nozzle_volume_type_name(item.nozzle_volume_type); + right_sizer->GetStaticBox()->SetLabel(title_name); + right_first_add_item = false; + } + right_grid_sizer->Add(tray_title, 1, wxEXPAND); + + if (comboBox_tray_name->IsShown()) { + right_grid_sizer->Add(comboBox_tray_name, 1, wxEXPAND); + } else { + right_grid_sizer->Add(tray_name_failed, 1, wxEXPAND); + } + + if (k_value->IsShown()) { + right_grid_sizer->Add(k_value, 1, wxEXPAND); + } else { + right_grid_sizer->Add(k_value_failed, 1, wxEXPAND); + } + } + } + + if (left_first_add_item) + left_sizer->Show(false); + if (right_first_add_item) + right_sizer->Show(false); + + m_grid_panel->SetSizer(grid_sizer, true); + m_grid_panel->Bind(wxEVT_LEFT_DOWN, [this](auto &e) { SetFocusIgnoringChildren(); }); + + if (part_failed) { + m_part_failed_panel->Show(); + m_complete_text_panel->Show(); + if (m_is_all_failed) { + m_complete_text_panel->Hide(); + } + } else { + m_complete_text_panel->Show(); + m_part_failed_panel->Hide(); + } + + wxGetApp().UpdateDarkUIWin(this); + + Layout(); +} + CaliPASaveManualPanel::CaliPASaveManualPanel( wxWindow* parent, wxWindowID id, @@ -521,7 +752,7 @@ void CaliPASaveManualPanel::create_panel(wxWindow* parent) } void CaliPASaveManualPanel::set_save_img() { - if (wxGetApp().app_config->get_language_code() == "zh-cn") { + if (wxGetApp().app_config->get_language_code() == "zh-cn") { m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result_CN", 330)); } else { m_picture_panel->set_bmp(ScalableBitmap(this, "fd_calibration_manual_result", 330)); @@ -778,19 +1009,19 @@ void CaliSavePresetValuePanel::set_save_name_title(const wxString& title) { m_save_name_title->SetLabel(title); } -void CaliSavePresetValuePanel::get_value(double& value) -{ - m_input_value->GetTextCtrl()->GetValue().ToDouble(&value); +void CaliSavePresetValuePanel::get_value(double& value) +{ + m_input_value->GetTextCtrl()->GetValue().ToDouble(&value); } void CaliSavePresetValuePanel::get_save_name(std::string& name) -{ - name = into_u8(m_input_name->GetTextCtrl()->GetValue()); +{ + name = into_u8(m_input_name->GetTextCtrl()->GetValue()); } void CaliSavePresetValuePanel::set_save_name(const std::string& name) -{ - m_input_name->GetTextCtrl()->SetValue(name); +{ + m_input_name->GetTextCtrl()->SetValue(name); } void CaliSavePresetValuePanel::msw_rescale() @@ -1307,7 +1538,7 @@ void CalibrationFlowCoarseSavePage::create_page(wxWindow* parent) } void CalibrationFlowCoarseSavePage::set_save_img() { - if (wxGetApp().app_config->get_language_code() == "zh-cn") { + if (wxGetApp().app_config->get_language_code() == "zh-cn") { m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse_result_CN", 350)); } else { m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_coarse_result", 350)); @@ -1491,7 +1722,7 @@ void CalibrationFlowFineSavePage::create_page(wxWindow* parent) } void CalibrationFlowFineSavePage::set_save_img() { - if (wxGetApp().app_config->get_language_code() == "zh-cn") { + if (wxGetApp().app_config->get_language_code() == "zh-cn") { m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine_result_CN", 350)); } else { m_picture_panel->set_bmp(ScalableBitmap(this, "flow_rate_calibration_fine_result", 350)); diff --git a/src/slic3r/GUI/CalibrationWizardSavePage.hpp b/src/slic3r/GUI/CalibrationWizardSavePage.hpp index 6b76b22acb3..aa63a75a187 100644 --- a/src/slic3r/GUI/CalibrationWizardSavePage.hpp +++ b/src/slic3r/GUI/CalibrationWizardSavePage.hpp @@ -98,6 +98,9 @@ class CaliPASaveAutoPanel : public wxPanel bool get_result(std::vector& out_result); bool is_all_failed() { return m_is_all_failed; } +protected: + void sync_cali_result_for_multi_extruder(const std::vector &cali_result, const std::vector &history_result); + protected: wxBoxSizer* m_top_sizer; wxPanel* m_complete_text_panel; @@ -218,7 +221,7 @@ class CalibrationFlowX1SavePage : public CalibrationCommonSavePage bool is_all_failed() { return m_is_all_failed; } virtual bool Show(bool show = true) override; - + void msw_rescale() override; protected: diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 6e0dd4dc88c..addf5771b65 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -194,6 +194,41 @@ void split_string(std::string s, std::vector& v) { v.push_back(t); } +wxString generate_nozzle_id(NozzleVolumeType nozzle_type, const std::string& diameter) +{ + // HS00-0.4 + std::string nozzle_id = "H"; + switch (nozzle_type) { + case NozzleVolumeType::nvtNormal: { + nozzle_id += "S"; + break; + } + case NozzleVolumeType::nvtBigTraffic: { + nozzle_id += "H"; + break; + } + default: break; + } + nozzle_id += "00"; + nozzle_id += "-"; + nozzle_id += diameter; + return nozzle_id; +} + +NozzleVolumeType convert_to_nozzle_type(const std::string &str) +{ + if (str.size() < 8) { + assert(false); + return NozzleVolumeType::nvtNormal; + } + NozzleVolumeType res = NozzleVolumeType::nvtNormal; + if (str[1] == 'S') + res = NozzleVolumeType::nvtNormal; + else if (str[1] == 'H') + res = NozzleVolumeType::nvtBigTraffic; + return res; +} + PrinterArch get_printer_arch_by_str(std::string arch_str) { if (arch_str == "i3") { @@ -2159,8 +2194,8 @@ int MachineObject::command_start_pa_calibration(const X1CCalibInfos &pa_data, in j["print"]["filaments"][i]["nozzle_temp"] = pa_data.calib_datas[i].nozzle_temp; j["print"]["filaments"][i]["ams_id"] = pa_data.calib_datas[i].ams_id; j["print"]["filaments"][i]["slot_id"] = pa_data.calib_datas[i].slot_id; - j["print"]["filaments"][i]["nozzle_volume_type"] = int(pa_data.calib_datas[i].nozzle_volume_type); - j["print"]["filaments"][i]["nozzle_diameter"] = pa_data.calib_datas[i].nozzle_diameter; + j["print"]["filaments"][i]["nozzle_id"] = generate_nozzle_id(pa_data.calib_datas[i].nozzle_volume_type,to_string_nozzle_diameter(pa_data.calib_datas[i].nozzle_diameter)).ToStdString(); + j["print"]["filaments"][i]["nozzle_diameter"] = to_string_nozzle_diameter(pa_data.calib_datas[i].nozzle_diameter); j["print"]["filaments"][i]["max_volumetric_speed"] = std::to_string(pa_data.calib_datas[i].max_volumetric_speed); if (i > 0) filament_ids += ","; @@ -2199,7 +2234,8 @@ int MachineObject::command_set_pa_calibration(const std::vector & j["print"]["filaments"][i]["cali_idx"] = pa_calib_values[i].cali_idx; j["print"]["filaments"][i]["tray_id"] = pa_calib_values[i].tray_id; j["print"]["filaments"][i]["extruder_id"] = pa_calib_values[i].extruder_id; - j["print"]["filaments"][i]["nozzle_volume_type"] = int(pa_calib_values[i].nozzle_volume_type); + j["print"]["filaments"][i]["nozzle_id"] = generate_nozzle_id(pa_calib_values[i].nozzle_volume_type, to_string_nozzle_diameter(pa_calib_values[i].nozzle_diameter)).ToStdString(); + j["print"]["filaments"][i]["nozzle_diameter"] = to_string_nozzle_diameter(pa_calib_values[i].nozzle_diameter); j["print"]["filaments"][i]["ams_id"] = pa_calib_values[i].ams_id; j["print"]["filaments"][i]["slot_id"] = pa_calib_values[i].slot_id; j["print"]["filaments"][i]["filament_id"] = pa_calib_values[i].filament_id; @@ -2225,7 +2261,7 @@ int MachineObject::command_delete_pa_calibration(const PACalibIndexInfo& pa_cali j["print"]["command"] = "extrusion_cali_del"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["extruder_id"] = pa_calib.extruder_id; - j["print"]["nozzle_volume_type"] = int(pa_calib.nozzle_volume_type); + j["print"]["nozzle_id"] = generate_nozzle_id(pa_calib.nozzle_volume_type, to_string_nozzle_diameter(pa_calib.nozzle_diameter)).ToStdString(); j["print"]["filament_id"] = pa_calib.filament_id; j["print"]["cali_idx"] = pa_calib.cali_idx; j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(pa_calib.nozzle_diameter); @@ -2243,7 +2279,8 @@ int MachineObject::command_get_pa_calibration_tab(const PACalibExtruderInfo &cal j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["filament_id"] = calib_info.filament_id; j["print"]["extruder_id"] = calib_info.extruder_id; - j["print"]["nozzle_volume_type"] = int(calib_info.nozzle_volume_type); + if (calib_info.use_nozzle_volume_type) + j["print"]["nozzle_id"] = generate_nozzle_id(calib_info.nozzle_volume_type, to_string_nozzle_diameter(calib_info.nozzle_diameter)).ToStdString(); j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(calib_info.nozzle_diameter); BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_get: " << j.dump(); diff --git a/src/slic3r/GUI/Widgets/Label.cpp b/src/slic3r/GUI/Widgets/Label.cpp index 7482f3c6187..5171c257ab1 100644 --- a/src/slic3r/GUI/Widgets/Label.cpp +++ b/src/slic3r/GUI/Widgets/Label.cpp @@ -254,10 +254,10 @@ wxSize Label::split_lines(wxDC &dc, int width, const wxString &text, wxString &m return dc.GetMultiLineTextExtent(multiline_text); } -Label::Label(wxWindow *parent, wxString const &text, long style) : Label(parent, Body_14, text, style) {} +Label::Label(wxWindow *parent, wxString const &text, long style, wxSize size) : Label(parent, Body_14, text, style, size) {} -Label::Label(wxWindow *parent, wxFont const &font, wxString const &text, long style) - : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, style) +Label::Label(wxWindow *parent, wxFont const &font, wxString const &text, long style, wxSize size) + : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, size, style) { this->m_font = font; this->m_text = text; diff --git a/src/slic3r/GUI/Widgets/Label.hpp b/src/slic3r/GUI/Widgets/Label.hpp index ea15128ec77..6c7809fea6a 100644 --- a/src/slic3r/GUI/Widgets/Label.hpp +++ b/src/slic3r/GUI/Widgets/Label.hpp @@ -11,9 +11,9 @@ class Label : public wxStaticText { public: - Label(wxWindow *parent, wxString const &text = {}, long style = 0); + Label(wxWindow *parent, wxString const &text = {}, long style = 0, wxSize size = wxDefaultSize); - Label(wxWindow *parent, wxFont const &font, wxString const &text = {}, long style = 0); + Label(wxWindow *parent, wxFont const &font, wxString const &text = {}, long style = 0, wxSize size = wxDefaultSize); void SetLabel(const wxString& label) override; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 57c01077a10..830cf974778 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -35,6 +35,16 @@ static std::string MachineBedTypeString[7] = { }; +wxString get_nozzle_volume_type_name(NozzleVolumeType type) +{ + if (NozzleVolumeType::nvtNormal == type) { + return _L("Normal"); + } else if (NozzleVolumeType::nvtBigTraffic == type) { + return _L("BigTraffic"); + } + return wxString(); +} + std::string get_calib_mode_name(CalibMode cali_mode, int stage) { switch(cali_mode) { diff --git a/src/slic3r/Utils/CalibUtils.hpp b/src/slic3r/Utils/CalibUtils.hpp index c1137ae584e..e3b6cedd529 100644 --- a/src/slic3r/Utils/CalibUtils.hpp +++ b/src/slic3r/Utils/CalibUtils.hpp @@ -78,5 +78,6 @@ class CalibUtils static void send_to_print(const CalibInfo &calib_info, wxString& error_message, int flow_ratio_mode = 0); // 0: none 1: coarse 2: fine }; +extern wxString get_nozzle_volume_type_name(NozzleVolumeType type); } } \ No newline at end of file From b0872aaba979416b019d0bd5fcbb5199d5549de5 Mon Sep 17 00:00:00 2001 From: tao wang Date: Wed, 6 Nov 2024 22:09:33 +0800 Subject: [PATCH 032/127] FIX:Fix the issue of extruder matching errors jira:[for nozzle match] Change-Id: I6965500bfb7feef6d18d28bea8a53a3c477f5e36 (cherry picked from commit 7bcf4b6cc5bc38e723bfd8dcd495c60a55134490) --- src/slic3r/GUI/DeviceManager.cpp | 2 -- src/slic3r/GUI/DeviceManager.hpp | 1 - src/slic3r/GUI/SelectMachine.cpp | 35 ++++++++++++++------------------ 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index addf5771b65..fe34507b23b 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -585,7 +585,6 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string is_ams_need_update = false; ams_insert_flag = false; ams_power_on_flag = false; - ams_support_use_ams = false; ams_calibrate_remain_flag = false; ams_humidity = 5; @@ -3919,7 +3918,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } if (jj["ams"].contains("tray_reading_bits")) { tray_reading_bits = stol(jj["ams"]["tray_reading_bits"].get(), nullptr, 16); - ams_support_use_ams = true; } if (jj["ams"].contains("tray_is_bbl_bits")) { tray_is_bbl_bits = stol(jj["ams"]["tray_is_bbl_bits"].get(), nullptr, 16); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index cd51613622d..9b50eb040c9 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -530,7 +530,6 @@ class MachineObject bool ams_calibrate_remain_flag { false }; bool ams_auto_switch_filament_flag { false }; bool ams_air_print_status { false }; - bool ams_support_use_ams { false }; bool ams_support_virtual_tray { true }; int ams_humidity; int ams_user_setting_hold_count = 0; diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index c1c10444048..ad408a00beb 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3519,7 +3519,7 @@ void SelectMachineDialog::update_flow_cali_check(MachineObject* obj) void SelectMachineDialog::update_ams_check(MachineObject* obj) { - if (obj && obj->ams_support_use_ams && obj->has_ams()) { + if (obj && obj->has_ams()) { select_use_ams->Show(); if (obj->get_printer_ams_type() == "generic") { img_use_ams_tip->Show(); @@ -3611,13 +3611,11 @@ void SelectMachineDialog::update_show_status() // do ams mapping if no ams result bool clean_ams_mapping = false; - if (obj_->has_ams() && m_ams_mapping_result.empty()) { - if (obj_->ams_support_use_ams) { - if (m_checkbox_list["use_ams"]->GetValue()) { - do_ams_mapping(obj_); - } else { - clean_ams_mapping = true; - } + if (m_ams_mapping_result.empty()) { + if (m_checkbox_list["use_ams"]->GetValue()) { + do_ams_mapping(obj_); + } else { + clean_ams_mapping = true; } } @@ -3685,20 +3683,17 @@ void SelectMachineDialog::update_show_status() return; } - if (obj_->ams_support_use_ams) { - if (!m_checkbox_list["use_ams"]->GetValue()) { - m_ams_mapping_result.clear(); - sync_ams_mapping_result(m_ams_mapping_result); - - if (has_timelapse_warning()) { - show_status(PrintDialogStatus::PrintStatusTimelapseWarning); - } - else { - show_status(PrintDialogStatus::PrintStatusDisableAms); - } + if (!m_checkbox_list["use_ams"]->GetValue()) { + m_ams_mapping_result.clear(); + sync_ams_mapping_result(m_ams_mapping_result); - return; + if (has_timelapse_warning()) { + show_status(PrintDialogStatus::PrintStatusTimelapseWarning); + } else { + show_status(PrintDialogStatus::PrintStatusDisableAms); } + + return; } From f6bfad9de15709871455a52fd078e639a90b2ac5 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 16:05:49 +0800 Subject: [PATCH 033/127] Fix wrong slot id --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 10 ++++------ src/slic3r/GUI/AMSMaterialsSetting.hpp | 1 - 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index f7028c42c65..fe1368b0826 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -523,7 +523,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { // set k / n value if (obj->cali_version <= -1 && obj->get_printer_series() == PrinterSeries::SERIES_P1P) { // set extrusion cali ratio - int cali_tray_id = ams_id * 4 + tray_id; + int cali_tray_id = ams_id * 4 + slot_id; double k = 0.0; try { @@ -544,7 +544,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { } else { PACalibIndexInfo select_index_info; - select_index_info.tray_id = tray_id; + select_index_info.tray_id = slot_id; select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; select_index_info.cali_idx = -1; select_index_info.filament_id = selected_ams_id; @@ -695,7 +695,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) } } else { - int cali_tray_id = ams_id * 4 + tray_id; + int cali_tray_id = ams_id * 4 + slot_id; double k = 0.0; try { k_text.ToDouble(&k); @@ -802,7 +802,7 @@ void AMSMaterialsSetting::on_clr_picker(wxMouseEvent &event) bool AMSMaterialsSetting::is_virtual_tray() { - if (tray_id == VIRTUAL_TRAY_ID) + if (ams_id == VIRTUAL_TRAY_ID) return true; return false; } @@ -1167,9 +1167,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (obj->cali_version >= 0) { // add default item PACalibResult default_item; - default_item.filament_id = ams_filament_id; default_item.cali_idx = -1; - default_item.filament_id = ams_filament_id; get_default_k_n_value(ams_filament_id, default_item.k_value, default_item.n_coef); m_pa_profile_items.emplace_back(default_item); items.push_back(_L("Default")); diff --git a/src/slic3r/GUI/AMSMaterialsSetting.hpp b/src/slic3r/GUI/AMSMaterialsSetting.hpp index 871c6ac26bd..3c8743b6347 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.hpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.hpp @@ -119,7 +119,6 @@ class AMSMaterialsSetting : public DPIDialog MachineObject* obj{ nullptr }; int ams_id { 0 }; /* 0 ~ 3 */ int slot_id { 0 }; /* 0 ~ 3 */ - int tray_id { 0 }; /* 0 ~ 3 */ std::string ams_filament_id; std::string ams_setting_id; From 2ee934a7ee0e1819ca8dcf0603f1735a62dd2e27 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Mon, 5 Aug 2024 17:34:45 +0800 Subject: [PATCH 034/127] FIX: cannot cali for single nozzle printer jira: none Change-Id: I1cc0e5e4b0f9db2a66694c894f96a14047fde9e5 (cherry picked from commit 7bd3a5218af9f3d172090a80da447c4f2bbfff61) --- src/slic3r/GUI/CalibrationWizardPresetPage.cpp | 7 ++++++- src/slic3r/GUI/DeviceManager.cpp | 5 +++++ src/slic3r/GUI/DeviceManager.hpp | 9 +++++---- src/slic3r/GUI/Plater.cpp | 1 - 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index ecb7deea446..98e09e479bb 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -1556,7 +1556,12 @@ void CalibrationPresetPage::sync_ams_info(MachineObject* obj) { if (!obj) return; - std::map full_filament_ams_list = wxGetApp().sidebar().build_filament_ams_list(obj); + std::map old_full_filament_ams_list = wxGetApp().sidebar().build_filament_ams_list(obj); + std::map full_filament_ams_list; + for (auto ams_item : old_full_filament_ams_list) { + int key = ams_item.first & 0x0FFFF; + full_filament_ams_list[key] = std::move(ams_item.second); + } // sync filament_ams_list from obj ams list filament_ams_list.clear(); diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index fe34507b23b..f02059dcf99 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1173,6 +1173,11 @@ void MachineObject::reset_mapping_result(std::vector& result) } } +bool MachineObject::is_multi_extruders() const +{ + return m_nozzle_data.total_nozzle_count > 1; +} + bool MachineObject::is_bbl_filament(std::string tag_uid) { if (tag_uid.empty()) diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 9b50eb040c9..4ee5e16c665 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -569,6 +569,7 @@ class MachineObject // exceed index start with 0 bool is_mapping_exceed_filament(std::vector& result, int &exceed_index); void reset_mapping_result(std::vector& result); + bool is_multi_extruders() const; /*online*/ bool online_rfid; @@ -749,17 +750,17 @@ class MachineObject } liveview_local{ LVL_None }; enum LiveviewRemote { LVR_None, - LVR_Tutk, + LVR_Tutk, LVR_Agora, LVR_TutkAgora } liveview_remote{ LVR_None }; enum FileLocal { - FL_None, + FL_None, FL_Local } file_local{ FL_None }; enum FileRemote { - FR_None, - FR_Tutk, + FR_None, + FR_Tutk, FR_Agora, FR_TutkAgora } file_remote{ FR_None }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cb2a37f6098..8283ae69635 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2080,7 +2080,6 @@ void Sidebar::auto_calc_flushing_volumes(const int modify_id) auto& printer_config = preset_bundle->printers.get_edited_preset().config; const auto& full_config = wxGetApp().preset_bundle->full_config(); auto& ams_multi_color_filament = preset_bundle->ams_multi_color_filment; - auto& ams_filament_list = preset_bundle->filament_ams_list; const std::vector& init_matrix = (project_config.option("flush_volumes_matrix"))->values; const std::vector& init_extruders = (project_config.option("flush_volumes_vector"))->values; From 108a5b8344eb44e472fa1aced73f2e80503a718e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 16:19:24 +0800 Subject: [PATCH 035/127] =?UTF-8?q?=EF=BB=BFUpdate=20naming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 10 ++--- src/slic3r/GUI/CaliHistoryDialog.cpp | 6 +-- src/slic3r/GUI/CalibrationWizard.cpp | 2 +- src/slic3r/GUI/CalibrationWizardCaliPage.cpp | 4 +- .../GUI/CalibrationWizardPresetPage.cpp | 2 +- src/slic3r/GUI/DeviceManager.cpp | 42 +++++++++---------- src/slic3r/GUI/DeviceManager.hpp | 14 +++---- src/slic3r/GUI/PrintOptionsDialog.cpp | 8 ++-- src/slic3r/GUI/SelectMachine.cpp | 18 ++++---- src/slic3r/GUI/StatusPanel.cpp | 12 +++--- src/slic3r/Utils/CalibUtils.cpp | 12 +++--- 11 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index fe1368b0826..73d9ce18a9c 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -545,7 +545,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { else { PACalibIndexInfo select_index_info; select_index_info.tray_id = slot_id; - select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; + select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; select_index_info.cali_idx = -1; select_index_info.filament_id = selected_ams_id; CalibUtils::select_PA_calib_result(select_index_info); @@ -676,7 +676,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = vt_tray; - select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; + select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); if (m_pa_profile_items.size() > 0 && cali_select_id >= 0) { @@ -715,7 +715,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = cali_tray_id; - select_index_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; + select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); if (m_pa_profile_items.size() > 0 && cali_select_id > 0) { @@ -878,7 +878,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi std::set filament_id_set; PresetBundle * preset_bundle = wxGetApp().preset_bundle; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << obj->m_nozzle_data.nozzles[0].diameter; + stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); @@ -1044,7 +1044,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (preset_bundle) { std::ostringstream stream; if (obj) - stream << std::fixed << std::setprecision(1) << obj->m_nozzle_data.nozzles[0].diameter; + stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 22f84e43e02..2cc210c6c2b 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -180,7 +180,7 @@ void HistoryWindow::on_device_connected(MachineObject* obj) int selection = 1; for (int i = 0; i < nozzle_diameter_list.size(); i++) { m_comboBox_nozzle_dia->AppendString(wxString::Format("%1.1f mm", nozzle_diameter_list[i])); - if (abs(curr_obj->m_nozzle_data.nozzles[0].diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(curr_obj->m_extder_data.extders[0].diameter - nozzle_diameter_list[i]) < 1e-3) { selection = i; } } @@ -507,7 +507,7 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject std::set filament_id_set; std::set printer_names; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << obj->m_nozzle_data.nozzles[0].diameter; + stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].diameter; std::string nozzle_diameter_str = stream.str(); for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) { @@ -624,7 +624,7 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const static std::array nozzle_diameter_list = {0.2f, 0.4f, 0.6f, 0.8f}; for (int i = 0; i < nozzle_diameter_list.size(); i++) { m_comboBox_nozzle_diameter->AppendString(wxString::Format("%1.1f mm", nozzle_diameter_list[i])); - if (abs(obj->m_nozzle_data.nozzles[0].diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(obj->m_extder_data.extders[0].diameter - nozzle_diameter_list[i]) < 1e-3) { m_comboBox_nozzle_diameter->SetSelection(i); } } diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index bc7500827ad..65edb845814 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -497,7 +497,7 @@ void PressureAdvanceWizard::update(MachineObject* obj) if (obj->cali_version != -1 && obj->cali_version != cali_version) { cali_version = obj->cali_version; PACalibExtruderInfo cali_info; - cali_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; + cali_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; CalibUtils::emit_get_PA_calib_info(cali_info); } } diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp index 8f438864d53..9cd780ff97c 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp @@ -495,8 +495,8 @@ float CalibrationCaliPage::get_selected_calibration_nozzle_dia(MachineObject* ob return obj->cali_selected_nozzle_dia; // return default nozzle if nozzle diameter is set - if (obj->m_nozzle_data.nozzles[0].diameter > 1e-3 && obj->m_nozzle_data.nozzles[0].diameter < 10.0f) - return obj->m_nozzle_data.nozzles[0].diameter; + if (obj->m_extder_data.extders[0].diameter > 1e-3 && obj->m_extder_data.extders[0].diameter < 10.0f) + return obj->m_extder_data.extders[0].diameter; // return 0.4 by default return 0.4; diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index 98e09e479bb..7a01f38784a 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -1505,7 +1505,7 @@ void CalibrationPresetPage::init_with_machine(MachineObject* obj) // set nozzle value from machine bool nozzle_is_set = false; for (int i = 0; i < NOZZLE_LIST_COUNT; i++) { - if (abs(obj->m_nozzle_data.nozzles[0].diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(obj->m_extder_data.extders[0].diameter - nozzle_diameter_list[i]) < 1e-3) { if (m_comboBox_nozzle_dia->GetCount() > i) { m_comboBox_nozzle_dia->SetSelection(i); nozzle_is_set = true; diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index f02059dcf99..e12ba39168f 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -617,11 +617,11 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string has_ipcam = true; // default true - m_nozzle_data.current_nozzle_id = 0; - m_nozzle_data.target_nozzle_id = 0; - m_nozzle_data.total_nozzle_count = 1; - Nozzle nozzle; - m_nozzle_data.nozzles.push_back(nozzle); + m_extder_data.current_extder_id = 0; + m_extder_data.target_extder_id = 0; + m_extder_data.total_extder_count = 1; + Extder nozzle; + m_extder_data.extders.push_back(nozzle); } MachineObject::~MachineObject() @@ -1175,7 +1175,7 @@ void MachineObject::reset_mapping_result(std::vector& result) bool MachineObject::is_multi_extruders() const { - return m_nozzle_data.total_nozzle_count > 1; + return m_extder_data.total_extder_count > 1; } bool MachineObject::is_bbl_filament(std::string tag_uid) @@ -3400,15 +3400,15 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } if (jj.contains("nozzle_temper")) { if (jj["nozzle_temper"].is_number()) { - if (m_nozzle_data.nozzles.size() == 1) { - m_nozzle_data.nozzles[0].temp = jj["nozzle_temper"].get(); + if (m_extder_data.extders.size() == 1) { + m_extder_data.extders[0].temp = jj["nozzle_temper"].get(); } } } if (jj.contains("nozzle_target_temper")) { if (jj["nozzle_target_temper"].is_number()) { - if (m_nozzle_data.nozzles.size() == 1) { - m_nozzle_data.nozzles[0].target_temp = jj["nozzle_temper"].get(); + if (m_extder_data.extders.size() == 1) { + m_extder_data.extders[0].target_temp = jj["nozzle_temper"].get(); } } } @@ -3593,8 +3593,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) nozzle_diameter = string_to_float(jj["nozzle_diameter"].get()); } - if (nozzle_diameter == 0.0f) {m_nozzle_data.nozzles[0].diameter = 0.4f;} - else {m_nozzle_data.nozzles[0].diameter = round(nozzle_diameter * 10) / 10;} + if (nozzle_diameter == 0.0f) {m_extder_data.extders[0].diameter = 0.4f;} + else {m_extder_data.extders[0].diameter = round(nozzle_diameter * 10) / 10;} } } } @@ -3611,7 +3611,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) else { if (jj["nozzle_type"].is_string()) { auto nozzle_type = jj["nozzle_type"].get(); - m_nozzle_data.nozzles[0].type = nozzle_type; + m_extder_data.extders[0].type = nozzle_type; } } } @@ -3898,7 +3898,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } PresetBundle *preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << DeviceManager::nozzle_diameter_conver(m_nozzle_data.nozzles[0].diameter); + stream << std::fixed << std::setprecision(1) << DeviceManager::nozzle_diameter_conver(m_extder_data.extders[0].diameter); std::string nozzle_diameter_str = stream.str(); if (m_printer_preset_name.find(nozzle_diameter_str + " nozzle") == std::string::npos) update_printer_preset_name(nozzle_diameter_str); @@ -5520,15 +5520,15 @@ void MachineObject::parse_new_info(json print) if (device.contains("nozzle")) { json const& nozzle = device["nozzle"]; - m_nozzle_data = NozzleData(); - m_nozzle_data.current_nozzle_id = get_flag_bits(nozzle["info"].get(), 0, 3); - m_nozzle_data.target_nozzle_id = get_flag_bits(nozzle["info"].get(), 4, 3); - m_nozzle_data.total_nozzle_count = get_flag_bits(nozzle["info"].get(), 8, 3); + m_extder_data = ExtderData(); + m_extder_data.current_extder_id = get_flag_bits(nozzle["info"].get(), 0, 3); + m_extder_data.target_extder_id = get_flag_bits(nozzle["info"].get(), 4, 3); + m_extder_data.total_extder_count = get_flag_bits(nozzle["info"].get(), 8, 3); - for (int i = 0; i < m_nozzle_data.total_nozzle_count; i++) { + for (int i = 0; i < m_extder_data.total_extder_count; i++) { - Nozzle nozzle_obj; + Extder nozzle_obj; std::string nozzle_id = std::to_string(i); if (nozzle.contains(nozzle_id)) { @@ -5561,7 +5561,7 @@ void MachineObject::parse_new_info(json print) nozzle_obj.rfid_stat = get_flag_bits(njon["stat"].get(), 16, 7); } - m_nozzle_data.nozzles.push_back(nozzle_obj); + m_extder_data.extders.push_back(nozzle_obj); } } } diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 4ee5e16c665..d431a66d32c 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -142,7 +142,7 @@ struct AmsSlot std::string slot_id; }; -struct Nozzle +struct Extder { std::string type; //0-hardened_steel 1-stainless_steel float diameter = {0.4f}; // 0-0.2mm 1-0.4mm 2-0.6 mm3-0.8mm @@ -160,12 +160,12 @@ struct Nozzle int rfid_stat{0}; ; }; -struct NozzleData +struct ExtderData { - int current_nozzle_id{0}; - int target_nozzle_id{0}; - int total_nozzle_count {0}; - std::vector nozzles; + int current_extder_id{0}; + int target_extder_id{0}; + int total_extder_count {0}; + std::vector extders; }; struct RatingInfo { @@ -1019,7 +1019,7 @@ class MachineObject /*for more extruder*/ bool is_enable_np{ false }; - NozzleData m_nozzle_data; + ExtderData m_extder_data; /* Device Filament Check */ std::set m_checked_filament; diff --git a/src/slic3r/GUI/PrintOptionsDialog.cpp b/src/slic3r/GUI/PrintOptionsDialog.cpp index e0c9d1026eb..bcfa6c9910d 100644 --- a/src/slic3r/GUI/PrintOptionsDialog.cpp +++ b/src/slic3r/GUI/PrintOptionsDialog.cpp @@ -553,8 +553,8 @@ void PrinterPartsDialog::set_nozzle_diameter(wxCommandEvent& evt) auto nozzle_diameter = std::stof(nozzle_diameter_checkbox->GetStringSelection().ToStdString()); nozzle_diameter = round(nozzle_diameter * 10) / 10; - obj->m_nozzle_data.nozzles[0].diameter = nozzle_diameter; - obj->m_nozzle_data.nozzles[0].type = nozzle_type; + obj->m_extder_data.extders[0].diameter = nozzle_diameter; + obj->m_extder_data.extders[0].type = nozzle_type; obj->command_set_printer_nozzle(nozzle_type, nozzle_diameter); } @@ -579,8 +579,8 @@ bool PrinterPartsDialog::Show(bool show) CentreOnParent(); - auto type = obj->m_nozzle_data.nozzles[0].type; - auto diameter = obj->m_nozzle_data.nozzles[0].diameter; + auto type = obj->m_extder_data.extders[0].type; + auto diameter = obj->m_extder_data.extders[0].diameter; nozzle_type_checkbox->Clear(); nozzle_diameter_checkbox->Clear(); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index ad408a00beb..ebcf23cf0af 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -2456,14 +2456,14 @@ bool SelectMachineDialog::is_same_nozzle_diameters(std::string& tag_nozzle_type, preset_nozzle_type = "stainless_steel"; } - tag_nozzle_type = obj_->m_nozzle_data.nozzles[0].type; + tag_nozzle_type = obj_->m_extder_data.extders[0].type; auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); if (opt_nozzle_diameters != nullptr) { for (auto i = 0; i < extruders.size(); i++) { auto extruder = extruders[i] - 1; preset_nozzle_diameters = float(opt_nozzle_diameters->get_at(extruder)); - if (preset_nozzle_diameters != obj_->m_nozzle_data.nozzles[0].diameter) { + if (preset_nozzle_diameters != obj_->m_extder_data.extders[0].diameter) { is_same_nozzle_diameters = false; } } @@ -2493,10 +2493,10 @@ bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::s NozzleType nozzle_type = NozzleType::ntUndefine; - if (obj_->m_nozzle_data.nozzles[0].type == "stainless_steel") { + if (obj_->m_extder_data.extders[0].type == "stainless_steel") { nozzle_type = NozzleType::ntStainlessSteel; } - else if (obj_->m_nozzle_data.nozzles[0].type == "hardened_steel") { + else if (obj_->m_extder_data.extders[0].type == "hardened_steel") { nozzle_type = NozzleType::ntHardenedSteel; } @@ -2517,7 +2517,7 @@ bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::s return is_same_nozzle_type; } else { - tag_nozzle_type = DeviceManager::nozzle_type_conver(obj_->m_nozzle_data.nozzles[0].type); + tag_nozzle_type = DeviceManager::nozzle_type_conver(obj_->m_extder_data.extders[0].type); } iter++; @@ -2710,13 +2710,13 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) std::string filament_type; std::string tag_nozzle_type; - if (!obj_->m_nozzle_data.nozzles[0].type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) { + if (!obj_->m_extder_data.extders[0].type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) { if (!is_same_nozzle_diameters(tag_nozzle_type, nozzle_diameter)) { has_slice_warnings = true; // is_printing_block = true; # Removed to allow nozzle overrides (to support non-standard nozzles) wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"),nozzle_diameter, ""); - wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj_->m_nozzle_data.nozzles[0].diameter, ""); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj_->m_extder_data.extders[0].diameter, ""); confirm_text.push_back(ConfirmBeforeSendInfo(_L("Your nozzle diameter in sliced file is not consistent with memorized nozzle. If you changed your nozzle lately, please go to Device > Printer Parts to change settings.") + "\n " + nozzle_in_preset @@ -2727,9 +2727,9 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) if (!is_same_nozzle_type(filament_type, tag_nozzle_type)){ has_slice_warnings = true; is_printing_block = true; - nozzle_diameter = wxString::Format("%.1f", obj_->m_nozzle_data.nozzles[0].diameter).ToStdString(); + nozzle_diameter = wxString::Format("%.1f", obj_->m_extder_data.extders[0].diameter).ToStdString(); - wxString nozzle_in_preset = wxString::Format(_L("Printing high temperature material(%s material) with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->m_nozzle_data.nozzles[0].type)); + wxString nozzle_in_preset = wxString::Format(_L("Printing high temperature material(%s material) with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->m_extder_data.extders[0].type)); confirm_text.push_back(ConfirmBeforeSendInfo(nozzle_in_preset, ConfirmBeforeSendInfo::InfoLevel::Warning)); } } diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 076d9ca76d4..ac99aad8782 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2378,7 +2378,7 @@ void StatusPanel::update_temp_ctrl(MachineObject *obj) m_tempCtrl_bed->SetIconNormal(); } - m_tempCtrl_nozzle->SetCurrTemp((int) obj->m_nozzle_data.nozzles[0].temp); + m_tempCtrl_nozzle->SetCurrTemp((int) obj->m_extder_data.extders[0].temp); if (obj->nozzle_max_temperature > -1) { if (m_tempCtrl_nozzle) m_tempCtrl_nozzle->SetMaxTemp(obj->nozzle_max_temperature); } @@ -2389,10 +2389,10 @@ void StatusPanel::update_temp_ctrl(MachineObject *obj) if (m_temp_nozzle_timeout > 0) { m_temp_nozzle_timeout--; } else { - if (!nozzle_temp_input) { m_tempCtrl_nozzle->SetTagTemp((int) obj->m_nozzle_data.nozzles[0].target_temp); } + if (!nozzle_temp_input) { m_tempCtrl_nozzle->SetTagTemp((int) obj->m_extder_data.extders[0].target_temp); } } - if ((obj->m_nozzle_data.nozzles[0].target_temp - obj->m_nozzle_data.nozzles[0].temp) >= TEMP_THRESHOLD_VAL) { + if ((obj->m_extder_data.extders[0].target_temp - obj->m_extder_data.extders[0].temp) >= TEMP_THRESHOLD_VAL) { m_tempCtrl_nozzle->SetIconActive(); } else { m_tempCtrl_nozzle->SetIconNormal(); @@ -2587,7 +2587,7 @@ void StatusPanel::update_ams(MachineObject *obj) if (obj->cali_version != -1 && last_cali_version != obj->cali_version) { last_cali_version = obj->cali_version; PACalibExtruderInfo cali_info; - cali_info.nozzle_diameter = obj->m_nozzle_data.nozzles[0].diameter; + cali_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; CalibUtils::emit_get_PA_calib_info(cali_info); } @@ -3410,7 +3410,7 @@ void StatusPanel::axis_ctrl_e_hint(bool up_down) void StatusPanel::on_axis_ctrl_e_up_10(wxCommandEvent &event) { if (obj) { - if (obj->m_nozzle_data.nozzles[0].temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) + if (obj->m_extder_data.extders[0].temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) obj->command_axis_control("E", 1.0, -10.0f, 900); else axis_ctrl_e_hint(true); @@ -3420,7 +3420,7 @@ void StatusPanel::on_axis_ctrl_e_up_10(wxCommandEvent &event) void StatusPanel::on_axis_ctrl_e_down_10(wxCommandEvent &event) { if (obj) { - if (obj->m_nozzle_data.nozzles[0].temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) + if (obj->m_extder_data.extders[0].temp >= TEMP_THRESHOLD_ALLOW_E_CTRL || (wxGetApp().app_config->get("not_show_ectrl_hint") == "1")) obj->command_axis_control("E", 1.0, 10.0f, 900); else axis_ctrl_e_hint(false); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 830cf974778..db08f1566ef 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -107,9 +107,9 @@ static bool is_same_nozzle_diameters(const DynamicPrintConfig &full_config, cons auto opt_nozzle_diameters = full_config.option("nozzle_diameter"); if (opt_nozzle_diameters != nullptr) { float preset_nozzle_diameter = opt_nozzle_diameters->get_at(0); - if (preset_nozzle_diameter != obj->m_nozzle_data.nozzles[0].diameter) { + if (preset_nozzle_diameter != obj->m_extder_data.extders[0].diameter) { wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"), wxString::Format("%.1f", preset_nozzle_diameter).ToStdString(), to_wstring_name(nozzle_type)); - wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->m_nozzle_data.nozzles[0].diameter, DeviceManager::nozzle_type_conver(obj->m_nozzle_data.nozzles[0].diameter)); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->m_extder_data.extders[0].diameter, DeviceManager::nozzle_type_conver(obj->m_extder_data.extders[0].diameter)); error_msg = _L("Your nozzle diameter in preset is not consistent with memorized nozzle diameter. Did you change your nozzle lately?") + "\n " + nozzle_in_preset + "\n " + nozzle_in_printer + "\n"; @@ -129,9 +129,9 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac NozzleType nozzle_type = NozzleType::ntUndefine; - if (obj->m_nozzle_data.nozzles[0].type == "stainless_steel") { + if (obj->m_extder_data.extders[0].type == "stainless_steel") { nozzle_type = NozzleType::ntStainlessSteel; - } else if (obj->m_nozzle_data.nozzles[0].type == "hardened_steel") { + } else if (obj->m_extder_data.extders[0].type == "hardened_steel") { nozzle_type = NozzleType::ntHardenedSteel; } @@ -141,7 +141,7 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) { BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: printer_nozzle_hrc = " << printer_nozzle_hrc << ", filament_nozzle_hrc = " << filament_nozzle_hrc; std::string filament_type = full_config.opt_string("filament_type", 0); - error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(obj->m_nozzle_data.nozzles[0].type)); + error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(obj->m_extder_data.extders[0].type)); error_msg += "\n"; MessageDialog msg_dlg(nullptr, error_msg, wxEmptyString, wxICON_WARNING | wxOK | wxCANCEL); @@ -174,7 +174,7 @@ static bool check_nozzle_diameter_and_type(const DynamicPrintConfig &full_config } // P1P/S - if (obj->m_nozzle_data.nozzles[0].type.empty()) + if (obj->m_extder_data.extders[0].type.empty()) return true; if (!is_same_nozzle_diameters(full_config, obj, error_msg)) From b4f1ef06a2fc7e6889794411016e300361bb9baa Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 16:24:37 +0800 Subject: [PATCH 036/127] Fix compile error --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 73d9ce18a9c..6d1fb666569 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -1155,15 +1155,9 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) m_pa_profile_items.clear(); m_comboBox_cali_result->SetValue(wxEmptyString); - int extruder_id = obj->get_extruder_id_by_ams_id(std::to_string(ams_id)); + // TODO: Orca hack + int extruder_id = 0; NozzleVolumeType nozzle_volume_type = NozzleVolumeType::nvtNormal; - if (obj->m_extder_data.extders[extruder_id].current_nozzle_flow_type == NozzleFlowType::NONE_FLOWTYPE) { - MessageDialog dlg(nullptr, _L("There are unset nozzle types. Please set the nozzle types of all extruders before synchronizing."), _L("Warning"), wxICON_WARNING | wxOK); - dlg.ShowModal(); - } - else { - nozzle_volume_type = NozzleVolumeType(obj->m_extder_data.extders[extruder_id].current_nozzle_flow_type - 1); - } if (obj->cali_version >= 0) { // add default item PACalibResult default_item; From 92972879f510c1281aa9a99fd48bc560c9edbb25 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Tue, 12 Nov 2024 09:18:40 +0800 Subject: [PATCH 037/127] FIX: modify for get pa cali result jira: none Change-Id: I3c57ccaac3b7e73e0b2eb0e26678635478480298 (cherry picked from commit 6bf39690517f9e25de895bf52673d3a4a7b77255) --- src/libslic3r/calib.hpp | 3 ++- src/slic3r/GUI/AMSMaterialsSetting.cpp | 8 +++++++- src/slic3r/GUI/CalibrationWizard.cpp | 4 +++- src/slic3r/GUI/DeviceManager.cpp | 7 +++++-- src/slic3r/GUI/StatusPanel.cpp | 4 +++- src/slic3r/Utils/CalibUtils.cpp | 25 ------------------------- src/slic3r/Utils/CalibUtils.hpp | 3 --- 7 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index b0cea424107..d7db10fd81b 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -136,10 +136,11 @@ struct PACalibIndexInfo struct PACalibExtruderInfo { - int extruder_id; + int extruder_id = -1; NozzleVolumeType nozzle_volume_type; float nozzle_diameter; std::string filament_id = ""; + bool use_extruder_id{true}; bool use_nozzle_volume_type{true}; }; diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 6d1fb666569..7e8d7cd8be2 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -544,7 +544,9 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { } else { PACalibIndexInfo select_index_info; - select_index_info.tray_id = slot_id; + select_index_info.tray_id = ams_id * 4 + slot_id; + select_index_info.ams_id = ams_id; + select_index_info.slot_id = slot_id; select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; select_index_info.cali_idx = -1; select_index_info.filament_id = selected_ams_id; @@ -676,6 +678,8 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = vt_tray; + select_index_info.ams_id = vt_tray; + select_index_info.slot_id = 0; select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); @@ -715,6 +719,8 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = cali_tray_id; + select_index_info.ams_id = ams_id; + select_index_info.slot_id = slot_id; select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index 65edb845814..7c826a15ab7 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -498,7 +498,9 @@ void PressureAdvanceWizard::update(MachineObject* obj) cali_version = obj->cali_version; PACalibExtruderInfo cali_info; cali_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; - CalibUtils::emit_get_PA_calib_info(cali_info); + cali_info.use_extruder_id = false; + cali_info.use_nozzle_volume_type = false; + CalibUtils::emit_get_PA_calib_infos(cali_info); } } } diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index e12ba39168f..54f9b52de27 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -207,7 +207,9 @@ wxString generate_nozzle_id(NozzleVolumeType nozzle_type, const std::string& dia nozzle_id += "H"; break; } - default: break; + default: + nozzle_id += "H"; + break; } nozzle_id += "00"; nozzle_id += "-"; @@ -2282,7 +2284,8 @@ int MachineObject::command_get_pa_calibration_tab(const PACalibExtruderInfo &cal j["print"]["command"] = "extrusion_cali_get"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["filament_id"] = calib_info.filament_id; - j["print"]["extruder_id"] = calib_info.extruder_id; + if (calib_info.use_extruder_id) + j["print"]["extruder_id"] = calib_info.extruder_id; if (calib_info.use_nozzle_volume_type) j["print"]["nozzle_id"] = generate_nozzle_id(calib_info.nozzle_volume_type, to_string_nozzle_diameter(calib_info.nozzle_diameter)).ToStdString(); j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(calib_info.nozzle_diameter); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index ac99aad8782..5d64ceb3441 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2588,7 +2588,9 @@ void StatusPanel::update_ams(MachineObject *obj) last_cali_version = obj->cali_version; PACalibExtruderInfo cali_info; cali_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; - CalibUtils::emit_get_PA_calib_info(cali_info); + cali_info.use_extruder_id = false; + cali_info.use_nozzle_volume_type = false; + CalibUtils::emit_get_PA_calib_infos(cali_info); } bool is_support_virtual_tray = obj->ams_support_virtual_tray; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index db08f1566ef..0bde1163b28 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -412,31 +412,6 @@ bool CalibUtils::get_PA_calib_tab(std::vector &pa_calib_infos) return obj_->has_get_pa_calib_tab; } -void CalibUtils::emit_get_PA_calib_info(const PACalibExtruderInfo &cali_info) -{ - DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return; - - MachineObject *obj_ = dev->get_selected_machine(); - if (obj_ == nullptr) return; - - obj_->command_get_pa_calibration_tab(cali_info); -} - -bool CalibUtils::get_PA_calib_info(PACalibResult & pa_calib_info) { - DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return false; - - MachineObject *obj_ = dev->get_selected_machine(); - if (obj_ == nullptr) return false; - - if (!obj_->pa_calib_tab.empty()) { - pa_calib_info = obj_->pa_calib_tab.front(); - return true; - } - return false; -} - void CalibUtils::set_PA_calib_result(const std::vector &pa_calib_values, bool is_auto_cali) { DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); diff --git a/src/slic3r/Utils/CalibUtils.hpp b/src/slic3r/Utils/CalibUtils.hpp index e3b6cedd529..d6b774ee9e6 100644 --- a/src/slic3r/Utils/CalibUtils.hpp +++ b/src/slic3r/Utils/CalibUtils.hpp @@ -45,9 +45,6 @@ class CalibUtils static void emit_get_PA_calib_infos(const PACalibExtruderInfo &cali_info); static bool get_PA_calib_tab(std::vector &pa_calib_infos); - static void emit_get_PA_calib_info(const PACalibExtruderInfo& cali_info); - static bool get_PA_calib_info(PACalibResult &pa_calib_info); - static void set_PA_calib_result(const std::vector& pa_calib_values, bool is_auto_cali); static void select_PA_calib_result(const PACalibIndexInfo &pa_calib_info); static void delete_PA_calib_result(const PACalibIndexInfo &pa_calib_info); From ca68aa6d2bf600861bc74b37c90ef7fc957fbaac Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 16:47:28 +0800 Subject: [PATCH 038/127] Fix compile error --- src/slic3r/GUI/DeviceManager.cpp | 6 ++++++ src/slic3r/GUI/DeviceManager.hpp | 1 + src/slic3r/GUI/StatusPanel.cpp | 1 - 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 54f9b52de27..89444a97273 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1175,6 +1175,12 @@ void MachineObject::reset_mapping_result(std::vector& result) } } +bool MachineObject::is_main_extruder_on_left() const +{ + // only means the extruder is on the left hand when extruder id is 0 + return false; +} + bool MachineObject::is_multi_extruders() const { return m_extder_data.total_extder_count > 1; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index d431a66d32c..3759c5e474e 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -569,6 +569,7 @@ class MachineObject // exceed index start with 0 bool is_mapping_exceed_filament(std::vector& result, int &exceed_index); void reset_mapping_result(std::vector& result); + bool is_main_extruder_on_left() const; bool is_multi_extruders() const; /*online*/ diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 5d64ceb3441..79cb35cd2cd 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3759,7 +3759,6 @@ void StatusPanel::on_ext_spool_edit(wxCommandEvent &event) m_filament_setting_dlg->ams_id = ams_id; m_filament_setting_dlg->slot_id = slot_id; - m_filament_setting_dlg->tray_id = VIRTUAL_TRAY_ID; try { std::string sn_number; From 48ec9edc513dba84490cf4c730c65be7b4ba9610 Mon Sep 17 00:00:00 2001 From: tao wang Date: Wed, 2 Apr 2025 10:51:57 +0800 Subject: [PATCH 039/127] ENH:command ams filament settings is compatible with all AMS jira:[none] Change-Id: I622300794d1fa14826847229737b1f6f2ae490db (cherry picked from commit c2adbe140b134b958f589ba178286e245a09adbf) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 33 ++++---------------------- src/slic3r/GUI/DeviceManager.cpp | 24 ++++++++++++++----- src/slic3r/GUI/DeviceManager.hpp | 2 +- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 7e8d7cd8be2..515edfc695c 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -499,25 +499,9 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { } if (obj) { - // set filament - if (is_virtual_tray()) { - auto tar_tray = VIRTUAL_TRAY_ID; - - if (!obj->is_enable_np) { - tar_tray = VIRTUAL_TRAY_ID; - } - else { - tar_tray = 0; - } - obj->command_ams_filament_settings(ams_id, tar_tray, ams_filament_id, ams_setting_id, color_str, m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); - } - else if(m_is_third){ - if (obj->is_enable_np) { - obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, color_str, m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); - } - else { - obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, color_str, m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); - } + if(m_is_third){ + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, + nozzle_temp_max_int); } // set k / n value @@ -629,16 +613,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) // set filament if (m_is_third) { - if (is_virtual_tray()) { - obj->command_ams_filament_settings(ams_id, VIRTUAL_TRAY_ID, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); - } - else { - if (obj->is_enable_np) { - obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); - } else { - obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); - } - } + obj->command_ams_filament_settings(ams_id, slot_id, ams_filament_id, ams_setting_id, std::string(col_buf), m_filament_type, nozzle_temp_min_int, nozzle_temp_max_int); } //reset param diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 89444a97273..937a5e6f2e7 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1900,16 +1900,28 @@ int MachineObject::command_ams_calibrate(int ams_id) return this->publish_gcode(gcode_cmd); } -int MachineObject::command_ams_filament_settings(int ams_id, int tray_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max) +int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max) { - BOOST_LOG_TRIVIAL(info) << "command_ams_filament_settings, ams_id = " << ams_id << ", tray_id = " << tray_id << ", tray_color = " << tray_color + int tag_tray_id = 0; + int tag_ams_id = ams_id; + int tag_slot_id = slot_id; + + if (tag_ams_id == VIRTUAL_TRAY_ID) { + tag_tray_id = VIRTUAL_TRAY_ID; + } else { + tag_tray_id = tag_slot_id; + } + + + BOOST_LOG_TRIVIAL(info) << "command_ams_filament_settings, ams_id = " << tag_ams_id << ", slot_id = " << tag_slot_id << ", tray_id = " << tag_tray_id << ", tray_color = " << tray_color << ", tray_type = " << tray_type << ", filament_id = " << filament_id << ", setting_id = " << setting_id << ", temp_min: = " << nozzle_temp_min << ", temp_max: = " << nozzle_temp_max; json j; j["print"]["command"] = "ams_filament_setting"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - j["print"]["ams_id"] = ams_id; - j["print"]["tray_id"] = tray_id; + j["print"]["ams_id"] = tag_ams_id; + j["print"]["slot_id"] = tag_slot_id; + j["print"]["tray_id"] = tag_tray_id; j["print"]["tray_info_idx"] = filament_id; j["print"]["setting_id"] = setting_id; // format "FFFFFFFF" RGBA @@ -4098,7 +4110,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " ams settings_id is not exist in filament_list and reset, ams_id: " << ams_id << " tray_id" << tray_id << "filament_id: " << curr_tray->setting_id; - this->command_ams_filament_settings(std::stoi(ams_id), std::stoi(tray_id), "", "", std::string(col_buf), "", 0, 0); + command_ams_filament_settings(std::stoi(ams_id), std::stoi(tray_id), "", "", std::string(col_buf), "", 0, 0); continue; } catch (...) { BOOST_LOG_TRIVIAL(info) @@ -4306,7 +4318,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) sprintf(col_buf, "%02X%02X%02XFF", (int) color.Red(), (int) color.Green(), (int) color.Blue()); try { BOOST_LOG_TRIVIAL(info) << "vt_tray.setting_id is not exist in filament_list and reset vt_tray and the filament_id is: " << vt_tray.setting_id; - this->command_ams_filament_settings(255, std::stoi(vt_tray.id), "", "", std::string(col_buf), "", 0, 0); + this->command_ams_filament_settings(VIRTUAL_TRAY_ID, std::stoi(vt_tray.id), "", "", std::string(col_buf), "", 0, 0); } catch (...) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " stoi error and tray_id" << vt_tray.id; } diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 3759c5e474e..037f80e5020 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -913,7 +913,7 @@ class MachineObject int command_ams_switch_filament(bool switch_filament); int command_ams_air_print_detect(bool air_print_detect); int command_ams_calibrate(int ams_id); - int command_ams_filament_settings(int ams_id, int tray_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max); + int command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max); int command_ams_select_tray(std::string tray_id); int command_ams_refresh_rfid(std::string tray_id); int command_ams_control(std::string action); From 406ccadd064d56d0aa187bc3344186610b85fdca Mon Sep 17 00:00:00 2001 From: tao wang Date: Mon, 7 Apr 2025 20:53:31 +0800 Subject: [PATCH 040/127] ENH:use the correct trayID jira[STUDIO-11274] Change-Id: I0025bb74002b00c448fd4a499e547a5fbd35537f (cherry picked from commit 937f687169091982bc6f11c5e76fb823b0456590) --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 515edfc695c..6452ecc2886 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -653,7 +653,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = vt_tray; - select_index_info.ams_id = vt_tray; + select_index_info.ams_id = ams_id; select_index_info.slot_id = 0; select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; From 37244cce95be0f210854f32657648e9f44361f81 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 20:42:23 +0800 Subject: [PATCH 041/127] Update to latest BBS code. Fix ams filament preset check --- src/slic3r/GUI/DeviceManager.cpp | 684 ++++++++++++++++++------------- src/slic3r/GUI/DeviceManager.hpp | 40 +- src/slic3r/GUI/StatusPanel.cpp | 1 + 3 files changed, 440 insertions(+), 285 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 937a5e6f2e7..156fbc87dbb 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -3917,14 +3917,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) catch (...) { ; } - PresetBundle *preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; - std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << DeviceManager::nozzle_diameter_conver(m_extder_data.extders[0].diameter); - std::string nozzle_diameter_str = stream.str(); - if (m_printer_preset_name.find(nozzle_diameter_str + " nozzle") == std::string::npos) - update_printer_preset_name(nozzle_diameter_str); + update_printer_preset_name(); update_filament_list(); - std::set need_checked_filament_id; if (jj.contains("ams")) { if (jj["ams"].contains("ams")) { long int last_ams_exist_bits = ams_exist_bits; @@ -4098,26 +4092,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } else { curr_tray->type = type; } - // settings_id is not exist in filament_list - if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && - m_filament_list.find(curr_tray->setting_id) == m_filament_list.end()) { - if (m_checked_filament.find(curr_tray->setting_id) == m_checked_filament.end()) { - need_checked_filament_id.insert(curr_tray->setting_id); - wxColour color = *wxWHITE; - char col_buf[10]; - sprintf(col_buf, "%02X%02X%02XFF", (int) color.Red(), (int) color.Green(), (int) color.Blue()); - try { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ - << " ams settings_id is not exist in filament_list and reset, ams_id: " << ams_id - << " tray_id" << tray_id << "filament_id: " << curr_tray->setting_id; - command_ams_filament_settings(std::stoi(ams_id), std::stoi(tray_id), "", "", std::string(col_buf), "", 0, 0); - continue; - } catch (...) { - BOOST_LOG_TRIVIAL(info) - << __FUNCTION__ << " " << __LINE__ << " stoi error and ams_id: " << ams_id << " tray_id" << tray_id; - } - } - } } else { curr_tray->setting_id = ""; curr_tray->type = ""; @@ -4165,29 +4139,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) curr_tray->nozzle_temp_min = (*tray_it)["nozzle_temp_min"].get(); else curr_tray->nozzle_temp_min = ""; - if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && curr_tray->nozzle_temp_min != "" && curr_tray->nozzle_temp_max != "") { - if (m_checked_filament.find(vt_tray.setting_id) == m_checked_filament.end()) { - need_checked_filament_id.insert(vt_tray.setting_id); - try { - std::string preset_setting_id; - bool is_equation = preset_bundle->check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray( - MachineObject::get_preset_printer_model_name(this->printer_type), nozzle_diameter_str, curr_tray->setting_id, - curr_tray->tag_uid, curr_tray->nozzle_temp_min, curr_tray->nozzle_temp_max, preset_setting_id); - if (!is_equation) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ - << " ams filament is not match min max temp and reset, ams_id: " << ams_id - << " tray_id" << tray_id << "filament_id: " << curr_tray->setting_id; - command_ams_filament_settings(std::stoi(ams_id), std::stoi(tray_id), curr_tray->setting_id, preset_setting_id, - curr_tray->color, curr_tray->type, - std::stoi(curr_tray->nozzle_temp_min), - std::stoi(curr_tray->nozzle_temp_max)); - } - continue; - } catch (...) { - BOOST_LOG_TRIVIAL(info) << "check fail and curr_tray ams_id" << ams_id << " curr_tray tray_id"<contains("xcam_info")) curr_tray->xcam_info = (*tray_it)["xcam_info"].get(); else @@ -4209,7 +4160,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } } - + if (tray_it->contains("remain")) { curr_tray->remain = (*tray_it)["remain"].get(); } else { @@ -4221,7 +4172,14 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (!ams_id.empty() && !curr_tray->id.empty()) { ams_id_int = atoi(ams_id.c_str()); tray_id_int = atoi(curr_tray->id.c_str()); - curr_tray->is_exists = (tray_exist_bits & (1 << (ams_id_int * 4 + tray_id_int))) != 0 ? true : false; + + if (type_id < 4) { + curr_tray->is_exists = (tray_exist_bits & (1 << (ams_id_int * 4 + tray_id_int))) != 0 ? true : false; + } + else { + curr_tray->is_exists = get_flag_bits(tray_exist_bits, 16 + (ams_id_int - 128)); + } + } } catch (...) { @@ -4276,149 +4234,13 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (!key_field_only) { try { if (jj.contains("vt_tray")) { - if (jj["vt_tray"].contains("id")) - vt_tray.id = jj["vt_tray"]["id"].get(); - auto curr_time = std::chrono::system_clock::now(); - auto diff = std::chrono::duration_cast(curr_time - extrusion_cali_set_hold_start); - if (diff.count() > HOLD_TIMEOUT || diff.count() < 0 - || extrusion_cali_set_tray_id != VIRTUAL_TRAY_ID) { - if (jj["vt_tray"].contains("k")) - vt_tray.k = jj["vt_tray"]["k"].get(); - if (jj["vt_tray"].contains("n")) - vt_tray.n = jj["vt_tray"]["n"].get(); - } - ams_support_virtual_tray = true; - - if (vt_tray.hold_count > 0) { - vt_tray.hold_count--; - } else { - if (jj["vt_tray"].contains("tag_uid")) - vt_tray.tag_uid = jj["vt_tray"]["tag_uid"].get(); - else - vt_tray.tag_uid = "0"; - if (jj["vt_tray"].contains("tray_info_idx") && jj["vt_tray"].contains("tray_type")) { - vt_tray.setting_id = jj["vt_tray"]["tray_info_idx"].get(); - //std::string type = jj["vt_tray"]["tray_type"].get(); - std::string type = setting_id_to_type(vt_tray.setting_id, jj["vt_tray"]["tray_type"].get()); - if (vt_tray.setting_id == "GFS00") { - vt_tray.type = "PLA-S"; - } - else if (vt_tray.setting_id == "GFS01") { - vt_tray.type = "PA-S"; - } - else { - vt_tray.type = type; - } - if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && - m_filament_list.find(vt_tray.setting_id) == m_filament_list.end()) { - if (m_checked_filament.find(vt_tray.setting_id) == m_checked_filament.end()) { - need_checked_filament_id.insert(vt_tray.setting_id); - wxColour color = *wxWHITE; - char col_buf[10]; - sprintf(col_buf, "%02X%02X%02XFF", (int) color.Red(), (int) color.Green(), (int) color.Blue()); - try { - BOOST_LOG_TRIVIAL(info) << "vt_tray.setting_id is not exist in filament_list and reset vt_tray and the filament_id is: " << vt_tray.setting_id; - this->command_ams_filament_settings(VIRTUAL_TRAY_ID, std::stoi(vt_tray.id), "", "", std::string(col_buf), "", 0, 0); - } catch (...) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " stoi error and tray_id" << vt_tray.id; - } - } - } - } - else { - vt_tray.setting_id = ""; - vt_tray.type = ""; - } - if (jj["vt_tray"].contains("tray_sub_brands")) - vt_tray.sub_brands = jj["vt_tray"]["tray_sub_brands"].get(); - else - vt_tray.sub_brands = ""; - if (jj["vt_tray"].contains("tray_weight")) - vt_tray.weight = jj["vt_tray"]["tray_weight"].get(); - else - vt_tray.weight = ""; - if (jj["vt_tray"].contains("tray_diameter")) - vt_tray.diameter = jj["vt_tray"]["tray_diameter"].get(); - else - vt_tray.diameter = ""; - if (jj["vt_tray"].contains("tray_temp")) - vt_tray.temp = jj["vt_tray"]["tray_temp"].get(); - else - vt_tray.temp = ""; - if (jj["vt_tray"].contains("tray_time")) - vt_tray.time = jj["vt_tray"]["tray_time"].get(); - else - vt_tray.time = ""; - if (jj["vt_tray"].contains("bed_temp_type")) - vt_tray.bed_temp_type = jj["vt_tray"]["bed_temp_type"].get(); - else - vt_tray.bed_temp_type = ""; - if (jj["vt_tray"].contains("bed_temp")) - vt_tray.bed_temp = jj["vt_tray"]["bed_temp"].get(); - else - vt_tray.bed_temp = ""; - if (jj["vt_tray"].contains("tray_color")) { - auto color = jj["vt_tray"]["tray_color"].get(); - vt_tray.update_color_from_str(color); - } else { - vt_tray.color = ""; - } - if (jj["vt_tray"].contains("nozzle_temp_max")) - vt_tray.nozzle_temp_max = jj["vt_tray"]["nozzle_temp_max"].get(); - else - vt_tray.nozzle_temp_max = ""; - if (jj["vt_tray"].contains("nozzle_temp_min")) - vt_tray.nozzle_temp_min = jj["vt_tray"]["nozzle_temp_min"].get(); - else - vt_tray.nozzle_temp_min = ""; - if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && vt_tray.nozzle_temp_min != "" && vt_tray.nozzle_temp_max != "") { - if (m_checked_filament.find(vt_tray.setting_id) == m_checked_filament.end()) { - need_checked_filament_id.insert(vt_tray.setting_id); - try { - std::string preset_setting_id; - bool is_equation = preset_bundle->check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray( - MachineObject::get_preset_printer_model_name(this->printer_type), nozzle_diameter_str, vt_tray.setting_id, vt_tray.tag_uid, - vt_tray.nozzle_temp_min, vt_tray.nozzle_temp_max, preset_setting_id); - if (!is_equation) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " vt_tray filament is not match min max temp and reset, filament_id: " << vt_tray.setting_id; - command_ams_filament_settings(255, std::stoi(vt_tray.id), vt_tray.setting_id, preset_setting_id, vt_tray.color, vt_tray.type, - std::stoi(vt_tray.nozzle_temp_min), std::stoi(vt_tray.nozzle_temp_max)); - } - } catch (...) { - BOOST_LOG_TRIVIAL(info) << "check fail and vt_tray.id" << vt_tray.id; - } - } - } - if (jj["vt_tray"].contains("xcam_info")) - vt_tray.xcam_info = jj["vt_tray"]["xcam_info"].get(); - else - vt_tray.xcam_info = ""; - if (jj["vt_tray"].contains("tray_uuid")) - vt_tray.uuid = jj["vt_tray"]["tray_uuid"].get(); - else - vt_tray.uuid = "0"; + auto main_slot = parse_vt_tray(jj["vt_tray"].get()); + main_slot.id = std::to_string(VIRTUAL_TRAY_ID); - if (jj["vt_tray"].contains("cali_idx")) - vt_tray.cali_idx = jj["vt_tray"]["cali_idx"].get(); - else - vt_tray.cali_idx = -1; - vt_tray.cols.clear(); - if (jj["vt_tray"].contains("cols")) { - if (jj["vt_tray"].is_array()) { - for (auto it = jj["vt_tray"].begin(); it != jj["vt_tray"].end(); it++) { - vt_tray.cols.push_back(it.value().get()); - } - } - } - - if (jj["vt_tray"].contains("remain")) { - vt_tray.remain = jj["vt_tray"]["remain"].get(); - } - else { - vt_tray.remain = -1; - } - } - } else { + is_ams_need_update |= vt_tray != main_slot; + vt_tray = main_slot; + } + else { ams_support_virtual_tray = false; is_support_extrusion_cali = false; } @@ -4821,8 +4643,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) pa_calib_result.extruder_id = -1; } - if (it->contains("nozzle_volume_type")) { - pa_calib_result.nozzle_volume_type = NozzleVolumeType((*it)["nozzle_volume_type"].get()); + if (it->contains("nozzle_id")) { + pa_calib_result.nozzle_volume_type = convert_to_nozzle_type((*it)["nozzle_id"].get()); } else { pa_calib_result.nozzle_volume_type = NozzleVolumeType::nvtNormal; } @@ -5314,104 +5136,145 @@ std::string MachineObject::get_string_from_fantype(FanType type) return ""; } -void MachineObject::update_filament_list() +AmsTray MachineObject::parse_vt_tray(json vtray) { - PresetBundle *preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; + auto vt_tray = AmsTray(std::to_string(VIRTUAL_TRAY_ID)); - // custom filament - std::map> filament_list; - for (auto &preset : preset_bundle->filaments()) { - if (preset.is_user() && preset.inherits() == "") { - ConfigOption * printer_opt = const_cast(preset).config.option("compatible_printers"); - ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); - for (const std::string &printer_str : printer_strs->values) { - if (printer_str == m_printer_preset_name) { - ConfigOption *opt_min = const_cast(preset).config.option("nozzle_temperature_range_low"); - int min_temp = -1; - if (opt_min) { - ConfigOptionInts *opt_min_ints = dynamic_cast(opt_min); - min_temp = opt_min_ints->get_at(0); - } - ConfigOption *opt_max = const_cast(preset).config.option("nozzle_temperature_range_high"); - int max_temp = -1; - if (opt_max) { - ConfigOptionInts *opt_max_ints = dynamic_cast(opt_max); - max_temp = opt_max_ints->get_at(0); - } - filament_list[preset.filament_id] = std::make_pair(min_temp, max_temp); - break; - } - } - } + if (vtray.contains("id")) + vt_tray.id = vtray["id"].get(); + auto curr_time = std::chrono::system_clock::now(); + auto diff = std::chrono::duration_cast(curr_time - extrusion_cali_set_hold_start); + if (diff.count() > HOLD_TIMEOUT || diff.count() < 0 + || extrusion_cali_set_tray_id != VIRTUAL_TRAY_ID) { + if (vtray.contains("k")) + vt_tray.k = vtray["k"].get(); + if (vtray.contains("n")) + vt_tray.n = vtray["n"].get(); } + ams_support_virtual_tray = true; - for (auto it = filament_list.begin(); it != filament_list.end(); it++) { - if (m_filament_list.find(it->first) != m_filament_list.end()) { - assert(it->first.size() == 8 && it->first[0] == 'P'); - - if (it->second.first != m_filament_list[it->first].first) { - BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first; - continue; + if (vt_tray.hold_count > 0) { + vt_tray.hold_count--; + } + else { + if (vtray.contains("tag_uid")) + vt_tray.tag_uid = vtray["tag_uid"].get(); + else + vt_tray.tag_uid = "0"; + if (vtray.contains("tray_info_idx") && vtray.contains("tray_type")) { + vt_tray.setting_id = vtray["tray_info_idx"].get(); + //std::string type = vtray["tray_type"].get(); + std::string type = setting_id_to_type(vt_tray.setting_id, vtray["tray_type"].get()); + if (vt_tray.setting_id == "GFS00") { + vt_tray.type = "PLA-S"; } - - if (it->second.second != m_filament_list[it->first].second) { - BOOST_LOG_TRIVIAL(info) << "old max temp is not equal to new max temp and filament id: " << it->first; - continue; + else if (vt_tray.setting_id == "GFS01") { + vt_tray.type = "PA-S"; + } + else { + vt_tray.type = type; } + } + else { + vt_tray.setting_id = ""; + vt_tray.type = ""; + } + if (vtray.contains("tray_sub_brands")) + vt_tray.sub_brands = vtray["tray_sub_brands"].get(); + else + vt_tray.sub_brands = ""; + if (vtray.contains("tray_weight")) + vt_tray.weight = vtray["tray_weight"].get(); + else + vt_tray.weight = ""; + if (vtray.contains("tray_diameter")) + vt_tray.diameter = vtray["tray_diameter"].get(); + else + vt_tray.diameter = ""; + if (vtray.contains("tray_temp")) + vt_tray.temp = vtray["tray_temp"].get(); + else + vt_tray.temp = ""; + if (vtray.contains("tray_time")) + vt_tray.time = vtray["tray_time"].get(); + else + vt_tray.time = ""; + if (vtray.contains("bed_temp_type")) + vt_tray.bed_temp_type = vtray["bed_temp_type"].get(); + else + vt_tray.bed_temp_type = ""; + if (vtray.contains("bed_temp")) + vt_tray.bed_temp = vtray["bed_temp"].get(); + else + vt_tray.bed_temp = ""; + if (vtray.contains("tray_color")) { + auto color = vtray["tray_color"].get(); + vt_tray.update_color_from_str(color); + } + else { + vt_tray.color = ""; + } + if (vtray.contains("nozzle_temp_max")) + vt_tray.nozzle_temp_max = vtray["nozzle_temp_max"].get(); + else + vt_tray.nozzle_temp_max = ""; + if (vtray.contains("nozzle_temp_min")) + vt_tray.nozzle_temp_min = vtray["nozzle_temp_min"].get(); + else + vt_tray.nozzle_temp_min = ""; + if (vtray.contains("xcam_info")) + vt_tray.xcam_info = vtray["xcam_info"].get(); + else + vt_tray.xcam_info = ""; + if (vtray.contains("tray_uuid")) + vt_tray.uuid = vtray["tray_uuid"].get(); + else + vt_tray.uuid = "0"; - m_filament_list.erase(it->first); + if (vtray.contains("cali_idx")) + vt_tray.cali_idx = vtray["cali_idx"].get(); + else + vt_tray.cali_idx = -1; + vt_tray.cols.clear(); + if (vtray.contains("cols")) { + if (vtray.is_array()) { + for (auto it = vtray.begin(); it != vtray.end(); it++) { + vt_tray.cols.push_back(it.value().get()); + } + } } - } - for (auto it = m_filament_list.begin(); it != m_filament_list.end(); it++) { - m_checked_filament.erase(it->first); + if (vtray.contains("remain")) { + vt_tray.remain = vtray["remain"].get(); + } + else { + vt_tray.remain = -1; + } } - m_filament_list = filament_list; + return vt_tray; } -int MachineObject::get_flag_bits(std::string str, int start, int count) +bool MachineObject::check_enable_np(const json& print) const { - int decimal_value = std::stoi(str, nullptr, 16); - int mask = 0; - for (int i = 0; i < count; i++) { mask += 1 << (start + i); } - - int flag = (decimal_value & (mask)) >> start; - return flag; -} - -int MachineObject::get_flag_bits(int num, int start, int count) -{ - int decimal_value = num; - int mask = 0; - for (int i = 0; i < count; i++) { mask += 1 << (start + i); } - - int flag = (decimal_value & (mask)) >> start; - return flag; -} + if (print.contains("cfg") && print.contains("fun") && print.contains("aux") && print.contains("stat")) + { + return true; + } -void MachineObject::update_printer_preset_name(const std::string &nozzle_diameter_str) -{ - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << "start update preset_name"; - auto preset_boundle = Slic3r::GUI::wxGetApp().preset_bundle; - auto printer_set = preset_boundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(this->printer_type), nozzle_diameter_str); - if (printer_set.size() > 0) - m_printer_preset_name = *printer_set.begin(); - else - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " update printer preset name failed "; + return false; } void MachineObject::parse_new_info(json print) { - if (print.contains("cfg") && print.contains("fun") && print.contains("aux") && print.contains("stat")) { - is_enable_np = true; - BOOST_LOG_TRIVIAL(info) << "using new print data for parsing"; - } - else { - is_enable_np = false; + is_enable_np = check_enable_np(print); + if (!is_enable_np) + { return; } + BOOST_LOG_TRIVIAL(info) << "using new print data for parsing"; + /*cfg*/ std::string cfg = print["cfg"].get(); @@ -5588,6 +5451,277 @@ void MachineObject::parse_new_info(json print) } } +int MachineObject::get_flag_bits(std::string str, int start, int count) const +{ + try { + unsigned long long decimal_value = std::stoull(str, nullptr, 16); + unsigned long long mask = (1ULL << count) - 1; + int flag = (decimal_value >> start) & mask; + return flag; + } catch (...) { + return 0; + } +} + +int MachineObject::get_flag_bits(int num, int start, int count, int base) const +{ + try { + unsigned long long mask = (1ULL << count) - 1; + unsigned long long value; + if (base == 10) { + value = static_cast(num); + } else if (base == 16) { + value = static_cast(std::stoul(std::to_string(num), nullptr, 16)); + } else { + throw std::invalid_argument("Unsupported base"); + } + + int flag = (value >> start) & mask; + return flag; + } catch (...) { + return 0; + } +} + +void MachineObject::update_filament_list() +{ + PresetBundle *preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; + + // custom filament + typedef std::map> map_pair; + std::map map_list; + for (auto &pair : m_nozzle_filament_data) { + map_list[pair.second.printer_preset_name] = map_pair{}; + } + for (auto &preset : preset_bundle->filaments()) { + if (preset.is_user() && preset.inherits() == "") { + ConfigOption * printer_opt = const_cast(preset).config.option("compatible_printers"); + ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); + for (const std::string &printer_str : printer_strs->values) { + if (map_list.find(printer_str) != map_list.end()) { + auto & filament_list = map_list[printer_str]; + ConfigOption *opt_min = const_cast(preset).config.option("nozzle_temperature_range_low"); + int min_temp = -1; + if (opt_min) { + ConfigOptionInts *opt_min_ints = dynamic_cast(opt_min); + min_temp = opt_min_ints->get_at(0); + } + ConfigOption *opt_max = const_cast(preset).config.option("nozzle_temperature_range_high"); + int max_temp = -1; + if (opt_max) { + ConfigOptionInts *opt_max_ints = dynamic_cast(opt_max); + max_temp = opt_max_ints->get_at(0); + } + filament_list[preset.filament_id] = std::make_pair(min_temp, max_temp); + break; + } + } + } + } + + for (auto& pair : m_nozzle_filament_data) { + auto & m_printer_preset_name = pair.second.printer_preset_name; + auto & m_filament_list = pair.second.filament_list; + auto & m_checked_filament = pair.second.checked_filament; + auto & filament_list = map_list[m_printer_preset_name]; + + for (auto it = filament_list.begin(); it != filament_list.end(); it++) { + if (m_filament_list.find(it->first) != m_filament_list.end()) { + assert(it->first.size() == 8 && it->first[0] == 'P'); + + if (it->second.first != m_filament_list[it->first].first) { + BOOST_LOG_TRIVIAL(info) << "old min temp is not equal to new min temp and filament id: " << it->first; + continue; + } + + if (it->second.second != m_filament_list[it->first].second) { + BOOST_LOG_TRIVIAL(info) << "old max temp is not equal to new max temp and filament id: " << it->first; + continue; + } + + m_filament_list.erase(it->first); + } + } + + for (auto it = m_filament_list.begin(); it != m_filament_list.end(); it++) { m_checked_filament.erase(it->first); } + + m_filament_list = filament_list; + } +} + +void MachineObject::update_printer_preset_name() +{ + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << "start update preset_name"; + PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; + if (!preset_bundle) return; + auto printer_model = MachineObject::get_preset_printer_model_name(this->printer_type); + std::set diameter_set; + for (auto &nozzle : m_extder_data.extders) { + float diameter = nozzle.diameter; + std::ostringstream stream; + stream << std::fixed << std::setprecision(1) << diameter; + std::string nozzle_diameter_str = stream.str(); + diameter_set.insert(nozzle_diameter_str); + if (m_nozzle_filament_data.find(nozzle_diameter_str) != m_nozzle_filament_data.end()) continue; + auto data = FilamentData(); + auto printer_set = preset_bundle->get_printer_names_by_printer_type_and_nozzle(printer_model, nozzle_diameter_str); + if (printer_set.size() > 0) { + data.printer_preset_name = *printer_set.begin(); + m_nozzle_filament_data[nozzle_diameter_str] = data; + } + else + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " update printer preset name failed: "<< "printer_type: " << printer_type << "nozzle_diameter_str" << nozzle_diameter_str; + } + + for (auto iter = m_nozzle_filament_data.begin(); iter != m_nozzle_filament_data.end();) + { + if (diameter_set.find(iter->first) == diameter_set.end()) + { + iter = m_nozzle_filament_data.erase(iter); + } + else + { + ++iter; + } + } +} + +void MachineObject::check_ams_filament_valid() +{ + PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; + auto printer_model = MachineObject::get_preset_printer_model_name(this->printer_type); + std::map> need_checked_filament_id; + for (auto &ams_pair : amsList) { + auto ams_id = ams_pair.first; + auto &ams = ams_pair.second; + std::ostringstream stream; + if (ams->nozzle < 0 || ams->nozzle >= m_extder_data.extders.size()) { + return; + } + stream << std::fixed << std::setprecision(1) << m_extder_data.extders[ams->nozzle].diameter; + std::string nozzle_diameter_str = stream.str(); + assert(nozzle_diameter_str.size() == 3); + if (m_nozzle_filament_data.find(nozzle_diameter_str) == m_nozzle_filament_data.end()) { + //assert(false); + continue; + } + auto &data = m_nozzle_filament_data[nozzle_diameter_str]; + auto &filament_list = data.filament_list; + auto &checked_filament = data.checked_filament; + for (const auto &[slot_id, curr_tray] : ams->trayList) { + + if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && filament_list.find(curr_tray->setting_id) == filament_list.end()) { + if (checked_filament.find(curr_tray->setting_id) == checked_filament.end()) { + need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id); + wxColour color = *wxWHITE; + char col_buf[10]; + sprintf(col_buf, "%02X%02X%02XFF", (int) color.Red(), (int) color.Green(), (int) color.Blue()); + try { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " ams settings_id is not exist in filament_list and reset, ams_id: " << ams_id << " tray_id" + << slot_id << "filament_id: " << curr_tray->setting_id; + + command_ams_filament_settings(std::stoi(ams_id), std::stoi(slot_id), "", "", std::string(col_buf), "", 0, 0); + continue; + } catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " stoi error and ams_id: " << ams_id << " tray_id" << slot_id; + } + } + } + if (curr_tray->setting_id.size() == 8 && curr_tray->setting_id[0] == 'P' && curr_tray->nozzle_temp_min != "" && curr_tray->nozzle_temp_max != "") { + if (checked_filament.find(curr_tray->setting_id) == checked_filament.end()) { + need_checked_filament_id[nozzle_diameter_str].insert(curr_tray->setting_id); + try { + std::string preset_setting_id; + bool is_equation = preset_bundle->check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(printer_model, nozzle_diameter_str, + curr_tray->setting_id, curr_tray->tag_uid, + curr_tray->nozzle_temp_min, + curr_tray->nozzle_temp_max, preset_setting_id); + if (!is_equation) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " ams filament is not match min max temp and reset, ams_id: " << ams_id << " tray_id" + << slot_id << "filament_id: " << curr_tray->setting_id; + + + command_ams_filament_settings(std::stoi(ams_id), std::stoi(slot_id), curr_tray->setting_id, preset_setting_id, curr_tray->color, curr_tray->type, + std::stoi(curr_tray->nozzle_temp_min), std::stoi(curr_tray->nozzle_temp_max)); + } + continue; + } catch (...) { + BOOST_LOG_TRIVIAL(info) << "check fail and curr_tray ams_id" << ams_id << " curr_tray tray_id" << slot_id; + } + } + } + } + } + + /*for (auto vt_tray : vt_slot)*/ do{ + int vt_id = std::stoi(vt_tray.id); + int index = 255 - vt_id; + if (index >= m_extder_data.total_extder_count) { + BOOST_LOG_TRIVIAL(error) << " vt_tray id map for nozzle id is not exist, index is: " << index << " nozzle count" << m_extder_data.total_extder_count; + continue; + } + auto diameter = m_extder_data.extders[index].diameter; + std::ostringstream stream; + stream << std::fixed << std::setprecision(1) << diameter; + std::string nozzle_diameter_str = stream.str(); + if (m_nozzle_filament_data.find(nozzle_diameter_str) == m_nozzle_filament_data.end()) { + continue; + } + auto &data = m_nozzle_filament_data[nozzle_diameter_str]; + auto &checked_filament = data.checked_filament; + auto &filament_list = data.filament_list; + if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && filament_list.find(vt_tray.setting_id) == filament_list.end()) { + if (checked_filament.find(vt_tray.setting_id) == checked_filament.end()) { + need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id); + wxColour color = *wxWHITE; + char col_buf[10]; + sprintf(col_buf, "%02X%02X%02XFF", (int) color.Red(), (int) color.Green(), (int) color.Blue()); + try { + BOOST_LOG_TRIVIAL(info) << "vt_tray.setting_id is not exist in filament_list and reset vt_tray and the filament_id is: " << vt_tray.setting_id; + command_ams_filament_settings(vt_id, 0, "", "", std::string(col_buf), "", 0, 0); + continue; + } catch (...) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " stoi error and tray_id" << vt_tray.id; + } + } + } + if (vt_tray.setting_id.size() == 8 && vt_tray.setting_id[0] == 'P' && vt_tray.nozzle_temp_min != "" && vt_tray.nozzle_temp_max != "") { + if (checked_filament.find(vt_tray.setting_id) == checked_filament.end()) { + need_checked_filament_id[nozzle_diameter_str].insert(vt_tray.setting_id); + try { + std::string preset_setting_id; + PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; + std::ostringstream stream; + stream << std::fixed << std::setprecision(1) << m_extder_data.extders[MAIN_NOZZLE_ID].diameter; + std::string nozzle_diameter_str = stream.str(); + bool is_equation = preset_bundle->check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(MachineObject::get_preset_printer_model_name( + this->printer_type), + nozzle_diameter_str, vt_tray.setting_id, + vt_tray.tag_uid, vt_tray.nozzle_temp_min, + vt_tray.nozzle_temp_max, preset_setting_id); + if (!is_equation) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ + << " vt_tray filament is not match min max temp and reset, filament_id: " << vt_tray.setting_id; + command_ams_filament_settings(vt_id, 0, vt_tray.setting_id, preset_setting_id, vt_tray.color, vt_tray.type, std::stoi(vt_tray.nozzle_temp_min), + std::stoi(vt_tray.nozzle_temp_max)); + + } + } catch (...) { + BOOST_LOG_TRIVIAL(info) << "check fail and vt_tray.id" << vt_tray.id; + } + } + } + } while (0); + + for (auto &diameter_pair : m_nozzle_filament_data) { + auto &diameter = diameter_pair.first; + auto &data = diameter_pair.second; + for (auto &filament_id : need_checked_filament_id[diameter]) { + data.checked_filament.insert(filament_id); + } + } +} + bool DeviceManager::EnableMultiMachine = false; bool DeviceManager::key_field_only = false; @@ -6074,18 +6208,20 @@ bool DeviceManager::set_selected_machine(std::string dev_id, bool need_disconnec } } else { BOOST_LOG_TRIVIAL(info) << "static: set_selected_machine: same dev_id = empty"; - m_agent->set_user_selected_machine(""); it->second->reset(); #if !BBL_RELEASE_TO_PUBLIC it->second->connect(false, Slic3r::GUI::wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false); #else it->second->connect(false, it->second->local_use_ssl_for_mqtt); #endif + m_agent->set_user_selected_machine(dev_id); it->second->set_lan_mode_connection_state(true); } } } - it->second->m_checked_filament.clear(); + for (auto& data : it->second->m_nozzle_filament_data) { + data.second.checked_filament.clear(); + } } selected_machine = dev_id; return true; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 037f80e5020..4c5c671495d 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -37,6 +37,9 @@ #define HOLD_COUNT_CAMERA 6 #define GET_VERSION_RETRYS 10 #define RETRY_INTERNAL 2000 + +#define MAIN_NOZZLE_ID 0 + #define VIRTUAL_TRAY_ID 254 #define START_SEQ_ID 20000 #define END_SEQ_ID 30000 @@ -210,6 +213,12 @@ class AmsTray { return wxColour(ret[0], ret[1], ret[2], ret[3]); } + bool operator==(AmsTray const &o) const + { + return id == o.id && type == o.type && filament_setting_id == o.filament_setting_id && color == o.color; + } + bool operator!=(AmsTray const &o) const { return !operator==(o); } + std::string id; std::string tag_uid; // tag_uid std::string setting_id; // tray_info_idx @@ -517,8 +526,6 @@ class MachineObject /* ams properties */ std::map amsList; // key: ams[id], start with 0 - AmsTray vt_tray; // virtual tray - std::vector vt_trays; // virtual tray for new long ams_exist_bits = 0; long tray_exist_bits = 0; long tray_is_bbl_bits = 0; @@ -1020,19 +1027,30 @@ class MachineObject /*for more extruder*/ bool is_enable_np{ false }; - ExtderData m_extder_data; - /* Device Filament Check */ - std::set m_checked_filament; - std::string m_printer_preset_name; - std::map> m_filament_list; // filament_id, pair - void update_filament_list(); + ExtderData m_extder_data; + /*vi slot data*/ + AmsTray vt_tray; // virtual tray + //std::vector vt_trays; // virtual tray for new + AmsTray parse_vt_tray(json vtray); /*for parse new info*/ + bool check_enable_np(const json& print) const; void parse_new_info(json print); - int get_flag_bits(std::string str, int start, int count = 1); - int get_flag_bits(int num, int start, int count = 1); - void update_printer_preset_name(const std::string &nozzle_diameter_str); + int get_flag_bits(std::string str, int start, int count = 1) const; + int get_flag_bits(int num, int start, int count = 1, int base = 10) const; + + /* Device Filament Check */ + struct FilamentData + { + std::set checked_filament; + std::string printer_preset_name; + std::map> filament_list; // filament_id, pair + }; + std::map m_nozzle_filament_data; + void update_filament_list(); + void update_printer_preset_name(); + void check_ams_filament_valid(); }; diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 79cb35cd2cd..b4d461b811e 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2600,6 +2600,7 @@ void StatusPanel::update_ams(MachineObject *obj) if (obj) { if (obj->get_printer_ams_type() == "f1") { ams_mode = AMSModel::EXTRA_AMS; } else if(obj->get_printer_ams_type() == "generic") { ams_mode = AMSModel::GENERIC_AMS; } + obj->check_ams_filament_valid(); } if (!obj From fe0f6497ad7b73eb376e94ede78d6ffd9fbd38ed Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 7 May 2025 21:11:16 +0800 Subject: [PATCH 042/127] Fix external filament calib --- src/slic3r/GUI/AMSMaterialsSetting.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 6452ecc2886..2ebd8bf99a5 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -528,7 +528,18 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { } else { PACalibIndexInfo select_index_info; - select_index_info.tray_id = ams_id * 4 + slot_id; + int tray_id = ams_id * 4 + slot_id; + if (is_virtual_tray()) { + tray_id = ams_id; + if (!obj->is_enable_np) { + tray_id = VIRTUAL_TRAY_ID; + } + + // TODO: Orca hack + ams_id = 255; + slot_id = 0; + } + select_index_info.tray_id = tray_id; select_index_info.ams_id = ams_id; select_index_info.slot_id = slot_id; select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; @@ -653,7 +664,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) if (obj->cali_version >= 0) { PACalibIndexInfo select_index_info; select_index_info.tray_id = vt_tray; - select_index_info.ams_id = ams_id; + select_index_info.ams_id = 255; // TODO: Orca hack select_index_info.slot_id = 0; select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; From 2ce2facb0e3cca21af6d2688bbba49ff86471d01 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 12 May 2025 21:51:34 +0800 Subject: [PATCH 043/127] Add network debugging --- src/slic3r/GUI/DeviceManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 156fbc87dbb..3b284e46cd3 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -24,6 +24,8 @@ #define MINUTE_30 1800000 //ms #define TIME_OUT 5000 //ms +#define ORCA_NETWORK_DEBUG + namespace pt = boost::property_tree; float string_to_float(const std::string& str_value) { @@ -2773,6 +2775,10 @@ static ENUM enum_index_of(char const *key, char const **enum_names, int enum_cou int MachineObject::parse_json(std::string payload, bool key_field_only) { +#ifdef ORCA_NETWORK_DEBUG + BOOST_LOG_TRIVIAL(info) << "parse_json: payload = " << payload; +#endif + parse_msg_count++; std::chrono::system_clock::time_point clock_start = std::chrono::system_clock::now(); this->set_online_state(true); From d4809b58b81c2c13d93c034717991995a4eb4822 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 14 May 2025 11:26:24 +0800 Subject: [PATCH 044/127] Fix startup crash when network plugin is not enabled --- src/slic3r/GUI/GUI_App.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1389c13aa78..a4270c3131e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2782,13 +2782,12 @@ void GUI_App::copy_network_if_available() bool GUI_App::on_init_network(bool try_backup) { + bool create_network_agent = false; auto should_load_networking_plugin = app_config->get_bool("installed_networking"); if(!should_load_networking_plugin) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "Don't load plugin as installed_networking is false"; - return false; - } + } else { int load_agent_dll = Slic3r::NetworkAgent::initialize_network_module(); - bool create_network_agent = false; __retry: if (!load_agent_dll) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_init_network, load dll ok"; @@ -2824,6 +2823,7 @@ bool GUI_App::on_init_network(bool try_backup) m_networking_need_update = true; } } + } if (create_network_agent) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", create network agent..."); From 1c58c933e2a14ac043c0b891bcaeafcf3b4b9bf6 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 14 May 2025 20:39:27 +0800 Subject: [PATCH 045/127] Add missing print params --- src/slic3r/GUI/Jobs/PrintJob.cpp | 4 ++ src/slic3r/GUI/Jobs/PrintJob.hpp | 16 +++++++- src/slic3r/GUI/SelectMachine.cpp | 66 ++++++++++++++++++++++++++++++-- src/slic3r/GUI/SelectMachine.hpp | 13 +++++++ src/slic3r/Utils/CalibUtils.cpp | 2 +- 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index 83a59672c62..990053622e5 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -233,10 +233,14 @@ void PrintJob::process(Ctl &ctl) params.ams_mapping = this->task_ams_mapping; params.ams_mapping2 = this->task_ams_mapping2; params.ams_mapping_info = this->task_ams_mapping_info; + params.nozzles_info = this->task_nozzles_info; params.connection_type = this->connection_type; params.task_use_ams = this->task_use_ams; params.task_bed_type = this->task_bed_type; params.print_type = this->m_print_type; + params.auto_bed_leveling = this->auto_bed_leveling; + params.auto_flow_cali = this->auto_flow_cali; + params.auto_offset_cali = this->auto_offset_cali; if (m_print_type == "from_sdcard_view") { params.dst_file = m_dst_path; diff --git a/src/slic3r/GUI/Jobs/PrintJob.hpp b/src/slic3r/GUI/Jobs/PrintJob.hpp index 9d7639aeb43..3d7421898cd 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.hpp +++ b/src/slic3r/GUI/Jobs/PrintJob.hpp @@ -63,6 +63,7 @@ class PrintJob : public Job std::string task_ams_mapping; std::string task_ams_mapping2; std::string task_ams_mapping_info; + std::string task_nozzles_info; std::string connection_type; std::string m_print_type; std::string m_dst_path; @@ -70,7 +71,7 @@ class PrintJob : public Job bool m_is_calibration_task = false; int m_print_from_sdc_plate_idx = 0; - + bool m_local_use_ssl_for_mqtt { true }; bool m_local_use_ssl_for_ftp { true }; bool task_bed_leveling; @@ -82,7 +83,14 @@ class PrintJob : public Job bool has_sdcard { false }; bool task_use_ams { true }; - void set_print_config(std::string bed_type, bool bed_leveling, bool flow_cali, bool vabration_cali, bool record_timelapse, bool layer_inspect) + int auto_bed_leveling{0}; + int auto_flow_cali{0}; + int auto_offset_cali{0}; + + void set_print_config(std::string bed_type, bool bed_leveling, bool flow_cali, bool vabration_cali, bool record_timelapse, bool layer_inspect, + int auto_bed_levelingt, + int auto_flow_calit, + int auto_offset_calit) { task_bed_type = bed_type; task_bed_leveling = bed_leveling; @@ -90,6 +98,10 @@ class PrintJob : public Job task_vibration_cali = vabration_cali; task_record_timelapse = record_timelapse; task_layer_inspect = layer_inspect; + + auto_bed_leveling = auto_bed_levelingt; + auto_flow_cali = auto_flow_calit; + auto_offset_cali = auto_offset_calit; } int status_range() const diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index ebcf23cf0af..87743bbca74 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1962,6 +1962,8 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_) } else { sync_ams_mapping_result(m_ams_mapping_result); BOOST_LOG_TRIVIAL(info) << "ams_mapping_array=" << ams_array; + BOOST_LOG_TRIVIAL(info) << "ams_mapping_array2=" << ams_array2; + BOOST_LOG_TRIVIAL(info) << "ams_mapping_info=" << mapping_info; } return obj_->is_valid_mapping_result(m_ams_mapping_result); } else { @@ -2039,8 +2041,8 @@ bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, try { if (m_ams_mapping_result[k].ams_id.empty() || m_ams_mapping_result[k].slot_id.empty()) { // invalid case - mapping_item_v1["ams_id"] = VIRTUAL_TRAY_ID; - mapping_item_v1["slot_id"] = VIRTUAL_TRAY_ID; + mapping_item_v1["ams_id"] = 255; // TODO: Orca hack + mapping_item_v1["slot_id"] = 255; } else { mapping_item_v1["ams_id"] = std::stoi(m_ams_mapping_result[k].ams_id); @@ -2067,6 +2069,56 @@ bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, return true; } +bool SelectMachineDialog::build_nozzles_info(std::string& nozzles_info) +{ + /* init nozzles info */ + json nozzle_info_json = json::array(); + nozzles_info = nozzle_info_json.dump(); + + PresetBundle* preset_bundle = wxGetApp().preset_bundle; + if (!preset_bundle) + return false; + auto opt_nozzle_diameters = preset_bundle->printers.get_edited_preset().config.option("nozzle_diameter"); + if (opt_nozzle_diameters == nullptr) { + BOOST_LOG_TRIVIAL(error) << "build_nozzles_info, opt_nozzle_diameters is nullptr"; + return false; + } + //auto opt_nozzle_volume_type = preset_bundle->project_config.option("nozzle_volume_type"); + //if (opt_nozzle_volume_type == nullptr) { + // BOOST_LOG_TRIVIAL(error) << "build_nozzles_info, opt_nozzle_volume_type is nullptr"; + // return false; + //} + json nozzle_item; + /* only o1d two nozzles has build_nozzles info now */ + if (opt_nozzle_diameters->size() != 2) { + return false; + } + for (size_t i = 0; i < opt_nozzle_diameters->size(); i++) { + if (i == (size_t)ConfigNozzleIdx::NOZZLE_LEFT) { + nozzle_item["id"] = CloudTaskNozzleId::NOZZLE_LEFT; + } + else if (i == (size_t)ConfigNozzleIdx::NOZZLE_RIGHT) { + nozzle_item["id"] = CloudTaskNozzleId::NOZZLE_RIGHT; + } + else { + /* unknown ConfigNozzleIdx */ + BOOST_LOG_TRIVIAL(error) << "build_nozzles_info, unknown ConfigNozzleIdx = " << i; + assert(false); + continue; + } + nozzle_item["type"] = nullptr; + //if (i >= 0 && i < opt_nozzle_volume_type->size()) { + nozzle_item["flowSize"] = "standard_flow"; // TODO: Orca hack + //} + if (i >= 0 && i < opt_nozzle_diameters->size()) { + nozzle_item["diameter"] = opt_nozzle_diameters->get_at(i); + } + nozzle_info_json.push_back(nozzle_item); + } + nozzles_info = nozzle_info_json.dump(); + return true; +} + void SelectMachineDialog::prepare(int print_plate_idx) { m_print_plate_idx = print_plate_idx; @@ -2997,6 +3049,11 @@ void SelectMachineDialog::on_send_print() m_print_job->task_ams_mapping_info = ""; } + /* build nozzles info for multi extruders printers */ + if (build_nozzles_info(m_print_job->task_nozzles_info)) { + BOOST_LOG_TRIVIAL(error) << "build_nozzle_info errors"; + } + m_print_job->has_sdcard = obj_->has_sdcard(); @@ -3008,7 +3065,10 @@ void SelectMachineDialog::on_send_print() m_checkbox_list["flow_cali"]->GetValue(), false, timelapse_option, - true); + true, + 0, // TODO: Orca hack + 0, + 0); if (obj_->has_ams()) { m_print_job->task_use_ams = m_checkbox_list["use_ams"]->GetValue(); diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index ac43251511a..1b6c62b31e5 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -64,6 +64,18 @@ enum PrintFromType { FROM_SDCARD_VIEW, }; +enum class CloudTaskNozzleId : int +{ + NOZZLE_RIGHT = 0, + NOZZLE_LEFT = 1, +}; + +enum class ConfigNozzleIdx : int +{ + NOZZLE_LEFT = 0, + NOZZLE_RIGHT = 1, +}; + static int get_brightness_value(wxImage image) { wxImage grayImage = image.ConvertToGreyscale(); @@ -539,6 +551,7 @@ class SelectMachineDialog : public DPIDialog bool Show(bool show); bool do_ams_mapping(MachineObject* obj_); bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info); + bool build_nozzles_info(std::string& nozzles_info); PrintFromType get_print_type() {return m_print_type;}; wxString format_steel_name(std::string name); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 0bde1163b28..73e9126ccd6 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -1243,7 +1243,7 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess print_job->set_calibration_task(true); print_job->has_sdcard = obj_->has_sdcard(); - print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true); + print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true, 0, 0, 0); print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name); { // after send: record the print job From 795945376cf274365ce88daa4819c6d0904bcf64 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 14 May 2025 21:26:18 +0800 Subject: [PATCH 046/127] Fix external spool filament settings --- src/slic3r/GUI/DeviceManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 3b284e46cd3..312fb087f81 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1910,6 +1910,7 @@ int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::s if (tag_ams_id == VIRTUAL_TRAY_ID) { tag_tray_id = VIRTUAL_TRAY_ID; + tag_ams_id = 255; // TODO: Orca hack } else { tag_tray_id = tag_slot_id; } From 8f143a176474521441ca5ddcb23610223d8c8db8 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Tue, 18 Feb 2025 10:53:09 +0800 Subject: [PATCH 047/127] FIX: the humidity display jira: [STUDIO-10481] Change-Id: Ib4bec6db6afbe40199c401c539b13a0e8459bbad (cherry picked from commit 658a8ab7ef1d2149fee58b45ea9455bb188f82f0) --- resources/images/hum_level1_no_num_dark.svg | 4 + resources/images/hum_level1_no_num_light.svg | 4 + resources/images/hum_level2_no_num_dark.svg | 4 + resources/images/hum_level2_no_num_light.svg | 4 + resources/images/hum_level3_no_num_dark.svg | 4 + resources/images/hum_level3_no_num_light.svg | 4 + resources/images/hum_level4_no_num_dark.svg | 4 + resources/images/hum_level4_no_num_light.svg | 4 + resources/images/hum_level5_no_num_dark.svg | 4 + resources/images/hum_level5_no_num_light.svg | 4 + src/slic3r/GUI/DeviceManager.cpp | 23 +++--- src/slic3r/GUI/DeviceManager.hpp | 2 +- src/slic3r/GUI/Widgets/AMSControl.cpp | 1 + src/slic3r/GUI/Widgets/AMSItem.cpp | 82 ++++++++++++++++---- src/slic3r/GUI/Widgets/AMSItem.hpp | 9 ++- 15 files changed, 126 insertions(+), 31 deletions(-) create mode 100644 resources/images/hum_level1_no_num_dark.svg create mode 100644 resources/images/hum_level1_no_num_light.svg create mode 100644 resources/images/hum_level2_no_num_dark.svg create mode 100644 resources/images/hum_level2_no_num_light.svg create mode 100644 resources/images/hum_level3_no_num_dark.svg create mode 100644 resources/images/hum_level3_no_num_light.svg create mode 100644 resources/images/hum_level4_no_num_dark.svg create mode 100644 resources/images/hum_level4_no_num_light.svg create mode 100644 resources/images/hum_level5_no_num_dark.svg create mode 100644 resources/images/hum_level5_no_num_light.svg diff --git a/resources/images/hum_level1_no_num_dark.svg b/resources/images/hum_level1_no_num_dark.svg new file mode 100644 index 00000000000..865a6c4a7f3 --- /dev/null +++ b/resources/images/hum_level1_no_num_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level1_no_num_light.svg b/resources/images/hum_level1_no_num_light.svg new file mode 100644 index 00000000000..be7c282e144 --- /dev/null +++ b/resources/images/hum_level1_no_num_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level2_no_num_dark.svg b/resources/images/hum_level2_no_num_dark.svg new file mode 100644 index 00000000000..9b47beef091 --- /dev/null +++ b/resources/images/hum_level2_no_num_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level2_no_num_light.svg b/resources/images/hum_level2_no_num_light.svg new file mode 100644 index 00000000000..b84791da268 --- /dev/null +++ b/resources/images/hum_level2_no_num_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level3_no_num_dark.svg b/resources/images/hum_level3_no_num_dark.svg new file mode 100644 index 00000000000..b5b08a15050 --- /dev/null +++ b/resources/images/hum_level3_no_num_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level3_no_num_light.svg b/resources/images/hum_level3_no_num_light.svg new file mode 100644 index 00000000000..e1fbd560f77 --- /dev/null +++ b/resources/images/hum_level3_no_num_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level4_no_num_dark.svg b/resources/images/hum_level4_no_num_dark.svg new file mode 100644 index 00000000000..980ada05d86 --- /dev/null +++ b/resources/images/hum_level4_no_num_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level4_no_num_light.svg b/resources/images/hum_level4_no_num_light.svg new file mode 100644 index 00000000000..4fb5bc7c617 --- /dev/null +++ b/resources/images/hum_level4_no_num_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level5_no_num_dark.svg b/resources/images/hum_level5_no_num_dark.svg new file mode 100644 index 00000000000..ab55eff332a --- /dev/null +++ b/resources/images/hum_level5_no_num_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/hum_level5_no_num_light.svg b/resources/images/hum_level5_no_num_light.svg new file mode 100644 index 00000000000..c96f344b07a --- /dev/null +++ b/resources/images/hum_level5_no_num_light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 312fb087f81..0bb38f3dd0d 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -590,7 +590,6 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string ams_insert_flag = false; ams_power_on_flag = false; ams_calibrate_remain_flag = false; - ams_humidity = 5; /* signals */ wifi_signal = ""; @@ -3961,16 +3960,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } if (jj["ams"].contains("ams_rfid_status")) ams_rfid_status = jj["ams"]["ams_rfid_status"].get(); - if (jj["ams"].contains("humidity")) { - if (jj["ams"]["humidity"].is_string()) { - std::string humidity_str = jj["ams"]["humidity"].get(); - try { - ams_humidity = atoi(humidity_str.c_str()); - } catch (...) { - ; - } - } - } if (jj["ams"].contains("insert_flag") || jj["ams"].contains("power_on_flag") || jj["ams"].contains("calibrate_remain_flag")) { @@ -4053,7 +4042,17 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) ; } } - + + if (it->contains("humidity_raw")) + { + std::string humidity_raw = (*it)["humidity_raw"].get(); + + try { + curr_ams->humidity_raw = atoi(humidity_raw.c_str()); + } catch (...) { + ; + } + } if (it->contains("tray")) { std::set tray_id_set; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 4c5c671495d..0d857d47838 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -274,6 +274,7 @@ class Ams { } std::string id; int humidity = 5; + int humidity_raw = -1;// the percentage, -1 means invalid. eg. 100 means 100% bool startup_read_opt{true}; bool tray_read_opt{false}; bool is_exists{false}; @@ -538,7 +539,6 @@ class MachineObject bool ams_auto_switch_filament_flag { false }; bool ams_air_print_status { false }; bool ams_support_virtual_tray { true }; - int ams_humidity; int ams_user_setting_hold_count = 0; AmsStatusMain ams_status_main; int ams_status_sub; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 7b43f19affe..c535249ce22 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -782,6 +782,7 @@ void AMSControl::msw_rescale() m_button_guide->SetMinSize(wxSize(-1, FromDIP(24))); m_button_retry->SetMinSize(wxSize(-1, FromDIP(24))); m_vams_lib->msw_rescale(); + m_vams_road->msw_rescale(); for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { AmsCansWindow *cans = m_ams_cans_list[i]; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 05aec784458..617816932aa 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -44,12 +44,14 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo if (humidity_flag) { this->ams_humidity = ams->humidity; } - else { + else{ this->ams_humidity = -1; } - + + this->humidity_raw = ams->humidity_raw; + cans.clear(); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < ams->trayList.size(); i++) { auto it = ams->trayList.find(std::to_string(i)); Caninfo info; // tray is exists @@ -74,7 +76,7 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo } else { info.material_state = AMSCanType::AMS_CAN_TYPE_THIRDBRAND; } - + if (!MachineObject::is_bbl_filament(it->second->tag_uid) || !remain_flag) { info.material_remain = 100; } else { @@ -1402,13 +1404,11 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_NONE_ANY_ROAD; } - for (int i = 1; i <= 5; i++) { - ams_humidity_img.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 32)); - } + for (int i = 1; i <= 5; i++) { ams_humidity_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 32));} + for (int i = 1; i <= 5; i++) { ams_humidity_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 32));} + for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } + for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } - for (int i = 1; i <= 5; i++) { - ams_humidity_img.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 32)); - } if (m_rode_mode != AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { create(parent, id, pos, size); } @@ -1588,15 +1588,52 @@ void AMSRoad::doRender(wxDC &dc) if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) {m_show_humidity = true;} else {m_show_humidity = false;} - if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) { + if (m_show_humidity) { + wxPoint pot; + if (m_amsinfo.humidity_raw != -1) /*image with no number + percentage*/ + { + // hum image + ScalableBitmap hum_img; + if (!wxGetApp().dark_mode()) { + hum_img = ams_humidity_no_num_imgs[m_amsinfo.ams_humidity - 1]; + } else { + hum_img = ams_humidity_no_num_dark_imgs[m_amsinfo.ams_humidity - 1]; + } - int hum_index = m_amsinfo.ams_humidity - 1; - if (wxGetApp().dark_mode()) { - hum_index += 5; + pot = wxPoint(FromDIP(5), size.y - hum_img.GetBmpSize().y - FromDIP(8)); + dc.DrawBitmap(hum_img.bmp(), pot); + + // percentage + wxString hum_percentage(std::to_string(m_amsinfo.humidity_raw)); + auto tsize = dc.GetMultiLineTextExtent(hum_percentage); + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetFont(Label::Body_14); + dc.SetTextForeground(StateColor::darkModeColorFor(AMS_CONTROL_BLACK_COLOUR)); + // pot = wxPoint(FromDIP(size.x * 0.3), FromDIP((size.y - tsize.y) / 2)); + pot.x = pot.x + hum_img.GetBmpSize().x + FromDIP(3); + dc.DrawText(hum_percentage, pot); + + pot.x += (tsize.x + FromDIP(5)); + dc.SetFont(Label::Body_12); + tsize = dc.GetMultiLineTextExtent(_L("%")); + pot.y += (tsize.y / 2 - FromDIP(4)); + dc.DrawText(_L("%"), pot); + + pot.x = pot.x + tsize.x + FromDIP(2); } + else /*image with number*/ + { + // hum image + ScalableBitmap hum_img; + if (!wxGetApp().dark_mode()) { + hum_img = ams_humidity_imgs[m_amsinfo.ams_humidity - 1]; + } else { + hum_img = ams_humidity_dark_imgs[m_amsinfo.ams_humidity - 1]; + } - if (hum_index >= 0) { - dc.DrawBitmap(ams_humidity_img[hum_index].bmp(), wxPoint(size.x - FromDIP(33), size.y - FromDIP(33))); + pot = wxPoint(size.x - FromDIP(33), size.y - FromDIP(33)); + dc.DrawBitmap(hum_img.bmp(), pot); + pot.x = pot.x + hum_img.GetBmpSize().x + FromDIP(3); } } else { @@ -1658,6 +1695,14 @@ void AMSRoad::OnPassRoad(std::vector prord_list) } } +void AMSRoad::msw_rescale() +{ + for (auto& img : ams_humidity_imgs) { img.msw_rescale();} + for (auto& img : ams_humidity_dark_imgs) { img.msw_rescale(); } + for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } + for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } +} + /************************************************* Description:AmsCan @@ -2191,6 +2236,11 @@ void AmsCans::msw_rescale() CanLibs* lib = m_can_lib_list[i]; lib->canLib->msw_rescale(); } + + for (auto i = 0; i < m_can_road_list.GetCount(); i++) { + CanRoads* road = m_can_road_list[i]; + road->canRoad->msw_rescale(); + } } void AmsCans::show_sn_value(bool show) diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index bdd13459d06..a089da690d2 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -159,6 +159,7 @@ struct AMSinfo AMSAction current_action; int curreent_filamentstep; int ams_humidity = 0; + int humidity_raw = -1; bool parse_ams_info(MachineObject* obj, Ams *ams, bool remain_flag = false, bool humidity_flag = false); }; @@ -390,8 +391,11 @@ class AMSRoad : public wxWindow wxColour m_road_color; void Update(AMSinfo amsinfo, Caninfo info, int canindex, int maxcan); - std::vector ams_humidity_img; + std::vector ams_humidity_imgs; + std::vector ams_humidity_dark_imgs; + std::vector ams_humidity_no_num_imgs; + std::vector ams_humidity_no_num_dark_imgs; int m_humidity = { 0 }; bool m_show_humidity = { false }; @@ -406,7 +410,8 @@ class AMSRoad : public wxWindow void paintEvent(wxPaintEvent &evt); void render(wxDC &dc); - void doRender(wxDC &dc); + void doRender(wxDC& dc); + void msw_rescale(); }; /************************************************* From b998ddd1bd31fc1fd3c4db6e5c950a37b48d5e3a Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Fri, 28 Feb 2025 20:13:14 +0800 Subject: [PATCH 048/127] FIX: fix the humidity display of N3S_AMS jira: [STUDIO-10641] Change-Id: I48ac96443f851262b3ce720d4b4948b7b515a381 (cherry picked from commit 51042edcbdc1d8d24c11fa8a479559d4fd000fc7) --- src/slic3r/GUI/DeviceManager.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 0bb38f3dd0d..d485205cf37 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4052,6 +4052,30 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } catch (...) { ; } + + if (curr_ams->humidity_raw != -1) + { + if (curr_ams->humidity_raw < 20) + { + curr_ams->humidity = 5; + } + else if (curr_ams->humidity_raw < 40) + { + curr_ams->humidity = 4; + } + else if (curr_ams->humidity_raw < 60) + { + curr_ams->humidity = 3; + } + else if (curr_ams->humidity_raw < 80) + { + curr_ams->humidity = 2; + } + else + { + curr_ams->humidity = 1; + } + } } if (it->contains("tray")) { From 54d6f9f0deb716ed9c2d4a4767b4abd1e48e693c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 18 May 2025 14:59:08 +0800 Subject: [PATCH 049/127] Fix nozzle target temp display --- src/slic3r/GUI/DeviceManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 4139845dde3..1f539fa3deb 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -3438,7 +3438,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("nozzle_target_temper")) { if (jj["nozzle_target_temper"].is_number()) { if (m_extder_data.extders.size() == 1) { - m_extder_data.extders[0].target_temp = jj["nozzle_temper"].get(); + m_extder_data.extders[0].target_temp = jj["nozzle_target_temper"].get(); } } } From fd5b6f88ab6c53cb4c486c915a2f61e75fb58795 Mon Sep 17 00:00:00 2001 From: tao wang Date: Fri, 2 Aug 2024 12:10:42 +0800 Subject: [PATCH 050/127] FIX:support show n3f ams in mapping popup jira:[for n3f ams] Change-Id: I619010de072df1635e1bb39b694c7a0e0a7c127a (cherry picked from commit 46efe1542742fbc43e0f60ea385aadad39d08353) --- src/slic3r/GUI/AmsMappingPopup.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/AmsMappingPopup.cpp b/src/slic3r/GUI/AmsMappingPopup.cpp index 3e5af77c34f..2feb54043de 100644 --- a/src/slic3r/GUI/AmsMappingPopup.cpp +++ b/src/slic3r/GUI/AmsMappingPopup.cpp @@ -467,7 +467,7 @@ void AmsMapingPopup::update_ams_data(std::map amsList) int ams_type = ams_iter->second->type; int nozzle_id = ams_iter->second->nozzle; - if (ams_type == 1) { + if (ams_type >=1 || ams_type <= 3) { //1:ams 2:ams-lite 3:n3f auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL); auto ams_mapping_item_container = new MappingContainer(this); @@ -531,6 +531,8 @@ void AmsMapingPopup::update_ams_data(std::map amsList) //m_warning_text->Show(m_has_unmatch_filament); } + else if(ams_type == 4){ //4:n3s + } } /*extra tray*/ From eba2e0af78f03c02fea19b32f7e7d2d7ed7a0e04 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 18 May 2025 16:32:09 +0800 Subject: [PATCH 051/127] Update `transition_tridid` to support newer ams --- src/slic3r/GUI/GUI_App.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index bdf0a1bb0b6..fd2a0e4ba54 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3676,7 +3676,8 @@ void GUI_App::load_gcode(wxWindow* parent, wxString& input_file) const wxString GUI_App::transition_tridid(int trid_id) { - wxString maping_dict[8] = { "A", "B", "C", "D", "E", "F", "G" }; + //wxString maping_dict = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + wxString maping_dict[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; int id_index = ceil(trid_id / 4); int id_suffix = (trid_id + 1) % 4 == 0 ? 4 : (trid_id + 1) % 4; return wxString::Format("%s%d", maping_dict[id_index], id_suffix); From 21c69a99e66da40331f099ab93614f89b6027f9c Mon Sep 17 00:00:00 2001 From: tao wang Date: Tue, 10 Sep 2024 13:56:52 +0800 Subject: [PATCH 052/127] ENH:show n3f/n3s version info jira:[for n3s] Change-Id: Ia0056dfdf7157036008cc63a37c9fd8076063a6a (cherry picked from commit a44ff5a95a6774b4eed1238bde12d0a750c24a10) --- src/slic3r/GUI/DeviceManager.cpp | 16 +++++++++++----- src/slic3r/GUI/GUI_App.cpp | 16 +++++++++++----- src/slic3r/GUI/UpgradePanel.cpp | 16 +++++++++++++++- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 1f539fa3deb..ae6b0d1d9de 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1325,12 +1325,18 @@ wxString MachineObject::get_upgrade_result_str(int err_code) std::map MachineObject::get_ams_version() { + std::vector ams_type = {"ams", "n3f", "n3s"}; + std::map result; - for (int i = 0; i < 4; i++) { - std::string ams_id = "ams/" + std::to_string(i); - auto it = module_vers.find(ams_id); - if (it != module_vers.end()) { - result.emplace(std::pair(i, it->second)); + for (int i = 0; i < 8; i++) { + std::string ams_id; + for (auto type : ams_type ) + { + ams_id = type + "/" + std::to_string(i); + auto it = module_vers.find(ams_id); + if (it != module_vers.end()) { + result.emplace(std::pair(i, it->second)); + } } } return result; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fd2a0e4ba54..14b272fe622 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3676,11 +3676,17 @@ void GUI_App::load_gcode(wxWindow* parent, wxString& input_file) const wxString GUI_App::transition_tridid(int trid_id) { - //wxString maping_dict = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - wxString maping_dict[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; - int id_index = ceil(trid_id / 4); - int id_suffix = (trid_id + 1) % 4 == 0 ? 4 : (trid_id + 1) % 4; - return wxString::Format("%s%d", maping_dict[id_index], id_suffix); + wxString maping_dict[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; + + if (trid_id >= 128 * 4) { + int id_index = 4 + trid_id % 128; + return wxString::Format("%s", maping_dict[id_index]); + } + else { + int id_index = ceil(trid_id / 4); + int id_suffix = id_suffix = (trid_id + 1) % 4 == 0 ? 4 : (trid_id + 1) % 4; + return wxString::Format("%s%d", maping_dict[id_index], id_suffix); + } } //BBS diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index e9384c385be..eecef3d0f43 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -688,9 +688,23 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) amspanel->Show(); auto it = ver_list.find(atoi(iter->first.c_str())); + + if (it == ver_list.end()) { + continue; + } + auto ams_id = std::stoi(iter->second->id); - wxString ams_text = wxString::Format("AMS%s", std::to_string(ams_id + 1)); + size_t pos = it->second.name.find('/'); + wxString ams_device_name = "AMS-%s"; + + if (pos != std::string::npos) { + wxString result = it->second.name.substr(0, pos); + result.MakeUpper(); + ams_device_name = result + "-%s"; + } + + wxString ams_text = wxString::Format(ams_device_name, std::to_string(ams_id + 1)); ams_name = ams_text; if (it == ver_list.end()) { From 1f41e18d7fba7de7dcfed0ca43cf32484b184e92 Mon Sep 17 00:00:00 2001 From: "liz.li" Date: Wed, 20 Nov 2024 16:33:09 +0800 Subject: [PATCH 053/127] ENH: support dynamic size ams panel list in upgrade panel jira: none adjust accessories display text Change-Id: I1de6872325b17bd5cfb11e750608d5f420055ee4 (cherry picked from commit 6ba1518c24b4dcba01eabb6d1d0ce3a0ce69576c) --- src/slic3r/GUI/DeviceManager.cpp | 16 ++++++++-- src/slic3r/GUI/UpgradePanel.cpp | 50 +++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index ae6b0d1d9de..ea8b4f2b4ab 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1325,12 +1325,11 @@ wxString MachineObject::get_upgrade_result_str(int err_code) std::map MachineObject::get_ams_version() { - std::vector ams_type = {"ams", "n3f", "n3s"}; - + std::vector multi_tray_ams_type = {"ams", "n3f"}; std::map result; for (int i = 0; i < 8; i++) { std::string ams_id; - for (auto type : ams_type ) + for (auto type : multi_tray_ams_type) { ams_id = type + "/" + std::to_string(i); auto it = module_vers.find(ams_id); @@ -1339,6 +1338,17 @@ std::map MachineObject::get_ams_version() } } } + + std::string single_tray_ams_type = "n3s"; + int n3s_start_id = 128; + for (int i = n3s_start_id; i < n3s_start_id + 8; i++) { + std::string ams_id; + ams_id = single_tray_ams_type + "/" + std::to_string(i); + auto it = module_vers.find(ams_id); + if (it != module_vers.end()) { + result.emplace(std::pair(i, it->second)); + } + } return result; } diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index eecef3d0f43..53c3066f6ec 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -12,6 +12,17 @@ namespace GUI { static const wxColour TEXT_NORMAL_CLR = wxColour(0, 150, 136); static const wxColour TEXT_FAILED_CLR = wxColour(255, 111, 0); +static const std::unordered_map ACCESSORY_DISPLAY_STR = { + {"N3F", "AMS 2 PRO"}, + {"N3S", "AMS HT"}, + {"O2L_PC", "Air Pump"}, + {"O2L_10B", "Laser 10w"}, + {"O2L_40B", "Laser 40w"}, + {"O2L_PCM", "Cutting Module"}, + {"O2L_ACM", "Active Cutting Module"}, + {"O2L_UCM", "Ultrasonic Cutting Module"}, +}; + enum FIRMWARE_STASUS { UNKOWN, @@ -136,16 +147,16 @@ MachineInfoPanel::MachineInfoPanel(wxWindow* parent, wxWindowID id, const wxPoin m_ams_info_sizer->SetFlexibleDirection(wxHORIZONTAL); m_ams_info_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL); - for (auto i = 0; i < 4; i++) { - auto amspanel = new AmsPanel(this, wxID_ANY); - m_ams_info_sizer->Add(amspanel, 1, wxEXPAND, 5); - amspanel->Hide(); + //for (auto i = 0; i < 4; i++) { + // auto amspanel = new AmsPanel(this, wxID_ANY); + // m_ams_info_sizer->Add(amspanel, 1, wxEXPAND, 5); + // amspanel->Hide(); - /*AmsPanelItem item = AmsPanelItem(); - item.id = i; - item.item = amspanel;*/ - m_amspanel_list.Add(amspanel); - } + // /*AmsPanelItem item = AmsPanelItem(); + // item.id = i; + // item.item = amspanel;*/ + // m_amspanel_list.Add(amspanel); + //} m_ams_content_sizer->Add(m_ams_info_sizer, 0, wxEXPAND, 0); m_ams_sizer->Add(m_ams_content_sizer, 1, wxEXPAND, 0); @@ -670,14 +681,28 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) show_ams(true); std::map ver_list = obj->get_ams_version(); - AmsPanelHash::iterator iter = m_amspanel_list.begin(); + if (obj->amsList.size() != m_amspanel_list.size()) { + int add_count = obj->amsList.size() - m_amspanel_list.size(); + if (add_count > 0) { + for (int i = 0; i < add_count; i++) { + auto amspanel = new AmsPanel(this, wxID_ANY); + m_ams_info_sizer->Add(amspanel, 1, wxEXPAND, 5); + m_amspanel_list.Add(amspanel); + } + } + if (add_count < 0) { + for (int i = 0; i < -add_count; i++) { + m_amspanel_list.back()->Destroy(); + m_amspanel_list.pop_back(); + } + } + } for (auto i = 0; i < m_amspanel_list.GetCount(); i++) { AmsPanel* amspanel = m_amspanel_list[i]; amspanel->Hide(); } - auto ams_index = 0; for (std::map::iterator iter = obj->amsList.begin(); iter != obj->amsList.end(); iter++) { wxString ams_name; @@ -694,6 +719,7 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) } auto ams_id = std::stoi(iter->second->id); + ams_id -= ams_id >= 128 ? 128 : 0; size_t pos = it->second.name.find('/'); wxString ams_device_name = "AMS-%s"; @@ -701,6 +727,8 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) if (pos != std::string::npos) { wxString result = it->second.name.substr(0, pos); result.MakeUpper(); + if (auto str_it = ACCESSORY_DISPLAY_STR.find(result); str_it != ACCESSORY_DISPLAY_STR.end()) + result = str_it->second; ams_device_name = result + "-%s"; } From 58c2ee4f06a3b3b7a50dc33bcb593d7620b9be7f Mon Sep 17 00:00:00 2001 From: "liz.li" Date: Wed, 20 Nov 2024 19:24:34 +0800 Subject: [PATCH 054/127] FIX: ams_id out of bounds crash jira: none Change-Id: Icfc5555e4772cd70a9f018f0c734e2edb8b7d626 (cherry picked from commit aa03f489dcc6bd737d2d12c53adfb90a01270d66) --- src/slic3r/GUI/GUI_App.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 14b272fe622..9270eed055e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3679,12 +3679,13 @@ wxString GUI_App::transition_tridid(int trid_id) wxString maping_dict[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; if (trid_id >= 128 * 4) { - int id_index = 4 + trid_id % 128; + trid_id -= 128 * 4; + int id_index = trid_id / 4; return wxString::Format("%s", maping_dict[id_index]); } else { int id_index = ceil(trid_id / 4); - int id_suffix = id_suffix = (trid_id + 1) % 4 == 0 ? 4 : (trid_id + 1) % 4; + int id_suffix = trid_id % 4 + 1; return wxString::Format("%s%d", maping_dict[id_index], id_suffix); } } From 1f2b320b94ba5dafca55b5e588e55e916f9e285e Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Fri, 3 Jan 2025 18:43:02 +0800 Subject: [PATCH 055/127] FIX: display fault in dark mode about AMS jira: [STUDIO-8964] Change-Id: If2785b3bf6b8067f87eef610af548abbe841603a (cherry picked from commit b22618db87c0bfdd4b36f108c258342a9db550d0) --- src/slic3r/GUI/UpgradePanel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 53c3066f6ec..0088ab416d9 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -686,6 +686,7 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) if (add_count > 0) { for (int i = 0; i < add_count; i++) { auto amspanel = new AmsPanel(this, wxID_ANY); + wxGetApp().UpdateDarkUIWin(amspanel); m_ams_info_sizer->Add(amspanel, 1, wxEXPAND, 5); m_amspanel_list.Add(amspanel); } From 7af9802688120bb9cc2a926dbffb64c250f34f31 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Thu, 20 Mar 2025 14:55:43 +0800 Subject: [PATCH 056/127] ENH: gui: add win_arm64 support jira: no-jira Change-Id: I43f66be1f264434a9bb26a9dd3fff1fb5c36d57c (cherry picked from commit 659f758e451d20d3a6c5505a2530be578dd584dd) --- src/slic3r/GUI/GUI_App.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 9270eed055e..45ee292cdcb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2048,7 +2048,11 @@ std::map GUI_App::get_extra_header() extra_headers.insert(std::make_pair("X-BBL-Client-Name", SLIC3R_APP_NAME)); extra_headers.insert(std::make_pair("X-BBL-Client-Version", VersionInfo::convert_full_version(SLIC3R_VERSION))); #if defined(__WINDOWS__) +#ifdef _M_X64 extra_headers.insert(std::make_pair("X-BBL-OS-Type", "windows")); +#else + extra_headers.insert(std::make_pair("X-BBL-OS-Type", "win_arm64")); +#endif #elif defined(__APPLE__) extra_headers.insert(std::make_pair("X-BBL-OS-Type", "macos")); #elif defined(__LINUX__) From 320cd87f0b63cc61407cdae057d3a0e459de319d Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Mon, 7 Apr 2025 20:09:51 +0800 Subject: [PATCH 057/127] ENH: GUI: add arm64 check logic for windows jira: no-jira Change-Id: Ic788d4ae9218b909eae5ce571d4436c39e77230a (cherry picked from commit 323184e42c5f85c8738b03b890e5aaf3818e8858) --- src/slic3r/GUI/GUI_App.cpp | 14 ++++++++++++++ src/slic3r/GUI/GUI_App.hpp | 7 +++++++ src/slic3r/Utils/Http.cpp | 8 +++++++- src/slic3r/Utils/Http.hpp | 1 + src/slic3r/Utils/PresetUpdater.cpp | 20 ++++++++++++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 45ee292cdcb..9dd2938c19c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1087,6 +1087,20 @@ GUI_App::GUI_App() #endif reset_to_active(); + +#if defined(__WINDOWS__) + SYSTEM_INFO sysInfo; + GetNativeSystemInfo(&sysInfo); + switch (sysInfo.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_ARM64: + m_is_arm64 = true; + break; + case PROCESSOR_ARCHITECTURE_AMD64: + default: + m_is_arm64 = false; + break; + } +#endif } void GUI_App::shutdown() diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index fb334568efe..c246adc5a96 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -238,6 +238,9 @@ class GUI_App : public wxApp #ifdef __linux__ bool m_opengl_initialized{ false }; #endif +#if defined(__WINDOWS__) + bool m_is_arm64{false}; +#endif //#ifdef _WIN32 @@ -583,6 +586,10 @@ class GUI_App : public wxApp std::string get_download_model_url() {return m_mall_model_download_url;} std::string get_download_model_name() {return m_mall_model_download_name;} +#if defined(__WINDOWS__) + bool is_running_on_arm64() { return m_is_arm64; } +#endif + void load_url(wxString url); void open_mall_page_dialog(); void open_publish_page_dialog(); diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 4127d3fd292..bcb9dda915e 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -666,7 +666,7 @@ Http& Http::form_add_file(const std::string &name, const fs::path &path, const s } #ifdef WIN32 -// Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present. +// Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present. // This option is only supported for Schannel (the native Windows SSL library). Http& Http::ssl_revoke_best_effort(bool set) { @@ -804,6 +804,12 @@ void Http::set_extra_headers(std::map headers) extra_headers.swap(headers); } +std::map Http::get_extra_headers() +{ + std::lock_guard l(g_mutex); + return extra_headers; +} + bool Http::ca_file_supported() { ::CURL *curl = ::curl_easy_init(); diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index fbded8eab27..d8eabb6dfd4 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -90,6 +90,7 @@ class Http : public std::enable_shared_from_this { //BBS set global header for each http request static void set_extra_headers(std::map headers); + static std::map get_extra_headers(); ~Http(); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index d09f69b6630..0c9b1e66943 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -943,6 +943,16 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ } } +#if defined(__WINDOWS__) + if (GUI::wxGetApp().is_running_on_arm64()) { + //set to arm64 for plugins + std::map current_headers = Slic3r::Http::get_extra_headers(); + current_headers["X-BBL-OS-Type"] = "win_arm64"; + + Slic3r::Http::set_extra_headers(current_headers); + BOOST_LOG_TRIVIAL(info) << boost::format("set X-BBL-OS-Type to win_arm64"); + } +#endif try { std::map resources { @@ -953,6 +963,16 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ catch (std::exception& e) { BOOST_LOG_TRIVIAL(warning) << format("[Orca Updater] sync_plugins: %1%", e.what()); } +#if defined(__WINDOWS__) + if (GUI::wxGetApp().is_running_on_arm64()) { + //set back + std::map current_headers = Slic3r::Http::get_extra_headers(); + current_headers["X-BBL-OS-Type"] = "windows"; + + Slic3r::Http::set_extra_headers(current_headers); + BOOST_LOG_TRIVIAL(info) << boost::format("set X-BBL-OS-Type back to windows"); + } +#endif bool result = get_cached_plugins_version(cached_version, force_upgrade); if (result) { From c0ba405a649a576cb34aac235e59cdcf48286093 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Thu, 10 Apr 2025 14:46:26 +0800 Subject: [PATCH 058/127] ENH: GUI: rename win_arm64 to windows_arm jira: no-jira Change-Id: I01eeb96efb06ec779f1338d1207f7f6641c2bc58 (cherry picked from commit bbf32fd6f7ffbf543c28882ff3801108942fb399) --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/Utils/PresetUpdater.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 9dd2938c19c..257e8ec1466 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2065,7 +2065,7 @@ std::map GUI_App::get_extra_header() #ifdef _M_X64 extra_headers.insert(std::make_pair("X-BBL-OS-Type", "windows")); #else - extra_headers.insert(std::make_pair("X-BBL-OS-Type", "win_arm64")); + extra_headers.insert(std::make_pair("X-BBL-OS-Type", "windows_arm")); #endif #elif defined(__APPLE__) extra_headers.insert(std::make_pair("X-BBL-OS-Type", "macos")); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 0c9b1e66943..7b77c7451cb 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -947,10 +947,10 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ if (GUI::wxGetApp().is_running_on_arm64()) { //set to arm64 for plugins std::map current_headers = Slic3r::Http::get_extra_headers(); - current_headers["X-BBL-OS-Type"] = "win_arm64"; + current_headers["X-BBL-OS-Type"] = "windows_arm"; Slic3r::Http::set_extra_headers(current_headers); - BOOST_LOG_TRIVIAL(info) << boost::format("set X-BBL-OS-Type to win_arm64"); + BOOST_LOG_TRIVIAL(info) << boost::format("set X-BBL-OS-Type to windows_arm"); } #endif try { From aec877c7e050f32aa3ebe8a591fed8b41c775ee4 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Fri, 11 Apr 2025 17:41:06 +0800 Subject: [PATCH 059/127] FIX: gui: fix the crash issue on arm64 plateform jira: no-jira Change-Id: Ib95ffc3ceb421af345418d73af0261d3c25464a3 (cherry picked from commit 132d87b687f4b3bd016539380d7e9268d817ac40) --- src/slic3r/GUI/GUI_App.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 257e8ec1466..f5d371bc87e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1225,6 +1225,17 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install fs::path tmp_path = target_file_path; tmp_path += format(".%1%%2%", get_current_pid(), ".tmp"); +#if defined(__WINDOWS__) + if (is_running_on_arm64()) { + //set to arm64 for plugins + std::map current_headers = Slic3r::Http::get_extra_headers(); + current_headers["X-BBL-OS-Type"] = "windows_arm"; + + Slic3r::Http::set_extra_headers(current_headers); + BOOST_LOG_TRIVIAL(info) << boost::format("download_plugin: set X-BBL-OS-Type to windows_arm"); + } +#endif + // get_url std::string url = get_plugin_url(name, app_config->get_country_code()); std::string download_url; @@ -1282,6 +1293,17 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install result = -1; }).perform_sync(); +#if defined(__WINDOWS__) + if (is_running_on_arm64()) { + //set back + std::map current_headers = Slic3r::Http::get_extra_headers(); + current_headers["X-BBL-OS-Type"] = "windows"; + + Slic3r::Http::set_extra_headers(current_headers); + BOOST_LOG_TRIVIAL(info) << boost::format("download_plugin: set X-BBL-OS-Type back to windows"); + } +#endif + bool cancel = false; if (result < 0) { j["result"] = "failed"; From ebc072b1418253e91c2447e6bb37a14a35f82ea7 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Fri, 11 Apr 2025 08:17:20 +0800 Subject: [PATCH 060/127] ENH: init: output the process architecture when init jira: no-jira Change-Id: Id5acb828269565945d887c6de4e32d715f83f503 (cherry picked from commit a29cb80bc7f959b5df44238a0a7f0a08948ff2a3) --- src/slic3r/GUI/GUI_App.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f5d371bc87e..50d97416dd8 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1087,20 +1087,6 @@ GUI_App::GUI_App() #endif reset_to_active(); - -#if defined(__WINDOWS__) - SYSTEM_INFO sysInfo; - GetNativeSystemInfo(&sysInfo); - switch (sysInfo.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_ARM64: - m_is_arm64 = true; - break; - case PROCESSOR_ARCHITECTURE_AMD64: - default: - m_is_arm64 = false; - break; - } -#endif } void GUI_App::shutdown() @@ -2300,6 +2286,20 @@ bool GUI_App::on_init_inner() #endif BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1%")%SoftFever_VERSION; +#if defined(__WINDOWS__) + SYSTEM_INFO sysInfo; + GetNativeSystemInfo(&sysInfo); + switch (sysInfo.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_ARM64: + m_is_arm64 = true; + break; + case PROCESSOR_ARCHITECTURE_AMD64: + default: + m_is_arm64 = false; + break; + } + BOOST_LOG_TRIVIAL(info) << boost::format("process architecture %1%, m_is_arm64 %2%")%(int)(sysInfo.wProcessorArchitecture) %m_is_arm64; +#endif // Enable this to get the default Win32 COMCTRL32 behavior of static boxes. // wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0); // Enable this to disable Windows Vista themes for all wxNotebooks. The themes seem to lead to terrible From 285bbeceb71e2e6b10bdb5d7bb8cac3b403ab298 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Fri, 11 Apr 2025 11:07:43 +0800 Subject: [PATCH 061/127] FIX: GUI: use another api to get process type jira: no-jira Change-Id: I43fb1738b9b0173704c17c0d92df06f3c78fcde6 (cherry picked from commit af8926ea396480ea06222d421a2ecb704df04218) --- src/slic3r/GUI/AboutDialog.cpp | 2 +- src/slic3r/GUI/GUI_App.cpp | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index c11da9858d8..7671af609e8 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -328,7 +328,7 @@ AboutDialog::AboutDialog() copyright_hor_sizer->Add(copyright_ver_sizer, 0, wxLEFT, FromDIP(20)); - wxStaticText *html_text = new wxStaticText(this, wxID_ANY, "Copyright(C) 2022-2024 Li Jiang All Rights Reserved", wxDefaultPosition, wxDefaultSize); + wxStaticText *html_text = new wxStaticText(this, wxID_ANY, "Copyright(C) 2022-2025 Li Jiang All Rights Reserved", wxDefaultPosition, wxDefaultSize); html_text->SetForegroundColour(wxColour(107, 107, 107)); copyright_ver_sizer->Add(html_text, 0, wxALL , 0); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 50d97416dd8..036e0a904e9 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2287,18 +2287,23 @@ bool GUI_App::on_init_inner() BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1%")%SoftFever_VERSION; #if defined(__WINDOWS__) - SYSTEM_INFO sysInfo; - GetNativeSystemInfo(&sysInfo); - switch (sysInfo.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_ARM64: - m_is_arm64 = true; - break; - case PROCESSOR_ARCHITECTURE_AMD64: - default: - m_is_arm64 = false; - break; + USHORT processMachine = 0; + USHORT nativeMachine = 0; + if (IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) { + switch (nativeMachine) { + case IMAGE_FILE_MACHINE_ARM64: + m_is_arm64 = true; + break; + case IMAGE_FILE_MACHINE_AMD64: + default: + m_is_arm64 = false; + break; + } + BOOST_LOG_TRIVIAL(info) << boost::format("processMachine architecture %1%, nativeMachine %2% m_is_arm64 %3%")%(int)(processMachine) %(int) nativeMachine %m_is_arm64; + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("IsWow64Process2 failed, m_is_arm64 %1%") %m_is_arm64; } - BOOST_LOG_TRIVIAL(info) << boost::format("process architecture %1%, m_is_arm64 %2%")%(int)(sysInfo.wProcessorArchitecture) %m_is_arm64; #endif // Enable this to get the default Win32 COMCTRL32 behavior of static boxes. // wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0); From 2d7259623f69aecd56db60b18d0ffc92ae681d45 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Wed, 16 Apr 2025 14:50:18 +0800 Subject: [PATCH 062/127] FIX: fix studio not launch issue on windows-7 jira: no-jira Change-Id: I531e009c0547d3a5d86d48e990d930eb8fa6ba00 (cherry picked from commit 3d02f03ef4ba229ebf9e28cd99a5d871916994dd) --- src/slic3r/GUI/GUI_App.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 036e0a904e9..a5e954f9a80 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2286,23 +2286,31 @@ bool GUI_App::on_init_inner() #endif BOOST_LOG_TRIVIAL(info) << boost::format("gui mode, Current OrcaSlicer Version %1%")%SoftFever_VERSION; + #if defined(__WINDOWS__) - USHORT processMachine = 0; - USHORT nativeMachine = 0; - if (IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) { - switch (nativeMachine) { - case IMAGE_FILE_MACHINE_ARM64: - m_is_arm64 = true; - break; - case IMAGE_FILE_MACHINE_AMD64: - default: - m_is_arm64 = false; - break; + HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + m_is_arm64 = false; + if (hKernel32) { + auto fnIsWow64Process2 = (decltype(&IsWow64Process2))GetProcAddress(hKernel32, "IsWow64Process2"); + if (fnIsWow64Process2) { + USHORT processMachine = 0; + USHORT nativeMachine = 0; + if (IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) { + if (nativeMachine == IMAGE_FILE_MACHINE_ARM64) { + m_is_arm64 = true; + } + BOOST_LOG_TRIVIAL(info) << boost::format("processMachine architecture %1%, nativeMachine %2% m_is_arm64 %3%")%(int)(processMachine) %(int) nativeMachine %m_is_arm64; + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("IsWow64Process2 failed, set m_is_arm64 to %1%") %m_is_arm64; + } + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("can not find IsWow64Process2, set m_is_arm64 to %1%") %m_is_arm64; } - BOOST_LOG_TRIVIAL(info) << boost::format("processMachine architecture %1%, nativeMachine %2% m_is_arm64 %3%")%(int)(processMachine) %(int) nativeMachine %m_is_arm64; } else { - BOOST_LOG_TRIVIAL(info) << boost::format("IsWow64Process2 failed, m_is_arm64 %1%") %m_is_arm64; + BOOST_LOG_TRIVIAL(info) << boost::format("can not find kernel32, set m_is_arm64 to %1%") %m_is_arm64; } #endif // Enable this to get the default Win32 COMCTRL32 behavior of static boxes. From 85bce2ac33d121c8f7704746a4f4eda8655aac75 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Wed, 16 Apr 2025 16:44:45 +0800 Subject: [PATCH 063/127] FIX: app: fix the issue on win-7 use typedef instead of IsWow64Process2 jira: no-jira Change-Id: I3d5c4becca1586094b6950431470b12bd71a0056 (cherry picked from commit c34e985f188c206d588ee8da7149ded2516981cf) --- src/slic3r/GUI/GUI_App.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a5e954f9a80..15c8799109a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -122,6 +122,13 @@ #include "dark_mode.hpp" #include "wx/headerctrl.h" #include "wx/msw/headerctrl.h" + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS2)( + HANDLE hProcess, + USHORT *pProcessMachine, + USHORT *pNativeMachine +); + #endif // _MSW_DARK_MODE #endif // __WINDOWS__ @@ -2291,7 +2298,7 @@ bool GUI_App::on_init_inner() HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); m_is_arm64 = false; if (hKernel32) { - auto fnIsWow64Process2 = (decltype(&IsWow64Process2))GetProcAddress(hKernel32, "IsWow64Process2"); + auto fnIsWow64Process2 = (LPFN_ISWOW64PROCESS2)GetProcAddress(hKernel32, "IsWow64Process2"); if (fnIsWow64Process2) { USHORT processMachine = 0; USHORT nativeMachine = 0; From a67436ee7e591bca8254ee2708f788d6891ece00 Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Wed, 16 Apr 2025 19:33:29 +0800 Subject: [PATCH 064/127] FIX: app: fix the crash issue on win-7 again jira: no-jira Change-Id: I96e713513270270db3abcfdd67792b0a3ac92619 (cherry picked from commit caff5d9f38cdb962ca4069f8b0b5696d140aac6d) --- src/slic3r/GUI/GUI_App.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 15c8799109a..dac4d8678ab 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2302,8 +2302,8 @@ bool GUI_App::on_init_inner() if (fnIsWow64Process2) { USHORT processMachine = 0; USHORT nativeMachine = 0; - if (IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) { - if (nativeMachine == IMAGE_FILE_MACHINE_ARM64) { + if (fnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) { + if (nativeMachine == IMAGE_FILE_MACHINE_ARM64) {//IMAGE_FILE_MACHINE_ARM64 m_is_arm64 = true; } BOOST_LOG_TRIVIAL(info) << boost::format("processMachine architecture %1%, nativeMachine %2% m_is_arm64 %3%")%(int)(processMachine) %(int) nativeMachine %m_is_arm64; From 9711b65736a6cf00c310a1bc839c1a1cfe5306f2 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 19 May 2025 10:51:55 +0800 Subject: [PATCH 065/127] Only download ARM version when not using legacy plugin --- src/slic3r/GUI/GUI_App.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index dac4d8678ab..f537d1f1b70 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1219,7 +1219,7 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install tmp_path += format(".%1%%2%", get_current_pid(), ".tmp"); #if defined(__WINDOWS__) - if (is_running_on_arm64()) { + if (is_running_on_arm64() && !NetworkAgent::use_legacy_network) { //set to arm64 for plugins std::map current_headers = Slic3r::Http::get_extra_headers(); current_headers["X-BBL-OS-Type"] = "windows_arm"; @@ -1287,7 +1287,7 @@ int GUI_App::download_plugin(std::string name, std::string package_name, Install }).perform_sync(); #if defined(__WINDOWS__) - if (is_running_on_arm64()) { + if (is_running_on_arm64() && !NetworkAgent::use_legacy_network) { //set back std::map current_headers = Slic3r::Http::get_extra_headers(); current_headers["X-BBL-OS-Type"] = "windows"; From 6c22b0c86f4361c2d822189cb296fc5208613aa6 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 19 May 2025 10:54:38 +0800 Subject: [PATCH 066/127] Update plugin version in `PresetUpdater` --- src/slic3r/Utils/PresetUpdater.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 7b77c7451cb..0af6cd459f2 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -849,7 +849,7 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ BOOST_LOG_TRIVIAL(info) << "non need to sync plugins for there is no plugins currently."; return; } - std::string curr_version = SLIC3R_VERSION; + std::string curr_version = NetworkAgent::use_legacy_network ? BAMBU_NETWORK_AGENT_VERSION_LEGACY : BAMBU_NETWORK_AGENT_VERSION; std::string using_version = curr_version.substr(0, 9) + "00"; std::string cached_version; @@ -944,7 +944,7 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ } #if defined(__WINDOWS__) - if (GUI::wxGetApp().is_running_on_arm64()) { + if (GUI::wxGetApp().is_running_on_arm64() && !NetworkAgent::use_legacy_network) { //set to arm64 for plugins std::map current_headers = Slic3r::Http::get_extra_headers(); current_headers["X-BBL-OS-Type"] = "windows_arm"; @@ -964,7 +964,7 @@ void PresetUpdater::priv::sync_plugins(std::string http_url, std::string plugin_ BOOST_LOG_TRIVIAL(warning) << format("[Orca Updater] sync_plugins: %1%", e.what()); } #if defined(__WINDOWS__) - if (GUI::wxGetApp().is_running_on_arm64()) { + if (GUI::wxGetApp().is_running_on_arm64() && !NetworkAgent::use_legacy_network) { //set back std::map current_headers = Slic3r::Http::get_extra_headers(); current_headers["X-BBL-OS-Type"] = "windows"; From 60ac0a514e24373525199a3ae3cd46c53975ef74 Mon Sep 17 00:00:00 2001 From: tao wang Date: Fri, 13 Dec 2024 16:19:43 +0800 Subject: [PATCH 067/127] ENH:adjust the parsing of ams info data jira:[none ] Change-Id: I8e5125ae313b48b3f64fe59ae45ee7b437a0119f (cherry picked from commit c38074d3cdc38f8e676a443f23b20d9477facea9) (cherry picked from commit c8ce030bd2de6b54a79e218d6073164956f6f0b9) --- src/slic3r/GUI/DeviceManager.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index ea8b4f2b4ab..1c3e51f02ba 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4017,15 +4017,14 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (!it->contains("id")) continue; std::string ams_id = (*it)["id"].get(); - int nozzle_id = 0; // Default nozzle id + int nozzle_id = MAIN_NOZZLE_ID; // Default nozzle id int type_id = 1; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s - if (it->contains("nozzle")) { - nozzle_id = (*it)["nozzle"].get(); - } - - if (it->contains("type")) { - type_id = (*it)["type"].get(); + /*ams info*/ + if (it->contains("info")) { + std::string info = (*it)["info"].get(); + type_id = get_flag_bits(info, 0, 3); + nozzle_id = get_flag_bits(info, 8, 3); } ams_id_set.erase(ams_id); From 1556523ca14f606e10c09e8ff03be1a1f75a6005 Mon Sep 17 00:00:00 2001 From: tao wang Date: Mon, 4 Nov 2024 21:54:33 +0800 Subject: [PATCH 068/127] FIX:Fix the display issue of uncalibrated AMS jira:[for uncalibrated ams] Change-Id: I02e3f3548750fd0bd61d64e36a535a0f83371e98 (cherry picked from commit f08d40b42a8193123bdba559cb8eade5ff062b4a) --- src/slic3r/GUI/DeviceManager.cpp | 6 ++++++ src/slic3r/GUI/SelectMachine.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 1c3e51f02ba..e82a8fe8f34 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4013,6 +4013,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) for (auto it = amsList.begin(); it != amsList.end(); it++) { ams_id_set.insert(it->first); } + for (auto it = j_ams.begin(); it != j_ams.end(); it++) { if (!it->contains("id")) continue; std::string ams_id = (*it)["id"].get(); @@ -4027,6 +4028,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) nozzle_id = get_flag_bits(info, 8, 3); } + /*AMS without initialization*/ + if (nozzle_id == 0x0E) { + continue; + } + ams_id_set.erase(ams_id); Ams* curr_ams = nullptr; auto ams_it = amsList.find(ams_id); diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 69b186550dd..ceee8c7889e 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1526,7 +1526,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_sizer_main->Add(m_statictext_ams_msg, 0, wxLEFT, 0); m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(16)); m_sizer_main->Add(sizer_split_options, 1, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15)); - m_sizer_main->Add(m_sizer_options, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT| wxRIGHT, FromDIP(15)); + m_sizer_main->Add(m_sizer_options, 0, wxLEFT|wxRIGHT, FromDIP(15)); m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(10)); m_sizer_main->Add(m_simplebook, 0, wxALIGN_CENTER_HORIZONTAL, 0); m_sizer_main->Add(m_sw_print_failed_info, 0, wxALIGN_CENTER, 0); From 8a7fa6918dcb184910f83a3a70c670e06269fbc6 Mon Sep 17 00:00:00 2001 From: tao wang Date: Tue, 24 Dec 2024 16:18:31 +0800 Subject: [PATCH 069/127] FIX:fixed obtaining incorrect bits jira:[none] Change-Id: I27a4ae24870276912b69fad1c0285889e749030b (cherry picked from commit 207d81c76933c5cf2fe2d28ed70ab2d246af2615) --- src/slic3r/GUI/DeviceManager.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index e82a8fe8f34..601ee3b30d9 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4024,12 +4024,12 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) /*ams info*/ if (it->contains("info")) { std::string info = (*it)["info"].get(); - type_id = get_flag_bits(info, 0, 3); - nozzle_id = get_flag_bits(info, 8, 3); + type_id = get_flag_bits(info, 0, 4); + nozzle_id = get_flag_bits(info, 8, 4); } /*AMS without initialization*/ - if (nozzle_id == 0x0E) { + if (nozzle_id == 0xE) { continue; } @@ -5355,11 +5355,10 @@ void MachineObject::parse_new_info(json print) upgrade_force_upgrade = get_flag_bits(cfg, 2); camera_recording_when_printing = get_flag_bits(cfg, 3); camera_resolution = get_flag_bits(cfg, 4) == 0 ? "720p" : "1080p"; - //liveview_local = get_flag_bits(cfg, 5); todo zhanma - camera_timelapse = get_flag_bits(cfg, 6); - tutk_state = get_flag_bits(cfg, 7) == 1 ? "disable" : ""; - chamber_light = get_flag_bits(cfg, 8) == 1 ? LIGHT_EFFECT::LIGHT_EFFECT_ON : LIGHT_EFFECT::LIGHT_EFFECT_OFF; - printing_speed_lvl = (PrintingSpeedLevel)get_flag_bits(cfg, 9, 3); + camera_timelapse = get_flag_bits(cfg, 5); + tutk_state = get_flag_bits(cfg, 6) == 1 ? "disable" : ""; + chamber_light = get_flag_bits(cfg, 7) == 1 ? LIGHT_EFFECT::LIGHT_EFFECT_ON : LIGHT_EFFECT::LIGHT_EFFECT_OFF; + printing_speed_lvl = (PrintingSpeedLevel)get_flag_bits(cfg, 8, 3); //is_support_build_plate_marker_detect = get_flag_bits(cfg, 12); todo yangcong xcam_first_layer_inspector = get_flag_bits(cfg, 13); @@ -5416,7 +5415,6 @@ void MachineObject::parse_new_info(json print) BOOST_LOG_TRIVIAL(info) << "new print data aux = " << aux; if (!aux.empty()) { - //ams_exist_bits = get_flag_bits(aux, 8, 3); //todo yangcong sdcard_state = MachineObject::SdcardState(get_flag_bits(aux, 12, 2)); } @@ -5426,7 +5424,6 @@ void MachineObject::parse_new_info(json print) BOOST_LOG_TRIVIAL(info) << "new print data stat = " << stat; if (!stat.empty()) { - //sdcard_state = get_flag_bits(aux, 12, 2); todo yangcong camera_recording = get_flag_bits(stat, 7); } @@ -5439,13 +5436,13 @@ void MachineObject::parse_new_info(json print) } if (device.contains("bed_temp")) { - bed_temp = get_flag_bits(device["bed_temp"].get(), 0, 15); - bed_temp_target = get_flag_bits(device["bed_temp"].get(), 16, 15); + bed_temp = get_flag_bits(device["bed_temp"].get(), 0, 16); + bed_temp_target = get_flag_bits(device["bed_temp"].get(), 16, 16); } if (device.contains("cham_temp")) { - chamber_temp = get_flag_bits(device["cham_temp"].get(), 0, 15); - chamber_temp_target = get_flag_bits(device["cham_temp"].get(), 16, 15); + chamber_temp = get_flag_bits(device["cham_temp"].get(), 0, 16); + chamber_temp_target = get_flag_bits(device["cham_temp"].get(), 16, 16); } if (device.contains("fan")) { From 80b234a369401f8df63835f103b261da4e06544c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 18 May 2025 19:53:23 +0800 Subject: [PATCH 070/127] Preparing for AMS drying support --- resources/images/ams_drying.svg | 10 +++++++++ src/slic3r/GUI/StatusPanel.cpp | 4 ++-- src/slic3r/GUI/Widgets/AMSControl.cpp | 30 +++++++++++++-------------- src/slic3r/GUI/Widgets/AMSControl.hpp | 6 +++--- src/slic3r/GUI/Widgets/AMSItem.cpp | 18 +++++++++------- src/slic3r/GUI/Widgets/AMSItem.hpp | 12 +++++++---- 6 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 resources/images/ams_drying.svg diff --git a/resources/images/ams_drying.svg b/resources/images/ams_drying.svg new file mode 100644 index 00000000000..e6f9fb9f634 --- /dev/null +++ b/resources/images/ams_drying.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index bcb5860f07c..7a9144a8513 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2598,7 +2598,7 @@ void StatusPanel::update_ams(MachineObject *obj) AMSModel ams_mode = AMSModel::GENERIC_AMS; if (obj) { - if (obj->get_printer_ams_type() == "f1") { ams_mode = AMSModel::EXTRA_AMS; } + if (obj->get_printer_ams_type() == "f1") { ams_mode = AMSModel::AMS_LITE; } else if(obj->get_printer_ams_type() == "generic") { ams_mode = AMSModel::GENERIC_AMS; } obj->check_ams_filament_valid(); } @@ -2618,7 +2618,7 @@ void StatusPanel::update_ams(MachineObject *obj) } - m_ams_control->SetAmsModel(AMSModel::NO_AMS, ams_mode); + m_ams_control->SetAmsModel(AMSModel::EXT_AMS, ams_mode); show_ams_group(false); m_ams_control->show_auto_refill(false); diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index c535249ce22..6fa1f412575 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -641,7 +641,7 @@ void AMSControl::SetActionState(bool button_status[]) void AMSControl::EnterNoneAMSMode() { m_vams_lib->m_ams_model = m_ext_model; - if(m_is_none_ams_mode == AMSModel::NO_AMS) return; + if(m_is_none_ams_mode == AMSModel::EXT_AMS) return; m_panel_top->Hide(); m_simplebook_amsitems->Hide(); m_simplebook_amsitems->SetSelection(0); @@ -657,7 +657,7 @@ void AMSControl::EnterNoneAMSMode() m_amswin->Layout(); m_amswin->Fit(); Layout(); - m_is_none_ams_mode = AMSModel::NO_AMS; + m_is_none_ams_mode = AMSModel::EXT_AMS; } void AMSControl::EnterGenericAMSMode() @@ -692,13 +692,13 @@ void AMSControl::EnterGenericAMSMode() void AMSControl::EnterExtraAMSMode() { m_vams_lib->m_ams_model = m_ext_model; - if(m_is_none_ams_mode == AMSModel::EXTRA_AMS) return; + if(m_is_none_ams_mode == AMSModel::AMS_LITE) return; m_panel_top->Hide(); m_simplebook_amsitems->Show(); m_simplebook_amsitems->SetSelection(1); - m_vams_lib->m_ams_model = AMSModel::EXTRA_AMS; + m_vams_lib->m_ams_model = AMSModel::AMS_LITE; m_ams_tip->SetLabel(wxEmptyString); m_img_vams_tip->SetBitmap(create_scaled_bitmap("enable_ams_disable", this, 16)); m_img_vams_tip->Disable(); @@ -717,7 +717,7 @@ void AMSControl::EnterExtraAMSMode() m_amswin->Fit(); Layout(); Refresh(true); - m_is_none_ams_mode = AMSModel::EXTRA_AMS; + m_is_none_ams_mode = AMSModel::AMS_LITE; } @@ -836,7 +836,7 @@ void AMSControl::UpdateStepCtrl(bool is_extrusion) } - if (m_ams_model == AMSModel::EXTRA_AMS || m_ext_model == AMSModel::EXTRA_AMS) { + if (m_ams_model == AMSModel::AMS_LITE || m_ext_model == AMSModel::AMS_LITE) { m_filament_load_step->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_HEAT_NOZZLE]); m_filament_load_step->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CHECK_POSITION]); m_filament_load_step->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CUT_FILAMENT]); @@ -908,11 +908,11 @@ void AMSControl::show_noams_mode() show_vams(true); m_sizer_ams_tips->Show(true); - if (m_ams_model == AMSModel::NO_AMS) { + if (m_ams_model == AMSModel::EXT_AMS) { EnterNoneAMSMode(); } else if(m_ams_model == AMSModel::GENERIC_AMS){ EnterGenericAMSMode(); - } else if (m_ams_model == AMSModel::EXTRA_AMS) { + } else if (m_ams_model == AMSModel::AMS_LITE) { EnterExtraAMSMode(); } } @@ -998,7 +998,7 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) if (m_ams_model == AMSModel::GENERIC_AMS){ m_ams_cans_list = m_ams_generic_cans_list; } - else if (m_ams_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE) { m_ams_cans_list = m_ams_extra_cans_list; } @@ -1034,7 +1034,7 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) if (ifo.ams_id == cans->amsIndex) { cans->amsCans->m_info = ifo; cans->amsCans->Update(ifo); - cans->amsCans->show_sn_value(m_ams_model == AMSModel::EXTRA_AMS?false:true); + cans->amsCans->show_sn_value(m_ams_model == AMSModel::AMS_LITE?false:true); } } } @@ -1045,7 +1045,7 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) } } - if (m_ams_model == AMSModel::NO_AMS && !m_vams_lib->is_selected()) { + if (m_ams_model == AMSModel::EXT_AMS && !m_vams_lib->is_selected()) { m_vams_lib->OnSelected(); } } @@ -1082,7 +1082,7 @@ void AMSControl::AddAms(AMSinfo info) void AMSControl::AddExtraAms(AMSinfo info) { AmsCansWindow* canswin = new AmsCansWindow(); - auto amscans = new AmsCans(m_simplebook_extra_cans, info, AMSModel::EXTRA_AMS); + auto amscans = new AmsCans(m_simplebook_extra_cans, info, AMSModel::AMS_LITE); canswin->amsIndex = info.ams_id; canswin->amsCans = amscans; @@ -1156,7 +1156,7 @@ void AMSControl::SwitchAms(std::string ams_id) if (m_ams_model == AMSModel::GENERIC_AMS) { m_simplebook_generic_cans->SetSelection(cans->amsCans->m_selection); } - else if (m_ams_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE) { m_simplebook_extra_cans->SetSelection(cans->amsCans->m_selection); } } @@ -1321,7 +1321,7 @@ void AMSControl::SetExtruder(bool on_off, bool is_vams, std::string ams_now, wxC m_vams_road->OnVamsLoading(false); } } - else if (m_ams_model == AMSModel::EXTRA_AMS || m_ext_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE || m_ext_model == AMSModel::AMS_LITE) { if (!is_vams && !on_off) { m_extruder->TurnOff(); m_extruder->OnVamsLoading(false); @@ -1400,7 +1400,7 @@ void AMSControl::SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadTy m_extruder->OnAmsLoading(true, cans->amsCans->GetTagColr(canid)); } } - else if (m_ams_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE) { cans->amsCans->SetAmsStepExtra(canid, type, step); if (step != AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { m_extruder->OnAmsLoading(true, cans->amsCans->GetTagColr(canid)); diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index e5c5e08942a..2063e0eb309 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -104,9 +104,9 @@ class AMSControl : public wxSimplebook std::string GetCurrentCan(std::string amsid); wxColour GetCanColour(std::string amsid, std::string canid); - AMSModel m_ams_model{AMSModel::NO_AMS}; - AMSModel m_ext_model{AMSModel::NO_AMS}; - AMSModel m_is_none_ams_mode{AMSModel::NO_AMS}; + AMSModel m_ams_model{AMSModel::EXT_AMS}; + AMSModel m_ext_model{AMSModel::EXT_AMS}; + AMSModel m_is_none_ams_mode{AMSModel::EXT_AMS}; void SetAmsModel(AMSModel mode, AMSModel ext_mode) {m_ams_model = mode; m_ext_model = ext_mode;}; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 617816932aa..5b80a8439b4 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -49,6 +49,7 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo } this->humidity_raw = ams->humidity_raw; + this->ams_type = AMSModel(ams->type); cans.clear(); for (int i = 0; i < ams->trayList.size(); i++) { @@ -707,7 +708,7 @@ void AMSLib::on_left_down(wxMouseEvent &evt) top = (size.y - FromDIP(15) - m_bitmap_editable_light.GetBmpSize().y); bottom = size.y - FromDIP(15); } - else if (m_ams_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE) { top = (size.y - FromDIP(20) - m_bitmap_editable_light.GetBmpSize().y); bottom = size.y - FromDIP(20); } @@ -759,7 +760,7 @@ void AMSLib::render(wxDC &dc) if (m_ams_model == AMSModel::GENERIC_AMS) { render_generic_text(dc); } - else if (m_ams_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE) { render_extra_text(dc); } } @@ -977,7 +978,7 @@ void AMSLib::doRender(wxDC &dc) if (m_ams_model == AMSModel::GENERIC_AMS) { render_generic_lib(dc); } - else if (m_ams_model == AMSModel::EXTRA_AMS) { + else if (m_ams_model == AMSModel::AMS_LITE) { render_extra_lib(dc); } } @@ -1408,7 +1409,7 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in for (int i = 1; i <= 5; i++) { ams_humidity_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 32));} for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } - + ams_sun_img = ScalableBitmap(this, "ams_drying", 16); if (m_rode_mode != AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { create(parent, id, pos, size); } @@ -1701,6 +1702,7 @@ void AMSRoad::msw_rescale() for (auto& img : ams_humidity_dark_imgs) { img.msw_rescale(); } for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } + ams_sun_img.msw_rescale(); } @@ -1736,7 +1738,7 @@ void AmsCans::create(wxWindow *parent) } SetSizer(sizer_can); } - else if(m_ams_model == AMSModel::EXTRA_AMS) { + else if(m_ams_model == AMSModel::AMS_LITE) { sizer_can = new wxBoxSizer(wxVERTICAL); sizer_can_middle = new wxBoxSizer(wxHORIZONTAL); sizer_can_left = new wxBoxSizer(wxVERTICAL); @@ -1823,7 +1825,7 @@ void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); m_sizer_ams->Add(m_panel_road, 0, wxALL, 0); } - else if (m_ams_model == AMSModel::EXTRA_AMS) + else if (m_ams_model == AMSModel::AMS_LITE) { m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); m_panel_road->Hide(); @@ -1846,7 +1848,7 @@ void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size if (m_ams_model == AMSModel::GENERIC_AMS) { sizer->Add(amscan, 0, wxALL, 0); } - else if (m_ams_model == AMSModel::EXTRA_AMS) + else if (m_ams_model == AMSModel::AMS_LITE) { if (canindex > 1) { sizer->Prepend(amscan, 0, wxALL, 0); @@ -2100,7 +2102,7 @@ void AmsCans::doRender(wxDC& dc) dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); //road for extra - if (m_ams_model == AMSModel::EXTRA_AMS) { + if (m_ams_model == AMSModel::AMS_LITE) { auto end_top = size.x / 2 - FromDIP(99); auto passroad_width = 6; diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index a089da690d2..149b6d7f616 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -36,11 +36,12 @@ namespace Slic3r { namespace GUI { - enum AMSModel { - NO_AMS = 0, + EXT_AMS = 0, //ext GENERIC_AMS = 1, - EXTRA_AMS = 2 + AMS_LITE = 2, //ams-lite + N3F_AMS = 3, + N3S_AMS = 4 //n3s single_ams }; enum ActionButton { @@ -160,6 +161,7 @@ struct AMSinfo int curreent_filamentstep; int ams_humidity = 0; int humidity_raw = -1; + AMSModel ams_type = AMSModel::GENERIC_AMS; bool parse_ams_info(MachineObject* obj, Ams *ams, bool remain_flag = false, bool humidity_flag = false); }; @@ -396,7 +398,9 @@ class AMSRoad : public wxWindow std::vector ams_humidity_no_num_imgs; std::vector ams_humidity_no_num_dark_imgs; - + + ScalableBitmap ams_sun_img; + int m_humidity = { 0 }; bool m_show_humidity = { false }; bool m_vams_loading{false}; From 2a19372ca021902485c666beef21bbd464afd2e6 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Thu, 20 Feb 2025 20:09:22 +0800 Subject: [PATCH 071/127] FIX: update the display of AMSHumidity jira: [STUDIO-10119] Change-Id: I7a1be57bd0dff13be149d6450b36fb54ffa9521d (cherry picked from commit c3a8690987005e0f53bbd5f9622a670e76bed93a) --- resources/images/ams_is_drying.svg | 3 +++ src/slic3r/GUI/DeviceManager.cpp | 5 +++++ src/slic3r/GUI/DeviceManager.hpp | 1 + src/slic3r/GUI/Widgets/AMSItem.cpp | 24 ++++++++++++++++++++++++ src/slic3r/GUI/Widgets/AMSItem.hpp | 7 +++++++ 5 files changed, 40 insertions(+) create mode 100644 resources/images/ams_is_drying.svg diff --git a/resources/images/ams_is_drying.svg b/resources/images/ams_is_drying.svg new file mode 100644 index 00000000000..a6c02f1a794 --- /dev/null +++ b/resources/images/ams_is_drying.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 601ee3b30d9..7a5aa5ea4e1 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4056,6 +4056,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } if (!curr_ams) continue; + if (it->contains("dry_time") && (*it)["dry_time"].is_number()) + { + curr_ams->left_dry_time = (*it)["dry_time"].get(); + } + if (it->contains("humidity")) { std::string humidity = (*it)["humidity"].get(); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 0d857d47838..5e845d5f1c7 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -273,6 +273,7 @@ class Ams { type = type_id; } std::string id; + int left_dry_time = 0; int humidity = 5; int humidity_raw = -1;// the percentage, -1 means invalid. eg. 100 means 100% bool startup_read_opt{true}; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 5b80a8439b4..7da276db6bf 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -49,6 +49,7 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo } this->humidity_raw = ams->humidity_raw; + this->left_dray_time = ams->left_dry_time; this->ams_type = AMSModel(ams->type); cans.clear(); @@ -1410,6 +1411,7 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } ams_sun_img = ScalableBitmap(this, "ams_drying", 16); + ams_drying_img = ScalableBitmap(this, "ams_is_drying", 16); if (m_rode_mode != AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { create(parent, id, pos, size); } @@ -1636,6 +1638,27 @@ void AMSRoad::doRender(wxDC &dc) dc.DrawBitmap(hum_img.bmp(), pot); pot.x = pot.x + hum_img.GetBmpSize().x + FromDIP(3); } + + if (m_amsinfo.support_drying()) + { + pot.x += FromDIP(2);// spacing + + // vertical line + dc.SetPen(wxPen(wxColour(194, 194, 194))); + dc.SetBrush(wxBrush(wxColour(194, 194, 194))); + dc.DrawLine(pot.x, GetSize().y / 2 - FromDIP(10), pot.x, GetSize().y / 2 + FromDIP(10)); + + // sun image + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + pot.x += ((size.GetWidth() - pot.x) - ams_drying_img.GetBmpWidth()) / 2;// spacing + if (m_amsinfo.left_dray_time > 0) { + pot.y = (size.y - ams_drying_img.GetBmpHeight()) / 2; + dc.DrawBitmap(ams_drying_img.bmp(), pot); + } else { + pot.y = (size.y - ams_sun_img.GetBmpHeight()) / 2; + dc.DrawBitmap(ams_sun_img.bmp(), pot); + } + } } else { //to do ... @@ -1703,6 +1726,7 @@ void AMSRoad::msw_rescale() for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } ams_sun_img.msw_rescale(); + ams_drying_img.msw_rescale(); } diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 149b6d7f616..3b8960be24a 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -137,6 +137,9 @@ enum FilamentStepType { #define AMS_EXTRUDER_SIZE wxSize(FromDIP(86), FromDIP(72)) #define AMS_EXTRUDER_BITMAP_SIZE wxSize(FromDIP(36), FromDIP(55)) +#define AMS_HUMIDITY_DRY_WIDTH FromDIP(35) + + struct Caninfo { std::string can_id; @@ -161,9 +164,12 @@ struct AMSinfo int curreent_filamentstep; int ams_humidity = 0; int humidity_raw = -1; + int left_dray_time = 0; AMSModel ams_type = AMSModel::GENERIC_AMS; bool parse_ams_info(MachineObject* obj, Ams *ams, bool remain_flag = false, bool humidity_flag = false); + + bool support_drying() const { return (ams_type == AMSModel::N3S_AMS) || (ams_type == AMSModel::N3F_AMS); }; }; /************************************************* @@ -400,6 +406,7 @@ class AMSRoad : public wxWindow std::vector ams_humidity_no_num_dark_imgs; ScalableBitmap ams_sun_img; + ScalableBitmap ams_drying_img; int m_humidity = { 0 }; bool m_show_humidity = { false }; From e3ffc39316b2e421f0509b10ac50a835a9508b6a Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 19 May 2025 23:10:16 +0800 Subject: [PATCH 072/127] Display correct AMS type --- src/slic3r/GUI/StatusPanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 7a9144a8513..9ab501843c9 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2599,10 +2599,9 @@ void StatusPanel::update_ams(MachineObject *obj) if (obj) { if (obj->get_printer_ams_type() == "f1") { ams_mode = AMSModel::AMS_LITE; } - else if(obj->get_printer_ams_type() == "generic") { ams_mode = AMSModel::GENERIC_AMS; } obj->check_ams_filament_valid(); } - + if (obj->is_enable_np && obj->amsList.size() > 0) { ams_mode = AMSModel(obj->amsList.begin()->second->type); } if (!obj || !obj->is_connected() || obj->amsList.empty() @@ -2640,6 +2639,7 @@ void StatusPanel::update_ams(MachineObject *obj) AMSinfo info; info.ams_id = ams->first; if (ams->second->is_exists && info.parse_ams_info(obj, ams->second, obj->ams_calibrate_remain_flag, obj->is_support_ams_humidity)) { + if (ams_mode == AMSModel::AMS_LITE) { info.ams_type = AMSModel::AMS_LITE; } ams_info.push_back(info); } } From 5f989c81d131972a1d4d1ec239e3c90c2f5d1e65 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 19 May 2025 23:37:10 +0800 Subject: [PATCH 073/127] Port BBS `AMSHumidity` --- src/slic3r/GUI/Widgets/AMSControl.cpp | 1 - src/slic3r/GUI/Widgets/AMSItem.cpp | 351 +++++++++++++++++--------- src/slic3r/GUI/Widgets/AMSItem.hpp | 97 ++++++- 3 files changed, 316 insertions(+), 133 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 6fa1f412575..87e81bde301 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -782,7 +782,6 @@ void AMSControl::msw_rescale() m_button_guide->SetMinSize(wxSize(-1, FromDIP(24))); m_button_retry->SetMinSize(wxSize(-1, FromDIP(24))); m_vams_lib->msw_rescale(); - m_vams_road->msw_rescale(); for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { AmsCansWindow *cans = m_ams_cans_list[i]; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 7da276db6bf..2e77a8dc913 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -1406,12 +1406,6 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in m_rode_mode = AMSRoadMode::AMS_ROAD_MODE_NONE_ANY_ROAD; } - for (int i = 1; i <= 5; i++) { ams_humidity_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 32));} - for (int i = 1; i <= 5; i++) { ams_humidity_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 32));} - for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } - for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } - ams_sun_img = ScalableBitmap(this, "ams_drying", 16); - ams_drying_img = ScalableBitmap(this, "ams_is_drying", 16); if (m_rode_mode != AMSRoadMode::AMS_ROAD_MODE_VIRTUAL_TRAY) { create(parent, id, pos, size); } @@ -1423,25 +1417,6 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in Bind(wxEVT_PAINT, &AMSRoad::paintEvent, this); wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - - Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { - if (m_canindex == 3 && m_show_humidity) { - auto mouse_pos = ClientToScreen(e.GetPosition()); - auto rect = ClientToScreen(wxPoint(0, 0)); - - if (mouse_pos.x > rect.x + GetSize().x - FromDIP(40) && - mouse_pos.y > rect.y + GetSize().y - FromDIP(40)) { - wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); - wxPostEvent(GetParent()->GetParent(), show_event); - -#ifdef __WXMSW__ - wxCommandEvent close_event(EVT_CLEAR_SPEED_CONTROL); - wxPostEvent(GetParent()->GetParent(), close_event); -#endif // __WXMSW__ - - } - } - }); } void AMSRoad::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size); } @@ -1585,85 +1560,6 @@ void AMSRoad::doRender(wxDC &dc) dc.SetBrush(wxBrush(m_road_def_color)); dc.DrawRoundedRectangle(size.x * 0.37 / 2, size.y * 0.6 - size.y / 6, size.x * 0.63, size.y / 3, m_radius); } - - if (m_canindex == 3) { - - if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) {m_show_humidity = true;} - else {m_show_humidity = false;} - - if (m_show_humidity) { - wxPoint pot; - if (m_amsinfo.humidity_raw != -1) /*image with no number + percentage*/ - { - // hum image - ScalableBitmap hum_img; - if (!wxGetApp().dark_mode()) { - hum_img = ams_humidity_no_num_imgs[m_amsinfo.ams_humidity - 1]; - } else { - hum_img = ams_humidity_no_num_dark_imgs[m_amsinfo.ams_humidity - 1]; - } - - pot = wxPoint(FromDIP(5), size.y - hum_img.GetBmpSize().y - FromDIP(8)); - dc.DrawBitmap(hum_img.bmp(), pot); - - // percentage - wxString hum_percentage(std::to_string(m_amsinfo.humidity_raw)); - auto tsize = dc.GetMultiLineTextExtent(hum_percentage); - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetFont(Label::Body_14); - dc.SetTextForeground(StateColor::darkModeColorFor(AMS_CONTROL_BLACK_COLOUR)); - // pot = wxPoint(FromDIP(size.x * 0.3), FromDIP((size.y - tsize.y) / 2)); - pot.x = pot.x + hum_img.GetBmpSize().x + FromDIP(3); - dc.DrawText(hum_percentage, pot); - - pot.x += (tsize.x + FromDIP(5)); - dc.SetFont(Label::Body_12); - tsize = dc.GetMultiLineTextExtent(_L("%")); - pot.y += (tsize.y / 2 - FromDIP(4)); - dc.DrawText(_L("%"), pot); - - pot.x = pot.x + tsize.x + FromDIP(2); - } - else /*image with number*/ - { - // hum image - ScalableBitmap hum_img; - if (!wxGetApp().dark_mode()) { - hum_img = ams_humidity_imgs[m_amsinfo.ams_humidity - 1]; - } else { - hum_img = ams_humidity_dark_imgs[m_amsinfo.ams_humidity - 1]; - } - - pot = wxPoint(size.x - FromDIP(33), size.y - FromDIP(33)); - dc.DrawBitmap(hum_img.bmp(), pot); - pot.x = pot.x + hum_img.GetBmpSize().x + FromDIP(3); - } - - if (m_amsinfo.support_drying()) - { - pot.x += FromDIP(2);// spacing - - // vertical line - dc.SetPen(wxPen(wxColour(194, 194, 194))); - dc.SetBrush(wxBrush(wxColour(194, 194, 194))); - dc.DrawLine(pot.x, GetSize().y / 2 - FromDIP(10), pot.x, GetSize().y / 2 + FromDIP(10)); - - // sun image - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - pot.x += ((size.GetWidth() - pot.x) - ams_drying_img.GetBmpWidth()) / 2;// spacing - if (m_amsinfo.left_dray_time > 0) { - pot.y = (size.y - ams_drying_img.GetBmpHeight()) / 2; - dc.DrawBitmap(ams_drying_img.bmp(), pot); - } else { - pot.y = (size.y - ams_sun_img.GetBmpHeight()) / 2; - dc.DrawBitmap(ams_sun_img.bmp(), pot); - } - } - } - else { - //to do ... - } - } } void AMSRoad::UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step) {} @@ -1719,16 +1615,6 @@ void AMSRoad::OnPassRoad(std::vector prord_list) } } -void AMSRoad::msw_rescale() -{ - for (auto& img : ams_humidity_imgs) { img.msw_rescale();} - for (auto& img : ams_humidity_dark_imgs) { img.msw_rescale(); } - for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } - for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } - ams_sun_img.msw_rescale(); - ams_drying_img.msw_rescale(); -} - /************************************************* Description:AmsCan @@ -1754,13 +1640,17 @@ void AmsCans::create(wxWindow *parent) Freeze(); SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (m_ams_model == AMSModel::GENERIC_AMS || m_ams_model == AMSModel::N3F_AMS || m_ams_model == AMSModel::N3S_AMS) { sizer_can = new wxBoxSizer(wxHORIZONTAL); + sizer_item = new wxBoxSizer(wxVERTICAL); for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { AddCan(*it, m_can_count, m_info.cans.size(), sizer_can); m_can_count++; } - SetSizer(sizer_can); + m_humidity = new AMSHumidity(this, wxID_ANY, m_info); + sizer_item->Add(m_humidity, 0, wxALIGN_CENTER_HORIZONTAL, 0); + sizer_item->Add(sizer_can, 0, wxALIGN_CENTER_HORIZONTAL, 0); + SetSizer(sizer_item); } else if(m_ams_model == AMSModel::AMS_LITE) { sizer_can = new wxBoxSizer(wxVERTICAL); @@ -1843,7 +1733,7 @@ void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); if (m_ams_model == AMSModel::GENERIC_AMS) { - m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(14)); + m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); @@ -1903,6 +1793,11 @@ void AmsCans::Update(AMSinfo info) m_info = info; m_can_count = info.cans.size(); + if (m_humidity) + { + m_humidity->Update(m_info); + } + for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { Canrefreshs *refresh = m_can_refresh_list[i]; if (i < m_can_count) { @@ -2262,11 +2157,7 @@ void AmsCans::msw_rescale() CanLibs* lib = m_can_lib_list[i]; lib->canLib->msw_rescale(); } - - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads* road = m_can_road_list[i]; - road->canRoad->msw_rescale(); - } + if (m_humidity != nullptr) m_humidity->msw_rescale(); } void AmsCans::show_sn_value(bool show) @@ -2277,6 +2168,222 @@ void AmsCans::show_sn_value(bool show) } } +/************************************************* +Description:AMSHumidity +**************************************************/ + +AMSHumidity::AMSHumidity() {} +AMSHumidity::AMSHumidity(wxWindow* parent, wxWindowID id, AMSinfo info, const wxPoint& pos, const wxSize& size) + : AMSHumidity() +{ + create(parent, id, pos, wxDefaultSize); + + for (int i = 1; i <= 5; i++) { ams_humidity_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 16));} + for (int i = 1; i <= 5; i++) { ams_humidity_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 16));} + for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } + for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } + + ams_sun_img = ScalableBitmap(this, "ams_drying", 16); + ams_drying_img = ScalableBitmap(this, "ams_is_drying", 16); + + Bind(wxEVT_PAINT, &AMSHumidity::paintEvent, this); + //wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_HUMIDITY_BK_COLOUR); + + Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { + if (m_show_humidity) { + auto mouse_pos = ClientToScreen(e.GetPosition()); + auto rect = ClientToScreen(wxPoint(0, 0)); + + if (mouse_pos.x > rect.x && + mouse_pos.y > rect.y) { + wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); + + //uiAmsHumidityInfo *info = new uiAmsHumidityInfo; + //info->ams_id = m_amsinfo.ams_id; + //info->humidity_level = m_amsinfo.ams_humidity; + //info->humidity_percent = m_amsinfo.humidity_raw; + //info->left_dry_time = m_amsinfo.left_dray_time; + //info->current_temperature = m_amsinfo.current_temperature; + //show_event.SetClientData(info); + wxPostEvent(GetParent()->GetParent(), show_event); + +#ifdef __WXMSW__ + wxCommandEvent close_event(EVT_CLEAR_SPEED_CONTROL); + wxPostEvent(GetParent()->GetParent(), close_event); +#endif // __WXMSW__ + + } + } + }); + + Update(info); +} + +void AMSHumidity::create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) { + wxWindow::Create(parent, id, pos, size); + SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); +} + + +void AMSHumidity::Update(AMSinfo amsinfo) +{ + if (m_amsinfo != amsinfo) + { + m_amsinfo = amsinfo; + update_size(); + Refresh(); + } +} + +void AMSHumidity::update_size() +{ + wxSize size; + if (m_amsinfo.humidity_raw != -1) { + size = AMS_HUMIDITY_SIZE; + } else { + size = AMS_HUMIDITY_NO_PERCENT_SIZE; + } + + if (!m_amsinfo.support_drying()) { size.x -= AMS_HUMIDITY_DRY_WIDTH; } + + SetMaxSize(size); + SetMinSize(size); + SetSize(size); +} + + +void AMSHumidity::paintEvent(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSHumidity::render(wxDC& dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AMSHumidity::doRender(wxDC& dc) +{ + wxSize size = GetSize(); + + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_BLOCK_BK_COLOUR))); + // left mode + if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) { m_show_humidity = true; } + else { m_show_humidity = false; } + + if (m_show_humidity) { + //background + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_BLOCK_BK_COLOUR))); + dc.DrawRoundedRectangle(0, 0, (size.x), (size.y), (size.y / 2)); + + wxPoint pot; + if (m_amsinfo.humidity_raw != -1) /*image with no number + percentage*/ + { + // hum image + ScalableBitmap hum_img; + if (!wxGetApp().dark_mode()) { + hum_img = ams_humidity_no_num_imgs[m_amsinfo.ams_humidity - 1]; + } else { + hum_img = ams_humidity_no_num_dark_imgs[m_amsinfo.ams_humidity - 1]; + } + + pot = wxPoint(FromDIP(5), ((size.y - hum_img.GetBmpSize().y) / 2)); + dc.DrawBitmap(hum_img.bmp(), pot); + pot.x += hum_img.GetBmpSize().x + FromDIP(3); + + // percentage + wxString hum_percentage(std::to_string(m_amsinfo.humidity_raw)); + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetFont(Label::Body_14); + dc.SetTextForeground(StateColor::darkModeColorFor(AMS_CONTROL_BLACK_COLOUR)); + + //WxFontUtils::get_suitable_font_size(0.7 * size.GetHeight(), dc); + auto tsize1 = dc.GetMultiLineTextExtent(hum_percentage); + pot.y = (size.y - tsize1.y) / 2; + dc.DrawText(hum_percentage, pot); + pot.x += (tsize1.x + FromDIP(3)); + + // percentage sign + dc.SetFont(Label::Body_12); + //WxFontUtils::get_suitable_font_size(0.5 * size.GetHeight(), dc); + auto tsize2 = dc.GetMultiLineTextExtent(_L("%")); + pot.y = pot.y + ((tsize1.y - tsize2.y) / 2) + FromDIP(2); + dc.DrawText(_L("%"), pot); + + pot.x += tsize2.x; + } + else /*image with number*/ + { + // hum image + ScalableBitmap hum_img; + if (!wxGetApp().dark_mode()) { + hum_img = ams_humidity_imgs[m_amsinfo.ams_humidity - 1]; + } else { + hum_img = ams_humidity_dark_imgs[m_amsinfo.ams_humidity - 1]; + } + + pot = wxPoint(FromDIP(5), ((size.y - hum_img.GetBmpSize().y) / 2)); + dc.DrawBitmap(hum_img.bmp(), pot); + pot.x = pot.x + hum_img.GetBmpSize().x; + } + + if (m_amsinfo.support_drying()) + { + pot.x += FromDIP(2);// spacing + + // vertical line + dc.SetPen(wxPen(wxColour(194, 194, 194))); + dc.SetBrush(wxBrush(wxColour(194, 194, 194))); + dc.DrawLine(pot.x, GetSize().y / 2 - FromDIP(10), pot.x, GetSize().y / 2 + FromDIP(10)); + + // sun image + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + pot.x += ((size.GetWidth() - pot.x) - ams_drying_img.GetBmpWidth()) / 2;// spacing + if (m_amsinfo.left_dray_time > 0) { + pot.y = (size.y - ams_drying_img.GetBmpHeight()) / 2; + dc.DrawBitmap(ams_drying_img.bmp(), pot); + } else { + pot.y = (size.y - ams_sun_img.GetBmpHeight()) / 2; + dc.DrawBitmap(ams_sun_img.bmp(), pot); + } + } + } + else { + //to do ... + } +} + +void AMSHumidity::msw_rescale() { + for (auto& img : ams_humidity_imgs) { img.msw_rescale();} + for (auto& img : ams_humidity_dark_imgs) { img.msw_rescale(); } + for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } + for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } + ams_sun_img.msw_rescale(); + ams_drying_img.msw_rescale(); + + Layout(); + Refresh(); +} + /************************************************* Description:AMSItem **************************************************/ diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 3b8960be24a..37edad7de71 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -137,6 +137,8 @@ enum FilamentStepType { #define AMS_EXTRUDER_SIZE wxSize(FromDIP(86), FromDIP(72)) #define AMS_EXTRUDER_BITMAP_SIZE wxSize(FromDIP(36), FromDIP(55)) +#define AMS_HUMIDITY_SIZE wxSize(FromDIP(93), FromDIP(26)) +#define AMS_HUMIDITY_NO_PERCENT_SIZE wxSize(FromDIP(60), FromDIP(26)) #define AMS_HUMIDITY_DRY_WIDTH FromDIP(35) @@ -151,6 +153,25 @@ struct Caninfo float k = 0.0f; float n = 0.0f; std::vector material_cols; + +public: + bool operator==(const Caninfo& other) const + { + if (can_id == other.can_id && + material_name == other.material_name && + material_colour == other.material_colour && + material_state == other.material_state && + ctype == other.ctype && + material_remain == other.material_remain && + k == other.k && + n == other.n && + material_cols == other.material_cols) + { + return true; + } + + return false; + }; }; struct AMSinfo @@ -167,6 +188,35 @@ struct AMSinfo int left_dray_time = 0; AMSModel ams_type = AMSModel::GENERIC_AMS; +public: + bool operator== (const AMSinfo& other) const + { + if (ams_id == other.ams_id && + cans == other.cans && + current_can_id == other.current_can_id && + current_step == other.current_step && + current_action == other.current_action && + curreent_filamentstep == other.curreent_filamentstep && + ams_humidity == other.ams_humidity && + left_dray_time == other.left_dray_time && + ams_type == other.ams_type) + { + return true; + } + + return false; + }; + + bool operator!=(const AMSinfo &other) const + { + if (operator==(other)) + { + return false; + } + + return true; + }; + bool parse_ams_info(MachineObject* obj, Ams *ams, bool remain_flag = false, bool humidity_flag = false); bool support_drying() const { return (ams_type == AMSModel::N3S_AMS) || (ams_type == AMSModel::N3F_AMS); }; @@ -399,6 +449,34 @@ class AMSRoad : public wxWindow wxColour m_road_color; void Update(AMSinfo amsinfo, Caninfo info, int canindex, int maxcan); + bool m_vams_loading{false}; + AMSModel m_ams_model; + + void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); + void SetPassRoadColour(wxColour col); + void SetMode(AMSRoadMode mode); + void OnPassRoad(std::vector prord_list); + void UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step); + + void paintEvent(wxPaintEvent &evt); + void render(wxDC &dc); + void doRender(wxDC& dc); +}; + +/************************************************* +Description:AMSHumidity +**************************************************/ +class AMSHumidity : public wxWindow +{ +public: + AMSHumidity(); + AMSHumidity(wxWindow* parent, wxWindowID id, AMSinfo info, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); + void create(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); + +public: + AMSinfo m_amsinfo; + void Update(AMSinfo amsinfo); + std::vector ams_humidity_imgs; std::vector ams_humidity_dark_imgs; @@ -408,21 +486,17 @@ class AMSRoad : public wxWindow ScalableBitmap ams_sun_img; ScalableBitmap ams_drying_img; + int m_humidity = { 0 }; bool m_show_humidity = { false }; - bool m_vams_loading{false}; - AMSModel m_ams_model; - void OnVamsLoading(bool load, wxColour col = AMS_CONTROL_GRAY500); - void SetPassRoadColour(wxColour col); - void SetMode(AMSRoadMode mode); - void OnPassRoad(std::vector prord_list); - void UpdatePassRoad(int tag_index, AMSPassRoadType type, AMSPassRoadSTEP step); - - void paintEvent(wxPaintEvent &evt); - void render(wxDC &dc); + void paintEvent(wxPaintEvent& evt); + void render(wxDC& dc); void doRender(wxDC& dc); void msw_rescale(); + +private: + void update_size(); }; /************************************************* @@ -530,8 +604,11 @@ class AmsCans : public wxWindow CanLibsHash m_can_lib_list; CansRoadsHash m_can_road_list; CanrefreshsHash m_can_refresh_list; + AMSHumidity* m_humidity = { nullptr }; + AMSinfo m_info; wxBoxSizer * sizer_can = {nullptr}; + wxBoxSizer * sizer_item = { nullptr }; wxBoxSizer * sizer_can_middle = {nullptr}; wxBoxSizer * sizer_can_left = {nullptr}; wxBoxSizer * sizer_can_right = {nullptr}; From 575d543299df947082df15db795c73e045afccef Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 19 May 2025 23:52:33 +0800 Subject: [PATCH 074/127] Fix AMS panel colour --- src/slic3r/GUI/Widgets/AMSControl.cpp | 14 +++++++------- src/slic3r/GUI/Widgets/AMSItem.cpp | 12 ++++++------ src/slic3r/GUI/Widgets/AMSItem.hpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 87e81bde301..ef2d2d379e4 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -112,21 +112,21 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_panel_can = new StaticBox(m_amswin, wxID_ANY, wxDefaultPosition, AMS_CANS_SIZE, wxBORDER_NONE); m_panel_can->SetMinSize(AMS_CANS_SIZE); m_panel_can->SetCornerRadius(FromDIP(10)); - m_panel_can->SetBackgroundColor(StateColor(std::pair(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, StateColor::Normal))); + m_panel_can->SetBackgroundColor(StateColor(std::pair(AMS_CONTROL_DEF_LIB_BK_COLOUR, StateColor::Normal))); m_sizer_cans = new wxBoxSizer(wxHORIZONTAL); m_simplebook_ams = new wxSimplebook(m_panel_can, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); - m_simplebook_ams->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + m_simplebook_ams->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); m_sizer_cans->Add(m_simplebook_ams, 0, wxLEFT | wxLEFT, FromDIP(10)); // ams mode m_simplebook_generic_cans = new wxSimplebook(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); - m_simplebook_generic_cans->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + m_simplebook_generic_cans->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); // none ams mode m_none_ams_panel = new wxPanel(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); - m_none_ams_panel->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + m_none_ams_panel->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); auto m_tip_none_ams = new wxStaticText(m_none_ams_panel, wxID_ANY, _L("AMS not connected"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); m_tip_none_ams->SetMinSize(wxSize(AMS_CANS_SIZE.x - FromDIP(20), -1)); @@ -144,7 +144,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons //extra ams mode m_simplebook_extra_cans = new wxSimplebook(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); - m_simplebook_extra_cans->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + m_simplebook_extra_cans->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); m_simplebook_ams->AddPage(m_none_ams_panel, wxEmptyString, false); m_simplebook_ams->AddPage(m_simplebook_generic_cans, wxEmptyString, false); @@ -252,7 +252,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons //virtual ams m_panel_virtual = new StaticBox(m_amswin, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); - m_panel_virtual->SetBackgroundColor(StateColor(std::pair(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, StateColor::Normal))); + m_panel_virtual->SetBackgroundColor(StateColor(std::pair(AMS_CONTROL_DEF_LIB_BK_COLOUR, StateColor::Normal))); m_panel_virtual->SetMinSize(wxSize(AMS_CAN_LIB_SIZE.x + FromDIP(16), AMS_CANS_SIZE.y)); m_panel_virtual->SetMaxSize(wxSize(AMS_CAN_LIB_SIZE.x + FromDIP(16), AMS_CANS_SIZE.y)); @@ -260,7 +260,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_vams_info.can_id = wxString::Format("%d", VIRTUAL_TRAY_ID).ToStdString(); auto vams_panel = new wxWindow(m_panel_virtual, wxID_ANY); - vams_panel->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + vams_panel->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); m_vams_lib = new AMSLib(vams_panel, m_vams_info.can_id, m_vams_info); m_vams_lib->m_slot_id = m_vams_info.can_id; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 2e77a8dc913..3fa2152c255 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -145,7 +145,7 @@ AMSrefresh::AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint void AMSrefresh::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size, wxBORDER_NONE); - SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); Bind(wxEVT_TIMER, &AMSrefresh::on_timer, this); Bind(wxEVT_PAINT, &AMSrefresh::paintEvent, this); @@ -608,7 +608,7 @@ void AMSVirtualRoad::doRender(wxDC& dc) dc.DrawRoundedRectangle(size.x / 2, -size.y / 1.1 + FromDIP(1), size.x, size.y, 4); if ((m_current_color == *wxWHITE || m_current_color.Alpha() == 0) && !wxGetApp().dark_mode()) { - dc.SetPen(wxPen(AMS_CONTROL_DEF_BLOCK_BK_COLOUR, 1, wxPENSTYLE_SOLID)); + dc.SetPen(wxPen(AMS_CONTROL_DEF_LIB_BK_COLOUR, 1, wxPENSTYLE_SOLID)); dc.DrawRoundedRectangle(size.x / 2 - FromDIP(3), -size.y / 1.1 + FromDIP(4), size.x, size.y, 5); dc.DrawRoundedRectangle(size.x / 2 + FromDIP(3), -size.y / 1.1 - FromDIP(2), size.x, size.y, 3); } @@ -630,7 +630,7 @@ AMSLib::AMSLib(wxWindow *parent, std::string ams_idx, Caninfo info) { m_border_color = (wxColour(130, 130, 128)); m_road_def_color = AMS_CONTROL_GRAY500; - wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); create(parent); Bind(wxEVT_PAINT, &AMSLib::paintEvent, this); @@ -1416,7 +1416,7 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in } Bind(wxEVT_PAINT, &AMSRoad::paintEvent, this); - wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); } void AMSRoad::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size); } @@ -1638,7 +1638,7 @@ AmsCans::AmsCans(wxWindow *parent,AMSinfo info, AMSModel model) : AmsCans() void AmsCans::create(wxWindow *parent) { Freeze(); - SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); if (m_ams_model == AMSModel::GENERIC_AMS || m_ams_model == AMSModel::N3F_AMS || m_ams_model == AMSModel::N3S_AMS) { sizer_can = new wxBoxSizer(wxHORIZONTAL); @@ -1695,7 +1695,7 @@ void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size { auto amscan = new wxWindow(this, wxID_ANY); - amscan->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + amscan->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 37edad7de71..f6d69adc264 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -525,7 +525,7 @@ class AMSItem : public wxWindow protected: wxSize m_cube_size; - wxColour m_background_colour = {AMS_CONTROL_DEF_BLOCK_BK_COLOUR}; + wxColour m_background_colour = {AMS_CONTROL_DEF_LIB_BK_COLOUR}; int m_padding = {7}; int m_space = {5}; bool m_hover = {false}; From 917b638227805761f3eb8555200f0802d6ca4db1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 20 May 2025 10:48:19 +0800 Subject: [PATCH 075/127] Adjust spacing --- src/slic3r/GUI/Widgets/AMSItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 3fa2152c255..2f6f7b52a61 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -1733,9 +1733,9 @@ void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); if (m_ams_model == AMSModel::GENERIC_AMS) { - m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); + //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); - m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); + //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); m_sizer_ams->Add(m_panel_road, 0, wxALL, 0); } From b05187024582673f4941ea7a4218c04b7493bfe5 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Thu, 2 Jan 2025 16:01:54 +0800 Subject: [PATCH 076/127] FIX: support more device components jira: [STUDIO-9275] Change-Id: I8105828183d42496eed77793daa1c1a618e252bf (cherry picked from commit 478fc597c4b0f054c93bef954f3ca1054111b4b3) --- resources/images/cut.svg | 177 +++++++++++++ resources/images/laser.svg | 249 ++++++++++++++++++ src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/DeviceManager.cpp | 22 +- src/slic3r/GUI/DeviceManager.hpp | 12 + src/slic3r/GUI/DeviceTab/CMakeLists.txt | 10 + .../GUI/DeviceTab/uiDeviceUpdateVersion.cpp | 103 ++++++++ .../GUI/DeviceTab/uiDeviceUpdateVersion.h | 47 ++++ src/slic3r/GUI/UpgradePanel.cpp | 149 ++++++++++- src/slic3r/GUI/UpgradePanel.hpp | 35 +++ 10 files changed, 804 insertions(+), 2 deletions(-) create mode 100644 resources/images/cut.svg create mode 100644 resources/images/laser.svg create mode 100644 src/slic3r/GUI/DeviceTab/CMakeLists.txt create mode 100644 src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp create mode 100644 src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h diff --git a/resources/images/cut.svg b/resources/images/cut.svg new file mode 100644 index 00000000000..f04edf7b395 --- /dev/null +++ b/resources/images/cut.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/laser.svg b/resources/images/laser.svg new file mode 100644 index 00000000000..7380a6d8064 --- /dev/null +++ b/resources/images/laser.svg @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 5bf0eab0ced..cd22de6ef0c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -579,6 +579,8 @@ set(SLIC3R_GUI_SOURCES Utils/bambu_networking.hpp ) +add_subdirectory(GUI/DeviceTab) + if (WIN32) list(APPEND SLIC3R_GUI_SOURCES GUI/dark_mode/dark_mode.hpp diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 7a5aa5ea4e1..3e4423105e1 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1352,6 +1352,24 @@ std::map MachineObject::get_ams_version() return result; } +void MachineObject::store_version_info(const ModuleVersionInfo& info) +{ + if (info.isAirPump()) + { + air_pump_version_info = info; + } + else if (info.isLaszer()) + { + laser_version_info = info; + } + else if (info.isCuttingModule()) + { + cutting_module_version_info = info; + } + + module_vers.emplace(info.name, info); +} + bool MachineObject::is_system_printing() { if (is_in_calibration() && is_in_printing_status(print_status)) @@ -2956,6 +2974,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) for (auto it = j_module.begin(); it != j_module.end(); it++) { ModuleVersionInfo ver_info; ver_info.name = (*it)["name"].get(); + ver_info.product_name = wxString::FromUTF8((*it).value("product_name", json()).get()); if ((*it).contains("sw_ver")) ver_info.sw_ver = (*it)["sw_ver"].get(); if ((*it).contains("sn")) @@ -2964,7 +2983,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) ver_info.hw_ver = (*it)["hw_ver"].get(); if((*it).contains("flag")) ver_info.firmware_status= (*it)["flag"].get(); - module_vers.emplace(ver_info.name, ver_info); + + store_version_info(ver_info); if (ver_info.name == "ota") { NetworkAgent* agent = GUI::wxGetApp().getAgent(); if (agent) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 5e845d5f1c7..3b41e7b661f 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -416,6 +416,7 @@ class MachineObject { public: std::string name; + wxString product_name; std::string sn; std::string hw_ver; std::string sw_ver; @@ -424,6 +425,12 @@ class MachineObject ModuleVersionInfo() :firmware_status(0) { }; + + public: + bool isValid() const { return !sn.empty(); } + bool isAirPump() const { return product_name.Contains("Air Pump"); } + bool isLaszer() const { return product_name.Contains("Laser"); } + bool isCuttingModule() const { return product_name.Contains("Cutting Module"); } }; enum SdcardState { @@ -630,6 +637,10 @@ class MachineObject std::string ota_new_version_number; std::string ahb_new_version_number; int get_version_retry = 0; + + ModuleVersionInfo air_pump_version_info; + ModuleVersionInfo laser_version_info; + ModuleVersionInfo cutting_module_version_info; std::map module_vers; std::map new_ver_list; std::map extrusion_ratio_map; @@ -647,6 +658,7 @@ class MachineObject wxString get_upgrade_result_str(int upgrade_err_code); // key: ams_id start as 0,1,2,3 std::map get_ams_version(); + void store_version_info(const ModuleVersionInfo& info); /* printing */ std::string print_type; diff --git a/src/slic3r/GUI/DeviceTab/CMakeLists.txt b/src/slic3r/GUI/DeviceTab/CMakeLists.txt new file mode 100644 index 00000000000..455f92ff6c5 --- /dev/null +++ b/src/slic3r/GUI/DeviceTab/CMakeLists.txt @@ -0,0 +1,10 @@ +# GUI/DeviceTab +# usage -- GUI about device tab for BambuStudio +# date -- 2025.01.01 +# status -- Building + +list(APPEND SLIC3R_GUI_SOURCES + GUI/DeviceTab/uiDeviceUpdateVersion.h + GUI/DeviceTab/uiDeviceUpdateVersion.cpp +) +set(SLIC3R_GUI_SOURCES ${SLIC3R_GUI_SOURCES} PARENT_SCOPE) \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp new file mode 100644 index 00000000000..bd3e63cc120 --- /dev/null +++ b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp @@ -0,0 +1,103 @@ +//**********************************************************/ +/* File: uiDeviceUpdateVersion.cpp +* Description: The panel with firmware info +* +* \n class uiDeviceUpdateVersion +//**********************************************************/ + +#include "uiDeviceUpdateVersion.h" + +#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/wxExtensions.hpp" + +#include + +#define SERIAL_STR "Serial:" +#define VERSION_STR "Version:" + +using namespace Slic3r::GUI; + + +uiDeviceUpdateVersion::uiDeviceUpdateVersion(wxWindow* parent, + wxWindowID id /*= wxID_ANY*/, + const wxPoint& pos /*= wxDefaultPosition*/, + const wxSize& size /*= wxDefaultSize*/, + long style /*= wxTAB_TRAVERSAL*/) + : wxPanel(parent, id, pos, size, style) +{ + CreateWidgets(); +} + +void uiDeviceUpdateVersion::UpdateInfo(const MachineObject::ModuleVersionInfo& info) +{ + SetName(info.product_name); + SetSerial(info.sn); + SetVersion(info.sw_ver, info.sw_new_ver); +} + +void uiDeviceUpdateVersion::SetVersion(const wxString& cur_version, const wxString& latest_version) +{ + if (cur_version.empty()) + { + return; + } + + if (!latest_version.empty() && (cur_version != latest_version)) + { + const wxString& shown_ver = wxString::Format("%s->%s", cur_version, latest_version); + m_dev_version->SetLabel(shown_ver); + if (!m_dev_upgrade_indicator->IsShown()) + { + m_dev_upgrade_indicator->Show(true); + } + } + else + { + const wxString& shown_ver = wxString::Format("%s(%s)", cur_version, _L("Latest version")); + m_dev_version->SetLabel(shown_ver); + if (m_dev_upgrade_indicator->IsShown()) + { + m_dev_upgrade_indicator->Hide(); + } + } +} + +void uiDeviceUpdateVersion::CreateWidgets() +{ + m_dev_name = new wxStaticText(this, wxID_ANY, "_"); + m_dev_snl = new wxStaticText(this, wxID_ANY, "_"); + m_dev_version = new wxStaticText(this, wxID_ANY, "_"); + + wxStaticText* serial_text = new wxStaticText(this, wxID_ANY, SERIAL_STR); + wxStaticText* version_text = new wxStaticText(this, wxID_ANY, VERSION_STR); + + // The main sizer + wxFlexGridSizer* main_sizer = new wxFlexGridSizer(3, 3, 0, 0); + main_sizer->AddGrowableCol(1); + main_sizer->SetFlexibleDirection(wxHORIZONTAL); + main_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + main_sizer->Add(m_dev_name, 0, wxALIGN_RIGHT | wxALL, FromDIP(5)); + main_sizer->Add(0, 0, wxALL, wxEXPAND); + main_sizer->Add(0, 0, wxALL, wxEXPAND); + + main_sizer->Add(serial_text, 0, wxALIGN_RIGHT | wxALL, FromDIP(5)); + main_sizer->Add(m_dev_snl, 0, wxALIGN_LEFT | wxALL, FromDIP(5)); + main_sizer->Add(0, 0, wxALL, wxEXPAND); + + m_dev_upgrade_indicator = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(5), FromDIP(5))); + m_dev_upgrade_indicator->SetBitmap(ScalableBitmap(this, "monitor_upgrade_online", 5).bmp()); + + wxBoxSizer* version_hsizer = new wxBoxSizer(wxHORIZONTAL); + version_hsizer->Add(m_dev_upgrade_indicator, 0, wxALIGN_CENTER_VERTICAL); + version_hsizer->AddSpacer(FromDIP(5)); + version_hsizer->Add(version_text, 0); + + main_sizer->Add(version_hsizer, 0, wxALIGN_RIGHT | wxALL, FromDIP(5)); + main_sizer->Add(m_dev_version, 0, wxALIGN_LEFT | wxALL, FromDIP(5)); + main_sizer->Add(0, 0, wxALL, wxEXPAND); + + // Updating + SetSizer(main_sizer); + Layout(); +} \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h new file mode 100644 index 00000000000..a4ffc52bb59 --- /dev/null +++ b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h @@ -0,0 +1,47 @@ +//**********************************************************/ +/* File: uiDeviceUpdateVersion.h +* Description: The panel with firmware info +* +* \n class uiDeviceUpdateVersion +//**********************************************************/ + +#pragma once +#include +#include "slic3r/GUI/wxExtensions.hpp" +#include "slic3r/GUI/DeviceManager.hpp" + +// Previous defintions +class wxStaticText; +class wxStaticBitmap; + +namespace Slic3r::GUI +{ +// @Class uiDeviceUpdateVersion +// @Note The panel with firmware info +class uiDeviceUpdateVersion : public wxPanel +{ +public: + uiDeviceUpdateVersion(wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL); + ~uiDeviceUpdateVersion() = default; + +public: + void UpdateInfo(const MachineObject::ModuleVersionInfo& info); + +private: + void CreateWidgets(); + + void SetName(const wxString& str) { m_dev_name->SetLabel(str); }; + void SetSerial(const wxString& str) { m_dev_snl->SetLabel(str); }; + void SetVersion(const wxString& cur_version, const wxString& latest_version); + +private: + wxStaticText* m_dev_name; + wxStaticText* m_dev_snl; + wxStaticText* m_dev_version; + wxStaticBitmap* m_dev_upgrade_indicator; +}; +};// end of namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 0088ab416d9..4b068958f8a 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -2,6 +2,8 @@ #include #include #include +#include "slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h" + #include "GUI.hpp" #include "GUI_App.hpp" #include "libslic3r/Thread.hpp" @@ -207,7 +209,10 @@ MachineInfoPanel::MachineInfoPanel(wxWindow* parent, wxWindowID id, const wxPoin m_main_left_sizer->Add(m_ext_sizer, 0, wxEXPAND, 0); - + /* cutting module */ + createCuttingWidgets(m_main_left_sizer); + createLaserWidgets(m_main_left_sizer); + createAirPumpWidgets(m_main_left_sizer); m_main_sizer->Add(m_main_left_sizer, 1, wxEXPAND, 0); @@ -318,6 +323,69 @@ wxPanel *MachineInfoPanel::create_caption_panel(wxWindow *parent) return caption_panel; } +void MachineInfoPanel::createAirPumpWidgets(wxBoxSizer* main_left_sizer) +{ + m_air_pump_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL); + m_air_pump_line_above->SetBackgroundColour(wxColour(206, 206, 206)); + main_left_sizer->Add(m_air_pump_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40)); + + m_air_pump_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200))); + m_air_pump_img->SetBitmap(m_img_air_pump.bmp()); + + wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL); + content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5)); + m_air_pump_version = new uiDeviceUpdateVersion(this, wxID_ANY); + content_sizer->Add(m_air_pump_version, 0, wxEXPAND, 0); + + m_air_pump_sizer = new wxBoxSizer(wxHORIZONTAL); + m_air_pump_sizer->Add(m_air_pump_img, 0, wxALIGN_TOP | wxALL, FromDIP(5)); + m_air_pump_sizer->Add(content_sizer, 1, wxEXPAND, 0); + + main_left_sizer->Add(m_air_pump_sizer, 0, wxEXPAND, 0); +} + +void MachineInfoPanel::createCuttingWidgets(wxBoxSizer* main_left_sizer) +{ + m_cutting_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL); + m_cutting_line_above->SetBackgroundColour(wxColour(206, 206, 206)); + main_left_sizer->Add(m_cutting_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40)); + + m_cutting_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200))); + m_cutting_img->SetBitmap(m_img_cutting.bmp()); + + wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL); + content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5)); + m_cutting_version = new uiDeviceUpdateVersion(this, wxID_ANY); + content_sizer->Add(m_cutting_version, 0, wxEXPAND, 0); + + m_cutting_sizer = new wxBoxSizer(wxHORIZONTAL); + m_cutting_sizer->Add(m_cutting_img, 0, wxALIGN_TOP | wxALL, FromDIP(5)); + m_cutting_sizer->Add(content_sizer, 1, wxEXPAND, 0); + + main_left_sizer->Add(m_cutting_sizer, 0, wxEXPAND, 0); +}; + +void MachineInfoPanel::createLaserWidgets(wxBoxSizer* main_left_sizer) +{ + m_laser_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL); + m_laser_line_above->SetBackgroundColour(wxColour(206, 206, 206)); + main_left_sizer->Add(m_laser_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40)); + + m_lazer_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200))); + m_lazer_img->SetBitmap(m_img_laser.bmp()); + + wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL); + content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5)); + m_laser_version = new uiDeviceUpdateVersion(this, wxID_ANY); + content_sizer->Add(m_laser_version, 0, wxEXPAND, 0); + + m_laser_sizer = new wxBoxSizer(wxHORIZONTAL); + m_laser_sizer->Add(m_lazer_img, 0, wxALIGN_TOP | wxALL, FromDIP(5)); + m_laser_sizer->Add(content_sizer, 1, wxEXPAND, 0); + + main_left_sizer->Add(m_laser_sizer, 0, wxEXPAND, 0); +} + void MachineInfoPanel::msw_rescale() { rescale_bitmaps(); @@ -345,6 +413,11 @@ void MachineInfoPanel::init_bitmaps() else { m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); } + + m_img_air_pump = ScalableBitmap(this, "printer_thumbnail", 160);/*TODO: replace the bitmap*/ + m_img_laser = ScalableBitmap(this, "laser", 160); + m_img_cutting = ScalableBitmap(this, "cut", 160); + upgrade_green_icon = ScalableBitmap(this, "monitor_upgrade_online", 5); upgrade_gray_icon = ScalableBitmap(this, "monitor_upgrade_offline", 5); upgrade_yellow_icon = ScalableBitmap(this, "monitor_upgrade_busy", 5); @@ -434,6 +507,11 @@ void MachineInfoPanel::update(MachineObject* obj) // update ams and extension update_ams_ext(obj); + // update + update_air_pump(obj); + update_cut(obj); + update_laszer(obj); + //update progress int upgrade_percent = obj->get_upgrade_percent(); if (obj->upgrade_display_state == (int) MachineObject::UpgradingDisplayState::UpgradingInProgress) { @@ -901,6 +979,45 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) this->Fit(); } +void MachineInfoPanel::update_air_pump(MachineObject* obj) +{ + if (obj && obj->air_pump_version_info.isValid()) + { + m_air_pump_version->UpdateInfo(obj->air_pump_version_info); + show_air_pump(true); + } + else + { + show_air_pump(false); + } +} + +void MachineInfoPanel::update_cut(MachineObject* obj) +{ + if (obj && obj->cutting_module_version_info.isValid()) + { + m_cutting_version->UpdateInfo(obj->cutting_module_version_info); + show_cut(true); + } + else + { + show_cut(false); + } +} + +void MachineInfoPanel::update_laszer(MachineObject* obj) +{ + if (obj && obj->laser_version_info.isValid()) + { + m_laser_version->UpdateInfo(obj->laser_version_info); + show_laszer(true); + } + else + { + show_laszer(false); + } +} + void MachineInfoPanel::show_status(int status, std::string upgrade_status_str) { if (last_status == status && last_status_str == upgrade_status_str) return; @@ -995,6 +1112,36 @@ void MachineInfoPanel::show_extra_ams(bool show, bool force_update) { m_last_extra_ams_show = show; } +void MachineInfoPanel::show_air_pump(bool show) +{ + if (m_air_pump_version->IsShown() != show) + { + m_air_pump_img->Show(show); + m_air_pump_line_above->Show(show); + m_air_pump_version->Show(show); + } +} + +void MachineInfoPanel::show_cut(bool show) +{ + if (m_cutting_version->IsShown() != show) + { + m_cutting_img->Show(show); + m_cutting_line_above->Show(show); + m_cutting_version->Show(show); + } +} + +void MachineInfoPanel::show_laszer(bool show) +{ + if (m_laser_version->IsShown() != show) + { + m_lazer_img->Show(show); + m_laser_line_above->Show(show); + m_laser_version->Show(show); + } +} + void MachineInfoPanel::on_sys_color_changed() { if (m_obj) { diff --git a/src/slic3r/GUI/UpgradePanel.hpp b/src/slic3r/GUI/UpgradePanel.hpp index 8e0a9ad0d9d..2028505f465 100644 --- a/src/slic3r/GUI/UpgradePanel.hpp +++ b/src/slic3r/GUI/UpgradePanel.hpp @@ -12,6 +12,9 @@ namespace Slic3r { namespace GUI { +// Previous definitions +class uiDeviceUpdateVersion; + class ExtensionPanel : public wxPanel { public: @@ -105,6 +108,24 @@ class MachineInfoPanel : public wxPanel bool m_last_extra_ams_show = true; wxBoxSizer* m_extra_ams_sizer; + /* air_pump info*/ + wxBoxSizer* m_air_pump_sizer = nullptr; + wxStaticBitmap* m_air_pump_img = nullptr; + wxStaticLine* m_air_pump_line_above = nullptr;; + uiDeviceUpdateVersion* m_air_pump_version = nullptr; + + /* cutting module info*/ + wxBoxSizer* m_cutting_sizer = nullptr; + wxStaticBitmap* m_cutting_img = nullptr; + wxStaticLine* m_cutting_line_above = nullptr;; + uiDeviceUpdateVersion* m_cutting_version = nullptr; + + /* laser info*/ + wxBoxSizer* m_laser_sizer = nullptr; + wxStaticBitmap* m_lazer_img = nullptr; + wxStaticLine* m_laser_line_above = nullptr;; + uiDeviceUpdateVersion* m_laser_version = nullptr; + /* upgrade widgets */ wxBoxSizer* m_upgrading_sizer; wxStaticText * m_staticText_upgrading_info; @@ -122,6 +143,9 @@ class MachineInfoPanel : public wxPanel ScalableBitmap m_img_monitor_ams; ScalableBitmap m_img_extra_ams; ScalableBitmap m_img_printer; + ScalableBitmap m_img_air_pump; + ScalableBitmap m_img_cutting; + ScalableBitmap m_img_laser; ScalableBitmap upgrade_gray_icon; ScalableBitmap upgrade_green_icon; ScalableBitmap upgrade_yellow_icon; @@ -151,10 +175,16 @@ class MachineInfoPanel : public wxPanel void update(MachineObject *obj); void update_version_text(MachineObject *obj); void update_ams_ext(MachineObject *obj); + void update_air_pump(MachineObject* obj); + void update_cut(MachineObject* obj); + void update_laszer(MachineObject* obj); void show_status(int status, std::string upgrade_status_str = ""); void show_ams(bool show = false, bool force_update = false); void show_ext(bool show = false, bool force_update = false); void show_extra_ams(bool show = false, bool force_update = false); + void show_air_pump(bool show = true); + void show_cut(bool show = true); + void show_laszer(bool show = true); void on_upgrade_firmware(wxCommandEvent &event); void on_consisitency_upgrade_firmware(wxCommandEvent &event); @@ -171,6 +201,11 @@ class MachineInfoPanel : public wxPanel ptOtaPanel, ptAmsPanel, }panel_type; + +private: + void createAirPumpWidgets(wxBoxSizer* main_left_sizer); + void createCuttingWidgets(wxBoxSizer* main_left_sizer); + void createLaserWidgets(wxBoxSizer* main_left_sizer); }; //enum UpgradeMode { From 6c9cbfc848d2a321903fd1bb8811bc5edae8fb2a Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Tue, 25 Feb 2025 14:31:32 +0800 Subject: [PATCH 077/127] FIX: the translation problem jira: [STUDIO-10531] Change-Id: I59b12a4efe181a98093bbbd5d3c341613609fc8e (cherry picked from commit 379e6314367a82a4e065f02355b853c4e068e75d) --- src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp index bd3e63cc120..4d1390f9632 100644 --- a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp +++ b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp @@ -12,8 +12,8 @@ #include -#define SERIAL_STR "Serial:" -#define VERSION_STR "Version:" +#define SERIAL_STR L("Serial:") +#define VERSION_STR L("Version:") using namespace Slic3r::GUI; @@ -68,8 +68,8 @@ void uiDeviceUpdateVersion::CreateWidgets() m_dev_snl = new wxStaticText(this, wxID_ANY, "_"); m_dev_version = new wxStaticText(this, wxID_ANY, "_"); - wxStaticText* serial_text = new wxStaticText(this, wxID_ANY, SERIAL_STR); - wxStaticText* version_text = new wxStaticText(this, wxID_ANY, VERSION_STR); + wxStaticText* serial_text = new wxStaticText(this, wxID_ANY, _L(SERIAL_STR)); + wxStaticText* version_text = new wxStaticText(this, wxID_ANY, _L(VERSION_STR)); // The main sizer wxFlexGridSizer* main_sizer = new wxFlexGridSizer(3, 3, 0, 0); From e924a04fb8eb15dcc2fb172d721819b68d91fdc8 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Thu, 6 Mar 2025 16:33:39 +0800 Subject: [PATCH 078/127] FIX: add translate key jira: [STUDIO-10586] Change-Id: Ice409b9459230254bbaaa4f706761d6927d8bdf8 (cherry picked from commit 5509447a6d500142ef3d078773678e37ba2f03e0) --- src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp | 2 +- src/slic3r/GUI/UpgradePanel.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp index 4d1390f9632..3d0feac7401 100644 --- a/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp +++ b/src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp @@ -30,7 +30,7 @@ uiDeviceUpdateVersion::uiDeviceUpdateVersion(wxWindow* parent, void uiDeviceUpdateVersion::UpdateInfo(const MachineObject::ModuleVersionInfo& info) { - SetName(info.product_name); + SetName(I18N::translate(info.product_name)); SetSerial(info.sn); SetVersion(info.sw_ver, info.sw_new_ver); } diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 4b068958f8a..9241aac4d57 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -17,10 +17,10 @@ static const wxColour TEXT_FAILED_CLR = wxColour(255, 111, 0); static const std::unordered_map ACCESSORY_DISPLAY_STR = { {"N3F", "AMS 2 PRO"}, {"N3S", "AMS HT"}, - {"O2L_PC", "Air Pump"}, - {"O2L_10B", "Laser 10w"}, - {"O2L_40B", "Laser 40w"}, - {"O2L_PCM", "Cutting Module"}, + {"O2L_PC", L("Air Pump")}, + {"O2L_10B", L("Laser 10w")}, + {"O2L_40B", L("Laser 40w")}, + {"O2L_PCM", L("Cutting Module")}, {"O2L_ACM", "Active Cutting Module"}, {"O2L_UCM", "Ultrasonic Cutting Module"}, }; From 0b98094dac2a6be50eb71561d911db43f26f7727 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Fri, 21 Feb 2025 15:57:10 +0800 Subject: [PATCH 079/127] FIX: The humidity popup with humidity_percent/temperature/dry_time jira: [STUDIO-9268] Change-Id: Ic6e923ae7cff56fa3e053d48e5dea6e393cd41eb (cherry picked from commit 75da1db2f926125a0cb3595a8cae9f4d7588c6a8) --- localization/i18n/list.txt | 4 + src/slic3r/GUI/DeviceManager.cpp | 14 ++ src/slic3r/GUI/DeviceManager.hpp | 2 + src/slic3r/GUI/DeviceTab/CMakeLists.txt | 2 + .../GUI/DeviceTab/uiAmsHumidityPopup.cpp | 238 ++++++++++++++++++ src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h | 70 ++++++ src/slic3r/GUI/Widgets/AMSControl.cpp | 41 ++- src/slic3r/GUI/Widgets/AMSControl.hpp | 4 + src/slic3r/GUI/Widgets/AMSItem.cpp | 16 +- src/slic3r/GUI/Widgets/AMSItem.hpp | 2 + 10 files changed, 375 insertions(+), 18 deletions(-) create mode 100644 src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp create mode 100644 src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h diff --git a/localization/i18n/list.txt b/localization/i18n/list.txt index f922c7878bf..f3792b34535 100644 --- a/localization/i18n/list.txt +++ b/localization/i18n/list.txt @@ -1,3 +1,7 @@ +src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h +src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp +src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.h +src/slic3r/GUI/DeviceTab/uiDeviceUpdateVersion.cpp src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 3e4423105e1..7206e98feed 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4127,6 +4127,20 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } + + if (it->contains("temp")) + { + std::string temp = (*it)["temp"].get(); + try + { + curr_ams->current_temperature = string_to_float(temp); + } + catch (...) + { + curr_ams->current_temperature = INVALID_AMS_TEMPERATURE; + } + } + if (it->contains("tray")) { std::set tray_id_set; for (auto it = curr_ams->trayList.begin(); it != curr_ams->trayList.end(); it++) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 3b41e7b661f..a37f32e995c 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -264,6 +264,7 @@ class AmsTray { std::string get_filament_type(); }; +#define INVALID_AMS_TEMPERATURE std::numeric_limits::min() class Ams { public: @@ -276,6 +277,7 @@ class Ams { int left_dry_time = 0; int humidity = 5; int humidity_raw = -1;// the percentage, -1 means invalid. eg. 100 means 100% + float current_temperature = INVALID_AMS_TEMPERATURE; // the temperature bool startup_read_opt{true}; bool tray_read_opt{false}; bool is_exists{false}; diff --git a/src/slic3r/GUI/DeviceTab/CMakeLists.txt b/src/slic3r/GUI/DeviceTab/CMakeLists.txt index 455f92ff6c5..2d62d59a0d6 100644 --- a/src/slic3r/GUI/DeviceTab/CMakeLists.txt +++ b/src/slic3r/GUI/DeviceTab/CMakeLists.txt @@ -4,6 +4,8 @@ # status -- Building list(APPEND SLIC3R_GUI_SOURCES + GUI/DeviceTab/uiAmsHumidityPopup.h + GUI/DeviceTab/uiAmsHumidityPopup.cpp GUI/DeviceTab/uiDeviceUpdateVersion.h GUI/DeviceTab/uiDeviceUpdateVersion.cpp ) diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp new file mode 100644 index 00000000000..ae4ee4739ca --- /dev/null +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp @@ -0,0 +1,238 @@ +//**********************************************************/ +/* File: uiAmsHumidityPopup.cpp +* Description: The popup with Ams Humidity +* +* \n class uiAmsHumidityPopup +//**********************************************************/ + +#include "uiAmsHumidityPopup.h" + +#include "slic3r/Utils/WxFontUtils.hpp" + +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/Widgets/StateColor.hpp" + + +#include + +namespace Slic3r { namespace GUI { + +uiAmsPercentHumidityDryPopup::uiAmsPercentHumidityDryPopup(wxWindow *parent) + : PopupWindow(parent, wxBORDER_NONE) +{ + SetSize(wxSize(FromDIP(400), FromDIP(270))); + SetMinSize(wxSize(FromDIP(400), FromDIP(270))); + SetMaxSize(wxSize(FromDIP(400), FromDIP(270))); + + idle_img = ScalableBitmap(this, "ams_drying", 16); + drying_img = ScalableBitmap(this, "ams_is_drying", 16); + close_img = ScalableBitmap(this, "hum_popup_close", 24); + + Bind(wxEVT_PAINT, &uiAmsPercentHumidityDryPopup::paintEvent, this); + Bind(wxEVT_LEFT_UP, [this](auto &e) { + auto rect = ClientToScreen(wxPoint(0, 0)); + + auto close_left = rect.x + GetSize().x - close_img.GetBmpWidth() - FromDIP(38); + auto close_right = close_left + close_img.GetBmpWidth(); + auto close_top = rect.y + FromDIP(24); + auto close_bottom = close_top + close_img.GetBmpHeight(); + + auto mouse_pos = ClientToScreen(e.GetPosition()); + if (mouse_pos.x > close_left && mouse_pos.y > close_top && mouse_pos.x < close_right && mouse_pos.y < close_bottom) { Dismiss(); } + }); +} + +void uiAmsPercentHumidityDryPopup::Update(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature) +{ + if (m_humidity_level != humidiy_level || m_humidity_percent != humidity_percent || + m_left_dry_time != left_dry_time || m_current_temperature != current_temperature) + { + m_humidity_level = humidiy_level; + m_humidity_percent = humidity_percent; + m_left_dry_time = left_dry_time; + m_current_temperature = current_temperature; + + Refresh(); + } +} + +void uiAmsPercentHumidityDryPopup::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void uiAmsPercentHumidityDryPopup::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void uiAmsPercentHumidityDryPopup::doRender(wxDC &dc) +{ + // background + { + dc.SetPen(StateColor::darkModeColorFor(*wxWHITE)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 0); + } + + wxPoint p; + + // Header + { + dc.SetFont(::Label::Head_24); + dc.SetTextForeground(StateColor::darkModeColorFor(*wxBLACK)); + //WxFontUtils::get_suitable_font_size(FromDIP(24), dc); + + auto extent = dc.GetTextExtent(_L("Current AMS humidity")); + dc.DrawText(_L("Current AMS humidity"), (GetSize().GetWidth() - extent.GetWidth()) / 2, FromDIP(24)); + } + + // close icon + p.y += FromDIP(24); + dc.DrawBitmap(close_img.bmp(), GetSize().x - close_img.GetBmpWidth() - FromDIP(38), p.y); + + // humitidy image + if (0 < m_humidity_level && m_humidity_level < 6) + { + ScalableBitmap humitidy_image; + if (wxGetApp().dark_mode()) + { + humitidy_image = ScalableBitmap(this, "hum_level" + std::to_string(m_humidity_level) + "_no_num_light", 64); + } + else + { + humitidy_image = ScalableBitmap(this, "hum_level" + std::to_string(m_humidity_level) + "_no_num_light", 64); + } + + p.y += 2 * FromDIP(24); + dc.DrawBitmap(humitidy_image.bmp(), (GetSize().GetWidth() - humitidy_image.GetBmpWidth()) / 2, p.y); + p.y += humitidy_image.GetBmpHeight(); + } + + // dry state + int spacing = FromDIP(5); + { + p.y += spacing; + if (m_left_dry_time > 0) + { + dc.DrawBitmap(drying_img.bmp(), GetSize().GetWidth() / 2 - drying_img.GetBmpWidth() - spacing, p.y); + } + else + { + dc.DrawBitmap(idle_img.bmp(), GetSize().GetWidth() / 2 - idle_img.GetBmpWidth() - spacing, p.y); + } + + dc.SetFont(::Label::Body_14); + //WxFontUtils::get_suitable_font_size(idle_img.GetBmpHeight(), dc); + + const wxString &dry_state = (m_left_dry_time > 0) ? _L("Drying") : _L("Idle"); + auto dry_state_extent = dc.GetTextExtent(dry_state); + + p.y += (idle_img.GetBmpHeight() - dry_state_extent.GetHeight());//align bottom + dc.DrawText(dry_state, GetSize().GetWidth() / 2 + spacing, p.y); + p.y += dry_state_extent.GetHeight(); + } + + // Grid area + { + p.y += 2 * spacing; + DrawGridArea(dc, p); + } +} + + +static vector grid_header{ L("Humidity"), L("Temperature"), L("Left Time")}; +void uiAmsPercentHumidityDryPopup::DrawGridArea(wxDC &dc, wxPoint start_p) +{ + const wxColour& gray_clr = StateColor::darkModeColorFor(wxColour(194, 194, 194)); + const wxColour& black_clr = StateColor::darkModeColorFor(*wxBLACK); + + // Horizontal line + dc.SetPen(gray_clr); + int h_margin = FromDIP(20); + dc.DrawLine(h_margin, start_p.y, GetSize().GetWidth() - h_margin, start_p.y); + start_p.x = h_margin; + start_p.y += h_margin; + + // Draw grid area + int toltal_col; + if (m_left_dry_time > 0) + { + toltal_col = 3; + } + else + { + toltal_col = 2; + } + + int row_height = FromDIP(30); + int text_height = FromDIP(20); + int distance = (GetSize().GetWidth() - 2 * h_margin)/ toltal_col; + for (int col = 0; col < toltal_col; ++col) + { + const wxString& header = _L(grid_header[col]); + dc.SetFont(::Label::Body_14); + //WxFontUtils::get_suitable_font_size(text_height, dc); + const auto &header_extent = dc.GetTextExtent(header); + + int left = start_p.x + (distance - header_extent.GetWidth()) / 2; + dc.SetPen(gray_clr); + dc.DrawText(header, left, start_p.y); + + // row content + dc.SetPen(black_clr); + if (header == _L("Humidity")) + { + const wxString &humidity_str = wxString::Format("%d%%", m_humidity_percent); + dc.DrawText(humidity_str, left, start_p.y + row_height); + } + else if (header == _L("Temperature")) + { + const wxString &temp_str = wxString::Format(_L("%.1f \u2103"), m_current_temperature); + dc.DrawText(temp_str, left, start_p.y + row_height); + } + else if (header == _L("Left Time")) + { + const wxString &time_str = wxString::Format(_L("%d Hours"), m_left_dry_time); + dc.DrawText(time_str, left, start_p.y + row_height); + } + + start_p.x += distance; + if (col < toltal_col - 1) /*draw splitter*/ + { + dc.SetPen(gray_clr); + dc.DrawLine(start_p.x, start_p.y, start_p.x, start_p.y + 2 * row_height); + } + } +} + +void uiAmsPercentHumidityDryPopup::msw_rescale() +{ + idle_img.msw_rescale(); + drying_img.msw_rescale(); + close_img.msw_rescale(); + + Refresh(); +} + +} // namespace GUI + +} // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h new file mode 100644 index 00000000000..e3a092e9ccf --- /dev/null +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h @@ -0,0 +1,70 @@ +//**********************************************************/ +/* File: uiAmsHumidityPopup.h +* Description: The popup with Ams Humidity +* +* \n class uiAmsHumidityPopup +//**********************************************************/ + +#pragma once +#include "slic3r/GUI/Widgets/Label.hpp" +#include "slic3r/GUI/Widgets/PopupWindow.hpp" + +#include "slic3r/GUI/wxExtensions.hpp" + +//Previous defintions +class wxGrid; + +namespace Slic3r { namespace GUI { + +struct uiAmsHumidityInfo +{ + int humidity_level = -1; + int humidity_percent = -1; + float current_temperature; + int left_dry_time = -1; +}; + +/// +/// Note: The popup of Ams Humidity with percentage and dry time +/// Author: xin.zhang +/// +class uiAmsPercentHumidityDryPopup : public PopupWindow +{ +public: + uiAmsPercentHumidityDryPopup(wxWindow *parent); + ~uiAmsPercentHumidityDryPopup() = default; + +public: + void Update(uiAmsHumidityInfo *info) { Update(info->humidity_level, info->humidity_percent, info->left_dry_time, info->current_temperature); }; + + virtual void OnDismiss() wxOVERRIDE {}; + virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE { return true;}; + + void msw_rescale(); + +private: + void Update(int humidiy_level, int humidity_percent, int left_dry_time, float current_temperature); + + void paintEvent(wxPaintEvent &evt); + void render(wxDC &dc); + void doRender(wxDC &dc); + + void DrawGridArea(wxDC &dc, wxPoint start_p); + +private: + int m_humidity_level = 0; + int m_humidity_percent = 0; + int m_left_dry_time = 0; + float m_current_temperature = 0; + + // Bitmap + ScalableBitmap close_img; + ScalableBitmap drying_img; + ScalableBitmap idle_img; + + // Widgets + wxStaticBitmap* m_humidity_img; + wxGrid* m_grid_area; +}; + +}} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index ef2d2d379e4..6bd8665b49b 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -4,6 +4,8 @@ #include "../I18N.hpp" #include "../GUI_App.hpp" +#include "slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h" + #include #include @@ -21,6 +23,7 @@ Description:AMSControl AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) : wxSimplebook(parent, wxID_ANY, pos, size) , m_Humidity_tip_popup(AmsHumidityTipPopup(this)) + , m_percent_humidity_dry_popup(new uiAmsPercentHumidityDryPopup(this)) , m_ams_introduce_popup(AmsIntroducePopup(this)) { SetBackgroundColour(*wxWHITE); @@ -557,19 +560,31 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons }); Bind(EVT_AMS_SHOW_HUMIDITY_TIPS, [this](wxCommandEvent& evt) { - - wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); - wxPoint popup_pos(img_pos.x - m_Humidity_tip_popup.GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); - m_Humidity_tip_popup.Position(popup_pos, wxSize(0, 0)); - if (m_ams_info.size() > 0) { - for (auto i = 0; i < m_ams_info.size(); i++) { - if (m_ams_info[i].ams_id == m_current_show_ams) { - m_Humidity_tip_popup.set_humidity_level(m_ams_info[i].ams_humidity); - } + uiAmsHumidityInfo *info = (uiAmsHumidityInfo *) evt.GetClientData(); + if (info) + { + if (info->humidity_percent >= 0) + { + m_percent_humidity_dry_popup->Update(info); + + wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); + wxPoint popup_pos(img_pos.x - m_percent_humidity_dry_popup->GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); + m_percent_humidity_dry_popup->Position(popup_pos, wxSize(0, 0)); + m_percent_humidity_dry_popup->Popup(); + } + else + { + wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); + wxPoint popup_pos(img_pos.x - m_Humidity_tip_popup.GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); + m_Humidity_tip_popup.Position(popup_pos, wxSize(0, 0)); + + int humidity_value = info->humidity_level; + if (humidity_value > 0 && humidity_value <= 5) { m_Humidity_tip_popup.set_humidity_level(humidity_value); } + m_Humidity_tip_popup.Popup(); } - } - m_Humidity_tip_popup.Popup(); + + delete info; }); @@ -788,6 +803,10 @@ void AMSControl::msw_rescale() cans->amsCans->msw_rescale(); } + if (m_percent_humidity_dry_popup){ + m_percent_humidity_dry_popup->msw_rescale(); + } + Layout(); Refresh(); } diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 2063e0eb309..b82d1899358 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -17,6 +17,9 @@ namespace Slic3r { namespace GUI { +//Previous definitions +class uiAmsPercentHumidityDryPopup; + class AMSControl : public wxSimplebook { public: @@ -94,6 +97,7 @@ class AMSControl : public wxSimplebook wxHyperlinkCtrl *m_hyperlink = {nullptr}; AmsHumidityTipPopup m_Humidity_tip_popup; + uiAmsPercentHumidityDryPopup* m_percent_humidity_dry_popup; std::string m_last_ams_id; std::string m_last_tray_id; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 2f6f7b52a61..5ac0a065e7a 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -5,6 +5,8 @@ #include "../GUI_App.hpp" #include "../Utils/WxFontUtils.hpp" +#include "slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h" + #include #include @@ -50,6 +52,7 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo this->humidity_raw = ams->humidity_raw; this->left_dray_time = ams->left_dry_time; + this->current_temperature = ams->current_temperature; this->ams_type = AMSModel(ams->type); cans.clear(); @@ -2198,13 +2201,12 @@ AMSHumidity::AMSHumidity(wxWindow* parent, wxWindowID id, AMSinfo info, const wx mouse_pos.y > rect.y) { wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); - //uiAmsHumidityInfo *info = new uiAmsHumidityInfo; - //info->ams_id = m_amsinfo.ams_id; - //info->humidity_level = m_amsinfo.ams_humidity; - //info->humidity_percent = m_amsinfo.humidity_raw; - //info->left_dry_time = m_amsinfo.left_dray_time; - //info->current_temperature = m_amsinfo.current_temperature; - //show_event.SetClientData(info); + uiAmsHumidityInfo *info = new uiAmsHumidityInfo; + info->humidity_level = m_amsinfo.ams_humidity; + info->humidity_percent = m_amsinfo.humidity_raw; + info->left_dry_time = m_amsinfo.left_dray_time; + info->current_temperature = m_amsinfo.current_temperature; + show_event.SetClientData(info); wxPostEvent(GetParent()->GetParent(), show_event); #ifdef __WXMSW__ diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index f6d69adc264..3aabf60321b 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -186,6 +186,7 @@ struct AMSinfo int ams_humidity = 0; int humidity_raw = -1; int left_dray_time = 0; + float current_temperature = INVALID_AMS_TEMPERATURE; AMSModel ams_type = AMSModel::GENERIC_AMS; public: @@ -199,6 +200,7 @@ struct AMSinfo curreent_filamentstep == other.curreent_filamentstep && ams_humidity == other.ams_humidity && left_dray_time == other.left_dray_time && + current_temperature == other.current_temperature && ams_type == other.ams_type) { return true; From 502cee88ee15389789694c6f21cc5a409e1b5186 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Mon, 24 Feb 2025 14:07:30 +0800 Subject: [PATCH 080/127] FIX: fix the bg painting jira: [none] Change-Id: Id3183ceb93850992cff9834d0141874e33594d35 (cherry picked from commit 0d480b3f6e4e71baae7787802b30c0d572e1ba9d) --- src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp index ae4ee4739ca..b31680802a4 100644 --- a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp @@ -88,10 +88,10 @@ void uiAmsPercentHumidityDryPopup::doRender(wxDC &dc) { // background { - dc.SetPen(StateColor::darkModeColorFor(*wxWHITE)); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 0); + dc.SetBrush(StateColor::darkModeColorFor(*wxWHITE)); + dc.DrawRoundedRectangle(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), 0); } + dc.SetBrush(*wxTRANSPARENT_BRUSH); wxPoint p; From 87c0719b32907ffa61df786711dae29ae3fb2a3e Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Thu, 27 Feb 2025 16:37:01 +0800 Subject: [PATCH 081/127] FIX: update the time shown; keep the val update while popup jira: [STUDIO-9268] Change-Id: I0b743ddb0ae479f9baad6239f68861a199681cda (cherry picked from commit e1bc737d1cbc1dcf79ceecf9ed301a4a02590d5a) --- .../GUI/DeviceTab/uiAmsHumidityPopup.cpp | 2 +- src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h | 8 +++++++- src/slic3r/GUI/Widgets/AMSControl.cpp | 20 +++++++++++++++++++ src/slic3r/GUI/Widgets/AMSItem.cpp | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp index b31680802a4..a28733f9487 100644 --- a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.cpp @@ -211,7 +211,7 @@ void uiAmsPercentHumidityDryPopup::DrawGridArea(wxDC &dc, wxPoint start_p) } else if (header == _L("Left Time")) { - const wxString &time_str = wxString::Format(_L("%d Hours"), m_left_dry_time); + const wxString &time_str = wxString::Format(_L("%d : %d"), m_left_dry_time / 60, m_left_dry_time % 60); dc.DrawText(time_str, left, start_p.y + row_height); } diff --git a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h index e3a092e9ccf..99237c0eda7 100644 --- a/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h +++ b/src/slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h @@ -18,6 +18,7 @@ namespace Slic3r { namespace GUI { struct uiAmsHumidityInfo { + std::string ams_id; int humidity_level = -1; int humidity_percent = -1; float current_temperature; @@ -35,7 +36,9 @@ class uiAmsPercentHumidityDryPopup : public PopupWindow ~uiAmsPercentHumidityDryPopup() = default; public: - void Update(uiAmsHumidityInfo *info) { Update(info->humidity_level, info->humidity_percent, info->left_dry_time, info->current_temperature); }; + void Update(uiAmsHumidityInfo *info) { m_ams_id = info->ams_id; Update(info->humidity_level, info->humidity_percent, info->left_dry_time, info->current_temperature); }; + + std::string get_owner_ams_id() const { return m_ams_id; } virtual void OnDismiss() wxOVERRIDE {}; virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE { return true;}; @@ -52,6 +55,9 @@ class uiAmsPercentHumidityDryPopup : public PopupWindow void DrawGridArea(wxDC &dc, wxPoint start_p); private: + /*owner ams id*/ + std::string m_ams_id; + int m_humidity_level = 0; int m_humidity_percent = 0; int m_left_dry_time = 0; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 6bd8665b49b..1c6eafe2820 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -1066,6 +1066,26 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) if (m_ams_model == AMSModel::EXT_AMS && !m_vams_lib->is_selected()) { m_vams_lib->OnSelected(); } + + /*update humidity popup*/ + if (m_percent_humidity_dry_popup->IsShown()) + { + string target_id = m_percent_humidity_dry_popup->get_owner_ams_id(); + for (const auto& the_info : info) + { + if (target_id == the_info.ams_id) + { + uiAmsHumidityInfo humidity_info; + humidity_info.ams_id = the_info.ams_id; + humidity_info.humidity_level = the_info.ams_humidity; + humidity_info.humidity_percent = the_info.humidity_raw; + humidity_info.left_dry_time = the_info.left_dray_time; + humidity_info.current_temperature = the_info.current_temperature; + m_percent_humidity_dry_popup->Update(&humidity_info); + break; + } + } + } } void AMSControl::AddAmsItems(AMSinfo info) diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 5ac0a065e7a..f9c088896e9 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -2202,6 +2202,7 @@ AMSHumidity::AMSHumidity(wxWindow* parent, wxWindowID id, AMSinfo info, const wx wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); uiAmsHumidityInfo *info = new uiAmsHumidityInfo; + info->ams_id = m_amsinfo.ams_id; info->humidity_level = m_amsinfo.ams_humidity; info->humidity_percent = m_amsinfo.humidity_raw; info->left_dry_time = m_amsinfo.left_dray_time; From 9c8736f416702f41a12a566de3a439c13c5d140e Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Mon, 6 Jan 2025 17:45:52 +0800 Subject: [PATCH 082/127] FIX: fix the json assert jira: none Change-Id: I0d17ef2e8474e84397c92ecd7868c6313bb8c9f7 (cherry picked from commit ec2412ddec0fd9d21a004f231154bec28d3107f8) --- src/slic3r/GUI/DeviceManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 7206e98feed..cbe7b2836f8 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -2974,7 +2974,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) for (auto it = j_module.begin(); it != j_module.end(); it++) { ModuleVersionInfo ver_info; ver_info.name = (*it)["name"].get(); - ver_info.product_name = wxString::FromUTF8((*it).value("product_name", json()).get()); + if ((*it).contains("product_name")) + ver_info.product_name = wxString::FromUTF8((*it)["product_name"].get()); if ((*it).contains("sw_ver")) ver_info.sw_ver = (*it)["sw_ver"].get(); if ((*it).contains("sn")) From d654408bedcf09c5f4c16eea41c934ba7a50c918 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 21 May 2025 10:18:33 +0800 Subject: [PATCH 083/127] Rename `AMSItem` to `AMSPreview` --- .../GUI/CalibrationWizardPresetPage.cpp | 19 +- .../GUI/CalibrationWizardPresetPage.hpp | 4 +- src/slic3r/GUI/Widgets/AMSControl.cpp | 121 +++--- src/slic3r/GUI/Widgets/AMSControl.hpp | 12 +- src/slic3r/GUI/Widgets/AMSItem.cpp | 373 +++++++++--------- src/slic3r/GUI/Widgets/AMSItem.hpp | 89 ++--- 6 files changed, 299 insertions(+), 319 deletions(-) diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index 790060019b7..207ba657d88 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -614,12 +614,12 @@ void CalibrationPresetPage::create_filament_list_panel(wxWindow* parent) auto ams_items_sizer = new wxBoxSizer(wxHORIZONTAL); for (int i = 0; i < 4; i++) { AMSinfo temp_info = AMSinfo{ std::to_string(i), std::vector{} }; - auto amsitem = new AMSItem(m_multi_ams_panel, wxID_ANY, temp_info); + auto amsitem = new AMSPreview(m_multi_ams_panel, wxID_ANY, temp_info); amsitem->Bind(wxEVT_LEFT_DOWN, [this, amsitem](wxMouseEvent& e) { - on_switch_ams(amsitem->m_amsinfo.ams_id); + on_switch_ams(amsitem->get_ams_id()); e.Skip(); }); - m_ams_item_list.push_back(amsitem); + m_ams_preview_list.push_back(amsitem); ams_items_sizer->Add(amsitem, 0, wxALIGN_CENTER | wxRIGHT, FromDIP(6)); } multi_ams_sizer->Add(ams_items_sizer, 0); @@ -896,12 +896,11 @@ void CalibrationPresetPage::on_select_tray(wxCommandEvent& event) void CalibrationPresetPage::on_switch_ams(std::string ams_id) { - for (auto i = 0; i < m_ams_item_list.size(); i++) { - AMSItem* item = m_ams_item_list[i]; - if (item->m_amsinfo.ams_id == ams_id) { + for (auto i = 0; i < m_ams_preview_list.size(); i++) { + AMSPreview *item = m_ams_preview_list[i]; + if (item->get_ams_id() == ams_id) { item->OnSelected(); - } - else { + } else { item->UnSelected(); } } @@ -1616,8 +1615,8 @@ void CalibrationPresetPage::sync_ams_info(MachineObject* obj) } } - for (auto i = 0; i < m_ams_item_list.size(); i++) { - AMSItem* item = m_ams_item_list[i]; + for (auto i = 0; i < m_ams_preview_list.size(); i++) { + AMSPreview* item = m_ams_preview_list[i]; if (ams_info.size() > 1) { if (i < ams_info.size()) { item->Update(ams_info[i]); diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.hpp b/src/slic3r/GUI/CalibrationWizardPresetPage.hpp index 4adcd858f3a..176006994c1 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.hpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.hpp @@ -284,8 +284,8 @@ class CalibrationPresetPage : public CalibrationWizardPage FilamentComboBoxList m_filament_comboBox_list; FilamentComboBox* m_virtual_tray_comboBox; - - std::vector m_ams_item_list; + + std::vector m_ams_preview_list; // for update filament combobox, key : tray_id std::map filament_ams_list; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 1c6eafe2820..b3b82845443 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -19,7 +19,6 @@ namespace Slic3r { namespace GUI { /************************************************* Description:AMSControl **************************************************/ -// WX_DEFINE_OBJARRAY(AmsItemsHash); AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) : wxSimplebook(parent, wxID_ANY, pos, size) , m_Humidity_tip_popup(AmsHumidityTipPopup(this)) @@ -34,28 +33,28 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_amswin->SetBackgroundColour(*wxWHITE); // top - ams tag - m_simplebook_amsitems = new wxSimplebook(m_amswin, wxID_ANY); - m_simplebook_amsitems->SetSize(wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); - m_simplebook_amsitems->SetMinSize(wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); - auto m_sizer_amsitems = new wxBoxSizer(wxHORIZONTAL); - m_simplebook_amsitems->SetSizer(m_sizer_amsitems); - m_simplebook_amsitems->Layout(); - m_sizer_amsitems->Fit(m_simplebook_amsitems); + m_simplebook_amsprvs = new wxSimplebook(m_amswin, wxID_ANY); + m_simplebook_amsprvs->SetSize(wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); + m_simplebook_amsprvs->SetMinSize(wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); + auto m_sizer_amspreviews = new wxBoxSizer(wxHORIZONTAL); + m_simplebook_amsprvs->SetSizer(m_sizer_amspreviews); + m_simplebook_amsprvs->Layout(); + m_sizer_amspreviews->Fit(m_simplebook_amsprvs); - m_panel_top = new wxPanel(m_simplebook_amsitems, wxID_ANY, wxDefaultPosition, wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); - m_sizer_top = new wxBoxSizer(wxHORIZONTAL); - m_panel_top->SetSizer(m_sizer_top); - m_panel_top->Layout(); - m_sizer_top->Fit(m_panel_top); + m_panel_prv = new wxPanel(m_simplebook_amsprvs, wxID_ANY, wxDefaultPosition, wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); + m_sizer_prv = new wxBoxSizer(wxHORIZONTAL); + m_panel_prv->SetSizer(m_sizer_prv); + m_panel_prv->Layout(); + m_sizer_prv->Fit(m_panel_prv); - auto m_panel_top_empty = new wxPanel(m_simplebook_amsitems, wxID_ANY, wxDefaultPosition, wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); + auto m_panel_top_empty = new wxPanel(m_simplebook_amsprvs, wxID_ANY, wxDefaultPosition, wxSize(-1, AMS_CAN_ITEM_HEIGHT_SIZE)); auto m_sizer_top_empty = new wxBoxSizer(wxHORIZONTAL); m_panel_top_empty->SetSizer(m_sizer_top_empty); m_panel_top_empty->Layout(); m_sizer_top_empty->Fit(m_panel_top_empty); - m_simplebook_amsitems->AddPage(m_panel_top_empty, wxEmptyString, false); - m_simplebook_amsitems->AddPage(m_panel_top, wxEmptyString, false); + m_simplebook_amsprvs->AddPage(m_panel_top_empty, wxEmptyString, false); + m_simplebook_amsprvs->AddPage(m_panel_prv, wxEmptyString, false); wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL); @@ -456,7 +455,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_sizer_bottom->Add(0, 0, 0, wxLEFT, FromDIP(15)); m_sizer_bottom->Add(m_sizer_right, 0, wxEXPAND, FromDIP(0)); - m_sizer_body->Add(m_simplebook_amsitems, 0, wxEXPAND, 0); + m_sizer_body->Add(m_simplebook_amsprvs, 0, wxEXPAND, 0); m_sizer_body->Add(0, 0, 1, wxEXPAND | wxTOP, FromDIP(18)); m_sizer_body->Add(m_sizer_bottom, 0, wxEXPAND | wxLEFT, FromDIP(6)); @@ -657,9 +656,9 @@ void AMSControl::EnterNoneAMSMode() { m_vams_lib->m_ams_model = m_ext_model; if(m_is_none_ams_mode == AMSModel::EXT_AMS) return; - m_panel_top->Hide(); - m_simplebook_amsitems->Hide(); - m_simplebook_amsitems->SetSelection(0); + m_panel_prv->Hide(); + m_simplebook_amsprvs->Hide(); + m_simplebook_amsprvs->SetSelection(0); m_simplebook_ams->SetSelection(0); m_extruder->no_ams_mode(true); @@ -679,9 +678,9 @@ void AMSControl::EnterGenericAMSMode() { m_vams_lib->m_ams_model = m_ext_model; if(m_is_none_ams_mode == AMSModel::GENERIC_AMS) return; - m_panel_top->Show(); - m_simplebook_amsitems->Show(); - m_simplebook_amsitems->SetSelection(1); + m_panel_prv->Show(); + m_simplebook_amsprvs->Show(); + m_simplebook_amsprvs->SetSelection(1); m_vams_lib->m_ams_model = AMSModel::GENERIC_AMS; m_ams_tip->SetLabel(_L("AMS")); @@ -708,9 +707,9 @@ void AMSControl::EnterExtraAMSMode() { m_vams_lib->m_ams_model = m_ext_model; if(m_is_none_ams_mode == AMSModel::AMS_LITE) return; - m_panel_top->Hide(); - m_simplebook_amsitems->Show(); - m_simplebook_amsitems->SetSelection(1); + m_panel_prv->Hide(); + m_simplebook_amsprvs->Show(); + m_simplebook_amsprvs->SetSelection(1); m_vams_lib->m_ams_model = AMSModel::AMS_LITE; @@ -891,13 +890,13 @@ void AMSControl::CreateAms() std::vector::iterator it; Freeze(); for (it = ams_info.begin(); it != ams_info.end(); it++) { - AddAmsItems(*it); + AddAmsPreview(*it); AddAms(*it); AddExtraAms(*it); m_ams_info.push_back(*it); } - m_sizer_top->Layout(); + m_sizer_prv->Layout(); Thaw(); } @@ -1021,27 +1020,29 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) } if (info.size() > 1) { - m_simplebook_amsitems->Show(); + m_simplebook_amsprvs->Show(); m_amswin->Layout(); m_amswin->Fit(); SetSize(m_amswin->GetSize()); SetMinSize(m_amswin->GetSize()); } else { - m_simplebook_amsitems->Hide(); + m_simplebook_amsprvs->Hide(); m_amswin->Layout(); m_amswin->Fit(); SetSize(m_amswin->GetSize()); SetMinSize(m_amswin->GetSize()); } - for (auto i = 0; i < m_ams_item_list.GetCount(); i++) { - AmsItems *item = m_ams_item_list[i]; + size_t i = 0; + for (auto prv_it : m_ams_preview_list) { + AMSPreview* prv = prv_it.second; if (i < info.size() && info.size() > 1) { - item->amsItem->Update(m_ams_info[i]); - item->amsItem->Open(); + prv->Update(m_ams_info[i]); + prv->Open(); } else { - item->amsItem->Close(); + prv->Close(); } + i++; } // update cans @@ -1088,20 +1089,16 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) } } -void AMSControl::AddAmsItems(AMSinfo info) +void AMSControl::AddAmsPreview(AMSinfo info) { - auto amsitem = new AMSItem(m_panel_top, wxID_ANY, info); - amsitem->Bind(wxEVT_LEFT_DOWN, [this, amsitem](wxMouseEvent& e) { - SwitchAms(amsitem->m_amsinfo.ams_id); + auto ams_prv = new AMSPreview(m_panel_prv, wxID_ANY, info); + m_sizer_prv->Add(ams_prv, 0, wxALIGN_CENTER | wxRIGHT, 6); + + ams_prv->Bind(wxEVT_LEFT_DOWN, [this, ams_prv](wxMouseEvent& e) { + SwitchAms(ams_prv->get_ams_id()); e.Skip(); }); - - AmsItems* item = new AmsItems(); - item->amsIndex = info.ams_id; - item->amsItem = amsitem; - - m_ams_item_list.Add(item); - m_sizer_top->Add(amsitem, 0, wxALIGN_CENTER | wxRIGHT, 6); + m_ams_preview_list[info.ams_id] = ams_prv; } void AMSControl::AddAms(AMSinfo info) @@ -1141,24 +1138,12 @@ void AMSControl::SwitchAms(std::string ams_id) } } - for (auto i = 0; i < m_ams_item_list.GetCount(); i++) { - AmsItems *item = m_ams_item_list[i]; - if (item->amsItem->m_amsinfo.ams_id == m_current_show_ams) { - item->amsItem->OnSelected(); + for (auto prv_it : m_ams_preview_list) { + AMSPreview* prv = prv_it.second; + if (prv->get_ams_id() == m_current_show_ams) { + prv->OnSelected(); m_current_select = ams_id; - //bool ready_selected = false; - //for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - // AmsCansWindow* ams = m_ams_cans_list[i]; - // if (ams->amsCans->m_info.ams_id == ams_id) { - // //ams->amsCans->SetDefSelectCan(); - // //m_vams_lib->OnSelected(); - // if () { - - // } - // } - //} - bool ready_selected = false; for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { AmsCansWindow* ams = m_ams_cans_list[i]; @@ -1181,10 +1166,10 @@ void AMSControl::SwitchAms(std::string ams_id) } } else { - item->amsItem->UnSelected(); + prv->UnSelected(); } - m_sizer_top->Layout(); - m_panel_top->Fit(); + m_sizer_prv->Layout(); + m_panel_prv->Fit(); } for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { @@ -1309,9 +1294,9 @@ void AMSControl::ShowFilamentTip(bool hasams) bool AMSControl::Enable(bool enable) { - for (auto i = 0; i < m_ams_item_list.GetCount(); i++) { - AmsItems *item = m_ams_item_list[i]; - item->amsItem->Enable(enable); + for (auto prv_it : m_ams_preview_list) { + AMSPreview* prv = prv_it.second; + prv->Enable(enable); } for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index b82d1899358..b5cc4e34abc 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -32,8 +32,8 @@ class AMSControl : public wxSimplebook std::string m_current_ams; std::string m_current_show_ams; std::map m_ams_selection; - - AmsItemsHash m_ams_item_list; + + std::map m_ams_preview_list; std::vector m_ams_info; AmsCansHash m_ams_cans_list; @@ -46,7 +46,7 @@ class AMSControl : public wxSimplebook wxSimplebook *m_simplebook_right = {nullptr}; wxSimplebook *m_simplebook_calibration = {nullptr}; - wxSimplebook *m_simplebook_amsitems = {nullptr}; + wxSimplebook *m_simplebook_amsprvs = {nullptr}; wxSimplebook *m_simplebook_ams = {nullptr}; wxSimplebook *m_simplebook_generic_cans= {nullptr}; @@ -58,7 +58,7 @@ class AMSControl : public wxSimplebook Label *m_tip_load_info = {nullptr}; wxStaticText *m_text_calibration_percent = {nullptr}; wxWindow * m_none_ams_panel = {nullptr}; - wxWindow * m_panel_top = {nullptr}; + wxWindow* m_panel_prv = {nullptr}; wxWindow * m_amswin = {nullptr}; wxBoxSizer* m_vams_sizer = {nullptr}; wxBoxSizer* m_sizer_vams_tips = {nullptr}; @@ -73,7 +73,7 @@ class AMSControl : public wxSimplebook AMSVirtualRoad* m_vams_extra_road = {nullptr}; StaticBox * m_panel_can = {nullptr}; - wxBoxSizer *m_sizer_top = {nullptr}; + wxBoxSizer* m_sizer_prv = {nullptr}; wxBoxSizer *m_sizer_cans = {nullptr}; wxBoxSizer *m_sizer_right_tip = {nullptr}; wxBoxSizer* m_sizer_ams_tips = {nullptr}; @@ -135,7 +135,7 @@ class AMSControl : public wxSimplebook void CreateAms(); void UpdateAms(std::vector info, bool is_reset = true); void AddAms(AMSinfo info); - void AddAmsItems(AMSinfo info); + void AddAmsPreview(AMSinfo info); void AddExtraAms(AMSinfo info); void SetExtruder(bool on_off, bool is_vams, std::string ams_now, wxColour col); void SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadType type, AMSPassRoadSTEP step); diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index f9c088896e9..dc5201d50bc 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -2171,6 +2171,193 @@ void AmsCans::show_sn_value(bool show) } } + +/************************************************* +Description:AMSPreview +**************************************************/ +AMSPreview::AMSPreview() {} + +AMSPreview::AMSPreview(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSPreview() +{ + m_amsinfo = amsinfo; + m_cube_size = cube_size; + create(parent, id, pos, AMS_ITEM_SIZE); + Bind(wxEVT_PAINT, &AMSPreview::paintEvent, this); + Bind(wxEVT_ENTER_WINDOW, &AMSPreview::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &AMSPreview::OnLeaveWindow, this); +} + +void AMSPreview::Open() +{ + m_open = true; + Show(); +} + +void AMSPreview::Close() +{ + m_open = false; + Hide(); +} + +void AMSPreview::Update(AMSinfo amsinfo) +{ + m_amsinfo = amsinfo; +} + +void AMSPreview::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +{ + m_ts_bitmap_cube = new ScalableBitmap(this, "ts_bitmap_cube", 14); + wxWindow::Create(parent, id, pos, size); + SetMinSize(AMS_ITEM_SIZE); + SetMaxSize(AMS_ITEM_SIZE); + SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + Refresh(); +} + +void AMSPreview::OnEnterWindow(wxMouseEvent &evt) +{ + // m_hover = true; + // Refresh(); +} + +void AMSPreview::OnLeaveWindow(wxMouseEvent &evt) +{ + // m_hover = false; + // Refresh(); +} + +void AMSPreview::OnSelected() +{ + if (!wxWindow::IsEnabled()) { return; } + m_selected = true; + Refresh(); +} + +void AMSPreview::UnSelected() +{ + m_selected = false; + Refresh(); +} + +bool AMSPreview::Enable(bool enable) { return wxWindow::Enable(enable); } + +void AMSPreview::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); +} + +void AMSPreview::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void AMSPreview::doRender(wxDC &dc) +{ + wxSize size = GetSize(); + dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(m_background_colour))); + dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); + + auto left = m_padding; + for (std::vector::iterator iter = m_amsinfo.cans.begin(); iter != m_amsinfo.cans.end(); iter++) { + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + + if (wxWindow::IsEnabled()) { + wxColour color = iter->material_colour; + change_the_opacity(color); + dc.SetBrush(wxBrush(color)); + } else { + dc.SetBrush(AMS_CONTROL_DISABLE_COLOUR); + } + + if (iter->material_cols.size() > 1) { + int fleft = left; + float total_width = AMS_ITEM_CUBE_SIZE.x; + int gwidth = std::round(total_width / (iter->material_cols.size() - 1)); + if (iter->ctype == 0) { + for (int i = 0; i < iter->material_cols.size() - 1; i++) { + + if ((fleft + gwidth) > (AMS_ITEM_CUBE_SIZE.x)) { + gwidth = (fleft + AMS_ITEM_CUBE_SIZE.x) - fleft; + } + + auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); + dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); + fleft += gwidth; + } + } else { + int cols_size = iter->material_cols.size(); + for (int i = 0; i < cols_size; i++) { + dc.SetBrush(wxBrush(iter->material_cols[i])); + float x = left + total_width * i / cols_size; + dc.DrawRoundedRectangle(x, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, total_width / cols_size, AMS_ITEM_CUBE_SIZE.y , 0); + } + } + + dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(left - 1, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2 - 1, AMS_ITEM_CUBE_SIZE.x + 2, AMS_ITEM_CUBE_SIZE.y + 2, 2); + + }else { + if (iter->material_colour.Alpha() == 0) { + dc.DrawBitmap(m_ts_bitmap_cube->bmp(),left,(size.y - AMS_ITEM_CUBE_SIZE.y) / 2); + } + else { + wxRect rect(left, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, AMS_ITEM_CUBE_SIZE.x, AMS_ITEM_CUBE_SIZE.y); + if(iter->material_state==AMSCanType::AMS_CAN_TYPE_EMPTY){ + dc.SetPen(wxPen(wxColor(0, 0, 0))); + dc.DrawRoundedRectangle(rect, 2); + + dc.DrawLine(rect.GetRight()-1, rect.GetTop()+1, rect.GetLeft()+1, rect.GetBottom()-1); + } + else { + dc.DrawRoundedRectangle(rect, 2); + } + } + + } + + + left += AMS_ITEM_CUBE_SIZE.x; + left += m_space; + } + + auto border_colour = AMS_CONTROL_BRAND_COLOUR; + if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } + + if (m_hover) { + dc.SetPen(wxPen(border_colour, 2)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); + + } + + if (m_selected) { + dc.SetPen(wxPen(border_colour, 2)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); + } +} + +void AMSPreview::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } + /************************************************* Description:AMSHumidity **************************************************/ @@ -2387,190 +2574,4 @@ void AMSHumidity::msw_rescale() { Refresh(); } -/************************************************* -Description:AMSItem -**************************************************/ -AMSItem::AMSItem() {} - -AMSItem::AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSItem() -{ - m_amsinfo = amsinfo; - m_cube_size = cube_size; - create(parent, id, pos, AMS_ITEM_SIZE); - Bind(wxEVT_PAINT, &AMSItem::paintEvent, this); - Bind(wxEVT_ENTER_WINDOW, &AMSItem::OnEnterWindow, this); - Bind(wxEVT_LEAVE_WINDOW, &AMSItem::OnLeaveWindow, this); -} - -void AMSItem::Open() -{ - m_open = true; - Show(); -} - -void AMSItem::Close() -{ - m_open = false; - Hide(); -} - -void AMSItem::Update(AMSinfo amsinfo) -{ - m_amsinfo = amsinfo; -} - -void AMSItem::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) -{ - m_ts_bitmap_cube = new ScalableBitmap(this, "ts_bitmap_cube", 14); - wxWindow::Create(parent, id, pos, size); - SetMinSize(AMS_ITEM_SIZE); - SetMaxSize(AMS_ITEM_SIZE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); - Refresh(); -} - -void AMSItem::OnEnterWindow(wxMouseEvent &evt) -{ - // m_hover = true; - // Refresh(); -} - -void AMSItem::OnLeaveWindow(wxMouseEvent &evt) -{ - // m_hover = false; - // Refresh(); -} - -void AMSItem::OnSelected() -{ - if (!wxWindow::IsEnabled()) { return; } - m_selected = true; - Refresh(); -} - -void AMSItem::UnSelected() -{ - m_selected = false; - Refresh(); -} - -bool AMSItem::Enable(bool enable) { return wxWindow::Enable(enable); } - -void AMSItem::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} - -void AMSItem::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void AMSItem::doRender(wxDC &dc) -{ - wxSize size = GetSize(); - dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); - dc.SetBrush(wxBrush(StateColor::darkModeColorFor(m_background_colour))); - dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); - - auto left = m_padding; - for (std::vector::iterator iter = m_amsinfo.cans.begin(); iter != m_amsinfo.cans.end(); iter++) { - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - - if (wxWindow::IsEnabled()) { - wxColour color = iter->material_colour; - change_the_opacity(color); - dc.SetBrush(wxBrush(color)); - } else { - dc.SetBrush(AMS_CONTROL_DISABLE_COLOUR); - } - - if (iter->material_cols.size() > 1) { - int fleft = left; - float total_width = AMS_ITEM_CUBE_SIZE.x; - int gwidth = std::round(total_width / (iter->material_cols.size() - 1)); - if (iter->ctype == 0) { - for (int i = 0; i < iter->material_cols.size() - 1; i++) { - - if ((fleft + gwidth) > (AMS_ITEM_CUBE_SIZE.x)) { - gwidth = (fleft + AMS_ITEM_CUBE_SIZE.x) - fleft; - } - - auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); - dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); - fleft += gwidth; - } - } else { - int cols_size = iter->material_cols.size(); - for (int i = 0; i < cols_size; i++) { - dc.SetBrush(wxBrush(iter->material_cols[i])); - float x = left + total_width * i / cols_size; - dc.DrawRoundedRectangle(x, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, total_width / cols_size, AMS_ITEM_CUBE_SIZE.y , 0); - } - } - - dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRoundedRectangle(left - 1, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2 - 1, AMS_ITEM_CUBE_SIZE.x + 2, AMS_ITEM_CUBE_SIZE.y + 2, 2); - - }else { - if (iter->material_colour.Alpha() == 0) { - dc.DrawBitmap(m_ts_bitmap_cube->bmp(),left,(size.y - AMS_ITEM_CUBE_SIZE.y) / 2); - } - else { - wxRect rect(left, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, AMS_ITEM_CUBE_SIZE.x, AMS_ITEM_CUBE_SIZE.y); - if(iter->material_state==AMSCanType::AMS_CAN_TYPE_EMPTY){ - dc.SetPen(wxPen(wxColor(0, 0, 0))); - dc.DrawRoundedRectangle(rect, 2); - - dc.DrawLine(rect.GetRight()-1, rect.GetTop()+1, rect.GetLeft()+1, rect.GetBottom()-1); - } - else { - dc.DrawRoundedRectangle(rect, 2); - } - } - - } - - - left += AMS_ITEM_CUBE_SIZE.x; - left += m_space; - } - - auto border_colour = AMS_CONTROL_BRAND_COLOUR; - if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } - - if (m_hover) { - dc.SetPen(wxPen(border_colour, 2)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); - - } - - if (m_selected) { - dc.SetPen(wxPen(border_colour, 2)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); - } -} - -void AMSItem::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } - }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 3aabf60321b..4efbf9ae487 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -465,6 +465,48 @@ class AMSRoad : public wxWindow void doRender(wxDC& dc); }; +/************************************************* +Description:AMSPreview +**************************************************/ +class AMSPreview : public wxWindow +{ +public: + AMSPreview(); + AMSPreview(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size = wxSize(14, 14), const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + + bool m_open = {false}; + void Open(); + void Close(); + + void Update(AMSinfo amsinfo); + void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); + void OnEnterWindow(wxMouseEvent &evt); + void OnLeaveWindow(wxMouseEvent &evt); + void OnSelected(); + void UnSelected(); + virtual bool Enable(bool enable = true); + + + std::string get_ams_id() const { return m_amsinfo.ams_id; }; + +protected: + AMSinfo m_amsinfo; + + wxSize m_cube_size; + wxColour m_background_colour = {AMS_CONTROL_DEF_LIB_BK_COLOUR}; + int m_padding = {7}; + int m_space = {5}; + bool m_hover = {false}; + bool m_selected = {false}; + ScalableBitmap* m_ts_bitmap_cube; + + void paintEvent(wxPaintEvent &evt); + void render(wxDC &dc); + void doRender(wxDC &dc); + virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); +}; + + /************************************************* Description:AMSHumidity **************************************************/ @@ -501,45 +543,6 @@ class AMSHumidity : public wxWindow void update_size(); }; -/************************************************* -Description:AMSItem -**************************************************/ - -class AMSItem : public wxWindow -{ -public: - AMSItem(); - AMSItem(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size = wxSize(14, 14), const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); - - bool m_open = {false}; - void Open(); - void Close(); - - void Update(AMSinfo amsinfo); - void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); - void OnEnterWindow(wxMouseEvent &evt); - void OnLeaveWindow(wxMouseEvent &evt); - void OnSelected(); - void UnSelected(); - virtual bool Enable(bool enable = true); - - AMSinfo m_amsinfo; - -protected: - wxSize m_cube_size; - wxColour m_background_colour = {AMS_CONTROL_DEF_LIB_BK_COLOUR}; - int m_padding = {7}; - int m_space = {5}; - bool m_hover = {false}; - bool m_selected = {false}; - ScalableBitmap* m_ts_bitmap_cube; - - void paintEvent(wxPaintEvent &evt); - void render(wxDC &dc); - void doRender(wxDC &dc); - virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); -}; - /************************************************* Description:AmsCans **************************************************/ @@ -638,13 +641,6 @@ class AmsCansWindow } }; -class AmsItems -{ -public: - wxString amsIndex; - AMSItem *amsItem; -}; - class AMSextruders { public: @@ -653,7 +649,6 @@ class AMSextruders }; WX_DEFINE_ARRAY(AmsCansWindow *, AmsCansHash); -WX_DEFINE_ARRAY(AmsItems *, AmsItemsHash); WX_DEFINE_ARRAY(AMSextruders *, AMSextrudersHash); From 3b3406a375274bb19b0188c96abbc4ad406d366c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 21 May 2025 13:58:08 +0800 Subject: [PATCH 084/127] Rename `AmsCans` to `AmsItem` --- src/slic3r/GUI/Widgets/AMSControl.cpp | 177 ++- src/slic3r/GUI/Widgets/AMSControl.hpp | 8 +- src/slic3r/GUI/Widgets/AMSItem.cpp | 1436 ++++++++++++------------- src/slic3r/GUI/Widgets/AMSItem.hpp | 109 +- 4 files changed, 838 insertions(+), 892 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index b3b82845443..cd3976cc118 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -268,19 +268,19 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_vams_lib->m_slot_id = m_vams_info.can_id; m_vams_road = new AMSRoad(vams_panel, wxID_ANY, m_vams_info, -1, -1, wxDefaultPosition, AMS_CAN_ROAD_SIZE); - m_vams_lib->Bind(wxEVT_LEFT_DOWN, [this](auto& e) { + m_vams_lib->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { //clear all selected m_current_ams = m_vams_info.can_id; m_vams_lib->OnSelected(); SwitchAms(m_current_ams); - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow* cans = m_ams_cans_list[i]; - cans->amsCans->SelectCan(m_current_ams); + for (auto ams_item : m_ams_item_list) { + AmsItem* item = ams_item.second; + item->SelectCan(m_current_ams); } e.Skip(); - }); + }); Bind(EVT_AMS_UNSELETED_VAMS, [this](wxCommandEvent& e) { /*if (m_current_ams == e.GetString().ToStdString()) { @@ -612,29 +612,36 @@ void AMSControl::init_scaled_buttons() m_button_extruder_back->SetCornerRadius(FromDIP(12)); } -std::string AMSControl::GetCurentAms() { return m_current_ams; } -std::string AMSControl::GetCurentShowAms() { return m_current_show_ams; } +std::string AMSControl::GetCurentAms() { + return m_current_ams; +} +std::string AMSControl::GetCurentShowAms() { + return m_current_show_ams; +} std::string AMSControl::GetCurrentCan(std::string amsid) { std::string current_can; - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *ams = m_ams_cans_list[i]; - if (ams->amsCans->m_info.ams_id == amsid) { - current_can = ams->amsCans->GetCurrentCan(); + for (auto ams_item : m_ams_item_list) { + AmsItem* item = ams_item.second; + if (item == nullptr){ + continue; + } + if (item->get_ams_id() == amsid) { + current_can = item->GetCurrentCan(); return current_can; } } return current_can; } -wxColour AMSControl::GetCanColour(std::string amsid, std::string canid) +wxColour AMSControl::GetCanColour(std::string amsid, std::string canid) { wxColour col = *wxWHITE; for (auto i = 0; i < m_ams_info.size(); i++) { - if (m_ams_info[i].ams_id == amsid) { + if (m_ams_info[i].ams_id == amsid) { for (auto o = 0; o < m_ams_info[i].cans.size(); o++) { - if (m_ams_info[i].cans[o].can_id == canid) { + if (m_ams_info[i].cans[o].can_id == canid) { col = m_ams_info[i].cans[o].material_colour; } } @@ -758,25 +765,21 @@ void AMSControl::SetClibrationLink(wxString link) void AMSControl::PlayRridLoading(wxString amsid, wxString canid) { - AmsCansHash::iterator iter = m_ams_cans_list.begin(); - auto count_item_index = 0; + auto iter = m_ams_item_list.find(amsid.ToStdString()); - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *cans = m_ams_cans_list[i]; - if (cans->amsCans->m_info.ams_id == amsid) { cans->amsCans->PlayRridLoading(canid); } - iter++; + if (iter != m_ams_item_list.end()) { + AmsItem* cans = iter->second; + cans->PlayRridLoading(canid); } } void AMSControl::StopRridLoading(wxString amsid, wxString canid) { - AmsCansHash::iterator iter = m_ams_cans_list.begin(); - auto count_item_index = 0; + auto iter = m_ams_item_list.find(amsid.ToStdString()); - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *cans = m_ams_cans_list[i]; - if (cans->amsCans->m_info.ams_id == amsid) { cans->amsCans->StopRridLoading(canid); } - iter++; + if (iter != m_ams_item_list.end()) { + AmsItem* cans = iter->second; + cans->StopRridLoading(canid); } } @@ -797,11 +800,13 @@ void AMSControl::msw_rescale() m_button_retry->SetMinSize(wxSize(-1, FromDIP(24))); m_vams_lib->msw_rescale(); - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *cans = m_ams_cans_list[i]; - cans->amsCans->msw_rescale(); + for (auto ams_item : m_ams_item_list) { + if (ams_item.second){ + ams_item.second->msw_rescale(); + } } + if (m_percent_humidity_dry_popup){ m_percent_humidity_dry_popup->msw_rescale(); } @@ -1013,10 +1018,10 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) // update item m_ams_info = info; if (m_ams_model == AMSModel::GENERIC_AMS){ - m_ams_cans_list = m_ams_generic_cans_list; + m_ams_item_list = m_ams_generic_item_list; } else if (m_ams_model == AMSModel::AMS_LITE) { - m_ams_cans_list = m_ams_extra_cans_list; + m_ams_item_list = m_ams_extra_item_list; } if (info.size() > 1) { @@ -1046,14 +1051,16 @@ void AMSControl::UpdateAms(std::vector info, bool is_reset) } // update cans - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *cans = m_ams_cans_list[i]; - + for (auto ams_item : m_ams_item_list) { + if (ams_item.second == nullptr) { + continue; + } + std::string ams_id = ams_item.second->get_ams_id(); + AmsItem* cans = ams_item.second; for (auto ifo : m_ams_info) { - if (ifo.ams_id == cans->amsIndex) { - cans->amsCans->m_info = ifo; - cans->amsCans->Update(ifo); - cans->amsCans->show_sn_value(m_ams_model == AMSModel::AMS_LITE?false:true); + if (ifo.ams_id == ams_id) { + cans->Update(ifo); + cans->show_sn_value(m_ams_model == AMSModel::AMS_LITE?false:true); } } } @@ -1103,28 +1110,20 @@ void AMSControl::AddAmsPreview(AMSinfo info) void AMSControl::AddAms(AMSinfo info) { - AmsCansWindow* canswin = new AmsCansWindow(); - auto amscans = new AmsCans(m_simplebook_generic_cans, info, AMSModel::GENERIC_AMS); + auto ams_item = new AmsItem(m_simplebook_generic_cans, info, AMSModel::GENERIC_AMS); + m_simplebook_generic_cans->AddPage(ams_item, wxEmptyString, false); + ams_item->set_selection(m_simplebook_generic_cans->GetPageCount() - 1); - canswin->amsIndex = info.ams_id; - canswin->amsCans = amscans; - m_ams_generic_cans_list.Add(canswin); - - m_simplebook_generic_cans->AddPage(amscans, wxEmptyString, false); - amscans->m_selection = m_simplebook_generic_cans->GetPageCount() - 1; + m_ams_generic_item_list[info.ams_id] = ams_item; } void AMSControl::AddExtraAms(AMSinfo info) { - AmsCansWindow* canswin = new AmsCansWindow(); - auto amscans = new AmsCans(m_simplebook_extra_cans, info, AMSModel::AMS_LITE); - - canswin->amsIndex = info.ams_id; - canswin->amsCans = amscans; - m_ams_extra_cans_list.Add(canswin); + auto ams_item = new AmsItem(m_simplebook_extra_cans, info, AMSModel::AMS_LITE); + m_simplebook_extra_cans->AddPage(ams_item, wxEmptyString, false); + ams_item->set_selection(m_simplebook_extra_cans->GetPageCount() - 1); - m_simplebook_extra_cans->AddPage(amscans, wxEmptyString, false); - amscans->m_selection = m_simplebook_extra_cans->GetPageCount() - 1; + m_ams_extra_item_list[info.ams_id] = ams_item; } void AMSControl::SwitchAms(std::string ams_id) @@ -1145,11 +1144,12 @@ void AMSControl::SwitchAms(std::string ams_id) m_current_select = ams_id; bool ready_selected = false; - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow* ams = m_ams_cans_list[i]; - if (ams->amsCans->m_info.ams_id == ams_id) { - for (auto lib : ams->amsCans->m_can_lib_list) { - if (lib->canLib->is_selected()) { + for (auto item_it : m_ams_item_list) { + AmsItem* item = item_it.second; + if (item->get_ams_id() == ams_id) { + for (auto lib_it : item->get_can_lib_list()) { + AMSLib* lib = lib_it.second; + if (lib->is_selected()) { ready_selected = true; } } @@ -1172,15 +1172,15 @@ void AMSControl::SwitchAms(std::string ams_id) m_panel_prv->Fit(); } - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *cans = m_ams_cans_list[i]; - if (cans->amsCans->m_info.ams_id == ams_id) { + for (auto ams_item : m_ams_item_list) { + AmsItem* item = ams_item.second; + if (item->get_ams_id() == ams_id) { if (m_ams_model == AMSModel::GENERIC_AMS) { - m_simplebook_generic_cans->SetSelection(cans->amsCans->m_selection); + m_simplebook_generic_cans->SetSelection(item->get_selection()); } else if (m_ams_model == AMSModel::AMS_LITE) { - m_simplebook_extra_cans->SetSelection(cans->amsCans->m_selection); + m_simplebook_extra_cans->SetSelection(item->get_selection()); } } } @@ -1286,7 +1286,7 @@ void AMSControl::ShowFilamentTip(bool hasams) m_tip_right_top->Hide(); m_tip_load_info->SetLabelText(wxEmptyString); } - + m_tip_load_info->SetMinSize(AMS_STEP_SIZE); m_tip_load_info->Wrap(AMS_STEP_SIZE.x - FromDIP(5)); m_sizer_right_tip->Layout(); @@ -1299,9 +1299,9 @@ bool AMSControl::Enable(bool enable) prv->Enable(enable); } - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - AmsCansWindow *cans = m_ams_cans_list[i]; - cans->amsCans->Enable(enable); + for (auto item_it : m_ams_item_list) { + AmsItem* item = item_it.second; + item->Enable(enable); } m_button_extruder_feed->Enable(enable); @@ -1370,17 +1370,8 @@ void AMSControl::SetExtruder(bool on_off, bool is_vams, std::string ams_now, wxC void AMSControl::SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadType type, AMSPassRoadSTEP step) { - AmsCansWindow *cans = nullptr; - bool notfound = true; - - for (auto i = 0; i < m_ams_cans_list.GetCount(); i++) { - cans = m_ams_cans_list[i]; - if (cans->amsCans->m_info.ams_id == ams_id) { - notfound = false; - break; - } - } - + AmsItem* ams = nullptr; + auto amsit = m_ams_item_list.find(ams_id); if (ams_id != m_last_ams_id || m_last_tray_id != canid) { SetAmsStep(m_last_ams_id, m_last_tray_id, AMSPassRoadType::AMS_ROAD_TYPE_UNLOAD, AMSPassRoadSTEP::AMS_ROAD_STEP_NONE); @@ -1389,9 +1380,9 @@ void AMSControl::SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadTy m_vams_road->OnVamsLoading(false); } - if (notfound) return; - if (cans == nullptr) return; - + if (amsit != m_ams_item_list.end()) {ams = amsit->second;} + else {return;} + if (ams == nullptr) return; m_last_ams_id = ams_id; m_last_tray_id = canid; @@ -1399,34 +1390,34 @@ void AMSControl::SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadTy if (m_ams_model == AMSModel::GENERIC_AMS) { if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_NONE); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_NONE); m_extruder->OnAmsLoading(false); } if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP1) { - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_1); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_1); m_extruder->OnAmsLoading(false); } if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP2) { - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_1); - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_2); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_1); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_2); if (m_current_show_ams == ams_id) { - m_extruder->OnAmsLoading(true, cans->amsCans->GetTagColr(canid)); + m_extruder->OnAmsLoading(true, ams->GetTagColr(canid)); } } if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP3) { - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_1); - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_2); - cans->amsCans->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_3); - m_extruder->OnAmsLoading(true, cans->amsCans->GetTagColr(canid)); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_1); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_2); + ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_3); + m_extruder->OnAmsLoading(true, ams->GetTagColr(canid)); } } else if (m_ams_model == AMSModel::AMS_LITE) { - cans->amsCans->SetAmsStepExtra(canid, type, step); + ams->SetAmsStepExtra(canid, type, step); if (step != AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { - m_extruder->OnAmsLoading(true, cans->amsCans->GetTagColr(canid)); + m_extruder->OnAmsLoading(true, ams->GetTagColr(canid)); } else { m_extruder->OnAmsLoading(false); diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index b5cc4e34abc..3cee1520e80 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -36,11 +36,11 @@ class AMSControl : public wxSimplebook std::map m_ams_preview_list; std::vector m_ams_info; - AmsCansHash m_ams_cans_list; - AmsCansHash m_ams_generic_cans_list; - AmsCansHash m_ams_extra_cans_list; + std::map m_ams_item_list; + std::map m_ams_generic_item_list; + std::map m_ams_extra_item_list; - AMSextruder *m_extruder = {nullptr}; + AMSextruder *m_extruder{nullptr}; AmsIntroducePopup m_ams_introduce_popup; diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index dc5201d50bc..9f232deec10 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -1620,384 +1620,282 @@ void AMSRoad::OnPassRoad(std::vector prord_list) /************************************************* -Description:AmsCan +Description:AMSPreview **************************************************/ +AMSPreview::AMSPreview() {} -AmsCans::AmsCans() {} +AMSPreview::AMSPreview(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSPreview() +{ + m_amsinfo = amsinfo; + m_cube_size = cube_size; + create(parent, id, pos, AMS_ITEM_SIZE); + Bind(wxEVT_PAINT, &AMSPreview::paintEvent, this); + Bind(wxEVT_ENTER_WINDOW, &AMSPreview::OnEnterWindow, this); + Bind(wxEVT_LEAVE_WINDOW, &AMSPreview::OnLeaveWindow, this); +} -AmsCans::AmsCans(wxWindow *parent,AMSinfo info, AMSModel model) : AmsCans() +void AMSPreview::Open() { - m_bitmap_extra_framework = ScalableBitmap(this, "ams_extra_framework_mid", 140); + m_open = true; + Show(); +} - SetDoubleBuffered(true); - m_ams_model = model; - m_info = info; +void AMSPreview::Close() +{ + m_open = false; + Hide(); +} - wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE); - create(parent); - Bind(wxEVT_PAINT, &AmsCans::paintEvent, this); +void AMSPreview::Update(AMSinfo amsinfo) +{ + m_amsinfo = amsinfo; } -void AmsCans::create(wxWindow *parent) +void AMSPreview::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { - Freeze(); - SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + m_ts_bitmap_cube = new ScalableBitmap(this, "ts_bitmap_cube", 14); + wxWindow::Create(parent, id, pos, size); + SetMinSize(AMS_ITEM_SIZE); + SetMaxSize(AMS_ITEM_SIZE); + SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + Refresh(); +} - if (m_ams_model == AMSModel::GENERIC_AMS || m_ams_model == AMSModel::N3F_AMS || m_ams_model == AMSModel::N3S_AMS) { - sizer_can = new wxBoxSizer(wxHORIZONTAL); - sizer_item = new wxBoxSizer(wxVERTICAL); - for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { - AddCan(*it, m_can_count, m_info.cans.size(), sizer_can); - m_can_count++; - } - m_humidity = new AMSHumidity(this, wxID_ANY, m_info); - sizer_item->Add(m_humidity, 0, wxALIGN_CENTER_HORIZONTAL, 0); - sizer_item->Add(sizer_can, 0, wxALIGN_CENTER_HORIZONTAL, 0); - SetSizer(sizer_item); - } - else if(m_ams_model == AMSModel::AMS_LITE) { - sizer_can = new wxBoxSizer(wxVERTICAL); - sizer_can_middle = new wxBoxSizer(wxHORIZONTAL); - sizer_can_left = new wxBoxSizer(wxVERTICAL); - sizer_can_right = new wxBoxSizer(wxVERTICAL); +void AMSPreview::OnEnterWindow(wxMouseEvent &evt) +{ + // m_hover = true; + // Refresh(); +} - sizer_can_left->Add(0,0,0,wxTOP,FromDIP(8)); +void AMSPreview::OnLeaveWindow(wxMouseEvent &evt) +{ + // m_hover = false; + // Refresh(); +} - for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { - if (m_can_count <= 1) { - AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_left); - if (m_can_count == 0) { - sizer_can_left->Add(0,0,0,wxTOP,FromDIP(20)); - } - } - else { - AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_right); - if (m_can_count == 2) { - sizer_can_right->Prepend(0, 0, 0, wxTOP, FromDIP(20)); - } - } +void AMSPreview::OnSelected() +{ + if (!wxWindow::IsEnabled()) { return; } + m_selected = true; + Refresh(); +} - m_can_count++; - } +void AMSPreview::UnSelected() +{ + m_selected = false; + Refresh(); +} - sizer_can_right->Prepend(0,0,0,wxTOP,FromDIP(8)); - sizer_can_middle->Add(0, 0, 0, wxLEFT, FromDIP(8)); - sizer_can_middle->Add(sizer_can_left, 0, wxALL, 0); - sizer_can_middle->Add( 0, 0, 0, wxLEFT, FromDIP(20) ); - sizer_can_middle->Add(sizer_can_right, 0, wxALL, 0); - sizer_can->Add(sizer_can_middle, 1, wxALIGN_CENTER, 0); - SetSizer(sizer_can); - } +bool AMSPreview::Enable(bool enable) { return wxWindow::Enable(enable); } - Layout(); - Fit(); - Thaw(); +void AMSPreview::paintEvent(wxPaintEvent &evt) +{ + wxPaintDC dc(this); + render(dc); } -void AmsCans::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer) +void AMSPreview::render(wxDC &dc) { +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); - auto amscan = new wxWindow(this, wxID_ANY); - amscan->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + { + wxGCDC dc2(memdc); + doRender(dc2); + } - wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); - + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} - auto m_panel_refresh = new AMSrefresh(amscan, m_can_count, caninfo); - auto m_panel_lib = new AMSLib(amscan, m_info.ams_id, caninfo); +void AMSPreview::doRender(wxDC &dc) +{ + wxSize size = GetSize(); + dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(m_background_colour))); + dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); - m_panel_lib->Bind(wxEVT_LEFT_DOWN, [this, canindex](wxMouseEvent& ev) { - m_canlib_selection = canindex; - // m_canlib_id = caninfo.can_id; + auto left = m_padding; + for (std::vector::iterator iter = m_amsinfo.cans.begin(); iter != m_amsinfo.cans.end(); iter++) { + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - if (lib->canLib->m_can_index == m_canlib_selection) { - wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); - evt.SetString(m_info.ams_id); - wxPostEvent(GetParent()->GetParent(), evt); - lib->canLib->OnSelected(); - } - else { - lib->canLib->UnSelected(); - } + if (wxWindow::IsEnabled()) { + wxColour color = iter->material_colour; + change_the_opacity(color); + dc.SetBrush(wxBrush(color)); + } else { + dc.SetBrush(AMS_CONTROL_DISABLE_COLOUR); } - ev.Skip(); - }); + if (iter->material_cols.size() > 1) { + int fleft = left; + float total_width = AMS_ITEM_CUBE_SIZE.x; + int gwidth = std::round(total_width / (iter->material_cols.size() - 1)); + if (iter->ctype == 0) { + for (int i = 0; i < iter->material_cols.size() - 1; i++) { - m_panel_lib->m_ams_model = m_ams_model; - m_panel_lib->m_ams_id = m_info.ams_id; - m_panel_lib->m_slot_id = caninfo.can_id; - m_panel_lib->m_info.can_id = caninfo.can_id; - m_panel_lib->m_can_index = canindex; - + if ((fleft + gwidth) > (AMS_ITEM_CUBE_SIZE.x)) { + gwidth = (fleft + AMS_ITEM_CUBE_SIZE.x) - fleft; + } - auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); + auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); + dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); + fleft += gwidth; + } + } else { + int cols_size = iter->material_cols.size(); + for (int i = 0; i < cols_size; i++) { + dc.SetBrush(wxBrush(iter->material_cols[i])); + float x = left + total_width * i / cols_size; + dc.DrawRoundedRectangle(x, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, total_width / cols_size, AMS_ITEM_CUBE_SIZE.y , 0); + } + } - if (m_ams_model == AMSModel::GENERIC_AMS) { - //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); - m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); - //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); - m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); - m_sizer_ams->Add(m_panel_road, 0, wxALL, 0); - } - else if (m_ams_model == AMSModel::AMS_LITE) - { - m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); - m_panel_road->Hide(); + dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(left - 1, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2 - 1, AMS_ITEM_CUBE_SIZE.x + 2, AMS_ITEM_CUBE_SIZE.y + 2, 2); - if (canindex <= 1) { - m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); - m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); - } - else { - m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); - m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); + }else { + if (iter->material_colour.Alpha() == 0) { + dc.DrawBitmap(m_ts_bitmap_cube->bmp(),left,(size.y - AMS_ITEM_CUBE_SIZE.y) / 2); + } + else { + wxRect rect(left, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, AMS_ITEM_CUBE_SIZE.x, AMS_ITEM_CUBE_SIZE.y); + if(iter->material_state==AMSCanType::AMS_CAN_TYPE_EMPTY){ + dc.SetPen(wxPen(wxColor(0, 0, 0))); + dc.DrawRoundedRectangle(rect, 2); + + dc.DrawLine(rect.GetRight()-1, rect.GetTop()+1, rect.GetLeft()+1, rect.GetBottom()-1); + } + else { + dc.DrawRoundedRectangle(rect, 2); + } + } + } + + + left += AMS_ITEM_CUBE_SIZE.x; + left += m_space; } + auto border_colour = AMS_CONTROL_BRAND_COLOUR; + if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } - amscan->SetSizer(m_sizer_ams); - amscan->Layout(); - amscan->Fit(); + if (m_hover) { + dc.SetPen(wxPen(border_colour, 2)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); - if (m_ams_model == AMSModel::GENERIC_AMS) { - sizer->Add(amscan, 0, wxALL, 0); - } - else if (m_ams_model == AMSModel::AMS_LITE) - { - if (canindex > 1) { - sizer->Prepend(amscan, 0, wxALL, 0); - } - else { - sizer->Add(amscan, 0, wxALL, 0); - } } - - Canrefreshs* canrefresh = new Canrefreshs; - canrefresh->canID = caninfo.can_id; - canrefresh->canrefresh = m_panel_refresh; - m_can_refresh_list.Add(canrefresh); - - CanLibs* canlib = new CanLibs; - canlib->canID = caninfo.can_id; - canlib->canLib = m_panel_lib; - m_can_lib_list.Add(canlib); - CanRoads* canroad = new CanRoads; - canroad->canID = caninfo.can_id; - canroad->canRoad = m_panel_road; - m_can_road_list.Add(canroad); + if (m_selected) { + dc.SetPen(wxPen(border_colour, 2)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); + } } -void AmsCans::Update(AMSinfo info) -{ - m_info = info; - m_can_count = info.cans.size(); - - if (m_humidity) - { - m_humidity->Update(m_info); - } - - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - if (i < m_can_count) { - refresh->canrefresh->Update(info.ams_id, info.cans[i]); - refresh->canrefresh->Show(); - } else { - refresh->canrefresh->Hide(); - } - } - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (i < m_can_count) { - lib->canLib->Update(info.cans[i], info.ams_id); - lib->canLib->Show(); - } else { - lib->canLib->Hide(); - } - } - - if (m_ams_model == AMSModel::GENERIC_AMS) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads* road = m_can_road_list[i]; - if (i < m_can_count) { - road->canRoad->Update(m_info, info.cans[i], i, m_can_count); - road->canRoad->Show(); - } - else { - road->canRoad->Hide(); - } - } - } - Layout(); -} - -void AmsCans::SetDefSelectCan() -{ - if (m_can_lib_list.GetCount() > 0) { - CanLibs* lib = m_can_lib_list[0]; - m_canlib_selection =lib->canLib->m_can_index; - m_canlib_id = lib->canLib->m_info.can_id; - SelectCan(m_canlib_id); - } -} - - -void AmsCans::SelectCan(std::string canid) -{ - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (lib->canLib->m_info.can_id == canid) { - m_canlib_selection = lib->canLib->m_can_index; - } - } - - m_canlib_id = canid; - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (lib->canLib->m_info.can_id == m_canlib_id) { - wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); - evt.SetString(m_info.ams_id); - wxPostEvent(GetParent()->GetParent(), evt); - lib->canLib->OnSelected(); - } else { - lib->canLib->UnSelected(); - } - } -} - -wxColour AmsCans::GetTagColr(wxString canid) -{ - auto tag_colour = *wxWHITE; - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - if (canid == lib->canLib->m_info.can_id) tag_colour = lib->canLib->GetLibColour(); - } - return tag_colour; -} +void AMSPreview::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } -void AmsCans::SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) -{ - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP1) { - SetAmsStep(canid.ToStdString()); - }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP2) { - SetAmsStep(canid.ToStdString()); - }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP3) { - SetAmsStep(canid.ToStdString()); - }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { - SetAmsStep(""); - } -} +/************************************************* +Description:AMSHumidity +**************************************************/ -void AmsCans::SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) +AMSHumidity::AMSHumidity() {} +AMSHumidity::AMSHumidity(wxWindow* parent, wxWindowID id, AMSinfo info, const wxPoint& pos, const wxSize& size) + : AMSHumidity() { + create(parent, id, pos, wxDefaultSize); - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - auto pr = std::vector{}; - pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_NONE); - road->canRoad->OnPassRoad(pr); - } + for (int i = 1; i <= 5; i++) { ams_humidity_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 16));} + for (int i = 1; i <= 5; i++) { ams_humidity_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 16));} + for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } + for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } - return; - } + ams_sun_img = ScalableBitmap(this, "ams_drying", 16); + ams_drying_img = ScalableBitmap(this, "ams_is_drying", 16); - - auto tag_can_index = -1; - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - if (canid == road->canRoad->m_info.can_id) { tag_can_index = road->canRoad->m_canindex; } - } - if (tag_can_index == -1) return; + Bind(wxEVT_PAINT, &AMSHumidity::paintEvent, this); + //wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_HUMIDITY_BK_COLOUR); - // get colour - auto tag_colour = *wxWHITE; - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs *lib = m_can_lib_list[i]; - if (canid == lib->canLib->m_info.can_id) tag_colour = lib->canLib->GetLibColour(); - } + Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { + if (m_show_humidity) { + auto mouse_pos = ClientToScreen(e.GetPosition()); + auto rect = ClientToScreen(wxPoint(0, 0)); - // unload - if (type == AMSPassRoadType::AMS_ROAD_TYPE_UNLOAD) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; + if (mouse_pos.x > rect.x && + mouse_pos.y > rect.y) { + wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); - auto index = road->canRoad->m_canindex; - auto pr = std::vector{}; + uiAmsHumidityInfo *info = new uiAmsHumidityInfo; + info->ams_id = m_amsinfo.ams_id; + info->humidity_level = m_amsinfo.ams_humidity; + info->humidity_percent = m_amsinfo.humidity_raw; + info->left_dry_time = m_amsinfo.left_dray_time; + info->current_temperature = m_amsinfo.current_temperature; + show_event.SetClientData(info); + wxPostEvent(GetParent()->GetParent(), show_event); - pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } +#ifdef __WXMSW__ + wxCommandEvent close_event(EVT_CLEAR_SPEED_CONTROL); + wxPostEvent(GetParent()->GetParent(), close_event); +#endif // __WXMSW__ - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_3) { - if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } - if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } - if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } - if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } } - - road->canRoad->SetPassRoadColour(tag_colour); - road->canRoad->OnPassRoad(pr); } - } - - // load - if (type == AMSPassRoadType::AMS_ROAD_TYPE_LOAD) { - for (auto i = 0; i < m_can_road_list.GetCount(); i++) { - CanRoads *road = m_can_road_list[i]; - - auto index = road->canRoad->m_canindex; - auto pr = std::vector{}; - - if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } - if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } - if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } - if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } + }); - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } + Update(info); +} - road->canRoad->SetPassRoadColour(tag_colour); - road->canRoad->OnPassRoad(pr); - } - } +void AMSHumidity::create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) { + wxWindow::Create(parent, id, pos, size); + SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); } -void AmsCans::SetAmsStep(std::string can_id) + +void AMSHumidity::Update(AMSinfo amsinfo) { - if (m_road_canid != can_id) { - m_road_canid = can_id; + if (m_amsinfo != amsinfo) + { + m_amsinfo = amsinfo; + update_size(); Refresh(); } } -void AmsCans::PlayRridLoading(wxString canid) +void AMSHumidity::update_size() { - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - if (refresh->canrefresh->m_info.can_id == canid) { refresh->canrefresh->PlayLoading(); } + wxSize size; + if (m_amsinfo.humidity_raw != -1) { + size = AMS_HUMIDITY_SIZE; + } else { + size = AMS_HUMIDITY_NO_PERCENT_SIZE; } -} -std::string AmsCans::GetCurrentCan() -{ - if (m_canlib_selection < 0) - return ""; + if (!m_amsinfo.support_drying()) { size.x -= AMS_HUMIDITY_DRY_WIDTH; } - return wxString::Format("%d", m_canlib_selection).ToStdString(); + SetMaxSize(size); + SetMinSize(size); + SetSize(size); } -void AmsCans::paintEvent(wxPaintEvent& evt) + +void AMSHumidity::paintEvent(wxPaintEvent& evt) { wxPaintDC dc(this); render(dc); } -void AmsCans::render(wxDC& dc) +void AMSHumidity::render(wxDC& dc) { #ifdef __WXMSW__ wxSize size = GetSize(); @@ -2018,437 +1916,487 @@ void AmsCans::render(wxDC& dc) #endif } -void AmsCans::doRender(wxDC& dc) +void AMSHumidity::doRender(wxDC& dc) { - wxSize size = GetSize(); - dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); - - //road for extra - if (m_ams_model == AMSModel::AMS_LITE) { - - auto end_top = size.x / 2 - FromDIP(99); - auto passroad_width = 6; - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; + wxSize size = GetSize(); - if (m_road_canid.empty()) { - lib->canLib->on_pass_road(false); - } - else { - if (lib->canLib->m_info.can_id == m_road_canid) { - m_road_colour = lib->canLib->m_info.material_colour; - lib->canLib->on_pass_road(true); - } - } - } + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_BLOCK_BK_COLOUR))); + // left mode + if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) { m_show_humidity = true; } + else { m_show_humidity = false; } - - // A1 - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + if (m_show_humidity) { + //background + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_BLOCK_BK_COLOUR))); + dc.DrawRoundedRectangle(0, 0, (size.x), (size.y), (size.y / 2)); - try + wxPoint pot; + if (m_amsinfo.humidity_raw != -1) /*image with no number + percentage*/ { - auto a1_top = size.y / 2 - FromDIP(4); - auto a1_left = m_can_lib_list[0]->canLib->GetScreenPosition().x + m_can_lib_list[0]->canLib->GetSize().x / 2; - auto local_pos1 = GetScreenPosition().x + GetSize().x / 2; - a1_left = size.x / 2 + (a1_left - local_pos1); - dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); - dc.DrawLine(a1_left, a1_top, end_top, a1_top); - - - // A2 - auto a2_top = size.y / 2 + FromDIP(8); - auto a2_left = m_can_lib_list[1]->canLib->GetScreenPosition().x + m_can_lib_list[1]->canLib->GetSize().x / 2; - auto local_pos2 = GetScreenPosition().x + GetSize().x / 2; - a2_left = size.x / 2 + (a2_left - local_pos2); - dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); - dc.DrawLine(a2_left, a2_top, end_top, a2_top); - - // A3 - auto a3_top = size.y / 2 + FromDIP(4); - auto a3_left = m_can_lib_list[2]->canLib->GetScreenPosition().x + m_can_lib_list[2]->canLib->GetSize().x / 2; - auto local_pos3 = GetScreenPosition().x + GetSize().x / 2; - a3_left = size.x / 2 + (a3_left - local_pos3); - dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); - dc.DrawLine(a3_left, a3_top, end_top, a3_top); - + // hum image + ScalableBitmap hum_img; + if (!wxGetApp().dark_mode()) { + hum_img = ams_humidity_no_num_imgs[m_amsinfo.ams_humidity - 1]; + } else { + hum_img = ams_humidity_no_num_dark_imgs[m_amsinfo.ams_humidity - 1]; + } - // A4 - auto a4_top = size.y / 2; - auto a4_left = m_can_lib_list[3]->canLib->GetScreenPosition().x + m_can_lib_list[3]->canLib->GetSize().x / 2; - auto local_pos4 = GetScreenPosition().x + GetSize().x / 2; - a4_left = size.x / 2 + (a4_left - local_pos4); - dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); - dc.DrawLine(a4_left, a4_top, end_top, a4_top); + pot = wxPoint(FromDIP(5), ((size.y - hum_img.GetBmpSize().y) / 2)); + dc.DrawBitmap(hum_img.bmp(), pot); + pot.x += hum_img.GetBmpSize().x + FromDIP(3); - - if (!m_road_canid.empty()) { - if (m_road_canid == "0") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); - dc.DrawLine(a1_left, a1_top, end_top, a1_top); - } + // percentage + wxString hum_percentage(std::to_string(m_amsinfo.humidity_raw)); + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + dc.SetFont(Label::Body_14); + dc.SetTextForeground(StateColor::darkModeColorFor(AMS_CONTROL_BLACK_COLOUR)); - if (m_road_canid == "1") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); - dc.DrawLine(a2_left, a2_top, end_top, a2_top); - } + //WxFontUtils::get_suitable_font_size(0.7 * size.GetHeight(), dc); + auto tsize1 = dc.GetMultiLineTextExtent(hum_percentage); + pot.y = (size.y - tsize1.y) / 2; + dc.DrawText(hum_percentage, pot); + pot.x += (tsize1.x + FromDIP(3)); - if (m_road_canid == "2") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); - dc.DrawLine(a3_left, a3_top, end_top, a3_top); - } + // percentage sign + dc.SetFont(Label::Body_12); + //WxFontUtils::get_suitable_font_size(0.5 * size.GetHeight(), dc); + auto tsize2 = dc.GetMultiLineTextExtent(_L("%")); + pot.y = pot.y + ((tsize1.y - tsize2.y) / 2) + FromDIP(2); + dc.DrawText(_L("%"), pot); - if (m_road_canid == "3") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); - dc.DrawLine(a4_left, a4_top, end_top, a4_top); - } + pot.x += tsize2.x; + } + else /*image with number*/ + { + // hum image + ScalableBitmap hum_img; + if (!wxGetApp().dark_mode()) { + hum_img = ams_humidity_imgs[m_amsinfo.ams_humidity - 1]; + } else { + hum_img = ams_humidity_dark_imgs[m_amsinfo.ams_humidity - 1]; } - //to Extruder - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + pot = wxPoint(FromDIP(5), ((size.y - hum_img.GetBmpSize().y) / 2)); + dc.DrawBitmap(hum_img.bmp(), pot); + pot.x = pot.x + hum_img.GetBmpSize().x; + } - dc.DrawLine(end_top, a1_top, end_top, size.y); + if (m_amsinfo.support_drying()) + { + pot.x += FromDIP(2);// spacing - if (!m_road_canid.empty()) { - if (!m_road_canid.empty()) { - if (m_road_canid == "0") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a1_top, end_top, size.y); - } - else if (m_road_canid == "1") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a2_top, end_top, size.y); - } - else if (m_road_canid == "2") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a3_top, end_top, size.y); - } - else if (m_road_canid == "3") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a4_top, end_top, size.y); - } - } + // vertical line + dc.SetPen(wxPen(wxColour(194, 194, 194))); + dc.SetBrush(wxBrush(wxColour(194, 194, 194))); + dc.DrawLine(pot.x, GetSize().y / 2 - FromDIP(10), pot.x, GetSize().y / 2 + FromDIP(10)); + + // sun image + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + pot.x += ((size.GetWidth() - pot.x) - ams_drying_img.GetBmpWidth()) / 2;// spacing + if (m_amsinfo.left_dray_time > 0) { + pot.y = (size.y - ams_drying_img.GetBmpHeight()) / 2; + dc.DrawBitmap(ams_drying_img.bmp(), pot); + } else { + pot.y = (size.y - ams_sun_img.GetBmpHeight()) / 2; + dc.DrawBitmap(ams_sun_img.bmp(), pot); } } - catch (...){} } -} - -void AmsCans::StopRridLoading(wxString canid) -{ - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - if (refresh->canrefresh->m_info.can_id == canid) { refresh->canrefresh->StopLoading(); } + else { + //to do ... } } -void AmsCans::msw_rescale() -{ - for (auto i = 0; i < m_can_refresh_list.GetCount(); i++) { - Canrefreshs *refresh = m_can_refresh_list[i]; - refresh->canrefresh->msw_rescale(); - } - - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - lib->canLib->msw_rescale(); - } - if (m_humidity != nullptr) m_humidity->msw_rescale(); -} +void AMSHumidity::msw_rescale() { + for (auto& img : ams_humidity_imgs) { img.msw_rescale();} + for (auto& img : ams_humidity_dark_imgs) { img.msw_rescale(); } + for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } + for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } + ams_sun_img.msw_rescale(); + ams_drying_img.msw_rescale(); -void AmsCans::show_sn_value(bool show) -{ - for (auto i = 0; i < m_can_lib_list.GetCount(); i++) { - CanLibs* lib = m_can_lib_list[i]; - lib->canLib->show_kn_value(show); - } + Layout(); + Refresh(); } /************************************************* -Description:AMSPreview +Description:AmsItem **************************************************/ -AMSPreview::AMSPreview() {} -AMSPreview::AMSPreview(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSPreview() -{ - m_amsinfo = amsinfo; - m_cube_size = cube_size; - create(parent, id, pos, AMS_ITEM_SIZE); - Bind(wxEVT_PAINT, &AMSPreview::paintEvent, this); - Bind(wxEVT_ENTER_WINDOW, &AMSPreview::OnEnterWindow, this); - Bind(wxEVT_LEAVE_WINDOW, &AMSPreview::OnLeaveWindow, this); -} +AmsItem::AmsItem() {} -void AMSPreview::Open() +AmsItem::AmsItem(wxWindow *parent,AMSinfo info, AMSModel model) : AmsItem() { - m_open = true; - Show(); -} + m_bitmap_extra_framework = ScalableBitmap(this, "ams_extra_framework_mid", 140); -void AMSPreview::Close() -{ - m_open = false; - Hide(); -} + SetDoubleBuffered(true); + m_ams_model = model; + m_info = info; -void AMSPreview::Update(AMSinfo amsinfo) -{ - m_amsinfo = amsinfo; + wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE); + create(parent); + Bind(wxEVT_PAINT, &AmsItem::paintEvent, this); } -void AMSPreview::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) +void AmsItem::create(wxWindow *parent) { - m_ts_bitmap_cube = new ScalableBitmap(this, "ts_bitmap_cube", 14); - wxWindow::Create(parent, id, pos, size); - SetMinSize(AMS_ITEM_SIZE); - SetMaxSize(AMS_ITEM_SIZE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); - Refresh(); + Freeze(); + SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + + if (m_ams_model == AMSModel::GENERIC_AMS || m_ams_model == AMSModel::N3F_AMS || m_ams_model == AMSModel::N3S_AMS) { + sizer_can = new wxBoxSizer(wxHORIZONTAL); + sizer_item = new wxBoxSizer(wxVERTICAL); + for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { + AddCan(*it, m_can_count, m_info.cans.size(), sizer_can); + m_can_count++; + } + m_humidity = new AMSHumidity(this, wxID_ANY, m_info); + sizer_item->Add(m_humidity, 0, wxALIGN_CENTER_HORIZONTAL, 0); + sizer_item->Add(sizer_can, 0, wxALIGN_CENTER_HORIZONTAL, 0); + SetSizer(sizer_item); + } + else if(m_ams_model == AMSModel::AMS_LITE) { + sizer_can = new wxBoxSizer(wxVERTICAL); + sizer_can_middle = new wxBoxSizer(wxHORIZONTAL); + sizer_can_left = new wxBoxSizer(wxVERTICAL); + sizer_can_right = new wxBoxSizer(wxVERTICAL); + + sizer_can_left->Add(0,0,0,wxTOP,FromDIP(8)); + + for (auto it = m_info.cans.begin(); it != m_info.cans.end(); it++) { + if (m_can_count <= 1) { + AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_left); + if (m_can_count == 0) { + sizer_can_left->Add(0,0,0,wxTOP,FromDIP(20)); + } + } + else { + AddCan(*it, m_can_count, m_info.cans.size(), sizer_can_right); + if (m_can_count == 2) { + sizer_can_right->Prepend(0, 0, 0, wxTOP, FromDIP(20)); + } + } + + m_can_count++; + } + + sizer_can_right->Prepend(0,0,0,wxTOP,FromDIP(8)); + sizer_can_middle->Add(0, 0, 0, wxLEFT, FromDIP(8)); + sizer_can_middle->Add(sizer_can_left, 0, wxALL, 0); + sizer_can_middle->Add( 0, 0, 0, wxLEFT, FromDIP(20) ); + sizer_can_middle->Add(sizer_can_right, 0, wxALL, 0); + sizer_can->Add(sizer_can_middle, 1, wxALIGN_CENTER, 0); + SetSizer(sizer_can); + } + + Layout(); + Fit(); + Thaw(); } -void AMSPreview::OnEnterWindow(wxMouseEvent &evt) +void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer) { - // m_hover = true; - // Refresh(); -} -void AMSPreview::OnLeaveWindow(wxMouseEvent &evt) -{ - // m_hover = false; - // Refresh(); -} + auto amscan = new wxWindow(this, wxID_ANY); + amscan->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); -void AMSPreview::OnSelected() -{ - if (!wxWindow::IsEnabled()) { return; } - m_selected = true; - Refresh(); -} + wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); + -void AMSPreview::UnSelected() -{ - m_selected = false; - Refresh(); -} + auto m_panel_refresh = new AMSrefresh(amscan, m_can_count, caninfo); + m_can_refresh_list[caninfo.can_id] = m_panel_refresh; -bool AMSPreview::Enable(bool enable) { return wxWindow::Enable(enable); } + auto m_panel_lib = new AMSLib(amscan, m_info.ams_id, caninfo); -void AMSPreview::paintEvent(wxPaintEvent &evt) -{ - wxPaintDC dc(this); - render(dc); -} + m_panel_lib->Bind(wxEVT_LEFT_DOWN, [this, canindex](wxMouseEvent& ev) { + m_canlib_selection = canindex; + // m_canlib_id = caninfo.can_id; -void AMSPreview::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (lib->m_can_index == m_canlib_selection) { + wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); + evt.SetString(m_info.ams_id); + wxPostEvent(GetParent()->GetParent(), evt); + lib->OnSelected(); + } + else { + lib->UnSelected(); + } + } + ev.Skip(); + }); - { - wxGCDC dc2(memdc); - doRender(dc2); + + m_panel_lib->m_ams_model = m_ams_model; + m_panel_lib->m_ams_id = m_info.ams_id; + m_panel_lib->m_slot_id = caninfo.can_id; + m_panel_lib->m_info.can_id = caninfo.can_id; + m_panel_lib->m_can_index = canindex; + + + auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); + + if (m_ams_model == AMSModel::GENERIC_AMS) { + //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); + m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); + //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); + m_sizer_ams->Add(m_panel_lib, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(3)); + m_sizer_ams->Add(m_panel_road, 0, wxALL, 0); } + else if (m_ams_model == AMSModel::AMS_LITE) + { + m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); + m_panel_road->Hide(); - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} + if (canindex <= 1) { + m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); + m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); + } + else { + m_sizer_ams->Add(m_panel_lib, 0, wxALIGN_CENTER, 0); + m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); + } + } -void AMSPreview::doRender(wxDC &dc) -{ - wxSize size = GetSize(); - dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); - dc.SetBrush(wxBrush(StateColor::darkModeColorFor(m_background_colour))); - dc.DrawRoundedRectangle(0, 0, size.x, size.y, 3); - auto left = m_padding; - for (std::vector::iterator iter = m_amsinfo.cans.begin(); iter != m_amsinfo.cans.end(); iter++) { - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); + amscan->SetSizer(m_sizer_ams); + amscan->Layout(); + amscan->Fit(); - if (wxWindow::IsEnabled()) { - wxColour color = iter->material_colour; - change_the_opacity(color); - dc.SetBrush(wxBrush(color)); - } else { - dc.SetBrush(AMS_CONTROL_DISABLE_COLOUR); + if (m_ams_model == AMSModel::GENERIC_AMS) { + sizer->Add(amscan, 0, wxALL, 0); + } + else if (m_ams_model == AMSModel::AMS_LITE) + { + if (canindex > 1) { + sizer->Prepend(amscan, 0, wxALL, 0); + } + else { + sizer->Add(amscan, 0, wxALL, 0); } + } - if (iter->material_cols.size() > 1) { - int fleft = left; - float total_width = AMS_ITEM_CUBE_SIZE.x; - int gwidth = std::round(total_width / (iter->material_cols.size() - 1)); - if (iter->ctype == 0) { - for (int i = 0; i < iter->material_cols.size() - 1; i++) { + m_can_lib_list[caninfo.can_id] = m_panel_lib; + m_can_road_list[caninfo.can_id] = m_panel_road; +} - if ((fleft + gwidth) > (AMS_ITEM_CUBE_SIZE.x)) { - gwidth = (fleft + AMS_ITEM_CUBE_SIZE.x) - fleft; - } +void AmsItem::Update(AMSinfo info) +{ + m_info = info; + m_can_count = info.cans.size(); - auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); - dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); - fleft += gwidth; - } - } else { - int cols_size = iter->material_cols.size(); - for (int i = 0; i < cols_size; i++) { - dc.SetBrush(wxBrush(iter->material_cols[i])); - float x = left + total_width * i / cols_size; - dc.DrawRoundedRectangle(x, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, total_width / cols_size, AMS_ITEM_CUBE_SIZE.y , 0); - } - } + if (m_humidity) + { + m_humidity->Update(m_info); + } - dc.SetPen(wxPen(StateColor::darkModeColorFor(m_background_colour))); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRoundedRectangle(left - 1, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2 - 1, AMS_ITEM_CUBE_SIZE.x + 2, AMS_ITEM_CUBE_SIZE.y + 2, 2); + for (int i = 0; i < m_can_count; i++) { + auto it = m_can_refresh_list.find(std::to_string(i)); + if (it == m_can_refresh_list.end()) break; - }else { - if (iter->material_colour.Alpha() == 0) { - dc.DrawBitmap(m_ts_bitmap_cube->bmp(),left,(size.y - AMS_ITEM_CUBE_SIZE.y) / 2); + auto refresh = it->second; + if (refresh != nullptr){ + refresh->Update(info.ams_id, info.cans[i]); + refresh->Show(); + } + } + + for (int i = 0; i < m_can_lib_list.size(); i++) { + AMSLib* lib = m_can_lib_list[std::to_string(i)]; + if (lib != nullptr){ + if (i < m_can_count){ + lib->Update(info.cans[i], info.ams_id); + lib->Show(); } - else { - wxRect rect(left, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, AMS_ITEM_CUBE_SIZE.x, AMS_ITEM_CUBE_SIZE.y); - if(iter->material_state==AMSCanType::AMS_CAN_TYPE_EMPTY){ - dc.SetPen(wxPen(wxColor(0, 0, 0))); - dc.DrawRoundedRectangle(rect, 2); - - dc.DrawLine(rect.GetRight()-1, rect.GetTop()+1, rect.GetLeft()+1, rect.GetBottom()-1); - } - else { - dc.DrawRoundedRectangle(rect, 2); - } + else{ + lib->Hide(); } - } + } - - left += AMS_ITEM_CUBE_SIZE.x; - left += m_space; + if (m_ams_model == AMSModel::GENERIC_AMS) { + for (auto i = 0; i < m_can_road_list.size(); i++) { + AMSRoad* road = m_can_road_list[std::to_string(i)]; + if (road != nullptr) { + if (i < m_can_count) { + road->Update(m_info, info.cans[i], i, m_can_count); + road->Show(); + } else { + road->Hide(); + } + } + } } + Layout(); +} - auto border_colour = AMS_CONTROL_BRAND_COLOUR; - if (!wxWindow::IsEnabled()) { border_colour = AMS_CONTROL_DISABLE_COLOUR; } +void AmsItem::SetDefSelectCan() +{ + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + m_canlib_selection =lib->m_can_index; + m_canlib_id = lib->m_info.can_id; + SelectCan(m_canlib_id); + break; + } +} - if (m_hover) { - dc.SetPen(wxPen(border_colour, 2)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 3); +void AmsItem::SelectCan(std::string canid) +{ + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (lib->m_info.can_id == canid) { + m_canlib_selection = lib->m_can_index; + } } - if (m_selected) { - dc.SetPen(wxPen(border_colour, 2)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - dc.DrawRoundedRectangle(1, 1, size.x-1, size.y-1, 3); + m_canlib_id = canid; + + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (lib->m_info.can_id == m_canlib_id) { + wxCommandEvent evt(EVT_AMS_UNSELETED_VAMS); + evt.SetString(m_info.ams_id); + wxPostEvent(GetParent()->GetParent(), evt); + lib->OnSelected(); + } else { + lib->UnSelected(); + } } } -void AMSPreview::DoSetSize(int x, int y, int width, int height, int sizeFlags /*= wxSIZE_AUTO*/) { wxWindow::DoSetSize(x, y, width, height, sizeFlags); } - -/************************************************* -Description:AMSHumidity -**************************************************/ +wxColour AmsItem::GetTagColr(wxString canid) +{ + auto tag_colour = *wxWHITE; + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (canid == lib->m_info.can_id) tag_colour = lib->GetLibColour(); + } + return tag_colour; +} -AMSHumidity::AMSHumidity() {} -AMSHumidity::AMSHumidity(wxWindow* parent, wxWindowID id, AMSinfo info, const wxPoint& pos, const wxSize& size) - : AMSHumidity() +void AmsItem::SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) { - create(parent, id, pos, wxDefaultSize); + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP1) { + SetAmsStep(canid.ToStdString()); + }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP2) { + SetAmsStep(canid.ToStdString()); + }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_COMBO_LOAD_STEP3) { + SetAmsStep(canid.ToStdString()); + }else if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { + SetAmsStep(""); + } +} - for (int i = 1; i <= 5; i++) { ams_humidity_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_light", 16));} - for (int i = 1; i <= 5; i++) { ams_humidity_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_dark", 16));} - for (int i = 1; i <= 5; i++) { ams_humidity_no_num_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_light", 16)); } - for (int i = 1; i <= 5; i++) { ams_humidity_no_num_dark_imgs.push_back(ScalableBitmap(this, "hum_level" + std::to_string(i) + "_no_num_dark", 16)); } +void AmsItem::SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) +{ - ams_sun_img = ScalableBitmap(this, "ams_drying", 16); - ams_drying_img = ScalableBitmap(this, "ams_is_drying", 16); + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { + for (auto road_it : m_can_road_list) { + AMSRoad* road = road_it.second; + auto pr = std::vector{}; + pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_NONE); + road->OnPassRoad(pr); + } - Bind(wxEVT_PAINT, &AMSHumidity::paintEvent, this); - //wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_HUMIDITY_BK_COLOUR); + return; + } - Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { - if (m_show_humidity) { - auto mouse_pos = ClientToScreen(e.GetPosition()); - auto rect = ClientToScreen(wxPoint(0, 0)); + + auto tag_can_index = -1; + for (auto road_it : m_can_road_list) { + AMSRoad* road = road_it.second; + if (canid == road->m_info.can_id) { tag_can_index = road->m_canindex; } + } + if (tag_can_index == -1) return; - if (mouse_pos.x > rect.x && - mouse_pos.y > rect.y) { - wxCommandEvent show_event(EVT_AMS_SHOW_HUMIDITY_TIPS); + // get colour + auto tag_colour = *wxWHITE; + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (canid == lib->m_info.can_id) tag_colour = lib->GetLibColour(); + } - uiAmsHumidityInfo *info = new uiAmsHumidityInfo; - info->ams_id = m_amsinfo.ams_id; - info->humidity_level = m_amsinfo.ams_humidity; - info->humidity_percent = m_amsinfo.humidity_raw; - info->left_dry_time = m_amsinfo.left_dray_time; - info->current_temperature = m_amsinfo.current_temperature; - show_event.SetClientData(info); - wxPostEvent(GetParent()->GetParent(), show_event); + // unload + if (type == AMSPassRoadType::AMS_ROAD_TYPE_UNLOAD) { + for (auto road_it : m_can_road_list) { + AMSRoad* road = road_it.second; -#ifdef __WXMSW__ - wxCommandEvent close_event(EVT_CLEAR_SPEED_CONTROL); - wxPostEvent(GetParent()->GetParent(), close_event); -#endif // __WXMSW__ + auto index = road->m_canindex; + auto pr = std::vector{}; + + pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_3) { + if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } + if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } + if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } + if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } } + + road->SetPassRoadColour(tag_colour); + road->OnPassRoad(pr); } - }); + } - Update(info); -} + // load + if (type == AMSPassRoadType::AMS_ROAD_TYPE_LOAD) { + for (auto road_it : m_can_road_list) { + AMSRoad* road = road_it.second; -void AMSHumidity::create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) { - wxWindow::Create(parent, id, pos, size); - SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); -} + auto index = road->m_canindex; + auto pr = std::vector{}; + if (index == tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT); } + if (index < tag_can_index && index > 0) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_LEFT_RIGHT); } + if (index == 0 && tag_can_index == index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_TOP); } + if (index == 0 && tag_can_index > index) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_RIGHT); } -void AMSHumidity::Update(AMSinfo amsinfo) + if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_2) { pr.push_back(AMSPassRoadMode::AMS_ROAD_MODE_END_BOTTOM); } + + road->SetPassRoadColour(tag_colour); + road->OnPassRoad(pr); + } + } +} + +void AmsItem::SetAmsStep(std::string can_id) { - if (m_amsinfo != amsinfo) - { - m_amsinfo = amsinfo; - update_size(); + if (m_road_canid != can_id) { + m_road_canid = can_id; Refresh(); } } -void AMSHumidity::update_size() +void AmsItem::PlayRridLoading(wxString canid) { - wxSize size; - if (m_amsinfo.humidity_raw != -1) { - size = AMS_HUMIDITY_SIZE; - } else { - size = AMS_HUMIDITY_NO_PERCENT_SIZE; + for (auto refresh_it : m_can_refresh_list) { + AMSrefresh* refresh = refresh_it.second; + if (refresh->GetCanId() == canid) { refresh->PlayLoading(); } } +} - if (!m_amsinfo.support_drying()) { size.x -= AMS_HUMIDITY_DRY_WIDTH; } +std::string AmsItem::GetCurrentCan() +{ + if (m_canlib_selection < 0) + return ""; - SetMaxSize(size); - SetMinSize(size); - SetSize(size); + return wxString::Format("%d", m_canlib_selection).ToStdString(); } - -void AMSHumidity::paintEvent(wxPaintEvent& evt) +void AmsItem::paintEvent(wxPaintEvent& evt) { wxPaintDC dc(this); render(dc); } -void AMSHumidity::render(wxDC& dc) +void AmsItem::render(wxDC& dc) { #ifdef __WXMSW__ wxSize size = GetSize(); @@ -2469,109 +2417,157 @@ void AMSHumidity::render(wxDC& dc) #endif } -void AMSHumidity::doRender(wxDC& dc) +void AmsItem::doRender(wxDC& dc) { - wxSize size = GetSize(); + wxSize size = GetSize(); + dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_BLOCK_BK_COLOUR))); - // left mode - if (m_amsinfo.ams_humidity >= 1 && m_amsinfo.ams_humidity <= 5) { m_show_humidity = true; } - else { m_show_humidity = false; } + //road for extra + if (m_ams_model == AMSModel::AMS_LITE) { - if (m_show_humidity) { - //background - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_BLOCK_BK_COLOUR))); - dc.DrawRoundedRectangle(0, 0, (size.x), (size.y), (size.y / 2)); + auto end_top = size.x / 2 - FromDIP(99); + auto passroad_width = 6; - wxPoint pot; - if (m_amsinfo.humidity_raw != -1) /*image with no number + percentage*/ - { - // hum image - ScalableBitmap hum_img; - if (!wxGetApp().dark_mode()) { - hum_img = ams_humidity_no_num_imgs[m_amsinfo.ams_humidity - 1]; - } else { - hum_img = ams_humidity_no_num_dark_imgs[m_amsinfo.ams_humidity - 1]; + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + + if (m_road_canid.empty()) { + lib->on_pass_road(false); + } + else { + if (lib->m_info.can_id == m_road_canid) { + m_road_colour = lib->m_info.material_colour; + lib->on_pass_road(true); + } } + } - pot = wxPoint(FromDIP(5), ((size.y - hum_img.GetBmpSize().y) / 2)); - dc.DrawBitmap(hum_img.bmp(), pot); - pot.x += hum_img.GetBmpSize().x + FromDIP(3); + + // A1 + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); - // percentage - wxString hum_percentage(std::to_string(m_amsinfo.humidity_raw)); - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetFont(Label::Body_14); - dc.SetTextForeground(StateColor::darkModeColorFor(AMS_CONTROL_BLACK_COLOUR)); + try + { + auto a1_top = size.y / 2 - FromDIP(4); + auto a1_left = m_can_lib_list["0"]->GetScreenPosition().x + m_can_lib_list["0"]->GetSize().x / 2; + auto local_pos1 = GetScreenPosition().x + GetSize().x / 2; + a1_left = size.x / 2 + (a1_left - local_pos1); + dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); + dc.DrawLine(a1_left, a1_top, end_top, a1_top); - //WxFontUtils::get_suitable_font_size(0.7 * size.GetHeight(), dc); - auto tsize1 = dc.GetMultiLineTextExtent(hum_percentage); - pot.y = (size.y - tsize1.y) / 2; - dc.DrawText(hum_percentage, pot); - pot.x += (tsize1.x + FromDIP(3)); - // percentage sign - dc.SetFont(Label::Body_12); - //WxFontUtils::get_suitable_font_size(0.5 * size.GetHeight(), dc); - auto tsize2 = dc.GetMultiLineTextExtent(_L("%")); - pot.y = pot.y + ((tsize1.y - tsize2.y) / 2) + FromDIP(2); - dc.DrawText(_L("%"), pot); + // A2 + auto a2_top = size.y / 2 + FromDIP(8); + auto a2_left = m_can_lib_list["1"]->GetScreenPosition().x + m_can_lib_list["1"]->GetSize().x / 2; + auto local_pos2 = GetScreenPosition().x + GetSize().x / 2; + a2_left = size.x / 2 + (a2_left - local_pos2); + dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); + dc.DrawLine(a2_left, a2_top, end_top, a2_top); - pot.x += tsize2.x; - } - else /*image with number*/ - { - // hum image - ScalableBitmap hum_img; - if (!wxGetApp().dark_mode()) { - hum_img = ams_humidity_imgs[m_amsinfo.ams_humidity - 1]; - } else { - hum_img = ams_humidity_dark_imgs[m_amsinfo.ams_humidity - 1]; - } + // A3 + auto a3_top = size.y / 2 + FromDIP(4); + auto a3_left = m_can_lib_list["2"]->GetScreenPosition().x + m_can_lib_list["2"]->GetSize().x / 2; + auto local_pos3 = GetScreenPosition().x + GetSize().x / 2; + a3_left = size.x / 2 + (a3_left - local_pos3); + dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); + dc.DrawLine(a3_left, a3_top, end_top, a3_top); - pot = wxPoint(FromDIP(5), ((size.y - hum_img.GetBmpSize().y) / 2)); - dc.DrawBitmap(hum_img.bmp(), pot); - pot.x = pot.x + hum_img.GetBmpSize().x; - } - if (m_amsinfo.support_drying()) - { - pot.x += FromDIP(2);// spacing + // A4 + auto a4_top = size.y / 2; + auto a4_left = m_can_lib_list["3"]->GetScreenPosition().x + m_can_lib_list["3"]->GetSize().x / 2; + auto local_pos4 = GetScreenPosition().x + GetSize().x / 2; + a4_left = size.x / 2 + (a4_left - local_pos4); + dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); + dc.DrawLine(a4_left, a4_top, end_top, a4_top); - // vertical line - dc.SetPen(wxPen(wxColour(194, 194, 194))); - dc.SetBrush(wxBrush(wxColour(194, 194, 194))); - dc.DrawLine(pot.x, GetSize().y / 2 - FromDIP(10), pot.x, GetSize().y / 2 + FromDIP(10)); + + if (!m_road_canid.empty()) { + if (m_road_canid == "0") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); + dc.DrawLine(a1_left, a1_top, end_top, a1_top); + } - // sun image - dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - pot.x += ((size.GetWidth() - pot.x) - ams_drying_img.GetBmpWidth()) / 2;// spacing - if (m_amsinfo.left_dray_time > 0) { - pot.y = (size.y - ams_drying_img.GetBmpHeight()) / 2; - dc.DrawBitmap(ams_drying_img.bmp(), pot); - } else { - pot.y = (size.y - ams_sun_img.GetBmpHeight()) / 2; - dc.DrawBitmap(ams_sun_img.bmp(), pot); + if (m_road_canid == "1") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); + dc.DrawLine(a2_left, a2_top, end_top, a2_top); + } + + if (m_road_canid == "2") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); + dc.DrawLine(a3_left, a3_top, end_top, a3_top); + } + + if (m_road_canid == "3") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); + dc.DrawLine(a4_left, a4_top, end_top, a4_top); + } + } + + //to Extruder + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + + dc.DrawLine(end_top, a1_top, end_top, size.y); + + if (!m_road_canid.empty()) { + if (!m_road_canid.empty()) { + if (m_road_canid == "0") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a1_top, end_top, size.y); + } + else if (m_road_canid == "1") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a2_top, end_top, size.y); + } + else if (m_road_canid == "2") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a3_top, end_top, size.y); + } + else if (m_road_canid == "3") { + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + dc.DrawLine(end_top, a4_top, end_top, size.y); + } + } } } + catch (...){} } - else { - //to do ... +} + +void AmsItem::StopRridLoading(wxString canid) +{ + for (auto refresh_it : m_can_refresh_list) { + AMSrefresh* refresh = refresh_it.second; + if (refresh->GetCanId() == canid) { refresh->StopLoading(); } } } -void AMSHumidity::msw_rescale() { - for (auto& img : ams_humidity_imgs) { img.msw_rescale();} - for (auto& img : ams_humidity_dark_imgs) { img.msw_rescale(); } - for (auto &img : ams_humidity_no_num_imgs) { img.msw_rescale(); } - for (auto &img : ams_humidity_no_num_dark_imgs) { img.msw_rescale(); } - ams_sun_img.msw_rescale(); - ams_drying_img.msw_rescale(); +void AmsItem::msw_rescale() +{ + for (auto refresh_it : m_can_refresh_list) { + AMSrefresh* refresh = refresh_it.second; + if(refresh) refresh->msw_rescale(); + } - Layout(); - Refresh(); + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (lib) lib->msw_rescale(); + } + if (m_humidity != nullptr) m_humidity->msw_rescale(); +} + +void AmsItem::show_sn_value(bool show) +{ + for (auto lib_it : m_can_lib_list) { + AMSLib* lib = lib_it.second; + if (lib) lib->show_kn_value(show); + } } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 4efbf9ae487..9132bedbea5 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -235,20 +235,26 @@ class AMSrefresh : public wxWindow AMSrefresh(wxWindow *parent, wxString number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); ~AMSrefresh(); + +public: + void Update(std::string ams_id, Caninfo info); + + std::string GetCanId() const { return m_info.can_id; }; + void PlayLoading(); void StopLoading(); - void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); - void on_timer(wxTimerEvent &event); - void OnEnterWindow(wxMouseEvent &evt); - void OnLeaveWindow(wxMouseEvent &evt); - void OnClick(wxMouseEvent &evt); - void post_event(wxCommandEvent &&event); - void paintEvent(wxPaintEvent &evt); - void Update(std::string ams_id, Caninfo info); + void msw_rescale(); - void set_disable_mode(bool disable) { m_disable_mode = disable; } - Caninfo m_info; - + +protected: + void create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size); + + void on_timer(wxTimerEvent &event); + void OnEnterWindow(wxMouseEvent &evt); + void OnLeaveWindow(wxMouseEvent &evt); + void OnClick(wxMouseEvent &evt); + void post_event(wxCommandEvent &&event); + void paintEvent(wxPaintEvent &evt); protected: wxTimer *m_playing_timer= {nullptr}; @@ -258,6 +264,7 @@ class AMSrefresh : public wxWindow std::string m_ams_id; std::string m_can_id; + Caninfo m_info; ScalableBitmap m_bitmap_normal; ScalableBitmap m_bitmap_selected; @@ -543,39 +550,15 @@ class AMSHumidity : public wxWindow void update_size(); }; + /************************************************* -Description:AmsCans +Description:AmsItem **************************************************/ -class Canrefreshs -{ -public: - wxString canID; - AMSrefresh *canrefresh; -}; - -class CanLibs -{ -public: - wxString canID; - AMSLib * canLib; -}; - -class CanRoads -{ -public: - wxString canID; - AMSRoad *canRoad; -}; - -WX_DEFINE_ARRAY(Canrefreshs *, CanrefreshsHash); -WX_DEFINE_ARRAY(CanLibs *, CanLibsHash); -WX_DEFINE_ARRAY(CanRoads *, CansRoadsHash); - -class AmsCans : public wxWindow +class AmsItem : public wxWindow { public: - AmsCans(); - AmsCans(wxWindow *parent, AMSinfo info, AMSModel model); + AmsItem(); + AmsItem(wxWindow *parent, AMSinfo info, AMSModel model); void Update(AMSinfo info); void create(wxWindow *parent); @@ -596,6 +579,14 @@ class AmsCans : public wxWindow std::string GetCurrentCan(); public: + std::string get_ams_id() const { return m_info.ams_id; }; + + std::map get_can_lib_list() const { return m_can_lib_list; }; + + int get_selection() const { return m_selection; }; + void set_selection(int selection) { m_selection = selection; }; + +private: ScalableBitmap m_bitmap_extra_framework; int m_canlib_selection = { -1 }; int m_selection = { 0 }; @@ -606,9 +597,9 @@ class AmsCans : public wxWindow std::string m_road_canid; wxColour m_road_colour; - CanLibsHash m_can_lib_list; - CansRoadsHash m_can_road_list; - CanrefreshsHash m_can_refresh_list; + std::map m_can_lib_list; + std::map m_can_road_list; + std::map m_can_refresh_list; AMSHumidity* m_humidity = { nullptr }; AMSinfo m_info; @@ -620,38 +611,6 @@ class AmsCans : public wxWindow AMSPassRoadSTEP m_step = {AMSPassRoadSTEP ::AMS_ROAD_STEP_NONE}; }; -/************************************************* -Description:AmsCansWindow -**************************************************/ -class AmsCansWindow -{ -public: - wxString amsIndex; - AmsCans *amsCans; - bool m_disable_mode{ false }; - - void set_disable_mode(bool disable) { - m_disable_mode = disable; - for (auto can_lib : amsCans->m_can_lib_list) { - can_lib->canLib->set_disable_mode(disable); - } - for (auto can_refresh : amsCans->m_can_refresh_list) { - can_refresh->canrefresh->set_disable_mode(disable); - } - } -}; - -class AMSextruders -{ -public: - wxString amsIndex; - AMSextruder *amsextruder; -}; - -WX_DEFINE_ARRAY(AmsCansWindow *, AmsCansHash); -WX_DEFINE_ARRAY(AMSextruders *, AMSextrudersHash); - - wxDECLARE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); wxDECLARE_EVENT(EVT_AMS_LOAD, SimpleEvent); wxDECLARE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); From cee7041b4dab728be87f4772e86b22086a10cafb Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 21 May 2025 16:25:48 +0800 Subject: [PATCH 085/127] Clean up code --- src/slic3r/GUI/Widgets/AMSControl.cpp | 8 +- src/slic3r/GUI/Widgets/AMSItem.cpp | 127 +++++++++++++------------- src/slic3r/GUI/Widgets/AMSItem.hpp | 14 +-- 3 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index cd3976cc118..9132f5541de 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -15,11 +15,11 @@ namespace Slic3r { namespace GUI { +#define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(196)) +#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) -/************************************************* -Description:AMSControl -**************************************************/ -AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) + +AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) : wxSimplebook(parent, wxID_ANY, pos, size) , m_Humidity_tip_popup(AmsHumidityTipPopup(this)) , m_percent_humidity_dry_popup(new uiAmsPercentHumidityDryPopup(this)) diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 9f232deec10..1ce7080159a 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -18,26 +18,26 @@ namespace Slic3r { namespace GUI { -static const wxColour AMS_TRAY_DEFAULT_COL = wxColour(255, 255, 255); - -wxDEFINE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_LOAD, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_SETTINGS, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_FILAMENT_BACKUP, SimpleEvent); -wxDEFINE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent); -wxDEFINE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_GUIDE_WIKI, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_RETRY, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_SHOW_HUMIDITY_TIPS, wxCommandEvent); -wxDEFINE_EVENT(EVT_AMS_UNSELETED_VAMS, wxCommandEvent); -wxDEFINE_EVENT(EVT_CLEAR_SPEED_CONTROL, wxCommandEvent); - - + static const wxColour AMS_TRAY_DEFAULT_COL = wxColour(255, 255, 255); + wxDEFINE_EVENT(EVT_AMS_EXTRUSION_CALI, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_LOAD, SimpleEvent); + wxDEFINE_EVENT(EVT_AMS_UNLOAD, SimpleEvent); + wxDEFINE_EVENT(EVT_AMS_SETTINGS, SimpleEvent); + wxDEFINE_EVENT(EVT_AMS_FILAMENT_BACKUP, SimpleEvent); + wxDEFINE_EVENT(EVT_AMS_REFRESH_RFID, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_ON_SELECTED, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_ON_FILAMENT_EDIT, wxCommandEvent); + wxDEFINE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_CLIBRATION_AGAIN, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_CLIBRATION_CANCEL, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_GUIDE_WIKI, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_RETRY, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_SHOW_HUMIDITY_TIPS, wxCommandEvent); + wxDEFINE_EVENT(EVT_AMS_UNSELETED_VAMS, wxCommandEvent); + wxDEFINE_EVENT(EVT_CLEAR_SPEED_CONTROL, wxCommandEvent); + + +#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, bool humidity_flag) { if (!ams) return false; @@ -85,11 +85,14 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo if (!MachineObject::is_bbl_filament(it->second->tag_uid) || !remain_flag) { info.material_remain = 100; } else { - info.material_remain = it->second->remain < 0 ? 0 : it->second->remain; - info.material_remain = it->second->remain > 100 ? 100 : info.material_remain; + if(it->second->remain < 0 || it->second->remain > 100) { + info.material_remain = 100;/*ignore the invalid data*/ + } else { + info.material_remain = it->second->remain; + } } - - + + } else { info.can_id = it->second->id; info.material_name = ""; @@ -136,7 +139,7 @@ AMSrefresh::AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint create(parent, wxID_ANY, pos, size); } - AMSrefresh::~AMSrefresh() + AMSrefresh::~AMSrefresh() { if (m_playing_timer) { m_playing_timer->Stop(); @@ -149,7 +152,7 @@ void AMSrefresh::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, con { wxWindow::Create(parent, id, pos, size, wxBORDER_NONE); SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); - + Bind(wxEVT_TIMER, &AMSrefresh::on_timer, this); Bind(wxEVT_PAINT, &AMSrefresh::paintEvent, this); Bind(wxEVT_ENTER_WINDOW, &AMSrefresh::OnEnterWindow, this); @@ -186,7 +189,7 @@ void AMSrefresh::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, con SetMaxSize(AMS_REFRESH_SIZE); } -void AMSrefresh::on_timer(wxTimerEvent &event) +void AMSrefresh::on_timer(wxTimerEvent &event) { //if (m_rotation_angle >= m_rfid_bitmap_list.size()) { // m_rotation_angle = 0; @@ -198,16 +201,17 @@ void AMSrefresh::on_timer(wxTimerEvent &event) void AMSrefresh::PlayLoading() { - if (m_play_loading | m_disable_mode) return; + if (m_play_loading || m_disable_mode) return; + m_play_loading = true; - //m_rotation_angle = 0; m_playing_timer->Start(AMS_REFRESH_PLAY_LOADING_TIMER); Refresh(); } void AMSrefresh::StopLoading() { - if (!m_play_loading | m_disable_mode) return; + if (!m_play_loading || m_disable_mode) return; + m_playing_timer->Stop(); m_play_loading = false; Refresh(); @@ -226,7 +230,7 @@ void AMSrefresh::OnLeaveWindow(wxMouseEvent &evt) } void AMSrefresh::OnClick(wxMouseEvent &evt) { - post_event(wxCommandEvent(EVT_AMS_REFRESH_RFID)); + post_event(wxCommandEvent(EVT_AMS_REFRESH_RFID)); } void AMSrefresh::post_event(wxCommandEvent &&event) @@ -330,13 +334,13 @@ void AMSextruderImage::TurnOn(wxColour col) Refresh(); } -void AMSextruderImage::TurnOff() +void AMSextruderImage::TurnOff() { m_colour = AMS_EXTRUDER_DEF_COLOUR; Refresh(); } -void AMSextruderImage::msw_rescale() +void AMSextruderImage::msw_rescale() { //m_ams_extruder.SetSize(AMS_EXTRUDER_BITMAP_SIZE); //auto image = m_ams_extruder.ConvertToImage(); @@ -344,7 +348,7 @@ void AMSextruderImage::msw_rescale() Refresh(); } -void AMSextruderImage::paintEvent(wxPaintEvent &evt) +void AMSextruderImage::paintEvent(wxPaintEvent &evt) { wxPaintDC dc(this); render(dc); @@ -371,8 +375,8 @@ void AMSextruderImage::render(wxDC &dc) #endif } -void AMSextruderImage::doRender(wxDC &dc) -{ +void AMSextruderImage::doRender(wxDC &dc) +{ auto size = GetSize(); dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(m_colour); @@ -399,6 +403,8 @@ AMSextruderImage::~AMSextruderImage() {} + +//Ams Extruder AMSextruder::AMSextruder(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { create(parent, id, pos, size); } AMSextruder::~AMSextruder() {} @@ -625,7 +631,6 @@ void AMSVirtualRoad::msw_rescale() Refresh(); } - /************************************************* Description:AMSLib **************************************************/ @@ -655,7 +660,6 @@ void AMSLib::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const w SetSize(AMS_CAN_LIB_SIZE); SetMinSize(AMS_CAN_LIB_SIZE); SetMaxSize(AMS_CAN_LIB_SIZE); - auto m_sizer_body = new wxBoxSizer(wxVERTICAL); wxBoxSizer *m_sizer_edit = new wxBoxSizer(wxHORIZONTAL); @@ -765,11 +769,11 @@ void AMSLib::render(wxDC &dc) render_generic_text(dc); } else if (m_ams_model == AMSModel::AMS_LITE) { - render_extra_text(dc); + render_lite_text(dc); } } -void AMSLib::render_extra_text(wxDC& dc) +void AMSLib::render_lite_text(wxDC& dc) { auto tmp_lib_colour = m_info.material_colour; @@ -818,7 +822,6 @@ void AMSLib::render_extra_text(wxDC& dc) } } - if (has_split) { dc.SetFont(::Label::Body_10); auto line_top = m_info.material_name.substr(0, m_info.material_name.find(has_split_char)); @@ -983,11 +986,11 @@ void AMSLib::doRender(wxDC &dc) render_generic_lib(dc); } else if (m_ams_model == AMSModel::AMS_LITE) { - render_extra_lib(dc); + render_lite_lib(dc); } } -void AMSLib::render_extra_lib(wxDC& dc) +void AMSLib::render_lite_lib(wxDC& dc) { wxSize size = GetSize(); @@ -1019,7 +1022,6 @@ void AMSLib::render_extra_lib(wxDC& dc) dc.DrawLine(size.x / 2, size.y / 2, size.x / 2, 0); } - //draw def background dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); dc.SetBrush(wxBrush(AMS_CONTROL_DEF_LIB_BK_COLOUR)); @@ -1387,7 +1389,7 @@ void AMSLib::msw_rescale() Description:AMSRoad **************************************************/ AMSRoad::AMSRoad() : m_road_def_color(AMS_CONTROL_GRAY500), m_road_color(AMS_CONTROL_GRAY500) {} -AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos, const wxSize &size) +AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, int maxcan, const wxPoint &pos, const wxSize &size) : AMSRoad() { m_info = info; @@ -1417,7 +1419,7 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in create(parent, id, pos, virtual_size); } - + Bind(wxEVT_PAINT, &AMSRoad::paintEvent, this); wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); } @@ -1533,7 +1535,7 @@ void AMSRoad::doRender(wxDC &dc) if (m_road_color.Alpha() == 0) {dc.SetPen(wxPen(*wxWHITE, m_passroad_width, wxPENSTYLE_SOLID));} else {dc.SetPen(wxPen(m_road_color, m_passroad_width, wxPENSTYLE_SOLID));} - + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); // left pass mode @@ -1626,9 +1628,9 @@ AMSPreview::AMSPreview() {} AMSPreview::AMSPreview(wxWindow *parent, wxWindowID id, AMSinfo amsinfo, const wxSize cube_size, const wxPoint &pos, const wxSize &size) : AMSPreview() { - m_amsinfo = amsinfo; - m_cube_size = cube_size; create(parent, id, pos, AMS_ITEM_SIZE); + m_amsinfo = amsinfo; + m_cube_size = cube_size; Bind(wxEVT_PAINT, &AMSPreview::paintEvent, this); Bind(wxEVT_ENTER_WINDOW, &AMSPreview::OnEnterWindow, this); Bind(wxEVT_LEAVE_WINDOW, &AMSPreview::OnLeaveWindow, this); @@ -2037,7 +2039,9 @@ AmsItem::AmsItem(wxWindow *parent,AMSinfo info, AMSModel model) : AmsItem() m_info = info; wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE); + create(parent); + Bind(wxEVT_PAINT, &AmsItem::paintEvent, this); } @@ -2092,6 +2096,7 @@ void AmsItem::create(wxWindow *parent) SetSizer(sizer_can); } + Layout(); Fit(); Thaw(); @@ -2099,8 +2104,8 @@ void AmsItem::create(wxWindow *parent) void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* sizer) { - auto amscan = new wxWindow(this, wxID_ANY); + amscan->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); @@ -2130,14 +2135,12 @@ void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size ev.Skip(); }); - - m_panel_lib->m_ams_model = m_ams_model; - m_panel_lib->m_ams_id = m_info.ams_id; - m_panel_lib->m_slot_id = caninfo.can_id; + m_panel_lib->m_ams_model = m_ams_model; + m_panel_lib->m_ams_id = m_info.ams_id; + m_panel_lib->m_slot_id = caninfo.can_id; m_panel_lib->m_info.can_id = caninfo.can_id; m_panel_lib->m_can_index = canindex; - auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); if (m_ams_model == AMSModel::GENERIC_AMS) { @@ -2161,8 +2164,6 @@ void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER, 0); } } - - amscan->SetSizer(m_sizer_ams); amscan->Layout(); amscan->Fit(); @@ -2204,7 +2205,7 @@ void AmsItem::Update(AMSinfo info) refresh->Show(); } } - + for (int i = 0; i < m_can_lib_list.size(); i++) { AMSLib* lib = m_can_lib_list[std::to_string(i)]; if (lib != nullptr){ @@ -2231,6 +2232,7 @@ void AmsItem::Update(AMSinfo info) } } } + Layout(); } @@ -2250,8 +2252,8 @@ void AmsItem::SelectCan(std::string canid) { for (auto lib_it : m_can_lib_list) { AMSLib* lib = lib_it.second; - if (lib->m_info.can_id == canid) { - m_canlib_selection = lib->m_can_index; + if (lib->m_info.can_id == canid) { + m_canlib_selection = lib->m_can_index; } } @@ -2270,7 +2272,7 @@ void AmsItem::SelectCan(std::string canid) } } -wxColour AmsItem::GetTagColr(wxString canid) +wxColour AmsItem::GetTagColr(wxString canid) { auto tag_colour = *wxWHITE; for (auto lib_it : m_can_lib_list) { @@ -2295,7 +2297,6 @@ void AmsItem::SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadS void AmsItem::SetAmsStep(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step) { - if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { for (auto road_it : m_can_road_list) { AMSRoad* road = road_it.second; @@ -2548,7 +2549,7 @@ void AmsItem::StopRridLoading(wxString canid) } } -void AmsItem::msw_rescale() +void AmsItem::msw_rescale() { for (auto refresh_it : m_can_refresh_list) { AMSrefresh* refresh = refresh_it.second; diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 9132bedbea5..8eb7c3812ab 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -28,11 +28,6 @@ #define AMS_CONTROL_MAX_COUNT 4 #define AMS_CONTRO_CALIBRATION_BUTTON_SIZE wxSize(FromDIP(150), FromDIP(28)) -// enum AMSRoadMode{ -// AMS_ROAD_MODE_LEFT, -// AMS_ROAD_MODE_LEFT_RIGHT, -// AMS_ROAD_MODE_END, -//}; namespace Slic3r { namespace GUI { @@ -118,6 +113,7 @@ enum FilamentStep { STEP_COUNT, }; + enum FilamentStepType { STEP_TYPE_LOAD = 0, STEP_TYPE_UNLOAD = 1, @@ -130,8 +126,8 @@ enum FilamentStepType { #define AMS_CAN_LIB_SIZE wxSize(FromDIP(58), FromDIP(80)) #define AMS_CAN_ROAD_SIZE wxSize(FromDIP(66), FromDIP(70)) #define AMS_CAN_ITEM_HEIGHT_SIZE FromDIP(27) -#define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(196)) -#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) +//#define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(196)) +//#define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) #define AMS_STEP_SIZE wxSize(FromDIP(172), FromDIP(196)) #define AMS_REFRESH_SIZE wxSize(FromDIP(30), FromDIP(30)) #define AMS_EXTRUDER_SIZE wxSize(FromDIP(86), FromDIP(72)) @@ -428,10 +424,10 @@ class AMSLib : public wxWindow void on_left_down(wxMouseEvent &evt); void paintEvent(wxPaintEvent &evt); void render(wxDC &dc); - void render_extra_text(wxDC& dc); + void render_lite_text(wxDC& dc); void render_generic_text(wxDC& dc); void doRender(wxDC& dc); - void render_extra_lib(wxDC& dc); + void render_lite_lib(wxDC& dc); void render_generic_lib(wxDC& dc); }; From 4425f91caa2738bbd5f860cfe16869af817989d8 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 21 May 2025 21:18:53 +0800 Subject: [PATCH 086/127] Fix AMS update --- src/slic3r/GUI/Widgets/AMSControl.cpp | 217 ++++++++++++++++---------- src/slic3r/GUI/Widgets/AMSControl.hpp | 7 +- src/slic3r/GUI/Widgets/AMSItem.cpp | 22 +-- src/slic3r/GUI/Widgets/AMSItem.hpp | 3 + 4 files changed, 151 insertions(+), 98 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 9132f5541de..880d1cd9a20 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -123,8 +123,8 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_sizer_cans->Add(m_simplebook_ams, 0, wxLEFT | wxLEFT, FromDIP(10)); // ams mode - m_simplebook_generic_cans = new wxSimplebook(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); - m_simplebook_generic_cans->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + m_simplebook_generic_ams = new wxSimplebook(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); + m_simplebook_generic_ams->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); // none ams mode m_none_ams_panel = new wxPanel(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); @@ -145,12 +145,12 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons m_none_ams_panel->Layout(); //extra ams mode - m_simplebook_extra_cans = new wxSimplebook(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); - m_simplebook_extra_cans->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + m_simplebook_extra_ams = new wxSimplebook(m_simplebook_ams, wxID_ANY, wxDefaultPosition, AMS_CANS_WINDOW_SIZE, 0); + m_simplebook_extra_ams->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); m_simplebook_ams->AddPage(m_none_ams_panel, wxEmptyString, false); - m_simplebook_ams->AddPage(m_simplebook_generic_cans, wxEmptyString, false); - m_simplebook_ams->AddPage(m_simplebook_extra_cans, wxEmptyString, false); + m_simplebook_ams->AddPage(m_simplebook_generic_ams, wxEmptyString, false); + m_simplebook_ams->AddPage(m_simplebook_extra_ams, wxEmptyString, false); m_panel_can->SetSizer(m_sizer_cans); m_panel_can->Layout(); @@ -594,8 +594,6 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons post_event(wxCommandEvent(EVT_AMS_RETRY)); }); - CreateAms(); - SetSelection(0); EnterNoneAMSMode(); } @@ -905,24 +903,52 @@ void AMSControl::CreateAms() Thaw(); } -void AMSControl::Reset() + +void AMSControl::ClearAms() { + m_simplebook_generic_ams->DeleteAllPages(); + m_simplebook_extra_ams->DeleteAllPages(); + m_simplebook_generic_ams->DestroyChildren(); + m_simplebook_extra_ams->DestroyChildren(); + m_simplebook_generic_ams->Layout(); + m_simplebook_extra_ams->Layout(); + m_simplebook_generic_ams->Refresh(); + m_simplebook_extra_ams->Refresh(); + + for (auto it : m_ams_preview_list) { + delete it.second; + } + m_ams_preview_list.clear(); + + m_current_show_ams = ""; + m_current_ams = ""; + m_current_select = ""; + + m_ams_item_list.clear(); + m_sizer_prv->Clear(); +} + +void AMSControl::CreateAmsSingleNozzle() { - auto caninfo0_0 = Caninfo{"0", "", *wxWHITE, AMSCanType::AMS_CAN_TYPE_NONE}; - auto caninfo0_1 = Caninfo{"1", "", *wxWHITE, AMSCanType::AMS_CAN_TYPE_NONE}; - auto caninfo0_2 = Caninfo{"2", "", *wxWHITE, AMSCanType::AMS_CAN_TYPE_NONE}; - auto caninfo0_3 = Caninfo{"3", "", *wxWHITE, AMSCanType::AMS_CAN_TYPE_NONE}; + //add ams data + for (auto ams_info = m_ams_info.begin(); ams_info != m_ams_info.end(); ams_info++) { + if (ams_info->cans.size() == GENERIC_AMS_SLOT_NUM) { + AddAmsPreview(*ams_info); + AddAms(*ams_info); + AddExtraAms(*ams_info); + } + else if (ams_info->cans.size() == 1) { + AddAmsPreview(*ams_info); + AddAms(*ams_info); + } + } +} - AMSinfo ams1 = AMSinfo{"0", std::vector{caninfo0_0, caninfo0_1, caninfo0_2, caninfo0_3}}; - AMSinfo ams2 = AMSinfo{"1", std::vector{caninfo0_0, caninfo0_1, caninfo0_2, caninfo0_3}}; - AMSinfo ams3 = AMSinfo{"2", std::vector{caninfo0_0, caninfo0_1, caninfo0_2, caninfo0_3}}; - AMSinfo ams4 = AMSinfo{"3", std::vector{caninfo0_0, caninfo0_1, caninfo0_2, caninfo0_3}}; +void AMSControl::Reset() +{ + m_ams_info.clear(); + ClearAms(); - std::vector ams_info{ams1, ams2, ams3, ams4}; - std::vector::iterator it; - UpdateAms(ams_info, true); - m_current_show_ams = ""; - m_current_ams = ""; - m_current_select = ""; + Layout(); } void AMSControl::show_noams_mode() @@ -1007,79 +1033,102 @@ void AMSControl::reset_vams() } -void AMSControl::UpdateAms(std::vector info, bool is_reset) +void AMSControl::UpdateAms(std::vector ams_info, bool is_reset) { - std::string curr_ams_id = GetCurentAms(); - std::string curr_can_id = GetCurrentCan(curr_ams_id); - m_button_area->Layout(); - m_button_area->Fit(); + m_button_area->Fit(); - // update item - m_ams_info = info; - if (m_ams_model == AMSModel::GENERIC_AMS){ - m_ams_item_list = m_ams_generic_item_list; - } - else if (m_ams_model == AMSModel::AMS_LITE) { - m_ams_item_list = m_ams_extra_item_list; - } + /*if (!test)*/{ + // update item + bool fresh = false; - if (info.size() > 1) { - m_simplebook_amsprvs->Show(); - m_amswin->Layout(); - m_amswin->Fit(); - SetSize(m_amswin->GetSize()); - SetMinSize(m_amswin->GetSize()); - } else { - m_simplebook_amsprvs->Hide(); - m_amswin->Layout(); - m_amswin->Fit(); - SetSize(m_amswin->GetSize()); - SetMinSize(m_amswin->GetSize()); - } + // basic check + if (m_ams_info.size() == ams_info.size() ) { + for (int i = 0; i < m_ams_info.size(); i++){ + if (m_ams_info[i].ams_id != ams_info[i].ams_id){ + fresh = true; + } + } + } + else{ + fresh = true; + } - size_t i = 0; - for (auto prv_it : m_ams_preview_list) { - AMSPreview* prv = prv_it.second; - if (i < info.size() && info.size() > 1) { - prv->Update(m_ams_info[i]); - prv->Open(); + m_ams_info.clear(); + m_ams_info = ams_info; + if (fresh){ + ClearAms(); + //if (m_extder_data.total_extder_count >= 2){ + // CreateAmsDoubleNozzle(series_name, printer_type); + //}else{ + CreateAmsSingleNozzle(); + //} + SetSize(wxSize(FromDIP(578), -1)); + SetMinSize(wxSize(FromDIP(578), -1)); + Layout(); + } + + if (m_ams_model == AMSModel::GENERIC_AMS){ + m_ams_item_list = m_ams_generic_item_list; + } + else if (m_ams_model == AMSModel::AMS_LITE) { + m_ams_item_list = m_ams_extra_item_list; + } + + if (ams_info.size() > 1) { + m_simplebook_amsprvs->Show(); + m_amswin->Layout(); + m_amswin->Fit(); + SetSize(m_amswin->GetSize()); + SetMinSize(m_amswin->GetSize()); } else { - prv->Close(); + m_simplebook_amsprvs->Hide(); + m_amswin->Layout(); + m_amswin->Fit(); + SetSize(m_amswin->GetSize()); + SetMinSize(m_amswin->GetSize()); } - i++; - } - // update cans - for (auto ams_item : m_ams_item_list) { - if (ams_item.second == nullptr) { - continue; + // update cans + + for (auto ams_item : m_ams_item_list) { + if (ams_item.second == nullptr){ + continue; + } + std::string ams_id = ams_item.second->get_ams_id(); + AmsItem* cans = ams_item.second; + for (auto ifo : m_ams_info) { + if (ifo.ams_id == ams_id) { + cans->Update(ifo); + cans->show_sn_value(m_ams_model == AMSModel::AMS_LITE?false:true); + } + } } - std::string ams_id = ams_item.second->get_ams_id(); - AmsItem* cans = ams_item.second; - for (auto ifo : m_ams_info) { - if (ifo.ams_id == ams_id) { - cans->Update(ifo); - cans->show_sn_value(m_ams_model == AMSModel::AMS_LITE?false:true); + + for (auto ams_prv : m_ams_preview_list) { + std::string id = ams_prv.second->get_ams_id(); + auto item = m_ams_item_list.find(id); + if (item != m_ams_item_list.end()) + { ams_prv.second->Update(item->second->get_ams_info()); } } - } - if ( m_current_show_ams.empty() && !is_reset ) { - if (info.size() > 0) { - SwitchAms(info[0].ams_id); + if ( m_current_show_ams.empty() && !is_reset ) { + if (ams_info.size() > 0) { + SwitchAms(ams_info[0].ams_id); + } } - } - if (m_ams_model == AMSModel::EXT_AMS && !m_vams_lib->is_selected()) { - m_vams_lib->OnSelected(); + if (m_ams_model == AMSModel::EXT_AMS && !m_vams_lib->is_selected()) { + m_vams_lib->OnSelected(); + } } /*update humidity popup*/ if (m_percent_humidity_dry_popup->IsShown()) { string target_id = m_percent_humidity_dry_popup->get_owner_ams_id(); - for (const auto& the_info : info) + for (const auto& the_info : ams_info) { if (target_id == the_info.ams_id) { @@ -1110,18 +1159,18 @@ void AMSControl::AddAmsPreview(AMSinfo info) void AMSControl::AddAms(AMSinfo info) { - auto ams_item = new AmsItem(m_simplebook_generic_cans, info, AMSModel::GENERIC_AMS); - m_simplebook_generic_cans->AddPage(ams_item, wxEmptyString, false); - ams_item->set_selection(m_simplebook_generic_cans->GetPageCount() - 1); + auto ams_item = new AmsItem(m_simplebook_generic_ams, info, AMSModel::GENERIC_AMS); + m_simplebook_generic_ams->AddPage(ams_item, wxEmptyString, false); + ams_item->set_selection(m_simplebook_generic_ams->GetPageCount() - 1); m_ams_generic_item_list[info.ams_id] = ams_item; } void AMSControl::AddExtraAms(AMSinfo info) { - auto ams_item = new AmsItem(m_simplebook_extra_cans, info, AMSModel::AMS_LITE); - m_simplebook_extra_cans->AddPage(ams_item, wxEmptyString, false); - ams_item->set_selection(m_simplebook_extra_cans->GetPageCount() - 1); + auto ams_item = new AmsItem(m_simplebook_extra_ams, info, AMSModel::AMS_LITE); + m_simplebook_extra_ams->AddPage(ams_item, wxEmptyString, false); + ams_item->set_selection(m_simplebook_extra_ams->GetPageCount() - 1); m_ams_extra_item_list[info.ams_id] = ams_item; } @@ -1177,10 +1226,10 @@ void AMSControl::SwitchAms(std::string ams_id) if (item->get_ams_id() == ams_id) { if (m_ams_model == AMSModel::GENERIC_AMS) { - m_simplebook_generic_cans->SetSelection(item->get_selection()); + m_simplebook_generic_ams->SetSelection(item->get_selection()); } else if (m_ams_model == AMSModel::AMS_LITE) { - m_simplebook_extra_cans->SetSelection(item->get_selection()); + m_simplebook_extra_ams->SetSelection(item->get_selection()); } } } diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 3cee1520e80..67158afe88f 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -48,9 +48,8 @@ class AMSControl : public wxSimplebook wxSimplebook *m_simplebook_calibration = {nullptr}; wxSimplebook *m_simplebook_amsprvs = {nullptr}; wxSimplebook *m_simplebook_ams = {nullptr}; - - wxSimplebook *m_simplebook_generic_cans= {nullptr}; - wxSimplebook *m_simplebook_extra_cans = {nullptr}; + wxSimplebook* m_simplebook_generic_ams = {nullptr}; + wxSimplebook* m_simplebook_extra_ams = {nullptr}; wxSimplebook *m_simplebook_bottom = {nullptr}; @@ -133,6 +132,8 @@ class AMSControl : public wxSimplebook void UpdateStepCtrl(bool is_extrusion_exist); void CreateAms(); + void CreateAmsSingleNozzle(); + void ClearAms(); void UpdateAms(std::vector info, bool is_reset = true); void AddAms(AMSinfo info); void AddAmsPreview(AMSinfo info); diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 1ce7080159a..c2b2b998b2e 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -151,7 +151,7 @@ AMSrefresh::AMSrefresh(wxWindow *parent, int number, Caninfo info, const wxPoint void AMSrefresh::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size, wxBORDER_NONE); - SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); Bind(wxEVT_TIMER, &AMSrefresh::on_timer, this); Bind(wxEVT_PAINT, &AMSrefresh::paintEvent, this); @@ -249,7 +249,7 @@ void AMSrefresh::paintEvent(wxPaintEvent &evt) wxPaintDC dc(this); auto colour = StateColor::darkModeColorFor(AMS_CONTROL_GRAY700); - if (!wxWindow::IsEnabled()) { colour = AMS_CONTROL_GRAY500; } + if (!wxWindow::IsEnabled()) { colour = StateColor::darkModeColorFor(AMS_CONTROL_GRAY500); } auto pot = wxPoint((size.x - m_bitmap_selected.GetBmpSize().x) / 2, (size.y - m_bitmap_selected.GetBmpSize().y) / 2); @@ -277,6 +277,7 @@ void AMSrefresh::paintEvent(wxPaintEvent &evt) dc.SetPen(wxPen(colour)); dc.SetBrush(wxBrush(colour)); dc.SetFont(Label::Body_11); + //dc.SetTextForeground(StateColor::darkModeColorFor(AMS_CONTROL_BLACK_COLOUR)); dc.SetTextForeground(colour); auto tsize = dc.GetTextExtent(m_refresh_id); pot = wxPoint((size.x - tsize.x) / 2, (size.y - tsize.y) / 2); @@ -388,7 +389,7 @@ void AMSextruderImage::doRender(wxDC &dc) AMSextruderImage::AMSextruderImage(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, AMS_EXTRUDER_BITMAP_SIZE); - SetBackgroundColour(*wxWHITE); + SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); m_ams_extruder = ScalableBitmap(this, "monitor_ams_extruder",55); SetSize(AMS_EXTRUDER_BITMAP_SIZE); @@ -568,7 +569,7 @@ void AMSVirtualRoad::OnVamsLoading(bool load, wxColour col) void AMSVirtualRoad::create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) { wxWindow::Create(parent, id, pos, wxDefaultSize, wxBORDER_NONE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_WHITE_COLOUR)); Layout(); Bind(wxEVT_PAINT, &AMSVirtualRoad::paintEvent, this); } @@ -638,7 +639,7 @@ AMSLib::AMSLib(wxWindow *parent, std::string ams_idx, Caninfo info) { m_border_color = (wxColour(130, 130, 128)); m_road_def_color = AMS_CONTROL_GRAY500; - wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + wxWindow::SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); create(parent); Bind(wxEVT_PAINT, &AMSLib::paintEvent, this); @@ -1024,7 +1025,7 @@ void AMSLib::render_lite_lib(wxDC& dc) //draw def background dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); - dc.SetBrush(wxBrush(AMS_CONTROL_DEF_LIB_BK_COLOUR)); + dc.SetBrush(wxBrush(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR))); dc.DrawRoundedRectangle(FromDIP(10), FromDIP(10), size.x - FromDIP(20), size.y - FromDIP(20), 0); if (tmp_lib_colour.GetLuminance() < 0.6) { @@ -1421,7 +1422,7 @@ AMSRoad::AMSRoad(wxWindow *parent, wxWindowID id, Caninfo info, int canindex, in } Bind(wxEVT_PAINT, &AMSRoad::paintEvent, this); - wxWindow::SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + wxWindow::SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); } void AMSRoad::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) { wxWindow::Create(parent, id, pos, size); } @@ -1659,7 +1660,7 @@ void AMSPreview::create(wxWindow *parent, wxWindowID id, const wxPoint &pos, con wxWindow::Create(parent, id, pos, size); SetMinSize(AMS_ITEM_SIZE); SetMaxSize(AMS_ITEM_SIZE); - SetBackgroundColour(AMS_CONTROL_WHITE_COLOUR); + SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_WHITE_COLOUR)); Refresh(); } @@ -2042,14 +2043,13 @@ AmsItem::AmsItem(wxWindow *parent,AMSinfo info, AMSModel model) : AmsItem() create(parent); + SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); Bind(wxEVT_PAINT, &AmsItem::paintEvent, this); } void AmsItem::create(wxWindow *parent) { Freeze(); - SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); - if (m_ams_model == AMSModel::GENERIC_AMS || m_ams_model == AMSModel::N3F_AMS || m_ams_model == AMSModel::N3S_AMS) { sizer_can = new wxBoxSizer(wxHORIZONTAL); sizer_item = new wxBoxSizer(wxVERTICAL); @@ -2106,7 +2106,7 @@ void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size { auto amscan = new wxWindow(this, wxID_ANY); - amscan->SetBackgroundColour(AMS_CONTROL_DEF_LIB_BK_COLOUR); + amscan->SetBackgroundColour(StateColor::darkModeColorFor(AMS_CONTROL_DEF_LIB_BK_COLOUR)); wxBoxSizer* m_sizer_ams = new wxBoxSizer(wxVERTICAL); diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 8eb7c3812ab..2cb771440ec 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -137,6 +137,7 @@ enum FilamentStepType { #define AMS_HUMIDITY_NO_PERCENT_SIZE wxSize(FromDIP(60), FromDIP(26)) #define AMS_HUMIDITY_DRY_WIDTH FromDIP(35) +#define GENERIC_AMS_SLOT_NUM 4 struct Caninfo { @@ -575,6 +576,8 @@ class AmsItem : public wxWindow std::string GetCurrentCan(); public: + AMSinfo get_ams_info() const { return m_info; }; + std::string get_ams_id() const { return m_info.ams_id; }; std::map get_can_lib_list() const { return m_can_lib_list; }; From 8b43ecca30db689c9e499296103a6f130c5435d1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 21 May 2025 23:18:54 +0800 Subject: [PATCH 087/127] Fix AMS HT slot render alignment --- src/slic3r/GUI/Widgets/AMSItem.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index c2b2b998b2e..d82e02d20e2 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -1561,7 +1561,7 @@ void AMSRoad::doRender(wxDC &dc) } // end mode - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END) { dc.SetPen(wxPen(m_road_def_color, 2, wxPENSTYLE_SOLID)); dc.SetBrush(wxBrush(m_road_def_color)); dc.DrawRoundedRectangle(size.x * 0.37 / 2, size.y * 0.6 - size.y / 6, size.x * 0.63, size.y / 3, m_radius); @@ -1608,7 +1608,7 @@ void AMSRoad::OnPassRoad(std::vector prord_list) } // left end - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END) { for (auto i = 0; i < prord_list.size(); i++) { std::vector::iterator iter = std::find(end_types.begin(), end_types.end(), prord_list[i]); if (iter != end_types.end()) m_pass_rode_mode.push_back(prord_list[i]); @@ -2059,7 +2059,7 @@ void AmsItem::create(wxWindow *parent) } m_humidity = new AMSHumidity(this, wxID_ANY, m_info); sizer_item->Add(m_humidity, 0, wxALIGN_CENTER_HORIZONTAL, 0); - sizer_item->Add(sizer_can, 0, wxALIGN_CENTER_HORIZONTAL, 0); + sizer_item->Add(sizer_can, 0, wxALIGN_LEFT, 0); SetSizer(sizer_item); } else if(m_ams_model == AMSModel::AMS_LITE) { @@ -2420,11 +2420,10 @@ void AmsItem::render(wxDC& dc) void AmsItem::doRender(wxDC& dc) { - wxSize size = GetSize(); - dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); - //road for extra if (m_ams_model == AMSModel::AMS_LITE) { + wxSize size = GetSize(); + dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); auto end_top = size.x / 2 - FromDIP(99); auto passroad_width = 6; From 4339bd308eae4cc8662d8448950b9350f717cd5b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 22 May 2025 17:01:48 +0800 Subject: [PATCH 088/127] Ensure log is flushed so we could know what happened before crash --- src/slic3r/GUI/DeviceManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index cbe7b2836f8..a4ddfb7b2cb 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -2811,6 +2811,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) { #ifdef ORCA_NETWORK_DEBUG BOOST_LOG_TRIVIAL(info) << "parse_json: payload = " << payload; + flush_logs(); #endif parse_msg_count++; From b88b1e48197ba01a8eba5cdfdfd008c1387e56c1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 22 May 2025 17:51:48 +0800 Subject: [PATCH 089/127] Fix AMS HT display if it's the only AMS (cherry picked from commit bambulab/BambuStudio@a182fa1aa4a3bdd32c4ccfa26adcd92a9f1cca37) --------- Co-authored-by: tao wang --- src/slic3r/GUI/DeviceManager.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index a4ddfb7b2cb..55dc449dc86 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4059,17 +4059,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) Ams* curr_ams = nullptr; auto ams_it = amsList.find(ams_id); if (ams_it == amsList.end()) { - Ams* new_ams = new Ams(ams_id, nozzle_id, type_id); - - try { - if (!ams_id.empty()) { - int ams_id_int = atoi(ams_id.c_str()); - new_ams->is_exists = (ams_exist_bits & (1 << ams_id_int)) != 0 ? true : false; - } - } - catch (...) { - ; - } + Ams* new_ams = new Ams(ams_id, nozzle_id, type_id); amsList.insert(std::make_pair(ams_id, new_ams)); // new ams added event curr_ams = new_ams; @@ -4078,6 +4068,25 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } if (!curr_ams) continue; + /*set ams type flag*/ + curr_ams->type = type_id; + + + /*set ams exist flag*/ + try { + if (!ams_id.empty()) { + int ams_id_int = atoi(ams_id.c_str()); + + if (type_id < 4) { + curr_ams->is_exists = (ams_exist_bits & (1 << ams_id_int)) != 0 ? true : false; + } else { + curr_ams->is_exists = get_flag_bits(ams_exist_bits, 4 + (ams_id_int - 128)); + } + } + } catch (...) { + ; + } + if (it->contains("dry_time") && (*it)["dry_time"].is_number()) { curr_ams->left_dry_time = (*it)["dry_time"].get(); From b5c164fae69e1392cff6f5ac16ff7fc53a67f311 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 22 May 2025 18:03:20 +0800 Subject: [PATCH 090/127] Fix crash when switching between printers with different AMS configs --- src/slic3r/GUI/Widgets/AMSControl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 880d1cd9a20..f2f35df3953 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -923,6 +923,8 @@ void AMSControl::ClearAms() { m_current_ams = ""; m_current_select = ""; + m_ams_generic_item_list.clear(); + m_ams_extra_item_list.clear(); m_ams_item_list.clear(); m_sizer_prv->Clear(); } From 625a946e254cae8d1632a756fae5c3b218d341e8 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Thu, 22 May 2025 21:54:15 +0800 Subject: [PATCH 091/127] FIX:update load/unload command for n3s (cherry picked from commit bambulab/BambuStudio@fc32042639cc83cc6876e63b86c944671649955c) --------- Co-authored-by: tao wang --- src/slic3r/GUI/DeviceManager.cpp | 93 ++++++++++++++++++++------------ src/slic3r/GUI/DeviceManager.hpp | 5 +- src/slic3r/GUI/StatusPanel.cpp | 63 ++++++++++++++++------ 3 files changed, 110 insertions(+), 51 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 55dc449dc86..11682a50584 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1868,45 +1868,71 @@ int MachineObject::command_set_chamber(int temp) return this->publish_json(j.dump(), 1); } -int MachineObject::command_ams_switch(int tray_index, int old_temp, int new_temp) +//int MachineObject::command_ams_switch(int tray_index, int old_temp, int new_temp) +//{ +// BOOST_LOG_TRIVIAL(trace) << "ams_switch to " << tray_index << " with temp: " << old_temp << ", " << new_temp; +// if (old_temp < 0) old_temp = FILAMENT_DEF_TEMP; +// if (new_temp < 0) new_temp = FILAMENT_DEF_TEMP; +// +// std::string gcode = ""; +// int result = 0; +// +// //command +// if (is_support_command_ams_switch) { +// command_ams_change_filament(tray_index, old_temp, new_temp); +// } +// else { +// std::string gcode = ""; +// if (tray_index == 255) { +// gcode = DeviceManager::load_gcode(printer_type, "ams_unload.gcode"); +// } +// else { +// // include VIRTUAL_TRAY_ID +// gcode = DeviceManager::load_gcode(printer_type, "ams_load.gcode"); +// boost::replace_all(gcode, "[next_extruder]", std::to_string(tray_index)); +// boost::replace_all(gcode, "[new_filament_temp]", std::to_string(new_temp)); +// } +// +// result = this->publish_gcode(gcode); +// } +// +// return result; +//} + +int MachineObject::command_ams_change_filament(bool load, std::string ams_id, std::string slot_id, int old_temp, int new_temp) { - BOOST_LOG_TRIVIAL(trace) << "ams_switch to " << tray_index << " with temp: " << old_temp << ", " << new_temp; - if (old_temp < 0) old_temp = FILAMENT_DEF_TEMP; - if (new_temp < 0) new_temp = FILAMENT_DEF_TEMP; + json j; + try { + auto tray_id = 0; + if (ams_id < "16") { + tray_id = atoi(ams_id.c_str()) * 4 + atoi(slot_id.c_str()); + } + // TODO: Orca hack + if (ams_id == "254") + ams_id = "255"; - std::string gcode = ""; - int result = 0; - //command - if (is_support_command_ams_switch) { - command_ams_change_filament(tray_index, old_temp, new_temp); - } - else { - std::string gcode = ""; - if (tray_index == 255) { - gcode = DeviceManager::load_gcode(printer_type, "ams_unload.gcode"); - } - else { - // include VIRTUAL_TRAY_ID - gcode = DeviceManager::load_gcode(printer_type, "ams_load.gcode"); - boost::replace_all(gcode, "[next_extruder]", std::to_string(tray_index)); - boost::replace_all(gcode, "[new_filament_temp]", std::to_string(new_temp)); - } + j["print"]["command"] = "ams_change_filament"; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["curr_temp"] = old_temp; + j["print"]["tar_temp"] = new_temp; + j["print"]["ams_id"] = atoi(ams_id.c_str()); - result = this->publish_gcode(gcode); - } + if (!load) { + j["print"]["target"] = 255; + j["print"]["slot_id"] = 255; // the new protocol to mark unload - return result; -} + } else { + if (tray_id == 0) { + j["print"]["target"] = atoi(ams_id.c_str()); + } else { + j["print"]["target"] = tray_id; + } + + j["print"]["slot_id"] = atoi(slot_id.c_str()); + } + } catch (const std::exception &) {} -int MachineObject::command_ams_change_filament(int tray_id, int old_temp, int new_temp) -{ - json j; - j["print"]["command"] = "ams_change_filament"; - j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - j["print"]["target"] = tray_id; - j["print"]["curr_temp"] = old_temp; - j["print"]["tar_temp"] = new_temp; return this->publish_json(j.dump()); } @@ -3308,6 +3334,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("flag3")) { int flag3 = jj["flag3"].get(); is_support_filament_setting_inprinting = get_flag_bits(flag3, 3); + is_enable_ams_np = get_flag_bits(flag3, 9); } } if (!key_field_only) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index a37f32e995c..ba9dc58a17c 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -929,8 +929,8 @@ class MachineObject int command_set_nozzle(int temp); int command_set_chamber(int temp); // ams controls - int command_ams_switch(int tray_index, int old_temp = 210, int new_temp = 210); - int command_ams_change_filament(int tray_id, int old_temp = 210, int new_temp = 210); + //int command_ams_switch(int tray_index, int old_temp = 210, int new_temp = 210); + int command_ams_change_filament(bool load, std::string ams_id, std::string slot_id, int old_temp = 210, int new_temp = 210); int command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt, bool remain_flag = false); int command_ams_switch_filament(bool switch_filament); int command_ams_air_print_detect(bool air_print_detect); @@ -1042,6 +1042,7 @@ class MachineObject /*for more extruder*/ bool is_enable_np{ false }; + bool is_enable_ams_np{ false }; ExtderData m_extder_data; diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 9ab501843c9..9fe5ac1ff7c 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3432,7 +3432,7 @@ void StatusPanel::on_axis_ctrl_e_down_10(wxCommandEvent &event) void StatusPanel::on_start_unload(wxCommandEvent &event) { - if (obj) obj->command_ams_switch(255); + if (obj) obj->command_ams_change_filament(false, "255", "255"); } void StatusPanel::on_set_bed_temp() @@ -3518,10 +3518,11 @@ void StatusPanel::on_ams_load_curr() std::string curr_ams_id = m_ams_control->GetCurentAms(); std::string curr_can_id = m_ams_control->GetCurrentCan(curr_ams_id); - + update_filament_step(); //virtual tray - if (curr_ams_id.compare(std::to_string(VIRTUAL_TRAY_ID)) == 0) { + if (curr_ams_id.compare(std::to_string(VIRTUAL_TRAY_ID)) == 0) + { int old_temp = -1; int new_temp = -1; AmsTray* curr_tray = &obj->vt_tray; @@ -3531,13 +3532,22 @@ void StatusPanel::on_ams_load_curr() try { if (!curr_tray->nozzle_temp_max.empty() && !curr_tray->nozzle_temp_min.empty()) old_temp = (atoi(curr_tray->nozzle_temp_min.c_str()) + atoi(curr_tray->nozzle_temp_max.c_str())) / 2; - if (!obj->vt_tray.nozzle_temp_max.empty() && !obj->vt_tray.nozzle_temp_min.empty()) - new_temp = (atoi(obj->vt_tray.nozzle_temp_min.c_str()) + atoi(obj->vt_tray.nozzle_temp_max.c_str())) / 2; + if (!curr_tray->nozzle_temp_max.empty() && !curr_tray->nozzle_temp_min.empty()) + new_temp = (atoi(curr_tray->nozzle_temp_min.c_str()) + atoi(curr_tray->nozzle_temp_max.c_str())) / 2; } catch (...) { ; } - obj->command_ams_switch(VIRTUAL_TRAY_ID, old_temp, new_temp); + + if (obj->is_enable_np || obj->is_enable_ams_np) { + try { + if (!curr_ams_id.empty() && !curr_can_id.empty()) { + obj->command_ams_change_filament(true, curr_ams_id, "0", old_temp, new_temp); + } + } catch (...) {} + } else { + obj->command_ams_change_filament(true, "254", "0", old_temp, new_temp); + } } std::map::iterator it = obj->amsList.find(curr_ams_id); @@ -3552,24 +3562,32 @@ void StatusPanel::on_ams_load_curr() } AmsTray* curr_tray = obj->get_curr_tray(); AmsTray* targ_tray = obj->get_ams_tray(curr_ams_id, curr_can_id); + + int old_temp = -1; + int new_temp = -1; + if (curr_tray && targ_tray) { - int old_temp = -1; - int new_temp = -1; try { if (!curr_tray->nozzle_temp_max.empty() && !curr_tray->nozzle_temp_min.empty()) old_temp = (atoi(curr_tray->nozzle_temp_min.c_str()) + atoi(curr_tray->nozzle_temp_max.c_str())) / 2; if (!targ_tray->nozzle_temp_max.empty() && !targ_tray->nozzle_temp_min.empty()) new_temp = (atoi(targ_tray->nozzle_temp_min.c_str()) + atoi(targ_tray->nozzle_temp_max.c_str())) / 2; - } - catch (...) { + } catch (...) { ; } - int tray_index = atoi(curr_ams_id.c_str()) * 4 + atoi(tray_it->second->id.c_str()); - obj->command_ams_switch(tray_index, old_temp, new_temp); } - else { - int tray_index = atoi(curr_ams_id.c_str()) * 4 + atoi(tray_it->second->id.c_str()); - obj->command_ams_switch(tray_index, -1, -1); + + int tray_index = atoi(curr_ams_id.c_str()) * 4 + atoi(tray_it->second->id.c_str()); + + if (obj->is_enable_np) { + try { + if (!curr_ams_id.empty() && !curr_can_id.empty()) { + obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp); + } + } + catch (...){} + } else { + obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp); } } } @@ -3586,7 +3604,20 @@ void StatusPanel::on_ams_load_vams(wxCommandEvent& event) { void StatusPanel::on_ams_unload(SimpleEvent &event) { - if (obj) { obj->command_ams_switch(255); } + if (obj) { + std::string curr_ams_id = m_ams_control->GetCurentAms(); + std::string curr_can_id = m_ams_control->GetCurrentCan(curr_ams_id); + + if (obj->is_enable_np) { + try { + for (auto ext : obj->m_extder_data.extders) { + if (ext.snow.ams_id == curr_ams_id && ext.snow.slot_id == curr_can_id) { obj->command_ams_change_filament(false, curr_ams_id, "255"); } + } + } catch (...) {} + } else { + obj->command_ams_change_filament(false, curr_ams_id, "255"); + } + } } void StatusPanel::on_ams_filament_backup(SimpleEvent& event) From 56b6e0742eeee04dac8fd2230909269cb748568f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 23 May 2025 10:11:26 +0800 Subject: [PATCH 092/127] Fix AMS HT filament road rendering (cherry picked from commit bambulab/BambuStudio@afbf3cf1976623c9a443f3471ec7ddcfb737d031) --------- Co-authored-by: tao wang --- src/slic3r/GUI/DeviceManager.cpp | 32 ++++++++++++++++++++++++------ src/slic3r/GUI/Widgets/AMSItem.cpp | 4 ++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 11682a50584..40254ce18ef 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -713,24 +713,44 @@ bool MachineObject::is_extrusion_cali_finished() void MachineObject::_parse_tray_now(std::string tray_now) { - m_tray_now = tray_now; if (tray_now.empty()) { return; } else { try { int tray_now_int = atoi(tray_now.c_str()); - if (tray_now_int >= 0 && tray_now_int < 16) { - m_ams_id = std::to_string(tray_now_int >> 2); - m_tray_id = std::to_string(tray_now_int & 0x3); - } - else if (tray_now_int == 255) { + + if (tray_now_int == 255) { m_ams_id = "0"; m_tray_id = "0"; + m_extder_data.extders[MAIN_NOZZLE_ID].snow.ams_id = ""; + m_extder_data.extders[MAIN_NOZZLE_ID].snow.slot_id = ""; + + if (m_tray_now == std::to_string(255)) { + m_extder_data.extders[MAIN_NOZZLE_ID].snow.ams_id = std::to_string(255); + m_extder_data.extders[MAIN_NOZZLE_ID].snow.slot_id = "0"; + } + } + else if (tray_now_int == 254) { + m_extder_data.extders[MAIN_NOZZLE_ID].snow.ams_id = std::to_string(254); + m_extder_data.extders[MAIN_NOZZLE_ID].snow.slot_id = "0"; + } + else { + if (tray_now_int >= 0x80 && tray_now_int <= 0x87) { + m_ams_id = std::to_string(tray_now_int); + } else { + m_ams_id = std::to_string(tray_now_int >> 2); + } + + m_tray_id = std::to_string(tray_now_int & 0x3); + m_extder_data.extders[MAIN_NOZZLE_ID].snow.ams_id = m_ams_id; + m_extder_data.extders[MAIN_NOZZLE_ID].snow.slot_id = m_tray_id; } } catch(...) { } } + + m_tray_now = tray_now; } Ams *MachineObject::get_curr_Ams() diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index d82e02d20e2..9d4178e517a 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -1608,7 +1608,7 @@ void AMSRoad::OnPassRoad(std::vector prord_list) } // left end - if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END) { + if (m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END || m_rode_mode == AMSRoadMode::AMS_ROAD_MODE_END_ONLY) { for (auto i = 0; i < prord_list.size(); i++) { std::vector::iterator iter = std::find(end_types.begin(), end_types.end(), prord_list[i]); if (iter != end_types.end()) m_pass_rode_mode.push_back(prord_list[i]); @@ -2219,7 +2219,7 @@ void AmsItem::Update(AMSinfo info) } } - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (m_ams_model != AMSModel::AMS_LITE) { for (auto i = 0; i < m_can_road_list.size(); i++) { AMSRoad* road = m_can_road_list[std::to_string(i)]; if (road != nullptr) { From e6eb80e0030c8f4d3ed49cae1ad14fefdedfe7c4 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 23 May 2025 15:25:55 +0800 Subject: [PATCH 093/127] Use Orca color scheme for machine selection dialog --- src/slic3r/GUI/SelectMachine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index ceee8c7889e..93a4e6f19a3 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1153,8 +1153,8 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_comboBox_printer->Bind(wxEVT_COMBOBOX, &SelectMachineDialog::on_selection_changed, this); - m_btn_bg_enable = StateColor(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), - std::pair(wxColour(0, 174, 66), StateColor::Normal)); + m_btn_bg_enable = StateColor(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); m_button_refresh = new Button(m_basic_panel, _L("Refresh")); m_button_refresh->SetBackgroundColor(m_btn_bg_enable); From 0d61ae87ed4d333b0d2bf3040d7ff96fddfa629f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 23 May 2025 15:31:09 +0800 Subject: [PATCH 094/127] Fix typo --- src/slic3r/GUI/Preferences.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index db2e4ba7421..ab152573835 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1205,7 +1205,7 @@ wxWindow* PreferencesDialog::create_general_page() auto item_stealth_mode = create_item_checkbox(_L("Stealth Mode"), page, _L("This stops the transmission of data to Bambu's cloud services. Users who don't use BBL machines or use LAN mode only can safely turn on this function."), 50, "stealth_mode"); auto item_enable_plugin = create_item_checkbox(_L("Enable network plugin"), page, _L("Enable network plugin"), 50, "installed_networking"); - auto item_legacy_network_plugin = create_item_checkbox(_L("Use legacy network plugin (Take effect after restarting Orca)"), page, _L("Disable to use latest network plugin that support new BambuLab firmwares."), 50, "legacy_networking"); + auto item_legacy_network_plugin = create_item_checkbox(_L("Use legacy network plugin (Takes effect after restarting Orca)"), page, _L("Disable to use latest network plugin that supports new BambuLab firmwares."), 50, "legacy_networking"); auto item_check_stable_version_only = create_item_checkbox(_L("Check for stable updates only"), page, _L("Check for stable updates only"), 50, "check_stable_update_only"); std::vector Units = {_L("Metric") + " (mm, g)", _L("Imperial") + " (in, oz)"}; From 65936b34c17bd6259cf1bb33d4b46fb7238767f7 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 24 May 2025 18:37:35 +0800 Subject: [PATCH 095/127] Fix crash when using old firmware --- src/libslic3r/PrintConfig.hpp | 7 + src/slic3r/GUI/AMSMaterialsSetting.cpp | 10 +- src/slic3r/GUI/AmsMappingPopup.cpp | 4 +- src/slic3r/GUI/CaliHistoryDialog.cpp | 6 +- src/slic3r/GUI/CalibrationWizard.cpp | 2 +- src/slic3r/GUI/CalibrationWizardCaliPage.cpp | 4 +- .../GUI/CalibrationWizardPresetPage.cpp | 2 +- src/slic3r/GUI/DeviceManager.cpp | 186 +++++++++++++----- src/slic3r/GUI/DeviceManager.hpp | 87 +++++--- src/slic3r/GUI/PrintOptionsDialog.cpp | 161 ++++++++------- src/slic3r/GUI/PrintOptionsDialog.hpp | 10 +- src/slic3r/GUI/SelectMachine.cpp | 129 +++++------- src/slic3r/GUI/SelectMachine.hpp | 6 +- src/slic3r/GUI/StatusPanel.cpp | 2 +- src/slic3r/Utils/CalibUtils.cpp | 24 +-- 15 files changed, 365 insertions(+), 275 deletions(-) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index c8d1f6a218f..62ca1da6d0e 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -299,6 +299,13 @@ static std::unordered_mapNozzleTypeEumnToStr = { {NozzleType::ntBrass, "brass"} }; +static std::unordered_mapNozzleTypeStrToEumn = { + {"undefine", NozzleType::ntUndefine}, + {"hardened_steel", NozzleType::ntHardenedSteel}, + {"stainless_steel", NozzleType::ntStainlessSteel}, + {"brass", NozzleType::ntBrass} +}; + // BBS enum PrinterStructure { psUndefine=0, diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index 2ebd8bf99a5..db04cf5065d 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -542,7 +542,7 @@ void AMSMaterialsSetting::on_select_reset(wxCommandEvent& event) { select_index_info.tray_id = tray_id; select_index_info.ams_id = ams_id; select_index_info.slot_id = slot_id; - select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; + select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].current_nozzle_diameter; select_index_info.cali_idx = -1; select_index_info.filament_id = selected_ams_id; CalibUtils::select_PA_calib_result(select_index_info); @@ -666,7 +666,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) select_index_info.tray_id = vt_tray; select_index_info.ams_id = 255; // TODO: Orca hack select_index_info.slot_id = 0; - select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; + select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].current_nozzle_diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); if (m_pa_profile_items.size() > 0 && cali_select_id >= 0) { @@ -707,7 +707,7 @@ void AMSMaterialsSetting::on_select_ok(wxCommandEvent &event) select_index_info.tray_id = cali_tray_id; select_index_info.ams_id = ams_id; select_index_info.slot_id = slot_id; - select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; + select_index_info.nozzle_diameter = obj->m_extder_data.extders[0].current_nozzle_diameter; auto cali_select_id = m_comboBox_cali_result->GetSelection(); if (m_pa_profile_items.size() > 0 && cali_select_id > 0) { @@ -870,7 +870,7 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi std::set filament_id_set; PresetBundle * preset_bundle = wxGetApp().preset_bundle; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].diameter; + stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].current_nozzle_diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); @@ -1036,7 +1036,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) if (preset_bundle) { std::ostringstream stream; if (obj) - stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].diameter; + stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].current_nozzle_diameter; std::string nozzle_diameter_str = stream.str(); std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle(MachineObject::get_preset_printer_model_name(obj->printer_type), nozzle_diameter_str); diff --git a/src/slic3r/GUI/AmsMappingPopup.cpp b/src/slic3r/GUI/AmsMappingPopup.cpp index 2feb54043de..bc1bc5ca844 100644 --- a/src/slic3r/GUI/AmsMappingPopup.cpp +++ b/src/slic3r/GUI/AmsMappingPopup.cpp @@ -1407,7 +1407,9 @@ void AmsReplaceMaterialDialog::update_machine_obj(MachineObject* obj) //creat group int group_index = 0; - for (int filam : m_obj->filam_bak) { + + const Extder& extder = m_obj->m_extder_data.extders[MAIN_NOZZLE_ID]; + for (int filam : extder.filam_bak) { auto status_list = GetStatus(filam); std::map group_info; diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 2cc210c6c2b..46a3eb4f4e8 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -180,7 +180,7 @@ void HistoryWindow::on_device_connected(MachineObject* obj) int selection = 1; for (int i = 0; i < nozzle_diameter_list.size(); i++) { m_comboBox_nozzle_dia->AppendString(wxString::Format("%1.1f mm", nozzle_diameter_list[i])); - if (abs(curr_obj->m_extder_data.extders[0].diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(curr_obj->m_extder_data.extders[0].current_nozzle_diameter - nozzle_diameter_list[i]) < 1e-3) { selection = i; } } @@ -507,7 +507,7 @@ wxArrayString NewCalibrationHistoryDialog::get_all_filaments(const MachineObject std::set filament_id_set; std::set printer_names; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].diameter; + stream << std::fixed << std::setprecision(1) << obj->m_extder_data.extders[0].current_nozzle_diameter; std::string nozzle_diameter_str = stream.str(); for (auto printer_it = preset_bundle->printers.begin(); printer_it != preset_bundle->printers.end(); printer_it++) { @@ -624,7 +624,7 @@ NewCalibrationHistoryDialog::NewCalibrationHistoryDialog(wxWindow *parent, const static std::array nozzle_diameter_list = {0.2f, 0.4f, 0.6f, 0.8f}; for (int i = 0; i < nozzle_diameter_list.size(); i++) { m_comboBox_nozzle_diameter->AppendString(wxString::Format("%1.1f mm", nozzle_diameter_list[i])); - if (abs(obj->m_extder_data.extders[0].diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(obj->m_extder_data.extders[0].current_nozzle_diameter - nozzle_diameter_list[i]) < 1e-3) { m_comboBox_nozzle_diameter->SetSelection(i); } } diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index 7ebf076a876..7e8ff01de0d 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -497,7 +497,7 @@ void PressureAdvanceWizard::update(MachineObject* obj) if (obj->cali_version != -1 && obj->cali_version != cali_version) { cali_version = obj->cali_version; PACalibExtruderInfo cali_info; - cali_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; + cali_info.nozzle_diameter = obj->m_extder_data.extders[0].current_nozzle_diameter; cali_info.use_extruder_id = false; cali_info.use_nozzle_volume_type = false; CalibUtils::emit_get_PA_calib_infos(cali_info); diff --git a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp index 9cd780ff97c..927285c149c 100644 --- a/src/slic3r/GUI/CalibrationWizardCaliPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardCaliPage.cpp @@ -495,8 +495,8 @@ float CalibrationCaliPage::get_selected_calibration_nozzle_dia(MachineObject* ob return obj->cali_selected_nozzle_dia; // return default nozzle if nozzle diameter is set - if (obj->m_extder_data.extders[0].diameter > 1e-3 && obj->m_extder_data.extders[0].diameter < 10.0f) - return obj->m_extder_data.extders[0].diameter; + if (obj->m_extder_data.extders[0].current_nozzle_diameter > 1e-3 && obj->m_extder_data.extders[0].current_nozzle_diameter < 10.0f) + return obj->m_extder_data.extders[0].current_nozzle_diameter; // return 0.4 by default return 0.4; diff --git a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp index 207ba657d88..badb4a69452 100644 --- a/src/slic3r/GUI/CalibrationWizardPresetPage.cpp +++ b/src/slic3r/GUI/CalibrationWizardPresetPage.cpp @@ -1504,7 +1504,7 @@ void CalibrationPresetPage::init_with_machine(MachineObject* obj) // set nozzle value from machine bool nozzle_is_set = false; for (int i = 0; i < NOZZLE_LIST_COUNT; i++) { - if (abs(obj->m_extder_data.extders[0].diameter - nozzle_diameter_list[i]) < 1e-3) { + if (abs(obj->m_extder_data.extders[0].current_nozzle_diameter - nozzle_diameter_list[i]) < 1e-3) { if (m_comboBox_nozzle_dia->GetCount() > i) { m_comboBox_nozzle_dia->SetSelection(i); nozzle_is_set = true; diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 40254ce18ef..adc7d57e143 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -620,10 +620,13 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string has_ipcam = true; // default true - m_extder_data.current_extder_id = 0; - m_extder_data.target_extder_id = 0; - m_extder_data.total_extder_count = 1; + m_extder_data.current_extder_id = MAIN_NOZZLE_ID; + m_extder_data.target_extder_id = MAIN_NOZZLE_ID; + m_extder_data.total_extder_count = 1; Extder nozzle; + nozzle.id = MAIN_NOZZLE_ID; + nozzle.nozzle_id = MAIN_NOZZLE_ID; + nozzle.target_nozzle_id = MAIN_NOZZLE_ID; m_extder_data.extders.push_back(nozzle); } @@ -3342,8 +3345,11 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) home_flag = jj["home_flag"].get(); parse_status(home_flag); } + + /*the param is invalid in np for Yeshu*/ if (jj.contains("hw_switch_state")) { hw_switch_state = jj["hw_switch_state"].get(); + m_extder_data.extders[MAIN_NOZZLE_ID].ext_has_filament = hw_switch_state; } if (jj.contains("mc_print_line_number")) { if (jj["mc_print_line_number"].is_string() && !jj["mc_print_line_number"].is_null()) @@ -3516,14 +3522,14 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("nozzle_temper")) { if (jj["nozzle_temper"].is_number()) { if (m_extder_data.extders.size() == 1) { - m_extder_data.extders[0].temp = jj["nozzle_temper"].get(); + m_extder_data.extders[MAIN_NOZZLE_ID].temp = jj["nozzle_temper"].get(); } } } if (jj.contains("nozzle_target_temper")) { if (jj["nozzle_target_temper"].is_number()) { if (m_extder_data.extders.size() == 1) { - m_extder_data.extders[0].target_temp = jj["nozzle_target_temper"].get(); + m_extder_data.extders[MAIN_NOZZLE_ID].target_temp = jj["nozzle_target_temper"].get(); } } } @@ -3621,12 +3627,14 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (!key_field_only) { /*get filam_bak*/ try { + m_extder_data.extders[MAIN_NOZZLE_ID].filam_bak.clear(); + if (jj.contains("filam_bak")) { is_support_show_filament_backup = true; - filam_bak.clear(); if (jj["filam_bak"].is_array()) { for (auto it = jj["filam_bak"].begin(); it != jj["filam_bak"].end(); it++) { - filam_bak.push_back(it.value().get()); + const auto& filam_bak_val = it.value().get(); + m_extder_data.extders[MAIN_NOZZLE_ID].filam_bak.push_back(filam_bak_val); } } } @@ -3708,8 +3716,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) nozzle_diameter = string_to_float(jj["nozzle_diameter"].get()); } - if (nozzle_diameter == 0.0f) {m_extder_data.extders[0].diameter = 0.4f;} - else {m_extder_data.extders[0].diameter = round(nozzle_diameter * 10) / 10;} + if (nozzle_diameter == 0.0f) {m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_diameter = 0.0f;} + else { m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_diameter = round(nozzle_diameter * 10) / 10;} } } } @@ -3726,7 +3734,12 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) else { if (jj["nozzle_type"].is_string()) { auto nozzle_type = jj["nozzle_type"].get(); - m_extder_data.extders[0].type = nozzle_type; + if (nozzle_type.empty()) { + m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_type = NozzleType::ntUndefine; + } + else { + m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_type = NozzleTypeStrToEumn[nozzle_type]; + } } } } @@ -5550,55 +5563,136 @@ void MachineObject::parse_new_info(json print) } if (device.contains("nozzle")) { - json const& nozzle = device["nozzle"]; + json const &nozzle = device["nozzle"]; - m_extder_data = ExtderData(); - m_extder_data.current_extder_id = get_flag_bits(nozzle["info"].get(), 0, 3); - m_extder_data.target_extder_id = get_flag_bits(nozzle["info"].get(), 4, 3); - m_extder_data.total_extder_count = get_flag_bits(nozzle["info"].get(), 8, 3); + m_nozzle_data = NozzleData(); + m_nozzle_data.extder_exist = get_flag_bits(nozzle["exist"].get(), 0, 16); + m_nozzle_data.cut_exist = get_flag_bits(nozzle["exist"].get(), 16, 16); + m_nozzle_data.state = get_flag_bits(nozzle["state"].get(), 0, 4); - for (int i = 0; i < m_extder_data.total_extder_count; i++) { + for (auto it = nozzle["info"].begin(); it != nozzle["info"].end(); it++) { + Nozzle nozzle_obj; + auto njon = it.value(); + std::string type = njon["type"].get(); + nozzle_obj.id = njon["id"].get(); - Extder nozzle_obj; + if (type.length() >= 4) { + if (type.substr(2, 2) == std::string("00")) { + nozzle_obj.nozzle_type = NozzleType::ntStainlessSteel; + } else if (type.substr(2, 2) == std::string("01")) { + nozzle_obj.nozzle_type = NozzleType::ntHardenedSteel; + } + } else { + nozzle_obj.nozzle_type = NozzleType::ntUndefine; + } - std::string nozzle_id = std::to_string(i); - if (nozzle.contains(nozzle_id)) { - auto njon = nozzle[nozzle_id].get(); + nozzle_obj.diameter = njon["diameter"].get(); + nozzle_obj.max_temp = njon["tm"].get(); + nozzle_obj.wear = njon["wear"].get(); + if (nozzle_obj.diameter == 0.0f) {nozzle_obj.diameter = 0.4f;} + m_nozzle_data.nozzles.push_back(nozzle_obj); + } + } + + if (device.contains("extruder")) { + json const& extruder = device["extruder"]; + + auto extder_data = ExtderData(); + extder_data.total_extder_count = get_flag_bits(extruder["state"].get(), 0, 4); - nozzle_obj.type = DeviceManager::nozzle_type_conver(get_flag_bits(njon["info"].get(), 0, 2)); - nozzle_obj.diameter = DeviceManager::nozzle_diameter_conver(get_flag_bits(njon["info"].get(), 3, 3)); - nozzle_obj.ext_has_filament = get_flag_bits(njon["info"].get(), 7); - nozzle_obj.buffer_has_filament = get_flag_bits(njon["info"].get(), 8); - nozzle_obj.flow_type = get_flag_bits(njon["info"].get(), 9, 2); - nozzle_obj.temp = get_flag_bits(njon["temp"].get(), 0, 15); - nozzle_obj.target_temp = get_flag_bits(njon["temp"].get(), 16, 15); - AmsSlot spre; - spre.ams_id = std::to_string(get_flag_bits(njon["spre"].get(), 0, 8)); - spre.slot_id = std::to_string(get_flag_bits(njon["spre"].get(), 8, 8)); + extder_data.current_extder_id = get_flag_bits(extruder["state"].get(), 4, 4); + extder_data.target_extder_id = get_flag_bits(extruder["state"].get(), 8, 4); - AmsSlot snow; - snow.ams_id = std::to_string(get_flag_bits(njon["snow"].get(), 0, 8)); - snow.slot_id = std::to_string(get_flag_bits(njon["snow"].get(), 8, 8)); + for (auto it = extruder["info"].begin(); it != extruder["info"].end(); it++) { - AmsSlot star; - star.ams_id = std::to_string(get_flag_bits(njon["star"].get(), 0, 8)); - star.slot_id = std::to_string(get_flag_bits(njon["star"].get(), 8, 8)); + Extder extder_obj; + auto njon = it.value(); + + extder_obj.id = njon["id"].get(); + + extder_obj.filam_bak.clear(); + is_support_show_filament_backup = njon.contains("filam_bak"); + if (is_support_show_filament_backup) + { + const json& filam_bak_items = njon["filam_bak"]; + for (const auto& filam_bak_item : filam_bak_items) + { + const auto& filam_bak_val = filam_bak_item.get(); + extder_obj.filam_bak.emplace_back(filam_bak_val); + } + } - nozzle_obj.spre = spre; - nozzle_obj.snow = snow; - nozzle_obj.star = star; - nozzle_obj.ams_stat = get_flag_bits(njon["stat"].get(), 0, 15); - nozzle_obj.rfid_stat = get_flag_bits(njon["stat"].get(), 16, 7); + extder_obj.ext_has_filament = get_flag_bits(njon["info"].get(), 1); + extder_obj.buffer_has_filament = get_flag_bits(njon["info"].get(), 2); + extder_obj.nozzle_exist = get_flag_bits(njon["info"].get(), 3); + extder_obj.temp = get_flag_bits(njon["temp"].get(), 0, 16); + extder_obj.target_temp = get_flag_bits(njon["temp"].get(), 16, 16); + + AmsSlot spre; + spre.slot_id = std::to_string(get_flag_bits(njon["spre"].get(), 0, 8)); + spre.ams_id = std::to_string(get_flag_bits(njon["spre"].get(), 8, 8)); + + AmsSlot snow; + snow.slot_id = std::to_string(get_flag_bits(njon["snow"].get(), 0, 8)); + snow.ams_id = std::to_string(get_flag_bits(njon["snow"].get(), 8, 8)); + + AmsSlot star; + star.slot_id = std::to_string(get_flag_bits(njon["star"].get(), 0, 8)); + star.ams_id = std::to_string(get_flag_bits(njon["star"].get(), 8, 8)); + + extder_obj.nozzle_id = njon["hnow"].get(); + extder_obj.target_nozzle_id = njon["htar"].get(); + + extder_obj.spre = spre; + extder_obj.snow = snow; + extder_obj.star = star; + extder_obj.ams_stat = get_flag_bits(njon["stat"].get(), 0, 16); + extder_obj.rfid_stat = get_flag_bits(njon["stat"].get(), 16, 16); + + //current nozzle info + if (extder_obj.nozzle_id == 0xff) { + extder_obj.current_nozzle_type = NozzleType::ntUndefine; + extder_obj.current_nozzle_diameter = 0.4f; + } else { + for (auto i = 0; i < m_nozzle_data.nozzles.size(); i++) { + if (m_nozzle_data.nozzles[i].id == extder_obj.nozzle_id) { + extder_obj.current_nozzle_type = m_nozzle_data.nozzles[i].nozzle_type; + extder_obj.current_nozzle_diameter = m_nozzle_data.nozzles[i].diameter; + } + } } + extder_data.extders.push_back(extder_obj); + } - m_extder_data.extders.push_back(nozzle_obj); + if (extder_data.extders.size() <= 0) { + // def data + extder_data.current_extder_id = 0; + extder_data.target_extder_id = 0; + extder_data.total_extder_count = 1; + Extder nozzle; + extder_data.extders.push_back(nozzle); } + + m_extder_data = extder_data; } } } +bool MachineObject::is_nozzle_data_invalid() +{ + for (const auto &ext : m_extder_data.extders) + { + if (ext.current_nozzle_type == NozzleType::ntUndefine || + ext.current_nozzle_diameter <= 0.0f) { + return true; + } + } + + return false; +} + int MachineObject::get_flag_bits(std::string str, int start, int count) const { try { @@ -5705,7 +5799,7 @@ void MachineObject::update_printer_preset_name() auto printer_model = MachineObject::get_preset_printer_model_name(this->printer_type); std::set diameter_set; for (auto &nozzle : m_extder_data.extders) { - float diameter = nozzle.diameter; + float diameter = nozzle.current_nozzle_diameter; std::ostringstream stream; stream << std::fixed << std::setprecision(1) << diameter; std::string nozzle_diameter_str = stream.str(); @@ -5746,7 +5840,7 @@ void MachineObject::check_ams_filament_valid() if (ams->nozzle < 0 || ams->nozzle >= m_extder_data.extders.size()) { return; } - stream << std::fixed << std::setprecision(1) << m_extder_data.extders[ams->nozzle].diameter; + stream << std::fixed << std::setprecision(1) << m_extder_data.extders[ams->nozzle].current_nozzle_diameter; std::string nozzle_diameter_str = stream.str(); assert(nozzle_diameter_str.size() == 3); if (m_nozzle_filament_data.find(nozzle_diameter_str) == m_nozzle_filament_data.end()) { @@ -5808,7 +5902,7 @@ void MachineObject::check_ams_filament_valid() BOOST_LOG_TRIVIAL(error) << " vt_tray id map for nozzle id is not exist, index is: " << index << " nozzle count" << m_extder_data.total_extder_count; continue; } - auto diameter = m_extder_data.extders[index].diameter; + auto diameter = m_extder_data.extders[index].current_nozzle_diameter; std::ostringstream stream; stream << std::fixed << std::setprecision(1) << diameter; std::string nozzle_diameter_str = stream.str(); @@ -5840,7 +5934,7 @@ void MachineObject::check_ams_filament_valid() std::string preset_setting_id; PresetBundle * preset_bundle = Slic3r::GUI::wxGetApp().preset_bundle; std::ostringstream stream; - stream << std::fixed << std::setprecision(1) << m_extder_data.extders[MAIN_NOZZLE_ID].diameter; + stream << std::fixed << std::setprecision(1) << m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_diameter; std::string nozzle_diameter_str = stream.str(); bool is_equation = preset_bundle->check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(MachineObject::get_preset_printer_model_name( this->printer_type), diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index ba9dc58a17c..654e4c9a888 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -145,22 +145,49 @@ struct AmsSlot std::string slot_id; }; -struct Extder +struct Nozzle { - std::string type; //0-hardened_steel 1-stainless_steel + int id; + NozzleType nozzle_type; // 0-stainless_steel 1-hardened_steel float diameter = {0.4f}; // 0-0.2mm 1-0.4mm 2-0.6 mm3-0.8mm - int exist{0}; //0-Not Installed 1-Wrong extruder 2-No enablement 3-Enable + int max_temp = 0; + int wear = 0; +}; + +struct NozzleData +{ + int extder_exist; //0- none exist 1-exist + int cut_exist; + int state; //0-idle 1-checking + std::vector nozzles; +}; + +struct Extder +{ + int id; // 0-right 1-left + int ext_has_filament{0}; int buffer_has_filament{0}; - int flow_type{0};//0-common 1-high flow + int nozzle_exist{0}; + + std::vector filam_bak;// the refill filam - int temp{0}; + int temp{0}; int target_temp{0}; - AmsSlot spre; //tray_pre - AmsSlot snow; //tray_now - AmsSlot star; //tray_tar - int ams_stat{0}; ; - int rfid_stat{0}; ; + + AmsSlot spre; // tray_pre + AmsSlot snow; // tray_now + AmsSlot star; // tray_tar + int ams_stat{0}; + + int rfid_stat{0}; + + int nozzle_id; // nozzle id now + int target_nozzle_id; // target nozzle id + + //current nozzle + NozzleType current_nozzle_type{NozzleType::ntUndefine}; // 0-hardened_steel 1-stainless_steel + float current_nozzle_diameter = {0.4f}; // 0-0.2mm 1-0.4mm 2-0.6 mm3-0.8mm }; struct ExtderData @@ -266,25 +293,27 @@ class AmsTray { #define INVALID_AMS_TEMPERATURE std::numeric_limits::min() -class Ams { +class Ams +{ public: - Ams(std::string ams_id, int nozzle_id, int type_id) { - id = ams_id; + Ams(std::string ams_id, int nozzle_id, int type_id) + { + id = ams_id; nozzle = nozzle_id; - type = type_id; + type = type_id; } - std::string id; - int left_dry_time = 0; - int humidity = 5; - int humidity_raw = -1;// the percentage, -1 means invalid. eg. 100 means 100% - float current_temperature = INVALID_AMS_TEMPERATURE; // the temperature - bool startup_read_opt{true}; - bool tray_read_opt{false}; - bool is_exists{false}; - std::map trayList; - - int nozzle; - int type{1}; //0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s + std::string id; + int left_dry_time = 0; + int humidity = 5; + int humidity_raw = -1; // the percentage, -1 means invalid. eg. 100 means 100% + float current_temperature = INVALID_AMS_TEMPERATURE; // the temperature + bool startup_read_opt{true}; + bool tray_read_opt{false}; + bool is_exists{false}; + std::map trayList; + + int nozzle; + int type{1}; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s }; enum PrinterFirmwareType { @@ -380,6 +409,7 @@ class MachineObject // type, time stamp, delay std::vector> message_delay; + public: enum LIGHT_EFFECT { @@ -507,9 +537,6 @@ class MachineObject std::string product_name; // set by iot service, get /user/print - std::vector filam_bak; - - std::string bind_user_name; std::string bind_user_id; std::string bind_state; /* free | occupied */ @@ -1045,6 +1072,7 @@ class MachineObject bool is_enable_ams_np{ false }; ExtderData m_extder_data; + NozzleData m_nozzle_data; /*vi slot data*/ AmsTray vt_tray; // virtual tray @@ -1053,6 +1081,7 @@ class MachineObject /*for parse new info*/ bool check_enable_np(const json& print) const; void parse_new_info(json print); + bool is_nozzle_data_invalid(); int get_flag_bits(std::string str, int start, int count = 1) const; int get_flag_bits(int num, int start, int count = 1, int base = 10) const; diff --git a/src/slic3r/GUI/PrintOptionsDialog.cpp b/src/slic3r/GUI/PrintOptionsDialog.cpp index 13d1e3ba8a8..13d085468f8 100644 --- a/src/slic3r/GUI/PrintOptionsDialog.cpp +++ b/src/slic3r/GUI/PrintOptionsDialog.cpp @@ -429,9 +429,9 @@ void PrintOptionsDialog::update_machine_obj(MachineObject *obj_) bool PrintOptionsDialog::Show(bool show) { - if (show) { + if (show) { wxGetApp().UpdateDlgDarkUI(this); - CentreOnParent(); + CentreOnParent(); } return DPIDialog::Show(show); } @@ -439,8 +439,11 @@ bool PrintOptionsDialog::Show(bool show) PrinterPartsDialog::PrinterPartsDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _L("Printer Parts"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) { - nozzle_type_map[0] = "hardened_steel"; - nozzle_type_map[1] = "stainless_steel"; + nozzle_type_map[NozzleType::ntHardenedSteel] = _L("Hardened Steel"); + nozzle_type_map[NozzleType::ntStainlessSteel] = _L("Stainless Steel"); + + nozzle_type_selection_map[NozzleType::ntHardenedSteel] = 0; + nozzle_type_selection_map[NozzleType::ntStainlessSteel] = 1; nozzle_stainless_diameter_map[0] = 0.2; nozzle_stainless_diameter_map[1] = 0.4; @@ -466,12 +469,15 @@ PrinterPartsDialog::PrinterPartsDialog(wxWindow* parent) nozzle_type->SetForegroundColour(STATIC_TEXT_CAPTION_COL); nozzle_type->Wrap(-1); + ID_NOZZLE_TYPE_CHECKBOX_SINGLE = wxNewId(); + ID_NOZZLE_DIAMETER_CHECKBOX_SINGLE = wxNewId(); + nozzle_type_checkbox = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(140), -1), 0, NULL, wxCB_READONLY); - nozzle_type_checkbox->Append(_L("Stainless Steel")); - nozzle_type_checkbox->Append(_L("Hardened Steel")); + nozzle_type_checkbox->Append(nozzle_type_map[NozzleType::ntHardenedSteel]); + nozzle_type_checkbox->Append(nozzle_type_map[NozzleType::ntStainlessSteel]); nozzle_type_checkbox->SetSelection(0); - + line_sizer_nozzle_type->Add(nozzle_type, 0, wxALIGN_CENTER, 5); line_sizer_nozzle_type->Add(0, 0, 1, wxEXPAND, 5); line_sizer_nozzle_type->Add(nozzle_type_checkbox, 0, wxALIGN_CENTER, 5); @@ -500,65 +506,76 @@ PrinterPartsDialog::PrinterPartsDialog(wxWindow* parent) sizer->Add(line_sizer_nozzle_diameter, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(18)); sizer->Add(0, 0, 0, wxTOP, FromDIP(24)); - - nozzle_type_checkbox->Connect( wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_type), NULL, this ); - nozzle_diameter_checkbox->Connect( wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_diameter), NULL, this ); - SetSizer(sizer); Layout(); Fit(); wxGetApp().UpdateDlgDarkUI(this); + + nozzle_type_checkbox->Connect(wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_data), NULL, this); + nozzle_diameter_checkbox->Connect(wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_data), NULL, this); + + nozzle_type_checkbox->SetId(ID_NOZZLE_TYPE_CHECKBOX_SINGLE); + + nozzle_diameter_checkbox->SetId(ID_NOZZLE_DIAMETER_CHECKBOX_SINGLE); } PrinterPartsDialog::~PrinterPartsDialog() { - nozzle_type_checkbox->Disconnect(wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_type), NULL, this); - nozzle_diameter_checkbox->Disconnect(wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_diameter), NULL, this); + nozzle_type_checkbox->Disconnect(wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_data), NULL, this); + nozzle_diameter_checkbox->Disconnect(wxEVT_COMBOBOX, wxCommandEventHandler(PrinterPartsDialog::set_nozzle_data), NULL, this); } -void PrinterPartsDialog::set_nozzle_type(wxCommandEvent& evt) +void PrinterPartsDialog::set_nozzle_data(wxCommandEvent& evt) { - auto type = nozzle_type_map[nozzle_type_checkbox->GetSelection()]; + ComboBox* current_nozzle_type_combox = nullptr; + ComboBox* current_nozzle_diameter_combox = nullptr; - if (type == last_nozzle_type) { - return; - } + int nozzle_id = MAIN_NOZZLE_ID; - std::map diameter_list; - if (type == "hardened_steel") { - diameter_list = nozzle_hard_diameter_map; - } - else if (type == "stainless_steel") { - diameter_list = nozzle_stainless_diameter_map; + if (evt.GetId() == ID_NOZZLE_TYPE_CHECKBOX_SINGLE || + evt.GetId() == ID_NOZZLE_DIAMETER_CHECKBOX_SINGLE) { + current_nozzle_type_combox = nozzle_type_checkbox; + current_nozzle_diameter_combox = nozzle_diameter_checkbox; + nozzle_id = MAIN_NOZZLE_ID; } - nozzle_diameter_checkbox->Clear(); - for (int i = 0; i < diameter_list.size(); i++) - { - nozzle_diameter_checkbox->Append(wxString::Format("%.1f", diameter_list[i])); - } - nozzle_diameter_checkbox->SetSelection(0); + if (obj) { + try { + auto nozzle_type = NozzleType::ntHardenedSteel; + auto nozzle_diameter = 0.4f; + + for (auto sm : nozzle_type_selection_map) { + if (sm.second == current_nozzle_type_combox->GetSelection()) { + nozzle_type = sm.first; + } + } - last_nozzle_type = type; - set_nozzle_diameter(evt); -} + /*update nozzle diameter*/ + if (evt.GetId() == ID_NOZZLE_TYPE_CHECKBOX_SINGLE) { + nozzle_diameter_checkbox->Clear(); + std::map diameter_map; + if (nozzle_type == NozzleType::ntHardenedSteel) { + diameter_map = nozzle_hard_diameter_map; + } else if (nozzle_type == NozzleType::ntStainlessSteel) { + diameter_map = nozzle_stainless_diameter_map; + } -void PrinterPartsDialog::set_nozzle_diameter(wxCommandEvent& evt) -{ - if (obj) { - try - { - auto nozzle_type = nozzle_type_map[nozzle_type_checkbox->GetSelection()]; - auto nozzle_diameter = std::stof(nozzle_diameter_checkbox->GetStringSelection().ToStdString()); + for (int i = 0; i < diameter_map.size(); i++) { nozzle_diameter_checkbox->Append(wxString::Format(_L("%.1f"), diameter_map[i])); } + nozzle_diameter_checkbox->SetSelection(0); + } + + nozzle_diameter = std::stof(current_nozzle_diameter_combox->GetStringSelection().ToStdString()); nozzle_diameter = round(nozzle_diameter * 10) / 10; - - obj->m_extder_data.extders[0].diameter = nozzle_diameter; - obj->m_extder_data.extders[0].type = nozzle_type; - obj->command_set_printer_nozzle(nozzle_type, nozzle_diameter); - } - catch (...) {} + /*if (!obj->is_enable_np)*/ { + if (current_nozzle_type_combox && current_nozzle_type_combox->IsShown() && current_nozzle_type_combox->GetValue().IsEmpty()) { return; } + if (current_nozzle_diameter_combox && current_nozzle_diameter_combox->IsShown() && current_nozzle_diameter_combox->GetValue().IsEmpty()) { return; } + obj->m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_diameter = nozzle_diameter; + obj->m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_type = nozzle_type; + obj->command_set_printer_nozzle(NozzleTypeEumnToStr[nozzle_type], nozzle_diameter); + } + } catch (...) {} } } @@ -578,50 +595,30 @@ bool PrinterPartsDialog::Show(bool show) wxGetApp().UpdateDlgDarkUI(this); CentreOnParent(); + auto type = obj->m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_type; + auto diameter = obj->m_extder_data.extders[MAIN_NOZZLE_ID].current_nozzle_diameter; - auto type = obj->m_extder_data.extders[0].type; - auto diameter = obj->m_extder_data.extders[0].diameter; - - nozzle_type_checkbox->Clear(); nozzle_diameter_checkbox->Clear(); - if (type.empty()) { + if (type == NozzleType::ntUndefine) { nozzle_type_checkbox->SetValue(wxEmptyString); nozzle_diameter_checkbox->SetValue(wxEmptyString); - - nozzle_type_checkbox->Disable(); - nozzle_diameter_checkbox->Disable(); - return DPIDialog::Show(show); - } - else { - nozzle_type_checkbox->Enable(); - nozzle_diameter_checkbox->Enable(); - } - - last_nozzle_type = type; - - for (int i=0; i < nozzle_type_map.size(); i++) - { - nozzle_type_checkbox->Append( nozzle_type_map[i] ); - if (nozzle_type_map[i] == type) { - nozzle_type_checkbox->SetSelection(i); + } else { + std::map diameter_map; + if (type == NozzleType::ntHardenedSteel) { + diameter_map = nozzle_hard_diameter_map; + } else if (type == NozzleType::ntStainlessSteel) { + diameter_map = nozzle_stainless_diameter_map; } - } - std::map diameter_list; - if (type == "hardened_steel") { - diameter_list = nozzle_hard_diameter_map; - } - else if (type == "stainless_steel") { - diameter_list = nozzle_stainless_diameter_map; - } - - for (int i = 0; i < diameter_list.size(); i++) - { - nozzle_diameter_checkbox->Append( wxString::Format("%.1f", diameter_list[i])); - if (diameter_list[i] == diameter) { - nozzle_diameter_checkbox->SetSelection(i); + for (int i = 0; i < diameter_map.size(); i++) { + nozzle_diameter_checkbox->Append(wxString::Format(_L("%.1f"), diameter_map[i])); + if (diameter == diameter_map[i]) { + nozzle_diameter_checkbox->SetSelection(i); + } } + + nozzle_type_checkbox->SetSelection(nozzle_type_selection_map[type]); } } return DPIDialog::Show(show); diff --git a/src/slic3r/GUI/PrintOptionsDialog.hpp b/src/slic3r/GUI/PrintOptionsDialog.hpp index db55d12dccd..7450933a431 100644 --- a/src/slic3r/GUI/PrintOptionsDialog.hpp +++ b/src/slic3r/GUI/PrintOptionsDialog.hpp @@ -21,18 +21,22 @@ namespace Slic3r { namespace GUI { class PrinterPartsDialog : public DPIDialog { protected: + wxWindowID ID_NOZZLE_TYPE_CHECKBOX_SINGLE; + + wxWindowID ID_NOZZLE_DIAMETER_CHECKBOX_SINGLE; + MachineObject* obj{ nullptr }; ComboBox* nozzle_type_checkbox; ComboBox* nozzle_diameter_checkbox; std::string last_nozzle_type; - std::map nozzle_type_map; + std::map nozzle_type_map; + std::map nozzle_type_selection_map; std::map nozzle_stainless_diameter_map; std::map nozzle_hard_diameter_map; public: PrinterPartsDialog(wxWindow* parent); ~PrinterPartsDialog(); - void set_nozzle_type(wxCommandEvent& evt); - void set_nozzle_diameter(wxCommandEvent& evt); + void set_nozzle_data(wxCommandEvent& evt); void on_dpi_changed(const wxRect& suggested_rect) override; void update_machine_obj(MachineObject* obj_); bool Show(bool show) override; diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 93a4e6f19a3..6151706deb2 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -2462,8 +2462,8 @@ bool SelectMachineDialog::is_blocking_printing(MachineObject* obj_) if (m_print_type == PrintFromType::FROM_NORMAL) { PresetBundle* preset_bundle = wxGetApp().preset_bundle; source_model = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle); - - + + }else if (m_print_type == PrintFromType::FROM_SDCARD_VIEW) { if (m_required_data_plate_data_list.size() > 0) { source_model = m_required_data_plate_data_list[m_print_plate_idx]->printer_model_id; @@ -2481,81 +2481,52 @@ bool SelectMachineDialog::is_blocking_printing(MachineObject* obj_) return false; } -bool SelectMachineDialog::is_same_nozzle_diameters(std::string& tag_nozzle_type, std::string& nozzle_diameter) -{ - bool is_same_nozzle_diameters = true; - - float preset_nozzle_diameters; - std::string preset_nozzle_type; +/**************************************************************//* + * @param tag_nozzle_type -- return the mismatch nozzle type + * @param tag_nozzle_diameter -- return the target nozzle_diameter but mismatch + * @return is same or not +/*************************************************************/ +bool SelectMachineDialog::is_same_nozzle_diameters(float &tag_nozzle_diameter) const +{ DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return true; + if (!dev) return false; MachineObject* obj_ = dev->get_selected_machine(); - if (obj_ == nullptr) return true; + if (obj_ == nullptr) return false; - try + PresetBundle* preset_bundle = wxGetApp().preset_bundle; + auto opt_nozzle_diameters = preset_bundle->printers.get_edited_preset().config.option("nozzle_diameter"); + if (!opt_nozzle_diameters) { - PresetBundle* preset_bundle = wxGetApp().preset_bundle; - auto opt_nozzle_diameters = preset_bundle->printers.get_edited_preset().config.option("nozzle_diameter"); - - const ConfigOptionEnum* nozzle_type = preset_bundle->printers.get_edited_preset().config.option>("nozzle_type"); - - if (nozzle_type->value == NozzleType::ntHardenedSteel) { - preset_nozzle_type = "hardened_steel"; - } - else if (nozzle_type->value == NozzleType::ntStainlessSteel) { - preset_nozzle_type = "stainless_steel"; - } - - tag_nozzle_type = obj_->m_extder_data.extders[0].type; + return false; + } - auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); - if (opt_nozzle_diameters != nullptr) { - for (auto i = 0; i < extruders.size(); i++) { - auto extruder = extruders[i] - 1; - preset_nozzle_diameters = float(opt_nozzle_diameters->get_at(extruder)); - if (preset_nozzle_diameters != obj_->m_extder_data.extders[0].diameter) { - is_same_nozzle_diameters = false; - } + try + { + auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders(); + for (auto i = 0; i < extruders.size(); i++) { + auto extruder = extruders[i] - 1; + tag_nozzle_diameter = float(opt_nozzle_diameters->get_at(extruder)); + if (tag_nozzle_diameter != obj_->m_extder_data.extders[0].current_nozzle_diameter) { + return false; } } - } - catch (...) + catch (const std::exception&) { + return false; } - //nozzle_type = preset_nozzle_type; - nozzle_diameter = wxString::Format("%.2f", preset_nozzle_diameters).ToStdString(); - - return is_same_nozzle_diameters; + return true; } -bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::string& tag_nozzle_type) +bool SelectMachineDialog::is_same_nozzle_type(const Extder& extruder, std::string& filament_type) const { - bool is_same_nozzle_type = true; - - DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return true; - - MachineObject* obj_ = dev->get_selected_machine(); - if (obj_ == nullptr) return true; - - - NozzleType nozzle_type = NozzleType::ntUndefine; - - if (obj_->m_extder_data.extders[0].type == "stainless_steel") { - nozzle_type = NozzleType::ntStainlessSteel; - } - else if (obj_->m_extder_data.extders[0].type == "hardened_steel") { - nozzle_type = NozzleType::ntHardenedSteel; - } - - auto printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(nozzle_type); + auto printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(extruder.current_nozzle_type); auto preset_bundle = wxGetApp().preset_bundle; - MaterialHash::iterator iter = m_materialList.begin(); + MaterialHash::const_iterator iter = m_materialList.begin(); while (iter != m_materialList.end()) { Material* item = iter->second; MaterialItem* m = item->item; @@ -2564,18 +2535,13 @@ bool SelectMachineDialog::is_same_nozzle_type(std::string& filament_type, std::s if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) { filament_type = m->m_material_name.ToStdString(); BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: filament = " << filament_type << " printer_nozzle_hrc = " << printer_nozzle_hrc; - is_same_nozzle_type = false; - tag_nozzle_type = "hardened_steel"; - return is_same_nozzle_type; - } - else { - tag_nozzle_type = DeviceManager::nozzle_type_conver(obj_->m_extder_data.extders[0].type); + return false; } iter++; } - return is_same_nozzle_type; + return true; } bool SelectMachineDialog::is_same_printer_model() @@ -2758,17 +2724,16 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) confirm_text.push_back(ConfirmBeforeSendInfo(_L("There are some unknown filaments in the AMS mappings. Please check whether they are the required filaments. If they are okay, press \"Confirm\" to start printing."))); } - std::string nozzle_diameter; - std::string filament_type; - std::string tag_nozzle_type; - - if (!obj_->m_extder_data.extders[0].type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) { - if (!is_same_nozzle_diameters(tag_nozzle_type, nozzle_diameter)) { + if (!obj_->m_extder_data.extders[0].current_nozzle_type != ntUndefine && (m_print_type == PrintFromType::FROM_NORMAL)) + { + float nozzle_diameter = 0; + if (!is_same_nozzle_diameters(nozzle_diameter)) + { has_slice_warnings = true; // is_printing_block = true; # Removed to allow nozzle overrides (to support non-standard nozzles) - wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"),nozzle_diameter, ""); - wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj_->m_extder_data.extders[0].diameter, ""); + wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %.1f %s"),nozzle_diameter, ""); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj_->m_extder_data.extders[0].current_nozzle_diameter, ""); confirm_text.push_back(ConfirmBeforeSendInfo(_L("Your nozzle diameter in sliced file is not consistent with memorized nozzle. If you changed your nozzle lately, please go to Device > Printer Parts to change settings.") + "\n " + nozzle_in_preset @@ -2776,12 +2741,13 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) + "\n", ConfirmBeforeSendInfo::InfoLevel::Warning)); } - if (!is_same_nozzle_type(filament_type, tag_nozzle_type)){ + std::string filament_type; + if (!is_same_nozzle_type(obj_->m_extder_data.extders[0], filament_type)) + { has_slice_warnings = true; is_printing_block = true; - nozzle_diameter = wxString::Format("%.1f", obj_->m_extder_data.extders[0].diameter).ToStdString(); - wxString nozzle_in_preset = wxString::Format(_L("Printing high temperature material (%s material) with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->m_extder_data.extders[0].type)); + wxString nozzle_in_preset = wxString::Format(_L("Printing high temperature material (%s material) with %s may cause nozzle damage"), filament_type, format_steel_name(obj_->m_extder_data.extders[0].current_nozzle_type)); confirm_text.push_back(ConfirmBeforeSendInfo(nozzle_in_preset, ConfirmBeforeSendInfo::InfoLevel::Warning)); } } @@ -2850,18 +2816,19 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) } } -wxString SelectMachineDialog::format_steel_name(std::string name) +wxString SelectMachineDialog::format_steel_name(NozzleType type) { - if (name == "hardened_steel") { + if (type == NozzleType::ntHardenedSteel) { return _L("Hardened Steel"); } - else if (name == "stainless_steel") { + else if (type == NozzleType::ntStainlessSteel) { return _L("Stainless Steel"); } - return wxEmptyString; + return _L("Unknown"); } + void SelectMachineDialog::Enable_Auto_Refill(bool enable) { if (enable) { diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index 1b6c62b31e5..a31623055f7 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -542,8 +542,8 @@ class SelectMachineDialog : public DPIDialog void update_timelapse_enable_status(); bool is_same_printer_model(); bool is_blocking_printing(MachineObject* obj_); - bool is_same_nozzle_diameters(std::string& tag_nozzle_type, std::string& nozzle_diameter); - bool is_same_nozzle_type(std::string& filament_type, std::string& tag_nozzle_type); + bool is_same_nozzle_diameters(float& tag_nozzle_diameter) const; + bool is_same_nozzle_type(const Extder& extruder, std::string& filament_type) const; bool has_tips(MachineObject* obj); bool is_timeout(); int update_print_required_data(Slic3r::DynamicPrintConfig config, Slic3r::Model model, Slic3r::PlateDataPtrs plate_data_list, std::string file_name, std::string file_path); @@ -554,7 +554,7 @@ class SelectMachineDialog : public DPIDialog bool build_nozzles_info(std::string& nozzles_info); PrintFromType get_print_type() {return m_print_type;}; - wxString format_steel_name(std::string name); + wxString format_steel_name(NozzleType type); wxString format_text(wxString &m_msg); wxWindow* create_ams_checkbox(wxString title, wxWindow* parent, wxString tooltip); wxWindow* create_item_checkbox(wxString title, wxWindow* parent, wxString tooltip, std::string param); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 9fe5ac1ff7c..caf6750b1dc 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2587,7 +2587,7 @@ void StatusPanel::update_ams(MachineObject *obj) if (obj->cali_version != -1 && last_cali_version != obj->cali_version) { last_cali_version = obj->cali_version; PACalibExtruderInfo cali_info; - cali_info.nozzle_diameter = obj->m_extder_data.extders[0].diameter; + cali_info.nozzle_diameter = obj->m_extder_data.extders[0].current_nozzle_diameter; cali_info.use_extruder_id = false; cali_info.use_nozzle_volume_type = false; CalibUtils::emit_get_PA_calib_infos(cali_info); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 73e9126ccd6..c0629fa2f39 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -98,18 +98,14 @@ static bool is_same_nozzle_diameters(const DynamicPrintConfig &full_config, cons try { std::string nozzle_type; const ConfigOptionEnum * config_nozzle_type = full_config.option>("nozzle_type"); - if (config_nozzle_type->value == NozzleType::ntHardenedSteel) { - nozzle_type = "hardened_steel"; - } else if (config_nozzle_type->value == NozzleType::ntStainlessSteel) { - nozzle_type = "stainless_steel"; - } + nozzle_type = NozzleTypeEumnToStr[config_nozzle_type->value]; auto opt_nozzle_diameters = full_config.option("nozzle_diameter"); if (opt_nozzle_diameters != nullptr) { float preset_nozzle_diameter = opt_nozzle_diameters->get_at(0); - if (preset_nozzle_diameter != obj->m_extder_data.extders[0].diameter) { + if (preset_nozzle_diameter != obj->m_extder_data.extders[0].current_nozzle_diameter) { wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"), wxString::Format("%.1f", preset_nozzle_diameter).ToStdString(), to_wstring_name(nozzle_type)); - wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->m_extder_data.extders[0].diameter, DeviceManager::nozzle_type_conver(obj->m_extder_data.extders[0].diameter)); + wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.1f %s"), obj->m_extder_data.extders[0].current_nozzle_diameter, to_wstring_name(NozzleTypeEumnToStr[obj->m_extder_data.extders[0].current_nozzle_type])); error_msg = _L("Your nozzle diameter in preset is not consistent with memorized nozzle diameter. Did you change your nozzle lately?") + "\n " + nozzle_in_preset + "\n " + nozzle_in_printer + "\n"; @@ -127,21 +123,15 @@ static bool is_same_nozzle_type(const DynamicPrintConfig &full_config, const Mac if (obj == nullptr) return true; - NozzleType nozzle_type = NozzleType::ntUndefine; - - if (obj->m_extder_data.extders[0].type == "stainless_steel") { - nozzle_type = NozzleType::ntStainlessSteel; - } else if (obj->m_extder_data.extders[0].type == "hardened_steel") { - nozzle_type = NozzleType::ntHardenedSteel; - } - + NozzleType nozzle_type = obj->m_extder_data.extders[0].current_nozzle_type; int printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(nozzle_type); + if (full_config.has("required_nozzle_HRC")) { int filament_nozzle_hrc = full_config.opt_int("required_nozzle_HRC", 0); if (abs(filament_nozzle_hrc) > abs(printer_nozzle_hrc)) { BOOST_LOG_TRIVIAL(info) << "filaments hardness mismatch: printer_nozzle_hrc = " << printer_nozzle_hrc << ", filament_nozzle_hrc = " << filament_nozzle_hrc; std::string filament_type = full_config.opt_string("filament_type", 0); - error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(obj->m_extder_data.extders[0].type)); + error_msg = wxString::Format(_L("*Printing %s material with %s may cause nozzle damage"), filament_type, to_wstring_name(NozzleTypeEumnToStr[obj->m_extder_data.extders[0].current_nozzle_type])); error_msg += "\n"; MessageDialog msg_dlg(nullptr, error_msg, wxEmptyString, wxICON_WARNING | wxOK | wxCANCEL); @@ -174,7 +164,7 @@ static bool check_nozzle_diameter_and_type(const DynamicPrintConfig &full_config } // P1P/S - if (obj->m_extder_data.extders[0].type.empty()) + if (obj->m_extder_data.extders[0].current_nozzle_type == NozzleType::ntUndefine) return true; if (!is_same_nozzle_diameters(full_config, obj, error_msg)) From 6e47c0c175aa63c4b0ebc51ed44bc6bfc7da7a64 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 24 May 2025 23:23:42 +0800 Subject: [PATCH 096/127] Fix issue that filament is rolled back and forth when click ams slots --- src/slic3r/GUI/Widgets/AMSControl.cpp | 22 +++++++++++++++++++++- src/slic3r/GUI/Widgets/AMSControl.hpp | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index f2f35df3953..3897927cccf 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -585,7 +585,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons delete info; }); - + Bind(EVT_AMS_ON_SELECTED, &AMSControl::AmsSelectedSwitch, this); m_button_guide->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) { post_event(wxCommandEvent(EVT_AMS_GUIDE_WIKI)); @@ -633,6 +633,26 @@ std::string AMSControl::GetCurrentCan(std::string amsid) return current_can; } +void AMSControl::AmsSelectedSwitch(wxCommandEvent& event) { + std::string ams_id_selected = std::to_string(event.GetInt()); + if (m_current_ams != ams_id_selected){ + m_current_ams = ams_id_selected; + } + if (m_current_show_ams != ams_id_selected && m_current_show_ams != "") { + auto item = m_ams_item_list[m_current_show_ams]; + if (!item) return; + try{ + const auto& can_lib_list = item->get_can_lib_list(); + for (auto can : can_lib_list) { + can.second->UnSelected(); + } + } + catch (...){ + ; + } + } +} + wxColour AMSControl::GetCanColour(std::string amsid, std::string canid) { wxColour col = *wxWHITE; diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 67158afe88f..c6ca606558f 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -112,6 +112,7 @@ class AMSControl : public wxSimplebook AMSModel m_is_none_ams_mode{AMSModel::EXT_AMS}; void SetAmsModel(AMSModel mode, AMSModel ext_mode) {m_ams_model = mode; m_ext_model = ext_mode;}; + void AmsSelectedSwitch(wxCommandEvent& event); void SetActionState(bool button_status[]); void EnterNoneAMSMode(); From 67ccaa3f6cb61063edc0a351e57eb189d2f97d7a Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 25 May 2025 14:38:40 +0800 Subject: [PATCH 097/127] Fix crash when H2D is present --- src/slic3r/GUI/Widgets/AMSControl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 3897927cccf..01537a20870 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -639,10 +639,10 @@ void AMSControl::AmsSelectedSwitch(wxCommandEvent& event) { m_current_ams = ams_id_selected; } if (m_current_show_ams != ams_id_selected && m_current_show_ams != "") { - auto item = m_ams_item_list[m_current_show_ams]; - if (!item) return; + auto iter = m_ams_item_list.find(m_current_show_ams); + if (iter == m_ams_item_list.end()) return; try{ - const auto& can_lib_list = item->get_can_lib_list(); + const auto& can_lib_list = iter->second->get_can_lib_list(); for (auto can : can_lib_list) { can.second->UnSelected(); } From 59c2a453abdcf59aa805673eb0853c77f33bea55 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 25 May 2025 16:45:31 +0800 Subject: [PATCH 098/127] Fix H2D AMS render --- src/slic3r/GUI/Widgets/AMSControl.cpp | 13 +++++++------ src/slic3r/GUI/Widgets/AMSItem.cpp | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 01537a20870..047adbeaeb6 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -18,6 +18,7 @@ namespace Slic3r { namespace GUI { #define AMS_CANS_SIZE wxSize(FromDIP(284), FromDIP(196)) #define AMS_CANS_WINDOW_SIZE wxSize(FromDIP(264), FromDIP(196)) +#define IS_GENERIC_AMS(model) (model != AMSModel::AMS_LITE && model != AMSModel::EXT_AMS) AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) : wxSimplebook(parent, wxID_ANY, pos, size) @@ -851,7 +852,7 @@ void AMSControl::UpdateStepCtrl(bool is_extrusion) m_filament_unload_step->DeleteAllItems(); m_filament_vt_load_step->DeleteAllItems(); - if (m_ams_model == AMSModel::GENERIC_AMS || m_ext_model == AMSModel::GENERIC_AMS) { + if (IS_GENERIC_AMS(m_ams_model) || IS_GENERIC_AMS(m_ext_model)) { if (is_extrusion) { m_filament_load_step->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_HEAT_NOZZLE]); m_filament_load_step->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CUT_FILAMENT]); @@ -980,7 +981,7 @@ void AMSControl::show_noams_mode() if (m_ams_model == AMSModel::EXT_AMS) { EnterNoneAMSMode(); - } else if(m_ams_model == AMSModel::GENERIC_AMS){ + } else if (IS_GENERIC_AMS(m_ams_model)){ EnterGenericAMSMode(); } else if (m_ams_model == AMSModel::AMS_LITE) { EnterExtraAMSMode(); @@ -1090,7 +1091,7 @@ void AMSControl::UpdateAms(std::vector ams_info, bool is_reset) Layout(); } - if (m_ams_model == AMSModel::GENERIC_AMS){ + if (IS_GENERIC_AMS(m_ams_model)) { m_ams_item_list = m_ams_generic_item_list; } else if (m_ams_model == AMSModel::AMS_LITE) { @@ -1247,7 +1248,7 @@ void AMSControl::SwitchAms(std::string ams_id) AmsItem* item = ams_item.second; if (item->get_ams_id() == ams_id) { - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (IS_GENERIC_AMS(m_ams_model)) { m_simplebook_generic_ams->SetSelection(item->get_selection()); } else if (m_ams_model == AMSModel::AMS_LITE) { @@ -1385,7 +1386,7 @@ bool AMSControl::Enable(bool enable) void AMSControl::SetExtruder(bool on_off, bool is_vams, std::string ams_now, wxColour col) { - if (m_ams_model == AMSModel::GENERIC_AMS || m_ext_model == AMSModel::GENERIC_AMS ) { + if (IS_GENERIC_AMS(m_ams_model) || IS_GENERIC_AMS(m_ext_model)) { if (!on_off) { m_extruder->TurnOff(); m_vams_extra_road->OnVamsLoading(false); @@ -1459,7 +1460,7 @@ void AMSControl::SetAmsStep(std::string ams_id, std::string canid, AMSPassRoadTy m_last_tray_id = canid; - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (IS_GENERIC_AMS(m_ams_model)) { if (step == AMSPassRoadSTEP::AMS_ROAD_STEP_NONE) { ams->SetAmsStep(canid, type, AMSPassRoadSTEP::AMS_ROAD_STEP_NONE); m_extruder->OnAmsLoading(false); diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 9d4178e517a..13007e41c8b 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -713,7 +713,7 @@ void AMSLib::on_left_down(wxMouseEvent &evt) auto top = 0; auto bottom = 0; - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (m_ams_model == AMSModel::GENERIC_AMS || m_ams_model == AMSModel::N3F_AMS || m_ams_model == AMSModel::N3S_AMS || m_ams_model == AMSModel::EXT_AMS) { top = (size.y - FromDIP(15) - m_bitmap_editable_light.GetBmpSize().y); bottom = size.y - FromDIP(15); } @@ -766,12 +766,12 @@ void AMSLib::render(wxDC &dc) #endif // text - if (m_ams_model == AMSModel::GENERIC_AMS) { - render_generic_text(dc); - } - else if (m_ams_model == AMSModel::AMS_LITE) { + if (m_ams_model == AMSModel::AMS_LITE) { render_lite_text(dc); } + else{ + render_generic_text(dc); + } } void AMSLib::render_lite_text(wxDC& dc) @@ -983,12 +983,12 @@ void AMSLib::render_generic_text(wxDC &dc) void AMSLib::doRender(wxDC &dc) { - if (m_ams_model == AMSModel::GENERIC_AMS) { - render_generic_lib(dc); - } - else if (m_ams_model == AMSModel::AMS_LITE) { + if (m_ams_model == AMSModel::AMS_LITE) { render_lite_lib(dc); } + else { + render_generic_lib(dc); + } } void AMSLib::render_lite_lib(wxDC& dc) @@ -2143,7 +2143,7 @@ void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size auto m_panel_road = new AMSRoad(amscan, wxID_ANY, caninfo, canindex, maxcan, wxDefaultPosition, AMS_CAN_ROAD_SIZE); - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (m_ams_model != AMSModel::AMS_LITE && m_ams_model != AMSModel::EXT_AMS) { //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); m_sizer_ams->Add(m_panel_refresh, 0, wxALIGN_CENTER_HORIZONTAL, 0); //m_sizer_ams->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(2)); @@ -2168,7 +2168,7 @@ void AmsItem::AddCan(Caninfo caninfo, int canindex, int maxcan, wxBoxSizer* size amscan->Layout(); amscan->Fit(); - if (m_ams_model == AMSModel::GENERIC_AMS) { + if (m_ams_model != AMSModel::AMS_LITE && m_ams_model != AMSModel::EXT_AMS) { sizer->Add(amscan, 0, wxALL, 0); } else if (m_ams_model == AMSModel::AMS_LITE) From 61aa5d2c095652d7415d53aaf5af34c87bd17b05 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sun, 25 May 2025 17:01:13 +0800 Subject: [PATCH 099/127] Sync AMS lite render code from BBS --- src/slic3r/GUI/Widgets/AMSItem.cpp | 180 +++++++++++++---------------- src/slic3r/GUI/Widgets/AMSItem.hpp | 1 + 2 files changed, 81 insertions(+), 100 deletions(-) diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 13007e41c8b..121d309ed05 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -2373,6 +2373,14 @@ void AmsItem::SetAmsStep(std::string can_id) m_road_canid = can_id; Refresh(); } + for (auto lib : m_can_lib_list){ + if (lib.second->m_info.can_id == can_id){ + lib.second->on_pass_road(true); + } + else{ + lib.second->on_pass_road(false); + } + } } void AmsItem::PlayRridLoading(wxString canid) @@ -2420,124 +2428,96 @@ void AmsItem::render(wxDC& dc) void AmsItem::doRender(wxDC& dc) { + wxSize size = GetSize(); + //road for extra if (m_ams_model == AMSModel::AMS_LITE) { - wxSize size = GetSize(); dc.DrawBitmap(m_bitmap_extra_framework.bmp(), (size.x - m_bitmap_extra_framework.GetBmpSize().x) / 2, (size.y - m_bitmap_extra_framework.GetBmpSize().y) / 2); - auto end_top = size.x / 2 - FromDIP(99); - auto passroad_width = 6; - - for (auto lib_it : m_can_lib_list) { - AMSLib* lib = lib_it.second; - - if (m_road_canid.empty()) { - lib->on_pass_road(false); - } - else { - if (lib->m_info.can_id == m_road_canid) { - m_road_colour = lib->m_info.material_colour; - lib->on_pass_road(true); - } - } - } - - // A1 dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + RenderLiteRoad(dc, size); + } +} - try - { - auto a1_top = size.y / 2 - FromDIP(4); - auto a1_left = m_can_lib_list["0"]->GetScreenPosition().x + m_can_lib_list["0"]->GetSize().x / 2; - auto local_pos1 = GetScreenPosition().x + GetSize().x / 2; - a1_left = size.x / 2 + (a1_left - local_pos1); - dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); - dc.DrawLine(a1_left, a1_top, end_top, a1_top); - - - // A2 - auto a2_top = size.y / 2 + FromDIP(8); - auto a2_left = m_can_lib_list["1"]->GetScreenPosition().x + m_can_lib_list["1"]->GetSize().x / 2; - auto local_pos2 = GetScreenPosition().x + GetSize().x / 2; - a2_left = size.x / 2 + (a2_left - local_pos2); - dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); - dc.DrawLine(a2_left, a2_top, end_top, a2_top); - - // A3 - auto a3_top = size.y / 2 + FromDIP(4); - auto a3_left = m_can_lib_list["2"]->GetScreenPosition().x + m_can_lib_list["2"]->GetSize().x / 2; - auto local_pos3 = GetScreenPosition().x + GetSize().x / 2; - a3_left = size.x / 2 + (a3_left - local_pos3); - dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); - dc.DrawLine(a3_left, a3_top, end_top, a3_top); - - - // A4 - auto a4_top = size.y / 2; - auto a4_left = m_can_lib_list["3"]->GetScreenPosition().x + m_can_lib_list["3"]->GetSize().x / 2; - auto local_pos4 = GetScreenPosition().x + GetSize().x / 2; - a4_left = size.x / 2 + (a4_left - local_pos4); - dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); - dc.DrawLine(a4_left, a4_top, end_top, a4_top); - - - if (!m_road_canid.empty()) { - if (m_road_canid == "0") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); - dc.DrawLine(a1_left, a1_top, end_top, a1_top); - } +void AmsItem::RenderLiteRoad(wxDC& dc, wxSize size) { + auto end_top = size.x / 2 - FromDIP(99); + auto passroad_width = 6; + auto a1_top = size.y / 2 - FromDIP(4); + auto a2_top = size.y / 2 + FromDIP(8); + auto a3_top = size.y / 2 + FromDIP(4); + auto a4_top = size.y / 2; - if (m_road_canid == "1") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); - dc.DrawLine(a2_left, a2_top, end_top, a2_top); - } + try + { + auto a1_left = m_can_lib_list["0"]->GetScreenPosition().x + m_can_lib_list["0"]->GetSize().x / 2; + auto local_pos1 = GetScreenPosition().x + GetSize().x / 2; + a1_left = size.x / 2 + (a1_left - local_pos1); + dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); + dc.DrawLine(a1_left, a1_top, end_top, a1_top); + + // A2 + auto a2_left = m_can_lib_list["1"]->GetScreenPosition().x + m_can_lib_list["1"]->GetSize().x / 2; + auto local_pos2 = GetScreenPosition().x + GetSize().x / 2; + a2_left = size.x / 2 + (a2_left - local_pos2); + dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); + dc.DrawLine(a2_left, a2_top, end_top, a2_top); + + // A3 + auto a3_left = m_can_lib_list["2"]->GetScreenPosition().x + m_can_lib_list["2"]->GetSize().x / 2; + auto local_pos3 = GetScreenPosition().x + GetSize().x / 2; + a3_left = size.x / 2 + (a3_left - local_pos3); + dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); + dc.DrawLine(a3_left, a3_top, end_top, a3_top); + + + //// A4 + auto a4_left = m_can_lib_list["3"]->GetScreenPosition().x + m_can_lib_list["3"]->GetSize().x / 2; + auto local_pos4 = GetScreenPosition().x + GetSize().x / 2; + a4_left = size.x / 2 + (a4_left - local_pos4); + dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); + dc.DrawLine(a4_left, a4_top, end_top, a4_top); + + //to Extruder + dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); + dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + dc.DrawLine(end_top, a1_top, end_top, size.y); - if (m_road_canid == "2") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); - dc.DrawLine(a3_left, a3_top, end_top, a3_top); - } - if (m_road_canid == "3") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); - dc.DrawLine(a4_left, a4_top, end_top, a4_top); - } + if (!m_road_canid.empty()) { + int can_idx = atoi(m_road_canid.c_str()); + if (can_idx < 0 || can_idx >= m_info.cans.size()) { + return; + } + m_road_colour = m_info.cans[can_idx].material_colour; + dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); + if (m_road_canid == "0") { + dc.DrawLine(a1_left, FromDIP(30), a1_left, a1_top); + dc.DrawLine(a1_left, a1_top, end_top, a1_top); + dc.DrawLine(end_top, a1_top, end_top, size.y); } - //to Extruder - dc.SetPen(wxPen(AMS_CONTROL_GRAY500, 2, wxPENSTYLE_SOLID)); - dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); + if (m_road_canid == "1") { + dc.DrawLine(a2_left, FromDIP(160), a2_left, a2_top); + dc.DrawLine(a2_left, a2_top, end_top, a2_top); + dc.DrawLine(end_top, a2_top, end_top, size.y); + } - dc.DrawLine(end_top, a1_top, end_top, size.y); + if (m_road_canid == "2") { + dc.DrawLine(a3_left, FromDIP(160), a3_left, a3_top); + dc.DrawLine(a3_left, a3_top, end_top, a3_top); + dc.DrawLine(end_top, a3_top, end_top, size.y); + } - if (!m_road_canid.empty()) { - if (!m_road_canid.empty()) { - if (m_road_canid == "0") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a1_top, end_top, size.y); - } - else if (m_road_canid == "1") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a2_top, end_top, size.y); - } - else if (m_road_canid == "2") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a3_top, end_top, size.y); - } - else if (m_road_canid == "3") { - dc.SetPen(wxPen(m_road_colour, passroad_width, wxPENSTYLE_SOLID)); - dc.DrawLine(end_top, a4_top, end_top, size.y); - } - } + if (m_road_canid == "3") { + dc.DrawLine(a4_left, FromDIP(30), a4_left, a4_top); + dc.DrawLine(a4_left, a4_top, end_top, a4_top); + dc.DrawLine(end_top, a4_top, end_top, size.y); } } - catch (...){} } + catch (...) {} } void AmsItem::StopRridLoading(wxString canid) diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 2cb771440ec..52a82fc04b9 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -572,6 +572,7 @@ class AmsItem : public wxWindow void paintEvent(wxPaintEvent& evt); void render(wxDC& dc); void doRender(wxDC& dc); + void RenderLiteRoad(wxDC& dc, wxSize size); wxColour GetTagColr(wxString canid); std::string GetCurrentCan(); From 6fca6f527c5ff7f003fc2926a1c5b760d29cf8ff Mon Sep 17 00:00:00 2001 From: tao wang Date: Mon, 31 Mar 2025 16:57:10 +0800 Subject: [PATCH 100/127] ENH:support new chamber temper protocols jira:[none] Change-Id: Id068b7144eacd03da342a15468d998b80f3cb8f2 (cherry picked from commit 17e0490337b61d0c38d8c17a56ac97c3d4a9034e) --- src/slic3r/GUI/DeviceManager.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index adc7d57e143..2117481013a 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -5677,6 +5677,19 @@ void MachineObject::parse_new_info(json print) m_extder_data = extder_data; } + + if (device.contains("ctc")) { + json const& ctc = device["ctc"]; + int state = get_flag_bits(ctc["state"].get(), 0, 4); + + if (ctc.contains("info")) { + json const &info = ctc["info"]; + chamber_temp = get_flag_bits(info["temp"].get(), 0, 16); + chamber_temp_target = get_flag_bits(info["temp"].get(), 16, 16); + } + + + } } } From 23c148fb741e6a31b27707c97a967288716fab57 Mon Sep 17 00:00:00 2001 From: "liz.li" Date: Tue, 10 Dec 2024 15:35:15 +0800 Subject: [PATCH 101/127] ENH: o series don't show ams hub jira: STUDIO-8568 Change-Id: I298e026f70211595ca58c69c6345961dbc64e350 (cherry picked from commit a6c29c3ad0a3030f3be90af58f1689bb1b28ab37) (cherry picked from commit 8b6f1612d819b47114449648578e6d07c6699016) --- resources/images/printer_thumbnail_h2d.svg | 531 +++++++++++++++++ .../images/printer_thumbnail_h2d_dark.svg | 533 ++++++++++++++++++ resources/printers/O1D.json | 74 +++ src/slic3r/GUI/DeviceManager.cpp | 2 +- src/slic3r/GUI/UpgradePanel.cpp | 6 +- 5 files changed, 1143 insertions(+), 3 deletions(-) create mode 100644 resources/images/printer_thumbnail_h2d.svg create mode 100644 resources/images/printer_thumbnail_h2d_dark.svg create mode 100644 resources/printers/O1D.json diff --git a/resources/images/printer_thumbnail_h2d.svg b/resources/images/printer_thumbnail_h2d.svg new file mode 100644 index 00000000000..9108233afc1 --- /dev/null +++ b/resources/images/printer_thumbnail_h2d.svg @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/printer_thumbnail_h2d_dark.svg b/resources/images/printer_thumbnail_h2d_dark.svg new file mode 100644 index 00000000000..050c20f449a --- /dev/null +++ b/resources/images/printer_thumbnail_h2d_dark.svg @@ -0,0 +1,533 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/printers/O1D.json b/resources/printers/O1D.json new file mode 100644 index 00000000000..3892481cdd8 --- /dev/null +++ b/resources/printers/O1D.json @@ -0,0 +1,74 @@ +{ + "00.00.00.00": { + "display_name": "Bambu Lab H2D", + "print": { + "2D": { + "laser": { + "power": [ 10, 40 ] + } + }, + "ipcam": { + "resolution_supported": [ "1080p" ], + "virtual_camera": "enabled", + "liveview": { + "remote": "tutk" + }, + "file": { + "local": "local", + "remote": "tutk", + "model_download": "enabled" + } + }, + "nozzle_temp_range": [ 20, 350 ], + "bed_temp_range": [ 20, 120 ], + "support_motor_noise_cali": false, + "support_tunnel_mqtt": true, + "support_mqtt_alive": true, + "support_command_ams_switch": true, + "support_ssl_for_mqtt": true, + "support_cloud_print_only": false, + "support_1080dpi": true, + "support_prompt_sound": false, + "support_ams_humidity": true, + "support_auto_recovery_step_loss": true, + "support_bed_leveling": 2, + "support_update_remain": true, + "support_timelapse": true, + "support_filament_backup": true, + "support_chamber_fan": true, + "support_aux_fan": true, + "support_send_to_sd": true, + "support_print_all": true, + "support_print_without_sd": true, + "support_flow_calibration": true, + "support_auto_flow_calibration": true, + "support_build_plate_marker_detect": true, + "support_build_plate_marker_detect_type": 2, + "support_lidar_calibration": false, + "support_nozzle_offset_calibration": true, + "support_high_tempbed_calibration": true, + "support_ai_monitoring": true, + "support_first_layer_inspect": false, + "support_save_remote_print_file_to_storage": true, + "support_chamber_temp_edit": true, + "support_chamber_temp_edit_range": [ 20, 65 ], + "support_chamber_temp_switch_heating": 40, + "support_extrusion_cali": false, + "support_user_preset": false + }, + "model_id": "O1D", + "printer_modes": [ "fdm", "laser", "cut" ], + "compatible_machine": [], + "printer_type": "O1D", + "printer_thumbnail_image": "printer_thumbnail_h2d", + "printer_connect_help_image": "input_access_code_h2d", + "printer_use_ams_image": "ams_icon", + "printer_ext_image": ["ext_image_o_right", "ext_image_o_left"], + "use_ams_type": "generic", + "printer_arch": "core_xy", + "printer_series": "series_o", + "has_cali_line": true, + "printer_is_enclosed": true, + "enable_set_nozzle_info": false + } +} \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 2117481013a..fe48163b830 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -531,7 +531,7 @@ bool MachineObject::is_lan_mode_printer() const PrinterSeries MachineObject::get_printer_series() const { std::string series = DeviceManager::get_printer_series(printer_type); - if (series == "series_x1") + if (series == "series_x1" || series == "series_o") return PrinterSeries::SERIES_X1; else if (series == "series_p1p") return PrinterSeries::SERIES_P1P; diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 9241aac4d57..c8463dedb7c 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -632,8 +632,10 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) { bool has_hub_model = false; + bool is_o_series = DeviceManager::get_printer_series(obj->printer_type) == "series_o"; + //hub - if (!obj->online_ahb || obj->module_vers.find("ahb") == obj->module_vers.end()) + if (!obj->online_ahb || obj->module_vers.find("ahb") == obj->module_vers.end() || is_o_series) m_ahb_panel->Hide(); else { has_hub_model = true; @@ -946,7 +948,7 @@ void MachineInfoPanel::update_ams_ext(MachineObject *obj) //ext auto ext_module = obj->module_vers.find("ext"); - if (ext_module == obj->module_vers.end()) + if (ext_module == obj->module_vers.end() || is_o_series) show_ext(false); else { wxString sn_text = ext_module->second.sn; From d613662ef7f71adacba67bc09c336a2d64a62533 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Fri, 27 Dec 2024 20:27:45 +0800 Subject: [PATCH 102/127] FIX: Calibration adaptation encryption jira: none Change-Id: Ie42da224ca02261b0c32262be895c215878b7921 (cherry picked from commit 7498d6e5f89751d4f576ba073485238baba53d0f) --- src/slic3r/GUI/CaliHistoryDialog.cpp | 3 +- src/slic3r/GUI/CaliHistoryDialog.hpp | 1 - src/slic3r/GUI/DeviceManager.cpp | 65 +++++++++++++++------------- src/slic3r/GUI/DeviceManager.hpp | 1 + src/slic3r/GUI/Monitor.cpp | 6 ++- src/slic3r/GUI/StatusPanel.cpp | 2 +- 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/slic3r/GUI/CaliHistoryDialog.cpp b/src/slic3r/GUI/CaliHistoryDialog.cpp index 46a3eb4f4e8..3d5bbcd646e 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.cpp +++ b/src/slic3r/GUI/CaliHistoryDialog.cpp @@ -201,9 +201,8 @@ void HistoryWindow::update(MachineObject* obj) { if (!obj) return; - if (obj->cali_version != history_version) { + if (obj->cali_version != obj->last_cali_version) { if (obj->has_get_pa_calib_tab) { - history_version = obj->cali_version; reqeust_history_result(obj); } } diff --git a/src/slic3r/GUI/CaliHistoryDialog.hpp b/src/slic3r/GUI/CaliHistoryDialog.hpp index 8f7b49a25a6..b8ef7666e30 100644 --- a/src/slic3r/GUI/CaliHistoryDialog.hpp +++ b/src/slic3r/GUI/CaliHistoryDialog.hpp @@ -36,7 +36,6 @@ class HistoryWindow : public DPIDialog { bool& m_show_history_dialog; std::vector m_calib_results_history; MachineObject* curr_obj { nullptr }; - int history_version = -1; }; class EditCalibrationHistoryDialog : public DPIDialog diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index fe48163b830..576fca14de5 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -706,7 +706,7 @@ bool MachineObject::is_extrusion_cali_finished() if (diff.count() < EXTRUSION_OMIT_TIME) { return false; } - + if (boost::contains(m_gcode_file, "extrusion_cali") && this->mc_print_percent == 100) return true; @@ -929,6 +929,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std } } + // is_support_ams_mapping if (!is_support_ams_mapping()) { BOOST_LOG_TRIVIAL(info) << "ams_mapping: do not support, use order mapping"; @@ -1033,7 +1034,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std } continue; } - + if (distance_map[i][j].is_same_color && distance_map[i][j].is_type_match) { if (min_val > distance_map[i][j].distance) { @@ -1041,7 +1042,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std min_val = distance_map[i][j].distance; picked_src_idx = i; picked_tar_idx = j; - } + } else if (min_val == distance_map[i][j].distance&& filaments[picked_src_idx].filament_id!= tray_filaments[picked_tar_idx].filament_id && filaments[i].filament_id == tray_filaments[j].filament_id) { picked_src_idx = i; @@ -1682,7 +1683,7 @@ int MachineObject::command_get_access_code() { json j; j["system"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["system"]["command"] = "get_access_code"; - + return this->publish_json(j.dump()); } @@ -1884,7 +1885,7 @@ int MachineObject::command_set_nozzle(int temp) int MachineObject::command_set_chamber(int temp) { json j; - j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["command"] = "set_ctt"; j["print"]["ctt_val"] = temp; @@ -2914,7 +2915,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) else { if (!printer_type.empty() && connection_type() == "lan") print_json.load_compatible_settings(printer_type, ""); - print_json.diff2all_base_reset(j_pre); + print_json.diff2all_base_reset(j_pre); } } } @@ -3587,7 +3588,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("heatbreak_fan_speed")) { heatbreak_fan_speed = stoi(jj["heatbreak_fan_speed"].get()); } - + /* parse speed */ try { if (jj.contains("spd_lvl")) { @@ -3918,7 +3919,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) virtual_camera = ipcam.value("virtual_camera", "disabled") == "enabled"; if (ipcam.contains("rtsp_url")) { local_rtsp_url = ipcam["rtsp_url"].get(); - liveview_local = local_rtsp_url.empty() ? LVL_None : local_rtsp_url == "disable" + liveview_local = local_rtsp_url.empty() ? LVL_None : local_rtsp_url == "disable" ? LVL_Disable : boost::algorithm::starts_with(local_rtsp_url, "rtsps") ? LVL_Rtsps : LVL_Rtsp; } if (ipcam.contains("tutk_server")) { @@ -4680,17 +4681,26 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } } } - } + } else if (jj["command"].get() == "extrusion_cali_get") { + std::string str = jj.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get: " << str; + reset_pa_cali_history_result(); + bool is_succeed = true; if (jj.contains("result") && jj.contains("reason")) { if (jj["result"].get() == "fail") { - auto err_code = jj["err_code"].get(); - print_error = err_code; + if (jj.contains("err_code")) { + auto err_code = jj["err_code"].get(); + print_error = err_code; + } + is_succeed = false; } } - reset_pa_cali_history_result(); - has_get_pa_calib_tab = true; + if (is_succeed) { + last_cali_version = cali_version; + has_get_pa_calib_tab = true; + } if (jj.contains("nozzle_diameter")) { if (jj["nozzle_diameter"].is_number_float()) { @@ -4717,11 +4727,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj.contains("filaments") && jj["filaments"].is_array()) { try { -#ifdef CALI_DEBUG - std::string str = jj.dump(); - BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get: " << str; -#endif - for (auto it = jj["filaments"].begin(); it != jj["filaments"].end(); it++) { PACalibResult pa_calib_result; pa_calib_result.filament_id = (*it)["filament_id"].get(); @@ -4760,23 +4765,25 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) // notify cali history to update } else if (jj["command"].get() == "extrusion_cali_get_result") { + std::string str = jj.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get_result: " << str; + reset_pa_cali_result(); + bool is_succeed = true; if (jj.contains("result") && jj.contains("reason")) { if (jj["result"].get() == "fail") { - auto err_code = jj["err_code"].get(); - print_error = err_code; + if (jj.contains("err_code")) { + auto err_code = jj["err_code"].get(); + print_error = err_code; + is_succeed = false; + } } } - reset_pa_cali_result(); - get_pa_calib_result = true; + if (is_succeed) + get_pa_calib_result = true; if (jj.contains("filaments") && jj["filaments"].is_array()) { try { -#ifdef CALI_DEBUG - std::string str = jj.dump(); - BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get_result: " << str; -#endif - for (auto it = jj["filaments"].begin(); it != jj["filaments"].end(); it++) { PACalibResult pa_calib_result; pa_calib_result.tray_id = (*it)["tray_id"].get(); @@ -4862,7 +4869,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (it->contains("confidence")) { flow_ratio_calib_result.confidence = (*it)["confidence"].get(); } else { - flow_ratio_calib_result.confidence = 0; + flow_ratio_calib_result.confidence = 0; } flow_ratio_results.push_back(flow_ratio_calib_result); @@ -6194,7 +6201,7 @@ void DeviceManager::on_machine_alive(std::string json_str) if(obj->dev_connection_name.empty()){obj->dev_connection_name = connection_name;} obj->dev_ip = dev_ip; } - + } /* ip changed reconnect mqtt */ } diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 654e4c9a888..dd32e3ef335 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -710,6 +710,7 @@ class MachineObject bool is_support_layer_num { false }; bool nozzle_blob_detection_enabled{ false }; + int last_cali_version = -1; int cali_version = -1; float cali_selected_nozzle_dia { 0.0 }; // 1: record when start calibration in preset page diff --git a/src/slic3r/GUI/Monitor.cpp b/src/slic3r/GUI/Monitor.cpp index 333f4d3de00..00aacf2f8cc 100644 --- a/src/slic3r/GUI/Monitor.cpp +++ b/src/slic3r/GUI/Monitor.cpp @@ -297,8 +297,12 @@ void MonitorPanel::on_update_all(wxMouseEvent &event) update_all(); MachineObject *obj_ = dev->get_selected_machine(); - if (obj_) + if (obj_) { + obj_->last_cali_version = -1; + obj_->reset_pa_cali_history_result(); + obj_->reset_pa_cali_result(); GUI::wxGetApp().sidebar().load_ams_list(obj_->dev_id, obj_); + } Layout(); Refresh(); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index caf6750b1dc..c57ca721d92 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -2584,7 +2584,7 @@ void StatusPanel::update_ams(MachineObject *obj) } if (m_filament_setting_dlg) { m_filament_setting_dlg->obj = obj; } - if (obj->cali_version != -1 && last_cali_version != obj->cali_version) { + if (obj && (obj->last_cali_version != obj->cali_version)) { last_cali_version = obj->cali_version; PACalibExtruderInfo cali_info; cali_info.nozzle_diameter = obj->m_extder_data.extders[0].current_nozzle_diameter; From 8579885e8ee8d603f1c46dceee066ab00fd6a111 Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Sat, 12 Oct 2024 16:47:39 +0800 Subject: [PATCH 103/127] FIX: FIX cali protocol add extruder_id for start_cali and add protection for setting_id jira:none Change-Id: Idd8eeaa38c618c0ef8db10064d3e4d9793487aa6 (cherry picked from commit 9097efd8699b93d1d8a128eadf55a9252fa728ad) --- src/slic3r/GUI/DeviceManager.cpp | 42 +++++++++++++------------------- src/slic3r/GUI/DeviceManager.hpp | 4 --- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 576fca14de5..bed35f8a21e 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -2298,6 +2298,7 @@ int MachineObject::command_start_pa_calibration(const X1CCalibInfos &pa_data, in std::string filament_ids; for (int i = 0; i < pa_data.calib_datas.size(); ++i) { j["print"]["filaments"][i]["tray_id"] = pa_data.calib_datas[i].tray_id; + j["print"]["filaments"][i]["extruder_id"] = pa_data.calib_datas[i].extruder_id; j["print"]["filaments"][i]["bed_temp"] = pa_data.calib_datas[i].bed_temp; j["print"]["filaments"][i]["filament_id"] = pa_data.calib_datas[i].filament_id; j["print"]["filaments"][i]["setting_id"] = pa_data.calib_datas[i].setting_id; @@ -4702,38 +4703,26 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) has_get_pa_calib_tab = true; } - if (jj.contains("nozzle_diameter")) { - if (jj["nozzle_diameter"].is_number_float()) { - pa_calib_tab_info.pa_calib_tab_nozzle_dia = jj["nozzle_diameter"].get(); - } - else if (jj["nozzle_diameter"].is_string()) { - pa_calib_tab_info.pa_calib_tab_nozzle_dia = string_to_float(jj["nozzle_diameter"].get()); - } - else { - assert(false); - } - } - else { - assert(false); - } - - if (jj.contains("extruder_id")) { - pa_calib_tab_info.extruder_id = jj["extruder_id"].get(); - } - - if (jj.contains("nozzle_volume_type")) { - pa_calib_tab_info.nozzle_volume_type = NozzleVolumeType(jj["nozzle_volume_type"].get()); - } - if (jj.contains("filaments") && jj["filaments"].is_array()) { try { for (auto it = jj["filaments"].begin(); it != jj["filaments"].end(); it++) { PACalibResult pa_calib_result; pa_calib_result.filament_id = (*it)["filament_id"].get(); - pa_calib_result.setting_id = (*it)["setting_id"].get(); pa_calib_result.name = (*it)["name"].get(); pa_calib_result.cali_idx = (*it)["cali_idx"].get(); + if ((*it).contains("setting_id")) { + pa_calib_result.setting_id = (*it)["setting_id"].get(); + } + + if ((*it).contains("extruder_id")) { + pa_calib_result.extruder_id = (*it)["extruder_id"].get(); + } + + if ((*it).contains("nozzle_id")) { + pa_calib_result.nozzle_volume_type = convert_to_nozzle_type((*it)["nozzle_id"].get()); + } + if (jj["nozzle_diameter"].is_number_float()) { pa_calib_result.nozzle_diameter = jj["nozzle_diameter"].get(); } else if (jj["nozzle_diameter"].is_string()) { @@ -4788,7 +4777,10 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) PACalibResult pa_calib_result; pa_calib_result.tray_id = (*it)["tray_id"].get(); pa_calib_result.filament_id = (*it)["filament_id"].get(); - pa_calib_result.setting_id = (*it)["setting_id"].get(); + + if ((*it).contains("setting_id")) { + pa_calib_result.setting_id = (*it)["setting_id"].get(); + } if (jj["nozzle_diameter"].is_number_float()) { pa_calib_result.nozzle_diameter = jj["nozzle_diameter"].get(); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index dd32e3ef335..278cb251cad 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -724,16 +724,12 @@ class MachineObject ManualPaCaliMethod manual_pa_cali_method = ManualPaCaliMethod::PA_LINE; bool has_get_pa_calib_tab{ false }; std::vector pa_calib_tab; - PACalibTabInfo pa_calib_tab_info; bool get_pa_calib_result { false }; std::vector pa_calib_results; bool get_flow_calib_result { false }; std::vector flow_ratio_results; void reset_pa_cali_history_result() { - pa_calib_tab_info.pa_calib_tab_nozzle_dia = 0.4f; - pa_calib_tab_info.extruder_id = -1; - pa_calib_tab_info.nozzle_volume_type = NozzleVolumeType::nvtNormal; has_get_pa_calib_tab = false; pa_calib_tab.clear(); } From aebd2f530512e967ede18d7c0adcbfd914b4a6ac Mon Sep 17 00:00:00 2001 From: "zhimin.zeng" Date: Thu, 23 Jan 2025 11:38:06 +0800 Subject: [PATCH 104/127] FIX:k value is set to default value when editing k value on printer jira: STUDIO-10120 Change-Id: I6c67efb77ca681aab510399031deed7faa473713 (cherry picked from commit 7380ee0a2c488bc5b206f4f6462e81ff744cc8d2) --- src/slic3r/GUI/DeviceManager.cpp | 128 ++++++++++++++++--------------- src/slic3r/GUI/DeviceManager.hpp | 1 + 2 files changed, 68 insertions(+), 61 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index bed35f8a21e..d811540383d 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -2313,7 +2313,7 @@ int MachineObject::command_start_pa_calibration(const X1CCalibInfos &pa_data, in filament_ids += pa_data.calib_datas[i].filament_id; } - BOOST_LOG_TRIVIAL(trace) << "extrusion_cali: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali: " << j.dump(); try { json js; @@ -2359,7 +2359,7 @@ int MachineObject::command_set_pa_calibration(const std::vector & j["print"]["filaments"][i]["n_coef"] = "0.0"; } - BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_set: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_set: " << j.dump(); return this->publish_json(j.dump()); } @@ -2377,7 +2377,7 @@ int MachineObject::command_delete_pa_calibration(const PACalibIndexInfo& pa_cali j["print"]["cali_idx"] = pa_calib.cali_idx; j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(pa_calib.nozzle_diameter); - BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_del: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_del: " << j.dump(); return this->publish_json(j.dump()); } @@ -2395,7 +2395,8 @@ int MachineObject::command_get_pa_calibration_tab(const PACalibExtruderInfo &cal j["print"]["nozzle_id"] = generate_nozzle_id(calib_info.nozzle_volume_type, to_string_nozzle_diameter(calib_info.nozzle_diameter)).ToStdString(); j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(calib_info.nozzle_diameter); - BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_get: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get: " << j.dump(); + request_tab_from_bbs = true; return this->publish_json(j.dump()); } @@ -2406,7 +2407,7 @@ int MachineObject::command_get_pa_calibration_result(float nozzle_diameter) j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(nozzle_diameter); - BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_get_result: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get_result: " << j.dump(); return this->publish_json(j.dump()); } @@ -2422,7 +2423,7 @@ int MachineObject::commnad_select_pa_calibration(const PACalibIndexInfo& pa_cali j["print"]["filament_id"] = pa_calib_info.filament_id; j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(pa_calib_info.nozzle_diameter); - BOOST_LOG_TRIVIAL(trace) << "extrusion_cali_sel: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "extrusion_cali_sel: " << j.dump(); return this->publish_json(j.dump()); } @@ -2452,7 +2453,7 @@ int MachineObject::command_start_flow_ratio_calibration(const X1CCalibInfos& cal filament_ids += calib_data.calib_datas[i].filament_id; } - BOOST_LOG_TRIVIAL(trace) << "flowrate_cali: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "flowrate_cali: " << j.dump(); return this->publish_json(j.dump()); } return -1; @@ -2465,7 +2466,7 @@ int MachineObject::command_get_flow_ratio_calibration_result(float nozzle_diamet j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["nozzle_diameter"] = to_string_nozzle_diameter(nozzle_diameter); - BOOST_LOG_TRIVIAL(trace) << "flowrate_get_result: " << j.dump(); + BOOST_LOG_TRIVIAL(info) << "flowrate_get_result: " << j.dump(); return this->publish_json(j.dump()); } @@ -4582,7 +4583,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) info = reason; } GUI::wxGetApp().push_notification(info, _L("Calibration error"), UserNotificationStyle::UNS_WARNING_CONFIRM); - BOOST_LOG_TRIVIAL(trace) << cali_mode << " result fail, reason = " << reason; + BOOST_LOG_TRIVIAL(info) << cali_mode << " result fail, reason = " << reason; } } } else if (jj["command"].get() == "extrusion_cali_set") { @@ -4685,73 +4686,78 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } else if (jj["command"].get() == "extrusion_cali_get") { std::string str = jj.dump(); - BOOST_LOG_TRIVIAL(info) << "extrusion_cali_get: " << str; - reset_pa_cali_history_result(); - bool is_succeed = true; - if (jj.contains("result") && jj.contains("reason")) { - if (jj["result"].get() == "fail") { - if (jj.contains("err_code")) { - auto err_code = jj["err_code"].get(); - print_error = err_code; + if (request_tab_from_bbs) { + BOOST_LOG_TRIVIAL(info) << "bbs extrusion_cali_get: " << str; + request_tab_from_bbs = false; + reset_pa_cali_history_result(); + bool is_succeed = true; + if (jj.contains("result") && jj.contains("reason")) { + if (jj["result"].get() == "fail") { + if (jj.contains("err_code")) { + auto err_code = jj["err_code"].get(); + print_error = err_code; + } + is_succeed = false; } - is_succeed = false; } - } - - if (is_succeed) { - last_cali_version = cali_version; - has_get_pa_calib_tab = true; - } - if (jj.contains("filaments") && jj["filaments"].is_array()) { - try { - for (auto it = jj["filaments"].begin(); it != jj["filaments"].end(); it++) { - PACalibResult pa_calib_result; - pa_calib_result.filament_id = (*it)["filament_id"].get(); - pa_calib_result.name = (*it)["name"].get(); - pa_calib_result.cali_idx = (*it)["cali_idx"].get(); + if (is_succeed) { + last_cali_version = cali_version; + has_get_pa_calib_tab = true; + } - if ((*it).contains("setting_id")) { - pa_calib_result.setting_id = (*it)["setting_id"].get(); - } + if (jj.contains("filaments") && jj["filaments"].is_array()) { + try { + for (auto it = jj["filaments"].begin(); it != jj["filaments"].end(); it++) { + PACalibResult pa_calib_result; + pa_calib_result.filament_id = (*it)["filament_id"].get(); + pa_calib_result.name = (*it)["name"].get(); + pa_calib_result.cali_idx = (*it)["cali_idx"].get(); + + if ((*it).contains("setting_id")) { + pa_calib_result.setting_id = (*it)["setting_id"].get(); + } - if ((*it).contains("extruder_id")) { - pa_calib_result.extruder_id = (*it)["extruder_id"].get(); - } + if ((*it).contains("extruder_id")) { + pa_calib_result.extruder_id = (*it)["extruder_id"].get(); + } - if ((*it).contains("nozzle_id")) { - pa_calib_result.nozzle_volume_type = convert_to_nozzle_type((*it)["nozzle_id"].get()); - } + if ((*it).contains("nozzle_id")) { + pa_calib_result.nozzle_volume_type = convert_to_nozzle_type((*it)["nozzle_id"].get()); + } - if (jj["nozzle_diameter"].is_number_float()) { - pa_calib_result.nozzle_diameter = jj["nozzle_diameter"].get(); - } else if (jj["nozzle_diameter"].is_string()) { - pa_calib_result.nozzle_diameter = string_to_float(jj["nozzle_diameter"].get()); - } + if (jj["nozzle_diameter"].is_number_float()) { + pa_calib_result.nozzle_diameter = jj["nozzle_diameter"].get(); + } else if (jj["nozzle_diameter"].is_string()) { + pa_calib_result.nozzle_diameter = string_to_float(jj["nozzle_diameter"].get()); + } - if ((*it)["k_value"].is_number_float()) - pa_calib_result.k_value = (*it)["k_value"].get(); - else if ((*it)["k_value"].is_string()) - pa_calib_result.k_value = string_to_float((*it)["k_value"].get()); + if ((*it)["k_value"].is_number_float()) + pa_calib_result.k_value = (*it)["k_value"].get(); + else if ((*it)["k_value"].is_string()) + pa_calib_result.k_value = string_to_float((*it)["k_value"].get()); - if ((*it)["n_coef"].is_number_float()) - pa_calib_result.n_coef = (*it)["n_coef"].get(); - else if ((*it)["n_coef"].is_string()) - pa_calib_result.n_coef = string_to_float((*it)["n_coef"].get()); + if ((*it)["n_coef"].is_number_float()) + pa_calib_result.n_coef = (*it)["n_coef"].get(); + else if ((*it)["n_coef"].is_string()) + pa_calib_result.n_coef = string_to_float((*it)["n_coef"].get()); - if (check_pa_result_validation(pa_calib_result)) - pa_calib_tab.push_back(pa_calib_result); - else { - BOOST_LOG_TRIVIAL(info) << "pa result is invalid"; + if (check_pa_result_validation(pa_calib_result)) + pa_calib_tab.push_back(pa_calib_result); + else { + BOOST_LOG_TRIVIAL(info) << "pa result is invalid"; + } } - } - } - catch (...) { + } + catch (...) { + } } + // notify cali history to update + } else { + BOOST_LOG_TRIVIAL(info) << "printer extrusion_cali_get: " << str; } - // notify cali history to update } else if (jj["command"].get() == "extrusion_cali_get_result") { std::string str = jj.dump(); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 278cb251cad..15ace5001f5 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -723,6 +723,7 @@ class MachineObject ManualPaCaliMethod manual_pa_cali_method = ManualPaCaliMethod::PA_LINE; bool has_get_pa_calib_tab{ false }; + bool request_tab_from_bbs { false }; std::vector pa_calib_tab; bool get_pa_calib_result { false }; std::vector pa_calib_results; From 057ba55c8753fca6b41cc1a5a4e20720cda0cb82 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 26 May 2025 09:55:56 +0800 Subject: [PATCH 105/127] Fix crash when attempt to start remote live view for H2D --- resources/images/input_access_code_h2d_cn.png | Bin 0 -> 234359 bytes resources/images/input_access_code_h2d_en.png | Bin 0 -> 132008 bytes src/slic3r/GUI/DeviceManager.cpp | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 resources/images/input_access_code_h2d_cn.png create mode 100644 resources/images/input_access_code_h2d_en.png diff --git a/resources/images/input_access_code_h2d_cn.png b/resources/images/input_access_code_h2d_cn.png new file mode 100644 index 0000000000000000000000000000000000000000..1a29777339f141f07be53437b6a3fcd343fbe956 GIT binary patch literal 234359 zcmeFZ_d`=z_dSed6cq&>nuvf6kuD&;3<`);LAq3>_fF{8KtMo1K>CORLMQ^#yEHLE z#0U{Xs6vbZLPw;%`)1~Op3g7ufAGCO%nZrRz2~00&)#dVwa!G})VY52Fvnp!I=Z7b z)K&E9=nk#X(fyH1zZX8yTwEr>zxMd(U%yIM*3U_%qvN5wp`vVn%9aP<=l*HMN-9A<;_eDsrIPaBN9o_y4 zk@_>2*+_aEjOzDKsWXkQ`{?QIy{EGGZ0xVy@W6h(V~mUm2??zmGnu=;%XfdT5j=Et zbszA2r5n;=k1V4^+SJYdxd+De&mrudi08-;-lg)nkv;V;0&}`R~soj$~&Ja-HVhZrvT*T?yR{Xx+><5@f|H zJ_%u?L_KEv?}>~?oC6=M`i}HnL7@q5p8Jh1Uo#IIj(VzY5a{ !IF3A5 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

f?vNLfy_4!pCI*eCTT*c7v=Y> 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Ð_~a7%=+Z`1^?lJ#apKi zie9bjd{Y=ZT{LwBtL@@pM>*DJQ9dZFz-M(t@}X8*()BjCEqwcicLFUPY>^9b^0-%n z%Wr2lO)bG$aRNR{npG$WpJ8_b^gmxWMrU&9PSgke-*~!&xiFeSN*4Jy z5r)tnPV?_bi4#Sgor(SM-QGJ&t|C1m6tj>%(`cSmPY0Ztg}>Bjbewe_Wt1*^Y3#N8 zVgh?j9Y`vW%R@U*f(IB5VBS+p$RsJq2^L8gQdPs%3Z6!=TZK6$(a1>EB@sNauo;3|4_@}QsuO|O z9)wU+tn)uSbI%-Xj(|cG*UdgHi!Cb+06`~Q+To8SP8nmEHE*h-SMf9hTiV?o zAB8BM5KKA~w1~zEY~ZNc-e=5Np8DgcN~A!kls>>_$B+f49#UH*AB0}KFwDw;IZd>Ug%Sr$-VZ_)|Cna$T2}PD3v0(UbZE*nlD-!C ztNz9Jee0IflAssP%FebjHwRN=TTvct6iXX=Q>WW;U=Qnj=Zc*PGF-?nqtxodsFYu-=trus(41-X%yTzQX` z+g#;lD}aqP!8Tp?a)KGfcDmg0CAeM$Zdp(FCkbKad+;PR)7k)8)B=ck7nskQjJD}z zr!G!j(Tc}KI0ncLTqFXdb8rtK7oV?qUHvrt8}vzp;J0^{fTZUu+F zh|T3`LONbC17Mb?gcHbUOi+?U6b4x#&J4JvjW19mgjQ-Kl-e9Nw`Gd)jqX3qS{ z+z{gcab3WXKvr`>q^OwE_~<8GMWwHzx%FoWf|u=-H{#2eVa);STjk=9(yfTs z`mf4t#pq$8+;A1{u1`r0SZvlWf~M0W23QVvEw~%IzHMGQp&viO(ERn=+|ai76BtD^ zB{$eVpM8bJz<{P!wuT~?w^mdfH2s{m3k!T$87`Zq+Y`zJ)rg=o5LzCR<1; zX6^7g!JiB^ww4or3;WstA0MU7^Z+nDD9v2+AZknmxg6B@X0XdsJ zNDb? z#M`>4yb><86TV<7!Vw8pY!?l4P7zq8<*T=pay>7FrArj|DSs+l{c^z!y30bv|J2^+ z9=pFKZR)PVP%QmoSfk6I=5Y}#tg9T~xaFS(PCfn&uWajDPDD)Xsv=Br-10H+_~27? z+^;@YH3eIhD+4Vd&DRSLF&o;rqk!4pBH!-cLe+?P=~)slpbi%0kJIt&FiZR=w_`ad zFnyyO-XQ{J7(Ac9MzLrk7QV#Z(P{vp0Bd-WqyBcVwMcA>eked0_%UO0lCe;b>5kl% z+HmrkkdjEUqjf4n@F}@Xg&p!l1kCP81eU5{n!`njbXK z7KiqZ8JAS2jQ;&p5snWk@o4ZlSUD&J-7!#)r*`2an$1ptH}+_kXf>DQ$S-C#8xF?Z zDgJO0*zo8T&HGqLs#1%+#P^0*hQtu7Ch0>x!*N>S3WS`V13aJn>2uPPZ*Fj#(YeI@so`b@U1!Z6*<=2 zdN}pTzNo>FrmKdpQz-uasXwwFTeYcs^KME!WLAfMn_=}kt@y)4Mpi5z+;(pK!&*Bu zaHEwwv;PKE{$Wh?h?$nwxY8A8uqC}6atxMFmI_gf@caLqP9y{qi41#6qWrvilaD#2$s8TPLTc+KrXNqkHkpO!i^1GYV2BC=~PNvpCqB z?pvsFfrEB2GSr+hQ1}k-K5R}ki8~R|zmn4xLSR$_D~2?-7# zzcA}-dr;SbBEmHf5N*yzc|EBkV!iR?>FS%Vm+7AN?v1T=T%;i2?AaTfcb_|9R{8f0Z? zv!SnnSw@zqgJ%zC$6ymBojm|2kDhouBSq^ImRB0!Gx2@dM{^kH)*tFNFJ|CLsdTKA zFv9%jLSVpkv-oR2ylI6-(%~v#6J0tOc$}mVkwzRrZiGeQN=k*gw1iW~^`1DNxALaPt1aB$zL6@DxaAX}^Fiatbx_Xok=XYOz48iI(xKV&o6nVahV z2_(`i#}SxQ)S86f#a2`HS_cC$rj~nmw{5p{ z!*@UUFf3|^?dvs6h-+>(o{n4fU6%U#Kx`ixb&{taz~M(X_*$C1Dn`@f2ht-ZU4yg0s>lCB+jpN9ufLVx6cfQJ%b}JC zHaqZE{t&6O!>R|m_EldOKoRc68v*`tme8`@Y^A;V;!db(6uau+Ws!7E)kGR49h&f| z0ZgUf^vh111ib*|c1GhE?o1e$k1s1Dcw3~dVw5&xP6rv!?)qCueu z?EE*&`yckAU)RF7i#~w$BDwNeq7E~X6TOUEqQ+r}5D((?V@GeHmk&4_=x%;j_ss}> zD8w)56{BNNH~1i#dt=CULeJzUyh{SN^R(&f`(VZWW;qZi8?YBe-x4Z$j7#)wbVLrR z!Q2uIy#AW(wPAD{aVMzVfOB4F8iw1<{_hC$hmR?Be)Yvx$5-Xd`6=zMYG9hsY{64k zLyeA6NI@-m12q-W0ezc6V==ZYo}uZ)D=7cySxD0H*(EE*8oyukW)&vT8~?&!&LP`pAv)C+_?{nsy~ohX%3L3|2oPB&;fD zQHC%bKM?!r+K{eWiRU_}sY!vU%dmSd(MhE4)c zn9RWbi3yiIVZ*NaqAnEKcLfb>8k;eJzVp$4I<0e;&dUz)rl;g{0%bA*0g*2Sn^{p{ z7F6%TJWqRPJLnJz-(B#-^`7AnTr&v=+X9aRz6#vY z^bNuV!ODvuK9a)qVI7RLXE-c(o@vc1kNIG+*93{H+6q&oV?`Ox!?z1O5bvA7-Zd=O z;ojoPb-^!aD-6papEY{`e$A;a@SMSrm?pTqK=!V*G;hFwBXUyfXw7JA5Gp3=|KuSP0HWmA$tdT%>@dS2ZTCDZNLf zL(?hry5D||;q~!SEk7;6I`x0Irpp}#ne-f>>erqk|2>chv`0AFkWEjKYvehO^#677 z`CQ-7)HEG)F5ZAkg=Fsn3pz*Y=Xito@G>?97`0w3UWx4Avo1xj-oUng#cL*-DuMD( zf~JO#xZVa&2Uzjr-5HJTwe4=Cx;DU>=zX*Qf^aD3&J7}9kt_9sO##DsIJ%CX!_7GM zGK42~7H}?bwi|&oo}00=2cdgsdcnAfRghNZo+X4nLs{?RSb0ip0xpLzD~2Lrf%@iu z_oL=-{)jja6TRzba`5PA?0R3Rt`H{2yDu&t(HbK;g?%56S6@7Mh%M{9LWVe3#%>w13)p6XRWu7=PtDt1OrW^gt}@mfc;-c zIyrY#OrTLtcJ>H{SR5h173&i<&(NC}kMEi=~0c@numUdfPm8 zdt^((XH1H1-QdL@k2lvY)>pe!AI}gxV)2Zn+Od)3Rd2A2MtU47~)>YWYxB=ZyPr5u)L42VuqR z228B*T_Z@VP@|HBqDkA~+H}vA%gL;3PE}5_+(T&H`6YaApXNgOpFEQgN!a5w(#(MNngDPx=14#9uy59@VH z?L@8|pP~|_?aAC;L@V!3y`=ry&TEt>r~f2>n%yGh3vYnTzeswfWN+YKAk7n|xO2p1 zb1PZ+yU(Ok9YlnU4G-&GxzkyTOhF_WJkYD0ga38?`gQnrJUN`$(liP``Vh{y>Rxge zqI3S_=>*|ZK9FGE8g`7EZ1w{mW1$ztCRX&|j{GN#$tvJ2#SurLZWa1b69b?n?x369_krNFCJPEV$nj4ZK`{ye1zgXxXC##)OGz&o?oo z46sN&Y8Gb(`ZxY&mK_!wyI~1|5-u5g0t9~oHZOQRt}qEB?&}={u^D7x4otOvII~w} z2bAUM6s{=6YuN*W&L4!b2Q0>5BMn&hPNmDI2LhAfg@RRc7-b`7NYFC@$M|XSRG$dX zP9ebI&tJGe9{$7;=|s^Ql3O#eaw!Ozd3m(TgfXtWaC-!YYYQ_h`brrZ^S#LMOoQX2 zGcvYzV9J$snp>>}F1QmVZy1a~7^|jP1>;Mn(Q>l1yV2(Jd(bibTMpn1#G*e!hkS` zB1HHrxQnC%(;gfeKmy>ik0#clHfGj8@{5a$yKGO*+hYe+9ORS3-+e+v()UDt4%Is$ zgFLB6=E%6zX^yo=7@u)!2}wQm3-s!LERaP#_N8!X$9!O#MINAyn)p0vh!m+Wp|_UHM(w%-F$iy(8?x7{!gFmIO`Gp%`aW>y z<1TDpwTfrav=^WEp9Y6*l~D+m8|>-nfpwJBLqlQ((k)_3&{^X3i@RuuEif`Ns$5o% zdxfICIq!3&nXU3uSn#!kZ$6+&H%%3%qc|kJmM8}ZQU0Jx@i36hUauU8bE#;|$)=b2*SUhkVBo}MBgn11@fT}og6T;Hu!10G9XOn>xu zfp-fQz#SS`Ohp`l@D?8aR0RLT`ejh80l~SwCgz{!4n>N=VnPoCuo z^Mn7~y6-=pm(^0~h%5klF#Ar@<|iBBPNCj;&-N)l3rQjOfkm&0ddTT9fac<$PiKm*7vQ!8v_JMTSY6GpVUkea#Inw;2Bp ziNSr7GG%agg}!J2)=@Z9t6i@tGpgpHd=6?-lMbq(PAR6iNVJNp8je>p#$eCzj19sS z@`xap6jEb@kI6H(_XQ0`4eZX3J`gh>Gl-nrH#@aHM|pDag?s6l7_Wdwsik1{fVy~Y zibK3}3UE!r&&_Ylno2X|U)C6F=T1+CE(erbcz6$VrRDlOjpkZp*OgnqZT@EL@bWfn z=HD1Lzkd%%h7%8STfyIl%^|9GBmDM2hVb(P^KGBDmw2Br7;YX&Wbk}a53wicsHI~1 z4y+Q|7=WE1-Q;m)!@v7=g8b{hZ{b{X$g;z}8C`$zzCJwt6IBue_Nn)(55wKS?K9_L zSMgH$j^TBvpS{?=i>%Tk9~)boOs>Ga)-mPFnub!UsxB#2zm_1RS*y>($jl7P1bBtE zGt22p=tEw)DitjR>L#d^koJL#%1h;^A9DT|umo*9V|T!#2lM@gtcg8#xC_9kfpEoP zM~gAU)GMb1-g3zy3lx5+M8xK%p zv#SAFvr_Oz1|O&d>nCcZS~zW`{93VA{$0qV1Vvbbvv$GJpy8EPaeies{;(cjzu;6h z6VCS=I*41N74l+N>CVXxcv*~Pw_lwMlSKY&=S}~VqNc=is#4S~LDK>}$|)`#zrLFq z0Z9D(d|{DeiW-!agScSi+&*H-g!BH%ImSXt3n7u=i~%F=Xl;&c~;i&K0U%?WCEF z_XQJb(PxU=%PDfiuk~M#J99R+JkEO#{j@q57LFPZEp0)% ziz70^ny*5bmIXy#sJpbjE|jTNP6-k2DU?-?$idaCcIir{J8H+zm%PD{&8rbYs}jGt zK?Iuxs7u^iXGr2TI5{vDrTYK%HNa_AR6?X1ePO&3kxQ1PY9KLDf0`Bi8cWJrD!d+w zsKWsZau~>mmzT^xMf<-55Xos*VV)}-GF1k8bM6gvVIt8tjn#I}sF7luyGkx;L-PWp zfwLO|uaO5;{O%n-Z12Yc-wulPPw{i!Q~NT-56Nwi?YczE=JV|11=2)PXtjxEmQhSR zdGP0@=hKM@-bT@$w-&Kc+mJn0yoR(JdYzfcztVoydivL`n@bQJ-&=Y^uZl}$fRalNsnRR5n_*g?i}6Fa`cc>+pww`RBk;7Qj@ zS%su77+!*iU+8Ggkcp$dVwNpm=-=X|AuH8aGYohH5SY5(F;^MsS2>>OpD zIg$RuV*n$JN=;3$1=KJY(~i^mfAMp^aG)mWh#(u2OidmIkX)_sT2NQ&n|cpkHVfB`VP zYV5=naynKF^3Jb}B5DU+W<`Ru-L`z zgdZ&GPzQs(BgiiI_VyshPPeqg*!j~HLM$YZj&F0~Q6~%$aiO&DHF49mK5Q zmF}NK$QUs8dLHymO+YiLZ{9>ZIXK}8=%T{ylQWPhl*o}z{G^*dZQq-C% zNtFM&U$x-&TNyyY&M8ptt+Ov{70Et&|L$taF!gZ?XrO!8EpOaNI5Trgpvsy~TmBR8 z_x7Lg?9EC6gNqUl!T`MyDQMX%s{b|#OnlTAkDX97FsjdtW+|5})$gsT(BRwzgO?P& zd}-F*44|{c#c{Nm@zI{^TtD`nzB->_9?*_)IXG_qn#NaK0mcLY0T68gjP7H0oaofd z=qVYcXQ1>RNUC5(7I8!O&(-W{%BN#C!mn(TDhZcFB2{387LHl=Oh1VXrSI#FypLbz z=@ORQ;{s|dMBOnlGD1|@bDJm}P7)eR-O3wzW_>r=ml{W$!kfV&ab1SUo+XhQOtE22 zTJTQU?3MVk{H?-AB}fjc5Qc&mky}%;a&qTkTwfz%2;q1vy=@is{S4_G21f9QDM$W_ zJZXLo4j_^9Z3Zg3YpujN5S$i7xE%{E1^_mbG-DQFos2?U=`~U|U>mh|m3Y)kdNe<} zuo+N1oDf?-ooeRCArl9wYsqEoJcu3B2{bKJg-z2mH6K-h0FtjvW!$N>rv9z=l}C%u zPOf*Nt8k(;@1)H~Zjn>}gg=Y*&(6*Qk^zM#R}*@*{@xq7GyUO{Hn5^;m`G_&9m{l> za<(e_*?wh>)|T$`xoiD3y^eIsa7^N*zGAd7uocoO?qqIVDJwA30J`4p0W40OpjTeJ zF60Z6FrXn0ET;AI5_U&6|0X`aQ`K2%{!x^I?R9&zNcA0is@Pdj0-&KVLZ;uivsy;O zEe6T;%8tSauKb4g5x-I@Oqx5%{O3y3oL_&}xZBr3r#-87Q3_O0l(} zM{X~0@BgZ*c*pR9sTyA|q#A;kF4#)6PgyOpFRwd%D4TJKu!g3BnURr^fkB0zwyvyp zUAME)#MMg`^;?RL0!Xlj5a|brwwYS0Kh9X5$M+ZxT(mKzCzedeBKXdq6?Zx5R{q@m zt$I8LM>hOb)SmD~)eZhFJ8Vp`^>}1i;P=S z<=sgC6u^s_;=q^zsHHcL{PIh2&CvbA%Zc;t*K0W^6D(W|oNMj4KDK$einUjaI5go=HdMmW@{9O}kt90GI!2gdsu-ubz~ahN27a z8=4RIzRpNGL?QHB<`x#JqNUPk0*(y}((9nn1S54d#^mj((1x-6FBGdYGkIgnI+xG+ zKR)SjShp3cE6nYGsr2+Z$i)m~(z1d@@i&#~GdOY@;#4=yMVX3LoS=?aKh6y7A z)CfNKWr-jx8wZq|1cQfarUf~$l(a*P>4Y9NaS*PyAe1jFNz{5fX%bPd=vfJ2gu+q`4AeC_B|*zVq*6sQxz-24wMQrm-!$|K7JtDdP# zUP}Ypj+3R^E&Nz#11J<6n62z~L8-uv*vpA+T+>&0L)vFAdWks&`$#^vdEMeRy)_M4 zIG_w>Q!|7x%ac_(Bja9`?1_@m{vPZXxTQH!Q1s=#5V$46*Vk{aXJE|QM&2U!U%8Su z=EBkr!VUNPsSn;H35rhV$_9l@X9=DIBl(Sg!Lf3Ykib32>80mUXyx+U3jyh<7N)=L z%h{wAhg%42bM5%b`R?Ttjy6jgi293faIDKzO|143EmT*X0q}v<_T8)${MFUQeK415 zpf7Cv?sJv^a6x2Mm7Q95f~|?51}XHn$&x1}ur;g9tbXN7Mna%7zSF0O(AU?jS--2& zPwn`%aP6=C0Q{dPG!>5Eew!sI_#;Me$i!WhS} zgvD5z_|LQNm7?nyvdT zM6rmG3vX-r*9;bi9@&=z&anNrgypnW({m_?r)v===xjeZM`2KwCw(`y>5}r6W#OZNb3FJHcc3M z|GUQp!`YwjHFvQC*X5c=hVE@1Dv57qh$B(R1~6%X(`>hTQdjK~wMyDoBY&1}` z^e0yCr_Nzv?6WX8hd)aR%#RiZ5l$^wv3fT-KQj>gJnO-Iz>2*><=BjCho#L@dyqH& zrH^;{FcrN8F0&8Bz-}h7{Xl58ZePoJB6Y+#1(nfbclhwb1?{4Mp^eJH2cSWKDgu#N zVHrTYwJd^Lp8h4CZJ~`ZgdH;t8Ds`*(}o@Vh>Bau1VJ(!B0zn(nF+2o6ZJgb;qn6k z&RN3DIEuf;{~AJz{ROhePCsC7LYmKq2=&r#Vcndij*n_GrA4HpF-SFl!v&%I8Ff3#Xy04e##4^7|+3hX|E!siLRKY7d&{y!_RB_a7G0Y-Eh#)p&_WFYICJMYyAP_82_(E@1x~@`16a# z84H<})x=u~ zLcak05$GzwQ~Mxf$^C;f(a9vKp4*fQ_qUx$X;YV7?KnbO__9P3>~+51dA{6KmK+a7 zvgsBOoe*5#r}&jUz1N&#D*?;9_!0Rqe+VDR0~uyv4Rqtr%9ooCS)miU&I?2I2)8?; zfzGBC4@WYKKSTQT6brsjvLqAFfX5m(6a6rDt9s>_ z!A(-_5(KCX{>M|@h6eD;VTgB(YN2jZWtE9sApAafZuXzyx{F~%k3tjg3}M`XTX%yU z=r3CMGnao|FRc8=uozHw5Np;G^<*2w$jVY{u@p6c5dgAn58PJUo;sHuHvN_t+YAGO zysWGNw)xZrQOf~)(SgmZ+g6r6^^RinK*BU*3EP$12hr#HR?k_wSWMZ<$cOv)-WcYS zi5LtFZCgg?wD5Q=s_@*nc@*Eaq0@A$ZY_Wk^J zzwTuh875RBl{y!}NyaVe8mb7MBW$pxu0HIFk69IIuXIk@>>q`~7{=xH-V9J=3$TjT z_=$qzU@|HTpn{hw+%gL*D`17v*zvH0=u_;JTN}q7G{vyN*B%*;G13($X{ewb6Jbq2S?!T@KslpkCyzI zE!yr?o9lBUwMP_@cYOL$fi7RdMojg#9LFt*Szh3~tTPEcM>k<$Rx&7~RcFloaNqsS z$v2vyqPR#>KHdlijK$=NOH?ufHoBdNPX_ylR8A}8)Gd@ zgMUY9b5JDv1P)p6$cwA>M!bQqxyLS1tx!u_8}Z^id(D^LS?DdNr>9{fSE`R$L{~C+ zrOl&%s~$96O*TifLd@W?F@{VaN&uH~%cm;`kQ?fi}YJfKN%zMH* z_XrZkeBjn|7Q5mFy)0mweOz|5RF=g_GuKiP@F7)8U%)Pj@tWNrBrrWhrm7W^g@451 za9_V_fzzLz2rfyn;;Qo2RLIsJgrWdC#K<`{J-2rX3@`GCp#YJeK~9!^|BdL5oNXRt zq_h)(axFWsIe`3_#_F~^CJJX{S?9->Xsy8eJ#9OGuRK?@F5GzQGO--#KQfUP;x=t& zjFmm@&wBD4H*NSs@FCo~0J`WqrbY;tnb+#O8IE^&CU$)K+3w(l;Agxfye%*EtBr8r z9AHE*^8T_RdJNVe8$Oa;93{yTjFHhGsM>)|+fw*+ z)h?~VOmplk9FOooXMb5C@323?!Is$RN}Z^Q_l$0wme$SpvSHu#Gtq4CxVzU`Eop3I z@jj7v5fszNqBmaDb&{h~{PyErk$OQ#m%V0-A)MBda9|UvCeUNNZ|YvS^M)>Bk)Y=5 zE44z3PW%EfST3XgB)$@s_XR0)n*rlooQqKcZ}~*e4Qzt(YVCOPp~d)G{R%x(j8i3? zZhbfP1>883Oj5hOM5(n>>3_mRy^WG{8vvYGW}9+ssu&&3icBmz$QwE)YL5!;gF&x{n_$_aYR1THwjN z$!Z3`=hbH_mznrje{aXgM>co;a#q;%IDqIGI3l&UC+Z=_0ruvcNrMN~b~kh*jM7Dc zVPa5nBSGZ>azWdPl;YE4>gO0eXrX+4cUC7PN5XcO=Fr3{VK4uy`OQ%C-5w-0ej6FN zgauWY45P@oc=6PfTF!(MoKABXB5SDUQ)n$jLK6G#hef}kF-jT_*C?MG0G+!?Iy@M# za@0zpA>Am8peJyj!rz~7^}S=#p3ibj+Ce>kJ~qXLm<~Fcv?(~Z?lO82F|mY%bLD4m ze^b{UKc65x8y^c)JX!_?wHT^3aeiw{!`;IN>DH$Tb>1Hwx4N z-77v>s>snawQza=W-Vd5795*^4KWb|8cpydZ`Zz3^iA6H(!gi;qQt4HtplFLy9y8O z?tV@yYw9Y{oa-LOHPB%fwxz09XQk07D1%$j^Zp@CtUUL)%yzJ#%!DTe-Z4zvRwX7b zUb})eU;3__mzeYxR;1r#c<|GwIfM979e&Hp@^^TlBppGM2voe0TNqUZz`Z4pG=iRg5jMT(r5wZF;G6;Xs z=B2kQO19yf{qOVcEM=O-S(Qfb#E8mQyIp zs$Br*mb}ZTb;l?Sh|iljy!14|RetwsTXK;CM@@FN={#`O zEom;@Y;_%}_ThOqXi?}Hi@ zM)*1hKu9yyQ|2x;0hH&i{qdZ~NOmEc8y_voPQ=U%vfKqy)Fx}%oqyPg08etZ; z;M@CkA^a2JZj}nX#Ey6FG6cC5ITAzjd0ONBz0H?!-Li~}hPeyD*z>(S6?u3WxicT_ z)$@^VzgxzC|31Gpzny(o`FNQ#!qmVWiMnAhYE_o$~*V$9negb037pL~5NAK0KI z8_nnc%DyFgZD14sUe~z_xY6!Xz8+-)2T*!aTCGkAm>Y@sAGj@O-mxrGb6xeletil&9f; z6?q0+Pf~543Om?&v*mjBnLpeA$KIR1Q`xs+!;+Lpl2FMMGKC~bh7>|5LMT&NWF9gT zAyYyWLMTF%X_Z;Vgd~-akSWPLB{R>yT+jV}eE))HeYm&n?z*ll=lL6sV?Xwxp=yGy zg1Z7rQvi}&#n5GmOZ%Jzsk%wpdv(!a4b60y;c*`j^QAaXyeiA-x+%8Vm%I@i(-7hj z3DKO}PP)y&PJdVuL(F@$gRFZWmJ?ZbY?o80J6YD^>&mP5WvdtRh3QbMpLNtEe8PYc zM1rx>s3tTE=@#fJOo~r_9>U-OcoHTu+QHlXK+GRj!#u)_;R#6PgPP z3!(Ip5(Y#$Jo{mWxOEDx7Faqk*(2Q|d3@J807L@2NN7F~xF^STmaJy)kxW{Ub5OI3 z9k47d7H|r*1Pe$3kj_{ZY({}jF06q3YN8f7oIfr>f&oMSG>zq6 z6J@4>Wg|p4fP5QpXc_y1S7liM-W{T_F~TkwP3&gVTN-gGL&e=@xpb~Pp(2*Hs`dQl zE9C5%XQ@ZhZ=9;x&|rN{=f;{eJ)kcr*P1QA!rFx;stIu{KW>ABbg%AuQCIVjW7g^1 zOS@dT-}9NM*E?(idnlw~c-m&UE2!3-t?uu_P-4q)X%1K{=nI(xO=ZzVIHQdLII($j z&2{=5$J;(aB&l@}p>%{kqsWTertVe@DzEm-R1)| z0&E(e-qT03FcZwVj~ZBt6KN8;d-@p}4*RdyT|}6_S)KqvLc30^S&Khy%mdtswvQuh z*E*sLsS9o3yGJ7SJe1@V=DNps>N83MXrX`#;6MSTPjtUpD=OzlNB7fE;upeeZg4G5 zWu1dxT@vxX$vw(*FR${VqAUE-&o9>|25GHLh%iQ}%^?T}LlQU!i!gWhXKbyK{O?Hl z<$eZ4Kfy6Gz;ZV-H9WrH5p8k_u62afUH|%7T_${9jf{*nQf0X3#}5@Q`clL<=8K|p z3%~2kwld4+`=K>j%YYPC7DYD&c9g-DALfgm^g&0Y(5Vl3;3RPqB)&(K5Fl#s_#^65 zzwjovSowh8uuv3#4A8gjJ?rNOX($n!G&?)H8TM8Ak&5|F{eN4SbIkwiQJzR8Ydbr0 z(fycj&uDG<*WZ41Wch*wB^CmnP_|CfoYV#m>Z;Vsx3)H3L>MQ!?0@&_*4ep((;}u! zMI)o@>no<~j|8w7bfDJIeBq9rmT`IMUdj=JcQ{tuh^D%|KYsiNPvF7A*9g}>AQi^6 zd<7}ig;?8)8IKEnM@2`X0zfNhg=Q24r=A#5e&Gz;op+7|pid%OXqqbrEpRj24TIK9 zEzC?cS`NnmO~v&%X76yguRJ6TrC z&$?zUfrCl1ecOf0Uim1VWP8Y{K5 z!W6EiBfm(meu`o zJmvlsw6sX2Mc1fhCi@P(kMotsrVn>|@w>~ClE_}px}s>q{y?p{ha}GuR&&#qU(+6S zf!&JHKETWT@2r>uEnCNSgW7O8vy_kiLp1CDbvog;$6KUMkoJ_@j@cLNoAg=?S7Mt$ zpuWVb#K#dbo8`Y2Qc|Qkt!+d48OtQoZmDEa-```ywjH{YT|_~aGW*wMuY8Mh1Qep} z^q|AFVC<*7s``~oN{DnqOVOb=?zjIwHjkqtU)Sr7?J@cROf!K{iZI`=ztKr`ff@x$ zlEem&h$1PiNAI()gs^5~@ktqXr@r=$<(li(WYfl*7oNT8SDzz2*BSPG)^5AoKF(Nc z3l^a`b*ebNNpY9^7vh^fOrC<6wvt(GzNOko<;q_j;9(-qEEhE67j(I!jHyu`wGq2e z2q_ubz2nX|#LNsI@oyiZ!=kspy2flWLxI;wIv0Z&-S{88m;fQo_86{0w$^=3nr>?W z@!E>H%ekogi8XRkDVzWGo#p~Z!r;FPY=TK-Zho8Jwc*z(IeHsAgtv0<+)fgQ;!|}z zPmCMZ7E&S~*8lqxGBTabZPVj?X(Ha)|31byNEPS*K6k=ME%yKS5#KDC|M!2tGm~ES|33fkKm30W=l^%*{Okg% zgF-uBcl`a7cFhq)llb0vz^Si#roCmMHkW<|D9aa z?N~T1mT?9sP0ko?v!!4~`@!V;9qUq)pR1zc)l4h2AO$2;rd+ zjQk#yO?XUVcc`wTe#4{z+%*yhPiyUF|CGaqTj4k}HrThRmnVE2_EeR{I9IeC+`a$e zT<=-i^MN&gK}#)9X=y8u4cwaQ zw`C3Q?o038c4zyUVAldd%U!gj9nP&{xC(e49#d--p)u&VocYKi9s`KacI@xKQa~JI zME$0)ZpLk#6#B$MLs@8Z8V7jJuse#%q4_+sU1S&K`bGx&7kbNo9g_9U*6L4|86Uz4 zb%f*k%$0W4j$Wrfy%{fJGW48Lr=<~26|d9%-u1z*dx3ZL&sOPH8q(oa2H6M?RatyG zX5kk4APc2w;#-lPh()UyzEsW_+!xX_$4XTu=5u8(e1hj)B;6GF)^xcxUHtC^-Vf%p zV2r|55Nk9^HZ7JdSnku?zWUBeI?Y;s-RkeB_E?rBbVLE6kLTVE&Lqt5(kM8WvyTgZ zR2Q|+S???^>I1Yv#LwB31M?lctfJ!wX5>_HaPi%B>xfq3Lc1X-klezwGXNAo%%9Rd zv(Gk*=G6_(n2MI;C3sHx_R_+Ne}6Zc!C)iU^4R9I;0A8Oride6&~+KR2` z_ua2l@Hzywsn{6=m>VnOYur9x=(CWJ&h$!GXBma)g;SgojWyRoy z4JzSKlohHxm-(ZCbQBg9LH;4u8Li(8(g|zCc6CSpy1&yiQO8h^5cGhi{`qqg?FGqI z5i~CJR+YUA8~R5osEscxC2nmM1INmQS=3}=VMWxWCs==5Lcz=5lmZd`TKm*m@71N4 zFeeRT*5X|`RXS;4G;#vNYp8@q-sFs7`!08G&rzXt2-yPjz=Ax0mq{m2w1GT?<79Sm zyoFK!mJ0jau2wNTY7|*clD^xni@K4K1=EGrLDSpWxfHQ6Ba39(XPTMsuIIyf1gt5a zFERKf~V zy(Me8&LuRN|6WgBiJswsKBE4H$6s={59F6gypVXaG)+jY8o_*D z0x835X;#7Gq3me%&nNtqcJXFB4{>^;Ih0_L`95X7UjiwEDp3%44moxbUxD5!p$@|} z8p`!UL@QC6bMLEDQxDgQSa)IbV3-%Na?>RKHzrq`JX(BFQioF@Y*f*pjle(>dl?~@ z0H%pSuxUaji~DJ6A~x#{Fh4hGpJ3LZ<%KddTL%Nh9~1uyexFUZsPJARIh#c)AwoH~ z16F-7L$m2}yd%qjVF|?x)oY!u+WgU6cjA?}N_!^T+jS&juSCj$d8{8(P+3We`a!6r z;aDrI7mY=}|M;;iyD_}+s^q5d1p%Vj{QBAoxNh0mM=kPr$Bt4@Y3SVjrBskCD7e1; zl&0Wm-JxiZJ`s4X^D>Q5jEwyb-PA^!_m`F9u9(F#n2OV!`|8qG-Q=C!+eV-;glK{M zBg#jN&m|Kf9YjWfWdWzh-`OgvzAsDE!wB#Rkx6>;WOY8*=l1+)TYGzZtgsQ-=w&^i zpG4fww_5u_vzoOq%ngQ8)l7yL{|;fgAq#i!|4W`TVMa5B=_|T}j z*wm1u%(!`pFq2FPHX8`cDVvBgaCs!5yLLa}g=AUay|K1{^{ODfCwoaQYxn1)lQd-0 zXQhYY*)IO#(5O3ax2kZoEb^MrLTu&g5b31o>bj7onKZnHxT%eKm=%7x$?%w3A!0t@ zY(FdrkWap58lOJwE=s*z@3VS--#|3?kE*WPE6zRcICxw9-ywEq9dIXMw+FawYID=m z)44utRx-)Ef6Xp8PV=j!0&X`IB_?|hy^-7XEB#2Nvn9q9Il;Yet4za1&47%n95)w1%K=b z^0^jKcb(p>Q1F6dC?QxSqcutZw-h5KJ?o<67UTVKJv{UwVBNP28@=_I|2J{9Q!lR3 zbYN!jgHiUFF!@inlFw`p4F8$$7Y5FirWt6`a2Uag0KU$aYkoi{g@kazZvF*1X>#s| zjo0%RCws~upVj+7v%Wl*OPxS1csj(V1wdEy2c;MSG#DMuJ}VPNke?9_jkLQDpg}3k zA+Z}Ik2a-)A|Sz%^D$fF)CUj+?RqN;1QBMZ>=G`u(NL)_lMMekuZ{KFpdlCNgZ)Ed zYja8F&L~h;?nKEk#uYK~v;2P|bo4Q@Jx6 zUkclwgjQJKh8S`bOCB`S5z*nIojL5`@2c-Z$sgyx16D{cp?<`2L2 zo>04x(HcW&RDgz2J!7wK?t`|Fv(Er(2%c9_)X8Yo*#4r~)X|jZ;S3w3+_eYm$cMFV zuUF}(w&jySfx_$h&(xe*sj7-F3uVTHDpTtR4Agphfa8I$@j24A z+0Ib<&66ijSlHNbL_uimvp(!2BQ0$ZXa0&l9hV|OFFqX;TKp5s0w6(CCL~eSAW5Pg zZG|-sVnM4|%be}BHd@_}@)wI%eU38h+&m0GyNAy}t;pm&x#^dGfB*hP&JUo#lM>G! z-Nbc1UtKMisrA*lr*HxSDAKCYKU(kb?Z-@wa;S$wmO1tT%95)uZMyJv@QIF!pg#Jt z!8!XN>YX?sPL&($E5;(sG?XCRw)m{yO4Fnoo()$#yg!{FVOUuB*|un7DS2ZFE}i}K zSbWk_Qc@BU5>is-FWnKlyFL_a1m+QJ0Hj(j=U&MAUgkPwTEBs_JN3(=-Nr=a?d89G z_JLh2RAd5g|DYT8z`)zFq#G9`2En*aF(f6u^xr-msZ;Thoco~af32tYI;Ii}rP{c! zRH(;&ixl6wb~&Lku?CCeBz6%vmJ!z$Jr_$?VA^6))a74Y1<8i4#=Lxov%!l0ukizc z8iI`4!B<9?Hsb>rQo(QXmIXrGxx&X+sd?y6>5vcip?3}}jWmXC3F}wLx68{O%KlXf zI&OJsDTHnyMFuvZ0I)2Ogbb47XLN66mgWn3o8EHwx&GQ9+?5t0Q|>?O>J%z_BP5iu zufUb+>bgwbOv0#6HSSxk{W=<-mS~@^`)Eo;(q;Y81uJqg@lcv`aAFW^K3`6=|Hm~F z7DU`;sV7?^LKVOMxAh{fW?8l}7@R!S&-O@KfMO?l`}X%%al#mzJbd^Nws_C32{pM2 z9jxRszv<)S)1PU2T?9*qWXA>Il{o3;{HMS-Rz+sIh3`gKLJ$AEV!N1Xq-M(~GPx&J5NJFFTe%YIQkND^0WHC0*_& zhYBSTj6@kFNgx^asb&Om_Xk*Up?a{SQ!ME zSMbD#b&ieS&*q`20QQc*VzWHZdD%pC?r`c^9CDLF@^68@+Vy^7+8fPG@c&WM80Kb# zUvoDZbq+~{5EPHNKZwm66JY3Jde_Q)m?G-YQ{;Ap7S}+kfSa_)t~X1#wQvGE4dsM# zjT5v(EW?;`;L=>VU1GL$<&Tpj@x)_;OMr8ZC4&__;Ip`UqaQb4el7umrVZQ-z@vRx z9^KTegm4u+v82XsV{!VKm?bYEf=2sDT#LDLbdaur$Z~J#~)UO;x6(rkw5z-sC8&|XO1JuGiAV>>~Q0L{*)kjNS6-7lS4}|G5Z=ZH7@21QB6$Il5 z{%BfSTEn*<+yqYYW@pwW;q{L*Ol_9t=H{E@My2+Vgp+pa>gpg>%vWX~ZRAttdB`T~P19RfbCueMqiOw> zN0+=;T+SH!3M3#-xPTLa4GFWY(o#ujY5acFo}V&*?OVD>UcYE`rT=F~uF=BE8sy6; z27|*?p#QQIic3EQqvzI4(^Vk(da}_zk+wyih)%HN%Q1_At=-UuEVa>g z;Qs3xko~jytj?^hEG#(8S}n~EHNi$25VGxg$+)P-z(Ta_rIR1t?;LwbhrUMhq{6zV z|G`JEVxbC8O-)TqJX9-UdNxXl3ln0kC$!gY^(9z~9S{u#k9SkkikmJ&lkb$GnbVm0 zji%LRF}1k8h6_ME+|)rFNBL9=kl&j&Ey+;y%bGE zQ-Q8SE;plouol_~3w{%Pxp(%Swa|k3^3Qc8GTo7(KsTsuGPSUl>izw<@+I$MRucES z@A6gX4=fkrRDZ)X5n=1JY~@?}I2yYR_KC#=KczUlwO;Uzqw9r5ss6w*h?m&b`;kAi z$bKOVJtSf}eJ~Krs-7?v#q0+Q9V4{OygNWFBTk#5aFlF7E=cx~g4~IA(>6*w^pae3 zSXnfVirD+}3!i7SsjW?B;Q?n6cR7M2oDFu0(5&dP!?4UdT^_;Pjp1GC#&b~D?>eMy4{q=Y*&Ks4qvG7m6mzGHf zK&6lHN+IETD$(v%$&*JJ;SvcJ@i51Yf_DNV7=hFO%6XGEi|{Xw>| z%sk&7xjs?3R@8r5-|ZJn@M5bD1w>HXi8j0*d}ZFXyR$Qr@ib(0L`z{ChLa9MCnJ?W z!giCIbT^b@MTv@hLtf!K%_(LR^qmDZWrn#ImKE;!{1mRFOmifz%0Ma#H-)Z=tY4q1 zrd&pNNZOIH+m5=DiKOBJ_5JgxOWekMRIpHSBRMsppnTma1rj(|A|7j_qhM-cAnU5WeA-~3Q_kP|`9Cgz1>wl+SS#tG<(D_FEvWoD3hJ`UB^W^3g((h}9?^TD znc2XAS}k+U%gXRs{P%|Ie^BiFeCv6Imw`S6iS30pO^;Ng{L|Lwz)$6TFgPPI%|{eI z8m*%25Q(+E(x}x=9DfN!jea3o%Aj$1*Y=1Z=Myb7ANB2?+=DKRM{{fP{fN=|O@;&_ z8qqf)wDf+0Wm%NY8l>ip%RvoiBtVFd@EYJ z9IO28+r&kGiUZGY`wJGr>7=9@aE4<^`Ro&XMOA;zM6ww75DvrW$`$m?*!UxpLOA69 z>Rr(O@ks3hcJVToa^S<~7i|V^Z~1QUyJeX0yWO@3!)og;buN17n}7Y1XN0vhIug+%T3c@HtBwx4 zi7T|wW+k-sg=b}FEF~7$&NtmCZqeJ#-m@S{8WA9T?HWb9ITz*XXdCo&hK=k$rxw=s zl{0$Z?cHU@$6o>3X; z%K7=n-pRthVt34c69U}0Y2(#1TwPqk!^7bU1BivoQ~F<8PmHAjU#gNIgcmb45&tcaKClF%IXs|bfaW2VsNgt5Y(m%C(9W&>n>3VE&lCKjGK)?e z^mY_|PmqK;3?td^_Oj>)w0sSfVA0TuejW3BEP_{tlZ&@XO7Rp0(WSK z!xImZJS$D>>R+AXK8faWMT_UMsC#+skfjqoh>kLXO*SigxC6Ka*V-BWU?un0c>dr6 z9ek3FA9o<^%S{YTt3-w23g-P9#7aR%A5`zCtgOWaPV8k}8J&#s_srgMp z-|N-ND%8&ep6s39PLrrs>q~RyOIF78pzWBl5#HsVKjkgKl9ZGLUeU~y&xU8V&gFpk zp(3kyMg79!yh|+MgIX`!Hr6UPir(#s1$AqEy5FBG^cBs_Q`uEo^o^9Q)zj;i#ux1a8) zT%YeH{iBx^r>PY~IvDre^69YAqx9Y& zF9FR)kYvaF!EOlCCrL#H{35KF*1R`R%55x0Y`6j3?RnkE_{K1oDanlN&aCFya^m#S z>~+%7MN9j9WAb=I@2&^OFiQZ)2bZ6*c{B=I&g=)Nst^Yu3L7I(@?dx7C=_6wf=8Eb z@j*b-?L1M)R9*OOGy0ub0I(zXNxQP5dHQ`+c!jhJs{$R^18gdeB7nX@0YTAy5~ganEIV@nCizb?#Bd(4|}Vwa(WDpC;N|t!O;cd!3A|eb_FQy@$ot zg%x*9m(I30yzAT!QvCq1nk_B*3>J;qYgAkG>*Z@y$oC}Z;j+UvjZ@7zHFO#O6vG5; zF;a>UgdZQonqjDzt+OHf@8@`ljeyz))5$wrWI}!Fmaq9bi8nF?3`PjHr5lqak8|Qb zs%pDByM8@%I$vCclW+3i89|EbZIz+J36~cm85EAHvn;J$dv3aug7zuHr&Ck2Qs~og z^WlGii^wFSe@kxJ9#(($*`0Wh7p>#X%6iOV_5wck@sUkbKev-0nV6O3;qLD4;(}17 z6Kb`|XXx&pVW%UR1{q7Rgv)cL@Gg7FXln=6_WRLspOQg9G+pw+$*P7LsXyVT@`A%w z$`+*uCK^lsqk|Q>BZk?s(?=k&_Hl?YdAV-!pg8+>XtUmBOMr zw&VEYp~!B7*P?pI>kg9<>DJB+&aUZfi&R26sjaQIB8vF)gpA|?f*m|ILx1W>EJ?Sm z3MCxX6&7xpLlU>N`I}m<9RtH0%rrm@`Yz@Y1FTO)q%Yq1}Nd zuk4I_?nXRHxq5kaX+|i2HU;1359!me_Jl*Pdfb9rSyEEct{Cx<8KwX=9w?_Xm}VO^~l1Yqca%63k0 zEUqD!iFpSFxi8uAapOvZ-lr@P2)J4v0~kcS#A_S?ZGQ7dX@ezPsge=zMPC33%Ec<$My9n!7X>C4Lp+V2!|s-AI60%{vpKPZLqW+VPi zdV2OriTPQh4{HKHqW9vxUW^X-_FJveaZr72d2Jn1GeABV?7+Whc;Q6YVP>b0ZDnK{|@NC~pF;g=0_j0-0m4Rp!Pk=Eb6Msv5>ZzZj zc*N{LZF_mk-&wq6u+b)5jy8RDUdxI8g0H+_Hssm1vezoSWd4ePUfkXuDV0Sk$FcS8 zuMa-CzfG=KS)P}fhO@pgovPl!ILJEwH`a)g#m!?+QBS)S9ByV6*1O zbz6`TNIh!=Xo&sBj7Jn=(a3{HFOXVQ%DZC0`4Y|gd)6a=&&Cb8piJ4-uj8dg4BG!6F!Tfn69Q;ys{umgB36nk|%Oo%0tCY zZTjzx+HyCxm-;`3=c+?vZx2+I&F{tJjR|JbFxve+cZz2Q*f#q7e)~U+H}2jLQf2e2 zep>c`+UF3nrEbg#7TWwQ-&IGf(<8Q+{uXtiR6~*L#||djx3->4uP3u*cu?;iVn^H* zE3L5XEwq7WQq%PmBjmR@mf#5USsIGPrG)kL>=GP_dGCSo7duR#yee{LmcqFUTWw~S z&N}U9Es+CZm+~suPw^;gq83H<`F84%4sBkm->5Esv?EK#CEo6-yQ~pF1P4Y(?`f7( z$i4bClHs<+(hgw-c3qD~6 zj{N-mberD|)cbhGgE83!kAQ)WX#MfR_*VSw}|)c+?%hmeRJFU)R>|ed`%ib|e2= zwQ-fYANQ_`b?ov{eAp3w{Xf51;w;+aiZU|En=e= zEaN*=HXd3i#njDLRI2H>$f4YOdYk3UU-;qjACe7CX;6u$sRh7XnseMF1(=w%cu+0J zt57{*>UxJwSGC$up*YoLuL{LfU+-&Og>fEu2i1`+Nz(p`umkX~CR@@Ne`Gs))v=fT z_hE@ym8eImJQ)1gOUT>D3`*$5V6X^IIL|{9?y5X7#e-^S_D>~Th=M?bGt#&~Erx)J zCzj9HWo|r!U?Xa4OT%O(??-1(-jzqkg#s>xcenMW_ir$KK$Xvt=GJkXnIw5arH=_z zGFa_9m%uBQ2oJ>&-|b1ZI9fYn5sA~M;j+Ev%|^}f>Rg@`rZpOmJl@haK2S;fI<@d@ zqI_I1SYb!|QJ9cwYvVTOR(=(KvtEsKjeL4~$@8|bb%B1}^ZT893ohd+kR~D;$t~v0 zij}?4ccB)LU7fC-pNHX*eu<4aTS_R5yfHO5K_>JO>;8r>H@}TI*%uCJ;9~Hu?6oXt zuixG-=zFPxaR-GI>+b7JBz{ff09Qio`_EGgnO33f!3l25e1^YVF(r{q4BR&5SGLk> z-28T0Dp@7XSPm0$6J{|1(yO=6y#r@#8JUXm@@p@$_E11Uj3S=!y35Pg!Rg$CC*ZJVY$oH#j#^S0&IVFGVUG#4F1E$!Rliiq`DC$j-VaROuk}(ow?5(&B zyz5Xs{$a1zoLZ*V^~MgIzFEkqnLHXcDB;J>5L$<8D_xUMFGfK_jAm=ThRfwe;iz2H zt0XgkFF<`@T|S1o25t`4V~%6zsvg7Nq2wBEz*!7NOLLMj%}h)*Ff;^Z1g-e}Bg{0V zhZuEacAZp>`mxp+*l#D=co=KI+hA3ymC?flU1J5XGR4#x-eJ_hBGGgd{plg=JeU5o zBg8lj%g}^!Z^IPmA*++Fl}*EQnCXKMlwenZ`vM)Tv==81AnYqmmDm-wb~a`(*uWm0Jy^|H?wOj0393ylWxTjTxS&HY)4JeS zeZAzGjI6Azj7*LeKX|{8-kZHns5w#m7X?w6A`Y0+oJ!9Hpg?lcpWgPKmjdPMMOLX- zmTl2W^T}Q>uq3Emovbt@R&1VKTEsl1vaIaj&VWndu-p`g-f4Pva#4PR?OqC$FAYU= zS%}8LbMhZ2(Wb0xqTTX@&K;uYo|UnI8^f-hO9<*MEp@E?im5b+{hggA6Nh))S)Z=m zEpWlhz7VzPX0BRwb@lqXjHTHZ^$GC-=hNLcjJd2#vP3 zowiE%1A7Un17Y2MjkfJf2GwJ7tzx>Z`9p9Y2SgI5TH!WBUQGxetiUYUvE)_O=&U|! zjY@&|}4Zz!8hHYhvr)3Mlbkj^3)-GVvyOZ*?d+Li%f9@{S2_M9n;JATLP5*RFQF}Leg)^ z!aFOqyOKo8v1iF3G2<>>{jr)3?p1;Q#)8kr_GiBl5;56henU~_viYmPU<%pmwj6(ThW*aQPmie-UX>^q;*=Xs zdC8oo(idTt*S#UF6b9`}(H6#obJ<2mb_~q@;>&OY95_z=R=LEcPL=T$L ziqhzklCo@sE^xw<<9xEKQb8A)A?k1GWukpXmzz>*`%+d|Mu9a$hlZ z=zaXvnUyun=6Cxn)&kB7SrvMI4|AeHiGF*xlF*w=ac7=IPQ3cw3kj0&B6rz_FphiI zQCS|+b7=R*bzMogkEj1Wo+hp2lc+i%GZ+S^XT@LEO zypE3bo7(>A<>lqY#p2$n*XuX%o#&-G8HC5Ks&UbOR@7y5TiutopOuzox4ecb$v`^S zS~&G6uN+-Oji1DEtK&VZW8{b(|2PLP?Oem+&SUF`J*1K# ziYFO$OP1c<>Ra{ipSVZx(I)uTJZz+hDRo^wjoGd|=gfHLYbIes{D;^qU4_SNAjk?I zBz0?{ybl{+Jt=WZs{j2UZd5Mt7&A>yxe&1-QN14B15upi=q4;6!>;jR&P(jT?N|GL zd=T&6RT+FnB&#&8m9?Edg%`5{)#VqvG3`8elqst9fvb)-#>=Hsn2eAvKb72$+N`N` z1;O^BYGaXqd!KJ?_6Co|Y)GoANsGwgB~;!9Ql}kF0u?$vI3vG<#nstaGM3iyE>X2r z-ahr3(Ce4E$pxKTYzrcgife1E^QnS{tC>;e?~>Q6S!}I)r8mg^4&n+LDrr#`@v!}fArx<4fKl65qR6 zSy|!n2l5uNj`9=V4)P0S*LO|B`^t>N*L?#3H?7b3o4gbh{GJPwhpskc?^ooE1fL9q zGI>*%eo70U&8j}onDQEa-}PKgIP2XTm>G%Bf_;w{yq> zO3#{>iGS$4#b!L--fVuiyMZC)++X$3-w_l%kJO~Dkg6zDyeGEG^4s@^$#Y_>pe+8( zVe0nQFbRdxVkna^t^kX8I1r09BTJl@!LY*1-O1@qSy`w#1~Cx$;{&vaphvPTO}8&1 zY$xB+Rrs=vzusZVD`|LX6HtoEMKPLg0qTmUl5oxb4&p19vamN!`MUSzIROAY6iOM& zVW;rx&nbF3dY}J>LC5Jt+Ik0p-FW;s&{*305m3Q)VTSzuPEghu6c&aPo-0Mxh_G9waC4OOMeLzwS*BHgj z@z;G{>tu|6UKYMMX}j;FS^Q}r9x?$t#6RSzwmLDn=XU0u4o5obtAjHa6*RnLdJk0o zJaO1`PauT*7W)6mn~S;*$|gC(7~yVBcTVk_2kbkp-%2vO*D*XNHz14HiFiL;FMP09?Sw?4{UozOzZgz*S&zeA7AtwwJ;3l1%($E$$yqH&#vXkr&sXB=6bIa_WCvfGx^V2+So7N#|CkDv_C7 zRJmq@ws^e)1rZ282^nrkdpdPWP9U#$ij6i1XfwtosG0F2dcHU^eeo;GDH90hzTfk+ zin{C5jN4|c>c{cn%Zo7xgzJuM6>?+rq@@m28%OTl#kR# z8*OynTgAV+V_>g|+8eL6Ba=SYTj2C|=@%Xatl9~um}!0#!d4a$04cl&b#62fk?j5D zKVRZDhvdkh!^SM`bmK=8{pe-P22;SG~4YHh}qj0#=UQX<;y#6-Y?R@ni z>{Y!O{Ebjd*AGTDJGBPd+f>oJv40X69N>8?molXqD`p{i8?s2-FP;CAK z`zxHH(Mrlu?ZR^XvrW%$+V0{Z{dE-icRYK;C@hP*K*T*n8x$gc9nQBZcCWs{QUT$z zW`D})r0Qk2`kvus004|@ZjojGbp;J^s*z$n`)ohOc;0(pHim_DBz{U(<@pjiH19Dy zcWN6_Yl{Ug9O9qlz}d3)>SL6bzh z780OOF%wzb`w0jDa6WDAmX;R(YW9_DQO~_(d@#xU-JIYg3A4kt5vPi!-wB$TceS~n zvmYagKIA$3f1bwh=oP29o)0Yhzu#K)lKC)>Y(lzs=Zp=?OR=ZsmALRd&?5>qy+|ht zzJy`&fnD0#9Z%pb0M8&-Mi;RI21Z86DOfqBmgfx1p%EwGudq}jcCWJDJ^M_ab5CfU zTT%wEG;sXB#&kCYjcbR$lv7f`{yEd8OLYtVDJrNhyerFOT(>Nwhff@YOJzj;$JO1O zUs2s_YMpe?7KUyS4;+nt%do`03lHsCg66CTZtP~y4vCx1=i$Nu(&v4sKdjz?W%;06 z67&$bB9mJV-w2uv!YIJo{6}GS7S<#oAg)qy^Gb#K4Fi^(SnkzR`&N3Q&!NXBN$_+}rV9`~hSXt-HzX5r|3TiLH44f`Sr7cCi!9ktZOYLN%($`B zRe5#bu{Hk&^!4eO-B$&!d)Fls85JULGpUv0(A6EGeADlwy18GEepdjz3VL<}tIQLi zGfhLtiL3u~$lLAaF9I8CSl~ajLHVxlgVHU)?AgsGb2GlMyW*h|*Y_5ddIe5MUrxrU zK0f#E0GBd=0HWY6mh*guq+-Wyhe#auWV%IG7Rjx?-@dFzJx%lTh`e5O&KT5x9Ew{$ zUm&x(`bvmS1K1DnrXJf~;ku?fwlAOtmzc~a*ZEBA>)xLFv*YXw%Xv-Xxcp+ab;#GMxQi|ClcBfraYX!Cf ziioT%Xn}6->t7e%@X4C{eU?@WPT9;1OCfdPNYI7u5gkB8z23b8Bj9_K6%_^9G-A<$ zPYdFo7C#Pvd5^?lchy^uuLI?EHrSZ%-%4LJS$0m--Q0Y;-`T}`HeHA}X|pt8EVKdT z>FE`-wYSDnsGy8|)|>?yt%|z9saswyMVq5H)gF|0-?M5`*`3tB^Y)}i;V7s`EYLNG>1ThnIVVOdn_n!X$cAVen)Z1ZAFVy`sHSo z`WQ#5-w0mj$vDNH!MmSn(P&1D%_-2m8?J5rIQ^`QmxZ=BbDcnPbJ=Uq0hwuT$5r(i zTt*ByQe~3u)P#Y26bVvqJO9V$Y)sAAJmD9j%oft#Vi$iW-Ct8UGCImn zAEFd>x8duiFU_6&Nyn(@;Uz?wp!`N%9bIKC!W-L!Yvd$1Ve0vB@V8Z4G0Vg$vg3L8 zAQv?pc5qV}d-YpT1k;8-BkEWt9 zS0Ok6`}h5PGq(e46eFnkbiEk-?bD^_ze4m1{yiFWRi0Z9FCPvM3gT1^1g3kF^=vcN zIGD3p`n(L_kfeP16X-fRx1>alA0I&>>6$F<`45FBy67E#bTpJbJZ04Ly!TSP7J6KD z?a#feBECX)Q2g(+$Loc2Qdg)HCv{I|3pPO;_p=m+pA0*Xn${mncp7M7Wi|He*Yi&6 z(NfyTb6N~?r3feJZ$vloca}EjTzbrX`;0PKN_Dqr6%gX`a;&Z;)+u&uw>cI5kZ>wa zHN{Dp0dP=GE=+6-bH>K=PPA<7IbKk?xM8+=J(l=3E~w8-<`7y*{Bq|ZTfm7=8w3s}fV`GD05V`U#1P=>DV$+_ zII;nBUbu~82l6uDJ;$fxAK(LSOLXja)1~SZ3JiZRZZk9_72{bQW7L&z*ymDf@^4Jz6O|DNAoo|tehaD& zVDXR56P@>rFMOAxmBn9;p%^MlSKm|i$;*C;7x*SCg<~)V;-9X zTV8T~H?_@hQV^41IqfAA^m*n379i9VppK^S3Q9Gr`>}oI!weN8SMaSVw(Rv^k+MJL zG$!@hDBqVO@xJ0q0MV9&g`w|UzmmcpFtZ=U99D+%!L~rpxYLy{v-l~fpgISzw7yy* z*tCPmGM>`6_ry|<(cOU9Ux`2C=zJHMYsm!LmIvxW@hgU=ys$W+nVoJS`tpW&Z2$Hq zB97boLD)WxU$OSfv+)#Rexsjl_L|DXW``&iHcAPx1jycr-E96shT@(-J%p)!jOrcy zs@XNsm7pY*ID~?v+W3wrPfR9ZD?GMrf!+v0G}^`o`IvwMPF3YGDt80-5xdS$W6ynHb7z2+ zY^<*#86#Wg#&r&B4qs0xY3ViKswkqei`biH;TZ)T4&Ob_5rNHm_V+8NGrEfuGijRx zbiZ~|z#%Su+b#7DFsCJ%-ECL7kqa5n%zy$oH34Tqc*R0ZN`jT`AFH2YQO!3lUCPFl zN~iEer<}-3O7OSr=J@0 z<532Mk$DdkEh)uM=?XNt_8OE^PpIJsMv(u6%N?DbU$|yKA}8aqN1}A)?nimi`Z8XS-o-W@~2$>I25276N<}SAJm$Pns^2#6kbFH zuAj~6kEu2)(#^3$kL{IKG1uO_`oUu~shHr6&AXJ{e)zjT-m{toBN<|+V4)b!KM5B8 zd*liJ0e1aC7~6%&_w|5DOi`9hwKD7^sm+k4pN&}HS+dQF z^T(@;oe)RD%IKz;G1p(-y#!Q5@|+~JbUZ1wn#bS-Zx-&;>0!7Rz?T^?lVoB_0h0hr z6OlBwuHfD2N(ys+`X?+AX^GcuFs+7VTlQdwvor`Qq(Q~m|7zRs4~9HEl3VKMq~P3{ z*(X8!Zv?^}sTQ=*;e!-%@P~sidlMdGicwMeqs3;X(G&)-xiE3MO$80(T}@stw`Gj*2!d)WzYe?`x|F(ddn{*h>HCFSPOad8LRf_3 zNMrjSrfiKo-BWo1r~SIZc<+I%$Qp6ZexUQUIp{OX%Ls5ul?^PJHZ(M>>FZ-X&GN=0 zGzFP_kpnPuMF!r=?I$)vPVeWy(qdF_0Lx%0W%1y%$9ycb=bknW&cOLzc5UQhxdI0JI z@tE8R)~G=Ay^gVc3SS0i#$i$%^>?&QpjZlr)*1E(EyF%@3B5q+gHvG0FMt034sOSm z-)4*qX*sde-FYKAR^wsJ4gzH=qfZ+3K6Jg=q*=uMWpOFi)7reD2yZ*FBH3^PNtUn| zVU372s`$R}qp;cUla<+?@^=njhHN!b+w@FsXj%F%RKy zLIf)$+m;3JdN3Bbb5B_3*U9KYujN-xp(e7m;oJ7NcUu3`RY(*-ArAf$@sT#hbyT6370aeSfzS&m7o`aTLkk*4GXip zEl(*y8^=BPo$U-&YU@Z|N>B7cxG*?%&BCScO|}rUOLG97u?KFRy%!H!KXFfr<+5=1 z1pHLnFCrfCy7T_eQCe~}~i19RUgE$Q)47G|}q=wyrH_{kEBDI}fGHf5&Q9KgK21WCAY0@v; zl&dfbd`zmeWUiJQ3a>J1)PQGptDy$sg2%ki*bja(O5wd;0L43GfUu(`=)q=sY5|N! zOgw=|90)rQ_8tIC&~7%UvtWwZFwLlQNOcJy6MO)-_pUK=?gNc^aOMHa4${WN={&WQ zzKG7|`@8X;+p8b;=JbBc|13_=aWZkZ{bl!{(!v#SsVKlk>V1is7C(?O(=v>JZG-vQ zH@?Euj(1}S(Dv-g@DD2Pl;gs^fNfYSqLXeHYo32%82nBD>OKs$R#y?u4RxH{fCOVG z;k906Z*rq)UyT*>dt@ZVkLBz?UbXk!VNscqhp(psU$J%7Jj}=w#EY2G^PTO*U}<*f z!gsb}#FcegGfw0^E`V_3P`w7jkVa1UqO}z3u=~&9IprwGpGor%>~bL%Dz*xwZh`(V z(+)B@w8xus`5pe0HyfY+pZ31|AIkO(dlXU>l~6>aLbf9NQlz3%Dzb;7WS4y}M1-;y zAunYCs64dRuGjeG2c1dD=v{YLVpH2SUyD_}|t2 zBDL$No=ie_8rYhbSXEQTj6D z{Y%m8uiv_)Nhk>Ug4i10BjQti|K{Op#02xaJND|EZOJ2gljC`tM+`amZ4P0+k$L#X zw>a*)L4RrSYSCMRC3tF>=v%v>I=#1u)~UFWCimG^{Do>m=WQTV)QK~77lD+Hs>?FI z*m$bb^1iwaE)zzvh>I&7ggpYP#iF9rRsl02y3E{~SaXt{e!mQGS?r5RBL`eD@&EHB ze_?gq*KM~=1wtI#O-D1?Xlc^lFiaNdix_oX2$mrY{u^*#+)z{uCi1UeEO)f$ zuhUrhnTQ9A8mLEdHT1i$ybyW;XFy=x{Ob({QS4}>aWx=zkny;VPz>;!$@!~=+s~DY zn?u_`Qz@*F0k2IIva_42Y&HO2B3nESU zFr*Hfy>L?y4dKhyR8>I!JN5}cnJ^c%Ehe%M+=E}!9$T}_+*H6+ z6qVzwYM+*RC52|IU$n$c3a~JgH29M5zADgri1$*b4s|BoRO(zw*mYF5hHgMqr#o+(&U#cN zJo5fhfwluIXea|*h!xX94BHX(>IJMfP~|nnZ)6T$63N%ddWaUQ;h|{@$M!`#_0Uf{ zj9(piHv|Mty>4fDe=m524+0-OylaqeaR-wd$Ck1GI`W*5m3kK*yJ2gRj))f|gYNxf%7mdD; zPxunKAZlW5&`t(g@Gnx%il3g*tkkli>Z_Et+yQ-k-xth+O5kMMjzz%Bn4Q9@D#f>(ebaqso*^>=hKCt{85w^4vF*)XOK%znx6= zS|_ObpkqpbXG7poEi7*ntoi)vHxECikllnB-sCoJ7*%ozJ@ZXfrus#(oKKzO`#-OX zY~Bi@nnSsV-ezN}!MFh%KP|gYU3vdMW_1@C7CjV3mf!`k{uAwzO+(WN7|zPFPA6Ka z=YZuWi1{eI!_qB7QcXGyB>qswf;(p8PGF56W^n z(A5O+%!X6FG4R>1boGUsQF|BVipq+U8jEa-JnN3>vetn;FUhkzCA4}1e=v`nDj=HU zV%;ru`i5L0aAq|vzWa#V8g(Il>@!m}i){L1-|Vri2CaOK@Z?rKBDK%SV9sHK=|4uL z{97<7klY~{;s{n4rJ%T+LeCnI(l7Mz6yNVP%S^5!O6LdRX3HIMTpOM^z}KHhzAY#x zd{QbmM$%DQawZAXp^^I!+sASH2ob9)o zHiEtnn{JkJW{mvs+T{6J0Z5OHx=yznRtj)^LR}6sEq?GD3MBm&trc3(h0uOUsTs?Q zv3O>N@e6~BFqS%d|UWc9pky*xT)7Dm$~}v-*7>i$DNbWJ_|U8mh(jwTT<;D5f5X zc2&!r4v)aG=l-2LU#B~^?)}ThhfWhKE9)=N#aM8y4dR^LNIdguX~vPUU{O4LP&b4< zPl~)JzN_cc>C{eFx%FxmxRt@jub7%u%)57bdC!;(OsjwXYAu&26mm`|Ce{@lO2@LT zY0Z9+PSmtm(&{_}V>Fh37sDXyw~a6xx-+~a?PHIUl46_8wOB7Iu?Ztc_}r6L273P@ zo9rwYgMFrXp8ZkMMw~9UlSyD99m`$&;0f z6JW9b!511FB?6y5z?;@L0UtMX(w7=e!2MeY4I?B9bV&agueYrQx<> z$HAfnCEEr5_u88TdkYICEPS6E-=~{UOBKNKJaxvJk7e7YAS#-eDckA1v*J*K*F}7! z7Qg{{M0ZjgI``H%aD}wNG6-PiI)8u@P12hHUYm%YWu*&!N%uu0ofVeUX#$NN3!uC1 zW>CS7Kja7#z2BcG+l<536R!(;`J>gR6e3OpQ$X@TJQ>i!0zbaiZ=OhmCLvK1d6FQ$ zG0X8GRpF-{l42xiTtF{a zLcaBmFuYdLTb?8`Zc_!0hzoPVwtqAx_d+#ksGP;)@pZ61xf9L%<0Cvu=eAcS*fVe0 zNW5oQzYhh#_&9VhV@?|y4*fj!c*xK8V&^X?GT;zTbu?+0v}u<7KIMib7M=gE$cEl} zkw46(3@_WR$KPJK)=z(+uRq9B@%d`sdB>JDk^I|2>ma*W9+s}cQ1<3mUSgSW6UyI7 zP-MZqxX7QPmps*&QMR-`atLI7Ry8MORkcAMqw<8>5}x8qk0=$G?SPh!{Dg3h{MGkD z{*#K&O1HMi@SZC#vQeF}U+zlTjiB_n!r!P-fc;ysaa}#^=-RLThG7t<``va` z5YZPay+>}HlhgN^g)4f-Tlpxb1inqlrBad$4Iej{>y*kL7w1Xq;aUHY1#}24Bg~sN zffPv{2UE$S;e#lNv3|!jf#B{ZW{rP{UHU`4V8r9 zL?^khBvK$SpP4V#>0}SAeo_gs=DByZdOczc9F$duY0C=>XW$=2b;n6W7U~^m1@6ls zM{RNjW#ZEvxZs$zP3_3Hm_(Q5-~MTCswphPV%=M(puSq}&;%&{na$Z-2}Y<8ij2GD=jTHckL}^;%r(ic{2f2IvpnDH{-P?z zc%uuJ>H?#Iwn2zoQJB7G9R*1cCX9z!OEsmBp-|fq20jjEupofQ%34Y#V3a!L#&zV* zsl9^}Jwxu?O)*s5{-2c{>_zl*L8bu8dGqk$uDJ_B+rp0BAH|)9%wYI-s({pvjkKZ^ zYh1<+k3nc3xsh|@tY4+LBkiwNU5u|F%u9zkM=^XxH6An#PF;(qH`=;48t}#aNPB-r z>GVc*BM8*|G9C^DZf#jEx9Bh0AA%Oai0%5YO!za~Jm0W^w7XI{<|!7l8~QxB({JI$ zemwH-O3p7?%|Ok9p+XWXU$SP#ZBy{$jqyneqKvXe^ZA|S;yk0xF64cjw_c-h#N1wh zwP)%z-8zh*zbdyv5m~|ga`yhLTCZzqwzK;qmbC%&tBPQltX@4k7@aTm+y?rwk0Il#INm_c{~^uk;aN^|Xw(;Am} z&uwHk{{5&`T7rYgy1Tbl>yKus*Vo?^u&ioVRjlP``gX4U0aTP53+d|5FA}t;(A5I; z21Tkv-q1sZya*I@;deZW^uLm+_0 zw&Z6C-Q|B^M<*f+dP9LAm}Mc6T=VpHs@qU>GLHuvL>MmYF!xlO{ifnSz&+xSjHV!E z-=9w2-0d-o$rO0r*{F-BcM&4D{^8CflKE=PVy;G9ON2hxiIrZfp9a`f<~&++2PVF# z4Y(+9Be7l}M7~a*g9+nP&3VnSAJnk2-S>mL$dF1*5HGWd{o{n3s{E6l@ndB~@!are z?tOlBsyKln*Igi;6{z)c_;?C7*gG5Gr2wAzjxY=n)Fa)1s6#L6w&8J{d9ygaZ@%uNN zpIb)!MOmY>W6um3C!0{jyY@1$uVSG+H3WOLzR7)C)~iQCeo)+9r}9ReiS@n6BevH% zkH8>>SaIA1PaspxS#9V3KZo|eKXj-Qlw#Hmn5==!u6Cl*c- zk^JF<--biAkAu2bXU5e)asA#QkMS<}7NBsfUJ*1t!UA71e)ZAkk^Hc8K#_L3bA7@t z3Um2B|9bK<3e~+FZtXHv4TE51W@V+ClQrL@VG*!NvJPPvJXLJ=J(qNW+~h3%JxVCK zbj=E)fpLR5xz@n58feX zaJYta6^%nrMxJA;u|Ly8t_t07X+C|^x7Cf19tMts^49`0J&KbA9?9v>85Egzl?&-m zHF@w;*L#0=jmW1#7m{pjY(T!PU3{Lko_0;}Uy`MI^(n8Z7BHI&yCZR}=ELx928M+G9XQ-V7JB;TsOhE4OGLV2hC&PNJ2fz}{kWl;6>Zo}XogZz0% zfaR!XD55a>9uSe6Fyuok230J4HL5Br!Ae0*iMcM8UD$o1B%tKuMg-Fy{eu-rCw?O;nId@C67X_inBlxi) z1IdYX7hUMB>4ptiV#z$icV((PpFwm(ZS>rt4>3c9e>>yRfb*n;a*|qKF0u0T(L>5x zn&!i^K;F6g!%|~v3+>eCw`IsPWy1Z1!Xeoh&qZ73>)SV8Rbc9HcTncqwjr5K8D<)9 z&&tDI_#;zoftymYMBq|$P#DVkik9GjDOF9GapmG8CiL~J0H|kFYe7K!GIDZYxZFH!B9-tk{mZxudG0TY zUD)#2dwVPH2*b8Y^BgBKus%=)eFa-+TD#>D7SK?3F#wZlm%IzPqO16hRXZw*$bIK1 ziVyzB@OeT}@m+KCAb6I~E?oB>kt~avl8~}~@TYUtdCkr0;yxeZI|)DzyMoOhbKY+n za!aam-JK7S@9c&c!3KwW_TEzib%|weqowY_V5+|; ztnn=4S#3+ex6%OkiQ zRI=S!0ot@EieDno#_8!TY5Mn1z=1VNL!iAdz&Vz%r%`NyI@uHaSUJ>@h%i_}RyOo|g(^Ng z``r}a+sM22Q&TFxXpD!TQMb`v9PMdYog8sr5WPg#nEW|vcil+|fWZ-go(CEoKphul z-GF5ylK%z&p0YEKRR(S6O6I+IFjD8gtk%M7>Wa^OOM{WH?PKzq74K}pSg~UfJHHLHxk1ud}|jR z!?R#=K?x><|JQxitIQi$?RNQvRu`M=!Dh`k-yrr?|3*L$Pc!XeMonHgm+X7Kvvo&= z;!j!W?dz$l6C66fNwIGV(sFlEh6h18)3a(!1W)kyR(hkiwcD^NQuv%yWAO_rBq+V* z5(9Vh`rW5QVmOJ$b@%py^~jh=r1Ave$bbWJVqBZ<7Z~|k{uw!PdPBt_JhzyJ!ss2N z^mfbO1F4A@S?jL0Bwq*xx3GO)d7>bfNE|*90w7je=)>GW9Tf45scUnuGOxyAmeZfuM zL6usQl+4hZPa#r)J;uPmn!W7cOJBV@0?XO(K?kLaRo|uA){f5i5M|N3p`Q^Sc`+pa;oCnrrS8L zv%KS&cMX9jvLqpMtKC~iR!4V!g_e^Pz#dLh$>5E_CrKrRC8EJJ)G9tbm6BQvz6I4^ zx@Kt8;nJ@KIRF@UgyGe*jK`H>3+>0Nehen*Qd;7f{v8v@!!TG62b0!oPc3%{+kfQu zKJPg@ty*ZqY4jmN^mzZ28@>PQ-79L;ZD3>gAWXJW&Z3UnJcn*dY=`k=#hn>9g=?um zzJFz{3m-h(vDV5Tp8s%np-|yLLwNfWDJ7Qi6jt3?ut(g&piuVgfbPXE;)*R)#4*;3MmQrKmbV#oolHANB>6mD^zm{sx~M(JEoJ&&g%amJ!*C0C}gHf>pcVGVfTkqB%T-^FQJ7$^4$b6+gC^;%n_q&EWk9s6Ubye=>U~iA~ zcWe*ax!by-vBOt^3m5iWcxAb5V*IuMEMWU>2WRKGfjY*QYij;Tv2Fl`5Z4Wy+&f2| zjDi~ZxcBB^r9>IjG6Ek3C}&UF)zk{r#!=~92D0Vr+OA2ms=3d$Q^^MFBYJDcjIC^X zt32DQd&YC$o2am=6-k}QXn&0&m3UG4wVdn58r`#+m0N#(hvpgF4@~r<-eH}7oDaWk zELT{&o0(At+tkM}Ul~%go#xWvj_7!nZh4KPZ0^G7OPC~K<$OWc$3sAbBo+FiR}V*^SHta}N49XD0?<99+me_n0|=)b!>@ zAgkQ^0f~{q6H}?L7!vv~d7Q1{a9i9htc3M<@7re14|rzTbRQlCz4^B3HA)&c!c-Q# zuGt=*7x{}Xf)N0^h^#Ez$Zpld4c0BYy53)L(_44PT#x0uth~HIUSki}=U6er#K0rc zvTM6DOIqyPy%qn?z8nsCi-gA4ux3CZ{q71EQhHJ1Xv1!F0x=$F#<5v;UT7Ks6LhOZ zs0qjIJTlNL7TWK3K`(;V$lWI;pU(F$)wU5z2;nBMhQ3&*lK*xZ)U49Sr^7k}x_bm~ zAMfA$TAkWv1c2Qw8kcg=(N3&4Var42mtOwKT%9K-I&OK|!2AO53t}9#w>9cQtGoaU zPwav`Y2MJ=@M$ykAGyX17MXEA>Q7*W8uKR1NO|dD_wMl~->MSpGDsSLO>FxZq+wWr zLhF=<4nB%#c=Pg#9tN)1cNiz=s`8$}1LF*r(`bA;B=wNAJ?eOz?#Hl`-vxFaFhwsl zJhp8l_i!25M{f(5wswMUQ~Cyl#OdLFd)@pl*j9!|MBvxhMvDs$zAO8+Qch+n5Pnep zXttv7pU-9?5B zz~nMP=EcK zzIhp{?sS*w0>$_N;S3SPwcgS3;?Z9ork6fe4ff{iq<`=Piz2EY%Gb|rAKSGP_^spQ zTMemqX9~MtYnUJhBB2=sK$LP+dk)y~4axw|>zlMo{o@#6-l4)Pa|~YrLH01na3GVY zJigs%V457oIm-Ju@I*5V6w=KIF6Mh08)rVK>SL`ktxedezS$8D8_tkti?wEUj;L5k-rbjfs zir>}Gt#^3TFj!hyd0R=D?2TDJK3^vr+7{Jwp5Cq>P8$eb$-(IOn&df(CxbK5=yOeV z{(MakGq830PzPo^FoYTgH*Wm}*7LC^ydivd9RZ}_5%``sIaf{n{+CVTEzql_9e*Jh z{1Ci1P)U&<(*k(>$RcF<$1033vYLC3OgJ()56S&V*A?;bfb+eHc=eCG_Oa12(WYsn z4#3;ZYQ5pLin9_fm03_ZYI~KGvpM?f7sF#`e(}B*Sn>e6zgYKvt+V2wZ*V}bWo5OW zYZGW7PvJoyN~t=OZrC<GQQr6T-6@vZgMeJgGMj{=TbrmV z{H3&Yb4{QRpA8NBMzra^@?Mjrw#AQHVTi?Oe)IsVD(OSxYp(EF@NIw=d z0ai71TqiI!H?IAptGfQLyy=$$)3|rX)wDYRf`LkW=ct!bvQ2kLYG&5osXT`5sqh3V zu38?SorM7taH0;fv+E=ya>vEQP=^H702JyXr^sJTD{RWWcx97xt_~cr;gO^l3keR9 zbUTJr6B7=BJ?tBuot-gl+1aptQ&321kDxkLbWwGTdw*=Pqo~C`m=A)q^YiEXBAf6* zfOS8mOm4ogu&LgX#~D7;xre6cm#)^~S9A;dE~N(kMIRZD#4b1R_&VhW>aeYXwEOG= zZVbj~PI7g5?nmDKP4_$^cS*Yg9$t8?oXHVoZ4~F2;7jtwA(`G!vzL6wNvG}j)jfEA zc|GIPBPqr^Ofu+Rwy9ae#89TIzc`ve<4xnM!s8Wb%0qi;Bj>L=zs@422&Noyve7Kl zm*)96(a4y&$bMDphGEt({KSMS<`Q>#d4Icf5Yg z9rIXnl2b(UCo79f=dkY%hl;Y1Z(Nbhpjq@})v6MGzr!6HS51lf7l?3yOJ;s{mYj^t zsHlzmH`ejy;o2A8BsT>mB_$uYlDaz2txdBWa8f<&F^xebSiL|2O1QkF66$WtOvUB_Wb>R|$uU&s`-crng<~>=`@9Cm3;4i8Q^BLQZ>+!?* z8sK@za245b+Oc_=G~IUFJ%@V%v&-a+wzYm-ByWAEdauW`2V%{?6y-i-F-O5k z31XQrA2?(AqUCVlOmosMU7vC9rP>UB@iMz{VSjbuLb+W+rT1~~AMf}S5zAR3?QFg6 zk;ga1fiG9b_A4r_LcHZsS0drEWL5kcvI^v3gw7<9av6F4^ouD98(BQvRxy>PJXYZ( zF=)FsN#^Gt_4>f0Hr?s<_1=rCY=qH-h{XMIK7Ep>6%emf7$n*Hr@Zjj`Q(zpKZDx# z<-gCwd~SaC@y|D`?j_d6%ik^^I#nF~qjMigBj2;7XYVN)LUqL>79O>~9L?iv-~Bya z?$B}3Is_y`%0!{{+Dq95+a+2!+rld!hZ(!^2+T#dW-P?+-H<%%>Gndm_E~*`?+>X5 z@Si>NDNa$-)n_59mZ!|X%lDWy6G6f7=k5e&g@<2nIguYtNbwpS=*0AV%%{XNSz)=x zlN@zQ8S#U=*vULo^$9MQC6b`>adE+maLmZIE;kF7O`d?D7{#jN$GVN=r5M-v_2j-5 zX+1f35%H!3@>Sf1mpg|re}-C;(&gjC!Fb@v8S$JnZp8ISx5S=_PswH!BeZ-QUV64O zfUrwmZ-i*ML^`%5n|m{o5O-(mDEei@h<+b%X+H21S_ZgXcBpz@AteQl#lchvntLeu zftCa4v7CI?Bi2RpHdtMo@V2g*+?XTA9Z1B7>@aAF$&s$B4}i)Y?vQ}f;4#&lb$s@1 ztY|rVDBfxeFYvVDz<-3Dj^VplN+65OH*cFXIW105NKBaXZ%6FyVdY%++62+FgU*Qh zhUg4Oa0C-!l|Ej;*_a$bE) z!_qLYg)(Gnp8VH`<`4f~IU2u>DL-l8Wct}c4W`STz^>=whZ3iHzb|<8N}krQT7>I9 zo~_v~XOAk}5ggB7NbMhhHj=`5tHExf7%NurvhTuDsbxGkf0#5UmTcc+m>t4KGoi0qJ06Wd-jtG2+tLJ)8{=zvG2^np;fD5?Dk;L4!pUw-FC33VP`7`?Vzhoy9$3Sg0FHbrW$nw_WjV?VfQ< z>2YpvYizw&()xl}Fu!+_tEjA00%St9mOx&CFBB1w$YKj!P^cKKxrEn+a=h)r6=+?{ z!=n-$dJXW^fIml$4ivm|-~7w+1_!>KX>=tv-P>eHAZ+eeKYHZCn6*dlpDpNtak=(J z;aj2HL4Srdvuh6~<4?&c_){;pr{8qXL$|6bij@ z1M~sF20q{(w6^wn61N`L);Lr z31LuwzbV|0wd*z!0dHN^dyb_j9&@69x@ z(W#YBXg15?jC)t_Ty`MdoAv9!e{aH>>v$82Y>?izTglYWwtGBgG58EZ?d+ceqMzw|6Swi_AfcX#dZ$Xef4Yq{nTs^o)GVu(QM>+Qx3nmq7R!VYr5X*pGJHo z<+x&+xVtwf|Ng6ZwtxTQ?Hjq{h`6R6R>u(XLp|E4h%5hlg=>Put3(M4hXL?2T z|HcpAyIEv7$ME;azrXeC(fh_V)gz4OjO%Fso!Y(7gE=0wio5;=0J~|9lYB+}-&qk# z)V7B-3Kj_b@5B#F^)T%D?}se3M}m@E);#aeO1P?8;TD5bYszt$ zK7jbnq~qTu{VZVf=L=Ra+vNM67pJ4gQyyoun#|HMa7Jx+?V*4#X*;p=jtdX3{!LyP^mTKdyRO7pWMk>Dg^;i>;B4`D z)0bHuBcqj}dKW{BL@!_R-zcp+_wS-7)ilmKKf2g4AJkBV zgoE+A)N3PS^WC9!V!po%r{jEAl6@D4gUHzyn=dY~+2~z(4LxXUtHW}HIcHWX*T!{K zpL_o{DKEDBuKZ2NRo|*|Lf-g&_76vyCEtAwg)xcsi)#O#BI}TeD^oKG_(K`{Mht2$ zw!h1qSiEPJ?=t^D`LrIk?S=l68o zwaQFYgFr~jhxDvOXvsTB@UYP>Y(qW4(G&hp3zJj9k;&v^q=b+Zm^JzAN;gW{VC_LWcHFn&-Ud zT1W-L-31ICK{s48ht?7!xu$nha7OC&V)+C>>56w`gj^R;EOv$At@{qfiT z6#Fhp1vK?{mU{%)OPGt=bmx^T{88XDetWEPK9WGN5+g4f)A(huSos^13b}E8By9yk zi!$qL##cRDextV`wSLIlzKLy2Rfw*FV4cabDi)9`kahM#3b=4uI$i#M-LB4F>{}hK zs;DZ5H^&nlHoX>$(K^QMx@BBKO$XcUxCq}i&;8)zkJ;~?@Q#k4ldU|Y@hND7P;}i> zp@?GFm8J+{RAH3w47=}C!`!brFS%hk1;w+y+=x`HTs>L>`W-=SJ4*gTuV-!;63dfkvEBPTqX{n5(Df6W?Ed zhr0UkO+(KHW^GW@Qkvk~LwI{Qvr$d2`A62Xb?gS+`{c!ZoDZxNBaOye+Tf9$O*1)5 zBx^wH%srcK)K1uwF1uaXCib1zhTY@?DU+f*_`4o0hO-+;>K`0<8~ zvc@gLBkjXK9hYhr7AIRYeZ75rehmz{5jUObbeC#BR*oC2Ue561AU$EUcjZ+U`Ci(G z%?>+UDXChyIy8hgXXc(N1b3W#^ltoJrizwPR~?aEEMi~ts@r_t*Y51@R3X(LM?c3> zJEm|>Ct;Ni9W{d`AKA&-x+ZmPMXgHCjDyoQ4f_WIt*`tQSxZp3-_c1geMvue4Z$hx z>tkm1ACYd%5ZLT@pDPKGwy9Of&vMs}F)+{&BuMq#==FgZ zNcG~V91pZ|Kb*zXP;jTpbHCa^_&D-)mu4<#E}x=Z=`NSp)R)-tuo4uiqOrhuhJq>D{(I4}1!L9HAlXFPiqOiWPPH8zsG#;Qf4Bf9SFYr}A1t zi^ay+jyrC=oQgk9*AjA$mMvSoy8q*xSg#kci$I9Tw(AZPRxfVN&vFv1X%{_-ZjI!c zXB|2adj0Op?BhA>D!)I|IZ?|fJJx%VZ-~yXIePD&MJb!F8>sEmT4(HwqmceQc~J0`IhsB zfd`8?mfE(RAUt=^5_|93-lG;@IeMecvG{e?I)c|Nr-v7`Ct3)88#{tT;+6L{$Nm=a zq$ebux3h}Lld0gmOd9ZsmJwM>;# zuD<$0Qw53J1jFIwksnVN%=Jd zCDj~S(C&Gz#{`Y$4Z8o%-O-HVpim>Qaffv)m*C!AYf0TF;zX5|q+V|zi_>dv*W!j>O;iIt1}aSNryhC$`)uzT=~{1_9Vt7l!lO`U0y61XM2D*V8M$!LF1_+v!{{; z;Txl~Rm`7cz4sTNZc}i0iP?PNdV=m+SK&tna*HD;YZ={xz0C$%_K&mSDLHIRG8=fa z6HladaDnjPOUo>69mUi$Y{fQr_vjdP`QH>gPte_JdHm&F4|Rom9&`oK6LNR5-Li3+ zuiI2UAo%4axF+Oz9Gwp?PEV_dznn{Xbi7Cv{L*vR-lplOm(90lT#;MZt0T67gYZ^U zt}0_^YuTd2)eD(D*_1f8tOi00?@EhIgS`6Wy~?`-dx9953A)OH`@`7z-Hk$=thPlx zCEUx8NUUx5HhK|fT+$`ndva!@84-8wZ&$?fjM514Jz>^RFLp|fUvqc5?E%-8hr?+^)?tgQ#EI^^Jb{P~)5-I^)tmXjMct$6 zg?{LQt%iHMh}91^L^+a3Z`zJ(xSkn)N=$egLcbV*&HhE&!pDg&J#Fo>I>O;(=axas zn{RVTW}U;f?Y6m&$FIseGZJQ-Nr~f~#@ChaPrNJCk|5+5x;`0h7Cc#YwEVeFnd>JP zV%^g{2T4uLUA%-}Ot!|CYx|y#`?uXSb^SWqyYJnnw$9yh-86@pMNU8H&C!;+!8T{n zqD=7Hwq;7Ceq!Q1yXz?pl9{dTp6H^Kb%dk_lEHdsVqH%0Z2ft2$3h)-W}Q4jb)maS zuA^&d0XH#%K$v|L%zn_NLHqoC$jM?3!swke%XY~dWjFV$w4EC!%6AK1Bz%)qd|F7V z$QYj6Z`pRNIh&h-P|XwU#(SB$yzHY0J;7tBvzhs#VrIujJc=Hp6Z+Se<%D+^lm{a@B(BAu|vR-^+iw z&XQQm0zUzNeY5`WRg|H8IQxGuznqCiocQnMjgMQh|GoNC;`0B0(Nq8LqW^8m|E+ua zG}YuYG-DYKm#qcI|NfI7o?76!bdw3J%EBoc@pQ!ha{<%Y6yNwQ=jAI?2;{*-xXO0a z+vMK#*GF<-YorIZWVhHm48tG7N1qsWLd7AF%rm0NPF0N%h(osZc(d@jP0-1xa|-8y z$(8*|=Yc>bmd0vLfr(ze^0vM?XdNc$?d4UN8niZHEHq!aEdYVMiy!2_{ z)l=o29Ak?6IfJ`R`rwy=+v^WF?%D!{8DO~Q*9^|%)KX35G_#~TZnjSKjGts`r#B&@Osw*{-OH!37xiI z=ciuf@zqmJOcWa+kS`Z}&!WDzKh5zkL==eo6#CU?f5+X?k=6vq?~vJGZ4{53#zurq z4)A90%6fS&I_uG+o$yg$q2pde>r<UKuq5V+d#}g=L&n;nKh-L4hw|n13 z^TQp2*Cwj`%#)MQ7)*m5_Kn_22*m3)J-6s-mxw;%k*B9LIsh2N&vm|jU^^IRJHhtx z{i6V!XyP1e-@Dv%pRsYKuWkc-g`2lsQ^K@%!xxM>_Q%St7h`v*=b`hhVf)vbuYe=` z9H*W(+Z>D#Q$!50BKmt|6RO)$sBYN`+|(2kEQZ0Xgb;3l=Y`qi3pEl$&VdKbrzND$ zC#ny!H-u7_rktM?taux>xjH!&%r9F4yFVAJHIkZE35NcddoZm zu5UOcuo8SM(7C%C4BqO#`w(sEVI7@aAhk7_n^*TFeQ< z%z{HTkZcn2RU2mG6q0F%-X^nu{PjEZ+mME?=P6)R7FSL-%hQ0TwAYD6u$LCQDF>6V z5sMzl8}^pq*!$sd_@Md(*i{(I+Dn=4Vohh&gKt=Zz48UDSXPTD)dVRb4^;YHe*TiEa+wyjI}; zsu!w$jb*ldTj!h0YDx&4>q<@ci(!gQL=(etoY-3Y^ zl@>PKy6R!+?d{F`5k#YPFAGThF5d>J%|4}JMj`_2SU;g#cYL_q79lMEfIbpm1#psjIk#1KfA) z&;2lg?nnof&clpEQi32@%$W|Ky0c*ShVGF*c}z@9yeyp$UY|-cnF3~6Z4H)N7KOq1 z;njmT3?#eeS++d$2e@mrVmN#0$I)%p;Z3&zcXC*~jD3Eo20_BQsDZt;;Lse8+5kRk zcLE$z)H#zQZnKoQ@4yS(cXuTN6u>2J082L09VwZbcrpt7MLs6_*9Lxme%&YF<4x_? z&x5yk1$X;^e}Q)fxq>J?GgF)&c>}#W?N30bZcI16GNElJp>j-U#5Ow7MeP+l%^&zr zrKuEns?>+=;G*9Z$;2#P)e1BC=zB6p*Wm1XL16d}kDAcn>b9a0>PktPdloRV8j7N3 z3bQ|+uAW?e<*)icFX>${|0N9gbkPM(c0nVS z`KMrWZH(;e=_&S?#n7OW8KOhU&g^ci?adqdXZ)B2AgJV~E=L2b=q4wl%C2LrWkXB%}_t(af2c7NKz&&SpQTUA$DI{n6Ao z>|%W*-?iOh7V0ayaEZ0a-}%VIK90Dd*oprkMXo1R-j&H>D8^#jafX;W(UctYlWgg? zYVWSu?@b|K-|F6GT+lpcex)X&Q+7Cg=2rkoMIw&aPnM3>q2@am{|ev-PZpJEv1!$7 z_z5I~2$6`kFJH7{QrG!^JthM+k3~^985+FFTA>qoDxPW8RCYHlNT0 zPnKMWV3XENN9_?9miWV6@-TF{w>Nzbq|Ahbgsff16~QH>%Cs>3yPhOE|9C-SSnjV; zlL}umD!|K`jWm_c!7G6Z3XWR zBAV=vIM3GjY0)xVY*d`;Gux77(iF1&2oBGWq`CLGRrWmIcx9xO zWrEzBbTfqshi~14kyl1baX!C6Ao^bxw?)ask1K-Xj`UXyymxU^GuZqu|34qMzhb}wyB*Nj;DbLC@o&q`MM)PJ}Xc&1!@7C_xWX)ow zd479!@;a2ayNsaX0tLT>G92Pf*F zqnb9H|IguGeOspo0n`fX%P1!Q9igutS4)@A)oHsx0| z3@fLd8{&V_ouhy=6kA6gA8eKp+(NRw>6SNb)QeEzMb;a&{aPwZ5_+F_?8~` z5YcfK@xm-<=kBzSM#y`&r8s+lpC8u=>P73?c{X<9^os|J?Bu{bsgW;)dNigRdaH!6Ksz9y*6-jx)D`V|(25$l759<4@fePrVzd;@lQa`|wNh$v1q%)J4x>*$K( zDfR)6+dmYvR;&{LIDPI~ocG{mT0sZLvjJPX3#V5YXy7pInC##yaI;dS*(cd^iECF% zYc+xWA&JTn{AoU-9aEIzja{P^SYnW;XKB2G-lGE&^9V(<=P=&@J{aZNl%S+gc2cNs z@Ge$2PX$BR8_!+mfjfw@6E{I6?1V;$9`UQHsp<2>aHW`7WGm@-NzEGXKU-nbXp&N0 zbBU7ElLPK&R%c7Adv?3VJGH_AH(P6XfV3E#xdbA_QD!h(3yL9{aoxw>?=PMHSk{tu ziPy-)9EwwtCdd$NN5RZ%%NlFHj*VWrH;1Ai829l|%(uwn?Vi)V=D9{7BRS}duHvHa z&eh!`b*ElAeH}5|VrkN1&)CT@g&CLERpb?ww=ou88Ks-Alw&g7R{GBG$7ArD-1how zdrLWLs;cqACm~;M62&5{;qZVnV@C}w*dSd7Fa-zA59E0@1En43yOiT`^4Z&yzj5fG zz=9gkiA zn(@%HWyroy<^b z1u)X@iR&p?4x;xj{>|kq11{`;Hg0#y(G8=qEN=}`p0K%{`lmhmH_fl`^Z|AQxA+=^^U5t$8@*TNJ+wB%h5(N z2gkedFRgxyu&fSeW2ql^HsbnM_bGC8zY(KplL_ej~oFB}L#U+JvH*U%Y&pG1AJ?hqW zziVw)SqJl-ggE5h{jop&cKAbp`NVGWHxlm-kgmLMQKj*R7qRNhf19L$(}B zo>}LMcZRPFPTbwVYrM63RLL>lFrPj(039Fqv7uXoBQ%R+g%n8pnyfhI4Kqeyoi9=G z8gV+>SO0q7;7^eE1NZ*BpK+n9Xas*!hk$lu%UL_SR%GqjaNSR}#gBaOp%&@;oiSX{ zWm*Fnt)JmqeT`Z*nhr-uTux4)(mtDG6+eF8+&so__I?Ey94h=lNG&~@e$$h;jaOWO zn%$hvdrDlyU_7R?B{HZhBeCFlKK*ZnDbppD%>tB{0VfryH;1r#bf9!f@+~tB+B-Nu2KQ>&SA!mQhbj)*Zwk1?)*~Vxf z{fIN;*M{V=@?x*s5sWw5UFr#LveGOJaz*W*1SZp0`5(UPB^Wvwk4e z*Tco%za|1F(aZs=q=59@^@Wv1k550aJplLV%jZwqNzOk1);APwr~+(t>=}3mj1#5} z5F+F;x5{Ht$uLj@r{pGRtiJcC?HH=3!kUsB63RR@yZCv>?$YtF{`FORChhDp6kT<( zodx@Tl&=t_F@}&WRk9Sr2ffJ4)xc(Pfxq*YYY>R%ZCa4uBDd~%rM;141ce>e*ucIwd4W}9&9^Oz$Y-`cfdBW=yq z)1P2cgF%<#S+Mg0+)006D#w4MIpM0$OOIOZqe+5pB8+9q0U08`VGF&zU^+KA|gBP`7PlFAV~Pt;%k&l{k#eP<2Zu zLK@sfO@?dHN38TNcq<&<%48fVWf8!$nZwg|Wv>^r7GBS(b?`fSceFCHwh*y8WnLPw zKND;U17)Y|;S7mZPKwn|>-5OV_74JED2J~YCsg(1+P57q$}Q*MW}Gvobf-WiGF^5< z``UAGy(n*&3PF?`NPT|@2vmpws6QYt9s(#P=m4)-;?WN9anH4#MV#1~!F(+J>oZP2 zymyn18e+B|Y7dYqI^baITk24jlG|tdN}I+Mli0Qu=MxYwBMHNtKM46K#^H`eO2fGe z%?7j}sS3-eEJ`*w1TQx@ympOyAV?9oR?Hq-j!Yalgf)^pIuF-wl&1l(>~&p$y&Bjpj^hE+@qHM1F~eTyV7zy!j>mllxe-)-2&_Ny?U48MzSxLT!^+p7 ztX4e&|wG>QM70cD35KX!ix`;Dy+?h;N^s zV=&nL)=k-FW3YwlzMPr!JxLknFuOXfBK4i7j!Yxxpo0D1L~!cdwz9yMc7au=Eh{#Z zf(qKAx(a_GH73{6K~eMYwE9H|2%;E5~Qd@vp&>%hNb1(DYbD*Y% z3Y~$Z?SoJ3a;dQo0E<(GSpiO1o}XD#CNmsRP%QnLjr zPD1)S-aF~=Fav?Dymx-VDQqYiLDsjI(!RuV&E~G8ZA*y4Q2k=@;*T1!o)p=&fEhwA7)|Qgc15bloA~nE2hvCUMeZ0T#G|Prl4ly7eYN)KzwHc*McC7trNA z>dN7ld0UnnRdy~5B?>@O{1a8m5zCKne*ioRcR?{laiipe<8b8{$;L~3?x!IZvYI`A z1LMyJ#(#!m`8VWT-Foxxz_R3&eU8@0!$jUZk;$nk4{cvcw`Kd}KYeE5e?>2%6bB4e z;2(3Oe$@8=va@zDZlx|TnLA<4Nh9euSB*O1-`9*tx;r~vJofQ2h|t#Q^hUR{azmx0 zLwqm{S&Pb}Z^m{mOINm-OlkB3)Tuvp-K49dx=<5Wj#()w&Vxy|9`E49TBp`>gJRYMxO(tV=Ip+mhf7L0=TWa$he^IWN!7kX)eyHAt zs#OR;CV+aax7N@#R2yq$4woPfACSbi#~BZOA5H)!0|W^K2qj>}WrcZ7#T2`-UiYGV zudj)to1{(*`+9N`oL0*}*Zo+Q106sgeXh`9BzIlgt(E8OJQz%Dq5D;FQSBQ(G}Wai zyWa;D6?s%lnF~e?XNM_8k80g&rSv0EvZGTY_k&Tv4)76VQ+?iAJf>=ykS{!ex%*m| z_(=Uu*L3gKy*TuUfBkrcEe@Km9$ev=o%#XvI;v8cTf&UnF!HFmy6GlPV(*I)u{+f7odUZ`hQC zx4h@qVigAv8Do0DW6ftr#}q<_QoUjWP9%aoV9M*oFjBGE>A8&CXo@4dU@$`=;Yum&&_~tUp%wahxuinpSwxW z{KM9#=j@`|qzRv7okUp_z)Cx?2+xuFIwwH-f;{{Mh5b-`&WD$jps~R`&Sxs2cVFcn z7izHueqXu+0(cQk?haj>w$$Q^^KIBu`0}*q@LN{o&67?ATzW6e@515TEV3E`S@Kxm zT}pOa8>b2c@~}+dJQSDm@;)n~RefX9?luc)M}~uj#B3NKDKHq|NXmYe$!Z+hbh42t zY_o-8m`zH{M8V<7rxF&=;Tm5`ZrLdy zJ2+0iE!Kp4SxX`EueYgh{B;XAc1}h_y=-8<&ReYF?-h~{&hv+xx7W>=dHq<=R=*Nq zw`J&`OyE4Xly^#!1vLGa3~&pNuPQoeC6BcRu9|i1(w|QrNzZh1S{QH#daS|`1xQa@ z$^*}`@%L6OR2z3&0yn>s zMP3A)ofc+x?^wlS&d0~+T1g-=8Dx!9)bs1@<9gWZ1Gn@HUtQaH_J6bhs@0dh$75>} z1)6{OZq!rp>#Z^mmCQlBnWl1HONUj#;aw`~$-kC!u8xr|9**>8>&g=E7U*8AFZS^A z1&B)V{yPbEeqBvsiv=STIBcFUCJ)_z$2t6V8R96_!}cL1VVYH&mSQ|+qvIA>r2;Ua zF8<7B5OXV;v`TQ2fRSceV=#Q&&mSTGcjt5bJ~GU4&K!qoWWA<;MVsQQPLKZ3&-NwJ z^@P2BIkU$8nr!Wg883haLAKsg*wHBGYNP=E`xdkIAbC!<);%of2)Us;3nygaSA06EQW<4WB5sPd#dqvrPxfT4 zQiOxg-;nw`M)Ct4Kua{jjY>-7zxl&F`tMNOiA%_O@bK80TK%flp?a=(>9YoFR3laT zhC1c@Y|hjfuE&=j33%qq1Up^ciy$wFu`3yzHPR+jsfHY(`>*~5+7#g7y#_Y%$^C?> zB1Bk)_{+fpGMn5B+d_G85#rO)!&&aM6}st_ z1(C#sr)sqoOu50xCHnKHbi|Lx`(i2TUr*(6gU9`oKBgK$L`i&u4m8%7p>xkqq3&g` z&a1Y$d|Z)Tn=<#a2>cd}N*vivVX^RlL3-?eV|-%$uX1mi>U5*O1e(P%TH5kFSn{XS zsFuoG%w~rxR?Ps#XHCb3)~)}Y)eFrB%*L_OP?d2)t%1BBQ~Sx+KkEEowsUB+;i4X)~9Myt|fGO_?J)j*)#>XJFtUH z$;2||ocAGrFg?9}eA0QGY#&JqM;?5$P)Z8!+64@p#MqLjVUNnErxaKU*r>wl}LBrtY|Xqk7qBk1|F&SZcmqpEK%wvQKtd*pvnZ zKnkQ*W79k%R~Y!1Y)J#dYuanTqbE1mGvcGgTMWi9Ph*k-!WfUlW$T0%_p6=-DW3g} zdD!wWP<83wQmZcBuE@O2U)j26)z=aUm{HBcnM?wJd8RNUtwU!^v!i&#hvhVLJITt< zrq0*87^)m|N6sJ5D%Y%K#%>h3i~13$yWSrf^&0jLfYgZCPwsVS+X z?a!bM_u0vS7nNYX0a}xzL^zZE>7e8omS=`sq$I6Ycc^c+nC6Y62qN=gfYKbw3)y^c z@Wj@Dcb(G(x9jZav<^7UWPiqrdE0CM#Km*{U-xX{Y>oD#9~0ZPPs{4lku3p$A#5nm11PXD?rN9VK)!$8`2w zt3Q1F`s(XMN*x!1uwL0d!^ z|D=w@*sBlQXnMF=(;4&xV79UR?M3TUpoAN)_?iezMEvm$rbRdYQrFy{f7ujqUOa z(KCi_7JMPCOr;Z1u90j#weJhI;Tmg|B#iT<_X)@iw}prqUHnG{T|EFf{CURX^~6=~ z1l3h6R^Dpdlc=yx@*e5X72mtiX?qhj|J9nYWz*v`ZP@DUa zmCI9vTn4`VAUM>#y2zs9=c>X^Z^dni3Ef)QG4n^ zbN!LfDm(n!=`lZG;QkxpLj~VnMm)FQzTZl!VZ(#(;ZGQbW+Oa;HS#EifJr!5- zdNhc|(D|2|Li5YmwkgjD$ty@*CzTKw-8-{ne+ogMWuEv>b*AqY`Q%v}@u zA2S2L|KJ6Lpo6{9W1h9$%`4-NUi5nIjfAh1r0_dcG0EC=Aa6n)$}xc|hmxe>qcLV3 z2!eNBB5e@|`XPu`>R4}WV)~s8)%1&pgCS*dXq2tU46#TA;YI9a>#XCTs;n3f^}FG7 z$PP5s&b$Ye!GTNtSvmfi?)2Kq2-#&Dg2HY3R3b8W3XnlSWwYoD>XSw4)4nMcQ^ii` zvc+m7RjP421pEnud8-H>z`se>bMdG4A?p64xlE0V6@%8Hpm$n|!HmE5RwB{_16D-R z)Mao))Z`qC(KGVcwV8X|HoLQlVjeAC)=GTERu>dq`(*{~Nb4FaC5gJ(Q0EUH2lXo< zZx0s4tjn(n=?}-v=Qof{cCRBbqjhcDFG(bSH=;$m+;``Bu~HSRqP+iu>jsV=b;n-X&h2}aEzlZBxsJ7d zCmd?y!#49(UyZWa6no9K6MwnyTBkk6uKvk#PC=LOybbgcRCiwD1hty((YP}U-VIOy zYECufOjhuI*K{L2jz?}OXa4mrQgDpn*?0S@9N_Luq&|&ty=4_Ngn8s)!9P*eccwBhKXGGbr zo_9h!xB4&L={jU)bhBgNmfdxL;va%s;5F$T1#OC?)2g%O(^yDt^1g+?FFmaF(=fm) zpu?q>dyhJt<8MRyjgr*Uklu3Gbd)Z_ZUJW=Fhk4q7m!YpHLcan&TyQG>vbmM@r;Gr zOL6|*n1=ygtq0TQyH+7ZgEf>pi&G%Wfuih(3d#gmci3v+I^hbWB|v&ffTDnpEuxn0 zF8(AhZM&*guBZJ+Vh$;sGOz=i9xpDYk^l7N$v3wPMYmk+nFR!3KeT6iWs|Y7S?AT4 z&pgb}$m<1cM)YWHZr>&J@Ih%Ct#qfQG1qpFwpy7n64(YhcFQ^QcCd9FzM~h~$Bv;c zw6nfUH_fDuDHb2(V#Y2Ab<^7cO{u_g;fFvqRTkeBPr{G*E8IVbw9mwcrk&0HMrYNTsO~>|FDHV4Z5hVj8f(8vqYZnRQ(&$qUtGe zn{Si_R`&!hzHp?t^HMkR%Lb%P`GV}x416T67Jy8RTEx?|3#~m*b6aDYEs{}!S%2kL zzu+Bp3_EL+5#3y)`a!n(aaHP59AD|=0J{8jJ)AC!HZkrH%;X8L@|PTWNOF6$YTFdh zXNmFtLu>b42jAgT$aHI1FdPn~F@IdLUVgY37YQ5%H`!hMV2A)*?-ABcOf7Gm(x4>+ zY5L0Ip#1S_KGQGNu@B*wV)|79x$9B8Xv>14!P7B!Tq(Iupz}Mw?`wg&vc$d5@vAXf z#iVWZYMu9wzVEPQ$-eL0aEw%!9QNQ59;%fL^e8=UP47KZog(Hb2{s`S%$Nw7y@U`K z=MKQoKJw8^5|Z7olxoHJabhe;v}zG^O|P~D$$6z4;RjFfhkNV9MWXVe1km0Qj&b>K zH9MrZ*vUV=_d5%vroY>x- zNWJtz!QiD=t-d;KZ9t~EXvW16ocScGUJCF-mQwDx=#7EhaYp~jxpqz2tYLcWvg5>r zNlf}!ji>i4F|u)hA0;ll(SlH$(csdP_mpEilaeIvT&DUIG!Z=)__+Hx2SkjbQ(r_XY}j=78N9s>%nsogAm^4nY9SGDH3LIEcJ z?540|_rNsPrOQh1biHMv6Kd<3aD2ZVlZZM(0L>bG1-No#TU363{W-OL>EXLg@e-5Yx600n_1Z>O?*+wEHT`v^U- z+&J;KW8S*M66sv?fI&RmvYfuEB?vLI!aaKHZ}ot=y6Rh9iRA`BTi+XZBlGJYK4rZ4 zqbK-AFUVL7`{Z~Gz#vYPqtM5px{+mu;~L^Zo_Sne738oq9Q_Q!-_+%DkxlNG@I#%f zvWFG2wO*pljX-9&bGg!}#V9d+{(X^QmOZbT9a7O$m!Pj7o$Hd<*Ciad4efR+L;xYV zg<^wmnvq5uiW%9+Zl4`d^z9NPvmHPbecB!jben$`+rZBnIT@(Bv=nin) zk43-??3spX=!G0k!5a^YH2fCs;v4f`38|6UA-Khs)f=onKw4pXV0vf1=_PwEXCx_j{mH*qRd`Ak-K+B` z#WULWleyeJUS111tD(~%8<@i{xyRo%4+pVd>cc^o55)>kK%)QKW;KF5{tg@NRRBg|fEFD8lsA#lDGv$w+;EB1lj|qTiAJ7# zYc?l=J$&2xbGX5LbfcTyF9pR4!>Dj?OziHooy*r<`lzzFCnpf10$oE?+FP-rQi=`2sAJ#IE=ee4NmdbM z?5#ZXA~|M_ARe8P0XW1Vw0?4$44YK)v-oL8XYK-5w?5N!$s^O2R)9PX zj3+efmcGuo++&;kToc7OZl_CGU9$dt=i|0y&nk(@*k@Cf!QMoBYpVFh<%t2XPOU8+ zkKM2zW7YO{@hu1$v2_0Y3y}6lERjd4hj`bwrUy3O&R-qOva+lAl(xFgsE*Iod*43% zK$9HIb3eQI(-%Q+jMRs|b9I(q3cZ~*WRsMep8TnJpZ{~!T!Ruhrd##0r+(t-S$j6f zzv@l=nLyD1gkFh)>LxINDrL>-dalZTXm7)h{YL_p3<*gz;C2cz81OeZJP@$iAwngS zz0cAq?~_Xsf`Ldotp|C(*?ps4fD-c?;-#|3yQD$gpwJ1*T~fDdWpUsSJy0=yt_j!JRNpNL@AOanr1O>`doQg15_pX zSZ~vhAJiYU=0)sHo;m#!YB@Nv_!;jsEjD~JjHEBwdbpG=rXx6-Y!85YidycUB_{;# ztv(H1JzX^ox(`pvi_MAeHeYlk7SQ%PK!;tKP=~=hwr)||OIX@8c78qo4^@saCx`T_ zr&B67ovOGMUUa3zEGf5zWarnqGRk+H>UY8b^j~#v|Utv!YQSOAXo52{zv!muA1M%82?_n>S5vDe66=~(r{(x9-G5@EmM=vY&t^Sq7j~leY|~_gIGwf zHrsZ+Dvf-=0r_&9#tpGJk-QT>?OdoK9J-L4((G+GjW^4INR>>20{Aa4jah7jI{LRj z_$pyF&E+=ApwLa(R}7!gC7Zkooxl6@DAB$$o~^R|1pgw~T7rF#=2 z!|llniAGYLO?OnLL1h*A$@yk1xh}QK!i=f4cSPlJ%L=z&#fXwb%V>^=eUPA7= z566gWGFJqEDdK-zVt#u8pb$u%PJ*P!qxCaZ6SbIn`rKV{t&Del$eo2g69g3qPN+uZ zi;hN=WM^lO`5Kn`8%BQMufP(`+|?eCk7+xX;MvguomxEl@H9{P7D! zCiBN;E+Ky{DSo)_EX&J_$^5;(=^_SYVwbi4Vzhd8-K)Gu?_|4)!B+M}PJ!UQxqC(1 zBd(D*`=vJ?bhx@Vc6B#t8XOs2sTlQyZu8Y#fJFTa8q5&0Kb_S?InHOLIFkFxD)~wY zcb0%u#6$=&-H_}L>eId6*hYVkCp|jXpgU#sOE?ksiJPkFm8hln5U9l# zazHhd@1Ll#k-)D8OSx`!4l?}GzPJg=UT>P3;=vR6k!Zj__5|o|1fFQIoswS3bRRRzr8CVM1xSilAP|#?ruZ zL%!!+*SQ!&)Dw{qmuOy^VBk^c;B-!*KBToU#1sakD`GuRX@&Yq6n#}GXIY;5ts_uSBaX2B zpO4z3S}~ZDZ08=rslv>8l!0W#5s{SVkVnv<7{JKQB>G0X3sB#eV=&BZZHC^x{qA|7 zM>K&|w(P)+ZiLtBUYpmtMm^nAU&0iUpSK#njRZtCD;8doUwgfeY^=?)e@trYOpm)< z%G)8;9k_LNuy?1mMsc%TVS{ZXT-zIR`JH2@ucLN}pu)`)Uxn5^S1X!mgG((*wNw45 zuj_7L#y|}O*ne+>S;u4()?8iR3;;wm51YKPZ?=0WFuI#DPI~+DPjfwcRvB%!5_v|-(jPtBs`of9jsvwC_oZ;PGVXc2;}s~me6K-(vm zMCyE(`%KOX{3~18IqD?3{AG*qbnK|NZh-qc>Ah!on-9c6jFtcOxp{lu1@PbN37G~n zn-SGnBrUa+-28|=%LPgOG1V2q3~0A4AA^yBT5a^GAa(G|^%!oVw#i_<51<33_Fmn+ zrRQBko4tt2O?zx`_0zn<-rslW-FaML#@YTQkn}drhf%W%{x` zZ3tL~UZOxuXnJyS3N}!_=He`fW;v7$Ahp|Z$8LRMrxK70+fSS;=UcxWkyztFGr=V9 z5c8~czOxjTcJ7=cP74K^y-W3}x4+~`Q!p6Cm+TNAg#)=jR{6Iq{vab)?y}Gt&SOu? zncC3tTc@Maxt}~%h={Oka%j|hvs$$rFW|o}S3E>PP3UyKDp|0y z4#p}-FqZen`Z=*J9R31FH$;XEzvZm zHJ#+n86b29JznQ#H$S$P910+|LG9SnJ(@AABWYWCjN!G1|87 zf(!B3OD9helheKV6+s_EP!0UaLt=W0(pOU^S;!nlX0H%uF;H>s*ecwBE^J1>ozIYQCYYG*e-MY*KG2@XbX-Dw=4&deIQU-NX5nouxZstq z0s?p&nUy#uK;_}=+MeW`kO5!(w%#@VVv^?+n* z<0JUvjf;cK=KPafG5`+_|fTy-)4*?_USuEY3p<62)4L#>v|il*`At6HwcXHHdL1oQ}e)~XyU{6EaON~C!rtbn~apYqy0rEv| zrxuVJJMC?D*l=iGC+9%#o1#o2dAN8L@X@$%SI>{P?TOxn>j12rgt{eMd?eUFn zp1X(~#`et98mWw5;&ZA8?0beH&2UruNEv$eFAy&^*43tU%D;fxHe?gq-3Q{NDDYTYj46H!z$fnYAew{*7JiXDyR*3xsaS0@u0lMIxetV&sYBTatYu}C zx}WErw6SrJ&RSMko#iBBIcTEw3OtaIubuC&1(HWQroU#?FRGEr*PI@9%WKQrK0;;r zxCeFIgFgLa!E;_=q*QNTPDJWF!pDaXAOda!kiau}KmKAib-dE<{pweLNIcrKja~F) zZk#ao^?Iwq>+l#^kru@+5 zndV@?#I7*zk~Su5iWht(&YO4c+wceB!iM)oC-SA*(R(Qg&eR@ zfG!_QJCPc|+#A8^s;?7a8VuyNcz%vD9>LB`9CT5W6-oij)HxmO|*2@_yJUh`cn*KGwP#Gef7ND;%S|W7PHwJg4#lgbrv1 zdv6&>N40J9!jQk0ZkOcQr`H~)Ssurh+0cS2^m!ZU>Wb;w8{ZK}{BlNvHy}}y@7@;u zTviHlyg%)1*ou`s}s#t@-aQK2J%hh&Jks5NN zx@<*(S0WujjlZ4JIRi>5eCV7_NK!AOo58D+S-_20%gSxC7XOp&=)Nb3lP@U7dOXph z=}X?V502z1doHNg=Xb|^CBxUXlAJvX_2&(*XzB{-$n6yH)|K^5ZK35N+?|}}f8cS9 zSAq!&`E?8^=}pFIHv?Jg7m05XB`GU;WoF;q2vV(%w@=d9kN^|Abv2G{KbbNv4v;G( z*i|Xdx>dd~UJ0%~cAKaxw~vGF$cHIJuU~pKQ#{p`3;A>Z9;te%DV%zT-xDi)tJ zyT*M%8X;SM=KS(KwStM^Nr7V55p)xuiO1wFi zCwQIV9?Vj3{k{giq5={{tpa>v>d>3pFFwy(bTuJINSD&?6d=FXdXAg0z$bmUzNJ91 z^Bh;qdOq`bd2!o3a?#ubW~8xwrzBdvv}%-qVo;1vG!^qz9EGt&D-T$c+x<8jy+T^g z=-DWR^q)87t19I>bWEsU{Ema_z2;=!coWKormG1M_a60l~>Sm=CT(0;zYLg{C&m z=@~!wAKiM26trR8s!oZO4y35l-dEYdcNr+Wg6c(l35nnJb`}xV2$A1u<>Hxk$!-SU zY|$6qbB%@fawwun8YY$BH7crach@@sjf0EEb-T)OFrN-obLy;uY3wG!!5crhC9C=Q z+Mqn_#`|0Ay9F4{umVRb);)iaXx-e;jEp&yO=19#asN}dH`Oku3S*GYab_Wa5}F(Q(Xrzwd}Na(A47Jry3H7I5(giHAE zTWg4~zy^L9o1>In{2*fedS{f9ww-E(@HNr#?l4!VsN$4zRUG9EN0o%i(a=h%b7#CZArmAo#`;2%hL| zK=utLTqMyFc_D8#SZbYRje!HtaA27Lqk3$Bf<3Irn4NM?iVd`n6^e}Tm{42A3jcORkMl&0>{)LKwO%@UaiY+55yuY|399-JP@k(e|vf=ZM2X* z=|L1Bdv+B{w#qWu)yO`^E@bH`B3mRvvV|-|jG3_vD*L{UZ44&Dz zl2m)6^xY)in^zvwY0tlZC>j&jtjzg^G{nJbKwI%)@!yhcPj#Iu_gny z*WD!)w?>=+X$S`MgVyJ8{m*VtzH{${+Syo?P$xMj{vxRHKg0phoDTGH6RshA81C$N zyo-xo!&H)F*GbI{0NXkJaY3F2yo1hez%W2sZ8e5`!I7{i`U|gJ0>^bXNUP@4_Y4za zIi<#L8)p}QubUTd8*wIupu^|_O2IUsAp_feqV~n`SyaFEtp38f4Q0Ng$VoTF zOci0$r^BeaUReL6e@%B z`IDVZ=~aS<<@O`P9fm?(Jtd(0jTux=M+fAsyL05R5vQRI&9ik zf5)imUH!Y~*3u3L1k0s%LjA-SP)i0KsmojR@Gb4xukbjf=cN->|~_cspq$1h*?r!$1WL#V7MA-EeqakkKa69K*Jq*b|u3(fc4KNFb%#g_THKPmVBgV-}OIvLyYk$=21Y?D*8D+QG&C zorfbWm8dl6YzA5J_O6rU%aGgJZ0bpG{-n9>4dP;!F3LpR>#Ny7d?Vfu4>tIwGZOqus_a{ zuH>J-!yq?LfCOfYqR|m|SrZvuOvWEIL8tqxPs4>@{#;)F{Z7G}nlYqDZCZ&1Li}Ib z%#WYntjStHJHP$G#<2u0(;IFAWxwV8oiSo-n?D6pW|~QgpkaET2fc-7_sLX4`YK2` zapyJNJvQL+h0-8#-{!I^_(l(RWUt+5H)Yu3v)b9}3R20Yiqx)(T+O!H!CE<8Or=~^ zP;|j$?K=g8Njy~VE7S;5%pLzwH&B#e>{4g7(^m)7H3mi8vsX5U5Has(AomZj?2my^ zhD)9rLHG{IP1H^xoL`1}X9Cphwj++kobS8yPzm=9n5s6p(*PNHkjTN>oeexlFsJZd zw0q3A6P;bxLZOotGac}?bn{<)sEnhF&R$U)#=_;Lq^y?2Q@8Q#591qOQphKQ=V%89 z10Jlv8h=yr#EnCl>u0DaHbVd?^Zb0lHgf3Sz5xh=<9ny4Z4Zu|I{j1gzqJUf-6!|v ztac-U9_WjK4w}xpuv8rnLE1rykDNq;IgQ+O;8g|0r7C9{#Mhp1w+AzY4h_9KdODo- z=$(4pc{_ym*B`G6FEk09IwiubCYSwhhqINGqFQp1KcCKkUObTxMN=zhRt!>9Vm@w2?hcx8sgu z>;2^?9{w0jd9IeHi57x<0D&OW2!tY<2R3Mm-^z+U4O}MH&wySU^0IZnb8qhfj^DPI zX-ZwXh0}YU4#@+Qvow}(+jlLMP4QXeR5P{xXOwK>HJfvDri@<10BhBX7mlEx%}IOFfkt*(}uEq{Kn{pLpCZh6=R;CAI;6}Z8*lBH><(u*P6TX`a%%^gy6 zSW5BG))Rt$h^n7bdtXemlAJp7^q3Dq(z|GR_v; zCSE(*K{ho#1UJCBL=m^Pwgj}K2fyTvez&$>IFwt8xy@4G%lde4JYpaMTL^P-M_QqKRjxkex%^yAb%4&ywSg7(F#K?^wfE^v_-z+Gu z5#~!2vv@PcQZl*}gv1oVNzZ9Sc;c6r3%&4?8fF?%u4wQQtY2eX-mCCvz!@m^2^OZd zezH_`PzBKdOeevQ|61OmS1FG)G&HzbICk(IK9e+3x3bl*ysHY@@3R!n`r?)ME?B_c z{@~_^?&k7Z5Mcmr6ebuUp=od}`5yIMUI-(@OMovO&d)SOdQw|dDXe{rzW^z~xpZLK zUZ%<+vPY?Cnn%X1s=WMzK==}i?r=UK5L=o5W}4U`nmbF7=(8JG^4huN1)pS+OC4!+ zKY{S^3-FeH3H+!fBGR~sJUZH580;j~x9+1nBIA!P`%!XH-p`q^KH|jZKHbh~h8#p| zny(DwQ?h(ZfrS`0u7;FP0${VuY;0_cf!zs*)duIPvTN4x^V8R%&zYJvr~}0~!MK8e z3uGL*A>p2~?fRuq@nbVykE0(=MvIzW`Z|j%?}N{|i{a1gVFycxZY?17M2k~#)i63o z2zLJ;`Z|OSco3->wzO6+-8r&ja=3iJwrBp5ZR>G{P~zeuR9oPa8+Cn&7RXQ1?%-Sq z8ehlZ!<#{>oWjK{pCctHuE8Y*k0i(%=7lSkrG|V;&6FSc)?>8v<*QeijCfT=g+oD0 zWs{|jmu0G^)hWMSdqK0ca!^ix6J}q!3sCj4L{m7tC?%E%?`DOYKW4FYIjI!7q@&yk z)cqd%Gr%gf#|vm=_rSoKqC@m|*SX{qk6nlAoZlw7bd8Jc!oO*XUw~ix_aoQn4R`qv z;N0WrCGq4ANI!*+BxZ&MbFVt`1b9{FsO`oaGhp&**hbWTonM&0gaYV z4PM?b#ZmzU4omt{?Ngb({Cq|cP!1Q0@eXaw0dMolT&8QCPfNblXUf$hA8;XlHR%ix zZ1e9qS-zAKS>9%9<91R|@!?K;5S^<%kl(oN>^SD>79PFEbupe0pBkmd*f-=xR-sui)Cd-r^(k=TsDrshkFTc!1 z7WJYj*E6y)!Fb+p2{tNngI@^_cFoUVfp*XJbGEj&>NX&4lO@5w92?ZDAP}zcX=`ia zB)_QYdhBvcEiO6(~gPgYZRcefEg(C)@Q?1OBfqp7-MC6n9#ceJq|gT4XU= zZ)JNR6h4vi_C${afBm!b$Y(i+Zc~)#-sCvk+%3eIQIwpBfp)FKCqzo5BC zhm5S#f^mbQAN5O^x%co>oSq|V((wH%;)G4ExcCFEccV0qObMqGsEG0DKazVFzAnAV zYznTrfc|Fz1$WfnR-SF-=rD51G4Gq0K(8mJZG}l_#$4$55%}{k@7=gb|M8tq=#7v0 z(&pOYb7rXOr!kK^de{{FC@TF5hn+5?Z4C7W1ha>pPc+VQ^+z|TnW%fbcY=;_X8?;STp1>{d)CXjf)TF zXN=cIhSg(6tgnAnPW4I+Z9Kz%;gj67TUwDspxNkUr)}ecOT~qS>N&61_7~uS1B0EQ zV4^-5%I$JC7E-`TR@aYHmn!#CKIP=(q!njhX@S@FSktho*q-m+Ey7tjRc~s!!DiX; zr;7$uiUUKTfIt1%;!$2686*KNUhtb6L=V-hMW@W}&O8j@7tv8nD6^lwSFmvjw`CIT zV3tBkyL!K^q7{=Q|G{_0`!wuxzkeU#yTf2*oRHB|Xg3~hU;Nr5(E8)Yf4aZlXKfUw z%6l{pupw{5y8&z_N+P+6TpLu2ez5&%gK$S3K5=d9I#V%+!4ZE!g&(-Ra$iR@^Kh`2l8*)Ls{?cMgV}uDvt2^JicnLBbZ) zAvm(qjv5#kAa6W?toQYQ{8o!i%=U(3iVs73clImS8rIj8lxLt_Cv1CRZ@f*^b+O^4 zwse*H1#g?!S$D~_ZoN~^A>&5lF}e)bUr?Wa+q>XE$%AN>!PC@5GZ?fies?iG$u}X{ z)7{8G6-li);1$E0LI2Y^w3w-E9&O7f^Ku7=uh#8*6C3b?Hjv|W%&VU~YfSRWZOQ6N zp5|Z6DJs1p5 z{~|g{Yk{}J7l%RB>_wM0EEfAzsvHP1;7*Kun?90|vkWt3eU#YV-3r^T=fGevS^Och z`pR>m#mdMJb;d<6W>059A^)%+_JTN$rcy;bQF>JaxXl#F?&v zJBucvS>+M7f!RhIrSDa^BZl9o(fa&+Zdp4Zb z08D9E@c!`)a|T8VF6nK$W!6e-<);W-ILeil)x3PJxcpnDQ{*nZ;C%J#!?4QBN`F+q zZNV2g{LbZwz#V=;VRE`^oIuYg1r(&5HLr*Izro;e2?8xpWUn5CTZ@|oLaFL>m(A+B zRxe#qXu~z&0uN zPx9IO+VAoLWyT5HHG!XQtlr0Cv#|_o#ep;tgbvG&!C*G=xwv_G`UwOgvZnWSr@frH z$5!%pqTgGPFX)!B!8F@>Zvx>Em|7QOwRztU?L=1kW0OWN*7p>~wq?~YSIpe1#*ZvR4l)6+~i_=c(~%4s~otiQGOO&Gu; z4;VM;ur^#kz%xm4P)4xdualv8v%1<~rLCR&N6C}aLA4+=7Lu8vCC)iO2=9h2`W}bgG1=RXBiKVTS$oI0Ge?78gGYcKa|ODZpvnK0%LZU@*g*^zY^R zdI(*jTCCjDrKY_b`(o#F2#HmGbmdWGxw5XRVs;|$k}>3~!5b^m-&80kHy7CH+o?%O zS4)nd!}4e{NFr&Vayr?`nZeE8lelkrxgZ&CC5tISmS;NJ9+s9LxvxAz=*8sS`Nh(h zr{isX!gt3!@%|L&ipRvu@887wQm=iq=ya+bmkm%)jz6|riTX6Z>w=QV{J&v23+^qp=G4rp`EvG!}y6ZX4rC#boQX`Qk)8FzWrh5 zOXM9-xrlkY892_Y8zuMO!|z8t{@!Rx7ti9E&N+i+u&WqFo0^)Io~R`}n|kISFxr!G zhF9g|Jzm+K>#DwUT#O7Z?;f5QAqeOD)}7w*sOWobkZ*)jE*_MM8Q=eK1UV)hI5H&W zG5ej(SVv|(DlLXoqK(F(EP(nOlK!ro@_TuT@pcSqq)5(*uhY_>wQ#eS(v$7 z11sMuP-dzuS^v8)(i!R7;!)PWo$WOxeg*RhvPI9F9Mj4k!^_miPRBgw3pJJz6E)8o z+|`_$VyEmzTiH(Hd@je)(|TC&UAk8aCU9itsA4}&?d}o=_OF!;MMW{CROu3bv@`xp zAV({RiiwSweyX8RD27b^oB2gzLDCj-tjWVX977uW=6Sv7*sMb{Xo-&N`UZGF+&FKGO0mQ3Ki(P-oer%00u@ydQ_Ef~#MN(Xia}2J# z-11@F&K2d@iGNgOrfV`oyjE=W8YtmFR~C?@ zh6SG>uEtN?w?G}(8!o~=sfmiqaW6eBwsiR4A0g;}bh>Xc&G<#sM9y`rLZK}ZfSQpa zKfN0k7Yijc*P6U88~<*5K21w%m~>go5hqXoA>baNEK!mE&k|Wx@rR~c!i#< z9C52cI?L(%$eiO_e0sek!KIV=ltY<6*1UQq(8H=f+egI&Nq?!of3GIw@cE%skm*s} z7r+D+&@u)eaS}k1naWB`0Qccd;eZLsr~k@p{!Z;BV-x@9spNkCJc7e+<)ZsZCJMKS zYI!50%MA^RdyE1_f@iPe>#CHj0(5xK}@AG6uHNJyPl?OdV@JN)17=>-lj zPGH3d^`3&&jk5^|uu!)Qpb;BKhHk8J2kP~+J&!U8+Y7L>6Vi$UjF9l=m_RB&q8*e- zBs4{i+>veBSCNww;sZtV^RX!|m0Id9HCxka)n>Y`l`VR;Gddz{PKtZjg_n?_GWO{N z@DZtV5a&Z3N|!1>ZoVoAFlXt4m{VZ{pbsU}NLUV7);1#2@K?mi+?G|!_oWKfD|du< zuT?4D%k66C%w=QNldmEXLo-5YM!OJydZ3i4kK%>*3k)0^s39tp@0GVefj0=fBj_Q6 z)>NgD-!SKIl;PY(Z2zAM+_91bq#c~{RReG*%HP*YNpL6byMNK35?kKgFqZ1*{BuLEF9w$s8q ze`OkkyBBDQ3ED-R^F7!Z=Y4ednMELZ*!AH6?N@~On`V$D^MgW^bZXuf84~JE{w`Yf z>chqFnMre*P8%%Wj1r8qmAy`Lx=BzAhQH@j{aQV1fW`i z8a`yrBX-T(f+F#KlPlBs5@{r5Pf4s^t!{DuYIW8>udm#Js@x#X45PargtSGjDw&FW z-W6rLC|$yCMZ|VIDaB2+XDfC9u}gIu4{%zRg;8Bjokp0*%CcuJ{y%6>>elkJvoEJG z6vfFAMSFh>p(1t@X0qSaA&;xx@lBn|I~Z}isar->#h*W+(SoQQ#JS3`dQMw z+L%2P^&E(jLKnXpWHU}*ZyXvsuRA!`_5J4oIh@tX2r5=^U{{CwY<-eAe1#7WjVeP{dB`W(szigEHB4Ox3kdw1M zLAXaBK2!NXanO3|w3zY|?(c1vfXY7zyt9VO^YZeV%PAo3td=n?_I&zO!)aW0eCS-u zq6X%BD?tTEu(50Zfe;K^!iMy1x5)-^pt>B*&8GQY*VuxARPu>zkz%jELe|gM8@9# z2&u1H`pIoYms1@NBR=qD@t;x;#SpR_Ztuth+?CE%$Fz}a{@xYrN8c(^(yX~gsMms% zlD}U<#T8B4gGr)ghjvy%LE3yomrp25iHkAOI1r0@h0pejyRmGgu@O@%x4N!B7E~u1 zJ~sw@>zMhr`K)=M-%!wJWofgZrBV5F@<5$4!#6iK7g=L9{#d$!^a%0SioJaSEtduJ za3Y&LRYWrCn#&F9@Cly{*^#OF_WB6u7Jc>cQncaP8h_0oW1{5->jV{moVJx%~P z*~SkbdSEb>yV#L!TY&$3h2lh&D$o1s@El84v%%RXd(Xzpp650|-B^xo{<_#LYxv;H zJ(pAd3ZS~^%m8>A9Xaa}IVc(#>g_<+x7oknEMNVEl>h#AMu-LAn$@oD#lDbgI$8AK z8TWz(*56Prb(`ij`)y(B6fga*^kTY&JTxLBBPE4c7zxeYI5iH{kBqCm)>4x$yH{O# zPbjRh2vm_Neo`>5Iz331*`ff4Diuk8jzHc$=- z&Qx|?v5--ot?F3NE~v&|l^i#Dl9&)!v%63B&fheTeA*`o9~lvA|05<`eb}t3n*J6r zWld+NqvfXO{3|er>j^+x5#;y4i54g^UDk{e({Q)0E?pT}-(H7fp`H zeSH;bU$M?Pwpzi!RqvGK#4ndf`AoosU~uW>PB&qr_H*pJw1tq1&7nm z;`+Tfo9i3`TA4(Vh|VI;o4TD2tnHs98q1C35yA~4oc!<%^6N^WJuZC6y`r3vX)$&F zAAvbi;@tB>1~N0r!<`vzp1k663|>7i`^FK0bEAZW@~y#Mep`}`_k6RK(c2EQnkC9D zrwb*(2A=~?M7Gfxh2lo!5f#>-?!MK8&zXWs#b_!cyh|Kf0)Rs z#KY0=*3VB;N@6Lm39Q4RULs{&HM$u^6E%O&>2)sXTiMHWY=Ho0IB<0HyO)d9&4}>}s8rjifp!ZLk6a8OsPp|%VGX)0O^!N(t zh6lVKe!xEDpH%RrptxWbGo2WYq^vD1Lt?*FNn`davZEt)bTASu-HyJ`AC81e%E*9D zRmV40VO%8^OB~F{OQdSO_%xV-n9*EMgwJ)avJ|+m=S-`t36rO>|JtUNH+7ZAWldD# zCLBV=hHG?w7&%L2wXA>bp`y8cdAF~X;e6JBdH`SP*RN;a)ezfDl$EHdO=NCZH}g`( z{V_AB#uMCf&bPWug#HZP>u)|Q7P{;%1}L~Con#6Y-$dXw1mL0U}{7YZ@tGWbTeSIg}qV8<1)JJ`I)2-6+AM$PM zeX$D*OzsLW7VZlu|Gynoazd{_pRD9{4Raa{I4 zH;o8S6g^)JxhJ({cswnFr!7>5>PELL+eXXFCo>w13GXsv@}?^=GgF=hS+{o@&hc|6 z4d$BJH%}#$d(Op4*aAi|)u52o6$p(l>ci}X0wPk9lS_#;}BbxjlD54B!nA=Y5 z$|rp}dm=sPnH;p{f+owg=jaw+W7LvOm(bDGmH4Q0d%H5Mu&}Uyq;kErAanje4pk&* z8nkxKOqaG#RQc`@nI5bz$JG=vJ;tlgKS)wK0f8#&Nx`Fr1!t9s$@1WU^H3(&%p zed)&X1LD*90tW{NEp^MFJz8|2a`*X~nzZu)@Sf`29gw62C)|xHOkW<$J2~z}=71_E z){CAxsTCFSI|g$`=~Gir{Y4FV=MCOh<0;L^MC3o1Ri>N2y=hR|o{xAR*2etE^IaSzgAlJ}+bv2{s%UdT z$n3g);a?lU#`@;w=4IhUP<7P9ilOYg=^0ItpN+XFFH3x&04y@%U@mXD-ETZ#W{eK< zGyDvHM)hj|czq3!^WIeNOjAWg&TW5r^>@cBAH5nNAGh#PT)pJ2NcZBGZ%aXHQ=JLhCI&V&XUJ69lxA-#xtb@ z7HZhte2xdZ^=$C+Xnd=YTFZgHhR!9Pitha+fpE*Ziq%#T4I2Pz;adeH+$e0+6x}7G z!df3c$?hC!8c8s=76P{bdtiAoeroMc$LEvYN(#A=9ZNmv#uG_|=@LiY4%?qwJDcbmdF$}I1M+LPWiX9ujnA|Y9aYS|R zLZGH}$YS)duhrGcKX8Y?9bf=-#GhCBcLelrn{6V80ieOM4|Hw-q2Yp0#7TMz!L2dI zpOD<1Rxmy&O&MSvX)hTMnmIGCm@F6-P)ACy*PERR^w?RYb$yHYlIRapdrjT3fl3f+ zEQ`d*=)es6xmvK#*3u<}Y{eRMkR3zX0&`Ioz7E<}Jr|cU+ZgTa*6h*70gW^tik`>_ za=`o(_KoY48>1IhSx3|`;AKyM-8RS+d`b5yGVoa?_+xskekHe2~qqvGo z4W(XlbLBC#FLcU3y*Gw1EouuozgiCwF7fpQ~W7~N$RTG6GEf2m~W$P_X*^&9!{zNI^FPukMhmyILJ zyS*6X(!Hi!@&(-vOTx1U>g!-?oBh9_{bBm9iY0|HT@Dmy>nV$ii{&K9qor5>15X3q z&aO$IuYiw2FLw;|7(~spatY=pUS6AQC%*_3w+KLnLAl>SNm?~x`T!f6W1V2k^klK0oU1%S9*eB&J8893I|B;& zV?oeU_Ge=UQ_BM`!h+d)q(VWCvV-|TBoYBYBY-rr7UP%QsJXs%qVswOy9)}%o-9%v zUC1^CYNX*h$ZgKyX4xa_FE45*8=>8aiYg(T@*Jq?)wPHHOKC0)i3^*tU|p$bTWZ9; zYH{6W(y8E;-h8~b5_5J)SJNOg%L$hHdHfpCRO5%D`N3mmJ5%&7K((YpfG{=niK)MfX~SopU5y8CIMh_BtNe6LMsvCq;_1L=mkP#~C2RcZV*Zk42 z3AhMwxZ-?rf5Stb5eJ&m zAOlgQM;+;6+oA~25u$F|WPSJf7Y5tT+jt?LvRU}Fe>BG@I_R;&*Tzt;zR`bsX2-G$ zQBk9*2rHSat6hw+LrExgMletSoGovQtxS4|&ep?)n$qK!hUcovuqMt+F18M93CM-W zm$5kucX2H}uLSTejmZQvmlpGyTFZml$^##7?|&?C`vxp7?^8T4Ff!y_bn>a*cXt6I z;yZmPOi+~nAj*A>wZaL#@_7r- zygjSmedk;rjRhIRQ*zOFqy+Tx< z7|)Yz-AO7^%N`@V^0XX~691QH2;r%mknXRuVB_S~vgzxUwxDQ~vi#s^w*!b|Nr)RkNF-YAQ;R~4CKfaGMi!iB1Kl2QvC&R(v#E}SX z`caAnn5-Z+EDpzJ^{v$I7bfF26T@M&3Ag+ax5*&#kdvjm;cKVULg94_QNs`Aekw}4 zrLeE@Z9VpeWUXttR?1X}{^LaO5y1xVddL`1G5qokxg!UyA=oyV{lvHd%YHh* zAYw?d_FnhB1lgD&&p#zbtByJOn0Ki@p07Q2I9W6)uzrkzym4?SVJDm6`8i-yH5P8?d}hx1xuq8dWZ2$`7YNn@XY&|+8>+4r~L_g1wqSu9pKTe-=-pT&u zf%iUvr8;B}aL9)upHcka)|Qw9`LLQJ*z6eb~|zr3u{m?!O)V1pUgvhd$K&~($t<|dV{ zQI#VrD=UbD3lfTd7+FZ|H1q#X@%4IKx3}a=3D?piA^2IHqgtA6#q8{p2NK~Sa)R%< zF?NQ}wz#Uja<#BYpU5z>zwg`(7@hDp1C^#%^a8FYRpTCeMO|0=PsXQ*|UD-|x18|s7FH71GnB3BF=*1HIWu6@+^SP=C8qRBRqGn*y5 ziUhR2fKUdyx-S$Fs7!FmA=q(|bIR=(KKMkQYc!0Re#F&XfAvm-p z*uS-Z*sX2c2j;m~J=#ZIM#imS!P-*Dsj+GqmSMFlg-bQ>iv4P{Ql6uGQQ1r*u@$>5Wm{eOurtSScNmN( zfv)_NZYtVo5uTM?CD=^Vgv}N;Z~QUD4-BdHn?`ii$A97xUfKG+IcHGyCGqwBo;_oG zvA;LQOJ&TFw7$KUfz9%fbeT;|dvgv09LxxwMGOxW@#mfzHeuV5(Z!i32h)bT> zEfU{nQOXHf3L?9rt*Yd(O%K06-7|37(1U=rtEFvz+&3@jF0c!E^Tv!fwsT5pPi|w% zpGH!G>b$ac`X|t4rb|4xH|nU;R(yXSA(>t=>s&BsdiY=|xO!#hUzw*pJhMK`KEJLW z_Y4Zn)lpU{dnxbnAK~A4?KaX(>NByCOQS@(bAkoCO*HxffB5-cm%$CiA-HeS;AUW6 zCQWxwtbLyK;a+|TafkSjX74mt5V2Uplg!xJcBQH z_Z7(crLWyTA#RN#sbv!n8Sw0Q3Q_hDh|bSTngqwcb%(IYlJqxp*Po@)+c zdfvxePm4i zt!D6w8NBD%|BfODC;ic1YqDfXH}>~-4dS}(tam}@%L{pTY^eW#|9Ba)Rj}0f#Lu3* zUE03Fl;_w!M&0MrXt}p%b>ACwv}MeTD=I1`MKQvO9VAVBt%sdm6S}it;f+pxPFz!< zoTISh!cyZ0$C^9`Nx84)a=z2J&7|pD+Iq;WJ&O&H_WDYy-o8Va{BZRQkAh8*DkLE% z3LTWQQ0*4x85*Sf^_S5t{6<;A`sefWJUY5_8|MeIJ)hjDk#O1YCA5bUZ$!IIXWmFJy>P|VQKOEamJeUI!& z8MKqi%HxdiRtr6tvU^@PJPx9=Hzm{AZ^;R-*Rm$uBJ1F3cs%~Kr9YER)?trqQ^_(b z*_tOM{z~OL0^&q;pEDB4gcOBYOOm}wNWRr?htCY%QCUms3Tp;96Y~;(Iuc=T4-!m> z6M$6f_-8C0Jvti;4M9?OshDEh>Dy?t+VAC91LGpK)uHiO0$PA~KXt}_qLeg+yY5li ze+z`(SNQ-~hHn*!)~TrjCRjq!VL>2~1`7_P?|@2lYeUtoHE%u-&I*lepJdV;>Ap<` zTNdFnDg5wZ*mbsvt}s8GQ)BtW0v0@`9cSa_CShb?%$pa8=>eci3iG1m>)v<@U|KTE4|)w+2=Rd- zL|=0d?*!cX>L&Efd_iQ?Ld`lnA772I~8b>8;TYafePe&$k?STZ*iqZ3|-J!ZxP%R1lu z)%zC@cGk}4ebk#>L&vQOsMUA>R4<xI}M7R z8y*_6FZ8065(v(b0QwNKB(d}C`7c?0%Z6csUA<+JZk#&i!_@3r(TN^m${8OqTS0<> zNfKeTY(zHYF_U>*w1b^(K`28AmULrxzWV@R&@*JVerO+Gyj}H<##swyx`tyTBV5Ss z?Klm8+U8s!A%!!Z#JpAMD{QiHP9fV4$8`;b3NLXOZ<6lmaMg?BVw6b zBEPDbVClRg>*2;F`fc7ParbXm`PthD74uhwH^z5=N{H0l-6X<-WjVHM$mlbr?HzLi z^eR&9-SOyXiRt3~`C@e&K1TV4R*d?R(QS%)pf}^Wd|4~g*9ZUbr$CtM{vjB` zMs+j#qO#*cb3UNe@@X;a);B%_6N#Lc)@yc_SYja&%*GE3MO7~Lf%pr$dyXkyQKn2A zK8K_(@e(6e_=3XTXFShW#@C_`opvL+RzH_+m&y60H5fNnIBOi z%kH(^GWC8`_Axbx1ebbt?F8$=RpY^mJ5ie)z^JML=fHDS&ZhvrH!2ciRCJ4Bs4e0} zzc?)Ya{lwPz{I|9e(xPGF%8B|@vRp5RBNjP_DASIPDcS{K4C3#8C}+J{NcGS*LnPx z%}Ezai%^1!t*S+GB9*pb=D7U^@mk%*qWp1ES51oSfRG$!36*hq$6u`vPi}=d{CEcX z6SI*^5!o9kNm#eVK2kF|){95c`uwzw)q;IF^ivlX!~S=9BpybM94JHi%mLZfMHWH72~`fvxsw^dUCN`U2ROcl1+K&J`W6`wS4KH!GQsF`o=0PEq#b+ zyK`HrT!RQ?3SrVhuBjQnxXYtuR~p0vd#n)e8*EG4oc-#d2rfMYY*Sqdd+qMBwz<{e z;1m6E9JBT|E{o0UYJDP(RDpkYpY`2CnNpa%*&o^eTnHp|w<3?uB*41eWyUs%p%6J^seZuG=2Gj~!Xt-J|_Am-nynVcKj*HZyLkkj5PDs|l zhnRw~aIjfOpahnV0+b%s)XT+xkPX6a#Nv02(%+VCFKTCIW8oI>1RRj0eE#YqFqZ7? zx6D~vKV3!cGb(G(Z3xMLU-+9UyE%=s$;ikM)gnfgKv2);KJ^~{rr8K?k$py!K}!nr zDJk)vH8HN~Y}LI(&k&M%fqVmLa)eg|zaj~<^WuTyl~G!hDEAfnpsg3mEMq4o>;#Ja zN~Voz@(Lc)kzo-1Nkh(N(Q^S(_x3yC2|KLzT0muA8Z3yb82Fs)llnbCE)YDX$IKk0s$>BtH2u5ENnhrW}Z6oC+@H= zlZ{Tnpd)ft7|ngWa}*)LYD2zCTQTI5T@&^g^KRJ4s0@FMpIYfEt@?kw)`pjp(t#=e=U(xShWgHbSn*pdKz<6US%u*jZ{hHUu0$;pV4k@@b zC@q15U>nr<$kI|TZc@Z*>y3pXc<$@+^t!&L#?Fg}J>OdTmyx_TIq>Goh@Okxn%sRK zGsH`9GUb}eW74n>(nbu#FAL8Rv+fVG)Tuj1KxGNmOox=S4UdkNmHfE%xJEz=Y}xk$ zE&cuRD!3r^WOmbn(RH~=2FDJjsxdnaRwQ={ZTb3GQ zhFwoG)Lh3BM#`Q}HjEM$OD{H#tY*GWvxr81sC|{WBWsj6STnGifCw6KEQS=7G$w&V zSpVXLAp{h0yR2=8%wiy|Jq2Mc=8m6%D-l-xj-|401zP5E0R`{vm&<=ggAQ~p(7!F) zvarzmxADVw>$CFawMBbCa}h^$t=%RTCzwHBvs<2CK|CjiykCN|A1lXxdC+sC`HIs3 zTk1Dn#)^c)f--+r@4u)kA3J;lv+p#<&(pCNS##?;EIsQV-ckv?zQ*dE-%z>lExo%f znt7s@nY|%W0%%>b5O4qXkt>4Oum`(c2jDydVZw-JIv=-#!WpDfo2fP0bNBKSL=JwA zMDSgUtCEm$Yr_ho#y)s8tR+_9aDsfOnynn&amS^B>ZVK<_AGAL^5*tTu0DP=hO?ACu1ru| zDzCHs56d)Y;gcFR8g#IS6Qi#LoSrYfT=(IL3g$UA7$6YX6&jIS zcL$%Kx7yfxcJ1YX8(hz|J!Zh-DaOw+ovT5PpP?gzp}8~algi7!F=6JQF%L)*Uam6S zTn2SAsOqI``bBUQYeb=dn<(LC*Nm`7XNKARek&8ELdWFqO3ASd`w z+u}bnh%qukqT~2(guVp$IVh5fRq$E*7`8ZGt9o5`@@_!(Ac%{kba4(0@E~#1Hb9JY zEOJ30vPu%7U#FD((QeNvVieTM^#8fJ^1JZ^7}fEnS!U3jpAVuLDQ2k_S82*QIdT6~ zSrT%S61T5>cT{C%&$GDpZTn4J9bCiU<>k;O8*lcMd$2?fo}OjNNZxaPpq&QL$0$|C zRAs5etdzHdmxFdU-OkCo{dyJlQ6*qRKiPZxUP+DA;s~})g*nY^WNZwldP3=t8e>2K z0pum~Olu%4W=(uf_8QE-*yF~}XU1B=7W4v|0qRU7H8eB`XgO;qR~58#K!Zl?w`H~B zfZMJ*gAkqrOyw5CqO|OaG0t>Q0zw-skzcgg!Gg8UriJV1a-McokA7y35+$7zy42*J zf4}XXh?szfx8BEVpkS=#kZps$BVLCmqDygPT4f8_ zeIcrNko%d^T16i`>Ea26TP~%VSm9G@=h2|@kw~Y`1b{|qxMWqv6u!^#P z1TY2-H_K5`bg81qp6gL}2-jyrM0OBPGaTM~3(Z*h=cU>6d4sgl7y@W^x?o3con!G4 zV6HU^!SOwuzQPq%1k8@-gWEGg{N>zdn!$K%^?#PnFGbWQJa6d^`E&UgOi(?hOT4MZ z0gf6FtiuW4kTgHvr!dhw;MbopNalZ-IX=q3J(((Sg zcrg4YG>iZS2x!I86%I~cRJy_kkydv)(7c6nb`~}JDpYE9y~{?y3;@wR$eT(On`Iu? zQw>PD>fxOEXJjv7(&!Y9)htS4+aTsh2N{s7jG@-)RX#{q0;!_tQEd@3HeXT=NQ7W2 z%ZyO|A(%v&N`bAVj0~U#n^j}GU$+4!Cq3=dR}KVoHNTky*$1ps{{t=QodQ-5{x0Q6 z2?#+Wp-DfY2yh$DL4yOpMMYWz^dr^!tl;@yDudo1-hGpa;zkjA_968l4G7=y z@nf5t{rNePM1h3gLeSek75~6yOE#0SAs35>C_KK0q){B-LMKIQFXx^NOmn*J)WYpj z()yxbRL0V0w(0bt;Djrt5#M=+YJbI@615|s_C@8P0*xqqkW;&2>d#Y7FEE?jHfoFj zN-cGR-2acK?~bSX`{TdWr}~tnWkm657?Hg~s6^SsCF@eM_vV@ymNr zwJw>Jz4s-1T$_7wt>3x6zu(WFJ#yXm`+eT$yk5`Oa{!naBaoL@n=v{)fA_cQyU?o{ zz#~B=`l*``2m-zo1uRM;egmH>dv-4u7wxCBb8`+B#`udaemDCQD4>a?m#q;T_$4KF zPe#lw1`iATGeKABlPS~0pmdEzPIz;@txY{CyYEx`|97bfH&Xu(;fwKznsp?qbga7z z4h`dz-<oH@r{!iR^HLG!4Qj6XzRR(F?NRzQHQd|>q&bqV`G8%I!F zfT;lY0|=z8OEZ-L_-5bU0GLMjZ(3vSB6(gr02rJ9V%f9`q*!6^FN3(;Yf*)MGkkd^ z;)Hiw!$$jR$wm^AOzN`yg!A3Q%$OXbX?t2{8!W`~etOpl(VZoL z^+9_B1fslDsn-2p{)pY{N)D>_bfdUtLd>36+dBLDRyJHu?{@}f-mhcmZzNTEa zYwj)%DD{nt>*V^X1={jT2K3GV8e!|y+lOe(Fq^1TIaBswk`&T6J67_?vody6jvT5*4J8Tlr$-3u`Ona9cgHb6~sG_89Ta=y#31gvZI=;_GA`N(4d;*}_x z)3HQ7s%L)Zl1famA>Z~l-<6_Bo)pjnq~55YRPo)^!_nQdrdh@b58qcMrE~ zoPMESzI^#S`sr1?kKNHg;DNsSff7u&i)CLLq>mys-FH~}BjTJW1H}SSvM}!{a zyD=WJZo2*vMw0&k#zoBCKR`*<_BXpaqF4;>(KyFn@plk(41^@9;Sjr5xp zOsuHGJZJJL4N$mS-g8mr zubBzgjGiE5|E|tua6g3h7f1>WUMM*5cXNx0DNv(+ODiAAI2&o1C=Om&CP=f(xVJc- z+N~-$1PorepgK8l>@Dc3giu1*o}kG)OJ@&)qxk4r707fcA@z+D?}bTJUvkL#;*d?E zg1`?8Qtke0R1psl&RaW-)6EX4)*5+v0s+6`?vsPVebUrkK>3$i+xqX5GA zPR@j*@XJSdbTvkf=XDqMTC`W&O-K++^2tySyQA-+=+8*|fB5qnJDnb6<|&L~re6JH zdycm;a*rMYKzcTtzw|W?6}GMA8&P0>b$vVYb7VP%&mCa~{)kj5f{>TOcSQhplaYMa zpX~^h+dW}Q#r}$5f@pmRaJF6^!C)}Q+Ledu!^>lY%3lj32n3^1i)g^nd-Qa_>ebRb z@rt71)-Jm{CFSClR!KrsH+S{%g2KW`Z^Cj;2X;);()35^uBYxY?HTaM0q;QY=ldPp+;nhG6`m6C$*UvZp^+)MOgP3r-C!hbwXy3ks!xzq9ApJry)UthsA}KM%Z>cRPoZk zv_g(D_q*3a<)_tENZPHHXNdl?zVXe)zX5>YmAQxdwV@&9NFeLUP>DbeX!>dZ7TY58 zkj9d_>@!d~X7NeN`EQWFaXiKJh-^yP<}D2w9tKI7tmeQ_^6qV5l)w}P{BJ+}-t3T< zcb8hBjJfxyBag`Vx|J9hEY-fff#zd2&(rQCayqmyPf|6mFf!W7IkD)?8pQ7R4u_*b% zw)0_0vAe!xLR9%bzF~O7hWm+yqRF&1weO{p% zr5QiI(7qO!Oa6>hmD^h?p=?)OD42EEVdm*H2bRWx_HMa}!UwHZa-!}6AVYB@Cbe|I zXokZhb*F)QsR)EA`P~r-C&8{(?yXcRPT%3!{Xmnd4b!O{uG6AF?kchzhiPZmFTR_5%ZA$e#c~$F}@bpP> zdge3-0e6*eHG8-9nTX7@`o@}%xVz4y!;NQ}Mn4*RT%BrqeEfM?qgxKzh7s;?xZx_M zC()LWCzPHO3Pw9u{_ivbSWjM)7T+pKQgWPA9Z{FPLO*W^Iaek>3;xy!pCKNzNg>bAg$W94hw7;aP-oz=&vgA7 z`NTfbFvjKAnn7afxz~-=Yit4p0&W4eWekQr7&zdB|EBrl;I(x^9j`}LRo)au%tPAI zrfdLT+wZk+4bqr+Z?|93jKzIS82*{4WlBQ~-c$3df%#vY#`xl1H zqwQN2y!bIE&g!4`lTj}+dW5n1Nn?Lj2yyGAjj+oa2Yfo^0)rok9Z*lRv2W*=gwK%a zdE$w4Fhkl`zRIU{mq$o{v4wdY#ijmNZl}n&*x7FMBEdG+AVRWG#SvEUU*QR!WBnf{ z`?_%(^Y9iX4tGMj zL2~!Mbz83z{EA$d?#j_7~ouwn=G{u9z~G%1wp zvdn4uhx7%57S2_iJ~&pN3H`aPdU1E#**sRo6w4$0#xOgbdEL<4zEpx)So;_ZRUFI$ET`$i4Z1a21c0;c;``nkGDVp^BX?Qem(D zd+?cb9q%FIO(pka4zt04oQAJwZKea@Sj(pBvrDDf?F49T!*hY za4?FLKt!mU(3dS_C%qV8IHEWmNjNwDl>O$xhGkj>hIUKjxZY5+H^&zyoOLRG<~-j0 zIUz+2y7IZrPWerkwbQrD`U)mNgi(D(Mik*%Bn*rWAdu%SH9V)Q_cr~{-%~fP{!p_l zr`h_px%Q#JF?=izAX-F3i$G<5=ebmkyz3xvY@5~GUCK}#$Kf6U^IaCdj7&|%d;N=A z8$c}u8&${0 z-*|?j3J3DQFygDqI1_n)vtwiw(_if|ka4`b`4%bm5I{H0Q^a&&6W^hJ&it7C5Z;-7 zIr>?4+)a_O7=65wP5O1TSY@2tDyx<9L44s=0T`L~2RpC$Jx&tyX{-|AW~s=nn&S4z z3@o4dC6-p8cOgF{4B*!L3f14lnHMPGd;Ljn58L}9pEswI^ho`nh8DUSBabk;}ur(+{VcyK;zHz zO;Ps3R;yZPBL!_}Uq`EPaS`?T`Ik!mn0a8vF4WX8kmv!;gQEcqlK`Iv3K~EbFfYq& zEAMkK0p3K#rW5gTaSz6%k13c$Enk2e9N{kIeDfJDw_04Z(Qrr^_m`WH-hM)(xdaLD zZgcitlplE%A!NMB=Qi@~1M7&6n7>i3h=4x3QhwON2$YIw$Gb*jK z`}PsAO6l+&Pt2NiQ)lKiGd&0aoV`C$2OIde_jDGgM_;Ua}Jp~F)k!M0@U!Teog&rV==Eius46PSO(6F z8nQItU}U_-B(_C$yh3?AVbr-5QBWn{RSL^;YJvKbsHg3K=iY1TNneWg{8&#S>tC<= zyeDOWMcTroWoo$V1{+0lyN18!IxZ7+qXRoWOB*9XO!QqKZ>nFZXAh@tC)gR&V_5I> zptmsWA58a#2ST&yX)`<{w!&OmYv)|^$v^om5L;m@fhg|-KwkOe{Ouw_Z7uZ!ZQBrX z7EB&&@$vBvRLV!bf*)M4 z_FbO@vr^y+Wq&2U@OA-^h?uv6-c*=t)p1k^RQm-5i>b+-G?G^k6x{)5$ayrPHoM)gthXoWl7Wv&(_b*k>a(gBx5hq!NhKD_ zx=cPbV=ag{0ZB~rDFgM+hu?tj(t2OQA8kVfUg-dV@>dz>T}Jn7?lQx?A3p^Y4&K{m zFWz{*T-3Usd$7|^I!BkIv56X^+TDOtZs_nxI`LzZ6X*DI;AbQ);ekg^PEI4E%iz_! z@&L|FxzXxaHtRSyH+Nv;9(eI{C~2&~mHB^WlJ9g^`UAq+T8R~06f|Eiu&8D?NW$gn zQsZ)8<&bark8IuiXEYtm)C>OXUbDOXTBhLYDDTJ%)g(IcG+Bl9Petx7zSI7~Y>Cas zlwjScZHJbctE?>7FP5(?Do}9?Q-z%yL{&=m zW9xi^`B!R{oG&H+!~R;B{I#gL18FU z-uc@6P?lvqG~Ro1UpSe~#6$||z*kCvC)vsbbMM+YFDn1J0j->GJFd}#uAKDxthp4g zH$Cz7QMTN7CqCHxrv~x+VEx$J+gpdI%KOWduG+%k!(3WqD+GLv22?aPDMjA}JF-xd z_3X|fx)4lnffJ`Xacgk}PvgVGekKSA*K9rzoJ)j1?1OCA2;ULutK(N7Npk&AME2NC zK#j5nP2(#~XdDchr)ttQ;M(16mm@<_9&%WIi1|qP@x$!XJ!*TJJA+*{2LO%?k@g@p zfO2Z9H&2JE%J0RczOk$hfyBn`o?t~*lC7po%IKR!%uw0(av<^T3(aMNb|Tw#_|mR43^a9B$& zB+aCV0wKs{n$syJYG`T;^8v`$xs_eP=3q472CP2xjtEP|EywPkw?*XTO{d@y7j@ZS zv26VGf}#PRg%OVCakK0;Z!OL+WgT^A4*PqS!ix?IIzV7wJy3wf+zn^{6E&W=)RpC9 z?au@_68kxf5Uoswu#4d|hKl*8T~HVM?>$$EzAIR@_U^+&kW12(Kr>a1a%!paI0ex% zSr~N~TVg4^%m7;sJA2r1v@3smBV5z($y3LQ1upZ}XYy3-%e%CiC%ydLu?HoHwvgKU zO{;Y-`+%qf9XFedZCWpPb9|=uEQeb3G-F#v!&fIC|<4R1zywu)x2&zTq*16PN-A~3~ zlPsFr)AjwdZqKXruT=IcY;V`U_kT2H#-8jT9~bh!te1@r^02&KfW$KYMs?FCQMzw9 z1JHQXC45>vJw1V>?oG~N@0&R=zXLYJ~OSa;&isJC|N>PQ<>&I zYwHa7c((p-di(h1sbF2ZVx1%Ov&2JpK8$TMg(i-71)Tn*GJ5=3TU%R|r{J0#pi9pw zEMudiYSB-(eY`tPK~#QlM1gWB^25WmpQoZk$6Q zSZC1c5K0s+Q#BDP9rbLU0AB55kl zTFtAmp^PN^l>62L*pqODmYeaFO^qiZD*slEhhAj^x}S#E0wQbbs1(DEs+~Dkcx8>; z3PY9gfMMMc=7oUQykS|i&M_-U`X@nFOVbO8lM!~}{H#tuVN7v+aNsjh7h=gecH40S zx;+A7m_G~C+=&U}TB|<2r5`P?gJZ+t^Tfi!;MJU2rHB1@?Yu8EC5SU&?2HOj3gikL zJR@JWJ*qS?YWv%i+*T?0KF)8IRYq2i%+jy#rJeYG#p^r=M5*H-w|go7P!|xALB}{! zb6^DAZg>A^Ze8938o$c+Y!8~#8vskJX=e48%a0ECbb9tyj>#OO;sHDL9FCSi@idR= zCOeWz{HBIRb()1tP)<;#0O6qEZCdL|pnmr;KFHHA5W}PL4C1+7W5+OG8l$~}WRLbY zZ*Kq$MB!;^U4g(dcvnj0iP$pz*3o^(Gzum~#EE~geD0fQlONcx*n!QQzJTComSau? zM8ginmtu_knKC|lGis*dE%BT?YdiS_WLa`6llO2czrp4LM=TJFKl&@0*zvkdgaOeT z3~T{<8M{B5I)z6lI>uxCzs4&8!PJYb^Z&)u(Kwk-A4UcT!B)@i4tC(fe_lywQvoO~ zTLNpG?rfLG@IBd$7{un7br4s$AIVb5DGujt}9-Xm1hlkL=e-T$Trgi>PqzB zH)#)EHvx>!UayX3`0rnG6yc;y!XgT7e{+;JDLT};ewg#<@3iy0k9li&*1`Nb_r;Et zK+DF5SN?o?^ztCN*5o-NMT*I|?qpE+Z8tnJwJOv0jz}4C?kJv68G+5L=#W1&`X%@4 zmz)GnxJlwY1Q#P=8-aQ5e_6>^2g{Pj3{^9Ns=PtLV*idkb`i8G;}a;4IEU)}*IJ;v z`3qe8oJ?MCsj!M^G>b~l-N8#IYXw=R@a7yfDdZaOXtHTyJl4vxBj6}N0N0L`EwOA{ z8nU7wv8lV{-QMIKt!o!A%ouR^E(xy^uArNVO$H-=D-=LR1J=aE@dK0GNTV`J>osUW zA7hRDL61DWxK~Smh7`yj6pV+W`5)q@sAcOoYp4Bg!GkNSADW(z8xrO7>U~P-tqOsK zZcMd_!?Svyx91*7E(UNG{UV-#lxF59KbCXV_GZcz4>I&0@{?RtdM^W8U74-YlSm*w zs(Kq@q?-j-l(a!OIv4#5fqxFn4}CVfG=3DH-H$>iXHKmHcLH*Ss>d#|aDQOMCsIrT zC}3!CFmjbuH{I3&)!8r8M$ImLTDW%x!cx|1@~ptLhJ7)V*H@ni+z7Yj3W6$s{P;`I z&w2r=w+9;?7FoaN^(UH>zB<|)WbA1n6OQsAY0T^aI}@$3?x33lC5%{!!w4?q*I5p~ z&Q_XS{6XM^BEHz|X?)F_xTw;8aqmQZUqo(M2%_!{L5Z!Q%0P^0F2Q=K!W+Ptlyz=O#s2o5oG>RrHrp? zt>|Ixle%#G_450{+X0)iZLi=JaDi@Gi!Fp=HFk_RD&)D5J;T9ZraOIfvcYNb%<4?B z)@4W<<8Do>EENqJftFDP#QDl#>egU~o8GG-iG|JCO@o_|Gw2q!^mH$!dCq^2;LHK^ z1y=P5>YYbs@A{Ls@oA3flew3O{s7cYFm?8^KbcaSNuc2M@UT0I#x zxu6<%|6HFN*y-#nS8I*}a!KQaOcX?SiIYwa{IJm$+L>Dandv{=f~tMQzcfWCDj+(#VbPwwhJXwsGjprX_3#PYp z(EuE)-}+X9zUNOhC<`@3NuA*WDtk4}NN<0(jCEdb$&)|dbQ4}6s!d8P)qjzKE&4G= zR+hl5_X62HFNp3!PT3-6akAIpaRiT5;7l{4W6}kPEMs@kEx{!1b-^`Scf#HRNJ-o= zEuUloUmtl-rI@Q5e~Xl7fw-aW3n+6bZnWCTtw80<7MSK-+?Ai#l^9zdwpcYA!ATf6tJ4b1gB(74CUNIkB?K_7n8Tv+uSQx1Wz+ zq`PPVd35ALIiX}2Z%WnJ=lBf-Zl69seT`)fTs8{-$tA6aKB!xCNndXYc^h_gr}U`& zvDZHkB^V+wG4!ZP=v?Ro)cQc_KUrzS_T1Gvp{m=N#|oM|YS)K=GaquO53R3odh{bl zbRD#kkL?wt8k6v>i72IeBK%p-+ng66%P#PRda*b;!uN!ZAp?TZt%!>C}BqS zBE%uwEknhYx6)_rZ*BiT7QCR@*m3YjtyIpl6fFQkVV{m~u=}mme%)&o%<^dT@FbUX zXElfOnivvT(b3s1D|$mSfL`~MdKbpqewOcq8_1*T{PKe_J=Q@-!;Lgy4kY#P4@A<@B*uKOidU==6uc=YifL zc;$({?w>0V6kr{Rmy9@8^1pE=y;z}uN!^%l)>++~SAVVzmfFN1iGX~8+;Z>$U4HZA zgE?Jb?;N^(l)wWhu!BF zggT(8^uWLf@Jf8e@9bMG_!u zojM_N76m!!9=+f(nW^!}pnq|y#w84OXOT6w5(E2C&@o?V|NdG%gKxhnq_O#MMu$m# zwG9}jspoq%8XFk({SiRJ=^)neBJrBCKKcL+2kf-9+=e#>?D)0zU3w*> zDc{R;Y<|;G&qQ=4c~KS-d~B=(+eDm0(l!igW(pRsntY3ZyR8X|%P54Bu)+_*`HH@d z@{hd9vZTd`=au*#9c=&d8EjYMu9#u$6`XwM`;^4SbR~tuak?^^pCy zFW>+b`K|wRCTZ`HywqH54oFIN@D7vkW#IMl-QBP_X#D&60>nRabeb0Pm=}iXu%Y^Z z1L~DMbXS9)45s})tCjhYMi0c2I1F?f`)SMY!d4t~t}XCC-InIRs2BFhq5}Cp6L%9( z%b0JKP;NxLto!^|H{i}9aDk26vEBG3Mna>qNtZ)1KyM^rh&w!TG|^Of-0vT$8t$p@ zt2CM7;D`tSr2h5z;GubwGaU^U8>D%EQ~sy~c|fW;w9EBMstp{nzD(=Pn{3iL555wmpQf@a|Tw;`;1=-J2w=zH}0oB~2jR!Q@*8>D*nc3(=9ILsV+%h)rJ%cYr}s{&1iMOoM>-VT96aly*%kh zH+*!H?bEh0i>dz2A@}&n>{!3PZ`!xZKfxKJtHCSsv|vx$Sasp|P?e8cz!^Zaf^-JS z*}U&yd!$Jlhno4_ZI1K^E;2IH>UNr5Ty0xq2KIOd+Ae0;$A`s=9vv6!JtdSQ#k|I8 zGM>&mw5EiGW6ZZNkKj7<5y@{-(JK{y_$BZ<=ROTt6$Jrk#thPQX(->7@?WhqjRKk% zI)HkD0ed%D|8~iP`1BKL9lCbj{EDa=t@f|Hf*eUj)y>c@=vVoYSawg9@%Wc3P> z=73`y<{rU0w8V1sJD{;KQ|Bw;Djrc&Z#*$_cB)b>;POA+_}|X-1&c+o;nw~MD*Hg3 zoO~Ux?!w6o34J=t;QFibFiyO?Eeu~Qcdh>grmy!WT_H~V2Qgy@;edbWF!4&rK8XP= z2HxW`v#wd7FYjc5K!5(rqPo`XY*c`iDswq-M{iSOlmv2si=r|>ZiCG8)u}i!2yx{>VrkmaPM4)DZ&5hDPQNgk1 zZOWt?inpujPFkOSdaSLQ?0^L2^&{=_H_K>0>~IwzDeEnT7FR`&7c7>_D~z9)Val;o zER+F{jfRK9l_e^KX+a%(sLLt`hI+jH&;^^(Gzn3{*an0 z)vp1b$x?GbGH{sZbkKU&uE%O@Z3&FbDwGc{P7pG|SJFEDziY^rHq0lkvxIsEz5QK- zHS!U)WbI;>t8fA&9DR&@O~{mUy~G2_Qtnu_wDQ^jHk^sc>2Vs`&T_0tXL&Wj`(nZa z3E0wK3Bbs6a}1y#rL|b@EXV-Hh&j{;*tMC?Y#3ADUA74-x?B^BG3IQ&!AA9&7Lbz| zRYw^(o*qNO^)ow`$EJe2x6g$Cf5S*C(C z)B3G44F`|)d-rNyaOx=9bRqck`&9x_wSMDIIEhS+WXCBiPhtM3!?rtD--<0x^Qmgq z%m@H!nA?^B1KrOR%z_elXzyOazZm^Lm~OKQUN-%-CZ+usIM?qpEqk9w2OX*yEzI$| z;k);URq9GEIVXOykh1%2By)o6GRi|VKQ~yFd`Vdf2pv;i+W(^ZxdCVgL4Fmj2r{$3 z=j%mYgo;*zS6ZaZ68Gj$wBd5@mAPT8U7H%&9eQ@V8Nr8isf;Si;pnsqcM^JYTZ>OG z|KC+{S&7W;>aiRYIB4f<_>FMyZL!qgLg{P(;izCd-LvNti1+vI>K%+c9NT-~&o}(B zLRoL-wPJX;UrSp<($zx6Z{CyVL}ftc74?h|wm;Wl9BUW94NLt9A{3XB(bbxVar5YJ2)goLVah4l2m`;5_GfiKo`Ozade z5MYXtvrdYuq1=70mT!8GjLDvf9)Bqz4fk&mJqsqNq2DzR8be<$+o`z7B^Lma?wS+uZTjCaGIwsq~ zr@wf;oR`rE!7v7N$=k3^baDO*3{>ebR*YC={w%@Nf%1&}$tfT(PW!grp8DP!fW25! z<})L?n*aRr8u)Jc^Wx{C7_I?9yTxOUk8-8^E7Y=!tiz@iCLJyB$$@DWDeS69* z(u?rA0x6* z7S^+zGk}iUl#zn*!h9#Gc`6+e^9t}h5I!FIo(eV%guhFB$^)0W*0I1N|5bvmww*@# z)EAj2ymp?R5?_{d<^M}@ix)KYY&WU$7JlP=0ur2YcfKq0nF8yJNK`2Lp~cr7yTYu= ze{xoWUcB@bFOAV0avUmdl*&1L{-EW(PI;WP-;VSA9L`}R*$q56vxIMdlXXPIDPRD( zxHQ_Y{@;^3o12@+$bV3RN$pAPB{rka{vQ{htqnN@0^^ZRKfY4JVTH8(+*K?Sb`21t zIYrtM13{t&qojJ$CJ23znVU3MDy*iwfxGy}c>~%&{Zq0ZP+>Ffftwrj>Ue!A_eP-1 zT!OJr*fNvu{jcRXR1>waWa?n1Y) zCl)JibP!9Ni}9UUg!}iC6i)nQl6;jRN7KlBx=K66)Gk?^K=?W6ozK z+~8-{U|7~48e9C+Ta4wiidpe&ENXTB)wsn6Bh8<8m@TQpDjCr!01-gRgn#-4Dp2|{ zT`2o-ii$E=>-dh{%=#_UYlC4SLIse$Gp2)20(Ue~%jDwu@SJDRl5qx`kIRn}V zYeaP)DMJFW-IocgrNJM%C;QoZ#?UX^^q(n?R#PyBJ+RMLn+!8&I|hbiz1RLrr47-P zF47JgEnfeK;bK!!^YcL5>3;GD$b|!?|ppXci0@5mG3o|*z~HuEY+p!E&Emxj*0G|$(Hz&Hl)4Nw!oJ1 zv+PBMg*(Qe#In-_A`}`+r+Zr~(nD~Irv&W@4kHecK-*{GBgKn3w^kGG;q|ibGZ+$3 zcKIsm{fiE9{0NP4JyUZz;pDN!MV}!@S9BY!aAhD#uq(bi$Vj*_S^1&lVE3XVkAUi3 z(!mwpztVGC-#*&)TYiaa;53uXLiyT0=0Ekwqn;Ajvva`l{RU>SE^bB+-HX#Y-J?bv z{j^hG58UMIhc}y18K~11vIsUkS1~4i-!`YHjZB*46Ykc!#5TU8v}14&YGH-el1E6k zeb-Q6m{M~a)y%S)$`a!=G1cRzi4ey2z?PY7&VWE4qHCyps{|NbmJQ-Uz+^bLbb;!g zDd5pXUgb=Zv>(*+eimc(&8JB!hj1S9s8X*GCOaVDH-G28#3yK81CJx~-7xKyN(OL9$o)D{+t-<=xBA-whj+rZOMw2L z3w^6Vhn3;B0t$PNLI;m~G2idA-D-)4FK36*GqsKyOLw(fe;(G;WSQIckt}@j$}R+J zFXLIsxO+;lI^Mjh0v!6%bFps>32?023W$wpFYn3G47*@V{s%MG)y%R$JPTntvu<@I zOB+$HJLv}Amv*VFC!3oQhd6X|o=7pE8Wp~jf*n!|kA|gkJY#D=U(KanV}4_(SFCeR zn=DmOm!vsr%db+Hy;+My=&7-TuqnHT!17@}r~St*7dF<8ZK2d5^+HvC9*%rZTBw>W zV+1@yA43iJ-BZEtztz>LNqCne;c$MBck_Ix`4R}M*%+HcAARZPRs-9a^0CEDZ|8dR z@Xwm5apB*C=LG_wlF56vKM1^N@j;bfNYJgWOiguy>SSEs%yRv&azpg*t&)|1f~;oZ zYgWlIHALGj3()2YE#~@12us?FCoi(rBx*uJ!)zT2jLW-yYXT0a#Y0bKA8nFWquHTT zdb*fRz;_fX0UR7uhSjgd9~OUF_8+cq?RV^2Y|5ik9>g2y9h4gMjT9epM`wpu;M%gk zZz~TSE>&;X8Bq0nWe%kE7L+UGcdw(qJE6xTim63W0TN?us4KC79QU5>#iZ^xw2lER zMu<~=XuBm|(0A2ow5)4gqaE^9(*8(Nz5VDh>OJbNU9uIlO?T#j$FEpi15}rUD}0D9 zxWh=ntqkSp&Euq(`^sR2II&cvWd?^SnqI>Y>onCkb+gicAE=tNXZofU zP6G6~x4O|gjRNWy7MRHwB>A_{`!f~!DkCmeLzjmQI8=6VW8Sl~W0_Z!^ESFkN}YWp zY7AdbK|&ulp3HKvnd!aM{%lvna`?WnBD{y{r{u^veuJVk#C(E|E&t_E`VTgXKAvtJ zX$f$rgI+1oB7V7IyNiHjD8sHirwdrnqHd_}ZiTb;yZ~wwqulT4*x>#v z=oh5YCEj$N+^9lV!vnr;ttq3~a;osG*l&d+@^ zLcds*kk4At`z6~;g0XP8w1a3N+i%5w$`Q;09#1*HycG(bH2}!{b^rjJC;YDo7HqeJ zDfQLrmVLlmelQ1mpszLt_l%&8J(VnAC*7E9_%{2P&M7iIF`u5*rTyNJ0lMSV_4~RE zZ2AFhRcgo&&X!dY2YKSjGvMWfm8&e3*`Fc2^DqU6IOG!(?QHye#D-X%(y!Tc$ahRG zf|uN!yB>aXgrq@{Vjf9-q&ZQ zLJorD(Y`!hQ!{n;R@)ErUl;o>I3~XZ?ZVIRG>c#e{I=*ri9hFp&z!PfFp`vfslR=v zfgp6@nPQ2rLC$LIOKl9CaFY!b6#hMbN82O|!0pqzNjv=3N_0~ft!>4u0n(OE&E9wi zJ#$Swc=0c7plyi*WDZMEo#|oQ^+FRD^)!~}8jIa$28vmWcKL1fZsL+$#?M^gbm}=b zwPG4oVKd8%T;(OAN8Dztp~7&0^7JCVxK&uxT4zlh&qipDLr4M;NLhMPmJC)2V;J}x z(5%8nKqY;pbV3_zZ|b+MC@KTowk!iuw!KzHZD>e)d-4jyjR&3ME8vNlH5}u)2zPm& z2SviQ`#YoFOCMVa@3@6@x+4Z$>{WnbT8PrjtA4G0Xm15vrkUUIFUYeAzfjWiseRy& zzPB)3B;5B4YPk(qd-VGGK--t%Ch0h8-C4hdYWdb?s@0NXh#tR(PcphRaP#ktSv$Y* zH_pG#SAI5XFEzk%)2+Tw&QlxBcUl;mHR`EUT0KdK)RnFHScXL+udg1^_!P8OrxfTK zTsfGY7(tPFGr`gdp6Kj=UF0Ob-^pkA!NuIMKJ3Ag-)8Pupe zzh~+xGcSC3Ku!)rG9lt@#!Ar z9`A?Z@;DPT)hT#vmU-d9{!o#+Me*juKylPm@xbkIS8CtA(TX36i+vv%`Kq?zXB%z) zf(qmw5r#fl+D`@!YkWHT43J@Qa2TxzUJ6Z>^R^$s@qc%MF6db;f|-f)nHu+n7dtz( zcra0(dc2)@Qi(X?R0AreSQ=OffwNE9jUEb}y(azT==1x-Z5(2t)I|e7^^o{J6x~q$ zjI;(;34L|GUjIoBT2-obndTVz=tS13j${x|32Y4Te$I*f;hrnRg%W-pd&xM)&yMD>Z(3>Osor=Tv?^VI$nxjqtT%%9Q6;t`mo*re;{C zfP|>%RI*Xg>ky;~4KFKz5m?!wKGG`)+tI^mZuxWNBOxInbtbh~GjO%svTx9aIC|b; z*E2vF^5~d((%F#aT0~?HOmPm8WGX0QI9rS!FxH z6Bhuu5cCi21W5}L`OthCpf~dL`e{HR)UTz3lcvAKdxT0%1B2c5v2lO|jqTAf3xN5} zb+JG`!>(aOJ^{Gqv@YRB97RElars)V6*jK57)i43i^<>JMFZ0~oht|fy22SKM~%Jb zy&tuhBRHy`!lW_42jdeZ1`X@B8yPsu&f1CEX{Zl$G|$=^5bgj~gf7Q`R1USXIs54E zS@{nnqAQje5>(5(SIWc%j43_xbAArp08h{6xHy&#|6w`FRS|Nv2fw^row|$N=8-of zu^LAVY>2394N!(1)esC`+i!>=U3nZI*&7=(t<(3WhoM(LeIO* zN@5ZJ{e}sV#yCTVsBP2Fg*IySl@Wiu3T9WxmoQ})*BKMoU)sfD&C&6;; zJWV>Ja%6QLsC`pr(O+=mGk?45?DmlJ#+6+)Tg!(cj^EA4H;nWta8A^IQ`lp8<@o{j zIY-3NMKYr27c4=veTg?x1_WYS(m07Fl4IU?-i%)_JEnL-5^fw{|5f#mZ3l(-&zv_LD-@?DLEpusFpb88+e9^UJc z6z{`$rFO`hN;8BJ-P;a4+WuO*EVoR5e2qccG?)p}+n=eOwb&MV!Foz){^!{y!-Yq` zYG--*FH|wmQJ_zRH>?tPrW)PT;#q!#7ECIW5j*|}NE6HP!yf^&^tL4su4qYFsay?R0CNq| z5`dAB1|B#L3SU84AzXCh^fAOTmwMm89mFVSGHF>%{ogxO88DgDMv+bGq(@;K~9_2h2Y^VtpiJK+S^X(GshlAsthfAwCOsuj_+oXsdND{6v?4zSvJRp8j?u zKgBayzzEO6%FeiuzM?$B_P>i#c)cUoa(r*-7lPYq2dAO7ZiybUadF`~lwg9jMIapp zf83hBiP(Z3Xk*;~mq&<@^lgBEcY}ZPa}|@fqR#%bIM<8Q4dmy|R%I)cBxHHWKZ+-u zhkk6FjfYn2JMHruymu&F?5-2&6k^de2TA9i4zs zAB~3$3?1i$4SN8T`#`8P{xuCt4Z0;VSZWujJKltoz%X0r)CajsPL1~I>-xiqj24a& z%LFHUwbKxfYcQJ@?O+54LQ!!;{;u3!~OgN?Q+f-Z(fxt$fxq+4r!>PSyDCHc~m#xzFRKuR2)$bkD*jv zX7J&15A>SBF)f7DdYV5t;sCWM-+uAMKvCM~Yz=oFj?+{*kkWeJBfwZp7y^ud?xL|h z(_Mt=!UMBx=}f!+eBlzT-9YF^FCRejC65&vmy7gr$_5_#yR%!;)VQ7;{hb8KeUI@`O*0@S8w&rW53l$g|Wn;2YP(;L-(bJ zGJnpzXDFvvPW1d+A%B5u{}HWp1_ylP<%)k5jxPx)J?zHz0C_xN==jwG`~3L@rM|25 z$!=)N2ZknRzk19;~*7ah&%y(?|A8c0r@#pvf)Q7gM)m zSsm(_p>MG~XV*WQih1ECS)+K5&~W}EzITZtqOELFkE zwLlr8?=OL5%(`EhpV=fs7jY`mC{_|be)Nj%&@7_wLm$}~d+7x(J-R@ota)XcZz1%) zy`{>8y#=z1X?5BdsARPai`Z`Jl+edwwFs`xa_Z1H4@cGHLA`dPU*YVc;cJGI{LsUf z2liyEA`XB9$d$pSYLR0f{!wJZQT29F>csJ52Y44NS^g?1Qh|@Ylj8Zv% zAETmbUOC0na~bB!+&9c#I#WZ;l`9?USY;FuGKkwmeEeRD(^^oqXCZzK{~ypgpVj=b00#ha38o84>xtMqJZrEwhl3m!VYlxTR_!dn%0 zFG8D%>zUCXW4-HV1V}HEMK$m@R>LfV8~V_LOt>DGXHXx)q>uaE`(VQD3k1F9AhOF1 z+2Gk&?NOz^6+*{cwGB$+0we+G@^AU85{w|$N~yQqEjci3DYVDNB7uT~3PyhZi|+9u zcH!k==uZcetTxH+*G!(e1$VY{Qxyj78}EC(RD9Sx^07j)7If{jpN-?2@vYN2pB)i+ z0F;-umH@huEU8?nXla$Bc14C#GjE+mUe{>RFHpCVB|ngqoJ-c}_k8v0mhRoYSYGAk zR-C(9wynzO$eHjl!_8^mzWlZd)kbVs61_s)j6XVGmS|s<&pXT;gK2IC#$iaObEPuT zsD|a^!<$BCso$2Ss~qlEIbrr`L30aO`y58k9fi^!+9SmZE+25}M(uPQN6*ZMubjPD zx&I%d+(!h_RZ3nqr9b6H$Xx%ywRI+D>48p%K;OUF&^I|E#lK$~;%AOGNZrGucg1Xt3%1i>4R7#ol|{DE2o(?o z)Kas3z%L~jt{{$xAoZ~#AR@hk3Roy2y*H82 zi4c0#K|qiqQbUVKF99h@XaS`vgd!aRL3#~H38C{n7o7J$c<(Rsks;yUbI;jlpS9Os zYYntK-_}Yk2UCr($bi~>i{$3!Wjw`Rf5B{!FN(sPEfkwt?M626=!wzO&k{}HRh>~? zi*@g&*yRIhU&3*w2)B4{WqMsxcq!}iZ1_v|$cgEEVmpEG_Oa^E{9ze1@1$e>5GAFJ zbNAP&tB?KWdvbO9PSbqvMvVeC*xOpdHpFxQsesZjVEYCKEIo06-rd*VEZO{Ru~R{; z3+g;&2T@rn^oGm#4e2g!{QdgPlY=ex(#W&W#|(rk5BQIsgrWZv9u$HSpsv59L4frn zoiUo$%nPjOxL|Kw^783e=cg_tI92_a6p5{&6LC6MT00kJZ@wXH|FFi{ffx7K@qdLU zKF)c5zF@D1Eoi%kK$BYtMxu%Nm!QN65Crk-Il9k_vN+DM-r@DvC=NE*1qEYaAsG(P zC_#9ZES_c&^v#%NHUNauV7bM-fL4?#bc>#q?nAey9S@7i%x;)RBda&Hh_)4gn)l{Z zj{Ar;?wR=*ds=t6JKLMWo4$4nbw{Zw%_mgT;y5jozTGp+liC4@5poddKf_^G?a61J zwzw|zNz8zDAfaP67}@B+#BwJQO_`=EMrg(E*cfdNT{&J(Be51Fhwq*I1jDSB=P#(M z-sScvT~EHm5xjn6%aCoQ3AZIWj^C6+Ha}iy+<<7dTZN7%{MKcOQpH@mc_>tzy~y6ne(0Nu|KD< zjw6z@vNSR-AP;`vp2iDy|0^y`G-hV&V!x?C|CC@40G_Mn4Ck%~ntxD>1gv6Y1NyC% zkmk6=M5LF~z6Q6sc2jtK8 z07m`^-urS1*)(bk4WM9n+ri%%aDnMZRKrOqcDt}|L`W^&D^>FuXMk<|Q1j~|^c5N> zJsDNnW=N_@Vd}Vyi{?*D8!XdGZs<*St{hRGw95~BefjcK8^nhIZ;^2TZ%O6{G$MKJ z9YP9g)3gS7k6+EAY7`IVLWjW?Ugx{&Lif0TwobdI_%KnUtqRpvPBM;03qH{om;cNa zqMgCzR`lf z*;}SWF?kYRr;K7#ZeM_hAInTT7U*u#?qYw@L?3!8n%C;Weik?w)}@mj{A*Svw+~<% ziGv_o*Kw7CW~hFGsKd}CeiQ&1NVFmDu6i_PaHhheK!BJ2@0|a*03762uII75;hGgr z+oJ7r)7fPr3Mu8>PR&H+IJ8XRsbmya;hh|-i3YS^#LN$^YlO+93Da&dfkM)O^i4ap zWbrY)uB)L8Pe8t|)g8ILqjN-9+0$}Wmc!U_Uh=XAxqhgM(?@l^Hda+RvJPAR`Q)m_ z*j#E^Z%6S#IX%q;pDc#1k{@~`ufkW0Zo4)As*w%DD%6X{6hLj~iD8XT1=1IYstA+< z22R2t)cpqogC`2%PcAome%lmn2Uqj-TCEM5%J9gu%{U1S4yy!?l#ASSY3MDurDP7SaBn%(1}-j%ZS)7Hhy}Qj^|bg zGCU^4f1qFNN+?iUUfl68QM?k%~uErOb9#^H*& z;R0%7fZDt|IOx-Yu(i#5WyUX;Y9Oix&bQNHnia@ml24y#VXL8zFLs+8)xA^kWv}j^ zsddtA%>?^);m^8ChUl_&poG}A2tiaHjj=bXK!qI%{AqQUpT^b$#w~Qs{sSfZW-l88 z5__3K{GWvVu$&Idga;Yr?6g!Nz3ON@vAnky5mxRGQ?RwRwT1d1so0e>oG``81N`OJ}iSV9$Ufmo1DYIAt}p20@i-;1q@;sV4UU8 z1>z1=BO9lgkco+ByJLmhs9$1}&Tvg4%I1b`jU;higCm5?j5?WZ)JX_Q*#J<>A+U2@ z$Q!6DJR}pPgY5qVjCttDM5EPPEW0qkJd{@)c)~px3+4=T-8Xgwcv`^Hu}*o*xn%XU zudAtfzEvQh5vl@pjJ8F9x`~!T;?&-?fEH2r*ND%*I-t{UUYM^|YwVYkc`BwL z5V#}yw(}c`T2a0&?k3yn&ny7^;B7P5w0L(5@^FmmtCwk5m?;NI&>uBRKFoRInE3-4>o-A3h^#s<Yn z#BogVC23gRFB|+|n;ftGuMS9sfd}nR?;`G&yZLp%>zgSBv8~V7gFgEwI)rgT(Sb&F zeYUCEA@i9Ow!4G%98=+YDPSLSczGToV=Nk~Mlw9QUO<~5HbbNo^pd=dLGw&F0? zmkzSml97TR%I+TB_PwizYs!UJhDKi$ zo9Hy&5Q5z~3QYgi+W$P?>$I=G!36&AqCF9Gh(sR!+wAr|ALtbE=aPRj1}4*g7xP(K zXx;v~zCJhG1cBqfE9md~KPwpe$-PU=(4O??`v3hW&0;*3>pR*j-fSHHO@pRC56FCT z<%5HC%;5uBy#Dhj_q>=7D^s_UseX43`1K@bkFo=ro+gKAu*P4X5i2~n^xrT%O1(RL zN570yM9+#N&g9qA@Dffnel!cO_N_wTu`=X4x^j1A@n@a~ym0MXXPs2@gU z=vP>qAOh*@GXj3D8i(%~{3C4|-(eK>)13@XRL!d|=)mv2<^el<-N6Y!jaC}>T8?dC zH$GfQ;1u$_o5tbR^L*2%gV5V!xP5T5z3zbJ(Isg0gX`YkE)p<^Smdj`4!zI>6{NYr zp6Rcn8ZIC7@PON#YhfuGWHpR|U;s0zzr5CCKN1d!?FmvrjB7gAHtmV^IABe>4_cHfEl zkHt3l!Pk3v%y`Si!&?*H^1loo(&E**qc8%#fmvc^-PcpQ@Nj1S@DC9R8-k^F`7`_( z&|cY%Vu?S04f=X8HUHlz3W=wU6fi309urU(a_`$_YSMQ$! zO{=dLLJwkJwbOw+_-|l4)q4#sUj=}w`qkQY=t!%# zkCfw`i=h#@Uj$6gqoG)EVqBo-0a{GJt@Vo|weGjiE-%nZn+Q7te(96@ZU&Uv4p&V0==P8 zKOmO~X=;U2fDAsZ7`D~B)@h=t?rbw?Oky>v1y5sp^cL6KdwRZP8wTV3!7Zbx09Fnhoy+%Ci4FtW6<}m80zyD?^ zXT^V^`H*Hr<14a@vpULAXzm?0pU`+c3BUj=P*G@B1kC}0DyubkoWqOuP}_yZ7kaUW z*Zo7oMjG-Osky$4Rn-1@uc3@33@BW(S)cmzt$#j4zW(BH9)Vl_3%cD;?8s^x!(>Eg z{)WT1hv7I!Fm5nFAdW;1f`UogBIu<}V{tU7O6s&i%4C^(yL^b@CceQhJsQJOUnpMp zeS35RpDsZ0s54^zm=@+_avi}nIJfdjUkkkTeplIb8Nv8Li)~CtRk8gkY;Smpn;Qf1hP=jJkz+kEpYtb!*UChNk#IqBxR4^Uw31%6G7%}wXRHj3sNA6a7m`Qzus$#)uDJ)P`b5mGLGPm8`v{>2=3k zfz*9#9H!HEUDV&Kp?Tvl3p0Q>HXgmmPT)8OUYkgzKYZ72Oqww%PsCryRf-`$=}Yp5 zu|k#8Qm93?Cq=;YcUC@t;38x`n45bZ)#bfiWBuXk(ZT4xArwSk54l0}5kyQu2+Mfe zU?M$<04^CqQf`Y0Nc?)2GHC~P=E=>!IsG=xg@_dht0&q`bM+uzNX$SsbI|k>E`_>j zl_p3#K#>AD2v`uzw|Ja3LGwl+_mBqVYP*YVJ5V!vyERevdHXlA!zb&TPIHeuw3^a$v_SW`i%AVn`odYc~d(DB%XMm&EI2prLy*|jU{jC zq77oNyzUXW62Y*%2eiI<9bIE5AcrKOQXsjnP-JlHe>*@-%X685$htuW-R$)Xck^U- zrjy`cR~=jOi_F~v!0{-7!{gT*LNPl$J>qvNhwjlNJbgGSZf{@P_=mnY|FodAqbq4J zSO#_eT0i-|kNa$&={J>tw)xh+kIzulp=o_4oM!?E6(k{+uf-1PaAyPgtC$|`#wLm zWQz^cV(ch!br>!e$Pm5xOxxCbf?%nF?;<_XI)lC~CyoO>ip##kIKiP%55t()9*e3~ zZn}l^~0bMaPRO`)WPnIe9^^f>WaV?upaeT2Fj?q0{JO} zw(RO@9YZD#-WR4raJrGUe15Jj$qNG4*)Gm+fp(m^=*P|$9d(my^NJD`=~%ze+3%6NINAM-HNA} z?IM*g^M6re5QTtTB7Tc~luo>dF%^a4C!&!3y86FCFu~qKj;u^=ka!RB(zk(<Y700W)-ER*G~8QZU0VF>j2s>H8G&(iH_*_m#4#e2!X zj&_fGZw_Zp%!LoCk!?3p!-M@<;^$Q~O9OppnXlLv6qMK)<|_~DRC+zb!QXuMP-NGY z{G9;vGj$!!6jw^M<`XDjJuoVk!;_-tHr7tKT={ksbY>5oK0DtCe#*mKkpis+Pxe8H z?1qYNp}MlndZ#=xjXhIHj#|;ts2cdK-)CBcqeVlJSRYIujDZi8ackk*`d773y|9rm z`{5yg#3my^6ZiMYARvyi--){Ss@GnDZ}AP8i1S_sOMFa4$|*u;=K(}^PCnQBRHzNK z=XnkIx{}I1aJshJ7|+in!E3Jc)d1Ya!C3s+xDypLYe~(Nh0l@VrW`5rvzWeruC*k| zg3SZTQ(-%{hB~N5ED52uRKyI)csaL4y#XRnem;9;)VRtGbh?*>Kla2FWZ8vo7hH}x z*;fhz(JBeL@zUn~Nwxh3Z__DC@6KIRmA2(9knEG3sR0DdK(}#sr~UFS-W(1NpbF9& zzx*fXM+*8+8%9X&*MDNBr_pAM|=zIYi(0w3LpE&G>l3xZ_Ou5veun&qbau* z#(qQN>MoU&GIEB^96?vcx7N1$!y*M2}1wScWj>|MV$NL&oM!8IHn)HK)scNbzaIzDuP?@sMe<^8U`@nbqeeLGCp3mohBU|yd&!()4(FTcCb00 zlVjF;8pv}hSEgY2<-SOsU&k2iEL9Koe!U=q?xy&}-4RfzNc-Dy_+Qxbj~=5nzGFGh z6$f}Q;S&la^CL~{noAWxA-NeF(Ip5Xr+Ur9QmpX~dQpZE_dzYkE|PI$Sb}NBaf00I zce+Sxd@plCiQEuk&YnM#5qA{mK8XFCBSu_}R8cQ}<8s|E&gU37013--21Xmejth*M zf!eipUvGJIK$qjGlQj}_J!gj^*0a;^nx-^JIK&s5)j025-e_t`8xvw^7Bq1lqNx$_L6??tl zqZdJ|`3~FtP)*+uODQklcDZ_{@xwn*Gi>9}2bpJfkX5SPB)_GK8OiqCn9_A%p0I$f zX}(Ve9Y9|P`LE5+>FMKW>O z!&^XlLCEw}kJXUJvMQj@`e*{{B=PFVhngV4$hACrq8Q}tx1K8OK5lbwU17v3&=ZV5eM)`ruK*9IemC5%DVNH-I z*K?G%$n!Ou{<@WR1M0P#w#c1tp_Vz?OqsL?)Bi+=3A_6 zTdP-^SOZa_`M3+UecO*7?lVSaza&YS_kshMdwcBE$ims>;U;&pKgpW?#cte~63Va5 zwEIr=Z{Y!tzs63|e5DZ)r_&~gZ!9GniiZwbo|C^;+#U2=NQJYkIg;%A9;VS5EQeTLQQFs5n;tqxkD&|N zkV&Tzac9b3%U2~xXK^>HlLV2x{i!K#&#HRi) zEtlEMJmmnDfH~;6VHO+g*0ID$R~;MlXO#f+!OPbJ(mf2{>n!;hxuyU5XNYynqG(&( zjv~>lR%AM^u=MBT8V)4abj}R%tOl;jQgYP-GZrflGhOecW@>X@?w? z761F;tPzd z35(zuzCw$1+8$$acdZYiGhbM(ARZn_O#HT{UTNiH3*)-dZFz#JbuhbqZn;e@sV)*cEa6`+jxJ>wu4UDCns_-!0dV}-{ zQVVGUsS$Eeo?a%VVy^_d0CdoVOFMj*5M#L|MvLGeD9@<(as!K40@N*CJn_Su_MT>t zn!)XI1#;Bqlc5eS1W1@bYxO52)Tj1Bb9A#wtVzm?wRYTGXrkJlx?Hf%#D5fVJ89>L zew~460;NEK+o;gzFPe)dKf>+4bn$T2%=6ytjsGd|DVbz(eb2n!dsL^vErTl0h*V1( z@!3i*a60;mGQ06E9N0A7`4h>^Bb{EYw%v}SH8KjKHV@!fd{NBQq>sif+~ zKAw!OMI&6VGCheMi^0!`6)gfgI__2f-F8NZuuc7`Y=ee4J zSbA@|`@%1MyvN4eZX%^d2Be_7b_06s^jGL)C0A`24jj;9Cr3@VvS z6(($1XlP5p%`)26Y`plI`ydHC2HO34-*$!lWYc`*oWtnZ8&v(lJ>`p3k*Cb)iL^JN ztONG{bK8wL!t-C7-*cKHR%*i;;$`iOi#24k!g%`K{8jbIK0qOMG3y@?zI}lt)wwz1 zX2vJm5+%Lq4sPur6AsVGf0prrMQ;#Gprna3f+2y#w?ZQK0-joaL+f*eQI~thhORlJGu80=-@>y6>*E* zJ^?zVj|D3B37v&sC8n1?vc_(E@;L<)m!u?k=ukS@;*d$7^=#^SFq zxJTbLf;wctUxd6xiL160z%>?Y~v_Ho- zi1F=TIAy`^bl&s4wqZ=iM_afZQQkmOC=A_ydl5%yK6BGO;Gev|*t+fFJ3h{1bd;)o zdz^n9HT_dvK%z`-{qDQSyL&P}YU3^PTz0_2Bn?6c4ADqaOHq${Y<3eU3>;os!eCD9 z_XM&pGV&J21M!^JVXF9^m|V?*{P=qRI8tClYeYyZAi{=`!Ig)woT<?}K7@_Xj1(Grj{mDT6Xq-m=HpK5mv+{&nL)blJ^cABt5kYTdb=dw)If z{lyDRo>z|n&u(@1N65+&?TduGi<136FSV}; z9#{CEXdu1cuK@9x#nh2GF(&!}dzFs$jivU*b;7P+V4`F~%A8+Sc6QZ_@6Kq443$ml zG4ob`j;E)!vU9uoSc!>%u(P*%ricOaR{MAHM|Az0?)bJe{E*{~$m`d|b@s$EFCl0t zp-EBy6m%5d9Xi-vD56TcvdndTf6ymK1>KV~$w_un4V9skZs|<@@c9giV!rK-{sS#- z_lRZ10+b%Am{Hp-Wr$NJn3eDwzsK*=^Lbe|<1$b7_eG zW%d-UzU}rRc2M&-5Ru1TLIS4AIH8KYsCIvQ@Y#jefjKj`{3*Kr80E(G;$2Ijh$|H& zHQ#y7$4W0Bofq#BDo@krbRYU;FnNoZPkwYu@Z&fC<>ftmGNSad{W~Kw*S9GNGJCj# zjnV03;>>^;bl6kk?z6q2w2UUbh4H*`f|K(`+YS^y7uPKAZ^3>x^O?aTtRXB&da6l5>+6Ij%Yc~ z&tpaV)xI(32LP_sFEs+y6yr;cfUQ5qb1+nb<75pBxdh9Y8Xs+DkZ8C50YuB=5q`i1 z&2_f(8DS;rF$Z_(I52isYW8gWxduoI1$jsk*lx8?bZ=BrjN@>vw|_l+bT(h2j|l9& zso61*hPM3ZK9JqXirMe2-PYCis^XeRDHX)}eGWz3uqHD6h?V_*)L;ABDeDP#NwC&xw-S$(@92irE!XnC2dJeqmVvVMz)wb+EwPH`DLKa)5N79g_++`pwZiizU#?sm!ga;zwv0J=pQDy&XC- zG9sbsuV1~|!u#H_E+pqAtzFKT(Cbj^5b$f7E*2(Je(J`YNu)i2B)KNZ4jlXlO8!qqeyUK=o<0aug9pB$qN zVBr(`+su=%arVj1KURg!>6vZMkrqA`1VrBb^pGeUA`n`}*EuGAGg9uy?#WT) zNp-<5pRH|Hec0*VXd8+cDGac%$74^ub}emZa{h}@uPQd8MZq+soKJ5SSvoJmb#4&Z zzii=h7SPEfI95S77bdZlL^4so1ia}M3#J95H+*)8qp9X<4~Kb$`(A|^RRayX_XhKM zbj3ZCjfRvCn5%n-1tHVZf)6(|-(G3(*TTn|HVOXSe&xM$4B`47(a_Cjb~WP?a({F~WGOa)##FQUK?!nffI; zDnd^8=82@w%hYoK3ViAuZ9y@;mb4ia>639g6u6q+oMF?1`290w-bI{BB*601MMS=} z*1SVm-XkqDDz0FPe94_Qq9dT;Sy6o$1clz(BzaXb0!hxBC8a{pUgjmVt!S=q*`2-_ zAawB4_O5EweP7^p`~I^BIDA@_`9!Lc5R@$rM-+icliF3O%*txx!((b+RLZ|PhFOgwG1U%Q*6_*ez*8^Uf=2sujlWeM{ zV9D;qQooBUIx^I%EJKE}{kQW!XUcT5AQrWIN}k?%$tu3l+>`vUb?>p%vlg=!S_v+r zM|M#)BZGtbE)2I4+no9m#{0CDZ{%G6{gB^gczVEG- zy0xXD1o%XGab+U|Mp>37YPY+ZpdL#pEEhI>lR6`JuoV&TUR_Qc8x4!}^}V*z@1;Wl zZqKsYFW9dQ9sCNQ=NL-8@N^wmZjdErtkvRe%lSsrKi_UCVN3c6;ByV7WzP=pyiC8b zKqdva)wLS;tFrMIM!D_EJHV(_{YL+e@#p9B@dT06EMdu-wj)CcVfJ?&P5t=vYbVE5^s^LD=ja-Z@E^4jrpjak!m;v z6pLM(KIeVaaknx3?s^SuDK&mz@V;DFiI%=t3|Ys)1lzv5f{haudR&i^e*oN&e@Fl~ ziUTi7OTscZMhZu7{ap|swOlRKWz&2ACs5)3h}ai9m>$)V!AI%%08h>&L?PF?^vah# zxoF*`0=wxu*ZVi$(EEH!4PaY%S{O-g!OfDm4ei=O!ji>>=UWj%IXy;MJz9Wz;YcH>bXS#NAlPuU&bWuBI_i}lI6bG7La-RM61=_+|zdhgQ;gF)bYMSZT~L!=a8b~pA_Ruib{uy)d-iK z5p6nrtVkcN3to6qkf}Eui6-h4<^=@SiL|jnux-=rM!LDAJ}z^|RtnpXH=b%v9U5@) zs)B7#KM}J_!|6!)5_#M9_S@UrcWdNoP|$mO1wewL64kLA-=eEZBEU>XY{b)1F`USvJ=_uN38Wr1O8^nL6MBv3wdjE) zeVYRC6Wkdr7A6BB4}(jM@A+%=(BV&B1wB!V$b>id^g9#;1M}p9mb5-pV@e!(_=)Uyqd5 zxYQ^GI(vE2c0f@Y=BP~bWjHbYb(_|>Sj|d!oR9fC6=D@2VCOkoY1ay6x=`kOLzXMo z+NIKKY$z%j^dOdWWXHUS0DCH~Tu5QB=Dd2m@Q~2uhvBhth=|%I3rr7p=BB$$04qH5 zW;h$Dj_4QQZ6J^;Mx*-H>c2nZ{T9%;%Ze)iR$TLVpR6%7G{j=3R#Gs-iZn);Hq3i&>K{rA9Y7m@cKZIA|5@>1@x|$#jkUGyk)GKZ7>ueP>siOg7K5P`{rhLEdUe1ML>nv|2-^n-%|N z{+i7fN^@z!9JVlot1Jy$9?}iH8WX&v zhyn+69&eUwk;EEQr1XoI3@9L693s(g!PoMSg4Du!Rm}O50oHnxFOrnm=ZIbpg;z^l zqgK#8rqbA70vIoid$PF`nQ)6o+TLKl66YgdVQ_u5Kn8fOkT0tp?2g6Aicok3;2y~I z3KjPNL(dxXb^Gg=Rs;{w;o+%`*`L_02M$QM3Y zL{6?q-c{4ML2st2MKR4!#02Xs6bLhXj;glLf~Wh7e@p~G>295SJ6QO{=2RrMhq5E7 zz(m!1QEm|2wu0qJGvtFSQ>eui4VCB_*#*zh37cnW266I{2|rP$a5V&b(37e@_C)5w zILRzdR3j*HBqJhRSrGuX7nqHByp@AsyS_kiC6ZD%ALC^xT26SGpJB|tkqr)7k+LBP z&aV`Qe)NjPdYz;K!girf5v}9slhM?RKrsxgslr>Aiw&O}(!{BGJMrXA@+B-KHrwz9i!LnP}s0EsGDQ*8)M4zmjn0_93uR)OB#e6MLB!~cXE$}RZNq3-y#l;r}BiC9QQ zQT@^i$&E5)i?vPsegkTko^S90Ot}0lH-Gp$H)z|T#H%g}q50t|*|wfa+y)#Dvx1K< zc2@wc{d}vuytmw$fW4l+tuU_np4)#3fwDu{Q%DK>z+x^zqY|7(23Q<_bUo-$JaE9@ zvZfA`%K+(s6j5Xvqc=ZLuh6wJ6>qvE{`PWFWJ|6@C#?Q`l^McXCJVN+sgcu~?;1osI^hM7yF^cJxAbNPi?5$8~q7EHeVxBn)(a zEI|00ayZY>B((Cfbw&`u&7`Ov)7TTW7{_OxdrGR=pzyro!IeW^uO9c~d6Te+{&|Xa z5Nv26vd8I4O0~9gzPIk&N|$c8SFlvg)PQeE@WuwV7Ed~m&DR!)#)&CAr)J#jL{Q-4 z8uVRkPhC&X)_fm9;6|u^e25|wp|$Ge71^n~4zd*y=e)xhHQ)y;Lqbm9=#3ehJz9-a zIf~mGzkFv+|G8o90@FH=KspP2S44&ed^3Z8*bo)n&}^|u=zl@|`Y*ciHDR@d43`NXpZn6yjG`0qv@tTfnbf~-kapbu-k1-aH~YbNzsu~(oVvCNwb zo*<3U0wW9hj}BJT@B&dO=%VN+F-_G5lgSWiqPS;Sw`MhV`hyikr2yxli;xjhRDKbT z;WF~yu=2;+s=e!&0{uEKF|b6<)VP}P0tX+H-WfrskUFN?&BmCn<^82)(dgz*gvB0C z8)Zw4820eRbIgMjL8IqqKK~Ao+8^Evx72Ui&ZWvVmqbpz&{U#S^z>_s)nt&%c`Ey)lB8P(-_obQ)g@pceo zu&28$nxg%*HjdPL-L?9z+d#VasrIrPPOU=S7nQk8C!-rq8gzAZ&rgQSr1!sPyjQ>2 zrV%#6Aun@+xMxh}#d?#d%*(bmT~A4*#x$u7&D&Ytvv}b|e%T+x`Dx=zs_ewi^A6Ue zC+QQyk$h7xo?kNDIR$U^hF5uQsp0*$#z~|$#bWhoa`>1ZixJ+(a>i^uo8NR$dZ1D# z!c8o+g!xi{egtoQ0*1MUy-IYlr>wswg*-w`+If5!`1MY8OEwdmH77XLT`6MzYhs#8 zQGwy>FJH=ZpyWo2O;;f*0P8JUg=#xi(i&ex)APE%ximn1(BB++67ewf;L?1nZ2tb*^tOFrK10Nbj2J8y8?m>sp|;yemd@<4 zKNt{>^pc;pEe%sEHBpqErhqikHM!@fDq-ZZTrqwRn|u&l`+J`iD3jDYF(eY}jn1D` zY-xn4*DRpnBO}bi8~fB+7q=a-68$&vWOToq`(yo+@e&5_$B6q0qkJ)uPW4`34w;=$ zS+LEaGL}_m@u+xbgy5vy6!8%qoas*=_i|j7bh9Bvi{vdBMa0iKa7#;w?iI`R!hd=e z+^V-(D6c4Nx+SyrZw-64(3-LJC}AU_=A6rHwnQr{6X)e$COteOx9R=HhxQHK-Qm?G zJJ=CCIo!Mj96z0srefX;d6rek4M{UIDmv9K#qOCqW!`yQ&v>OK6V>-((@kBXr`UTq zl6_!fV`Ca8q{NK}hy)^09NhAkJ402La;s61TKYd~ciaygwcupgDW0M$`+cL^hTNIo z)B1KW%K(^8M)YXVQ6#JA<#u0bjj<>By|lXS#H!!nQ4LNrc@;g1BZJ#UpB=h+s)ImX zQ*{yL*(^m;x3o?A><|?dely&lR5i*Ut(zI%5_s^7b2p%Pu3su*oU+1<2&t@S!}MHY z2tW* z!sm!em>v*Oxb)|d!_r$G$9`}fR5x|udV4C>Dq7O8)iwG%*e<8v-f(!)-U(wCqgtsI zg4{|7(X%z|#W#5jdy_ABQ`T=#uu&^exR>3^{aMB^{in>b=L}!GY3|kwM_oLTq4V% z)wWPq&Hd3~pS3oLnJ1Du=gHUKyV!est=@nqdOb@pE^Jf;iw}xkA z<26DT?R%bv`&ix3$-b$SE(5G8pDWFQSL4sFmKC#9xlrh}jZIXqmgTUZ!)3q`?dmrC z1{X)-)k8#`aVsR7T%f*B1ky0}WW^u~!0Ov14q|Ipbzg*>C!<4MFY;A`vkIae9Eo+C z*B#ysli|Bfa2Fq6nK@R62ocT$N4S;!u_#c>uh|LxyvcMhZra29YdSf9fOEZ}z!_Jn z8h=+Oe$Ssu9EnsV4^Ul~ODp_ZjF;~D%MRn<&#Zn4)!2q>VPDj+Y%E*2cT2$wOX6OIRB8KcP@@yLzbv0 z4%S=>_&jiX4d&T-vCH_{${yK(g- zUx#j854AhV6}eLQ#O;wS0(&jp^W#pOqU2g}GY6}8&0zmOgTqfogXWFf1cv6f04;_u za~**8)5+th}Q7 zZmIu9N7H4VAszo^P+O33V9$z4^_tJ+;oX(0U6bn8=wS%ffUtF*Io4KLRfJC&ejF~+ zZM)Ya7Z0kWH~O~HG*3r;3kOpqwAOeCV3{R87DhZ?tyZ$Lf)4*fjGth8UnydD$6L!7 ztqUjDh-USQMl^=a2{&IKH(v3HSGEFM#C$Y)0Bd1)Abv~KY&=1^IjiZP8L;xzC@Nu= zD*4ys>=*>YEqOLJipb<;xPxPsQI>R$rQ0arf1WKTva$xSMH>XtI(C=Qb;y{iMX!?= zU8}7v3&-~jfo|LXXr3xO&}!z22mW6)_dED(o>+cna8q!}jqBfSehM49$U5&)+Y-S! zdd3v{fg=?ON9LF1%8zK+6A`Kx0=JFn5)tsF=7^DxCg|TAbu(N7anY&0FQwX7a{P_y zBpCZo2JDS}xpV%C2y5mGIl4l+AWMTO^#n$fvYRCUCz>C)pnJT5k&WV=+abU9FcxG` zj^lRI@e$!uuIvyea$TRZvgz~C!c&DuYYMJ&lEcp`c32lgtgq{`Tp5Nj6210@p6oW* zUGrtN>CZ_c64FRc&FsC+x<#8r(q{26xuNa@g-Ky2>A=y}QF%me&{jr^?wyL8dz8K3 zG}6ks9h9)WMcQ~kT}qYxmZUko1ID3$Cwa$Btznw!%e+|Oyawt^NA-}qNcZYZGNMVz>ondn%e#Dk)u8L3Sj^p`Pk-n-BfFmT=lM1VXa@n<2H9~ za8S<%J~9U-IPZJR8NKCiRwEm@JV1N><6dHM?IYFU@|m;Q7O~y9_juXjsS73NFKl3)rr-XLRlUV5dDdEa0Q0McyubxqdX;q9txmaLI0i5~FS zYpUFeg=MLMDGAy#E^{xoA^drtJyKw5+9;xu2Lia=jOrF9g7x1vup}Ez% zDGXZ5F&Y_fCbsmBjjZLirS8s#7vcO3$iz;|p6UwrrKKef@0@~tlC_me?T*Is;$oQb z*L5H<$dOCereY=IF4aNs>d9i)isX*BNHS_^>>c~iQITV^=i;1Is+_xqb&{Sts!Jl6OGwjD3HKkKvJ zbSu8B9R`(uKc&ZL=*K*k{#i;N_{+Px5=MD4-N;$mWmSl4WQCE2k6vs3?# z*Gg2ZrIbHqGCT;*r0x0()EMm~?rHV!^q{229vC0?P;GNNaL!#Z_BTdNCE~X1em`(SHNurO<@9!+jjm6L#OX?LAuRF*DvqXY5W5N9+c};J0 zkvr1CWi(uuny138C|c%y9+R4mR&y9K%EM@BtNVf-Mp9IS#F{UV1-cwDs-fxEi8=IpjZjetb9%G zwY=NFmFz2)Do0m3I5Dn~meTyfc-?bdBb7O$${6YQ^kNdd%ElypjhXZP&b_B2iEOEe z7t1vQ6^vzaD{~9aTqpMTQxz3@%Y8hS3%4@;>odxSXrPu>g_+HYxD60|yb`%9$%}7P zfWAA{&_6cEQlD8RYYPz$7!}6{x-s1H>3w!mE7^km{kj(w>};rYVSKYcP)k2rhq?wB zxPIBTpX?U072CGN#nG^yq(Br(G%ny1pZHZYzC!B{fd9C>qX&Oc;kRa|R z1nFMx9Tcf3CJT0O{%l{jwCtm7BlBkMM{jkZeC_i)s+e-h5(pe9xc**QGVvq7@U(2^%#Y<-ew8_7 zHr%f%KP!eGd9R{2nN^B4uje#$%-boS-cy%;39r&p;%G)>B|F4bzy7JC2qW&M zufMZY@Y$=x<@kL>QFrAm(TYXdR+PE92Vwk8vrR(-e;5mNeL^ZY z_WB5QnSQMw4tw>Yd}O1_)Z>O3>0Gl^6X6~E5FGReW_}ahIO-F-7o|0;Jd zU_}H^4u!KuyD-=QVS6L>*jyW9zRk$c2}dcmxz{y)*P&t^Fryi^d;_$8iKMyYC!>LZ zbndx;x#9ps7T5fD4%GxbA5ir&DCH|iQ*P4ho||vY=)VeF^U!r-VFvhBgeg%8Jes@Seya&-(Q*%eAqOdkx^@G7iU>{p!fs@xv55q!gfcE%AiW{(BSWfXz+g~Q(DoAs1 zS=&W2()Lt5!EMgEA17^3P$!t_by;v!BvCFb#`DaDFZdy}Hz1xeMCt?9)dC57Rq1Z*_4Z0W}=%%dOEqkT>RypdeCR3PH^ z?0T5$K~e12*Nl}mRn?*yW8=|1M~03<>X)wefL#{6vC1)c{PFl>LB$jI$aghKh>aRV z++yf#!P3x^kl7LsmL9K5%3%8dN&+S8Wp(eCJ@0!LtLgR3lcN1*r9XbGb-i&F_t)=MQ z_F0{ojJY3JP`BR3kbP{ERfzWTu45pjAH7TOnMwdxu7^o_*oM^^8PIw3gWYWkB^ms& zJ%Q*9#|SdpU$c0}ipy!I!zBsNgo}hHPkMd&P;?!)W-wdQZ0~C=8ZcoTaB<3v>8X~s z!lISNwOPla8vZ1qVr2QeKl>C%*)htZN%_uJDm`xLjA-@<`zw}~=U8JJX0HrfF@(Sw z+|aQ%M*Qm}nR299Li-O`P0`L`rqaFRh1=|5i5=Gp6};9>lXGin_v8ZKx0SjrUvu7W zxe%t*5)JIRj&}h~4njFzpI2$02wij1IObxnj6Bs3-Ndb&%@-tI zq~m5a_9=>$fes-9xaKuoJGh`OG)IW9T%;?rjZB3l-`Z$2u6T#e&it-3->e71^YldF@;X=XhbY40N_Y#IxRr3U~)shlKlfa!pVEo;Qjl~3sAtg=ib zP0^u~e^9>cKcmv?5q^E^v2U6PcJ-yS-zSkEfb7j}bPoVbVj1t^I^@rw1J{a$ug6;} z(PvnT&gouPZTBcTt62Em*9X@(ZOc^@r&wn`n|pH~+_udx*(kaG7PwwZ33mMI%6wJd zR6EE&J9ptn`a?U%IwQBTD@C0fUcNq8D4Y#5nJS`KlLPdu&BC=GCrXQje|QNGokXM( zd0M<;>4wmts4i=V| zI9oWE#7g*j0=3zfS-LC%#2G1u2COH~2|2a|jB+M_0sP@Zz9@Q6eUA<&X7`tqR7SFU zc__0#J$8;&8(CkoBhwQAc$p@lL*8$6GV2EeK)@z=b235DpXXi{Sl09HpWc|@@{+!@ zJR~9bi+1iamDBRsJt6>fBFz|;KC?CSWH+l0=zgc~f9 z6J>mEZFz>xMhu+dI?j^b@QLPYnZ#aO+K1FN(?qogT&F1fHn$T;Ss^&gYv7urmVN#`?S#8^Hwk$k77Oo@n3q@jUs9%|+Z$Bx+Z3zh zdCv5It-X+KF=Me$zFQjhW~Li)Mw_#N0>E}Sl3H9&;M$MwFfThhGmLv_&nH$#R*lCs z1=V@`vg(Iltx>Xd%Vp1`9)4sVQ<~dSaz|4(2?Msv+T*1l?1MWFr5hU|lk~kD-96Q} zzn2noQgYlLT&vjML9lgB!U^wq8h4-z8ISoug{PnZ@?+u`9Z@w1!t zu>+j0mv};szByxaL}FpzDMND*%sW@=u>L9pJDuOX6xS;Zlqpp~ufJl8l#>?83f7CQ zKrhPTdeqqG2!F>b_M}a2EiMPD`Hn{EE_r3a1Dqs=Sy~d^YEI!?4CT1G7Q`w)8l3V5 znn0M3lEkGiGyPVB z5_w5e&ceK4|4e@5i?!Xlv9~X_xCe=jc;wO!tgqzV9+52TW80 z>dwE(<+W!-T^sogHXCwgQ7D2F?)q2|X5sSraK3Qt-8**@yLDARrd9+DDL2FxPIa%X zMDQ()JVVteTwU*@U{SZt^xH4`D;I61MOLh0!Aa*>x!A}T;}dC-qngoMgKI=|6w6e< z@nyZCdnM;w{vB56gWha{ZJ6C;mCY8#`qT`3fU3Nv427^DydcoF8qUxiFLi5;$O--7 z=&uCoa28%#MlNl6e_0O!0N^=MEGyh55=3RtsI7`r5S}+w9=qIGHL|n0V#7bT)bqth z*>(3WHD7I1=k?MPPylu!!OPP#v$9sc&|Bb#DRP{-n#}03G28hI6B=o|tK6${%FJ@M z*Ag((=WQV*7C(8VUUNUHX1|)e^B$vzH5XLmy*Kb7pvg=q`)`xl5BA#W72W2u%Nj~+ z0LEyj-pkUEQ^}YL|4(tXlN*iVIpYa}E6`*Hy~on>zAE&1Y>#K2T7*qlbX}a&W>!26 zpmG7U@0M(S`%sdUV8&&_lY~F+gvL&rEEZW4)?csEB0L5>k)y0hu4M&ngil^PLgaoN z!ssellMa@|m_xA5x3eF#UR~$w=Wh9&O%ql2j_0^v-TK2RT|i~LC1Cls*C!Ht+Wk+#3#kkMWL(R3 zxLq_DQ|g`EAw`P~9OJJEbH@av1*$Os&JH?zk1wAlJku}Nlz+!0+7p}&sal)*n9^!TEV=(6fc(jCQx}&i>gyFj}R&X z6>Xkw&h#&)k+%7-MkgiQ`JneH|Kjn${^^L|YY1DDF@_^xS+j6IApFL+#_-fYWM?tR zP#06|X_GquDV*zH{8;MofT~lL^(H<3xV%ihj5cr#E!3rRjnHlzedR!Yc)c0*=OIXRO=i+m zvl%sjjfA(^Dxx@smu@C4&*Y%EL6;S#a9++uHLYZD3(u6VMeD$s0;2MOky$e6yyL)ikUV2}$V(T$1%nrtN?P@gY*IO^FicB}G?Zsu^!mYRAG{N6rDwE92&^6XOtr5Pbl zCysyrQqV%tiHBy!lIADJd(BT5KnuezcfI!lH12Snf+ekT1xRk@fT~RtP!*$FesneN zy=Slx+W#k3n-!P_&8PZb>a-iu{~q~z|f(z}X16Ub=?EabfS;B9zX5mE87LQ7P# zbkB$fQ0hZ7uxUcas zKrF_$B!0UFBzFDtz^AfyEP}j`sJ}NK{b4Wz3L9%WbhLn(6g|XX1n8a!umpEm4PBL# z;PeMvSgawTEF>R#v7f$73T0ra@A%LK2HN0m6EE?$z2uh)@<8nDA5#c&!^b zcd6fwi!@!q8W>iYyQ9J5FLG5%0AZbg>!yGUJ{o^US^e?#!4=R$<2|9T{>>vG@j9|| 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 SnEx36$Vw?m7C(FW_WuB-d+}=k literal 0 HcmV?d00001 diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index d811540383d..89956eb1325 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -6843,6 +6843,8 @@ boost::bimaps::bimap DeviceManager::get_all_model_id_w } for (wxString file : m_files) { + if (!file.Lower().ends_with(".json")) continue; + std::string config_file = Slic3r::resources_dir() + "/printers/" + file.ToStdString(); boost::nowide::ifstream json_file(config_file.c_str()); From 5246fc4c0cd55f64c8c47d6e6e27069a1ba97b09 Mon Sep 17 00:00:00 2001 From: tao wang Date: Wed, 8 Jan 2025 16:20:59 +0800 Subject: [PATCH 106/127] ENH:fet the correct Agora status jira:[none] Change-Id: Ic779e41f0b652212aa8e4ce016cfe1ef2aba3608 (cherry picked from commit 1c1b366d0035298b387fbeb3a7ee69ef4afb8e2d) --- src/slic3r/GUI/DeviceManager.cpp | 19 +++++++++++++++---- src/slic3r/GUI/DeviceManager.hpp | 3 +++ src/slic3r/GUI/MediaFilePanel.cpp | 2 +- src/slic3r/GUI/MediaPlayCtrl.cpp | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 89956eb1325..8b50aa61140 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1640,6 +1640,21 @@ bool MachineObject::is_recording() return camera_recording; } +int MachineObject::get_liveview_remote() +{ + if (is_support_agora) { + liveview_remote == LVR_None ? LVR_Agora : liveview_remote == LVR_Tutk ? LVR_TutkAgora : liveview_remote; + } + return liveview_remote; +} + +int MachineObject::get_file_remote() +{ + if (is_support_agora) + file_remote = file_remote == FR_None ? FR_Agora : file_remote == FR_Tutk ? FR_TutkAgora : file_remote; + return file_remote; +} + std::string MachineObject::parse_version() { auto ota_version = module_vers.find("ota"); @@ -3906,16 +3921,12 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) liveview_local = enum_index_of(ipcam["liveview"].value("local", "none").c_str(), local_protos, 5, LiveviewLocal::LVL_None); char const *remote_protos[] = {"none", "tutk", "agora", "tutk_agaro"}; liveview_remote = enum_index_of(ipcam["liveview"].value("remote", "none").c_str(), remote_protos, 4, LiveviewRemote::LVR_None); - if (is_support_agora) - liveview_remote = liveview_remote == LVR_None ? LVR_Agora : liveview_remote == LVR_Tutk ? LVR_TutkAgora : liveview_remote; } if (ipcam.contains("file")) { char const *local_protos[] = {"none", "local"}; file_local = enum_index_of(ipcam["file"].value("local", "none").c_str(), local_protos, 2, FileLocal::FL_None); char const *remote_protos[] = {"none", "tutk", "agora", "tutk_agaro"}; file_remote = enum_index_of(ipcam["file"].value("remote", "none").c_str(), remote_protos, 4, FileRemote::FR_None); - if (is_support_agora) - file_remote = file_remote == FR_None ? FR_Agora : file_remote == FR_Tutk ? FR_TutkAgora : file_remote; file_model_download = ipcam["file"].value("model_download", "disabled") == "enabled"; } virtual_camera = ipcam.value("virtual_camera", "disabled") == "enabled"; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 15ace5001f5..1e3947c5487 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -918,6 +918,9 @@ class MachineObject bool is_recording(); + int get_liveview_remote(); + int get_file_remote(); + MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip); ~MachineObject(); diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index c62307dbb5c..bd713a3b690 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -222,7 +222,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) m_device_busy = obj->is_camera_busy_off(); m_sdcard_exist = obj->has_sdcard(); m_local_proto = obj->file_local; - m_remote_proto = obj->file_remote; + m_remote_proto = obj->get_file_remote(); m_model_download_support = obj->file_model_download; } else { m_lan_mode = false; diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp index 92367a5975e..47f19e55391 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.cpp +++ b/src/slic3r/GUI/MediaPlayCtrl.cpp @@ -150,7 +150,7 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj) m_dev_ver = obj->get_ota_version(); m_lan_mode = obj->is_lan_mode_printer(); m_lan_proto = obj->liveview_local; - m_remote_proto = obj->liveview_remote; + m_remote_proto = obj->get_liveview_remote(); m_lan_ip = obj->dev_ip; m_lan_passwd = obj->get_access_code(); m_device_busy = obj->is_camera_busy_off(); From 062d922beb0d0bcc4c33160d4e48be4b2feef4e4 Mon Sep 17 00:00:00 2001 From: "chunmao.guo" Date: Mon, 20 Jan 2025 11:08:00 +0800 Subject: [PATCH 107/127] FIX: liveview_remote protocol missing agora Change-Id: If3a46c67e139e3abc47dc672e32246eb6b59f9fd Jira: STUDIO-10041 (cherry picked from commit 71d9d8969e4bf502adaa56f165fc857be7fe6f5a) --- src/slic3r/GUI/DeviceManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 8b50aa61140..fff8ef10d49 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1643,7 +1643,7 @@ bool MachineObject::is_recording() int MachineObject::get_liveview_remote() { if (is_support_agora) { - liveview_remote == LVR_None ? LVR_Agora : liveview_remote == LVR_Tutk ? LVR_TutkAgora : liveview_remote; + return liveview_remote == LVR_None ? LVR_Agora : liveview_remote == LVR_Tutk ? LVR_TutkAgora : liveview_remote; } return liveview_remote; } From add22fb69500ca5ec0e81703039e2e7815bd10a2 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Wed, 8 Jan 2025 16:19:52 +0800 Subject: [PATCH 108/127] FIX: update the images jira: [STUDIO-9581] Change-Id: I1cea4547d9b436ca29932d0d5724dedf42eadc8f (cherry picked from commit 09a6a3695be229f655adbb10b820134d4922479e) --- resources/images/air_pump.svg | 396 ++++++++++++++++++++++++++++++++ src/slic3r/GUI/UpgradePanel.cpp | 9 +- src/slic3r/GUI/UpgradePanel.hpp | 2 +- 3 files changed, 402 insertions(+), 5 deletions(-) create mode 100644 resources/images/air_pump.svg diff --git a/resources/images/air_pump.svg b/resources/images/air_pump.svg new file mode 100644 index 00000000000..799588ec2e1 --- /dev/null +++ b/resources/images/air_pump.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index c8463dedb7c..32b44dec722 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -414,7 +414,7 @@ void MachineInfoPanel::init_bitmaps() m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); } - m_img_air_pump = ScalableBitmap(this, "printer_thumbnail", 160);/*TODO: replace the bitmap*/ + m_img_air_pump = ScalableBitmap(this, "air_pump", 160); m_img_laser = ScalableBitmap(this, "laser", 160); m_img_cutting = ScalableBitmap(this, "cut", 160); @@ -446,7 +446,7 @@ MachineInfoPanel::~MachineInfoPanel() delete confirm_dlg; } -void MachineInfoPanel::Update_printer_img(MachineObject* obj) +void MachineInfoPanel::update_printer_imgs(MachineObject* obj) { if (!obj) {return;} auto img = obj->get_printer_thumbnail_img_str(); @@ -458,6 +458,7 @@ void MachineInfoPanel::Update_printer_img(MachineObject* obj) m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); } + m_img_printer = ScalableBitmap(this, img, 160); m_printer_img->SetBitmap(m_img_printer.bmp()); m_printer_img->Refresh(); @@ -469,7 +470,7 @@ void MachineInfoPanel::Update_printer_img(MachineObject* obj) void MachineInfoPanel::update(MachineObject* obj) { if (m_obj != obj) - Update_printer_img(obj); + update_printer_imgs(obj); m_obj = obj; if (obj) { @@ -1147,7 +1148,7 @@ void MachineInfoPanel::show_laszer(bool show) void MachineInfoPanel::on_sys_color_changed() { if (m_obj) { - Update_printer_img(m_obj); + update_printer_imgs(m_obj); } } diff --git a/src/slic3r/GUI/UpgradePanel.hpp b/src/slic3r/GUI/UpgradePanel.hpp index 2028505f465..7e9c84c8010 100644 --- a/src/slic3r/GUI/UpgradePanel.hpp +++ b/src/slic3r/GUI/UpgradePanel.hpp @@ -163,7 +163,7 @@ class MachineInfoPanel : public wxPanel ~MachineInfoPanel(); void on_sys_color_changed(); - void Update_printer_img(MachineObject* obj); + void update_printer_imgs(MachineObject* obj); void init_bitmaps(); void rescale_bitmaps(); From f970bf81603f573c35acdd727f70bd2964eb6393 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Thu, 9 Jan 2025 15:05:18 +0800 Subject: [PATCH 109/127] FIX: add some dark mode images jira: [STUDIO-9654] Change-Id: I89c8efcd95e7b326c4e9ecff76a10c1813e018ea (cherry picked from commit 10ea0696c613340cc54e3245678e7e4605d19f4f) --- resources/images/air_pump_dark.svg | 396 +++++++++++++++++++++++++++++ src/slic3r/GUI/UpgradePanel.cpp | 3 +- 2 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 resources/images/air_pump_dark.svg diff --git a/resources/images/air_pump_dark.svg b/resources/images/air_pump_dark.svg new file mode 100644 index 00000000000..2f075c21321 --- /dev/null +++ b/resources/images/air_pump_dark.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/slic3r/GUI/UpgradePanel.cpp b/src/slic3r/GUI/UpgradePanel.cpp index 32b44dec722..7d16cbc3a1a 100644 --- a/src/slic3r/GUI/UpgradePanel.cpp +++ b/src/slic3r/GUI/UpgradePanel.cpp @@ -408,13 +408,14 @@ void MachineInfoPanel::init_bitmaps() m_img_monitor_ams = ScalableBitmap(this, "monitor_upgrade_ams", 200); m_img_ext = ScalableBitmap(this, "monitor_upgrade_ext", 200); if (wxGetApp().dark_mode()) { + m_img_air_pump = ScalableBitmap(this, "air_pump_dark", 160); m_img_extra_ams = ScalableBitmap(this, "extra_icon_dark", 160); } else { + m_img_air_pump = ScalableBitmap(this, "air_pump", 160); m_img_extra_ams = ScalableBitmap(this, "extra_icon", 160); } - m_img_air_pump = ScalableBitmap(this, "air_pump", 160); m_img_laser = ScalableBitmap(this, "laser", 160); m_img_cutting = ScalableBitmap(this, "cut", 160); From 54748aee1c629b5178f0969f95358a3758cc8707 Mon Sep 17 00:00:00 2001 From: tao wang Date: Fri, 29 Nov 2024 19:31:06 +0800 Subject: [PATCH 110/127] ENH:Support more SD card states jira:[for sdcard] Change-Id: Ic09198a0ed357f827768ed2f8d8a9ed6266f749f (cherry picked from commit c877405caba2b75c515c814b7aaa0793200eee04) --- src/slic3r/GUI/DeviceManager.cpp | 34 +++++++++---------------- src/slic3r/GUI/DeviceManager.hpp | 4 +-- src/slic3r/GUI/MediaFilePanel.cpp | 30 +++++++++++----------- src/slic3r/GUI/Monitor.cpp | 24 ++++++++--------- src/slic3r/GUI/SelectMachine.cpp | 2 +- src/slic3r/GUI/SendMultiMachinePage.cpp | 2 +- src/slic3r/GUI/SendToPrinter.cpp | 20 +++++++-------- src/slic3r/GUI/StatusPanel.cpp | 10 ++++---- src/slic3r/Utils/CalibUtils.cpp | 2 +- 9 files changed, 59 insertions(+), 69 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index fff8ef10d49..5213a87587e 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1513,6 +1513,8 @@ void MachineObject::parse_status(int flag) camera_recording = ((flag >> 5) & 0x1) != 0; ams_calibrate_remain_flag = ((flag >> 7) & 0x1) != 0; + sdcard_state = MachineObject::SdcardState(get_flag_bits(flag, 8, 2)); + if (ams_print_option_count > 0) ams_print_option_count--; else { @@ -1565,8 +1567,6 @@ void MachineObject::parse_status(int flag) is_support_upgrade_kit = ((flag >> 27) & 0x1) != 0; installed_upgrade_kit = ((flag >> 26) & 0x1) != 0; - sdcard_state = MachineObject::SdcardState((flag >> 8) & 0x11); - is_support_agora = ((flag >> 30) & 0x1) != 0; if (is_support_agora) is_support_tunnel_mqtt = false; @@ -1615,11 +1615,6 @@ bool MachineObject::is_sdcard_printing() return false; } -bool MachineObject::has_sdcard() -{ - return (sdcard_state == MachineObject::SdcardState::HAS_SDCARD_NORMAL); -} - MachineObject::SdcardState MachineObject::get_sdcard_state() { return sdcard_state; @@ -3358,6 +3353,16 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) if (jj["print_error"].is_number()) print_error = jj["print_error"].get(); } + + if (jj.contains("sdcard")) { + if (jj["sdcard"].get()) + sdcard_state = MachineObject::SdcardState::HAS_SDCARD_NORMAL; + else + sdcard_state = MachineObject::SdcardState::NO_SDCARD; + } else { + sdcard_state = MachineObject::SdcardState::NO_SDCARD; + } + if (!key_field_only) { if (jj.contains("home_flag")) { home_flag = jj["home_flag"].get(); @@ -3703,21 +3708,6 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) catch (...) { ; } - // media - try { - if (jj.contains("sdcard")) { - if (jj["sdcard"].get()) - sdcard_state = MachineObject::SdcardState::HAS_SDCARD_NORMAL; - else - sdcard_state = MachineObject::SdcardState::NO_SDCARD; - } else { - //do not check sdcard if no sdcard field - sdcard_state = MachineObject::SdcardState::NO_SDCARD; - } - } - catch (...) { - ; - } } #pragma endregion if (!key_field_only) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 1e3947c5487..49fcc9f350a 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -469,7 +469,8 @@ class MachineObject NO_SDCARD = 0, HAS_SDCARD_NORMAL = 1, HAS_SDCARD_ABNORMAL = 2, - SDCARD_STATE_NUM = 3 + HAS_SDCARD_READONLY = 3, + SDCARD_STATE_NUM = 4 }; enum ActiveState { @@ -912,7 +913,6 @@ class MachineObject std::string obj_subtask_id; // subtask_id == 0 for sdcard std::string subtask_name; bool is_sdcard_printing(); - bool has_sdcard(); bool is_timelapse(); bool is_recording_enable(); bool is_recording(); diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index bd713a3b690..6ac7f89308c 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -71,7 +71,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent) // File type StateColor background( std::make_pair(0xEEEEEE, (int) StateColor::Checked), - std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered), + std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered), std::make_pair(*wxWHITE, (int) StateColor::Normal)); m_type_panel = new ::StaticBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); m_type_panel->SetBackgroundColor(*wxWHITE); @@ -220,7 +220,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) m_lan_passwd = obj->get_access_code(); m_dev_ver = obj->get_ota_version(); m_device_busy = obj->is_camera_busy_off(); - m_sdcard_exist = obj->has_sdcard(); + m_sdcard_exist = obj->sdcard_state == MachineObject::SdcardState::HAS_SDCARD_NORMAL || obj->sdcard_state == MachineObject::SdcardState::HAS_SDCARD_READONLY; m_local_proto = obj->file_local; m_remote_proto = obj->get_file_remote(); m_model_download_support = obj->file_model_download; @@ -326,7 +326,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) CallAfter([this, m = e.GetString()] { MessageDialog(this, m, _L("Download failed"), wxOK | wxICON_ERROR).ShowModal(); }); - + NetworkAgent* agent = wxGetApp().getAgent(); if (result > 1 || result == 0) { json j; @@ -518,16 +518,16 @@ void MediaFilePanel::doAction(size_t index, int action) auto fs = m_image_grid->GetFileSystem(); if (action == 0) { if (index == -1) { - MessageDialog dlg(this, + MessageDialog dlg(this, wxString::Format(_L_PLURAL("You are going to delete %u file from printer. Are you sure to continue?", "You are going to delete %u files from printer. Are you sure to continue?", fs->GetSelectCount()), - fs->GetSelectCount()), + fs->GetSelectCount()), _L("Delete files"), wxYES_NO | wxICON_WARNING); if (dlg.ShowModal() != wxID_YES) return; } else { - MessageDialog dlg(this, - wxString::Format(_L("Do you want to delete the file '%s' from printer?"), from_u8(fs->GetFile(index).name)), + MessageDialog dlg(this, + wxString::Format(_L("Do you want to delete the file '%s' from printer?"), from_u8(fs->GetFile(index).name)), _L("Delete file"), wxYES_NO | wxICON_WARNING); if (dlg.ShowModal() != wxID_YES) return; @@ -557,13 +557,13 @@ void MediaFilePanel::doAction(size_t index, int action) std::istringstream is(data); if (!Slic3r::load_gcode_3mf_from_stream(is, &config, &model, &plate_data_list, &file_version) || plate_data_list.empty()) { - MessageDialog(this, - _L("Failed to parse model information."), + MessageDialog(this, + _L("Failed to parse model information."), _L("Print"), wxOK).ShowModal(); return; } - + auto &file = fs->GetFile(index); std::string file_path = file.path; @@ -581,7 +581,7 @@ void MediaFilePanel::doAction(size_t index, int action) wxEmptyString, wxICON_WARNING | wxOK); auto res = dlg.ShowModal(); } - + }); return; } @@ -591,8 +591,8 @@ void MediaFilePanel::doAction(size_t index, int action) if (file.IsDownload() && file.DownloadProgress() >= -1) { if (!file.local_path.empty()) { if (!fs->DownloadCheckFile(index)) { - MessageDialog(this, - wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), + MessageDialog(this, + wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), _L("Error"), wxOK).ShowModal(); Refresh(); return; @@ -617,8 +617,8 @@ void MediaFilePanel::doAction(size_t index, int action) if (file.IsDownload() && file.DownloadProgress() >= -1) { if (!file.local_path.empty()) { if (!fs->DownloadCheckFile(index)) { - MessageDialog(this, - wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), + MessageDialog(this, + wxString::Format(_L("File '%s' was lost! Please download it again."), from_u8(file.name)), _L("Error"), wxOK).ShowModal(); Refresh(); return; diff --git a/src/slic3r/GUI/Monitor.cpp b/src/slic3r/GUI/Monitor.cpp index 00aacf2f8cc..c1d04744ddf 100644 --- a/src/slic3r/GUI/Monitor.cpp +++ b/src/slic3r/GUI/Monitor.cpp @@ -181,7 +181,7 @@ MonitorPanel::~MonitorPanel() auto page = m_tabpanel->GetCurrentPage(); if (page == m_media_file_panel) { auto title = m_tabpanel->GetPageText(m_tabpanel->GetSelection()); - m_media_file_panel->SwitchStorage(title == _L("SD Card")); + m_media_file_panel->SwitchStorage(title == _L("Storage")); } page->SetFocus(); }, m_tabpanel->GetId()); @@ -191,7 +191,7 @@ MonitorPanel::~MonitorPanel() m_tabpanel->AddPage(m_status_info_panel, _L("Status"), "", true); m_media_file_panel = new MediaFilePanel(m_tabpanel); - m_tabpanel->AddPage(m_media_file_panel, _L("SD Card"), "", false); + m_tabpanel->AddPage(m_media_file_panel, _L("Storage"), "", false); //m_tabpanel->AddPage(m_media_file_panel, _L("Internal Storage"), "", false); m_upgrade_panel = new UpgradePanel(m_tabpanel); @@ -376,7 +376,7 @@ void MonitorPanel::update_all() m_status_info_panel->m_media_play_ctrl->SetMachineObject(obj); m_media_file_panel->SetMachineObject(obj); m_side_tools->update_status(obj); - + if (!obj) { show_status((int)MONITOR_NO_PRINTER); m_hms_panel->clear_hms_tag(); @@ -454,7 +454,7 @@ bool MonitorPanel::Show(bool show) if (obj == nullptr) { dev->load_last_machine(); obj = dev->get_selected_machine(); - if (obj) + if (obj) GUI::wxGetApp().sidebar().load_ams_list(obj->dev_id, obj); } else { obj->reset_update_time(); @@ -503,7 +503,7 @@ void MonitorPanel::show_status(int status) BOOST_LOG_TRIVIAL(info) << "monitor: show_status = " << status; - + #if !BBL_RELEASE_TO_PUBLIC m_upgrade_panel->update(nullptr); #endif @@ -518,15 +518,15 @@ Freeze(); if ((status & (int)MonitorStatus::MONITOR_NO_PRINTER) != 0) { set_default(); m_tabpanel->Layout(); - } else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0) - || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0) - || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) - || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0) ) + } else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0) + || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0) + || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) + || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0) ) { - if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0) - || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) - || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0)) + if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0) + || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) + || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0)) { set_default(); } diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 6151706deb2..b77a50893b2 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3021,7 +3021,7 @@ void SelectMachineDialog::on_send_print() BOOST_LOG_TRIVIAL(error) << "build_nozzle_info errors"; } - m_print_job->has_sdcard = obj_->has_sdcard(); + m_print_job->has_sdcard = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL; bool timelapse_option = select_timelapse->IsShown() ? m_checkbox_list["timelapse"]->GetValue() : true; diff --git a/src/slic3r/GUI/SendMultiMachinePage.cpp b/src/slic3r/GUI/SendMultiMachinePage.cpp index 3c5d1d19ed3..c05b77fa3ef 100644 --- a/src/slic3r/GUI/SendMultiMachinePage.cpp +++ b/src/slic3r/GUI/SendMultiMachinePage.cpp @@ -568,7 +568,7 @@ BBL::PrintParams SendMultiMachinePage::request_params(MachineObject* obj) params.comments = "no_ip"; else if (obj->is_support_cloud_print_only) params.comments = "low_version"; - else if (!obj->has_sdcard()) + else if (obj->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) params.comments = "no_sdcard"; else if (params.password.empty()) params.comments = "no_password"; diff --git a/src/slic3r/GUI/SendToPrinter.cpp b/src/slic3r/GUI/SendToPrinter.cpp index 7d0fb5663cd..180a7e8beed 100644 --- a/src/slic3r/GUI/SendToPrinter.cpp +++ b/src/slic3r/GUI/SendToPrinter.cpp @@ -201,7 +201,7 @@ SendToPrinterDialog::SendToPrinterDialog(Plater *plater) m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); m_scrollable_region = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); - m_sizer_scrollable_region = new wxBoxSizer(wxVERTICAL); + m_sizer_scrollable_region = new wxBoxSizer(wxVERTICAL); m_panel_image = new wxPanel(m_scrollable_region, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); m_panel_image->SetBackgroundColour(m_colour_def_color); @@ -613,7 +613,7 @@ void SendToPrinterDialog::prepare(int print_plate_idx) m_print_plate_idx = print_plate_idx; } -void SendToPrinterDialog::update_priner_status_msg(wxString msg, bool is_warning) +void SendToPrinterDialog::update_priner_status_msg(wxString msg, bool is_warning) { auto colour = is_warning ? wxColour(0xFF, 0x6F, 0x00) : wxColour(0x6B, 0x6B, 0x6B); m_statictext_printer_msg->SetForegroundColour(colour); @@ -675,7 +675,7 @@ void SendToPrinterDialog::on_cancel(wxCloseEvent &event) m_worker->cancel_all(); this->EndModal(wxID_CANCEL); } - + void SendToPrinterDialog::on_ok(wxCommandEvent &event) { BOOST_LOG_TRIVIAL(info) << "print_job: on_ok to send"; @@ -693,7 +693,7 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) if (!dev) return; MachineObject *obj_ = dev->get_selected_machine(); - + if (obj_ == nullptr) { m_printer_last_select = ""; m_comboBox_printer->SetTextLabel(""); @@ -764,7 +764,7 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) fs::path default_output_file_path = boost::filesystem::path(default_output_file.c_str()); file_name = default_output_file_path.filename().string(); }*/ - + auto m_send_job = std::make_unique(m_printer_last_select); @@ -782,9 +782,9 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event) m_send_job->connection_type = obj_->connection_type(); m_send_job->cloud_print_only = true; - m_send_job->has_sdcard = obj_->has_sdcard(); + m_send_job->has_sdcard = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL; m_send_job->set_project_name(m_current_project_name.utf8_string()); - + enable_prepare_mode = false; m_send_job->on_check_ip_address_fail([this](int result) { @@ -1289,7 +1289,7 @@ void SendToPrinterDialog::set_default() m_comboBox_printer->Enable(); // rset status bar m_status_bar->reset(); - + NetworkAgent* agent = wxGetApp().getAgent(); if (agent) { if (agent->is_user_login()) { @@ -1316,7 +1316,7 @@ void SendToPrinterDialog::set_default() image = image.Rescale(FromDIP(256), FromDIP(256)); m_thumbnailPanel->set_thumbnail(image); } - + std::vector materials; std::vector display_materials; { @@ -1338,7 +1338,7 @@ void SendToPrinterDialog::set_default() Layout(); Fit(); - + wxSize screenSize = wxGetDisplaySize(); auto dialogSize = this->GetSize(); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index c57ca721d92..b5424e6a407 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -1026,7 +1026,7 @@ wxBoxSizer *StatusBasePanel::create_monitoring_page() }); m_camera_switch_button->Hide(); - m_bitmap_sdcard_img->SetToolTip(_L("SD Card")); + m_bitmap_sdcard_img->SetToolTip(_L("Storage")); m_bitmap_timelapse_img->SetToolTip(_L("Timelapse")); m_bitmap_recording_img->SetToolTip(_L("Video")); m_bitmap_vcamera_img->SetToolTip(_L("Go Live")); @@ -1635,16 +1635,16 @@ void StatusPanel::update_camera_state(MachineObject* obj) if (m_last_sdcard != (int)obj->get_sdcard_state()) { if (obj->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) { m_bitmap_sdcard_img->SetBitmap(m_bitmap_sdcard_state_no.bmp()); - m_bitmap_sdcard_img->SetToolTip(_L("No SD Card")); + m_bitmap_sdcard_img->SetToolTip(_L("No Storage")); } else if (obj->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL) { m_bitmap_sdcard_img->SetBitmap(m_bitmap_sdcard_state_normal.bmp()); - m_bitmap_sdcard_img->SetToolTip(_L("SD Card")); + m_bitmap_sdcard_img->SetToolTip(_L("Storage")); } else if (obj->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_ABNORMAL) { m_bitmap_sdcard_img->SetBitmap(m_bitmap_sdcard_state_abnormal.bmp()); - m_bitmap_sdcard_img->SetToolTip(_L("SD Card Abnormal")); + m_bitmap_sdcard_img->SetToolTip(_L("Storage Abnormal")); } else { m_bitmap_sdcard_img->SetBitmap(m_bitmap_sdcard_state_normal.bmp()); - m_bitmap_sdcard_img->SetToolTip(_L("SD Card")); + m_bitmap_sdcard_img->SetToolTip(_L("Storage")); } m_last_sdcard = (int)obj->get_sdcard_state(); } diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index c0629fa2f39..1f74c536306 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -1232,7 +1232,7 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess print_job->m_project_name = get_calib_mode_name(cali_mode, flow_ratio_mode); print_job->set_calibration_task(true); - print_job->has_sdcard = obj_->has_sdcard(); + print_job->has_sdcard = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL; print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true, 0, 0, 0); print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name); From 06cc09b62a23b01bf512c288fef6893c665b7521 Mon Sep 17 00:00:00 2001 From: "chunmao.guo" Date: Thu, 28 Nov 2024 12:17:38 +0800 Subject: [PATCH 111/127] FIX: wxMediaCtrl2 on macOS error code JIRA: STUDIO-8945 Change-Id: I03d6f7bcb7f3032dd269fc60202aca86bedfef18 (cherry picked from commit 0e1b399859a60075b46878bc3560df87c66b2092) --- src/slic3r/GUI/wxMediaCtrl2.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/wxMediaCtrl2.mm b/src/slic3r/GUI/wxMediaCtrl2.mm index ca2ccf6ea19..063472eccc7 100644 --- a/src/slic3r/GUI/wxMediaCtrl2.mm +++ b/src/slic3r/GUI/wxMediaCtrl2.mm @@ -97,8 +97,8 @@ BambuPlayer * player = (BambuPlayer *) m_player; if (player) { [player close]; - [player open: url.BuildURI().ToUTF8()]; m_error = 0; + m_error = [player open: url.BuildURI().ToUTF8()]; } wxMediaEvent event(wxEVT_MEDIA_STATECHANGED); event.SetId(GetId()); From 5335357f4c25647423f86602380d50894ead8aba Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 26 May 2025 16:27:50 +0800 Subject: [PATCH 112/127] ENH:optimization of select machine page (cherry picked from commit bambulab/BambuStudio@9afe123026ba5a4ffc13f7f3ce0e04100418db03) --------- Co-authored-by: tao wang --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/CalibrationPanel.cpp | 4 +- src/slic3r/GUI/CalibrationPanel.hpp | 8 - src/slic3r/GUI/Monitor.hpp | 2 +- src/slic3r/GUI/SelectMachine.cpp | 1235 ++------------------------- src/slic3r/GUI/SelectMachine.hpp | 364 ++------ src/slic3r/GUI/SelectMachinePop.cpp | 1054 +++++++++++++++++++++++ src/slic3r/GUI/SelectMachinePop.hpp | 233 +++++ 8 files changed, 1422 insertions(+), 1480 deletions(-) create mode 100644 src/slic3r/GUI/SelectMachinePop.cpp create mode 100644 src/slic3r/GUI/SelectMachinePop.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index cd22de6ef0c..ec1fce8996c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -440,6 +440,8 @@ set(SLIC3R_GUI_SOURCES GUI/ModelMall.cpp GUI/SelectMachine.hpp GUI/SelectMachine.cpp + GUI/SelectMachinePop.hpp + GUI/SelectMachinePop.cpp GUI/SendToPrinter.hpp GUI/SendToPrinter.cpp GUI/AmsMappingPopup.hpp diff --git a/src/slic3r/GUI/CalibrationPanel.cpp b/src/slic3r/GUI/CalibrationPanel.cpp index 9a16c133222..8fa07b924fc 100644 --- a/src/slic3r/GUI/CalibrationPanel.cpp +++ b/src/slic3r/GUI/CalibrationPanel.cpp @@ -4,11 +4,13 @@ #include "MainFrame.hpp" #include "CalibrationPanel.hpp" #include "I18N.hpp" +#include "SelectMachine.hpp" +#include "SelectMachinePop.hpp" namespace Slic3r { namespace GUI { #define REFRESH_INTERVAL 1000 - + #define INITIAL_NUMBER_OF_MACHINES 0 #define LIST_REFRESH_INTERVAL 200 #define MACHINE_LIST_REFRESH_INTERVAL 2000 diff --git a/src/slic3r/GUI/CalibrationPanel.hpp b/src/slic3r/GUI/CalibrationPanel.hpp index a993ff28869..eafb380c79a 100644 --- a/src/slic3r/GUI/CalibrationPanel.hpp +++ b/src/slic3r/GUI/CalibrationPanel.hpp @@ -7,16 +7,8 @@ namespace Slic3r { namespace GUI { -#define SELECT_MACHINE_GREY900 wxColour(38, 46, 48) -#define SELECT_MACHINE_GREY600 wxColour(144,144,144) -#define SELECT_MACHINE_GREY400 wxColour(206, 206, 206) -#define SELECT_MACHINE_BRAND wxColour(0, 150, 136) -#define SELECT_MACHINE_REMIND wxColour(255,111,0) -#define SELECT_MACHINE_LIGHT_GREEN wxColour(219, 253, 231) - #define CALI_MODE_COUNT 2 - wxString get_calibration_type_name(CalibMode cali_mode); class MObjectPanel : public wxPanel diff --git a/src/slic3r/GUI/Monitor.hpp b/src/slic3r/GUI/Monitor.hpp index 8da56ddc3b8..75cf204ac0c 100644 --- a/src/slic3r/GUI/Monitor.hpp +++ b/src/slic3r/GUI/Monitor.hpp @@ -48,7 +48,7 @@ #include "slic3r/GUI/HMSPanel.hpp" #include "slic3r/GUI/AmsWidgets.hpp" #include "Widgets/SideTools.hpp" -#include "SelectMachine.hpp" +#include "SelectMachinePop.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index b77a50893b2..f0627712a26 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -30,881 +30,18 @@ namespace Slic3r { namespace GUI { -wxDEFINE_EVENT(EVT_UPDATE_WINDOWS_POSITION, wxCommandEvent); -wxDEFINE_EVENT(EVT_FINISHED_UPDATE_MACHINE_LIST, wxCommandEvent); wxDEFINE_EVENT(EVT_UPDATE_USER_MACHINE_LIST, wxCommandEvent); wxDEFINE_EVENT(EVT_PRINT_JOB_CANCEL, wxCommandEvent); -wxDEFINE_EVENT(EVT_BIND_MACHINE, wxCommandEvent); -wxDEFINE_EVENT(EVT_UNBIND_MACHINE, wxCommandEvent); -wxDEFINE_EVENT(EVT_DISSMISS_MACHINE_LIST, wxCommandEvent); -wxDEFINE_EVENT(EVT_CONNECT_LAN_PRINT, wxCommandEvent); -wxDEFINE_EVENT(EVT_EDIT_PRINT_NAME, wxCommandEvent); wxDEFINE_EVENT(EVT_CLEAR_IPADDRESS, wxCommandEvent); #define INITIAL_NUMBER_OF_MACHINES 0 -#define LIST_REFRESH_INTERVAL 200 + #define MACHINE_LIST_REFRESH_INTERVAL 2000 #define WRAP_GAP FromDIP(2) static wxString task_canceled_text = _L("Task canceled"); - -std::string get_print_status_info(PrintDialogStatus status) -{ - switch(status) { - case PrintStatusInit: - return "PrintStatusInit"; - case PrintStatusNoUserLogin: - return "PrintStatusNoUserLogin"; - case PrintStatusInvalidPrinter: - return "PrintStatusInvalidPrinter"; - case PrintStatusConnectingServer: - return "PrintStatusConnectingServer"; - case PrintStatusReading: - return "PrintStatusReading"; - case PrintStatusReadingFinished: - return "PrintStatusReadingFinished"; - case PrintStatusReadingTimeout: - return "PrintStatusReadingTimeout"; - case PrintStatusInUpgrading: - return "PrintStatusInUpgrading"; - case PrintStatusNeedUpgradingAms: - return "PrintStatusNeedUpgradingAms"; - case PrintStatusInSystemPrinting: - return "PrintStatusInSystemPrinting"; - case PrintStatusInPrinting: - return "PrintStatusInPrinting"; - case PrintStatusDisableAms: - return "PrintStatusDisableAms"; - case PrintStatusAmsMappingSuccess: - return "PrintStatusAmsMappingSuccess"; - case PrintStatusAmsMappingInvalid: - return "PrintStatusAmsMappingInvalid"; - case PrintStatusAmsMappingU0Invalid: - return "PrintStatusAmsMappingU0Invalid"; - case PrintStatusAmsMappingValid: - return "PrintStatusAmsMappingValid"; - case PrintStatusAmsMappingByOrder: - return "PrintStatusAmsMappingByOrder"; - case PrintStatusRefreshingMachineList: - return "PrintStatusRefreshingMachineList"; - case PrintStatusSending: - return "PrintStatusSending"; - case PrintStatusSendingCanceled: - return "PrintStatusSendingCanceled"; - case PrintStatusLanModeNoSdcard: - return "PrintStatusLanModeNoSdcard"; - case PrintStatusNoSdcard: - return "PrintStatusNoSdcard"; - case PrintStatusUnsupportedPrinter: - return "PrintStatusUnsupportedPrinter"; - case PrintStatusTimelapseNoSdcard: - return "PrintStatusTimelapseNoSdcard"; - case PrintStatusNotSupportedPrintAll: - return "PrintStatusNotSupportedPrintAll"; - } - return "unknown"; -} - -MachineObjectPanel::MachineObjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name) -{ - wxPanel::Create(parent, id, pos, SELECT_MACHINE_ITEM_SIZE, style, name); - Bind(wxEVT_PAINT, &MachineObjectPanel::OnPaint, this); - - SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); - - m_unbind_img = ScalableBitmap(this, "unbind", 18); - m_edit_name_img = ScalableBitmap(this, "edit_button", 18); - m_select_unbind_img = ScalableBitmap(this, "unbind_selected", 18); - - m_printer_status_offline = ScalableBitmap(this, "printer_status_offline", 12); - m_printer_status_busy = ScalableBitmap(this, "printer_status_busy", 12); - m_printer_status_idle = ScalableBitmap(this, "printer_status_idle", 12); - m_printer_status_lock = ScalableBitmap(this, "printer_status_lock", 16); - m_printer_in_lan = ScalableBitmap(this, "printer_in_lan", 16); - - this->Bind(wxEVT_ENTER_WINDOW, &MachineObjectPanel::on_mouse_enter, this); - this->Bind(wxEVT_LEAVE_WINDOW, &MachineObjectPanel::on_mouse_leave, this); - this->Bind(wxEVT_LEFT_UP, &MachineObjectPanel::on_mouse_left_up, this); - -#ifdef __APPLE__ - wxPlatformInfo platformInfo; - auto major = platformInfo.GetOSMajorVersion(); - auto minor = platformInfo.GetOSMinorVersion(); - auto micro = platformInfo.GetOSMicroVersion(); - - //macos 13.1.0 - if (major >= 13 && minor >= 1 && micro >= 0) { - m_is_macos_special_version = true; - } -#endif - -} - - -MachineObjectPanel::~MachineObjectPanel() {} - -void MachineObjectPanel::show_bind_dialog() -{ - if (wxGetApp().is_user_login()) { - BindMachineDialog dlg; - dlg.update_machine_info(m_info); - dlg.ShowModal(); - } -} - -void MachineObjectPanel::set_printer_state(PrinterState state) -{ - m_state = state; - Refresh(); -} - -void MachineObjectPanel::show_edit_printer_name(bool show) -{ - m_show_edit = show; - Refresh(); -} - -void MachineObjectPanel::show_printer_bind(bool show, PrinterBindState state) -{ - m_show_bind = show; - m_bind_state = state; - Refresh(); -} - -void MachineObjectPanel::OnPaint(wxPaintEvent &event) -{ - wxPaintDC dc(this); - doRender(dc); -} - -void MachineObjectPanel::render(wxDC &dc) -{ -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({0, 0}, size, &dc, {0, 0}); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif -} - -void MachineObjectPanel::doRender(wxDC &dc) -{ - auto left = 10; - wxSize size = GetSize(); - dc.SetPen(*wxTRANSPARENT_PEN); - - auto dwbitmap = m_printer_status_offline; - if (m_state == PrinterState::IDLE) { dwbitmap = m_printer_status_idle; } - if (m_state == PrinterState::BUSY) { dwbitmap = m_printer_status_busy; } - if (m_state == PrinterState::OFFLINE) { dwbitmap = m_printer_status_offline; } - if (m_state == PrinterState::LOCK) { dwbitmap = m_printer_status_lock; } - if (m_state == PrinterState::IN_LAN) { dwbitmap = m_printer_in_lan; } - - // dc.DrawCircle(left, size.y / 2, 3); - dc.DrawBitmap(dwbitmap.bmp(), wxPoint(left, (size.y - dwbitmap.GetBmpSize().y) / 2)); - - left += dwbitmap.GetBmpSize().x + 8; - dc.SetFont(Label::Body_13); - dc.SetBackgroundMode(wxTRANSPARENT); - dc.SetTextForeground(StateColor::darkModeColorFor(SELECT_MACHINE_GREY900)); - wxString dev_name = ""; - if (m_info) { - dev_name = from_u8(m_info->dev_name); - - if (m_state == PrinterState::IN_LAN) { - dev_name += _L("(LAN)"); - } - } - auto sizet = dc.GetTextExtent(dev_name); - auto text_end = 0; - - if (m_show_edit) { - text_end = size.x - m_unbind_img.GetBmpSize().x - 30; - } - else { - text_end = size.x - m_unbind_img.GetBmpSize().x; - } - - wxString finally_name = dev_name; - if (sizet.x > (text_end - left)) { - auto limit_width = text_end - left - dc.GetTextExtent("...").x - 15; - for (auto i = 0; i < dev_name.length(); i++) { - auto curr_width = dc.GetTextExtent(dev_name.substr(0, i)); - if (curr_width.x >= limit_width) { - finally_name = dev_name.substr(0, i) + "..."; - break; - } - } - } - - dc.DrawText(finally_name, wxPoint(left, (size.y - sizet.y) / 2)); - - - if (m_hover || m_is_macos_special_version) { - - if (m_hover && !m_is_macos_special_version) { - dc.SetPen(SELECT_MACHINE_BRAND); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(0, 0, size.x, size.y); - } - - if (m_show_bind) { - if (m_bind_state == ALLOW_UNBIND) { - left = size.x - m_unbind_img.GetBmpSize().x - 6; - dc.DrawBitmap(m_unbind_img.bmp(), left, (size.y - m_unbind_img.GetBmpSize().y) / 2); - } - } - - if (m_show_edit) { - left = size.x - m_unbind_img.GetBmpSize().x - 6 - m_edit_name_img.GetBmpSize().x - 6; - dc.DrawBitmap(m_edit_name_img.bmp(), left, (size.y - m_edit_name_img.GetBmpSize().y) / 2); - } - } - -} - -void MachineObjectPanel::update_machine_info(MachineObject *info, bool is_my_devices) -{ - m_info = info; - m_is_my_devices = is_my_devices; - Refresh(); -} - -void MachineObjectPanel::on_mouse_enter(wxMouseEvent &evt) -{ - m_hover = true; - Refresh(); -} - -void MachineObjectPanel::on_mouse_leave(wxMouseEvent &evt) -{ - m_hover = false; - Refresh(); -} - -void MachineObjectPanel::on_mouse_left_up(wxMouseEvent &evt) -{ - if (m_is_my_devices) { - // show edit - if (m_show_edit) { - auto edit_left = GetSize().x - m_unbind_img.GetBmpSize().x - 6 - m_edit_name_img.GetBmpSize().x - 6; - auto edit_right = edit_left + m_edit_name_img.GetBmpSize().x; - auto edit_top = (GetSize().y - m_edit_name_img.GetBmpSize().y) / 2; - auto edit_bottom = (GetSize().y - m_edit_name_img.GetBmpSize().y) / 2 + m_edit_name_img.GetBmpSize().y; - if ((evt.GetPosition().x >= edit_left && evt.GetPosition().x <= edit_right) && evt.GetPosition().y >= edit_top && evt.GetPosition().y <= edit_bottom) { - wxCommandEvent event(EVT_EDIT_PRINT_NAME); - event.SetEventObject(this); - wxPostEvent(this, event); - return; - } - } - if (m_show_bind) { - auto left = GetSize().x - m_unbind_img.GetBmpSize().x - 6; - auto right = left + m_unbind_img.GetBmpSize().x; - auto top = (GetSize().y - m_unbind_img.GetBmpSize().y) / 2; - auto bottom = (GetSize().y - m_unbind_img.GetBmpSize().y) / 2 + m_unbind_img.GetBmpSize().y; - - if ((evt.GetPosition().x >= left && evt.GetPosition().x <= right) && evt.GetPosition().y >= top && evt.GetPosition().y <= bottom) { - wxCommandEvent event(EVT_UNBIND_MACHINE, GetId()); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); - } else { - if (m_info) { - wxGetApp().mainframe->jump_to_monitor(m_info->dev_id); - } - //wxGetApp().mainframe->SetFocus(); - wxCommandEvent event(EVT_DISSMISS_MACHINE_LIST); - event.SetEventObject(this->GetParent()); - wxPostEvent(this->GetParent(), event); - } - return; - } - if (m_info && m_info->is_lan_mode_printer()) { - if (m_info->has_access_right() && m_info->is_avaliable()) { - wxGetApp().mainframe->jump_to_monitor(m_info->dev_id); - } else { - wxCommandEvent event(EVT_CONNECT_LAN_PRINT); - event.SetEventObject(this); - wxPostEvent(this, event); - } - } else { - wxGetApp().mainframe->jump_to_monitor(m_info->dev_id); - } - } else { - if (m_info && m_info->is_lan_mode_printer()) { - wxCommandEvent event(EVT_CONNECT_LAN_PRINT); - event.SetEventObject(this); - wxPostEvent(this, event); - } else { - wxCommandEvent event(EVT_BIND_MACHINE); - event.SetEventObject(this); - wxPostEvent(this, event); - } - } - -} - -SelectMachinePopup::SelectMachinePopup(wxWindow *parent) - : PopupWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS), m_dismiss(false) -{ -#ifdef __WINDOWS__ - SetDoubleBuffered(true); -#endif //__WINDOWS__ - - - SetSize(SELECT_MACHINE_POPUP_SIZE); - SetMinSize(SELECT_MACHINE_POPUP_SIZE); - SetMaxSize(SELECT_MACHINE_POPUP_SIZE); - - Freeze(); - wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL); - SetBackgroundColour(SELECT_MACHINE_GREY400); - - - - m_scrolledWindow = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_LIST_SIZE, wxHSCROLL | wxVSCROLL); - m_scrolledWindow->SetBackgroundColour(*wxWHITE); - m_scrolledWindow->SetMinSize(SELECT_MACHINE_LIST_SIZE); - m_scrolledWindow->SetScrollRate(0, 5); - auto m_sizxer_scrolledWindow = new wxBoxSizer(wxVERTICAL); - m_scrolledWindow->SetSizer(m_sizxer_scrolledWindow); - m_scrolledWindow->Layout(); - m_sizxer_scrolledWindow->Fit(m_scrolledWindow); - -#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) - m_sizer_search_bar = new wxBoxSizer(wxVERTICAL); - m_search_bar = new wxSearchCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); - m_search_bar->SetDescriptiveText(_L("Search")); - m_search_bar->ShowSearchButton( true ); - m_search_bar->ShowCancelButton( false ); - m_sizer_search_bar->Add( m_search_bar, 1, wxALL| wxEXPAND, 1 ); - m_sizer_main->Add(m_sizer_search_bar, 0, wxALL | wxEXPAND, FromDIP(2)); - m_search_bar->Bind( wxEVT_COMMAND_TEXT_UPDATED, &SelectMachinePopup::update_machine_list, this ); -#endif - auto own_title = create_title_panel(_L("My Device")); - m_sizer_my_devices = new wxBoxSizer(wxVERTICAL); - auto other_title = create_title_panel(_L("Other Device")); - m_sizer_other_devices = new wxBoxSizer(wxVERTICAL); - - - m_panel_ping_code = new PinCodePanel(m_scrolledWindow, 0, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE); - m_panel_direct_connection = new PinCodePanel(m_scrolledWindow, 1, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE); - - m_sizxer_scrolledWindow->Add(own_title, 0, wxEXPAND | wxLEFT, FromDIP(15)); - m_sizxer_scrolledWindow->Add(m_sizer_my_devices, 0, wxEXPAND, 0); - m_sizxer_scrolledWindow->Add(m_panel_ping_code, 0, wxEXPAND, 0); - m_sizxer_scrolledWindow->Add(m_panel_direct_connection, 0, wxEXPAND, 0); - m_sizxer_scrolledWindow->Add(other_title, 0, wxEXPAND | wxLEFT, FromDIP(15)); - m_sizxer_scrolledWindow->Add(m_sizer_other_devices, 0, wxEXPAND, 0); - - m_sizer_main->Add(m_scrolledWindow, 0, wxALL | wxEXPAND, FromDIP(2)); - - SetSizer(m_sizer_main); - Layout(); - Thaw(); - - #ifdef __APPLE__ - m_scrolledWindow->Bind(wxEVT_LEFT_UP, &SelectMachinePopup::OnLeftUp, this); - #endif // __APPLE__ - - m_refresh_timer = new wxTimer(); - m_refresh_timer->SetOwner(this); - Bind(EVT_UPDATE_USER_MACHINE_LIST, &SelectMachinePopup::update_machine_list, this); - Bind(wxEVT_TIMER, &SelectMachinePopup::on_timer, this); - Bind(EVT_DISSMISS_MACHINE_LIST, &SelectMachinePopup::on_dissmiss_win, this); -} - -SelectMachinePopup::~SelectMachinePopup() { delete m_refresh_timer;} - -void SelectMachinePopup::Popup(wxWindow *WXUNUSED(focus)) -{ - BOOST_LOG_TRIVIAL(trace) << "get_print_info: start"; - start_ssdp(true); - if (m_refresh_timer) { - m_refresh_timer->Stop(); - m_refresh_timer->Start(MACHINE_LIST_REFRESH_INTERVAL); - } - - if (wxGetApp().is_user_login()) { - if (!get_print_info_thread) { - get_print_info_thread = new boost::thread(Slic3r::create_thread([this, token = std::weak_ptr(m_token)] { - NetworkAgent* agent = wxGetApp().getAgent(); - unsigned int http_code; - std::string body; - int result = agent->get_user_print_info(&http_code, &body); - CallAfter([token, this, result, body]() { - if (token.expired()) {return;} - if (result == 0) { - m_print_info = body; - } - else { - m_print_info = ""; - } - wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); - event.SetEventObject(this); - wxPostEvent(this, event); - }); - })); - } - } - - wxPostEvent(this, wxTimerEvent()); - PopupWindow::Popup(); -} - -void SelectMachinePopup::OnDismiss() -{ - BOOST_LOG_TRIVIAL(trace) << "get_print_info: dismiss"; - start_ssdp(false); - m_dismiss = true; - - if (m_refresh_timer) { - m_refresh_timer->Stop(); - } - if (get_print_info_thread) { - if (get_print_info_thread->joinable()) { - get_print_info_thread->join(); - delete get_print_info_thread; - get_print_info_thread = nullptr; - } - } - - wxCommandEvent event(EVT_FINISHED_UPDATE_MACHINE_LIST); - event.SetEventObject(this); - wxPostEvent(this, event); -} - -bool SelectMachinePopup::ProcessLeftDown(wxMouseEvent &event) { - return PopupWindow::ProcessLeftDown(event); -} - -bool SelectMachinePopup::Show(bool show) { - if (show) { - for (int i = 0; i < m_user_list_machine_panel.size(); i++) { - m_user_list_machine_panel[i]->mPanel->update_machine_info(nullptr); - m_user_list_machine_panel[i]->mPanel->Hide(); - } - - for (int j = 0; j < m_other_list_machine_panel.size(); j++) { - m_other_list_machine_panel[j]->mPanel->update_machine_info(nullptr); - m_other_list_machine_panel[j]->mPanel->Hide(); - } - } - return PopupWindow::Show(show); -} - -wxWindow *SelectMachinePopup::create_title_panel(wxString text) -{ - auto m_panel_title_own = new wxWindow(m_scrolledWindow, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE, wxTAB_TRAVERSAL); - m_panel_title_own->SetBackgroundColour(*wxWHITE); - - wxBoxSizer *m_sizer_title_own = new wxBoxSizer(wxHORIZONTAL); - - auto m_title_own = new wxStaticText(m_panel_title_own, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, 0); - m_title_own->Wrap(-1); - m_sizer_title_own->Add(m_title_own, 0, wxALIGN_CENTER, 0); - - wxBoxSizer *m_sizer_line_own = new wxBoxSizer(wxHORIZONTAL); - - auto m_panel_line_own = new wxPanel(m_panel_title_own, wxID_ANY, wxDefaultPosition, wxSize(SELECT_MACHINE_ITEM_SIZE.x, FromDIP(1)), wxTAB_TRAVERSAL); - m_panel_line_own->SetBackgroundColour(SELECT_MACHINE_GREY400); - - m_sizer_line_own->Add(m_panel_line_own, 0, wxALIGN_CENTER, 0); - m_sizer_title_own->Add(0, 0, 0, wxLEFT, FromDIP(10)); - m_sizer_title_own->Add(m_sizer_line_own, 1, wxEXPAND | wxRIGHT, FromDIP(10)); - - m_panel_title_own->SetSizer(m_sizer_title_own); - m_panel_title_own->Layout(); - return m_panel_title_own; -} - -void SelectMachinePopup::on_timer(wxTimerEvent &event) -{ - BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup on_timer"; - wxGetApp().reset_to_active(); - wxCommandEvent user_event(EVT_UPDATE_USER_MACHINE_LIST); - user_event.SetEventObject(this); - wxPostEvent(this, user_event); -} - -void SelectMachinePopup::update_other_devices() -{ - DeviceManager* dev = wxGetApp().getDeviceManager(); - if (!dev) return; - m_free_machine_list = dev->get_local_machine_list(); - - BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices start"; - this->Freeze(); - m_scrolledWindow->Freeze(); - int i = 0; - - for (auto &elem : m_free_machine_list) { - MachineObject * mobj = elem.second; - /* do not show printer bind state is empty */ - if (!mobj->is_avaliable()) continue; - - if (!wxGetApp().is_user_login() && !mobj->is_lan_mode_printer()) - continue; - - /* do not show printer in my list */ - auto it = m_bind_machine_list.find(mobj->dev_id); - if (it != m_bind_machine_list.end()) - continue; - - MachineObjectPanel* op = nullptr; - if (i < m_other_list_machine_panel.size()) { - op = m_other_list_machine_panel[i]->mPanel; - } else { - op = new MachineObjectPanel(m_scrolledWindow, wxID_ANY); - MachinePanel* mpanel = new MachinePanel(); - mpanel->mIndex = wxString::Format("%d", i); - mpanel->mPanel = op; - m_other_list_machine_panel.push_back(mpanel); - m_sizer_other_devices->Add(op, 0, wxEXPAND, 0); - } -#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) - if (!search_for_printer(mobj)) { - op->Hide(); - } - else { - op->Show(); - } -#else - op->Show(); -#endif - i++; - - op->update_machine_info(mobj); - - if (mobj->is_lan_mode_printer()) { - if (mobj->has_access_right()) { - op->set_printer_state(PrinterState::IN_LAN); - } else { - op->set_printer_state(PrinterState::LOCK); - } - } else { - op->show_edit_printer_name(false); - op->show_printer_bind(true, PrinterBindState::ALLOW_BIND); - if (mobj->is_in_printing()) { - op->set_printer_state(PrinterState::BUSY); - } else { - op->SetToolTip(_L("Online")); - op->set_printer_state(IDLE); - } - } - - op->Bind(EVT_CONNECT_LAN_PRINT, [this, mobj](wxCommandEvent &e) { - if (mobj) { - if (mobj->is_lan_mode_printer()) { - ConnectPrinterDialog dlg(wxGetApp().mainframe, wxID_ANY, _L("Input access code")); - dlg.set_machine_object(mobj); - if (dlg.ShowModal() == wxID_OK) { - wxGetApp().mainframe->jump_to_monitor(mobj->dev_id); - } - } - } - }); - - op->Bind(EVT_BIND_MACHINE, [this, mobj](wxCommandEvent &e) { - BindMachineDialog dlg; - dlg.update_machine_info(mobj); - int dlg_result = wxID_CANCEL; - dlg_result = dlg.ShowModal(); - if (dlg_result == wxID_OK) { wxGetApp().mainframe->jump_to_monitor(mobj->dev_id); } - }); - } - - for (int j = i; j < m_other_list_machine_panel.size(); j++) { - m_other_list_machine_panel[j]->mPanel->update_machine_info(nullptr); - m_other_list_machine_panel[j]->mPanel->Hide(); - } - - if (m_placeholder_panel != nullptr) { - m_scrolledWindow->RemoveChild(m_placeholder_panel); - m_placeholder_panel->Destroy(); - m_placeholder_panel = nullptr; - } - - m_placeholder_panel = new wxWindow(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxSize(-1,FromDIP(26))); - wxBoxSizer* placeholder_sizer = new wxBoxSizer(wxVERTICAL); - - m_hyperlink = new wxHyperlinkCtrl(m_placeholder_panel, wxID_ANY, _L("Can't find my devices?"), wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE); - m_hyperlink->SetNormalColour(StateColor::darkModeColorFor("#009789")); - placeholder_sizer->Add(m_hyperlink, 0, wxALIGN_CENTER | wxALL, 5); - - - m_placeholder_panel->SetSizer(placeholder_sizer); - m_placeholder_panel->Layout(); - placeholder_sizer->Fit(m_placeholder_panel); - - m_placeholder_panel->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); - m_sizer_other_devices->Add(m_placeholder_panel, 0, wxEXPAND, 0); - - //m_sizer_other_devices->Layout(); - if(m_other_devices_count != i) { - m_scrolledWindow->Fit(); - } - m_scrolledWindow->Layout(); - m_scrolledWindow->Thaw(); - Layout(); - Fit(); - this->Thaw(); - m_other_devices_count = i; - BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices end"; -} - -void SelectMachinePopup::update_user_devices() -{ - Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (!dev) return; - - if (!m_print_info.empty()) { - dev->parse_user_print_info(m_print_info); - m_print_info = ""; - } - - m_bind_machine_list.clear(); - m_bind_machine_list = dev->get_my_machine_list(); - - //sort list - std::vector> user_machine_list; - for (auto& it: m_bind_machine_list) { - user_machine_list.push_back(it); - } - - std::sort(user_machine_list.begin(), user_machine_list.end(), [&](auto& a, auto&b) { - if (a.second && b.second) { - return a.second->dev_name.compare(b.second->dev_name) < 0; - } - return false; - }); - - BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_machine_list start"; - this->Freeze(); - m_scrolledWindow->Freeze(); - int i = 0; - - for (auto& elem : user_machine_list) { - MachineObject* mobj = elem.second; - MachineObjectPanel* op = nullptr; - if (i < m_user_list_machine_panel.size()) { - op = m_user_list_machine_panel[i]->mPanel; -#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) - if (!search_for_printer(mobj)) { - op->Hide(); - } else { - op->Show(); - } -#else - op->Show(); -#endif - } else { - op = new MachineObjectPanel(m_scrolledWindow, wxID_ANY); - MachinePanel* mpanel = new MachinePanel(); - mpanel->mIndex = wxString::Format("%d", i); - mpanel->mPanel = op; - m_user_list_machine_panel.push_back(mpanel); - m_sizer_my_devices->Add(op, 0, wxEXPAND, 0); - } - i++; - op->update_machine_info(mobj, true); - //set in lan - if (mobj->is_lan_mode_printer()) { - if (!mobj->is_online()) { - continue; - } - else { - op->show_printer_bind(false, PrinterBindState::NONE); - op->show_edit_printer_name(false); - if (mobj->has_access_right() && mobj->is_avaliable()) { - op->set_printer_state(PrinterState::IN_LAN); - op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); - op->SetToolTip(_L("Online")); - } - else { - op->set_printer_state(PrinterState::LOCK); - } - } - op->Bind(EVT_UNBIND_MACHINE, [this, dev, mobj](wxCommandEvent& e) { - dev->set_selected_machine(""); - if (mobj) { - AppConfig* config = wxGetApp().app_config; - if (config) { - config->erase_local_machine(mobj->dev_id); - } - - mobj->set_access_code(""); - mobj->erase_user_access_code(); - } - - MessageDialog msg_wingow(nullptr, _L("Log out successful."), "", wxAPPLY | wxOK); - if (msg_wingow.ShowModal() == wxOK) { return; } - }); - } - else { - op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); - op->Bind(EVT_UNBIND_MACHINE, [this, mobj, dev](wxCommandEvent& e) { - // show_unbind_dialog - UnBindMachineDialog dlg; - dlg.update_machine_info(mobj); - if (dlg.ShowModal() == wxID_OK) { - dev->set_selected_machine(""); - } - }); - - if (!mobj->is_online()) { - op->SetToolTip(_L("Offline")); - op->set_printer_state(PrinterState::OFFLINE); - } - else { - op->show_edit_printer_name(true); - op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); - if (mobj->is_in_printing()) { - op->SetToolTip(_L("Busy")); - op->set_printer_state(PrinterState::BUSY); - } - else { - op->SetToolTip(_L("Online")); - op->set_printer_state(PrinterState::IDLE); - } - } - } - - op->Bind(EVT_CONNECT_LAN_PRINT, [this, mobj](wxCommandEvent &e) { - if (mobj) { - if (mobj->is_lan_mode_printer()) { - ConnectPrinterDialog dlg(wxGetApp().mainframe, wxID_ANY, _L("Input access code")); - dlg.set_machine_object(mobj); - if (dlg.ShowModal() == wxID_OK) { - wxGetApp().mainframe->jump_to_monitor(mobj->dev_id); - } - } - } - }); - - op->Bind(EVT_EDIT_PRINT_NAME, [this, mobj](wxCommandEvent &e) { - EditDevNameDialog dlg; - dlg.set_machine_obj(mobj); - dlg.ShowModal(); - }); - } - - for (int j = i; j < m_user_list_machine_panel.size(); j++) { - m_user_list_machine_panel[j]->mPanel->update_machine_info(nullptr); - m_user_list_machine_panel[j]->mPanel->Hide(); - } - //m_sizer_my_devices->Layout(); - - if (m_my_devices_count != i) { - m_scrolledWindow->Fit(); - } - m_scrolledWindow->Layout(); - m_scrolledWindow->Thaw(); - Layout(); - Fit(); - this->Thaw(); - m_my_devices_count = i; -} - -bool SelectMachinePopup::search_for_printer(MachineObject* obj) -{ - std::string search_text = std::string((m_search_bar->GetValue()).mb_str()); - if (search_text.empty()) { - return true; - } - auto name = obj->dev_name; - auto ip = obj->dev_ip; - auto name_it = name.find(search_text); - auto ip_it = ip.find(search_text); - if ((name_it != std::string::npos)||(ip_it != std::string::npos)) { - return true; - } - - return false; -} - -void SelectMachinePopup::on_dissmiss_win(wxCommandEvent &event) -{ - Dismiss(); -} - -void SelectMachinePopup::update_machine_list(wxCommandEvent &event) -{ - update_user_devices(); - update_other_devices(); - BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_machine_list end"; -} - -void SelectMachinePopup::start_ssdp(bool start) -{ - return; - //if (wxGetApp().getAgent()) { wxGetApp().getAgent()->start_discovery(true, start); } -} - -void SelectMachinePopup::OnLeftUp(wxMouseEvent &event) -{ - auto mouse_pos = ClientToScreen(event.GetPosition()); - auto wxscroll_win_pos = m_scrolledWindow->ClientToScreen(wxPoint(0, 0)); - - if (mouse_pos.x > wxscroll_win_pos.x && mouse_pos.y > wxscroll_win_pos.y && mouse_pos.x < (wxscroll_win_pos.x + m_scrolledWindow->GetSize().x) && - mouse_pos.y < (wxscroll_win_pos.y + m_scrolledWindow->GetSize().y)) { - - for (MachinePanel* p : m_user_list_machine_panel) { - auto p_rect = p->mPanel->ClientToScreen(wxPoint(0, 0)); - if (mouse_pos.x > p_rect.x && mouse_pos.y > p_rect.y && mouse_pos.x < (p_rect.x + p->mPanel->GetSize().x) && mouse_pos.y < (p_rect.y + p->mPanel->GetSize().y)) { - wxMouseEvent event(wxEVT_LEFT_UP); - auto tag_pos = p->mPanel->ScreenToClient(mouse_pos); - event.SetPosition(tag_pos); - event.SetEventObject(p->mPanel); - wxPostEvent(p->mPanel, event); - } - } - - for (MachinePanel* p : m_other_list_machine_panel) { - auto p_rect = p->mPanel->ClientToScreen(wxPoint(0, 0)); - if (mouse_pos.x > p_rect.x && mouse_pos.y > p_rect.y && mouse_pos.x < (p_rect.x + p->mPanel->GetSize().x) && mouse_pos.y < (p_rect.y + p->mPanel->GetSize().y)) { - wxMouseEvent event(wxEVT_LEFT_UP); - auto tag_pos = p->mPanel->ScreenToClient(mouse_pos); - event.SetPosition(tag_pos); - event.SetEventObject(p->mPanel); - wxPostEvent(p->mPanel, event); - } - } - - //pin code - auto pc_rect = m_panel_ping_code->ClientToScreen(wxPoint(0, 0)); - if (mouse_pos.x > pc_rect.x && mouse_pos.y > pc_rect.y && mouse_pos.x < (pc_rect.x + m_panel_ping_code->GetSize().x) && mouse_pos.y < (pc_rect.y + m_panel_ping_code->GetSize().y)) { - wxGetApp().popup_ping_bind_dialog(); - } - - //bind with access code - auto dc_rect = m_panel_direct_connection->ClientToScreen(wxPoint(0, 0)); - if (mouse_pos.x > dc_rect.x && mouse_pos.y > dc_rect.y && mouse_pos.x < (dc_rect.x + m_panel_direct_connection->GetSize().x) && mouse_pos.y < (dc_rect.y + m_panel_direct_connection->GetSize().y)) { - InputIpAddressDialog dlgo; - dlgo.ShowModal(); - } - - //hyper link - auto h_rect = m_hyperlink->ClientToScreen(wxPoint(0, 0)); - if (mouse_pos.x > h_rect.x && mouse_pos.y > h_rect.y && mouse_pos.x < (h_rect.x + m_hyperlink->GetSize().x) && mouse_pos.y < (h_rect.y + m_hyperlink->GetSize().y)) { - wxLaunchDefaultBrowser(wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer")); - } - } -} - static wxString MACHINE_BED_TYPE_STRING[BED_TYPE_COUNT] = { //_L("Auto"), _L("Bambu Cool Plate") + " / " + _L("PLA Plate"), @@ -912,14 +49,6 @@ static wxString MACHINE_BED_TYPE_STRING[BED_TYPE_COUNT] = { _L("Bambu Smooth PEI Plate") + "/" + _L("High temperature Plate"), _L("Bambu Textured PEI Plate")}; -static std::string MachineBedTypeString[BED_TYPE_COUNT] = { - //"auto", - "pc", - "pe", - "pei", - "pte", -}; - void SelectMachineDialog::stripWhiteSpace(std::string& str) { if (str == "") { return; } @@ -937,6 +66,14 @@ void SelectMachineDialog::stripWhiteSpace(std::string& str) } } +static std::string MachineBedTypeString[BED_TYPE_COUNT] = { + //"auto", + "pc", + "pe", + "pei", + "pte", +}; + wxString SelectMachineDialog::format_text(wxString &m_msg) { if (wxGetApp().app_config->get("language") != "zh_CN") {return m_msg; } @@ -956,7 +93,6 @@ wxString SelectMachineDialog::format_text(wxString &m_msg) } return out_txt; } - SelectMachineDialog::SelectMachineDialog(Plater *plater) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Send print job to"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) , m_plater(plater), m_export_3mf_cancel(false) @@ -996,7 +132,6 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_basicl_sizer = new wxBoxSizer(wxHORIZONTAL); /*basic info*/ - /*thumbnail*/ auto m_sizer_thumbnail_area = new wxBoxSizer(wxHORIZONTAL); @@ -1014,7 +149,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_sizer_thumbnail_area->Add(m_panel_image, 0, wxALIGN_CENTER, 0); m_sizer_thumbnail_area->Layout(); - + /*basic info right*/ auto sizer_basic_right_info = new wxBoxSizer(wxVERTICAL); @@ -1115,8 +250,6 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_text_bed_type->SetFont(Label::Body_13); /*last & next page*/ - - auto last_plate_sizer = new wxBoxSizer(wxVERTICAL); m_bitmap_last_plate = new wxStaticBitmap(m_basic_panel, wxID_ANY, create_scaled_bitmap("go_last_plate", this, 25), wxDefaultPosition, wxSize(FromDIP(25), FromDIP(25)), 0); m_bitmap_last_plate->Hide(); @@ -1191,7 +324,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) m_basicl_sizer->Add(m_sizer_thumbnail_area, 0, wxLEFT, 0); m_basicl_sizer->Add(0, 0, 0, wxLEFT, FromDIP(8)); m_basicl_sizer->Add(sizer_basic_right_info, 0, wxLEFT, 0); - + m_basic_panel->SetSizer(m_basicl_sizer); @@ -1239,37 +372,6 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) sizer_split_filament->Add(m_split_line_filament, 1, wxALIGN_CENTER_VERTICAL, 0); sizer_split_filament->Add(m_sizer_autorefill, 0, wxALIGN_CENTER, 0); - //wxBoxSizer* m_sizer_ams_mapping_tips = new wxBoxSizer(wxHORIZONTAL); - - - - /* ams_mapping_help_icon = new ScalableBitmap(this, "enable_ams", 16); - img_amsmapping_tip = new wxStaticBitmap(this, wxID_ANY, ams_mapping_help_icon->bmp(), wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)), 0); - m_sizer_ams_mapping_tips->Add(img_amsmapping_tip, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5)); - - img_amsmapping_tip->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) { - wxPoint img_pos = img_amsmapping_tip->ClientToScreen(wxPoint(0, 0)); - wxPoint popup_pos(img_pos.x, img_pos.y + img_amsmapping_tip->GetRect().height); - m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); - m_mapping_tutorial_popup.Popup(); - - if (m_mapping_tutorial_popup.ClientToScreen(wxPoint(0, 0)).y < img_pos.y) { - m_mapping_tutorial_popup.Dismiss(); - popup_pos = wxPoint(img_pos.x, img_pos.y - m_mapping_tutorial_popup.GetRect().height); - m_mapping_tutorial_popup.Position(popup_pos, wxSize(0, 0)); - m_mapping_tutorial_popup.Popup(); - } - }); - - img_amsmapping_tip->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { - m_mapping_tutorial_popup.Dismiss(); - }); - - - - - m_sizer_filament->Add(m_sizer_ams_mapping_tips, 0, wxALIGN_CENTER|wxLEFT, FromDIP(8));*/ - /*filament area*/ /*1 extruder*/ m_filament_panel = new wxPanel(this, wxID_ANY); @@ -1509,11 +611,6 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3)); sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5); - //m_sizer_scrollable_region->Add(m_sizer_material, 0, wxALIGN_CENTER_HORIZONTAL, 0); - //m_basic_panel_sizer->Add(m_sizer_material_area, 0, wxLEFT, FromDIP(10)); - - - m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(12)); @@ -1977,7 +1074,7 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_) } } sync_ams_mapping_result(m_ams_mapping_result); - return is_valid; + return is_valid; } return true; @@ -2661,7 +1758,7 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event) wxString error_info = Plater::get_slice_warning_string(warning); if (error_info.IsEmpty()) { error_info = wxString::Format("%s\n", warning.msg); - } + } confirm_text.push_back(ConfirmBeforeSendInfo(error_info)); has_slice_warnings = true; @@ -3156,7 +2253,7 @@ void SelectMachineDialog::on_set_finish_mapping(wxCommandEvent &evt) MaterialHash::iterator iter = m_materialList.begin(); while (iter != m_materialList.end()) { Material* item = iter->second; - MaterialItem *m = item->item; + MaterialItem *m = item->item; if (item->id == m_current_filament_id) { auto ams_colour = wxColour(wxAtoi(selection_data_arr[0]), wxAtoi(selection_data_arr[1]), wxAtoi(selection_data_arr[2]), wxAtoi(selection_data_arr[3])); m->set_ams_info(ams_colour, selection_data_arr[4], ctype, material_cols); @@ -3628,7 +2725,6 @@ void SelectMachineDialog::update_show_status() } reset_timeout(); - //update_ams_check(obj_); if (!obj_->is_support_print_all && m_print_plate_idx == PLATE_ALL_IDX) { show_status(PrintDialogStatus::PrintStatusNotSupportedPrintAll); @@ -3800,7 +2896,7 @@ bool SelectMachineDialog::has_timelapse_warning() return true; } } - + return false; } @@ -4501,9 +3597,9 @@ void SelectMachineDialog::set_default_normal(const ThumbnailData &data) for (unsigned int r = 0; r < data.height; ++r) { unsigned int rr = (data.height - 1 - r) * data.width; for (unsigned int c = 0; c < data.width; ++c) { - unsigned char* px = (unsigned char*)data.pixels.data() + 4 * (rr + c); - image.SetRGB((int)c, (int)r, px[0], px[1], px[2]); - image.SetAlpha((int)c, (int)r, px[3]); + unsigned char *px = (unsigned char *) data.pixels.data() + 4 * (rr + c); + image.SetRGB((int) c, (int) r, px[0], px[1], px[2]); + image.SetAlpha((int) c, (int) r, px[3]); } } image = image.Rescale(FromDIP(198), FromDIP(198)); @@ -4513,14 +3609,13 @@ void SelectMachineDialog::set_default_normal(const ThumbnailData &data) m_basic_panel->Layout(); m_basic_panel->Fit(); - //disable pei bed - DeviceManager* dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager(); + // disable pei bed + DeviceManager *dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager(); if (!dev_manager) return; - MachineObject* obj_ = dev_manager->get_selected_machine(); + MachineObject *obj_ = dev_manager->get_selected_machine(); update_flow_cali_check(obj_); - - wxSize screenSize = wxGetDisplaySize(); - auto dialogSize = this->GetSize(); + wxSize screenSize = wxGetDisplaySize(); + auto dialogSize = this->GetSize(); #ifdef __WINDOWS__ @@ -4528,7 +3623,7 @@ void SelectMachineDialog::set_default_normal(const ThumbnailData &data) // basic info auto aprint_stats = m_plater->get_partplate_list().get_current_fff_print().print_statistics(); wxString time; - PartPlate* plate = m_plater->get_partplate_list().get_curr_plate(); + PartPlate *plate = m_plater->get_partplate_list().get_curr_plate(); if (plate) { if (plate->get_slice_result()) { time = wxString::Format("%s", short_time(get_time_dhms(plate->get_slice_result()->print_statistics.modes[0].time))); } } @@ -4536,8 +3631,7 @@ void SelectMachineDialog::set_default_normal(const ThumbnailData &data) char weight[64]; if (wxGetApp().app_config->get("use_inches") == "1") { ::sprintf(weight, " %.2f oz", aprint_stats.total_weight * 0.035274); - } - else { + } else { ::sprintf(weight, " %.2f g", aprint_stats.total_weight); } @@ -4558,7 +3652,7 @@ void SelectMachineDialog::set_default_from_sdcard() image = image.Rescale(FromDIP(198), FromDIP(198)); m_thumbnailPanel->set_thumbnail(image); } - + //for black list std::vector materials; std::vector brands; @@ -4586,7 +3680,6 @@ void SelectMachineDialog::set_default_from_sdcard() m_materialList.clear(); m_filaments.clear(); - for (auto i = 0; i < m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size(); i++) { FilamentInfo fo = m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info[i]; @@ -4783,170 +3876,50 @@ void SelectMachineDialog::update_lan_machine_list() if (!mobj->is_avaliable()) continue; if (!mobj->is_online()) continue; if (!mobj->is_lan_mode_printer()) continue; - /*if (mobj->is_in_printing()) {op->set_printer_state(PrinterState::BUSY);}*/ - if (mobj->has_access_right()) { - auto b = mobj->dev_name; - - // clear machine list - - //m_comboBox_printer->Clear(); - std::vector machine_list; - wxArrayString machine_list_name; - std::map option_list; - - // same machine only appear once - - /* machine_list = sort_string(machine_list); - for (auto tt = machine_list.begin(); tt != machine_list.end(); tt++) { - for (auto it = option_list.begin(); it != option_list.end(); it++) { - if (it->second->dev_name == *tt) { - m_list.push_back(it->second); - wxString dev_name_text = from_u8(it->second->dev_name); - if (it->second->is_lan_mode_printer()) { - dev_name_text += "(LAN)"; - } - machine_list_name.Add(dev_name_text); - break; - } - } - } - - m_comboBox_printer->Set(machine_list_name); - - MachineObject* obj = dev->get_selected_machine(); - if (obj) { - m_printer_last_select = obj->dev_id; - } - else { - m_printer_last_select = ""; - }*/ - //op->set_printer_state(PrinterState::LOCK); - } + std::vector machine_list; + wxArrayString machine_list_name; + std::map option_list; + } } - - - BOOST_LOG_TRIVIAL(trace) << "SelectMachineDialog update_lan_devices end"; } -EditDevNameDialog::EditDevNameDialog(Plater *plater /*= nullptr*/) - : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Modifying the device name"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) -{ - std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); - SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); - - SetBackgroundColour(*wxWHITE); - wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL); - auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); - m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); - m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); - m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(38)); - m_textCtr = new ::TextInput(this, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(260), FromDIP(40)), wxTE_PROCESS_ENTER); - m_textCtr->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(22))); - m_textCtr->SetMinSize(wxSize(FromDIP(260), FromDIP(40))); - m_sizer_main->Add(m_textCtr, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, FromDIP(40)); - - m_static_valid = new wxStaticText(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0); - m_static_valid->Wrap(-1); - m_static_valid->SetFont(::Label::Body_13); - m_static_valid->SetForegroundColour(wxColour(255, 111, 0)); - m_sizer_main->Add(m_static_valid, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxLEFT | wxRIGHT, FromDIP(10)); - - - m_button_confirm = new Button(this, _L("Confirm")); - StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(0, 150, 136), StateColor::Normal)); - m_button_confirm->SetBackgroundColor(btn_bg_green); - m_button_confirm->SetBorderColor(wxColour(0, 150, 136)); - m_button_confirm->SetTextColor(wxColour(255, 255, 255)); - m_button_confirm->SetSize(wxSize(FromDIP(72), FromDIP(24))); - m_button_confirm->SetMinSize(wxSize(FromDIP(72), FromDIP(24))); - m_button_confirm->SetCornerRadius(FromDIP(12)); - m_button_confirm->Bind(wxEVT_BUTTON, &EditDevNameDialog::on_edit_name, this); - - m_sizer_main->Add(m_button_confirm, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(10)); - m_sizer_main->Add(0, 0, 0, wxBOTTOM, FromDIP(38)); - - SetSizer(m_sizer_main); - Layout(); - Fit(); - Centre(wxBOTH); - wxGetApp().UpdateDlgDarkUI(this); -} - -EditDevNameDialog::~EditDevNameDialog() {} - -void EditDevNameDialog::set_machine_obj(MachineObject *obj) -{ - m_info = obj; - if (m_info) - m_textCtr->GetTextCtrl()->SetValue(from_u8(m_info->dev_name)); -} - -void EditDevNameDialog::on_dpi_changed(const wxRect &suggested_rect) -{ - m_button_confirm->SetSize(wxSize(FromDIP(72), FromDIP(24))); - m_button_confirm->SetMinSize(wxSize(FromDIP(72), FromDIP(24))); -} - -void EditDevNameDialog::on_edit_name(wxCommandEvent &e) -{ - m_static_valid->SetLabel(wxEmptyString); - auto m_valid_type = Valid; - wxString info_line; - auto new_dev_name = m_textCtr->GetTextCtrl()->GetValue(); - - const char * unusable_symbols = "<>[]:/\\|?*\""; - const std::string unusable_suffix = PresetCollection::get_suffix_modified(); - - for (size_t i = 0; i < std::strlen(unusable_symbols); i++) { - if (new_dev_name.find_first_of(unusable_symbols[i]) != std::string::npos) { - info_line = _L("Name is invalid;") + _L("illegal characters:") + " " + unusable_symbols; - m_valid_type = NoValid; - break; - } - } - - if (m_valid_type == Valid && new_dev_name.find(unusable_suffix) != std::string::npos) { - info_line = _L("Name is invalid;") + _L("illegal suffix:") + "\n\t" + from_u8(PresetCollection::get_suffix_modified()); - m_valid_type = NoValid; - } - - if (m_valid_type == Valid && new_dev_name.empty()) { - info_line = _L("The name is not allowed to be empty."); - m_valid_type = NoValid; - } - - if (m_valid_type == Valid && new_dev_name.find_first_of(' ') == 0) { - info_line = _L("The name is not allowed to start with space character."); - m_valid_type = NoValid; - } - - if (m_valid_type == Valid && new_dev_name.find_last_of(' ') == new_dev_name.length() - 1) { - info_line = _L("The name is not allowed to end with space character."); - m_valid_type = NoValid; - } - - if (m_valid_type == NoValid) { - m_static_valid->SetLabel(info_line); - Layout(); - } - - if (m_valid_type == Valid) { - m_static_valid->SetLabel(wxEmptyString); - DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (dev) { - auto utf8_str = new_dev_name.ToUTF8(); - auto name = std::string(utf8_str.data(), utf8_str.length()); - if (m_info) - dev->modify_device_name(m_info->dev_id, name); - } - DPIDialog::EndModal(wxID_CLOSE); +std::string SelectMachineDialog::get_print_status_info(PrintDialogStatus status) +{ + switch (status) { + case PrintStatusInit: return "PrintStatusInit"; + case PrintStatusNoUserLogin: return "PrintStatusNoUserLogin"; + case PrintStatusInvalidPrinter: return "PrintStatusInvalidPrinter"; + case PrintStatusConnectingServer: return "PrintStatusConnectingServer"; + case PrintStatusReading: return "PrintStatusReading"; + case PrintStatusReadingFinished: return "PrintStatusReadingFinished"; + case PrintStatusReadingTimeout: return "PrintStatusReadingTimeout"; + case PrintStatusInUpgrading: return "PrintStatusInUpgrading"; + case PrintStatusNeedUpgradingAms: return "PrintStatusNeedUpgradingAms"; + case PrintStatusInSystemPrinting: return "PrintStatusInSystemPrinting"; + case PrintStatusInPrinting: return "PrintStatusInPrinting"; + case PrintStatusDisableAms: return "PrintStatusDisableAms"; + case PrintStatusAmsMappingSuccess: return "PrintStatusAmsMappingSuccess"; + case PrintStatusAmsMappingInvalid: return "PrintStatusAmsMappingInvalid"; + case PrintStatusAmsMappingU0Invalid: return "PrintStatusAmsMappingU0Invalid"; + case PrintStatusAmsMappingValid: return "PrintStatusAmsMappingValid"; + case PrintStatusAmsMappingByOrder: return "PrintStatusAmsMappingByOrder"; + case PrintStatusRefreshingMachineList: return "PrintStatusRefreshingMachineList"; + case PrintStatusSending: return "PrintStatusSending"; + case PrintStatusSendingCanceled: return "PrintStatusSendingCanceled"; + case PrintStatusLanModeNoSdcard: return "PrintStatusLanModeNoSdcard"; + case PrintStatusNoSdcard: return "PrintStatusNoSdcard"; + case PrintStatusUnsupportedPrinter: return "PrintStatusUnsupportedPrinter"; + case PrintStatusTimelapseNoSdcard: return "PrintStatusTimelapseNoSdcard"; + case PrintStatusNotSupportedPrintAll: return "PrintStatusNotSupportedPrintAll"; } + return "unknown"; } + ThumbnailPanel::ThumbnailPanel(wxWindow *parent, wxWindowID winid, const wxPoint &pos, const wxSize &size) : wxPanel(parent, winid, pos, size) { @@ -4986,7 +3959,7 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e) } void ThumbnailPanel::render(wxDC& dc) { - + if (wxGetApp().dark_mode() && m_brightness_value < SHOW_BACKGROUND_BITMAP_PIXEL_THRESHOLD) { #ifdef __WXMSW__ wxMemoryDC memdc; @@ -5000,95 +3973,11 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e) } else dc.DrawBitmap(m_bitmap, 0, 0); - - } - - ThumbnailPanel::~ThumbnailPanel() {} - - PinCodePanel::PinCodePanel(wxWindow* parent, int type, wxWindowID winid /*= wxID_ANY*/, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/) - { - wxPanel::Create(parent, winid, pos, SELECT_MACHINE_ITEM_SIZE); - Bind(wxEVT_PAINT, &PinCodePanel::OnPaint, this); - SetSize(SELECT_MACHINE_ITEM_SIZE); - SetMaxSize(SELECT_MACHINE_ITEM_SIZE); - SetMinSize(SELECT_MACHINE_ITEM_SIZE); - - m_type = type; - m_bitmap = ScalableBitmap(this, "bind_device_ping_code",10); - - this->Bind(wxEVT_ENTER_WINDOW, &PinCodePanel::on_mouse_enter, this); - this->Bind(wxEVT_LEAVE_WINDOW, &PinCodePanel::on_mouse_leave, this); - this->Bind(wxEVT_LEFT_UP, &PinCodePanel::on_mouse_left_up, this); - } - void PinCodePanel::OnPaint(wxPaintEvent& event) - { - wxPaintDC dc(this); - render(dc); } - void PinCodePanel::render(wxDC& dc) - { -#ifdef __WXMSW__ - wxSize size = GetSize(); - wxMemoryDC memdc; - wxBitmap bmp(size.x, size.y); - memdc.SelectObject(bmp); - memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); - - { - wxGCDC dc2(memdc); - doRender(dc2); - } - - memdc.SelectObject(wxNullBitmap); - dc.DrawBitmap(bmp, 0, 0); -#else - doRender(dc); -#endif - } - - void PinCodePanel::doRender(wxDC& dc) - { - auto size = GetSize(); - dc.DrawBitmap(m_bitmap.bmp(), wxPoint(FromDIP(12), (size.y - m_bitmap.GetBmpSize().y) / 2)); - dc.SetFont(::Label::Head_13); - dc.SetTextForeground(StateColor::darkModeColorFor(wxColour("#262E30"))); // ORCA fix text not visible on dark theme - wxString txt; - if (m_type == 0) { txt = _L("Bind with Pin Code"); } - else if (m_type == 1) { txt = _L("Bind with Access Code"); } - - auto txt_size = dc.GetTextExtent(txt); - dc.DrawText(txt, wxPoint(FromDIP(28), (size.y - txt_size.y) / 2)); - - if (m_hover) { - dc.SetPen(SELECT_MACHINE_BRAND); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(0, 0, size.x, size.y); - } - } - - void PinCodePanel::on_mouse_enter(wxMouseEvent& evt) - { - m_hover = true; - Refresh(); - } + ThumbnailPanel::~ThumbnailPanel() {} - void PinCodePanel::on_mouse_leave(wxMouseEvent& evt) - { - m_hover = false; - Refresh(); - } - void PinCodePanel::on_mouse_left_up(wxMouseEvent& evt) - { - if (m_type == 0) { - wxGetApp().popup_ping_bind_dialog(); - } - else if (m_type == 1) { - InputIpAddressDialog dlgo; - dlgo.ShowModal(); - } - } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index a31623055f7..0c22c4c4885 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -45,25 +45,60 @@ namespace Slic3r { namespace GUI { -enum PrinterState { - OFFLINE, - IDLE, - BUSY, - LOCK, - IN_LAN +void print_ams_mapping_result(std::vector &result); +enum PrintFromType { + FROM_NORMAL, + FROM_SDCARD_VIEW, }; -enum PrinterBindState { - NONE, - ALLOW_BIND, - ALLOW_UNBIND +enum PrintPageMode { + PrintPageModePrepare = 0, + PrintPageModeSending, + PrintPageModeFinish }; -enum PrintFromType { - FROM_NORMAL, - FROM_SDCARD_VIEW, +enum PrintDialogStatus { + PrintStatusInit = 0, + PrintStatusNoUserLogin, + PrintStatusInvalidPrinter, + PrintStatusConnectingServer, + PrintStatusReading, + PrintStatusReadingFinished, + PrintStatusReadingTimeout, + PrintStatusInUpgrading, + PrintStatusNeedUpgradingAms, + PrintStatusInSystemPrinting, + PrintStatusInPrinting, + PrintStatusDisableAms, + PrintStatusAmsMappingSuccess, + PrintStatusAmsMappingInvalid, + PrintStatusAmsMappingU0Invalid, + PrintStatusAmsMappingValid, + PrintStatusAmsMappingByOrder, + PrintStatusRefreshingMachineList, + PrintStatusSending, + PrintStatusSendingCanceled, + PrintStatusLanModeNoSdcard, + PrintStatusNoSdcard, + PrintStatusTimelapseNoSdcard, + PrintStatusNotOnTheSameLAN, + PrintStatusNeedForceUpgrading, + PrintStatusNeedConsistencyUpgrading, + PrintStatusNotSupportedSendToSDCard, + PrintStatusNotSupportedPrintAll, + PrintStatusBlankPlate, + PrintStatusUnsupportedPrinter, + PrintStatusTimelapseWarning }; +class Material +{ +public: + int id; + MaterialItem *item; +}; + + enum class CloudTaskNozzleId : int { NOZZLE_RIGHT = 0, @@ -76,6 +111,12 @@ enum class ConfigNozzleIdx : int NOZZLE_RIGHT = 1, }; + +WX_DECLARE_HASH_MAP(int, Material *, wxIntegerHash, wxIntegerEqual, MaterialHash); + +#define SELECT_MACHINE_DIALOG_BUTTON_SIZE wxSize(FromDIP(68), FromDIP(23)) +#define SELECT_MACHINE_DIALOG_SIMBOOK_SIZE wxSize(FromDIP(370), FromDIP(64)) +#define LIST_REFRESH_INTERVAL 200 static int get_brightness_value(wxImage image) { wxImage grayImage = image.ConvertToGreyscale(); @@ -104,250 +145,27 @@ static int get_brightness_value(wxImage image) { return totalLuminance / num_none_transparent; } -class Material -{ -public: - int id; - MaterialItem *item; -}; - -WX_DECLARE_HASH_MAP(int, Material *, wxIntegerHash, wxIntegerEqual, MaterialHash); - -// move to seperate file -class MachineListModel : public wxDataViewVirtualListModel +class ThumbnailPanel : public wxPanel { public: - enum { - Col_MachineName = 0, - Col_MachineSN = 1, - Col_MachineBind = 2, - Col_MachinePrintingStatus = 3, - Col_MachineIPAddress = 4, - Col_MachineConnection = 5, - Col_MachineTaskName = 6, - Col_Max = 7 - }; - MachineListModel(); - - virtual unsigned int GetColumnCount() const wxOVERRIDE { return Col_Max; } - - virtual wxString GetColumnType(unsigned int col) const wxOVERRIDE { return "string"; } - - virtual void GetValueByRow(wxVariant &variant, unsigned int row, unsigned int col) const wxOVERRIDE; - virtual bool GetAttrByRow(unsigned int row, unsigned int col, wxDataViewItemAttr &attr) const wxOVERRIDE; - virtual bool SetValueByRow(const wxVariant &variant, unsigned int row, unsigned int col) wxOVERRIDE; - - void display_machines(std::map list); - void add_machine(MachineObject *obj, bool reset = true); - int find_row_by_sn(wxString sn); - -private: - wxArrayString m_values[Col_Max]; - - wxArrayString m_nameColValues; - wxArrayString m_snColValues; - wxArrayString m_bindColValues; - wxArrayString m_connectionColValues; - wxArrayString m_printingStatusValues; - wxArrayString m_ipAddressValues; -}; - -class MachineObjectPanel : public wxPanel -{ -private: - bool m_is_my_devices {false}; - bool m_show_edit{false}; - bool m_show_bind{false}; - bool m_hover {false}; - bool m_is_macos_special_version{false}; - - - PrinterBindState m_bind_state; - PrinterState m_state; - - ScalableBitmap m_unbind_img; - ScalableBitmap m_edit_name_img; - ScalableBitmap m_select_unbind_img; - - ScalableBitmap m_printer_status_offline; - ScalableBitmap m_printer_status_busy; - ScalableBitmap m_printer_status_idle; - ScalableBitmap m_printer_status_lock; - ScalableBitmap m_printer_in_lan; - - MachineObject *m_info; - -protected: - wxStaticBitmap *m_bitmap_info; - wxStaticBitmap *m_bitmap_bind; + wxBitmap m_bitmap; + wxStaticBitmap *m_staticbitmap{nullptr}; -public: - MachineObjectPanel(wxWindow * parent, - wxWindowID id = wxID_ANY, - const wxPoint & pos = wxDefaultPosition, - const wxSize & size = wxDefaultSize, - long style = wxTAB_TRAVERSAL, - const wxString &name = wxEmptyString); - - ~MachineObjectPanel(); + ThumbnailPanel(wxWindow *parent, wxWindowID winid = wxID_ANY, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); + ~ThumbnailPanel(); - void show_bind_dialog(); - void set_printer_state(PrinterState state); - void show_printer_bind(bool show, PrinterBindState state); - void show_edit_printer_name(bool show); - void update_machine_info(MachineObject *info, bool is_my_devices = false); -protected: void OnPaint(wxPaintEvent &event); + void PaintBackground(wxDC &dc); + void OnEraseBackground(wxEraseEvent &event); + void set_thumbnail(wxImage &img); void render(wxDC &dc); - void doRender(wxDC &dc); - void on_mouse_enter(wxMouseEvent &evt); - void on_mouse_leave(wxMouseEvent &evt); - void on_mouse_left_up(wxMouseEvent &evt); -}; - -#define SELECT_MACHINE_POPUP_SIZE wxSize(FromDIP(216), FromDIP(364)) -#define SELECT_MACHINE_LIST_SIZE wxSize(FromDIP(212), FromDIP(360)) -#define SELECT_MACHINE_ITEM_SIZE wxSize(FromDIP(190), FromDIP(35)) -#define SELECT_MACHINE_GREY900 wxColour(38, 46, 48) -#define SELECT_MACHINE_GREY600 wxColour(144,144,144) -#define SELECT_MACHINE_GREY400 wxColour(206, 206, 206) -#define SELECT_MACHINE_BRAND wxColour(0, 150, 136) -#define SELECT_MACHINE_REMIND wxColour(255,111,0) -#define SELECT_MACHINE_LIGHT_GREEN wxColour(219, 253, 231) - -class MachinePanel -{ -public: - wxString mIndex; - MachineObjectPanel *mPanel; -}; - -class PinCodePanel : public wxPanel -{ -public: - PinCodePanel(wxWindow* parent, - int type, - wxWindowID winid = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize); - ~PinCodePanel() {}; - - ScalableBitmap m_bitmap; - bool m_hover{false}; - int m_type{0}; - - void OnPaint(wxPaintEvent& event); - void render(wxDC& dc); - void doRender(wxDC& dc); - - void on_mouse_enter(wxMouseEvent& evt); - void on_mouse_leave(wxMouseEvent& evt); - void on_mouse_left_up(wxMouseEvent& evt); -}; - - -class ThumbnailPanel; - -class SelectMachinePopup : public PopupWindow -{ -public: - SelectMachinePopup(wxWindow *parent); - ~SelectMachinePopup(); - - // PopupWindow virtual methods are all overridden to log them - virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE; - virtual void OnDismiss() wxOVERRIDE; - virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE; - virtual bool Show(bool show = true) wxOVERRIDE; - - void update_machine_list(wxCommandEvent &event); - void start_ssdp(bool on_off); - bool was_dismiss() { return m_dismiss; } - -private: - int m_my_devices_count{0}; - int m_other_devices_count{0}; - PinCodePanel* m_panel_ping_code{nullptr}; - PinCodePanel* m_panel_direct_connection{nullptr}; - wxWindow* m_placeholder_panel{nullptr}; - wxHyperlinkCtrl* m_hyperlink{nullptr}; - Label* m_ping_code_text{nullptr}; - wxStaticBitmap* m_img_ping_code{nullptr}; - wxBoxSizer * m_sizer_body{nullptr}; - wxBoxSizer * m_sizer_my_devices{nullptr}; - wxBoxSizer * m_sizer_other_devices{nullptr}; - wxBoxSizer * m_sizer_search_bar{nullptr}; - wxSearchCtrl* m_search_bar{nullptr}; - wxScrolledWindow * m_scrolledWindow{nullptr}; - wxWindow * m_panel_body{nullptr}; - wxTimer * m_refresh_timer{nullptr}; - std::vector m_user_list_machine_panel; - std::vector m_other_list_machine_panel; - boost::thread* get_print_info_thread{ nullptr }; - std::shared_ptr m_token = std::make_shared(0); - std::string m_print_info = ""; - bool m_dismiss { false }; - - std::map m_bind_machine_list; - std::map m_free_machine_list; private: - void OnLeftUp(wxMouseEvent &event); - void on_timer(wxTimerEvent &event); - - void update_other_devices(); - void update_user_devices(); - bool search_for_printer(MachineObject* obj); - void on_dissmiss_win(wxCommandEvent &event); - wxWindow *create_title_panel(wxString text); -}; - -#define SELECT_MACHINE_DIALOG_BUTTON_SIZE wxSize(FromDIP(68), FromDIP(23)) -#define SELECT_MACHINE_DIALOG_SIMBOOK_SIZE wxSize(FromDIP(370), FromDIP(64)) - - -enum PrintPageMode { - PrintPageModePrepare = 0, - PrintPageModeSending, - PrintPageModeFinish -}; - -enum PrintDialogStatus { - PrintStatusInit = 0, - PrintStatusNoUserLogin, - PrintStatusInvalidPrinter, - PrintStatusConnectingServer, - PrintStatusReading, - PrintStatusReadingFinished, - PrintStatusReadingTimeout, - PrintStatusInUpgrading, - PrintStatusNeedUpgradingAms, - PrintStatusInSystemPrinting, - PrintStatusInPrinting, - PrintStatusDisableAms, - PrintStatusAmsMappingSuccess, - PrintStatusAmsMappingInvalid, - PrintStatusAmsMappingU0Invalid, - PrintStatusAmsMappingValid, - PrintStatusAmsMappingByOrder, - PrintStatusRefreshingMachineList, - PrintStatusSending, - PrintStatusSendingCanceled, - PrintStatusLanModeNoSdcard, - PrintStatusNoSdcard, - PrintStatusTimelapseNoSdcard, - PrintStatusNotOnTheSameLAN, - PrintStatusNeedForceUpgrading, - PrintStatusNeedConsistencyUpgrading, - PrintStatusNotSupportedSendToSDCard, - PrintStatusNotSupportedPrintAll, - PrintStatusBlankPlate, - PrintStatusUnsupportedPrinter, - PrintStatusTimelapseWarning + ScalableBitmap m_background_bitmap; + wxBitmap bitmap_with_background; + int m_brightness_value{-1}; }; -std::string get_print_status_info(PrintDialogStatus status); - class SelectMachineDialog : public DPIDialog { private: @@ -553,6 +371,8 @@ class SelectMachineDialog : public DPIDialog bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info); bool build_nozzles_info(std::string& nozzles_info); + std::string get_print_status_info(PrintDialogStatus status); + PrintFromType get_print_type() {return m_print_type;}; wxString format_steel_name(NozzleType type); wxString format_text(wxString &m_msg); @@ -563,56 +383,6 @@ class SelectMachineDialog : public DPIDialog std::vector sort_string(std::vector strArray); }; -wxDECLARE_EVENT(EVT_FINISHED_UPDATE_MACHINE_LIST, wxCommandEvent); -wxDECLARE_EVENT(EVT_REQUEST_BIND_LIST, wxCommandEvent); -wxDECLARE_EVENT(EVT_WILL_DISMISS_MACHINE_LIST, wxCommandEvent); -wxDECLARE_EVENT(EVT_UPDATE_WINDOWS_POSITION, wxCommandEvent); -wxDECLARE_EVENT(EVT_DISSMISS_MACHINE_LIST, wxCommandEvent); -wxDECLARE_EVENT(EVT_CONNECT_LAN_PRINT, wxCommandEvent); -wxDECLARE_EVENT(EVT_EDIT_PRINT_NAME, wxCommandEvent); -wxDECLARE_EVENT(EVT_UNBIND_MACHINE, wxCommandEvent); -wxDECLARE_EVENT(EVT_BIND_MACHINE, wxCommandEvent); - -class EditDevNameDialog : public DPIDialog -{ -public: - EditDevNameDialog(Plater *plater = nullptr); - ~EditDevNameDialog(); - - void set_machine_obj(MachineObject *obj); - void on_dpi_changed(const wxRect &suggested_rect) override; - void on_edit_name(wxCommandEvent &e); - - Button* m_button_confirm{nullptr}; - TextInput* m_textCtr{nullptr}; - wxStaticText* m_static_valid{nullptr}; - MachineObject* m_info{nullptr}; -}; - - -class ThumbnailPanel : public wxPanel -{ -public: - wxBitmap m_bitmap; - wxStaticBitmap *m_staticbitmap{nullptr}; - - ThumbnailPanel(wxWindow * parent, - wxWindowID winid = wxID_ANY, - const wxPoint & pos = wxDefaultPosition, - const wxSize & size = wxDefaultSize); - ~ThumbnailPanel(); - - void OnPaint(wxPaintEvent &event); - void PaintBackground(wxDC &dc); - void OnEraseBackground(wxEraseEvent &event); - void set_thumbnail(wxImage &img); - void render(wxDC &dc); -private: - ScalableBitmap m_background_bitmap; - wxBitmap bitmap_with_background; - int m_brightness_value{ -1 }; -}; - }} // namespace Slic3r::GUI #endif diff --git a/src/slic3r/GUI/SelectMachinePop.cpp b/src/slic3r/GUI/SelectMachinePop.cpp new file mode 100644 index 00000000000..320df171849 --- /dev/null +++ b/src/slic3r/GUI/SelectMachinePop.cpp @@ -0,0 +1,1054 @@ +#include "SelectMachinePop.hpp" +#include "I18N.hpp" + +#include "libslic3r/Utils.hpp" +#include "libslic3r/Thread.hpp" + +#include "slic3r/Utils/WxFontUtils.hpp" + +#include "GUI.hpp" +#include "GUI_App.hpp" +#include "GUI_Preview.hpp" +#include "MainFrame.hpp" +#include "format.hpp" +#include "Widgets/ProgressDialog.hpp" +#include "Widgets/RoundedRectangle.hpp" +#include "Widgets/StaticBox.hpp" +#include "ConnectPrinter.hpp" + + +#include +#include +#include +#include +#include +#include +#include "Plater.hpp" +#include "Notebook.hpp" +#include "BitmapCache.hpp" +#include "BindDialog.hpp" + +namespace Slic3r { namespace GUI { + +wxDEFINE_EVENT(EVT_UPDATE_WINDOWS_POSITION, wxCommandEvent); +wxDEFINE_EVENT(EVT_FINISHED_UPDATE_MACHINE_LIST, wxCommandEvent); +wxDEFINE_EVENT(EVT_UPDATE_USER_MACHINE_LIST, wxCommandEvent); +wxDEFINE_EVENT(EVT_BIND_MACHINE, wxCommandEvent); +wxDEFINE_EVENT(EVT_UNBIND_MACHINE, wxCommandEvent); +wxDEFINE_EVENT(EVT_DISSMISS_MACHINE_LIST, wxCommandEvent); +wxDEFINE_EVENT(EVT_CONNECT_LAN_PRINT, wxCommandEvent); +wxDEFINE_EVENT(EVT_EDIT_PRINT_NAME, wxCommandEvent); +wxDEFINE_EVENT(EVT_CLEAR_IPADDRESS, wxCommandEvent); + + +#define INITIAL_NUMBER_OF_MACHINES 0 +#define LIST_REFRESH_INTERVAL 200 +#define MACHINE_LIST_REFRESH_INTERVAL 2000 + +#define WRAP_GAP FromDIP(2) + +MachineObjectPanel::MachineObjectPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style, const wxString &name) +{ + wxPanel::Create(parent, id, pos, wxDefaultSize, style, name); + + SetSize(SELECT_MACHINE_ITEM_SIZE); + SetMinSize(SELECT_MACHINE_ITEM_SIZE); + SetMaxSize(SELECT_MACHINE_ITEM_SIZE); + + Bind(wxEVT_PAINT, &MachineObjectPanel::OnPaint, this); + + SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); + + m_unbind_img = ScalableBitmap(this, "unbind", 18); + m_edit_name_img = ScalableBitmap(this, "edit_button", 18); + m_select_unbind_img = ScalableBitmap(this, "unbind_selected", 18); + + m_printer_status_offline = ScalableBitmap(this, "printer_status_offline", 12); + m_printer_status_busy = ScalableBitmap(this, "printer_status_busy", 12); + m_printer_status_idle = ScalableBitmap(this, "printer_status_idle", 12); + m_printer_status_lock = ScalableBitmap(this, "printer_status_lock", 16); + m_printer_in_lan = ScalableBitmap(this, "printer_in_lan", 16); + + this->Bind(wxEVT_ENTER_WINDOW, &MachineObjectPanel::on_mouse_enter, this); + this->Bind(wxEVT_LEAVE_WINDOW, &MachineObjectPanel::on_mouse_leave, this); + this->Bind(wxEVT_LEFT_UP, &MachineObjectPanel::on_mouse_left_up, this); + +#ifdef __APPLE__ + wxPlatformInfo platformInfo; + auto major = platformInfo.GetOSMajorVersion(); + auto minor = platformInfo.GetOSMinorVersion(); + auto micro = platformInfo.GetOSMicroVersion(); + + //macos 13.1.0 + if (major >= 13 && minor >= 1 && micro >= 0) { + m_is_macos_special_version = true; + } +#endif + +} + + +MachineObjectPanel::~MachineObjectPanel() {} + +void MachineObjectPanel::show_bind_dialog() +{ + if (wxGetApp().is_user_login()) { + BindMachineDialog dlg; + dlg.update_machine_info(m_info); + dlg.ShowModal(); + } +} + +void MachineObjectPanel::set_printer_state(PrinterState state) +{ + m_state = state; + Refresh(); +} + +void MachineObjectPanel::show_edit_printer_name(bool show) +{ + m_show_edit = show; + Refresh(); +} + +void MachineObjectPanel::show_printer_bind(bool show, PrinterBindState state) +{ + m_show_bind = show; + m_bind_state = state; + Refresh(); +} + +void MachineObjectPanel::OnPaint(wxPaintEvent &event) +{ + wxPaintDC dc(this); + doRender(dc); +} + +void MachineObjectPanel::render(wxDC &dc) +{ +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({0, 0}, size, &dc, {0, 0}); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif +} + +void MachineObjectPanel::doRender(wxDC &dc) +{ + auto left = 10; + wxSize size = GetSize(); + dc.SetPen(*wxTRANSPARENT_PEN); + + auto dwbitmap = m_printer_status_offline; + if (m_state == PrinterState::IDLE) { dwbitmap = m_printer_status_idle; } + if (m_state == PrinterState::BUSY) { dwbitmap = m_printer_status_busy; } + if (m_state == PrinterState::OFFLINE) { dwbitmap = m_printer_status_offline; } + if (m_state == PrinterState::LOCK) { dwbitmap = m_printer_status_lock; } + if (m_state == PrinterState::IN_LAN) { dwbitmap = m_printer_in_lan; } + + // dc.DrawCircle(left, size.y / 2, 3); + dc.DrawBitmap(dwbitmap.bmp(), wxPoint(left, (size.y - dwbitmap.GetBmpSize().y) / 2)); + + left += dwbitmap.GetBmpSize().x + 8; + dc.SetFont(Label::Body_13); + dc.SetBackgroundMode(wxTRANSPARENT); + dc.SetTextForeground(StateColor::darkModeColorFor(SELECT_MACHINE_GREY900)); + wxString dev_name = ""; + if (m_info) { + dev_name = from_u8(m_info->dev_name); + + if (m_state == PrinterState::IN_LAN) { + dev_name += _L("(LAN)"); + } + } + auto sizet = dc.GetTextExtent(dev_name); + auto text_end = 0; + + if (m_show_edit) { + text_end = size.x - m_unbind_img.GetBmpSize().x - 30; + } + else { + text_end = size.x - m_unbind_img.GetBmpSize().x; + } + + wxString finally_name = dev_name; + if (sizet.x > (text_end - left)) { + auto limit_width = text_end - left - dc.GetTextExtent("...").x - 15; + for (auto i = 0; i < dev_name.length(); i++) { + auto curr_width = dc.GetTextExtent(dev_name.substr(0, i)); + if (curr_width.x >= limit_width) { + finally_name = dev_name.substr(0, i) + "..."; + break; + } + } + } + + dc.DrawText(finally_name, wxPoint(left, (size.y - sizet.y) / 2)); + + + if (m_hover || m_is_macos_special_version) { + + if (m_hover && !m_is_macos_special_version) { + dc.SetPen(SELECT_MACHINE_BRAND); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(0, 0, size.x, size.y); + } + + if (m_show_bind) { + if (m_bind_state == ALLOW_UNBIND) { + left = size.x - m_unbind_img.GetBmpSize().x - 6; + dc.DrawBitmap(m_unbind_img.bmp(), left, (size.y - m_unbind_img.GetBmpSize().y) / 2); + } + } + + if (m_show_edit) { + left = size.x - m_unbind_img.GetBmpSize().x - 6 - m_edit_name_img.GetBmpSize().x - 6; + dc.DrawBitmap(m_edit_name_img.bmp(), left, (size.y - m_edit_name_img.GetBmpSize().y) / 2); + } + } + +} + +void MachineObjectPanel::update_machine_info(MachineObject *info, bool is_my_devices) +{ + m_info = info; + m_is_my_devices = is_my_devices; + Refresh(); +} + +void MachineObjectPanel::on_mouse_enter(wxMouseEvent &evt) +{ + m_hover = true; + Refresh(); +} + +void MachineObjectPanel::on_mouse_leave(wxMouseEvent &evt) +{ + m_hover = false; + Refresh(); +} + +void MachineObjectPanel::on_mouse_left_up(wxMouseEvent &evt) +{ + if (m_is_my_devices) { + // show edit + if (m_show_edit) { + auto edit_left = GetSize().x - m_unbind_img.GetBmpSize().x - 6 - m_edit_name_img.GetBmpSize().x - 6; + auto edit_right = edit_left + m_edit_name_img.GetBmpSize().x; + auto edit_top = (GetSize().y - m_edit_name_img.GetBmpSize().y) / 2; + auto edit_bottom = (GetSize().y - m_edit_name_img.GetBmpSize().y) / 2 + m_edit_name_img.GetBmpSize().y; + if ((evt.GetPosition().x >= edit_left && evt.GetPosition().x <= edit_right) && evt.GetPosition().y >= edit_top && evt.GetPosition().y <= edit_bottom) { + wxCommandEvent event(EVT_EDIT_PRINT_NAME); + event.SetEventObject(this); + wxPostEvent(this, event); + return; + } + } + if (m_show_bind) { + auto left = GetSize().x - m_unbind_img.GetBmpSize().x - 6; + auto right = left + m_unbind_img.GetBmpSize().x; + auto top = (GetSize().y - m_unbind_img.GetBmpSize().y) / 2; + auto bottom = (GetSize().y - m_unbind_img.GetBmpSize().y) / 2 + m_unbind_img.GetBmpSize().y; + + if ((evt.GetPosition().x >= left && evt.GetPosition().x <= right) && evt.GetPosition().y >= top && evt.GetPosition().y <= bottom) { + wxCommandEvent event(EVT_UNBIND_MACHINE, GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } else { + if (m_info) { + wxGetApp().mainframe->jump_to_monitor(m_info->dev_id); + } + //wxGetApp().mainframe->SetFocus(); + wxCommandEvent event(EVT_DISSMISS_MACHINE_LIST); + event.SetEventObject(this->GetParent()); + wxPostEvent(this->GetParent(), event); + } + return; + } + if (m_info && m_info->is_lan_mode_printer()) { + if (m_info->has_access_right() && m_info->is_avaliable()) { + wxGetApp().mainframe->jump_to_monitor(m_info->dev_id); + } else { + wxCommandEvent event(EVT_CONNECT_LAN_PRINT); + event.SetEventObject(this); + wxPostEvent(this, event); + } + } else { + wxGetApp().mainframe->jump_to_monitor(m_info->dev_id); + } + } else { + if (m_info && m_info->is_lan_mode_printer()) { + wxCommandEvent event(EVT_CONNECT_LAN_PRINT); + event.SetEventObject(this); + wxPostEvent(this, event); + } else { + wxCommandEvent event(EVT_BIND_MACHINE); + event.SetEventObject(this); + wxPostEvent(this, event); + } + } + +} + +SelectMachinePopup::SelectMachinePopup(wxWindow *parent) + : PopupWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS), m_dismiss(false) +{ +#ifdef __WINDOWS__ + SetDoubleBuffered(true); +#endif //__WINDOWS__ + + + SetSize(SELECT_MACHINE_POPUP_SIZE); + SetMinSize(SELECT_MACHINE_POPUP_SIZE); + SetMaxSize(SELECT_MACHINE_POPUP_SIZE); + + Freeze(); + wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL); + SetBackgroundColour(SELECT_MACHINE_GREY400); + + + + m_scrolledWindow = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_LIST_SIZE, wxHSCROLL | wxVSCROLL); + m_scrolledWindow->SetBackgroundColour(*wxWHITE); + m_scrolledWindow->SetMinSize(SELECT_MACHINE_LIST_SIZE); + m_scrolledWindow->SetScrollRate(0, 5); + auto m_sizxer_scrolledWindow = new wxBoxSizer(wxVERTICAL); + m_scrolledWindow->SetSizer(m_sizxer_scrolledWindow); + m_scrolledWindow->Layout(); + m_sizxer_scrolledWindow->Fit(m_scrolledWindow); + +#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) + m_sizer_search_bar = new wxBoxSizer(wxVERTICAL); + m_search_bar = new wxSearchCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + m_search_bar->SetDescriptiveText(_L("Search")); + m_search_bar->ShowSearchButton( true ); + m_search_bar->ShowCancelButton( false ); + m_sizer_search_bar->Add( m_search_bar, 1, wxALL| wxEXPAND, 1 ); + m_sizer_main->Add(m_sizer_search_bar, 0, wxALL | wxEXPAND, FromDIP(2)); + m_search_bar->Bind( wxEVT_COMMAND_TEXT_UPDATED, &SelectMachinePopup::update_machine_list, this ); +#endif + auto own_title = create_title_panel(_L("My Device")); + m_sizer_my_devices = new wxBoxSizer(wxVERTICAL); + auto other_title = create_title_panel(_L("Other Device")); + m_sizer_other_devices = new wxBoxSizer(wxVERTICAL); + + + m_panel_ping_code = new PinCodePanel(m_scrolledWindow, 0, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE); + m_panel_direct_connection = new PinCodePanel(m_scrolledWindow, 1, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE); + + m_sizxer_scrolledWindow->Add(own_title, 0, wxEXPAND | wxLEFT, FromDIP(15)); + m_sizxer_scrolledWindow->Add(m_sizer_my_devices, 0, wxEXPAND, 0); + m_sizxer_scrolledWindow->Add(m_panel_ping_code, 0, wxEXPAND, 0); + m_sizxer_scrolledWindow->Add(m_panel_direct_connection, 0, wxEXPAND, 0); + m_sizxer_scrolledWindow->Add(other_title, 0, wxEXPAND | wxLEFT, FromDIP(15)); + m_sizxer_scrolledWindow->Add(m_sizer_other_devices, 0, wxEXPAND, 0); + + m_sizer_main->Add(m_scrolledWindow, 0, wxALL | wxEXPAND, FromDIP(2)); + + SetSizer(m_sizer_main); + Layout(); + Thaw(); + + #ifdef __APPLE__ + m_scrolledWindow->Bind(wxEVT_LEFT_UP, &SelectMachinePopup::OnLeftUp, this); + #endif // __APPLE__ + + m_refresh_timer = new wxTimer(); + m_refresh_timer->SetOwner(this); + Bind(EVT_UPDATE_USER_MACHINE_LIST, &SelectMachinePopup::update_machine_list, this); + Bind(wxEVT_TIMER, &SelectMachinePopup::on_timer, this); + Bind(EVT_DISSMISS_MACHINE_LIST, &SelectMachinePopup::on_dissmiss_win, this); +} + +SelectMachinePopup::~SelectMachinePopup() { delete m_refresh_timer;} + +void SelectMachinePopup::Popup(wxWindow *WXUNUSED(focus)) +{ + BOOST_LOG_TRIVIAL(trace) << "get_print_info: start"; + start_ssdp(true); + if (m_refresh_timer) { + m_refresh_timer->Stop(); + m_refresh_timer->Start(MACHINE_LIST_REFRESH_INTERVAL); + } + + if (wxGetApp().is_user_login()) { + if (!get_print_info_thread) { + get_print_info_thread = new boost::thread(Slic3r::create_thread([this, token = std::weak_ptr(m_token)] { + NetworkAgent* agent = wxGetApp().getAgent(); + unsigned int http_code; + std::string body; + int result = agent->get_user_print_info(&http_code, &body); + CallAfter([token, this, result, body]() { + if (token.expired()) {return;} + if (result == 0) { + m_print_info = body; + } + else { + m_print_info = ""; + } + wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST); + event.SetEventObject(this); + wxPostEvent(this, event); + }); + })); + } + } + + wxPostEvent(this, wxTimerEvent()); + PopupWindow::Popup(); +} + +void SelectMachinePopup::OnDismiss() +{ + BOOST_LOG_TRIVIAL(trace) << "get_print_info: dismiss"; + start_ssdp(false); + m_dismiss = true; + + if (m_refresh_timer) { + m_refresh_timer->Stop(); + } + if (get_print_info_thread) { + if (get_print_info_thread->joinable()) { + get_print_info_thread->join(); + delete get_print_info_thread; + get_print_info_thread = nullptr; + } + } + + wxCommandEvent event(EVT_FINISHED_UPDATE_MACHINE_LIST); + event.SetEventObject(this); + wxPostEvent(this, event); +} + +bool SelectMachinePopup::ProcessLeftDown(wxMouseEvent &event) { + return PopupWindow::ProcessLeftDown(event); +} + +bool SelectMachinePopup::Show(bool show) { + if (show) { + for (int i = 0; i < m_user_list_machine_panel.size(); i++) { + m_user_list_machine_panel[i]->mPanel->update_machine_info(nullptr); + m_user_list_machine_panel[i]->mPanel->Hide(); + } + + for (int j = 0; j < m_other_list_machine_panel.size(); j++) { + m_other_list_machine_panel[j]->mPanel->update_machine_info(nullptr); + m_other_list_machine_panel[j]->mPanel->Hide(); + } + } + return PopupWindow::Show(show); +} + +wxWindow *SelectMachinePopup::create_title_panel(wxString text) +{ + auto m_panel_title_own = new wxWindow(m_scrolledWindow, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_ITEM_SIZE, wxTAB_TRAVERSAL); + m_panel_title_own->SetBackgroundColour(*wxWHITE); + + wxBoxSizer *m_sizer_title_own = new wxBoxSizer(wxHORIZONTAL); + + auto m_title_own = new wxStaticText(m_panel_title_own, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, 0); + m_title_own->Wrap(-1); + m_sizer_title_own->Add(m_title_own, 0, wxALIGN_CENTER, 0); + + wxBoxSizer *m_sizer_line_own = new wxBoxSizer(wxHORIZONTAL); + + auto m_panel_line_own = new wxPanel(m_panel_title_own, wxID_ANY, wxDefaultPosition, wxSize(SELECT_MACHINE_ITEM_SIZE.x, FromDIP(1)), wxTAB_TRAVERSAL); + m_panel_line_own->SetBackgroundColour(SELECT_MACHINE_GREY400); + + m_sizer_line_own->Add(m_panel_line_own, 0, wxALIGN_CENTER, 0); + m_sizer_title_own->Add(0, 0, 0, wxLEFT, FromDIP(10)); + m_sizer_title_own->Add(m_sizer_line_own, 1, wxEXPAND | wxRIGHT, FromDIP(10)); + + m_panel_title_own->SetSizer(m_sizer_title_own); + m_panel_title_own->Layout(); + return m_panel_title_own; +} + +void SelectMachinePopup::on_timer(wxTimerEvent &event) +{ + BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup on_timer"; + wxGetApp().reset_to_active(); + wxCommandEvent user_event(EVT_UPDATE_USER_MACHINE_LIST); + user_event.SetEventObject(this); + wxPostEvent(this, user_event); +} + +void SelectMachinePopup::update_other_devices() +{ + DeviceManager* dev = wxGetApp().getDeviceManager(); + if (!dev) return; + m_free_machine_list = dev->get_local_machine_list(); + + BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices start"; + this->Freeze(); + m_scrolledWindow->Freeze(); + int i = 0; + + for (auto &elem : m_free_machine_list) { + MachineObject * mobj = elem.second; + /* do not show printer bind state is empty */ + if (!mobj->is_avaliable()) continue; + + if (!wxGetApp().is_user_login() && !mobj->is_lan_mode_printer()) + continue; + + /* do not show printer in my list */ + auto it = m_bind_machine_list.find(mobj->dev_id); + if (it != m_bind_machine_list.end()) + continue; + + MachineObjectPanel* op = nullptr; + if (i < m_other_list_machine_panel.size()) { + op = m_other_list_machine_panel[i]->mPanel; + } else { + op = new MachineObjectPanel(m_scrolledWindow, wxID_ANY); + MachinePanel* mpanel = new MachinePanel(); + mpanel->mIndex = wxString::Format("%d", i); + mpanel->mPanel = op; + m_other_list_machine_panel.push_back(mpanel); + m_sizer_other_devices->Add(op, 0, wxEXPAND, 0); + } +#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) + if (!search_for_printer(mobj)) { + op->Hide(); + } + else { + op->Show(); + } +#else + op->Show(); +#endif + i++; + + op->update_machine_info(mobj); + + if (mobj->is_lan_mode_printer()) { + if (mobj->has_access_right()) { + op->set_printer_state(PrinterState::IN_LAN); + } else { + op->set_printer_state(PrinterState::LOCK); + } + } else { + op->show_edit_printer_name(false); + op->show_printer_bind(true, PrinterBindState::ALLOW_BIND); + if (mobj->is_in_printing()) { + op->set_printer_state(PrinterState::BUSY); + } else { + op->SetToolTip(_L("Online")); + op->set_printer_state(IDLE); + } + } + + op->Bind(EVT_CONNECT_LAN_PRINT, [this, mobj](wxCommandEvent &e) { + if (mobj) { + if (mobj->is_lan_mode_printer()) { + ConnectPrinterDialog dlg(wxGetApp().mainframe, wxID_ANY, _L("Input access code")); + dlg.set_machine_object(mobj); + if (dlg.ShowModal() == wxID_OK) { + wxGetApp().mainframe->jump_to_monitor(mobj->dev_id); + } + } + } + }); + + op->Bind(EVT_BIND_MACHINE, [this, mobj](wxCommandEvent &e) { + BindMachineDialog dlg; + dlg.update_machine_info(mobj); + int dlg_result = wxID_CANCEL; + dlg_result = dlg.ShowModal(); + if (dlg_result == wxID_OK) { wxGetApp().mainframe->jump_to_monitor(mobj->dev_id); } + }); + } + + for (int j = i; j < m_other_list_machine_panel.size(); j++) { + m_other_list_machine_panel[j]->mPanel->update_machine_info(nullptr); + m_other_list_machine_panel[j]->mPanel->Hide(); + } + + if (m_placeholder_panel != nullptr) { + m_scrolledWindow->RemoveChild(m_placeholder_panel); + m_placeholder_panel->Destroy(); + m_placeholder_panel = nullptr; + } + + m_placeholder_panel = new wxWindow(m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxSize(-1,FromDIP(26))); + wxBoxSizer* placeholder_sizer = new wxBoxSizer(wxVERTICAL); + + m_hyperlink = new wxHyperlinkCtrl(m_placeholder_panel, wxID_ANY, _L("Can't find my devices?"), wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE); + m_hyperlink->SetNormalColour(StateColor::darkModeColorFor("#009789")); + placeholder_sizer->Add(m_hyperlink, 0, wxALIGN_CENTER | wxALL, 5); + + + m_placeholder_panel->SetSizer(placeholder_sizer); + m_placeholder_panel->Layout(); + placeholder_sizer->Fit(m_placeholder_panel); + + m_placeholder_panel->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); + m_sizer_other_devices->Add(m_placeholder_panel, 0, wxEXPAND, 0); + + //m_sizer_other_devices->Layout(); + if(m_other_devices_count != i) { + m_scrolledWindow->Fit(); + } + m_scrolledWindow->Layout(); + m_scrolledWindow->Thaw(); + Layout(); + Fit(); + this->Thaw(); + m_other_devices_count = i; + BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_other_devices end"; +} + +void SelectMachinePopup::update_user_devices() +{ + Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (!dev) return; + + if (!m_print_info.empty()) { + dev->parse_user_print_info(m_print_info); + m_print_info = ""; + } + + m_bind_machine_list.clear(); + m_bind_machine_list = dev->get_my_machine_list(); + + //sort list + std::vector> user_machine_list; + for (auto& it: m_bind_machine_list) { + user_machine_list.push_back(it); + } + + std::sort(user_machine_list.begin(), user_machine_list.end(), [&](auto& a, auto&b) { + if (a.second && b.second) { + return a.second->dev_name.compare(b.second->dev_name) < 0; + } + return false; + }); + + BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_machine_list start"; + this->Freeze(); + m_scrolledWindow->Freeze(); + int i = 0; + + for (auto& elem : user_machine_list) { + MachineObject* mobj = elem.second; + MachineObjectPanel* op = nullptr; + if (i < m_user_list_machine_panel.size()) { + op = m_user_list_machine_panel[i]->mPanel; +#if !BBL_RELEASE_TO_PUBLIC && defined(__WINDOWS__) + if (!search_for_printer(mobj)) { + op->Hide(); + } else { + op->Show(); + } +#else + op->Show(); +#endif + } else { + op = new MachineObjectPanel(m_scrolledWindow, wxID_ANY); + MachinePanel* mpanel = new MachinePanel(); + mpanel->mIndex = wxString::Format("%d", i); + mpanel->mPanel = op; + m_user_list_machine_panel.push_back(mpanel); + m_sizer_my_devices->Add(op, 0, wxEXPAND, 0); + } + i++; + op->update_machine_info(mobj, true); + //set in lan + if (mobj->is_lan_mode_printer()) { + if (!mobj->is_online()) { + continue; + } + else { + op->show_printer_bind(false, PrinterBindState::NONE); + op->show_edit_printer_name(false); + if (mobj->has_access_right() && mobj->is_avaliable()) { + op->set_printer_state(PrinterState::IN_LAN); + op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); + op->SetToolTip(_L("Online")); + } + else { + op->set_printer_state(PrinterState::LOCK); + } + } + op->Bind(EVT_UNBIND_MACHINE, [this, dev, mobj](wxCommandEvent& e) { + dev->set_selected_machine(""); + if (mobj) { + AppConfig* config = wxGetApp().app_config; + if (config) { + config->erase_local_machine(mobj->dev_id); + } + + mobj->set_access_code(""); + mobj->erase_user_access_code(); + } + + MessageDialog msg_wingow(nullptr, _L("Log out successful."), "", wxAPPLY | wxOK); + if (msg_wingow.ShowModal() == wxOK) { return; } + }); + } + else { + op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); + op->Bind(EVT_UNBIND_MACHINE, [this, mobj, dev](wxCommandEvent& e) { + // show_unbind_dialog + UnBindMachineDialog dlg; + dlg.update_machine_info(mobj); + if (dlg.ShowModal() == wxID_OK) { + dev->set_selected_machine(""); + } + }); + + if (!mobj->is_online()) { + op->SetToolTip(_L("Offline")); + op->set_printer_state(PrinterState::OFFLINE); + } + else { + op->show_edit_printer_name(true); + op->show_printer_bind(true, PrinterBindState::ALLOW_UNBIND); + if (mobj->is_in_printing()) { + op->SetToolTip(_L("Busy")); + op->set_printer_state(PrinterState::BUSY); + } + else { + op->SetToolTip(_L("Online")); + op->set_printer_state(PrinterState::IDLE); + } + } + } + + op->Bind(EVT_CONNECT_LAN_PRINT, [this, mobj](wxCommandEvent &e) { + if (mobj) { + if (mobj->is_lan_mode_printer()) { + ConnectPrinterDialog dlg(wxGetApp().mainframe, wxID_ANY, _L("Input access code")); + dlg.set_machine_object(mobj); + if (dlg.ShowModal() == wxID_OK) { + wxGetApp().mainframe->jump_to_monitor(mobj->dev_id); + } + } + } + }); + + op->Bind(EVT_EDIT_PRINT_NAME, [this, mobj](wxCommandEvent &e) { + EditDevNameDialog dlg; + dlg.set_machine_obj(mobj); + dlg.ShowModal(); + }); + } + + for (int j = i; j < m_user_list_machine_panel.size(); j++) { + m_user_list_machine_panel[j]->mPanel->update_machine_info(nullptr); + m_user_list_machine_panel[j]->mPanel->Hide(); + } + //m_sizer_my_devices->Layout(); + + if (m_my_devices_count != i) { + m_scrolledWindow->Fit(); + } + m_scrolledWindow->Layout(); + m_scrolledWindow->Thaw(); + Layout(); + Fit(); + this->Thaw(); + m_my_devices_count = i; +} + +bool SelectMachinePopup::search_for_printer(MachineObject* obj) +{ + std::string search_text = std::string((m_search_bar->GetValue()).mb_str()); + if (search_text.empty()) { + return true; + } + auto name = obj->dev_name; + auto ip = obj->dev_ip; + auto name_it = name.find(search_text); + auto ip_it = ip.find(search_text); + if ((name_it != std::string::npos)||(ip_it != std::string::npos)) { + return true; + } + + return false; +} + +void SelectMachinePopup::on_dissmiss_win(wxCommandEvent &event) +{ + Dismiss(); +} + +void SelectMachinePopup::update_machine_list(wxCommandEvent &event) +{ + update_user_devices(); + update_other_devices(); + BOOST_LOG_TRIVIAL(trace) << "SelectMachinePopup update_machine_list end"; +} + +void SelectMachinePopup::start_ssdp(bool start) +{ + return; + //if (wxGetApp().getAgent()) { wxGetApp().getAgent()->start_discovery(true, start); } +} + +void SelectMachinePopup::OnLeftUp(wxMouseEvent &event) +{ + auto mouse_pos = ClientToScreen(event.GetPosition()); + auto wxscroll_win_pos = m_scrolledWindow->ClientToScreen(wxPoint(0, 0)); + + if (mouse_pos.x > wxscroll_win_pos.x && mouse_pos.y > wxscroll_win_pos.y && mouse_pos.x < (wxscroll_win_pos.x + m_scrolledWindow->GetSize().x) && + mouse_pos.y < (wxscroll_win_pos.y + m_scrolledWindow->GetSize().y)) { + + for (MachinePanel* p : m_user_list_machine_panel) { + auto p_rect = p->mPanel->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > p_rect.x && mouse_pos.y > p_rect.y && mouse_pos.x < (p_rect.x + p->mPanel->GetSize().x) && mouse_pos.y < (p_rect.y + p->mPanel->GetSize().y)) { + wxMouseEvent event(wxEVT_LEFT_UP); + auto tag_pos = p->mPanel->ScreenToClient(mouse_pos); + event.SetPosition(tag_pos); + event.SetEventObject(p->mPanel); + wxPostEvent(p->mPanel, event); + } + } + + for (MachinePanel* p : m_other_list_machine_panel) { + auto p_rect = p->mPanel->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > p_rect.x && mouse_pos.y > p_rect.y && mouse_pos.x < (p_rect.x + p->mPanel->GetSize().x) && mouse_pos.y < (p_rect.y + p->mPanel->GetSize().y)) { + wxMouseEvent event(wxEVT_LEFT_UP); + auto tag_pos = p->mPanel->ScreenToClient(mouse_pos); + event.SetPosition(tag_pos); + event.SetEventObject(p->mPanel); + wxPostEvent(p->mPanel, event); + } + } + + //pin code + auto pc_rect = m_panel_ping_code->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > pc_rect.x && mouse_pos.y > pc_rect.y && mouse_pos.x < (pc_rect.x + m_panel_ping_code->GetSize().x) && mouse_pos.y < (pc_rect.y + m_panel_ping_code->GetSize().y)) { + wxGetApp().popup_ping_bind_dialog(); + } + + //bind with access code + auto dc_rect = m_panel_direct_connection->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > dc_rect.x && mouse_pos.y > dc_rect.y && mouse_pos.x < (dc_rect.x + m_panel_direct_connection->GetSize().x) && mouse_pos.y < (dc_rect.y + m_panel_direct_connection->GetSize().y)) { + InputIpAddressDialog dlgo; + dlgo.ShowModal(); + } + + //hyper link + auto h_rect = m_hyperlink->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > h_rect.x && mouse_pos.y > h_rect.y && mouse_pos.x < (h_rect.x + m_hyperlink->GetSize().x) && mouse_pos.y < (h_rect.y + m_hyperlink->GetSize().y)) { + wxLaunchDefaultBrowser(wxT("https://wiki.bambulab.com/en/software/bambu-studio/failed-to-connect-printer")); + } + } +} + +EditDevNameDialog::EditDevNameDialog(Plater *plater /*= nullptr*/) + : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Modifying the device name"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) +{ + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + SetBackgroundColour(*wxWHITE); + wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL); + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); + m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); + m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(38)); + m_textCtr = new ::TextInput(this, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(260), FromDIP(40)), wxTE_PROCESS_ENTER); + m_textCtr->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(22))); + m_textCtr->SetMinSize(wxSize(FromDIP(260), FromDIP(40))); + m_sizer_main->Add(m_textCtr, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, FromDIP(40)); + + m_static_valid = new wxStaticText(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0); + m_static_valid->Wrap(-1); + m_static_valid->SetFont(::Label::Body_13); + m_static_valid->SetForegroundColour(wxColour(255, 111, 0)); + m_sizer_main->Add(m_static_valid, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxLEFT | wxRIGHT, FromDIP(10)); + + + m_button_confirm = new Button(this, _L("Confirm")); + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), std::pair(wxColour(0, 150, 136), StateColor::Normal)); + m_button_confirm->SetBackgroundColor(btn_bg_green); + m_button_confirm->SetBorderColor(wxColour(0, 150, 136)); + m_button_confirm->SetTextColor(wxColour(255, 255, 255)); + m_button_confirm->SetSize(wxSize(FromDIP(72), FromDIP(24))); + m_button_confirm->SetMinSize(wxSize(FromDIP(72), FromDIP(24))); + m_button_confirm->SetCornerRadius(FromDIP(12)); + m_button_confirm->Bind(wxEVT_BUTTON, &EditDevNameDialog::on_edit_name, this); + + m_sizer_main->Add(m_button_confirm, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, FromDIP(10)); + m_sizer_main->Add(0, 0, 0, wxBOTTOM, FromDIP(38)); + + SetSizer(m_sizer_main); + Layout(); + Fit(); + Centre(wxBOTH); + wxGetApp().UpdateDlgDarkUI(this); +} + +EditDevNameDialog::~EditDevNameDialog() {} + +void EditDevNameDialog::set_machine_obj(MachineObject *obj) +{ + m_info = obj; + if (m_info) + m_textCtr->GetTextCtrl()->SetValue(from_u8(m_info->dev_name)); +} + +void EditDevNameDialog::on_dpi_changed(const wxRect &suggested_rect) +{ + m_button_confirm->SetSize(wxSize(FromDIP(72), FromDIP(24))); + m_button_confirm->SetMinSize(wxSize(FromDIP(72), FromDIP(24))); +} + +void EditDevNameDialog::on_edit_name(wxCommandEvent &e) +{ + m_static_valid->SetLabel(wxEmptyString); + auto m_valid_type = Valid; + wxString info_line; + auto new_dev_name = m_textCtr->GetTextCtrl()->GetValue(); + + const char * unusable_symbols = "<>[]:/\\|?*\""; + const std::string unusable_suffix = PresetCollection::get_suffix_modified(); + + for (size_t i = 0; i < std::strlen(unusable_symbols); i++) { + if (new_dev_name.find_first_of(unusable_symbols[i]) != std::string::npos) { + info_line = _L("Name is invalid;") + _L("illegal characters:") + " " + unusable_symbols; + m_valid_type = NoValid; + break; + } + } + + if (m_valid_type == Valid && new_dev_name.find(unusable_suffix) != std::string::npos) { + info_line = _L("Name is invalid;") + _L("illegal suffix:") + "\n\t" + from_u8(PresetCollection::get_suffix_modified()); + m_valid_type = NoValid; + } + + if (m_valid_type == Valid && new_dev_name.empty()) { + info_line = _L("The name is not allowed to be empty."); + m_valid_type = NoValid; + } + + if (m_valid_type == Valid && new_dev_name.find_first_of(' ') == 0) { + info_line = _L("The name is not allowed to start with space character."); + m_valid_type = NoValid; + } + + if (m_valid_type == Valid && new_dev_name.find_last_of(' ') == new_dev_name.length() - 1) { + info_line = _L("The name is not allowed to end with space character."); + m_valid_type = NoValid; + } + + if (m_valid_type == NoValid) { + m_static_valid->SetLabel(info_line); + Layout(); + } + + if (m_valid_type == Valid) { + m_static_valid->SetLabel(wxEmptyString); + DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (dev) { + auto utf8_str = new_dev_name.ToUTF8(); + auto name = std::string(utf8_str.data(), utf8_str.length()); + if (m_info) + dev->modify_device_name(m_info->dev_id, name); + } + DPIDialog::EndModal(wxID_CLOSE); + } +} + +PinCodePanel::PinCodePanel(wxWindow* parent, int type, wxWindowID winid /*= wxID_ANY*/, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/) + { + wxPanel::Create(parent, winid, pos); + Bind(wxEVT_PAINT, &PinCodePanel::OnPaint, this); + SetSize(SELECT_MACHINE_ITEM_SIZE); + SetMaxSize(SELECT_MACHINE_ITEM_SIZE); + SetMinSize(SELECT_MACHINE_ITEM_SIZE); + + m_type = type; + m_bitmap = ScalableBitmap(this, "bind_device_ping_code",10); + + this->Bind(wxEVT_ENTER_WINDOW, &PinCodePanel::on_mouse_enter, this); + this->Bind(wxEVT_LEAVE_WINDOW, &PinCodePanel::on_mouse_leave, this); + this->Bind(wxEVT_LEFT_UP, &PinCodePanel::on_mouse_left_up, this); + } + + void PinCodePanel::OnPaint(wxPaintEvent& event) + { + wxPaintDC dc(this); + render(dc); + } + + void PinCodePanel::render(wxDC& dc) + { +#ifdef __WXMSW__ + wxSize size = GetSize(); + wxMemoryDC memdc; + wxBitmap bmp(size.x, size.y); + memdc.SelectObject(bmp); + memdc.Blit({ 0, 0 }, size, &dc, { 0, 0 }); + + { + wxGCDC dc2(memdc); + doRender(dc2); + } + + memdc.SelectObject(wxNullBitmap); + dc.DrawBitmap(bmp, 0, 0); +#else + doRender(dc); +#endif + } + + void PinCodePanel::doRender(wxDC& dc) + { + auto size = GetSize(); + dc.DrawBitmap(m_bitmap.bmp(), wxPoint(FromDIP(12), (size.y - m_bitmap.GetBmpSize().y) / 2)); + dc.SetFont(::Label::Head_13); + dc.SetTextForeground(StateColor::darkModeColorFor(wxColour("#262E30"))); // ORCA fix text not visible on dark theme + wxString txt; + if (m_type == 0) {txt = _L("Bind with Pin Code");} + else if (m_type == 1) {txt = _L("Bind with Access Code");} + + auto txt_size = dc.GetTextExtent(txt); + dc.DrawText(txt, wxPoint(FromDIP(28), (size.y - txt_size.y) / 2)); + + if (m_hover) { + dc.SetPen(SELECT_MACHINE_BRAND); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(0, 0, size.x, size.y); + } + } + + void PinCodePanel::on_mouse_enter(wxMouseEvent& evt) + { + m_hover = true; + Refresh(); + } + + void PinCodePanel::on_mouse_leave(wxMouseEvent& evt) + { + m_hover = false; + Refresh(); + } + + void PinCodePanel::on_mouse_left_up(wxMouseEvent& evt) + { + if (m_type == 0) { + wxGetApp().popup_ping_bind_dialog(); + } + else if (m_type == 1) { + InputIpAddressDialog dlgo; + dlgo.ShowModal(); + } + } + + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/SelectMachinePop.hpp b/src/slic3r/GUI/SelectMachinePop.hpp new file mode 100644 index 00000000000..d1a34f9b3a4 --- /dev/null +++ b/src/slic3r/GUI/SelectMachinePop.hpp @@ -0,0 +1,233 @@ +#ifndef slic3r_GUI_SelectMachinePop_hpp_ +#define slic3r_GUI_SelectMachinePop_hpp_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ReleaseNote.hpp" +#include "GUI_Utils.hpp" +#include "wxExtensions.hpp" +#include "DeviceManager.hpp" +#include "Plater.hpp" +#include "BBLStatusBar.hpp" +#include "BBLStatusBarSend.hpp" +#include "Widgets/Label.hpp" +#include "Widgets/Button.hpp" +#include "Widgets/CheckBox.hpp" +#include "Widgets/ComboBox.hpp" +#include "Widgets/ScrolledWindow.hpp" +#include "Widgets/PopupWindow.hpp" +#include +#include + +namespace Slic3r { namespace GUI { + +enum PrinterState { + OFFLINE, + IDLE, + BUSY, + LOCK, + IN_LAN +}; + +enum PrinterBindState { + NONE, + ALLOW_BIND, + ALLOW_UNBIND +}; + +wxDECLARE_EVENT(EVT_FINISHED_UPDATE_MACHINE_LIST, wxCommandEvent); +wxDECLARE_EVENT(EVT_WILL_DISMISS_MACHINE_LIST, wxCommandEvent); +wxDECLARE_EVENT(EVT_UPDATE_WINDOWS_POSITION, wxCommandEvent); +wxDECLARE_EVENT(EVT_DISSMISS_MACHINE_LIST, wxCommandEvent); +wxDECLARE_EVENT(EVT_CONNECT_LAN_PRINT, wxCommandEvent); +wxDECLARE_EVENT(EVT_EDIT_PRINT_NAME, wxCommandEvent); +wxDECLARE_EVENT(EVT_UNBIND_MACHINE, wxCommandEvent); +wxDECLARE_EVENT(EVT_BIND_MACHINE, wxCommandEvent); + +#define SELECT_MACHINE_POPUP_SIZE wxSize(FromDIP(216), FromDIP(364)) +#define SELECT_MACHINE_LIST_SIZE wxSize(FromDIP(212), FromDIP(360)) +#define SELECT_MACHINE_ITEM_SIZE wxSize(FromDIP(190), FromDIP(35)) +#define SELECT_MACHINE_GREY900 wxColour(38, 46, 48) +#define SELECT_MACHINE_GREY600 wxColour(144, 144, 144) +#define SELECT_MACHINE_GREY400 wxColour(206, 206, 206) +#define SELECT_MACHINE_BRAND wxColour(0, 150, 136) +#define SELECT_MACHINE_REMIND wxColour(255, 111, 0) +#define SELECT_MACHINE_LIGHT_GREEN wxColour(219, 253, 231) + +class MachineObjectPanel : public wxPanel +{ +private: + bool m_is_my_devices {false}; + bool m_show_edit{false}; + bool m_show_bind{false}; + bool m_hover {false}; + bool m_is_macos_special_version{false}; + + + PrinterBindState m_bind_state; + PrinterState m_state; + + ScalableBitmap m_unbind_img; + ScalableBitmap m_edit_name_img; + ScalableBitmap m_select_unbind_img; + + ScalableBitmap m_printer_status_offline; + ScalableBitmap m_printer_status_busy; + ScalableBitmap m_printer_status_idle; + ScalableBitmap m_printer_status_lock; + ScalableBitmap m_printer_in_lan; + + MachineObject *m_info; + +protected: + wxStaticBitmap *m_bitmap_info; + wxStaticBitmap *m_bitmap_bind; + +public: + MachineObjectPanel(wxWindow * parent, + wxWindowID id = wxID_ANY, + const wxPoint & pos = wxDefaultPosition, + const wxSize & size = wxDefaultSize, + long style = wxTAB_TRAVERSAL, + const wxString &name = wxEmptyString); + + ~MachineObjectPanel(); + + void show_bind_dialog(); + void set_printer_state(PrinterState state); + void show_printer_bind(bool show, PrinterBindState state); + void show_edit_printer_name(bool show); + void update_machine_info(MachineObject *info, bool is_my_devices = false); +protected: + void OnPaint(wxPaintEvent &event); + void render(wxDC &dc); + void doRender(wxDC &dc); + void on_mouse_enter(wxMouseEvent &evt); + void on_mouse_leave(wxMouseEvent &evt); + void on_mouse_left_up(wxMouseEvent &evt); +}; + +class MachinePanel +{ +public: + wxString mIndex; + MachineObjectPanel *mPanel; +}; + +class PinCodePanel : public wxPanel +{ +public: + PinCodePanel(wxWindow* parent, + int type, + wxWindowID winid = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize); + ~PinCodePanel() {}; + + ScalableBitmap m_bitmap; + bool m_hover{false}; + int m_type{0}; + + void OnPaint(wxPaintEvent& event); + void render(wxDC& dc); + void doRender(wxDC& dc); + + void on_mouse_enter(wxMouseEvent& evt); + void on_mouse_leave(wxMouseEvent& evt); + void on_mouse_left_up(wxMouseEvent& evt); +}; + +class SelectMachinePopup : public PopupWindow +{ +public: + SelectMachinePopup(wxWindow *parent); + ~SelectMachinePopup(); + + // PopupWindow virtual methods are all overridden to log them + virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE; + virtual void OnDismiss() wxOVERRIDE; + virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE; + virtual bool Show(bool show = true) wxOVERRIDE; + + void update_machine_list(wxCommandEvent &event); + void start_ssdp(bool on_off); + bool was_dismiss() { return m_dismiss; } + +private: + int m_my_devices_count{0}; + int m_other_devices_count{0}; + PinCodePanel* m_panel_ping_code{nullptr}; + PinCodePanel* m_panel_direct_connection{nullptr}; + wxWindow* m_placeholder_panel{nullptr}; + wxHyperlinkCtrl* m_hyperlink{nullptr}; + Label* m_ping_code_text{nullptr}; + wxStaticBitmap* m_img_ping_code{nullptr}; + wxBoxSizer * m_sizer_body{nullptr}; + wxBoxSizer * m_sizer_my_devices{nullptr}; + wxBoxSizer * m_sizer_other_devices{nullptr}; + wxBoxSizer * m_sizer_search_bar{nullptr}; + wxSearchCtrl* m_search_bar{nullptr}; + wxScrolledWindow * m_scrolledWindow{nullptr}; + wxWindow * m_panel_body{nullptr}; + wxTimer * m_refresh_timer{nullptr}; + std::vector m_user_list_machine_panel; + std::vector m_other_list_machine_panel; + boost::thread* get_print_info_thread{ nullptr }; + std::shared_ptr m_token = std::make_shared(0); + std::string m_print_info = ""; + bool m_dismiss { false }; + + std::map m_bind_machine_list; + std::map m_free_machine_list; + +private: + void OnLeftUp(wxMouseEvent &event); + void on_timer(wxTimerEvent &event); + + void update_other_devices(); + void update_user_devices(); + bool search_for_printer(MachineObject* obj); + void on_dissmiss_win(wxCommandEvent &event); + wxWindow *create_title_panel(wxString text); +}; + +class EditDevNameDialog : public DPIDialog +{ +public: + EditDevNameDialog(Plater *plater = nullptr); + ~EditDevNameDialog(); + + void set_machine_obj(MachineObject *obj); + void on_dpi_changed(const wxRect &suggested_rect) override; + void on_edit_name(wxCommandEvent &e); + + Button* m_button_confirm{nullptr}; + TextInput* m_textCtr{nullptr}; + wxStaticText* m_static_valid{nullptr}; + MachineObject* m_info{nullptr}; +}; + +}} // namespace Slic3r::GUI + +#endif From 6b9ce834e1acc389cd47341e71bff3d7df7d3dc3 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 26 May 2025 17:54:10 +0800 Subject: [PATCH 113/127] Fix text alignment of storage page error message --- src/slic3r/GUI/ImageGrid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ImageGrid.cpp b/src/slic3r/GUI/ImageGrid.cpp index ebfdb33ea40..feb57644b26 100644 --- a/src/slic3r/GUI/ImageGrid.cpp +++ b/src/slic3r/GUI/ImageGrid.cpp @@ -520,7 +520,7 @@ void ImageGrid::render(wxDC& dc) dc.DrawRectangle({ 0, 0, size.x, size.y }); if (!m_status_msg.IsEmpty()) { auto si = m_status_icon.GetBmpSize(); - auto st = dc.GetTextExtent(m_status_msg); + auto st = dc.GetMultiLineTextExtent(m_status_msg); auto rect = wxRect{0, 0, max(st.x, si.x), si.y + 26 + st.y}.CenterIn(wxRect({0, 0}, size)); dc.DrawBitmap(m_status_icon.bmp(), rect.x + (rect.width - si.x) / 2, rect.y); dc.SetTextForeground(wxColor(0x909090)); From 659a65f27fd888f78dbaa6c759f2786e99e5b9e4 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 26 May 2025 20:02:16 +0800 Subject: [PATCH 114/127] Force using local camera view for H2D if legacy network plugin is used --- src/slic3r/GUI/MediaPlayCtrl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp index 47f19e55391..d5cdba95047 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.cpp +++ b/src/slic3r/GUI/MediaPlayCtrl.cpp @@ -155,6 +155,11 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj) m_lan_passwd = obj->get_access_code(); m_device_busy = obj->is_camera_busy_off(); m_tutk_state = obj->tutk_state; + + if (DeviceManager::get_printer_series(obj->printer_type) == "series_o" && NetworkAgent::use_legacy_network) { + // Legacy plugin cannot support remote play for H2D, force using local mode + m_remote_proto = MachineObject::LVR_None; + } } else { m_camera_exists = false; m_lan_mode = false; From 7ecd3e7f0c8643da52282fa73297eb595e5bf603 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 27 May 2025 10:14:34 +0800 Subject: [PATCH 115/127] Reorganize bbl printer profiles --- .../BBL/process/fdm_process_bbl_common.json | 61 +-------- .../BBL/process/fdm_process_common.json | 122 +++++++++++------- 2 files changed, 83 insertions(+), 100 deletions(-) diff --git a/resources/profiles/BBL/process/fdm_process_bbl_common.json b/resources/profiles/BBL/process/fdm_process_bbl_common.json index d77980a29d8..672244c1e77 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_common.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_common.json @@ -4,71 +4,22 @@ "inherits": "fdm_process_common", "from": "system", "instantiation": "false", - "max_travel_detour_distance": "0", - "bottom_surface_pattern": "monotonic", - "bottom_shell_layers": "3", - "bottom_shell_thickness": "0", "bridge_speed": "50", - "brim_object_gap": "0.1", - "compatible_printers_condition": "", - "draft_shield": "disabled", - "elefant_foot_compensation": "0", - "enable_arc_fitting": "1", - "outer_wall_acceleration": "5000", - "wall_infill_order": "inner wall/outer wall/infill", - "line_width": "0.42", - "internal_bridge_support_thickness": "0.8", + "gap_infill_speed": "50", "initial_layer_acceleration": "500", - "initial_layer_line_width": "0.5", + "initial_layer_infill_speed": "60", "initial_layer_speed": "30", - "gap_infill_speed": "50", - "sparse_infill_speed": "250", - "ironing_flow": "10%", - "ironing_spacing": "0.15", - "ironing_speed": "30", - "ironing_type": "no ironing", - "layer_height": "0.2", - "reduce_infill_retraction": "1", - "filename_format": "{input_filename_base}_{filament_type[0]}_{print_time}.gcode", - "detect_overhang_wall": "1", + "inner_wall_speed": "150", + "internal_solid_infill_speed": "150", + "outer_wall_acceleration": "5000", "overhang_1_4_speed": "0", "overhang_2_4_speed": "50", "overhang_3_4_speed": "30", "overhang_4_4_speed": "10", - "only_one_wall_top": "1", - "inner_wall_speed": "150", - "seam_position": "aligned", - "skirt_height": "1", - "skirt_loops": "0", - "minimum_sparse_infill_area": "15", - "internal_solid_infill_line_width": "0.42", - "internal_solid_infill_speed": "150", - "initial_layer_infill_speed": "60", - "resolution": "0.012", - "support_type": "normal(auto)", - "support_style": "default", - "support_top_z_distance": "0.2", - "support_bottom_z_distance": "0.2", - "support_interface_bottom_layers": "2", - "support_interface_spacing": "0.5", - "support_expansion": "0", - "support_base_pattern_spacing": "2.5", + "sparse_infill_speed": "250", "support_speed": "150", - "support_threshold_angle": "30", - "support_object_xy_distance": "0.35", - "tree_support_branch_diameter": "2", - "tree_support_branch_angle": "45", - "tree_support_wall_count": "0", - "max_bridge_length": "0", - "top_surface_pattern": "monotonicline", "top_surface_acceleration": "2000", "top_surface_speed": "200", - "top_shell_layers": "3", - "top_shell_thickness": "0.8", "travel_speed": "500", - "enable_prime_tower": "1", - "wipe_tower_no_sparse_layers": "0", - "prime_tower_width": "35", - "wall_generator": "classic", "compatible_printers": [] } \ No newline at end of file diff --git a/resources/profiles/BBL/process/fdm_process_common.json b/resources/profiles/BBL/process/fdm_process_common.json index 9b99ec1b283..6a8a42a19eb 100644 --- a/resources/profiles/BBL/process/fdm_process_common.json +++ b/resources/profiles/BBL/process/fdm_process_common.json @@ -4,72 +4,104 @@ "from": "system", "instantiation": "false", "adaptive_layer_height": "0", - "reduce_crossing_wall": "0", + "bottom_shell_layers": "3", + "bottom_shell_thickness": "0", + "bottom_surface_pattern": "monotonic", "bridge_flow": "0.95", + "bridge_no_support": "0", "bridge_speed": "25", + "brim_object_gap": "0.1", "brim_width": "5", - "print_sequence": "by layer", + "compatible_printers_condition": "", "default_acceleration": "10000", - "bridge_no_support": "0", - "elefant_foot_compensation": "0.1", - "outer_wall_line_width": "0.42", - "ironing_inset": "0.21", - "outer_wall_speed": "120", - "line_width": "0.45", - "infill_direction": "45", - "sparse_infill_density": "15%", - "sparse_infill_pattern": "crosshatch", - "initial_layer_line_width": "0.42", - "initial_layer_print_height": "0.2", - "initial_layer_speed": "20", + "detect_overhang_wall": "1", + "detect_thin_wall": "0", + "draft_shield": "disabled", + "elefant_foot_compensation": "0", + "enable_arc_fitting": "1", + "enable_prime_tower": "1", + "enable_support": "0", + "filename_format": "{input_filename_base}_{filament_type[0]}_{print_time}.gcode", "gap_infill_speed": "30", "infill_combination": "0", - "sparse_infill_line_width": "0.45", + "infill_direction": "45", "infill_wall_overlap": "15%", - "sparse_infill_speed": "50", - "interface_shells": "0", - "detect_overhang_wall": "0", - "reduce_infill_retraction": "0", - "filename_format": "{input_filename_base}.gcode", - "wall_loops": "2", + "initial_layer_line_width": "0.5", + "initial_layer_print_height": "0.2", + "initial_layer_speed": "20", "inner_wall_line_width": "0.45", "inner_wall_speed": "40", + "interface_shells": "0", + "internal_bridge_support_thickness": "0.8", + "internal_solid_infill_line_width": "0.42", + "internal_solid_infill_speed": "40", + "ironing_flow": "10%", + "ironing_inset": "0.21", + "ironing_spacing": "0.15", + "ironing_speed": "30", + "ironing_type": "no ironing", + "layer_height": "0.2", + "line_width": "0.42", + "max_bridge_length": "0", + "max_travel_detour_distance": "0", + "minimum_sparse_infill_area": "15", + "only_one_wall_top": "1", + "outer_wall_line_width": "0.42", + "outer_wall_speed": "120", + "overhang_totally_speed": "19", + "prime_tower_width": "35", + "print_sequence": "by layer", "print_settings_id": "", "raft_layers": "0", - "seam_position": "nearest", + "reduce_crossing_wall": "0", + "reduce_infill_retraction": "1", + "resolution": "0.012", + "scarf_angle_threshold": "155", + "seam_position": "aligned", "skirt_distance": "2", - "skirt_height": "2", - "minimum_sparse_infill_area": "0", - "internal_solid_infill_line_width": "0.45", - "internal_solid_infill_speed": "40", + "skirt_height": "1", + "skirt_loops": "0", + "smooth_coefficient": "80", + "sparse_infill_density": "15%", + "sparse_infill_line_width": "0.45", + "sparse_infill_pattern": "crosshatch", + "sparse_infill_speed": "50", "spiral_mode": "0", "standby_temperature_delta": "-5", - "enable_support": "0", + "support_base_pattern": "default", + "support_base_pattern_spacing": "2.5", + "support_bottom_z_distance": "0.2", + "support_expansion": "0", "support_filament": "0", - "support_line_width": "0.42", + "support_interface_bottom_layers": "2", "support_interface_filament": "0", - "support_on_build_plate_only": "0", - "support_top_z_distance": "0.15", "support_interface_loop_pattern": "0", - "support_interface_top_layers": "2", - "support_interface_spacing": "0", - "support_interface_speed": "80", "support_interface_pattern": "auto", - "support_base_pattern": "default", - "support_base_pattern_spacing": "2", + "support_interface_spacing": "0.5", + "support_interface_speed": "80", + "support_interface_top_layers": "2", + "support_line_width": "0.42", + "support_object_xy_distance": "0.35", + "support_on_build_plate_only": "0", "support_speed": "40", - "support_threshold_angle": "40", - "support_object_xy_distance": "0.5", - "detect_thin_wall": "0", + "support_style": "default", + "support_threshold_angle": "30", + "support_top_z_distance": "0.2", + "support_type": "normal(auto)", + "top_shell_layers": "3", + "top_shell_thickness": "0.8", "top_surface_line_width": "0.42", + "top_surface_pattern": "monotonicline", "top_surface_speed": "30", "travel_speed": "400", - "enable_prime_tower": "0", - "prime_tower_width": "60", - "xy_hole_compensation": "0", + "tree_support_branch_angle": "45", + "tree_support_branch_diameter": "2", + "tree_support_wall_count": "0", + "wall_generator": "classic", + "wall_infill_order": "inner wall/outer wall/infill", + "wall_loops": "2", + "wipe_tower_no_sparse_layers": "0", "xy_contour_compensation": "0", - "compatible_printers": [], - "smooth_coefficient": "80", - "overhang_totally_speed": "19", - "scarf_angle_threshold": "155" + "xy_hole_compensation": "0", + "compatible_printers": [] } \ No newline at end of file From 2dacde5b3badf69903aebb52cb0a58f869d094ea Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 27 May 2025 10:21:37 +0800 Subject: [PATCH 116/127] Rename `fdm_process_bbl_` to `fdm_process_single_` --- resources/profiles/BBL.json | 88 +++++++++---------- .../0.06mm Fine @BBL A1 0.2 nozzle.json | 2 +- .../0.06mm Fine @BBL A1M 0.2 nozzle.json | 2 +- .../0.06mm Fine @BBL P1P 0.2 nozzle.json | 2 +- ....06mm High Quality @BBL A1 0.2 nozzle.json | 2 +- ...06mm High Quality @BBL A1M 0.2 nozzle.json | 2 +- ...06mm High Quality @BBL P1P 0.2 nozzle.json | 2 +- ...06mm High Quality @BBL X1C 0.2 nozzle.json | 2 +- .../0.06mm Standard @BBL X1C 0.2 nozzle.json | 2 +- .../process/0.08mm Extra Fine @BBL A1.json | 2 +- .../process/0.08mm Extra Fine @BBL A1M.json | 2 +- .../process/0.08mm Extra Fine @BBL P1P.json | 2 +- .../process/0.08mm Extra Fine @BBL X1C.json | 2 +- ....08mm High Quality @BBL A1 0.2 nozzle.json | 2 +- .../process/0.08mm High Quality @BBL A1.json | 2 +- ...08mm High Quality @BBL A1M 0.2 nozzle.json | 2 +- .../process/0.08mm High Quality @BBL A1M.json | 2 +- ...08mm High Quality @BBL P1P 0.2 nozzle.json | 2 +- .../process/0.08mm High Quality @BBL P1P.json | 2 +- ...08mm High Quality @BBL X1C 0.2 nozzle.json | 2 +- .../process/0.08mm High Quality @BBL X1C.json | 2 +- .../0.08mm Optimal @BBL A1 0.2 nozzle.json | 2 +- .../0.08mm Optimal @BBL A1M 0.2 nozzle.json | 2 +- .../0.08mm Optimal @BBL P1P 0.2 nozzle.json | 2 +- .../0.08mm Standard @BBL X1C 0.2 nozzle.json | 2 +- ....10mm High Quality @BBL A1 0.2 nozzle.json | 2 +- ...10mm High Quality @BBL A1M 0.2 nozzle.json | 2 +- ...10mm High Quality @BBL P1P 0.2 nozzle.json | 2 +- ...10mm High Quality @BBL X1C 0.2 nozzle.json | 2 +- .../0.10mm Standard @BBL A1 0.2 nozzle.json | 2 +- .../0.10mm Standard @BBL P1P 0.2 nozzle.json | 2 +- .../0.10mm Standard @BBL X1C 0.2 nozzle.json | 2 +- .../0.12mm Draft @BBL A1 0.2 nozzle.json | 2 +- .../0.12mm Draft @BBL A1M 0.2 nozzle.json | 2 +- .../0.12mm Draft @BBL P1P 0.2 nozzle.json | 2 +- .../BBL/process/0.12mm Fine @BBL A1.json | 2 +- .../BBL/process/0.12mm Fine @BBL A1M.json | 2 +- .../BBL/process/0.12mm Fine @BBL P1P.json | 2 +- .../BBL/process/0.12mm Fine @BBL X1C.json | 2 +- .../process/0.12mm High Quality @BBL A1.json | 2 +- .../process/0.12mm High Quality @BBL A1M.json | 2 +- .../process/0.12mm High Quality @BBL P1P.json | 2 +- .../process/0.12mm High Quality @BBL X1C.json | 2 +- .../0.12mm Standard @BBL X1C 0.2 nozzle.json | 2 +- ...0.14mm Extra Draft @BBL A1 0.2 nozzle.json | 2 +- ....14mm Extra Draft @BBL A1M 0.2 nozzle.json | 2 +- ....14mm Extra Draft @BBL P1P 0.2 nozzle.json | 2 +- .../0.14mm Standard @BBL X1C 0.2 nozzle.json | 2 +- .../process/0.16mm High Quality @BBL A1.json | 2 +- .../process/0.16mm High Quality @BBL A1M.json | 2 +- .../process/0.16mm High Quality @BBL P1P.json | 2 +- .../process/0.16mm High Quality @BBL X1C.json | 2 +- .../BBL/process/0.16mm Optimal @BBL A1.json | 2 +- .../BBL/process/0.16mm Optimal @BBL A1M.json | 2 +- .../BBL/process/0.16mm Optimal @BBL P1P.json | 2 +- .../BBL/process/0.16mm Optimal @BBL X1C.json | 2 +- .../0.18mm Fine @BBL A1 0.6 nozzle.json | 2 +- .../0.18mm Fine @BBL A1M 0.6 nozzle.json | 2 +- .../0.18mm Fine @BBL P1P 0.6 nozzle.json | 2 +- .../0.18mm Standard @BBL X1C 0.6 nozzle.json | 2 +- .../0.20mm Bambu Support W @BBL X1C.json | 2 +- .../BBL/process/0.20mm Standard @BBL A1.json | 2 +- .../BBL/process/0.20mm Standard @BBL P1P.json | 2 +- .../BBL/process/0.20mm Standard @BBL X1C.json | 2 +- .../BBL/process/0.20mm Strength @BBL A1.json | 2 +- .../BBL/process/0.20mm Strength @BBL P1P.json | 2 +- .../BBL/process/0.20mm Strength @BBL X1C.json | 2 +- .../BBL/process/0.24mm Draft @BBL A1.json | 2 +- .../BBL/process/0.24mm Draft @BBL A1M.json | 2 +- .../BBL/process/0.24mm Draft @BBL P1P.json | 2 +- .../BBL/process/0.24mm Draft @BBL X1C.json | 2 +- .../0.24mm Fine @BBL A1 0.8 nozzle.json | 2 +- .../0.24mm Fine @BBL A1M 0.8 nozzle.json | 2 +- .../0.24mm Fine @BBL P1P 0.8 nozzle.json | 2 +- .../0.24mm Optimal @BBL A1 0.6 nozzle.json | 2 +- .../0.24mm Optimal @BBL A1M 0.6 nozzle.json | 2 +- .../0.24mm Optimal @BBL P1P 0.6 nozzle.json | 2 +- .../0.24mm Standard @BBL X1C 0.6 nozzle.json | 2 +- .../0.24mm Standard @BBL X1C 0.8 nozzle.json | 2 +- .../process/0.28mm Extra Draft @BBL A1.json | 2 +- .../process/0.28mm Extra Draft @BBL A1M.json | 2 +- .../process/0.28mm Extra Draft @BBL P1P.json | 2 +- .../process/0.28mm Extra Draft @BBL X1C.json | 2 +- .../0.30mm Standard @BBL A1 0.6 nozzle.json | 2 +- .../0.30mm Standard @BBL P1P 0.6 nozzle.json | 2 +- .../0.30mm Standard @BBL X1 0.6 nozzle.json | 2 +- .../0.30mm Standard @BBL X1C 0.6 nozzle.json | 2 +- .../0.30mm Strength @BBL A1 0.6 nozzle.json | 2 +- .../0.30mm Strength @BBL A1M 0.6 nozzle.json | 2 +- .../0.30mm Strength @BBL P1P 0.6 nozzle.json | 2 +- .../0.30mm Strength @BBL X1C 0.6 nozzle.json | 2 +- .../0.32mm Optimal @BBL A1 0.8 nozzle.json | 2 +- .../0.32mm Optimal @BBL A1M 0.8 nozzle.json | 2 +- .../0.32mm Optimal @BBL P1P 0.8 nozzle.json | 2 +- .../0.32mm Standard @BBL X1C 0.8 nozzle.json | 2 +- .../0.36mm Draft @BBL A1 0.6 nozzle.json | 2 +- .../0.36mm Draft @BBL A1M 0.6 nozzle.json | 2 +- .../0.36mm Draft @BBL P1P 0.6 nozzle.json | 2 +- .../0.36mm Standard @BBL X1C 0.6 nozzle.json | 2 +- .../0.40mm Standard @BBL A1 0.8 nozzle.json | 2 +- .../0.40mm Standard @BBL P1P 0.8 nozzle.json | 2 +- .../0.40mm Standard @BBL X1 0.8 nozzle.json | 2 +- .../0.40mm Standard @BBL X1C 0.8 nozzle.json | 2 +- ...0.42mm Extra Draft @BBL A1 0.6 nozzle.json | 2 +- ....42mm Extra Draft @BBL A1M 0.6 nozzle.json | 2 +- ....42mm Extra Draft @BBL P1P 0.6 nozzle.json | 2 +- .../0.42mm Standard @BBL X1C 0.6 nozzle.json | 2 +- .../0.48mm Draft @BBL A1 0.8 nozzle.json | 2 +- .../0.48mm Draft @BBL A1M 0.8 nozzle.json | 2 +- .../0.48mm Draft @BBL P1P 0.8 nozzle.json | 2 +- .../0.48mm Standard @BBL X1C 0.8 nozzle.json | 2 +- ...0.56mm Extra Draft @BBL A1 0.8 nozzle.json | 2 +- ....56mm Extra Draft @BBL A1M 0.8 nozzle.json | 2 +- ....56mm Extra Draft @BBL P1P 0.8 nozzle.json | 2 +- .../0.56mm Standard @BBL X1C 0.8 nozzle.json | 2 +- ...> fdm_process_single_0.06_nozzle_0.2.json} | 4 +- ...0.08.json => fdm_process_single_0.08.json} | 4 +- ...> fdm_process_single_0.08_nozzle_0.2.json} | 4 +- ...> fdm_process_single_0.10_nozzle_0.2.json} | 4 +- ...0.12.json => fdm_process_single_0.12.json} | 4 +- ...> fdm_process_single_0.12_nozzle_0.2.json} | 4 +- ...> fdm_process_single_0.14_nozzle_0.2.json} | 4 +- ...0.16.json => fdm_process_single_0.16.json} | 4 +- ...> fdm_process_single_0.18_nozzle_0.6.json} | 4 +- ...0.20.json => fdm_process_single_0.20.json} | 4 +- ...0.24.json => fdm_process_single_0.24.json} | 4 +- ...> fdm_process_single_0.24_nozzle_0.6.json} | 4 +- ...> fdm_process_single_0.24_nozzle_0.8.json} | 4 +- ...0.28.json => fdm_process_single_0.28.json} | 4 +- ...> fdm_process_single_0.30_nozzle_0.6.json} | 4 +- ...> fdm_process_single_0.32_nozzle_0.8.json} | 4 +- ...> fdm_process_single_0.36_nozzle_0.6.json} | 4 +- ...> fdm_process_single_0.40_nozzle_0.8.json} | 4 +- ...> fdm_process_single_0.42_nozzle_0.6.json} | 4 +- ...> fdm_process_single_0.48_nozzle_0.8.json} | 4 +- ...> fdm_process_single_0.56_nozzle_0.8.json} | 4 +- ...on.json => fdm_process_single_common.json} | 2 +- .../0.20mm Bambu Support W @RatRig.json | 2 +- 138 files changed, 202 insertions(+), 202 deletions(-) rename resources/profiles/BBL/process/{fdm_process_bbl_0.06_nozzle_0.2.json => fdm_process_single_0.06_nozzle_0.2.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.08.json => fdm_process_single_0.08.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.08_nozzle_0.2.json => fdm_process_single_0.08_nozzle_0.2.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.10_nozzle_0.2.json => fdm_process_single_0.10_nozzle_0.2.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.12.json => fdm_process_single_0.12.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.12_nozzle_0.2.json => fdm_process_single_0.12_nozzle_0.2.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.14_nozzle_0.2.json => fdm_process_single_0.14_nozzle_0.2.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.16.json => fdm_process_single_0.16.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.18_nozzle_0.6.json => fdm_process_single_0.18_nozzle_0.6.json} (89%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.20.json => fdm_process_single_0.20.json} (84%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.24.json => fdm_process_single_0.24.json} (86%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.24_nozzle_0.6.json => fdm_process_single_0.24_nozzle_0.6.json} (87%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.24_nozzle_0.8.json => fdm_process_single_0.24_nozzle_0.8.json} (88%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.28.json => fdm_process_single_0.28.json} (86%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.30_nozzle_0.6.json => fdm_process_single_0.30_nozzle_0.6.json} (87%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.32_nozzle_0.8.json => fdm_process_single_0.32_nozzle_0.8.json} (88%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.36_nozzle_0.6.json => fdm_process_single_0.36_nozzle_0.6.json} (87%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.40_nozzle_0.8.json => fdm_process_single_0.40_nozzle_0.8.json} (88%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.42_nozzle_0.6.json => fdm_process_single_0.42_nozzle_0.6.json} (87%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.48_nozzle_0.8.json => fdm_process_single_0.48_nozzle_0.8.json} (88%) rename resources/profiles/BBL/process/{fdm_process_bbl_0.56_nozzle_0.8.json => fdm_process_single_0.56_nozzle_0.8.json} (88%) rename resources/profiles/BBL/process/{fdm_process_bbl_common.json => fdm_process_single_common.json} (94%) diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 10383cb01e5..f38e7c2a742 100644 --- a/resources/profiles/BBL.json +++ b/resources/profiles/BBL.json @@ -40,92 +40,92 @@ "sub_path": "process/fdm_process_common.json" }, { - "name": "fdm_process_bbl_common", - "sub_path": "process/fdm_process_bbl_common.json" + "name": "fdm_process_single_common", + "sub_path": "process/fdm_process_single_common.json" }, { - "name": "fdm_process_bbl_0.08", - "sub_path": "process/fdm_process_bbl_0.08.json" + "name": "fdm_process_single_0.08", + "sub_path": "process/fdm_process_single_0.08.json" }, { - "name": "fdm_process_bbl_0.10_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.10_nozzle_0.2.json" + "name": "fdm_process_single_0.10_nozzle_0.2", + "sub_path": "process/fdm_process_single_0.10_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.40_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.40_nozzle_0.8.json" + "name": "fdm_process_single_0.40_nozzle_0.8", + "sub_path": "process/fdm_process_single_0.40_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.30_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.30_nozzle_0.6.json" + "name": "fdm_process_single_0.30_nozzle_0.6", + "sub_path": "process/fdm_process_single_0.30_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.12", - "sub_path": "process/fdm_process_bbl_0.12.json" + "name": "fdm_process_single_0.12", + "sub_path": "process/fdm_process_single_0.12.json" }, { - "name": "fdm_process_bbl_0.16", - "sub_path": "process/fdm_process_bbl_0.16.json" + "name": "fdm_process_single_0.16", + "sub_path": "process/fdm_process_single_0.16.json" }, { - "name": "fdm_process_bbl_0.20", - "sub_path": "process/fdm_process_bbl_0.20.json" + "name": "fdm_process_single_0.20", + "sub_path": "process/fdm_process_single_0.20.json" }, { - "name": "fdm_process_bbl_0.24", - "sub_path": "process/fdm_process_bbl_0.24.json" + "name": "fdm_process_single_0.24", + "sub_path": "process/fdm_process_single_0.24.json" }, { - "name": "fdm_process_bbl_0.28", - "sub_path": "process/fdm_process_bbl_0.28.json" + "name": "fdm_process_single_0.28", + "sub_path": "process/fdm_process_single_0.28.json" }, { - "name": "fdm_process_bbl_0.06_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.06_nozzle_0.2.json" + "name": "fdm_process_single_0.06_nozzle_0.2", + "sub_path": "process/fdm_process_single_0.06_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.08_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.08_nozzle_0.2.json" + "name": "fdm_process_single_0.08_nozzle_0.2", + "sub_path": "process/fdm_process_single_0.08_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.12_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.12_nozzle_0.2.json" + "name": "fdm_process_single_0.12_nozzle_0.2", + "sub_path": "process/fdm_process_single_0.12_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.14_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.14_nozzle_0.2.json" + "name": "fdm_process_single_0.14_nozzle_0.2", + "sub_path": "process/fdm_process_single_0.14_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.18_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.18_nozzle_0.6.json" + "name": "fdm_process_single_0.18_nozzle_0.6", + "sub_path": "process/fdm_process_single_0.18_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.24_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.24_nozzle_0.6.json" + "name": "fdm_process_single_0.24_nozzle_0.6", + "sub_path": "process/fdm_process_single_0.24_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.36_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.36_nozzle_0.6.json" + "name": "fdm_process_single_0.36_nozzle_0.6", + "sub_path": "process/fdm_process_single_0.36_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.42_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.42_nozzle_0.6.json" + "name": "fdm_process_single_0.42_nozzle_0.6", + "sub_path": "process/fdm_process_single_0.42_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.24_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.24_nozzle_0.8.json" + "name": "fdm_process_single_0.24_nozzle_0.8", + "sub_path": "process/fdm_process_single_0.24_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.32_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.32_nozzle_0.8.json" + "name": "fdm_process_single_0.32_nozzle_0.8", + "sub_path": "process/fdm_process_single_0.32_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.48_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.48_nozzle_0.8.json" + "name": "fdm_process_single_0.48_nozzle_0.8", + "sub_path": "process/fdm_process_single_0.48_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.56_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.56_nozzle_0.8.json" + "name": "fdm_process_single_0.56_nozzle_0.8", + "sub_path": "process/fdm_process_single_0.56_nozzle_0.8.json" }, { "name": "0.08mm Extra Fine @BBL X1C", diff --git a/resources/profiles/BBL/process/0.06mm Fine @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm Fine @BBL A1 0.2 nozzle.json index a46163008e9..48e6ad9c262 100644 --- a/resources/profiles/BBL/process/0.06mm Fine @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm Fine @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm Fine @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP084", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm Fine @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm Fine @BBL A1M 0.2 nozzle.json index 829e9176753..1ca4fc711f4 100644 --- a/resources/profiles/BBL/process/0.06mm Fine @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm Fine @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm Fine @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP050", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json index d05620a789c..fbbc791445f 100644 --- a/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm Fine @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm Fine @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP063", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm High Quality @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm High Quality @BBL A1 0.2 nozzle.json index 19c218e4e38..7af52f3efe1 100644 --- a/resources/profiles/BBL/process/0.06mm High Quality @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm High Quality @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm High Quality @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP118", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm High Quality @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm High Quality @BBL A1M 0.2 nozzle.json index 15f97d190e6..2bd36aafe7b 100644 --- a/resources/profiles/BBL/process/0.06mm High Quality @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm High Quality @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm High Quality @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP117", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm High Quality @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm High Quality @BBL P1P 0.2 nozzle.json index da1f6a89c34..a7c62f45221 100644 --- a/resources/profiles/BBL/process/0.06mm High Quality @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm High Quality @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm High Quality @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP116", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm High Quality @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm High Quality @BBL X1C 0.2 nozzle.json index 56388c0b15a..14e6f9474a5 100644 --- a/resources/profiles/BBL/process/0.06mm High Quality @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm High Quality @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm High Quality @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP115", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.06mm Standard @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.06mm Standard @BBL X1C 0.2 nozzle.json index 15ac55524b1..63826577bfe 100644 --- a/resources/profiles/BBL/process/0.06mm Standard @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.06mm Standard @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.06mm Standard @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_single_0.06_nozzle_0.2", "from": "system", "setting_id": "GP024", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1.json b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1.json index a77c85e6310..01cdcd24467 100644 --- a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1.json +++ b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Extra Fine @BBL A1", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP076", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json index b54ff1ac714..cb8b2ee21f3 100644 --- a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json +++ b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Extra Fine @BBL A1M", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP049", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL P1P.json b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL P1P.json index 080e4005ece..45b7282822c 100644 --- a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL P1P.json +++ b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Extra Fine @BBL P1P", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP018", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL X1C.json b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL X1C.json index 22ed2d79544..c7c1a7eb8d8 100644 --- a/resources/profiles/BBL/process/0.08mm Extra Fine @BBL X1C.json +++ b/resources/profiles/BBL/process/0.08mm Extra Fine @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Extra Fine @BBL X1C", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP001", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1 0.2 nozzle.json index 77459773872..6fe64c28c90 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP119", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1.json index 7d7f7be4570..1ec74ae7903 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL A1", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP102", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M 0.2 nozzle.json index 2d181eae1b3..a3e9d1d41fd 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP120", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M.json index 71e2f43b7d6..209ce23d830 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL A1M", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP101", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P 0.2 nozzle.json index 6424eae3c07..937db1fd86c 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP121", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P.json index f135573cf2b..ba9af3803e3 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL P1P", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP100", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C 0.2 nozzle.json index dc0de89bc68..cad7de9e3bb 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP122", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C.json b/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C.json index 778b1b9bef1..7ec94c385c0 100644 --- a/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C.json +++ b/resources/profiles/BBL/process/0.08mm High Quality @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm High Quality @BBL X1C", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_single_0.08", "from": "system", "setting_id": "GP099", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Optimal @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm Optimal @BBL A1 0.2 nozzle.json index 072bfd59b0e..77c8e762e11 100644 --- a/resources/profiles/BBL/process/0.08mm Optimal @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm Optimal @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Optimal @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP085", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Optimal @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm Optimal @BBL A1M 0.2 nozzle.json index 19f85778222..ed91cd49522 100644 --- a/resources/profiles/BBL/process/0.08mm Optimal @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm Optimal @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Optimal @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP051", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json index 99950575865..690daff8058 100644 --- a/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm Optimal @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Optimal @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP064", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.08mm Standard @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.08mm Standard @BBL X1C 0.2 nozzle.json index 905fef5e097..b8bceee19ce 100644 --- a/resources/profiles/BBL/process/0.08mm Standard @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.08mm Standard @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.08mm Standard @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_single_0.08_nozzle_0.2", "from": "system", "setting_id": "GP025", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm High Quality @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm High Quality @BBL A1 0.2 nozzle.json index 23393e37b97..75077880312 100644 --- a/resources/profiles/BBL/process/0.10mm High Quality @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm High Quality @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm High Quality @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP114", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm High Quality @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm High Quality @BBL A1M 0.2 nozzle.json index cb96b785afe..ba7728beea7 100644 --- a/resources/profiles/BBL/process/0.10mm High Quality @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm High Quality @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm High Quality @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP113", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm High Quality @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm High Quality @BBL P1P 0.2 nozzle.json index f463a9e0601..4d15aa5af6f 100644 --- a/resources/profiles/BBL/process/0.10mm High Quality @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm High Quality @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm High Quality @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP112", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm High Quality @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm High Quality @BBL X1C 0.2 nozzle.json index b1ab2d897b2..b89a17a330c 100644 --- a/resources/profiles/BBL/process/0.10mm High Quality @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm High Quality @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm High Quality @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP111", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm Standard @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm Standard @BBL A1 0.2 nozzle.json index 56a9bfacedd..384b4f319a9 100644 --- a/resources/profiles/BBL/process/0.10mm Standard @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm Standard @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm Standard @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP083", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json index 37a2a127773..9e5597170d0 100644 --- a/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm Standard @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP014", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.10mm Standard @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm Standard @BBL X1C 0.2 nozzle.json index 64f47b93a5a..19291675f5c 100644 --- a/resources/profiles/BBL/process/0.10mm Standard @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.10mm Standard @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.10mm Standard @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_single_0.10_nozzle_0.2", "from": "system", "setting_id": "GP007", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Draft @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.12mm Draft @BBL A1 0.2 nozzle.json index 549a6d7fe59..5adf5539818 100644 --- a/resources/profiles/BBL/process/0.12mm Draft @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.12mm Draft @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Draft @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.12_nozzle_0.2", + "inherits": "fdm_process_single_0.12_nozzle_0.2", "from": "system", "setting_id": "GP086", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Draft @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.12mm Draft @BBL A1M 0.2 nozzle.json index 66a9004da7d..18427473b1e 100644 --- a/resources/profiles/BBL/process/0.12mm Draft @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.12mm Draft @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Draft @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.12_nozzle_0.2", + "inherits": "fdm_process_single_0.12_nozzle_0.2", "from": "system", "setting_id": "GP052", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json index 675c21747d5..4ba21cba5a9 100644 --- a/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.12mm Draft @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Draft @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.12_nozzle_0.2", + "inherits": "fdm_process_single_0.12_nozzle_0.2", "from": "system", "setting_id": "GP065", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Fine @BBL A1.json b/resources/profiles/BBL/process/0.12mm Fine @BBL A1.json index 6cb7369ad2d..4769cf9030d 100644 --- a/resources/profiles/BBL/process/0.12mm Fine @BBL A1.json +++ b/resources/profiles/BBL/process/0.12mm Fine @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Fine @BBL A1", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP077", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json b/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json index 74d30722a0c..d0894a61d3f 100644 --- a/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json +++ b/resources/profiles/BBL/process/0.12mm Fine @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Fine @BBL A1M", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP044", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Fine @BBL P1P.json b/resources/profiles/BBL/process/0.12mm Fine @BBL P1P.json index 172d506ecaf..2ba69e4d6e1 100644 --- a/resources/profiles/BBL/process/0.12mm Fine @BBL P1P.json +++ b/resources/profiles/BBL/process/0.12mm Fine @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Fine @BBL P1P", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP019", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Fine @BBL X1C.json b/resources/profiles/BBL/process/0.12mm Fine @BBL X1C.json index b51e89eb5b1..603658d686c 100644 --- a/resources/profiles/BBL/process/0.12mm Fine @BBL X1C.json +++ b/resources/profiles/BBL/process/0.12mm Fine @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Fine @BBL X1C", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP002", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm High Quality @BBL A1.json b/resources/profiles/BBL/process/0.12mm High Quality @BBL A1.json index 0a1a283141d..819c415474a 100644 --- a/resources/profiles/BBL/process/0.12mm High Quality @BBL A1.json +++ b/resources/profiles/BBL/process/0.12mm High Quality @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm High Quality @BBL A1", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP106", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm High Quality @BBL A1M.json b/resources/profiles/BBL/process/0.12mm High Quality @BBL A1M.json index dbe1743fbcc..5a4483795f6 100644 --- a/resources/profiles/BBL/process/0.12mm High Quality @BBL A1M.json +++ b/resources/profiles/BBL/process/0.12mm High Quality @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm High Quality @BBL A1M", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP105", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm High Quality @BBL P1P.json b/resources/profiles/BBL/process/0.12mm High Quality @BBL P1P.json index 1acd431c126..c6499205325 100644 --- a/resources/profiles/BBL/process/0.12mm High Quality @BBL P1P.json +++ b/resources/profiles/BBL/process/0.12mm High Quality @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm High Quality @BBL P1P", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP104", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm High Quality @BBL X1C.json b/resources/profiles/BBL/process/0.12mm High Quality @BBL X1C.json index d49e9314854..93f395c1cb6 100644 --- a/resources/profiles/BBL/process/0.12mm High Quality @BBL X1C.json +++ b/resources/profiles/BBL/process/0.12mm High Quality @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm High Quality @BBL X1C", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_single_0.12", "from": "system", "setting_id": "GP103", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.12mm Standard @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.12mm Standard @BBL X1C 0.2 nozzle.json index 703993972e0..d0f25e9a0ab 100644 --- a/resources/profiles/BBL/process/0.12mm Standard @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.12mm Standard @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.12mm Standard @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.12_nozzle_0.2", + "inherits": "fdm_process_single_0.12_nozzle_0.2", "from": "system", "setting_id": "GP026", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1 0.2 nozzle.json b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1 0.2 nozzle.json index c1ff7b34a38..05ce32c6af1 100644 --- a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.14mm Extra Draft @BBL A1 0.2 nozzle", - "inherits": "fdm_process_bbl_0.14_nozzle_0.2", + "inherits": "fdm_process_single_0.14_nozzle_0.2", "from": "system", "setting_id": "GP087", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1M 0.2 nozzle.json b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1M 0.2 nozzle.json index c8b97600b7c..c60278482b2 100644 --- a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1M 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL A1M 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.14mm Extra Draft @BBL A1M 0.2 nozzle", - "inherits": "fdm_process_bbl_0.14_nozzle_0.2", + "inherits": "fdm_process_single_0.14_nozzle_0.2", "from": "system", "setting_id": "GP053", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json index d19c428cd4a..b5ac82bf571 100644 --- a/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.14mm Extra Draft @BBL P1P 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.14mm Extra Draft @BBL P1P 0.2 nozzle", - "inherits": "fdm_process_bbl_0.14_nozzle_0.2", + "inherits": "fdm_process_single_0.14_nozzle_0.2", "from": "system", "setting_id": "GP066", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.14mm Standard @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/process/0.14mm Standard @BBL X1C 0.2 nozzle.json index be951de13bf..dcec7383643 100644 --- a/resources/profiles/BBL/process/0.14mm Standard @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/process/0.14mm Standard @BBL X1C 0.2 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.14mm Standard @BBL X1C 0.2 nozzle", - "inherits": "fdm_process_bbl_0.14_nozzle_0.2", + "inherits": "fdm_process_single_0.14_nozzle_0.2", "from": "system", "setting_id": "GP027", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm High Quality @BBL A1.json b/resources/profiles/BBL/process/0.16mm High Quality @BBL A1.json index 5632bdbe262..4769751992d 100644 --- a/resources/profiles/BBL/process/0.16mm High Quality @BBL A1.json +++ b/resources/profiles/BBL/process/0.16mm High Quality @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm High Quality @BBL A1", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP110", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm High Quality @BBL A1M.json b/resources/profiles/BBL/process/0.16mm High Quality @BBL A1M.json index fe51c4740f3..97cd71e5cf6 100644 --- a/resources/profiles/BBL/process/0.16mm High Quality @BBL A1M.json +++ b/resources/profiles/BBL/process/0.16mm High Quality @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm High Quality @BBL A1M", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP109", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm High Quality @BBL P1P.json b/resources/profiles/BBL/process/0.16mm High Quality @BBL P1P.json index a3cd2eb87cf..41e8831710f 100644 --- a/resources/profiles/BBL/process/0.16mm High Quality @BBL P1P.json +++ b/resources/profiles/BBL/process/0.16mm High Quality @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm High Quality @BBL P1P", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP108", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm High Quality @BBL X1C.json b/resources/profiles/BBL/process/0.16mm High Quality @BBL X1C.json index 2e8fb3e44a2..9517c6cb273 100644 --- a/resources/profiles/BBL/process/0.16mm High Quality @BBL X1C.json +++ b/resources/profiles/BBL/process/0.16mm High Quality @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm High Quality @BBL X1C", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP107", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm Optimal @BBL A1.json b/resources/profiles/BBL/process/0.16mm Optimal @BBL A1.json index eedbf6577d5..a3d0c291e10 100644 --- a/resources/profiles/BBL/process/0.16mm Optimal @BBL A1.json +++ b/resources/profiles/BBL/process/0.16mm Optimal @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm Optimal @BBL A1", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP078", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json b/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json index 509404f9cd7..10778bcc73b 100644 --- a/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json +++ b/resources/profiles/BBL/process/0.16mm Optimal @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm Optimal @BBL A1M", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP045", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm Optimal @BBL P1P.json b/resources/profiles/BBL/process/0.16mm Optimal @BBL P1P.json index 6df7fae3f2e..9c707bbbce5 100644 --- a/resources/profiles/BBL/process/0.16mm Optimal @BBL P1P.json +++ b/resources/profiles/BBL/process/0.16mm Optimal @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm Optimal @BBL P1P", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP020", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.16mm Optimal @BBL X1C.json b/resources/profiles/BBL/process/0.16mm Optimal @BBL X1C.json index 5dc996d120f..39bae7f05a2 100644 --- a/resources/profiles/BBL/process/0.16mm Optimal @BBL X1C.json +++ b/resources/profiles/BBL/process/0.16mm Optimal @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.16mm Optimal @BBL X1C", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_single_0.16", "from": "system", "setting_id": "GP003", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.18mm Fine @BBL A1 0.6 nozzle.json b/resources/profiles/BBL/process/0.18mm Fine @BBL A1 0.6 nozzle.json index f19e70c25f0..ef37b467937 100644 --- a/resources/profiles/BBL/process/0.18mm Fine @BBL A1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.18mm Fine @BBL A1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.18mm Fine @BBL A1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.18_nozzle_0.6", + "inherits": "fdm_process_single_0.18_nozzle_0.6", "from": "system", "setting_id": "GP088", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.18mm Fine @BBL A1M 0.6 nozzle.json b/resources/profiles/BBL/process/0.18mm Fine @BBL A1M 0.6 nozzle.json index 7b1612a79d2..c7ca32e2149 100644 --- a/resources/profiles/BBL/process/0.18mm Fine @BBL A1M 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.18mm Fine @BBL A1M 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.18mm Fine @BBL A1M 0.6 nozzle", - "inherits": "fdm_process_bbl_0.18_nozzle_0.6", + "inherits": "fdm_process_single_0.18_nozzle_0.6", "from": "system", "setting_id": "GP062", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json index 53d29a785fb..0fdea76fe9b 100644 --- a/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.18mm Fine @BBL P1P 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.18mm Fine @BBL P1P 0.6 nozzle", - "inherits": "fdm_process_bbl_0.18_nozzle_0.6", + "inherits": "fdm_process_single_0.18_nozzle_0.6", "from": "system", "setting_id": "GP072", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.18mm Standard @BBL X1C 0.6 nozzle.json b/resources/profiles/BBL/process/0.18mm Standard @BBL X1C 0.6 nozzle.json index 6395e965b00..3ebf14f69c0 100644 --- a/resources/profiles/BBL/process/0.18mm Standard @BBL X1C 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.18mm Standard @BBL X1C 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.18mm Standard @BBL X1C 0.6 nozzle", - "inherits": "fdm_process_bbl_0.18_nozzle_0.6", + "inherits": "fdm_process_single_0.18_nozzle_0.6", "from": "system", "setting_id": "GP028", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.20mm Bambu Support W @BBL X1C.json b/resources/profiles/BBL/process/0.20mm Bambu Support W @BBL X1C.json index 0a01e92daa1..c7d9745406f 100644 --- a/resources/profiles/BBL/process/0.20mm Bambu Support W @BBL X1C.json +++ b/resources/profiles/BBL/process/0.20mm Bambu Support W @BBL X1C.json @@ -4,7 +4,7 @@ "name": "0.20mm Bambu Support W @BBL X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "enable_support": "1", "support_interface_top_layers": "3", "support_top_z_distance": "0.2", diff --git a/resources/profiles/BBL/process/0.20mm Standard @BBL A1.json b/resources/profiles/BBL/process/0.20mm Standard @BBL A1.json index 91feaa67740..960717592f9 100644 --- a/resources/profiles/BBL/process/0.20mm Standard @BBL A1.json +++ b/resources/profiles/BBL/process/0.20mm Standard @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.20mm Standard @BBL A1", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "from": "system", "setting_id": "GP079", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json b/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json index cea5a44b6d9..226241d6f3b 100644 --- a/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json +++ b/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.20mm Standard @BBL P1P", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "from": "system", "setting_id": "GP015", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.20mm Standard @BBL X1C.json b/resources/profiles/BBL/process/0.20mm Standard @BBL X1C.json index 01133f83ec9..d0df6bc4462 100644 --- a/resources/profiles/BBL/process/0.20mm Standard @BBL X1C.json +++ b/resources/profiles/BBL/process/0.20mm Standard @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.20mm Standard @BBL X1C", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "from": "system", "setting_id": "GP004", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.20mm Strength @BBL A1.json b/resources/profiles/BBL/process/0.20mm Strength @BBL A1.json index 30e9ca38ee8..063459a6fc2 100644 --- a/resources/profiles/BBL/process/0.20mm Strength @BBL A1.json +++ b/resources/profiles/BBL/process/0.20mm Strength @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.20mm Strength @BBL A1", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "from": "system", "setting_id": "GP080", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.20mm Strength @BBL P1P.json b/resources/profiles/BBL/process/0.20mm Strength @BBL P1P.json index 9edb0342ad9..bd131693f4b 100644 --- a/resources/profiles/BBL/process/0.20mm Strength @BBL P1P.json +++ b/resources/profiles/BBL/process/0.20mm Strength @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.20mm Strength @BBL P1P", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "from": "system", "setting_id": "GP021", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json b/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json index 6635305debd..8700ad327e9 100644 --- a/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json +++ b/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.20mm Strength @BBL X1C", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "from": "system", "setting_id": "GP013", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Draft @BBL A1.json b/resources/profiles/BBL/process/0.24mm Draft @BBL A1.json index 20e452f19b0..195a3c7538e 100644 --- a/resources/profiles/BBL/process/0.24mm Draft @BBL A1.json +++ b/resources/profiles/BBL/process/0.24mm Draft @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Draft @BBL A1", - "inherits": "fdm_process_bbl_0.24", + "inherits": "fdm_process_single_0.24", "from": "system", "setting_id": "GP081", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json b/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json index 4c791c46004..82a34774fba 100644 --- a/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json +++ b/resources/profiles/BBL/process/0.24mm Draft @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Draft @BBL A1M", - "inherits": "fdm_process_bbl_0.24", + "inherits": "fdm_process_single_0.24", "from": "system", "setting_id": "GP047", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Draft @BBL P1P.json b/resources/profiles/BBL/process/0.24mm Draft @BBL P1P.json index ed3bd535f96..d78362d4a69 100644 --- a/resources/profiles/BBL/process/0.24mm Draft @BBL P1P.json +++ b/resources/profiles/BBL/process/0.24mm Draft @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Draft @BBL P1P", - "inherits": "fdm_process_bbl_0.24", + "inherits": "fdm_process_single_0.24", "from": "system", "setting_id": "GP022", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Draft @BBL X1C.json b/resources/profiles/BBL/process/0.24mm Draft @BBL X1C.json index cc2806ac9fc..3c2667ba65c 100644 --- a/resources/profiles/BBL/process/0.24mm Draft @BBL X1C.json +++ b/resources/profiles/BBL/process/0.24mm Draft @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Draft @BBL X1C", - "inherits": "fdm_process_bbl_0.24", + "inherits": "fdm_process_single_0.24", "from": "system", "setting_id": "GP005", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Fine @BBL A1 0.8 nozzle.json b/resources/profiles/BBL/process/0.24mm Fine @BBL A1 0.8 nozzle.json index 629884dc7c9..0a1938f8425 100644 --- a/resources/profiles/BBL/process/0.24mm Fine @BBL A1 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Fine @BBL A1 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Fine @BBL A1 0.8 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.8", + "inherits": "fdm_process_single_0.24_nozzle_0.8", "from": "system", "setting_id": "GP092", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Fine @BBL A1M 0.8 nozzle.json b/resources/profiles/BBL/process/0.24mm Fine @BBL A1M 0.8 nozzle.json index ca2631fb714..4187b5e97d4 100644 --- a/resources/profiles/BBL/process/0.24mm Fine @BBL A1M 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Fine @BBL A1M 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Fine @BBL A1M 0.8 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.8", + "inherits": "fdm_process_single_0.24_nozzle_0.8", "from": "system", "setting_id": "GP057", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json index 7f7934ad5af..99e6c8558e6 100644 --- a/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Fine @BBL P1P 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Fine @BBL P1P 0.8 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.8", + "inherits": "fdm_process_single_0.24_nozzle_0.8", "from": "system", "setting_id": "GP068", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Optimal @BBL A1 0.6 nozzle.json b/resources/profiles/BBL/process/0.24mm Optimal @BBL A1 0.6 nozzle.json index f8388f6262e..ba272780863 100644 --- a/resources/profiles/BBL/process/0.24mm Optimal @BBL A1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Optimal @BBL A1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Optimal @BBL A1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.6", + "inherits": "fdm_process_single_0.24_nozzle_0.6", "from": "system", "setting_id": "GP089", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Optimal @BBL A1M 0.6 nozzle.json b/resources/profiles/BBL/process/0.24mm Optimal @BBL A1M 0.6 nozzle.json index 28082afef5a..eff76ccaeb6 100644 --- a/resources/profiles/BBL/process/0.24mm Optimal @BBL A1M 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Optimal @BBL A1M 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Optimal @BBL A1M 0.6 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.6", + "inherits": "fdm_process_single_0.24_nozzle_0.6", "from": "system", "setting_id": "GP054", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json index a143d7b6357..4a31ef5a0f1 100644 --- a/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Optimal @BBL P1P 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Optimal @BBL P1P 0.6 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.6", + "inherits": "fdm_process_single_0.24_nozzle_0.6", "from": "system", "setting_id": "GP069", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.6 nozzle.json b/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.6 nozzle.json index 2675aaa3739..9b213430a58 100644 --- a/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Standard @BBL X1C 0.6 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.6", + "inherits": "fdm_process_single_0.24_nozzle_0.6", "from": "system", "setting_id": "GP029", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.8 nozzle.json b/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.8 nozzle.json index 9ff95902a77..33d9f252548 100644 --- a/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.24mm Standard @BBL X1C 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.24mm Standard @BBL X1C 0.8 nozzle", - "inherits": "fdm_process_bbl_0.24_nozzle_0.8", + "inherits": "fdm_process_single_0.24_nozzle_0.8", "from": "system", "setting_id": "GP032", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1.json b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1.json index 490c0026cd6..e8ec96ac253 100644 --- a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1.json +++ b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.28mm Extra Draft @BBL A1", - "inherits": "fdm_process_bbl_0.28", + "inherits": "fdm_process_single_0.28", "from": "system", "setting_id": "GP082", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json index f1923e0d69e..a0c3058a710 100644 --- a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json +++ b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL A1M.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.28mm Extra Draft @BBL A1M", - "inherits": "fdm_process_bbl_0.28", + "inherits": "fdm_process_single_0.28", "from": "system", "setting_id": "GP048", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL P1P.json b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL P1P.json index 4f9bb7b53ed..a1dbdc67e65 100644 --- a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL P1P.json +++ b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL P1P.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.28mm Extra Draft @BBL P1P", - "inherits": "fdm_process_bbl_0.28", + "inherits": "fdm_process_single_0.28", "from": "system", "setting_id": "GP023", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL X1C.json b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL X1C.json index 4d544e0f97a..0dbb703749d 100644 --- a/resources/profiles/BBL/process/0.28mm Extra Draft @BBL X1C.json +++ b/resources/profiles/BBL/process/0.28mm Extra Draft @BBL X1C.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.28mm Extra Draft @BBL X1C", - "inherits": "fdm_process_bbl_0.28", + "inherits": "fdm_process_single_0.28", "from": "system", "setting_id": "GP006", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Standard @BBL A1 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Standard @BBL A1 0.6 nozzle.json index 26ad6e58061..dce6cbfc307 100644 --- a/resources/profiles/BBL/process/0.30mm Standard @BBL A1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Standard @BBL A1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Standard @BBL A1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP096", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json index 164c03866f3..4fffef2b26f 100644 --- a/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Standard @BBL P1P 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP016", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Standard @BBL X1 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Standard @BBL X1 0.6 nozzle.json index e501731193c..d622c05abad 100644 --- a/resources/profiles/BBL/process/0.30mm Standard @BBL X1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Standard @BBL X1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Standard @BBL X1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP011", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Standard @BBL X1C 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Standard @BBL X1C 0.6 nozzle.json index 7a629102571..55a49f3888c 100644 --- a/resources/profiles/BBL/process/0.30mm Standard @BBL X1C 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Standard @BBL X1C 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Standard @BBL X1C 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP010", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Strength @BBL A1 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Strength @BBL A1 0.6 nozzle.json index 775523f0d6d..67cf897a41d 100644 --- a/resources/profiles/BBL/process/0.30mm Strength @BBL A1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Strength @BBL A1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Strength @BBL A1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP097", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Strength @BBL A1M 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Strength @BBL A1M 0.6 nozzle.json index 044c7c24cbd..e5c6026fb5a 100644 --- a/resources/profiles/BBL/process/0.30mm Strength @BBL A1M 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Strength @BBL A1M 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Strength @BBL A1M 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP061", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json index 284206f4fac..8a711ba4a6d 100644 --- a/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Strength @BBL P1P 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Strength @BBL P1P 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP067", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.30mm Strength @BBL X1C 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Strength @BBL X1C 0.6 nozzle.json index 7d39dcfa0c7..dc25f49cb35 100644 --- a/resources/profiles/BBL/process/0.30mm Strength @BBL X1C 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.30mm Strength @BBL X1C 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.30mm Strength @BBL X1C 0.6 nozzle", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_single_0.30_nozzle_0.6", "from": "system", "setting_id": "GP036", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.32mm Optimal @BBL A1 0.8 nozzle.json b/resources/profiles/BBL/process/0.32mm Optimal @BBL A1 0.8 nozzle.json index b1e8658fce1..799c9c96c2a 100644 --- a/resources/profiles/BBL/process/0.32mm Optimal @BBL A1 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.32mm Optimal @BBL A1 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.32mm Optimal @BBL A1 0.8 nozzle", - "inherits": "fdm_process_bbl_0.32_nozzle_0.8", + "inherits": "fdm_process_single_0.32_nozzle_0.8", "from": "system", "setting_id": "GP093", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.32mm Optimal @BBL A1M 0.8 nozzle.json b/resources/profiles/BBL/process/0.32mm Optimal @BBL A1M 0.8 nozzle.json index e3778f37093..41209c609db 100644 --- a/resources/profiles/BBL/process/0.32mm Optimal @BBL A1M 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.32mm Optimal @BBL A1M 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.32mm Optimal @BBL A1M 0.8 nozzle", - "inherits": "fdm_process_bbl_0.32_nozzle_0.8", + "inherits": "fdm_process_single_0.32_nozzle_0.8", "from": "system", "setting_id": "GP058", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json index 7586ed84bfc..8447e73bc21 100644 --- a/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.32mm Optimal @BBL P1P 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.32mm Optimal @BBL P1P 0.8 nozzle", - "inherits": "fdm_process_bbl_0.32_nozzle_0.8", + "inherits": "fdm_process_single_0.32_nozzle_0.8", "from": "system", "setting_id": "GP075", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.32mm Standard @BBL X1C 0.8 nozzle.json b/resources/profiles/BBL/process/0.32mm Standard @BBL X1C 0.8 nozzle.json index 148b39055b5..50219578c6e 100644 --- a/resources/profiles/BBL/process/0.32mm Standard @BBL X1C 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.32mm Standard @BBL X1C 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.32mm Standard @BBL X1C 0.8 nozzle", - "inherits": "fdm_process_bbl_0.32_nozzle_0.8", + "inherits": "fdm_process_single_0.32_nozzle_0.8", "from": "system", "setting_id": "GP033", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.36mm Draft @BBL A1 0.6 nozzle.json b/resources/profiles/BBL/process/0.36mm Draft @BBL A1 0.6 nozzle.json index e5ebbcfe315..230396014fe 100644 --- a/resources/profiles/BBL/process/0.36mm Draft @BBL A1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.36mm Draft @BBL A1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.36mm Draft @BBL A1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.36_nozzle_0.6", + "inherits": "fdm_process_single_0.36_nozzle_0.6", "from": "system", "setting_id": "GP090", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.36mm Draft @BBL A1M 0.6 nozzle.json b/resources/profiles/BBL/process/0.36mm Draft @BBL A1M 0.6 nozzle.json index 0268a0ea0fa..835655d8312 100644 --- a/resources/profiles/BBL/process/0.36mm Draft @BBL A1M 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.36mm Draft @BBL A1M 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.36mm Draft @BBL A1M 0.6 nozzle", - "inherits": "fdm_process_bbl_0.36_nozzle_0.6", + "inherits": "fdm_process_single_0.36_nozzle_0.6", "from": "system", "setting_id": "GP055", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json index 51251017b3e..41d988e684f 100644 --- a/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.36mm Draft @BBL P1P 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.36mm Draft @BBL P1P 0.6 nozzle", - "inherits": "fdm_process_bbl_0.36_nozzle_0.6", + "inherits": "fdm_process_single_0.36_nozzle_0.6", "from": "system", "setting_id": "GP070", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.36mm Standard @BBL X1C 0.6 nozzle.json b/resources/profiles/BBL/process/0.36mm Standard @BBL X1C 0.6 nozzle.json index d09c89ecb7c..2348de67e44 100644 --- a/resources/profiles/BBL/process/0.36mm Standard @BBL X1C 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.36mm Standard @BBL X1C 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.36mm Standard @BBL X1C 0.6 nozzle", - "inherits": "fdm_process_bbl_0.36_nozzle_0.6", + "inherits": "fdm_process_single_0.36_nozzle_0.6", "from": "system", "setting_id": "GP030", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.40mm Standard @BBL A1 0.8 nozzle.json b/resources/profiles/BBL/process/0.40mm Standard @BBL A1 0.8 nozzle.json index de5ffe19c33..5fa1b108aae 100644 --- a/resources/profiles/BBL/process/0.40mm Standard @BBL A1 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.40mm Standard @BBL A1 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.40mm Standard @BBL A1 0.8 nozzle", - "inherits": "fdm_process_bbl_0.40_nozzle_0.8", + "inherits": "fdm_process_single_0.40_nozzle_0.8", "from": "system", "setting_id": "GP098", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json index a647b300b65..57196d2671f 100644 --- a/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.40mm Standard @BBL P1P 0.8 nozzle", - "inherits": "fdm_process_bbl_0.40_nozzle_0.8", + "inherits": "fdm_process_single_0.40_nozzle_0.8", "from": "system", "setting_id": "GP017", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.40mm Standard @BBL X1 0.8 nozzle.json b/resources/profiles/BBL/process/0.40mm Standard @BBL X1 0.8 nozzle.json index f5115f43b79..51339de5254 100644 --- a/resources/profiles/BBL/process/0.40mm Standard @BBL X1 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.40mm Standard @BBL X1 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.40mm Standard @BBL X1 0.8 nozzle", - "inherits": "fdm_process_bbl_0.40_nozzle_0.8", + "inherits": "fdm_process_single_0.40_nozzle_0.8", "from": "system", "setting_id": "GP012", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.40mm Standard @BBL X1C 0.8 nozzle.json b/resources/profiles/BBL/process/0.40mm Standard @BBL X1C 0.8 nozzle.json index 15ba67645d6..0a07b0c26e8 100644 --- a/resources/profiles/BBL/process/0.40mm Standard @BBL X1C 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.40mm Standard @BBL X1C 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.40mm Standard @BBL X1C 0.8 nozzle", - "inherits": "fdm_process_bbl_0.40_nozzle_0.8", + "inherits": "fdm_process_single_0.40_nozzle_0.8", "from": "system", "setting_id": "GP009", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1 0.6 nozzle.json b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1 0.6 nozzle.json index d6b15c6eba8..2c968b7404f 100644 --- a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.42mm Extra Draft @BBL A1 0.6 nozzle", - "inherits": "fdm_process_bbl_0.42_nozzle_0.6", + "inherits": "fdm_process_single_0.42_nozzle_0.6", "from": "system", "setting_id": "GP091", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1M 0.6 nozzle.json b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1M 0.6 nozzle.json index 571ab55f0dc..e13b0b7e7ae 100644 --- a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1M 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL A1M 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.42mm Extra Draft @BBL A1M 0.6 nozzle", - "inherits": "fdm_process_bbl_0.42_nozzle_0.6", + "inherits": "fdm_process_single_0.42_nozzle_0.6", "from": "system", "setting_id": "GP056", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json index 69578536be0..b0e9ac619ee 100644 --- a/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.42mm Extra Draft @BBL P1P 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.42mm Extra Draft @BBL P1P 0.6 nozzle", - "inherits": "fdm_process_bbl_0.42_nozzle_0.6", + "inherits": "fdm_process_single_0.42_nozzle_0.6", "from": "system", "setting_id": "GP073", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.42mm Standard @BBL X1C 0.6 nozzle.json b/resources/profiles/BBL/process/0.42mm Standard @BBL X1C 0.6 nozzle.json index 1005112ff6d..857a50dfbd8 100644 --- a/resources/profiles/BBL/process/0.42mm Standard @BBL X1C 0.6 nozzle.json +++ b/resources/profiles/BBL/process/0.42mm Standard @BBL X1C 0.6 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.42mm Standard @BBL X1C 0.6 nozzle", - "inherits": "fdm_process_bbl_0.42_nozzle_0.6", + "inherits": "fdm_process_single_0.42_nozzle_0.6", "from": "system", "setting_id": "GP031", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.48mm Draft @BBL A1 0.8 nozzle.json b/resources/profiles/BBL/process/0.48mm Draft @BBL A1 0.8 nozzle.json index d3e5e0c26ab..a60a7495be1 100644 --- a/resources/profiles/BBL/process/0.48mm Draft @BBL A1 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.48mm Draft @BBL A1 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.48mm Draft @BBL A1 0.8 nozzle", - "inherits": "fdm_process_bbl_0.48_nozzle_0.8", + "inherits": "fdm_process_single_0.48_nozzle_0.8", "from": "system", "setting_id": "GP094", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.48mm Draft @BBL A1M 0.8 nozzle.json b/resources/profiles/BBL/process/0.48mm Draft @BBL A1M 0.8 nozzle.json index dc3159fb7f1..7c619a104c0 100644 --- a/resources/profiles/BBL/process/0.48mm Draft @BBL A1M 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.48mm Draft @BBL A1M 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.48mm Draft @BBL A1M 0.8 nozzle", - "inherits": "fdm_process_bbl_0.48_nozzle_0.8", + "inherits": "fdm_process_single_0.48_nozzle_0.8", "from": "system", "setting_id": "GP059", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json index 7a5062a369e..2a056071132 100644 --- a/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.48mm Draft @BBL P1P 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.48mm Draft @BBL P1P 0.8 nozzle", - "inherits": "fdm_process_bbl_0.48_nozzle_0.8", + "inherits": "fdm_process_single_0.48_nozzle_0.8", "from": "system", "setting_id": "GP074", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.48mm Standard @BBL X1C 0.8 nozzle.json b/resources/profiles/BBL/process/0.48mm Standard @BBL X1C 0.8 nozzle.json index 40c694d8914..398f8d6f117 100644 --- a/resources/profiles/BBL/process/0.48mm Standard @BBL X1C 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.48mm Standard @BBL X1C 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.48mm Standard @BBL X1C 0.8 nozzle", - "inherits": "fdm_process_bbl_0.48_nozzle_0.8", + "inherits": "fdm_process_single_0.48_nozzle_0.8", "from": "system", "setting_id": "GP034", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1 0.8 nozzle.json b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1 0.8 nozzle.json index 7669c35cdca..3b8778eaee6 100644 --- a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.56mm Extra Draft @BBL A1 0.8 nozzle", - "inherits": "fdm_process_bbl_0.56_nozzle_0.8", + "inherits": "fdm_process_single_0.56_nozzle_0.8", "from": "system", "setting_id": "GP095", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1M 0.8 nozzle.json b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1M 0.8 nozzle.json index 8090a646179..e4719a71d66 100644 --- a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1M 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL A1M 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.56mm Extra Draft @BBL A1M 0.8 nozzle", - "inherits": "fdm_process_bbl_0.56_nozzle_0.8", + "inherits": "fdm_process_single_0.56_nozzle_0.8", "from": "system", "setting_id": "GP060", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json index fcc8b66b82f..bd77cf1e45f 100644 --- a/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.56mm Extra Draft @BBL P1P 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.56mm Extra Draft @BBL P1P 0.8 nozzle", - "inherits": "fdm_process_bbl_0.56_nozzle_0.8", + "inherits": "fdm_process_single_0.56_nozzle_0.8", "from": "system", "setting_id": "GP071", "instantiation": "true", diff --git a/resources/profiles/BBL/process/0.56mm Standard @BBL X1C 0.8 nozzle.json b/resources/profiles/BBL/process/0.56mm Standard @BBL X1C 0.8 nozzle.json index 9b80a1a5dda..fa913af494f 100644 --- a/resources/profiles/BBL/process/0.56mm Standard @BBL X1C 0.8 nozzle.json +++ b/resources/profiles/BBL/process/0.56mm Standard @BBL X1C 0.8 nozzle.json @@ -1,7 +1,7 @@ { "type": "process", "name": "0.56mm Standard @BBL X1C 0.8 nozzle", - "inherits": "fdm_process_bbl_0.56_nozzle_0.8", + "inherits": "fdm_process_single_0.56_nozzle_0.8", "from": "system", "setting_id": "GP035", "instantiation": "true", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.06_nozzle_0.2.json b/resources/profiles/BBL/process/fdm_process_single_0.06_nozzle_0.2.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.06_nozzle_0.2.json rename to resources/profiles/BBL/process/fdm_process_single_0.06_nozzle_0.2.json index 364bcaa1ee4..ea35d93d185 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.06_nozzle_0.2.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.06_nozzle_0.2.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.06_nozzle_0.2", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.06_nozzle_0.2", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.06", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.08.json b/resources/profiles/BBL/process/fdm_process_single_0.08.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.08.json rename to resources/profiles/BBL/process/fdm_process_single_0.08.json index 61897f7a738..e9b651f2826 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.08.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.08.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.08", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.08", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.08", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.08_nozzle_0.2.json b/resources/profiles/BBL/process/fdm_process_single_0.08_nozzle_0.2.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.08_nozzle_0.2.json rename to resources/profiles/BBL/process/fdm_process_single_0.08_nozzle_0.2.json index 52a1749075b..643d8667c2c 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.08_nozzle_0.2.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.08_nozzle_0.2.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.08_nozzle_0.2", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.08_nozzle_0.2", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.08", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.10_nozzle_0.2.json b/resources/profiles/BBL/process/fdm_process_single_0.10_nozzle_0.2.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.10_nozzle_0.2.json rename to resources/profiles/BBL/process/fdm_process_single_0.10_nozzle_0.2.json index 020a3f9cc87..2caa8812d2a 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.10_nozzle_0.2.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.10_nozzle_0.2.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.10_nozzle_0.2", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.10_nozzle_0.2", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.1", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.12.json b/resources/profiles/BBL/process/fdm_process_single_0.12.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.12.json rename to resources/profiles/BBL/process/fdm_process_single_0.12.json index e22593fb300..43878152786 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.12.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.12.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.12", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.12", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.12", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.12_nozzle_0.2.json b/resources/profiles/BBL/process/fdm_process_single_0.12_nozzle_0.2.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.12_nozzle_0.2.json rename to resources/profiles/BBL/process/fdm_process_single_0.12_nozzle_0.2.json index 56aedfd03ed..f2c1662d40a 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.12_nozzle_0.2.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.12_nozzle_0.2.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.12_nozzle_0.2", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.12_nozzle_0.2", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.12", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.14_nozzle_0.2.json b/resources/profiles/BBL/process/fdm_process_single_0.14_nozzle_0.2.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.14_nozzle_0.2.json rename to resources/profiles/BBL/process/fdm_process_single_0.14_nozzle_0.2.json index 7c10c6c6730..0cae00d0307 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.14_nozzle_0.2.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.14_nozzle_0.2.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.14_nozzle_0.2", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.14_nozzle_0.2", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.14", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.16.json b/resources/profiles/BBL/process/fdm_process_single_0.16.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.16.json rename to resources/profiles/BBL/process/fdm_process_single_0.16.json index 3d60b01d8bb..5bcb42994dc 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.16.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.16.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.16", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.16", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.16", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.18_nozzle_0.6.json b/resources/profiles/BBL/process/fdm_process_single_0.18_nozzle_0.6.json similarity index 89% rename from resources/profiles/BBL/process/fdm_process_bbl_0.18_nozzle_0.6.json rename to resources/profiles/BBL/process/fdm_process_single_0.18_nozzle_0.6.json index 31c88af561e..db8428fad79 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.18_nozzle_0.6.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.18_nozzle_0.6.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.18_nozzle_0.6", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.18_nozzle_0.6", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.18", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.20.json b/resources/profiles/BBL/process/fdm_process_single_0.20.json similarity index 84% rename from resources/profiles/BBL/process/fdm_process_bbl_0.20.json rename to resources/profiles/BBL/process/fdm_process_single_0.20.json index 331f77e4e70..a6809f2df2d 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.20.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.20.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.20", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.20", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "elefant_foot_compensation": "0.15", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.24.json b/resources/profiles/BBL/process/fdm_process_single_0.24.json similarity index 86% rename from resources/profiles/BBL/process/fdm_process_bbl_0.24.json rename to resources/profiles/BBL/process/fdm_process_single_0.24.json index 1a0bd76e40d..72d1f540097 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.24.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.24.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.24", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.24", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.24", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.24_nozzle_0.6.json b/resources/profiles/BBL/process/fdm_process_single_0.24_nozzle_0.6.json similarity index 87% rename from resources/profiles/BBL/process/fdm_process_bbl_0.24_nozzle_0.6.json rename to resources/profiles/BBL/process/fdm_process_single_0.24_nozzle_0.6.json index ca621513421..76d6443637d 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.24_nozzle_0.6.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.24_nozzle_0.6.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.24_nozzle_0.6", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.24_nozzle_0.6", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.24", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.24_nozzle_0.8.json b/resources/profiles/BBL/process/fdm_process_single_0.24_nozzle_0.8.json similarity index 88% rename from resources/profiles/BBL/process/fdm_process_bbl_0.24_nozzle_0.8.json rename to resources/profiles/BBL/process/fdm_process_single_0.24_nozzle_0.8.json index 88e1f680758..516aeab7254 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.24_nozzle_0.8.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.24_nozzle_0.8.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.24_nozzle_0.8", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.24_nozzle_0.8", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.24", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.28.json b/resources/profiles/BBL/process/fdm_process_single_0.28.json similarity index 86% rename from resources/profiles/BBL/process/fdm_process_bbl_0.28.json rename to resources/profiles/BBL/process/fdm_process_single_0.28.json index efd2cc4d010..ebaf9c18a17 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.28.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.28.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.28", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.28", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.28", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.30_nozzle_0.6.json b/resources/profiles/BBL/process/fdm_process_single_0.30_nozzle_0.6.json similarity index 87% rename from resources/profiles/BBL/process/fdm_process_bbl_0.30_nozzle_0.6.json rename to resources/profiles/BBL/process/fdm_process_single_0.30_nozzle_0.6.json index 08476dbb784..0fb84521137 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.30_nozzle_0.6.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.30_nozzle_0.6.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.30_nozzle_0.6", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.30_nozzle_0.6", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.3", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.32_nozzle_0.8.json b/resources/profiles/BBL/process/fdm_process_single_0.32_nozzle_0.8.json similarity index 88% rename from resources/profiles/BBL/process/fdm_process_bbl_0.32_nozzle_0.8.json rename to resources/profiles/BBL/process/fdm_process_single_0.32_nozzle_0.8.json index c1622d28f55..4c950cea9f5 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.32_nozzle_0.8.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.32_nozzle_0.8.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.32_nozzle_0.8", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.32_nozzle_0.8", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.32", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.36_nozzle_0.6.json b/resources/profiles/BBL/process/fdm_process_single_0.36_nozzle_0.6.json similarity index 87% rename from resources/profiles/BBL/process/fdm_process_bbl_0.36_nozzle_0.6.json rename to resources/profiles/BBL/process/fdm_process_single_0.36_nozzle_0.6.json index f9c917dfc58..5deb4a3d4b5 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.36_nozzle_0.6.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.36_nozzle_0.6.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.36_nozzle_0.6", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.36_nozzle_0.6", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.36", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.40_nozzle_0.8.json b/resources/profiles/BBL/process/fdm_process_single_0.40_nozzle_0.8.json similarity index 88% rename from resources/profiles/BBL/process/fdm_process_bbl_0.40_nozzle_0.8.json rename to resources/profiles/BBL/process/fdm_process_single_0.40_nozzle_0.8.json index be6eb5944a3..0b8258b96e4 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.40_nozzle_0.8.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.40_nozzle_0.8.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.40_nozzle_0.8", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.40_nozzle_0.8", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.4", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.42_nozzle_0.6.json b/resources/profiles/BBL/process/fdm_process_single_0.42_nozzle_0.6.json similarity index 87% rename from resources/profiles/BBL/process/fdm_process_bbl_0.42_nozzle_0.6.json rename to resources/profiles/BBL/process/fdm_process_single_0.42_nozzle_0.6.json index d879b17b8b0..6923ab22363 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.42_nozzle_0.6.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.42_nozzle_0.6.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.42_nozzle_0.6", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.42_nozzle_0.6", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.42", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.48_nozzle_0.8.json b/resources/profiles/BBL/process/fdm_process_single_0.48_nozzle_0.8.json similarity index 88% rename from resources/profiles/BBL/process/fdm_process_bbl_0.48_nozzle_0.8.json rename to resources/profiles/BBL/process/fdm_process_single_0.48_nozzle_0.8.json index e9955abd55e..f66069668c0 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.48_nozzle_0.8.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.48_nozzle_0.8.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.48_nozzle_0.8", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.48_nozzle_0.8", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.48", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.56_nozzle_0.8.json b/resources/profiles/BBL/process/fdm_process_single_0.56_nozzle_0.8.json similarity index 88% rename from resources/profiles/BBL/process/fdm_process_bbl_0.56_nozzle_0.8.json rename to resources/profiles/BBL/process/fdm_process_single_0.56_nozzle_0.8.json index 99fb6bf6e7d..41e489443b7 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.56_nozzle_0.8.json +++ b/resources/profiles/BBL/process/fdm_process_single_0.56_nozzle_0.8.json @@ -1,7 +1,7 @@ { "type": "process", - "name": "fdm_process_bbl_0.56_nozzle_0.8", - "inherits": "fdm_process_bbl_common", + "name": "fdm_process_single_0.56_nozzle_0.8", + "inherits": "fdm_process_single_common", "from": "system", "instantiation": "false", "layer_height": "0.56", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_common.json b/resources/profiles/BBL/process/fdm_process_single_common.json similarity index 94% rename from resources/profiles/BBL/process/fdm_process_bbl_common.json rename to resources/profiles/BBL/process/fdm_process_single_common.json index 672244c1e77..9edabd17ec6 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_common.json +++ b/resources/profiles/BBL/process/fdm_process_single_common.json @@ -1,6 +1,6 @@ { "type": "process", - "name": "fdm_process_bbl_common", + "name": "fdm_process_single_common", "inherits": "fdm_process_common", "from": "system", "instantiation": "false", diff --git a/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json b/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json index 3e4b2431bbc..9e6363d6e20 100644 --- a/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json +++ b/resources/profiles/Ratrig/process/0.20mm Bambu Support W @RatRig.json @@ -4,7 +4,7 @@ "name": "0.20mm Bambu Support W @RatRig", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_single_0.20", "enable_support": "1", "support_interface_top_layers": "3", "support_top_z_distance": "0.2", From 49ae4ab8f7ab182ab2033995cd23e2b66b558cfa Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 27 May 2025 10:33:07 +0800 Subject: [PATCH 117/127] Update OrcaArena vendor name in file names --- resources/profiles/OrcaArena.json | 88 +++++++++---------- ...0.06mm Standard @Arena X1C 0.2 nozzle.json | 2 +- .../process/0.08mm Extra Fine @Arena X1C.json | 2 +- ...0.08mm Standard @Arena X1C 0.2 nozzle.json | 2 +- ...0.10mm Standard @Arena X1C 0.2 nozzle.json | 2 +- .../process/0.12mm Fine @Arena X1C.json | 2 +- ...0.12mm Standard @Arena X1C 0.2 nozzle.json | 2 +- ...0.14mm Standard @Arena X1C 0.2 nozzle.json | 2 +- .../process/0.16mm Optimal @Arena X1C.json | 2 +- ...0.18mm Standard @Arena X1C 0.6 nozzle.json | 2 +- .../0.20mm Bambu Support W @Arena X1C.json | 2 +- .../process/0.20mm Standard @Arena X1C.json | 2 +- .../process/0.20mm Strength @Arena X1C.json | 2 +- .../process/0.24mm Draft @Arena X1C.json | 2 +- ...0.24mm Standard @Arena X1C 0.6 nozzle.json | 2 +- ...0.24mm Standard @Arena X1C 0.8 nozzle.json | 2 +- .../0.28mm Extra Draft @Arena X1C.json | 2 +- ...0.30mm Standard @Arena X1C 0.6 nozzle.json | 2 +- ...0.30mm Strength @Arena X1C 0.6 nozzle.json | 2 +- ...0.32mm Standard @Arena X1C 0.8 nozzle.json | 2 +- ...0.36mm Standard @Arena X1C 0.6 nozzle.json | 2 +- ...0.40mm Standard @Arena X1C 0.8 nozzle.json | 2 +- ...0.42mm Standard @Arena X1C 0.6 nozzle.json | 2 +- ...0.48mm Standard @Arena X1C 0.8 nozzle.json | 2 +- ...0.56mm Standard @Arena X1C 0.8 nozzle.json | 2 +- ...=> fdm_process_arena_0.06_nozzle_0.2.json} | 4 +- ..._0.08.json => fdm_process_arena_0.08.json} | 4 +- ...=> fdm_process_arena_0.08_nozzle_0.2.json} | 4 +- ...=> fdm_process_arena_0.10_nozzle_0.2.json} | 4 +- ..._0.12.json => fdm_process_arena_0.12.json} | 4 +- ...=> fdm_process_arena_0.12_nozzle_0.2.json} | 4 +- ...=> fdm_process_arena_0.14_nozzle_0.2.json} | 4 +- ..._0.16.json => fdm_process_arena_0.16.json} | 4 +- ...=> fdm_process_arena_0.18_nozzle_0.6.json} | 4 +- ..._0.20.json => fdm_process_arena_0.20.json} | 4 +- ..._0.24.json => fdm_process_arena_0.24.json} | 4 +- ...=> fdm_process_arena_0.24_nozzle_0.6.json} | 4 +- ...=> fdm_process_arena_0.24_nozzle_0.8.json} | 4 +- ..._0.28.json => fdm_process_arena_0.28.json} | 4 +- ...=> fdm_process_arena_0.30_nozzle_0.6.json} | 4 +- ...=> fdm_process_arena_0.32_nozzle_0.8.json} | 4 +- ...=> fdm_process_arena_0.36_nozzle_0.6.json} | 4 +- ...=> fdm_process_arena_0.40_nozzle_0.8.json} | 4 +- ...=> fdm_process_arena_0.42_nozzle_0.6.json} | 4 +- ...=> fdm_process_arena_0.48_nozzle_0.8.json} | 4 +- ...=> fdm_process_arena_0.56_nozzle_0.8.json} | 4 +- ...mon.json => fdm_process_arena_common.json} | 2 +- 47 files changed, 111 insertions(+), 111 deletions(-) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.06_nozzle_0.2.json => fdm_process_arena_0.06_nozzle_0.2.json} (87%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.08.json => fdm_process_arena_0.08.json} (89%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.08_nozzle_0.2.json => fdm_process_arena_0.08_nozzle_0.2.json} (87%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.10_nozzle_0.2.json => fdm_process_arena_0.10_nozzle_0.2.json} (88%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.12.json => fdm_process_arena_0.12.json} (89%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.12_nozzle_0.2.json => fdm_process_arena_0.12_nozzle_0.2.json} (87%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.14_nozzle_0.2.json => fdm_process_arena_0.14_nozzle_0.2.json} (87%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.16.json => fdm_process_arena_0.16.json} (89%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.18_nozzle_0.6.json => fdm_process_arena_0.18_nozzle_0.6.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.20.json => fdm_process_arena_0.20.json} (86%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.24.json => fdm_process_arena_0.24.json} (88%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.24_nozzle_0.6.json => fdm_process_arena_0.24_nozzle_0.6.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.24_nozzle_0.8.json => fdm_process_arena_0.24_nozzle_0.8.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.28.json => fdm_process_arena_0.28.json} (88%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.30_nozzle_0.6.json => fdm_process_arena_0.30_nozzle_0.6.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.32_nozzle_0.8.json => fdm_process_arena_0.32_nozzle_0.8.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.36_nozzle_0.6.json => fdm_process_arena_0.36_nozzle_0.6.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.40_nozzle_0.8.json => fdm_process_arena_0.40_nozzle_0.8.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.42_nozzle_0.6.json => fdm_process_arena_0.42_nozzle_0.6.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.48_nozzle_0.8.json => fdm_process_arena_0.48_nozzle_0.8.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_0.56_nozzle_0.8.json => fdm_process_arena_0.56_nozzle_0.8.json} (91%) rename resources/profiles/OrcaArena/process/{fdm_process_bbl_common.json => fdm_process_arena_common.json} (98%) diff --git a/resources/profiles/OrcaArena.json b/resources/profiles/OrcaArena.json index d218006bee6..6f10184faf0 100644 --- a/resources/profiles/OrcaArena.json +++ b/resources/profiles/OrcaArena.json @@ -16,44 +16,44 @@ "sub_path": "process/fdm_process_common.json" }, { - "name": "fdm_process_bbl_common", - "sub_path": "process/fdm_process_bbl_common.json" + "name": "fdm_process_arena_common", + "sub_path": "process/fdm_process_arena_common.json" }, { - "name": "fdm_process_bbl_0.08", - "sub_path": "process/fdm_process_bbl_0.08.json" + "name": "fdm_process_arena_0.08", + "sub_path": "process/fdm_process_arena_0.08.json" }, { - "name": "fdm_process_bbl_0.10_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.10_nozzle_0.2.json" + "name": "fdm_process_arena_0.10_nozzle_0.2", + "sub_path": "process/fdm_process_arena_0.10_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.40_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.40_nozzle_0.8.json" + "name": "fdm_process_arena_0.40_nozzle_0.8", + "sub_path": "process/fdm_process_arena_0.40_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.30_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.30_nozzle_0.6.json" + "name": "fdm_process_arena_0.30_nozzle_0.6", + "sub_path": "process/fdm_process_arena_0.30_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.12", - "sub_path": "process/fdm_process_bbl_0.12.json" + "name": "fdm_process_arena_0.12", + "sub_path": "process/fdm_process_arena_0.12.json" }, { - "name": "fdm_process_bbl_0.16", - "sub_path": "process/fdm_process_bbl_0.16.json" + "name": "fdm_process_arena_0.16", + "sub_path": "process/fdm_process_arena_0.16.json" }, { - "name": "fdm_process_bbl_0.20", - "sub_path": "process/fdm_process_bbl_0.20.json" + "name": "fdm_process_arena_0.20", + "sub_path": "process/fdm_process_arena_0.20.json" }, { - "name": "fdm_process_bbl_0.24", - "sub_path": "process/fdm_process_bbl_0.24.json" + "name": "fdm_process_arena_0.24", + "sub_path": "process/fdm_process_arena_0.24.json" }, { - "name": "fdm_process_bbl_0.28", - "sub_path": "process/fdm_process_bbl_0.28.json" + "name": "fdm_process_arena_0.28", + "sub_path": "process/fdm_process_arena_0.28.json" }, { "name": "0.08mm Extra Fine @Arena X1C", @@ -96,20 +96,20 @@ "sub_path": "process/0.40mm Standard @Arena X1C 0.8 nozzle.json" }, { - "name": "fdm_process_bbl_0.06_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.06_nozzle_0.2.json" + "name": "fdm_process_arena_0.06_nozzle_0.2", + "sub_path": "process/fdm_process_arena_0.06_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.08_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.08_nozzle_0.2.json" + "name": "fdm_process_arena_0.08_nozzle_0.2", + "sub_path": "process/fdm_process_arena_0.08_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.12_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.12_nozzle_0.2.json" + "name": "fdm_process_arena_0.12_nozzle_0.2", + "sub_path": "process/fdm_process_arena_0.12_nozzle_0.2.json" }, { - "name": "fdm_process_bbl_0.14_nozzle_0.2", - "sub_path": "process/fdm_process_bbl_0.14_nozzle_0.2.json" + "name": "fdm_process_arena_0.14_nozzle_0.2", + "sub_path": "process/fdm_process_arena_0.14_nozzle_0.2.json" }, { "name": "0.06mm Standard @Arena X1C 0.2 nozzle", @@ -128,20 +128,20 @@ "sub_path": "process/0.14mm Standard @Arena X1C 0.2 nozzle.json" }, { - "name": "fdm_process_bbl_0.18_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.18_nozzle_0.6.json" + "name": "fdm_process_arena_0.18_nozzle_0.6", + "sub_path": "process/fdm_process_arena_0.18_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.24_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.24_nozzle_0.6.json" + "name": "fdm_process_arena_0.24_nozzle_0.6", + "sub_path": "process/fdm_process_arena_0.24_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.36_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.36_nozzle_0.6.json" + "name": "fdm_process_arena_0.36_nozzle_0.6", + "sub_path": "process/fdm_process_arena_0.36_nozzle_0.6.json" }, { - "name": "fdm_process_bbl_0.42_nozzle_0.6", - "sub_path": "process/fdm_process_bbl_0.42_nozzle_0.6.json" + "name": "fdm_process_arena_0.42_nozzle_0.6", + "sub_path": "process/fdm_process_arena_0.42_nozzle_0.6.json" }, { "name": "0.18mm Standard @Arena X1C 0.6 nozzle", @@ -160,20 +160,20 @@ "sub_path": "process/0.42mm Standard @Arena X1C 0.6 nozzle.json" }, { - "name": "fdm_process_bbl_0.24_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.24_nozzle_0.8.json" + "name": "fdm_process_arena_0.24_nozzle_0.8", + "sub_path": "process/fdm_process_arena_0.24_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.32_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.32_nozzle_0.8.json" + "name": "fdm_process_arena_0.32_nozzle_0.8", + "sub_path": "process/fdm_process_arena_0.32_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.48_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.48_nozzle_0.8.json" + "name": "fdm_process_arena_0.48_nozzle_0.8", + "sub_path": "process/fdm_process_arena_0.48_nozzle_0.8.json" }, { - "name": "fdm_process_bbl_0.56_nozzle_0.8", - "sub_path": "process/fdm_process_bbl_0.56_nozzle_0.8.json" + "name": "fdm_process_arena_0.56_nozzle_0.8", + "sub_path": "process/fdm_process_arena_0.56_nozzle_0.8.json" }, { "name": "0.24mm Standard @Arena X1C 0.8 nozzle", diff --git a/resources/profiles/OrcaArena/process/0.06mm Standard @Arena X1C 0.2 nozzle.json b/resources/profiles/OrcaArena/process/0.06mm Standard @Arena X1C 0.2 nozzle.json index fb227626fd0..c11c22991ad 100644 --- a/resources/profiles/OrcaArena/process/0.06mm Standard @Arena X1C 0.2 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.06mm Standard @Arena X1C 0.2 nozzle.json @@ -4,7 +4,7 @@ "name": "0.06mm Standard @Arena X1C 0.2 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.06_nozzle_0.2", + "inherits": "fdm_process_arena_0.06_nozzle_0.2", "compatible_printers": [ "Orca Arena X1 Carbon 0.2 nozzle", "Orca Arena X1 0.2 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.08mm Extra Fine @Arena X1C.json b/resources/profiles/OrcaArena/process/0.08mm Extra Fine @Arena X1C.json index 3f92bb8b6fd..a21add8f871 100644 --- a/resources/profiles/OrcaArena/process/0.08mm Extra Fine @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.08mm Extra Fine @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.08mm Extra Fine @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.08", + "inherits": "fdm_process_arena_0.08", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.08mm Standard @Arena X1C 0.2 nozzle.json b/resources/profiles/OrcaArena/process/0.08mm Standard @Arena X1C 0.2 nozzle.json index b2fe7cb3bb9..99c3bae3852 100644 --- a/resources/profiles/OrcaArena/process/0.08mm Standard @Arena X1C 0.2 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.08mm Standard @Arena X1C 0.2 nozzle.json @@ -4,7 +4,7 @@ "name": "0.08mm Standard @Arena X1C 0.2 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.08_nozzle_0.2", + "inherits": "fdm_process_arena_0.08_nozzle_0.2", "compatible_printers": [ "Orca Arena X1 Carbon 0.2 nozzle", "Orca Arena X1 0.2 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.10mm Standard @Arena X1C 0.2 nozzle.json b/resources/profiles/OrcaArena/process/0.10mm Standard @Arena X1C 0.2 nozzle.json index 89a48d31bbf..c392d0ee9c6 100644 --- a/resources/profiles/OrcaArena/process/0.10mm Standard @Arena X1C 0.2 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.10mm Standard @Arena X1C 0.2 nozzle.json @@ -4,7 +4,7 @@ "name": "0.10mm Standard @Arena X1C 0.2 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "inherits": "fdm_process_arena_0.10_nozzle_0.2", "compatible_printers": [ "Orca Arena X1 Carbon 0.2 nozzle", "Orca Arena X1 0.2 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.12mm Fine @Arena X1C.json b/resources/profiles/OrcaArena/process/0.12mm Fine @Arena X1C.json index 140f6e7331d..e5c28d36eb2 100644 --- a/resources/profiles/OrcaArena/process/0.12mm Fine @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.12mm Fine @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.12mm Fine @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.12", + "inherits": "fdm_process_arena_0.12", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.12mm Standard @Arena X1C 0.2 nozzle.json b/resources/profiles/OrcaArena/process/0.12mm Standard @Arena X1C 0.2 nozzle.json index c63dffe1a47..bc0686ffb87 100644 --- a/resources/profiles/OrcaArena/process/0.12mm Standard @Arena X1C 0.2 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.12mm Standard @Arena X1C 0.2 nozzle.json @@ -4,7 +4,7 @@ "name": "0.12mm Standard @Arena X1C 0.2 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.12_nozzle_0.2", + "inherits": "fdm_process_arena_0.12_nozzle_0.2", "compatible_printers": [ "Orca Arena X1 Carbon 0.2 nozzle", "Orca Arena X1 0.2 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.14mm Standard @Arena X1C 0.2 nozzle.json b/resources/profiles/OrcaArena/process/0.14mm Standard @Arena X1C 0.2 nozzle.json index 2d299244745..37809dbca96 100644 --- a/resources/profiles/OrcaArena/process/0.14mm Standard @Arena X1C 0.2 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.14mm Standard @Arena X1C 0.2 nozzle.json @@ -4,7 +4,7 @@ "name": "0.14mm Standard @Arena X1C 0.2 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.14_nozzle_0.2", + "inherits": "fdm_process_arena_0.14_nozzle_0.2", "compatible_printers": [ "Orca Arena X1 Carbon 0.2 nozzle", "Orca Arena X1 0.2 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.16mm Optimal @Arena X1C.json b/resources/profiles/OrcaArena/process/0.16mm Optimal @Arena X1C.json index 6c41ea8e3f1..a4eae17d26e 100644 --- a/resources/profiles/OrcaArena/process/0.16mm Optimal @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.16mm Optimal @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.16mm Optimal @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.16", + "inherits": "fdm_process_arena_0.16", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.18mm Standard @Arena X1C 0.6 nozzle.json b/resources/profiles/OrcaArena/process/0.18mm Standard @Arena X1C 0.6 nozzle.json index 23e5a273408..66371f83394 100644 --- a/resources/profiles/OrcaArena/process/0.18mm Standard @Arena X1C 0.6 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.18mm Standard @Arena X1C 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "0.18mm Standard @Arena X1C 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.18_nozzle_0.6", + "inherits": "fdm_process_arena_0.18_nozzle_0.6", "compatible_printers": [ "Orca Arena X1 Carbon 0.6 nozzle", "Orca Arena X1 0.6 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json b/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json index b31526453e0..ed49f5d0e96 100644 --- a/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.20mm Bambu Support W @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.20mm Arena Support W @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_arena_0.20", "enable_support": "1", "support_interface_top_layers": "3", "support_top_z_distance": "0.2", diff --git a/resources/profiles/OrcaArena/process/0.20mm Standard @Arena X1C.json b/resources/profiles/OrcaArena/process/0.20mm Standard @Arena X1C.json index 7c29054e32c..dbc599a13c7 100644 --- a/resources/profiles/OrcaArena/process/0.20mm Standard @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.20mm Standard @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.20mm Standard @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_arena_0.20", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.20mm Strength @Arena X1C.json b/resources/profiles/OrcaArena/process/0.20mm Strength @Arena X1C.json index aee1feb20f7..70284b77199 100644 --- a/resources/profiles/OrcaArena/process/0.20mm Strength @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.20mm Strength @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.20mm Strength @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.20", + "inherits": "fdm_process_arena_0.20", "outer_wall_speed": "60", "wall_loops": "6", "sparse_infill_density": "25%", diff --git a/resources/profiles/OrcaArena/process/0.24mm Draft @Arena X1C.json b/resources/profiles/OrcaArena/process/0.24mm Draft @Arena X1C.json index 3493d123c87..b1a5683ad9b 100644 --- a/resources/profiles/OrcaArena/process/0.24mm Draft @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.24mm Draft @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.24mm Draft @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.24", + "inherits": "fdm_process_arena_0.24", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.6 nozzle.json b/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.6 nozzle.json index 0b68f55207f..2468e03eb30 100644 --- a/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.6 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "0.24mm Standard @Arena X1C 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.24_nozzle_0.6", + "inherits": "fdm_process_arena_0.24_nozzle_0.6", "compatible_printers": [ "Orca Arena X1 Carbon 0.6 nozzle", "Orca Arena X1 0.6 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.8 nozzle.json b/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.8 nozzle.json index d41f42e7059..2b699eef159 100644 --- a/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.8 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.24mm Standard @Arena X1C 0.8 nozzle.json @@ -4,7 +4,7 @@ "name": "0.24mm Standard @Arena X1C 0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.24_nozzle_0.8", + "inherits": "fdm_process_arena_0.24_nozzle_0.8", "compatible_printers": [ "Orca Arena X1 Carbon 0.8 nozzle", "Orca Arena X1 0.8 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.28mm Extra Draft @Arena X1C.json b/resources/profiles/OrcaArena/process/0.28mm Extra Draft @Arena X1C.json index 0f7399c0ffe..3f0ce712d23 100644 --- a/resources/profiles/OrcaArena/process/0.28mm Extra Draft @Arena X1C.json +++ b/resources/profiles/OrcaArena/process/0.28mm Extra Draft @Arena X1C.json @@ -4,7 +4,7 @@ "name": "0.28mm Extra Draft @Arena X1C", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.28", + "inherits": "fdm_process_arena_0.28", "compatible_printers": [ "Orca Arena X1 Carbon 0.4 nozzle", "Orca Arena X1 0.4 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.30mm Standard @Arena X1C 0.6 nozzle.json b/resources/profiles/OrcaArena/process/0.30mm Standard @Arena X1C 0.6 nozzle.json index 7b4a4d159dc..72862163d2f 100644 --- a/resources/profiles/OrcaArena/process/0.30mm Standard @Arena X1C 0.6 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.30mm Standard @Arena X1C 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "0.30mm Standard @Arena X1C 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_arena_0.30_nozzle_0.6", "compatible_printers": [ "Orca Arena X1 Carbon 0.6 nozzle" ] diff --git a/resources/profiles/OrcaArena/process/0.30mm Strength @Arena X1C 0.6 nozzle.json b/resources/profiles/OrcaArena/process/0.30mm Strength @Arena X1C 0.6 nozzle.json index 4703c9bd976..22e7ceab3b0 100644 --- a/resources/profiles/OrcaArena/process/0.30mm Strength @Arena X1C 0.6 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.30mm Strength @Arena X1C 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "0.30mm Strength @Arena X1C 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "inherits": "fdm_process_arena_0.30_nozzle_0.6", "wall_loops": "4", "sparse_infill_density":"25%", "compatible_printers": [ diff --git a/resources/profiles/OrcaArena/process/0.32mm Standard @Arena X1C 0.8 nozzle.json b/resources/profiles/OrcaArena/process/0.32mm Standard @Arena X1C 0.8 nozzle.json index 46495ffd045..187a24d811e 100644 --- a/resources/profiles/OrcaArena/process/0.32mm Standard @Arena X1C 0.8 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.32mm Standard @Arena X1C 0.8 nozzle.json @@ -4,7 +4,7 @@ "name": "0.32mm Standard @Arena X1C 0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.32_nozzle_0.8", + "inherits": "fdm_process_arena_0.32_nozzle_0.8", "compatible_printers": [ "Orca Arena X1 Carbon 0.8 nozzle", "Orca Arena X1 0.8 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.36mm Standard @Arena X1C 0.6 nozzle.json b/resources/profiles/OrcaArena/process/0.36mm Standard @Arena X1C 0.6 nozzle.json index 73188a627a3..51c677d51f3 100644 --- a/resources/profiles/OrcaArena/process/0.36mm Standard @Arena X1C 0.6 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.36mm Standard @Arena X1C 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "0.36mm Standard @Arena X1C 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.36_nozzle_0.6", + "inherits": "fdm_process_arena_0.36_nozzle_0.6", "compatible_printers": [ "Orca Arena X1 Carbon 0.6 nozzle", "Orca Arena X1 0.6 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.40mm Standard @Arena X1C 0.8 nozzle.json b/resources/profiles/OrcaArena/process/0.40mm Standard @Arena X1C 0.8 nozzle.json index c89228221ae..69f766b0a59 100644 --- a/resources/profiles/OrcaArena/process/0.40mm Standard @Arena X1C 0.8 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.40mm Standard @Arena X1C 0.8 nozzle.json @@ -4,7 +4,7 @@ "name": "0.40mm Standard @Arena X1C 0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.40_nozzle_0.8", + "inherits": "fdm_process_arena_0.40_nozzle_0.8", "compatible_printers": [ "Orca Arena X1 Carbon 0.8 nozzle" ] diff --git a/resources/profiles/OrcaArena/process/0.42mm Standard @Arena X1C 0.6 nozzle.json b/resources/profiles/OrcaArena/process/0.42mm Standard @Arena X1C 0.6 nozzle.json index 0dd4f8e8299..de38bf2726f 100644 --- a/resources/profiles/OrcaArena/process/0.42mm Standard @Arena X1C 0.6 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.42mm Standard @Arena X1C 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "0.42mm Standard @Arena X1C 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.42_nozzle_0.6", + "inherits": "fdm_process_arena_0.42_nozzle_0.6", "compatible_printers": [ "Orca Arena X1 Carbon 0.6 nozzle", "Orca Arena X1 0.6 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.48mm Standard @Arena X1C 0.8 nozzle.json b/resources/profiles/OrcaArena/process/0.48mm Standard @Arena X1C 0.8 nozzle.json index d745f58ddad..86d937870f3 100644 --- a/resources/profiles/OrcaArena/process/0.48mm Standard @Arena X1C 0.8 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.48mm Standard @Arena X1C 0.8 nozzle.json @@ -4,7 +4,7 @@ "name": "0.48mm Standard @Arena X1C 0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.48_nozzle_0.8", + "inherits": "fdm_process_arena_0.48_nozzle_0.8", "compatible_printers": [ "Orca Arena X1 Carbon 0.8 nozzle", "Orca Arena X1 0.8 nozzle" diff --git a/resources/profiles/OrcaArena/process/0.56mm Standard @Arena X1C 0.8 nozzle.json b/resources/profiles/OrcaArena/process/0.56mm Standard @Arena X1C 0.8 nozzle.json index 15fade29642..62e578beb8b 100644 --- a/resources/profiles/OrcaArena/process/0.56mm Standard @Arena X1C 0.8 nozzle.json +++ b/resources/profiles/OrcaArena/process/0.56mm Standard @Arena X1C 0.8 nozzle.json @@ -4,7 +4,7 @@ "name": "0.56mm Standard @Arena X1C 0.8 nozzle", "from": "system", "instantiation": "true", - "inherits": "fdm_process_bbl_0.56_nozzle_0.8", + "inherits": "fdm_process_arena_0.56_nozzle_0.8", "compatible_printers": [ "Orca Arena X1 Carbon 0.8 nozzle", "Orca Arena X1 0.8 nozzle" diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.06_nozzle_0.2.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.06_nozzle_0.2.json similarity index 87% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.06_nozzle_0.2.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.06_nozzle_0.2.json index 35257823ae7..e842267f207 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.06_nozzle_0.2.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.06_nozzle_0.2.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.06_nozzle_0.2", + "name": "fdm_process_arena_0.06_nozzle_0.2", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.06", "initial_layer_print_height": "0.1", "wall_loops": "4", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.08.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.08.json similarity index 89% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.08.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.08.json index 6a3bd6f05db..891e3e65279 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.08.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.08.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.08", + "name": "fdm_process_arena_0.08", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.08", "elefant_foot_compensation": "0.15", "bottom_shell_layers": "7", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.08_nozzle_0.2.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.08_nozzle_0.2.json similarity index 87% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.08_nozzle_0.2.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.08_nozzle_0.2.json index 90fae21397b..e19a49279b9 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.08_nozzle_0.2.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.08_nozzle_0.2.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.08_nozzle_0.2", + "name": "fdm_process_arena_0.08_nozzle_0.2", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.08", "initial_layer_print_height": "0.1", "wall_loops": "4", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.10_nozzle_0.2.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.10_nozzle_0.2.json similarity index 88% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.10_nozzle_0.2.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.10_nozzle_0.2.json index a53df8b5a9f..2a87fdde762 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.10_nozzle_0.2.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.10_nozzle_0.2.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.10_nozzle_0.2", + "name": "fdm_process_arena_0.10_nozzle_0.2", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.1", "initial_layer_print_height": "0.1", "wall_loops": "4", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.12.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.12.json similarity index 89% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.12.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.12.json index 3890b18a5c3..b31a0b012a7 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.12.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.12.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.12", + "name": "fdm_process_arena_0.12", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.12", "bottom_shell_layers": "5", "elefant_foot_compensation": "0.15", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.12_nozzle_0.2.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.12_nozzle_0.2.json similarity index 87% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.12_nozzle_0.2.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.12_nozzle_0.2.json index 8a76d4c7cb2..432d530d207 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.12_nozzle_0.2.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.12_nozzle_0.2.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.12_nozzle_0.2", + "name": "fdm_process_arena_0.12_nozzle_0.2", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.12", "initial_layer_print_height": "0.1", "wall_loops": "4", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.14_nozzle_0.2.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.14_nozzle_0.2.json similarity index 87% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.14_nozzle_0.2.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.14_nozzle_0.2.json index 81bd28b30c3..ec826048d7c 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.14_nozzle_0.2.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.14_nozzle_0.2.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.14_nozzle_0.2", + "name": "fdm_process_arena_0.14_nozzle_0.2", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.14", "initial_layer_print_height": "0.1", "wall_loops": "4", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.16.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.16.json similarity index 89% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.16.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.16.json index 98523a0fa66..016a2a1a016 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.16.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.16.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.16", + "name": "fdm_process_arena_0.16", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.16", "elefant_foot_compensation": "0.15", "bottom_shell_layers": "4", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.18_nozzle_0.6.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.18_nozzle_0.6.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.18_nozzle_0.6.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.18_nozzle_0.6.json index 1a9120fdb98..9fb9a8582fa 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.18_nozzle_0.6.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.18_nozzle_0.6.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.18_nozzle_0.6", + "name": "fdm_process_arena_0.18_nozzle_0.6", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.18", "initial_layer_print_height": "0.3", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.20.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.20.json similarity index 86% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.20.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.20.json index 12fe82dd123..a03d7a0e750 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.20.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.20.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.20", + "name": "fdm_process_arena_0.20", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.2", "elefant_foot_compensation": "0.15", "bottom_shell_layers": "3", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.24.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.24.json similarity index 88% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.24.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.24.json index bb43494a56e..ff5cbbbdd46 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.24.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.24.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.24", + "name": "fdm_process_arena_0.24", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.24", "elefant_foot_compensation": "0.15", "top_surface_line_width": "0.45", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.24_nozzle_0.6.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.24_nozzle_0.6.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.24_nozzle_0.6.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.24_nozzle_0.6.json index aec643962c1..b2d86d7f21e 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.24_nozzle_0.6.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.24_nozzle_0.6.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.24_nozzle_0.6", + "name": "fdm_process_arena_0.24_nozzle_0.6", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.24", "initial_layer_print_height": "0.3", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.24_nozzle_0.8.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.24_nozzle_0.8.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.24_nozzle_0.8.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.24_nozzle_0.8.json index 55d9be4407f..a271c409896 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.24_nozzle_0.8.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.24_nozzle_0.8.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.24_nozzle_0.8", + "name": "fdm_process_arena_0.24_nozzle_0.8", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.24", "initial_layer_print_height": "0.4", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.28.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.28.json similarity index 88% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.28.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.28.json index aeb45ebe562..fc2ea3c5d81 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.28.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.28.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.28", + "name": "fdm_process_arena_0.28", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.28", "elefant_foot_compensation": "0.15", "top_surface_line_width": "0.45", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.30_nozzle_0.6.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.30_nozzle_0.6.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.30_nozzle_0.6.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.30_nozzle_0.6.json index 37decfe4dad..0834bbf0d64 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.30_nozzle_0.6.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.30_nozzle_0.6.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.30_nozzle_0.6", + "name": "fdm_process_arena_0.30_nozzle_0.6", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.3", "initial_layer_print_height": "0.3", "wall_loops": "3", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.32_nozzle_0.8.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.32_nozzle_0.8.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.32_nozzle_0.8.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.32_nozzle_0.8.json index 6172f32e94e..4519ea607d9 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.32_nozzle_0.8.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.32_nozzle_0.8.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.32_nozzle_0.8", + "name": "fdm_process_arena_0.32_nozzle_0.8", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.32", "initial_layer_print_height": "0.3", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.36_nozzle_0.6.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.36_nozzle_0.6.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.36_nozzle_0.6.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.36_nozzle_0.6.json index a8a8a1387a6..4c2316f806d 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.36_nozzle_0.6.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.36_nozzle_0.6.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.36_nozzle_0.6", + "name": "fdm_process_arena_0.36_nozzle_0.6", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.36", "initial_layer_print_height": "0.3", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.40_nozzle_0.8.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.40_nozzle_0.8.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.40_nozzle_0.8.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.40_nozzle_0.8.json index aa514e6f044..d643b852b74 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.40_nozzle_0.8.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.40_nozzle_0.8.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.40_nozzle_0.8", + "name": "fdm_process_arena_0.40_nozzle_0.8", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.4", "initial_layer_print_height": "0.4", "wall_loops": "3", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.42_nozzle_0.6.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.42_nozzle_0.6.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.42_nozzle_0.6.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.42_nozzle_0.6.json index 7d9309c1b1c..35e8b4a7b9e 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.42_nozzle_0.6.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.42_nozzle_0.6.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.42_nozzle_0.6", + "name": "fdm_process_arena_0.42_nozzle_0.6", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.42", "initial_layer_print_height": "0.3", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.48_nozzle_0.8.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.48_nozzle_0.8.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.48_nozzle_0.8.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.48_nozzle_0.8.json index d026bdc7469..92b4378781a 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.48_nozzle_0.8.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.48_nozzle_0.8.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.48_nozzle_0.8", + "name": "fdm_process_arena_0.48_nozzle_0.8", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.48", "initial_layer_print_height": "0.4", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.56_nozzle_0.8.json b/resources/profiles/OrcaArena/process/fdm_process_arena_0.56_nozzle_0.8.json similarity index 91% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_0.56_nozzle_0.8.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_0.56_nozzle_0.8.json index f43ab7e2e5f..8039c670211 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_0.56_nozzle_0.8.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_0.56_nozzle_0.8.json @@ -1,9 +1,9 @@ { "type": "process", - "name": "fdm_process_bbl_0.56_nozzle_0.8", + "name": "fdm_process_arena_0.56_nozzle_0.8", "from": "system", "instantiation": "false", - "inherits": "fdm_process_bbl_common", + "inherits": "fdm_process_arena_common", "layer_height": "0.56", "initial_layer_print_height": "0.4", "wall_loops": "2", diff --git a/resources/profiles/OrcaArena/process/fdm_process_bbl_common.json b/resources/profiles/OrcaArena/process/fdm_process_arena_common.json similarity index 98% rename from resources/profiles/OrcaArena/process/fdm_process_bbl_common.json rename to resources/profiles/OrcaArena/process/fdm_process_arena_common.json index 0f484cdbedf..09e687514ca 100644 --- a/resources/profiles/OrcaArena/process/fdm_process_bbl_common.json +++ b/resources/profiles/OrcaArena/process/fdm_process_arena_common.json @@ -1,6 +1,6 @@ { "type": "process", - "name": "fdm_process_bbl_common", + "name": "fdm_process_arena_common", "from": "system", "instantiation": "false", "inherits": "fdm_process_common", From 26306d586a9d2342561f60fb80d7144946783903 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 31 May 2025 18:54:56 +0800 Subject: [PATCH 118/127] Fix H2D AMS humidity display --- src/slic3r/GUI/Widgets/AMSItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 121d309ed05..54dfbce4539 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -43,7 +43,7 @@ bool AMSinfo::parse_ams_info(MachineObject *obj, Ams *ams, bool remain_flag, boo if (!ams) return false; this->ams_id = ams->id; - if (humidity_flag) { + if (ams->type == 1 || ams->type == 3 || ams->type == N3S_AMS) { this->ams_humidity = ams->humidity; } else{ From 50fe1f73128771ca91018e8da3b14efe56fa3da8 Mon Sep 17 00:00:00 2001 From: tao wang Date: Fri, 10 Jan 2025 20:50:51 +0800 Subject: [PATCH 119/127] NEW:use new homing command jira:[none] Change-Id: I9d60d0b5c2d0e2cf7ac5c5e4b0dbcf2daf6edbb1 (cherry picked from commit 9dce95d401e8333077db63dbad57bda837d0ce19) --- src/slic3r/GUI/DeviceManager.cpp | 9 +++++++++ src/slic3r/GUI/DeviceManager.hpp | 1 + src/slic3r/GUI/StatusPanel.cpp | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 5d4874d1f5f..9cb07b8b866 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -1824,6 +1824,15 @@ int MachineObject::command_go_home() return this->publish_gcode("G28 \n"); } +int MachineObject::command_go_home2() +{ + BOOST_LOG_TRIVIAL(info) << "New protocol of command_go_home2"; + json j; + j["print"]["command"] = "back_to_center"; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + return this->publish_json(j.dump()); +} + int MachineObject::command_control_fan(FanType fan_type, bool on_off) { std::string gcode = (boost::format("M106 P%1% S%2% \n") % (int)fan_type % (on_off ? 255 : 0)).str(); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 49fcc9f350a..b742cefa333 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -946,6 +946,7 @@ class MachineObject int command_xyz_abs(); int command_auto_leveling(); int command_go_home(); + int command_go_home2(); int command_control_fan(FanType fan_type, bool on_off); int command_control_fan_val(FanType fan_type, int val); int command_task_abort(); diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 719ed4b30a5..687cccef54a 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3314,7 +3314,13 @@ void StatusPanel::on_axis_ctrl_xy(wxCommandEvent &event) if (event.GetInt() == 5) { obj->command_axis_control("X", 1.0, -1.0f, 3000); } if (event.GetInt() == 6) { obj->command_axis_control("Y", 1.0, -1.0f, 3000); } if (event.GetInt() == 7) { obj->command_axis_control("X", 1.0, 1.0f, 3000); } - if (event.GetInt() == 8) { obj->command_go_home(); } + if (event.GetInt() == 8) { + if (obj->is_enable_np) { + obj->command_go_home2(); + } else { + obj->command_go_home(); + } + } //check is at home if (event.GetInt() == 1 From e8f5b374b2abcf99597d8ea264eb1d9d83d04d1a Mon Sep 17 00:00:00 2001 From: tao wang Date: Sat, 18 Jan 2025 12:43:32 +0800 Subject: [PATCH 120/127] ENH:support u0 firmware homing jira:[none] Change-Id: I9533944c343007897d25929739e5eb175bad6689 (cherry picked from commit 533911e2cd46fadc92bd7d908e81ad51ce14944c) --- src/slic3r/GUI/DeviceManager.cpp | 1 + src/slic3r/GUI/DeviceManager.hpp | 1 + src/slic3r/GUI/StatusPanel.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 9cb07b8b866..7754f8eea19 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -5532,6 +5532,7 @@ void MachineObject::parse_new_info(json print) is_support_user_preset = get_flag_bits(fun, 11); is_support_nozzle_blob_detection = get_flag_bits(fun, 13); is_support_upgrade_kit = get_flag_bits(cfg, 14); + is_support_command_homing = get_flag_bits(fun, 32); } /*aux*/ diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index b742cefa333..85263899e81 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -869,6 +869,7 @@ class MachineObject bool is_support_filament_setting_inprinting{false}; bool is_support_agora{false}; bool is_support_upgrade_kit{false}; + bool is_support_command_homing { false };// fun[32] bool installed_upgrade_kit{false}; int nozzle_max_temperature = -1; diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 687cccef54a..2b8185bb3e7 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3315,7 +3315,7 @@ void StatusPanel::on_axis_ctrl_xy(wxCommandEvent &event) if (event.GetInt() == 6) { obj->command_axis_control("Y", 1.0, -1.0f, 3000); } if (event.GetInt() == 7) { obj->command_axis_control("X", 1.0, 1.0f, 3000); } if (event.GetInt() == 8) { - if (obj->is_enable_np) { + if (obj->is_support_command_homing) { obj->command_go_home2(); } else { obj->command_go_home(); From 1441da246b9d2c31052cc83c887b9d7e609b897b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 2 Jun 2025 16:17:11 +0800 Subject: [PATCH 121/127] Add debugger detector for macOS --- src/slic3r/GUI/GUI_App.cpp | 4 +++- src/slic3r/GUI/GUI_Utils.hpp | 2 ++ src/slic3r/GUI/GUI_UtilsMac.mm | 37 +++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f537d1f1b70..2bd663c7cb4 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2582,8 +2582,10 @@ bool GUI_App::on_init_inner() // See https://github.com/bambulab/BambuStudio/issues/6726 if (!NetworkAgent::use_legacy_network) { bool debugger_attached = false; -#ifdef __WINDOWS__ +#if defined(__WINDOWS__) debugger_attached = IsDebuggerPresent(); +#elif defined(__WXOSX__) + debugger_attached = is_debugger_present(); #endif if (debugger_attached) { NetworkAgent::use_legacy_network = true; diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index cbfd4e31552..c9750e25b90 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -496,6 +496,8 @@ int get_dpi_for_window(const wxWindow *window); #ifdef __WXOSX__ void dataview_remove_insets(wxDataViewCtrl* dv); + +bool is_debugger_present(); #endif ///

diff --git a/src/slic3r/GUI/GUI_UtilsMac.mm b/src/slic3r/GUI/GUI_UtilsMac.mm index 46ee9dce7e4..6e9605fbb66 100644 --- a/src/slic3r/GUI/GUI_UtilsMac.mm +++ b/src/slic3r/GUI/GUI_UtilsMac.mm @@ -1,4 +1,5 @@ - +#include +#include #import #import "GUI_Utils.hpp" @@ -14,6 +15,40 @@ void dataview_remove_insets(wxDataViewCtrl* dv) { } } +bool is_debugger_present() +// Returns true if the current process is being debugged (either +// running under the debugger or has a debugger attached post facto). +// https://stackoverflow.com/a/2200786/3289421 +{ + int junk; + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + assert(junk == 0); + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); +} + } } From fc33a680d17b5b6eccf752d6e52e02c28ea415b7 Mon Sep 17 00:00:00 2001 From: noisyfox Date: Mon, 2 Jun 2025 16:48:58 +0800 Subject: [PATCH 122/127] Add debugger detector for Linux --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/GUI_Utils.cpp | 21 +++++++++++++++++++++ src/slic3r/GUI/GUI_Utils.hpp | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 2bd663c7cb4..21563ef19cf 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2584,7 +2584,7 @@ bool GUI_App::on_init_inner() bool debugger_attached = false; #if defined(__WINDOWS__) debugger_attached = IsDebuggerPresent(); -#elif defined(__WXOSX__) +#elif defined(__WXOSX__) || defined(__linux__) debugger_attached = is_debugger_present(); #endif if (debugger_attached) { diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 0cbadc8e8c2..d9d4c8143ce 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -495,5 +495,26 @@ void fit_in_display(wxTopLevelWindow& window, wxSize desired_size) window.SetSize(desired_size); } +#ifdef __linux__ +// Detect if the application is running inside a debugger. +// https://stackoverflow.com/a/69842462/3289421 +bool is_debugger_present() { + std::ifstream sf("/proc/self/status"); + std::string s; + while (sf >> s) + { + if (s == "TracerPid:") + { + int pid; + sf >> pid; + return pid != 0; + } + std::getline(sf, s); + } + + return false; +} +#endif + } } diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index c9750e25b90..f6956001e83 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -496,7 +496,9 @@ int get_dpi_for_window(const wxWindow *window); #ifdef __WXOSX__ void dataview_remove_insets(wxDataViewCtrl* dv); +#endif +#if defined(__WXOSX__) || defined(__linux__) bool is_debugger_present(); #endif From 81c14f60b617c900feee2a7380cb3f498785b9e0 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 2 Jun 2025 18:57:51 +0800 Subject: [PATCH 123/127] Remove unused code --- src/slic3r/GUI/DeviceManager.cpp | 44 -------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 7754f8eea19..ff30a9b4c9f 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -34,50 +34,6 @@ float string_to_float(const std::string& str_value) { return value; } -const int PRINTING_STAGE_COUNT = 36; -std::string PRINTING_STAGE_STR[PRINTING_STAGE_COUNT] = { - "printing", - "bed_leveling", - "heatbed_preheating", - "xy_mech_mode_sweep", - "change_material", - "m400_pause", - "filament_runout_pause", - "hotend_heating", - "extrude_compensation_scan", - "bed_scan", - "first_layer_scan", - "be_surface_typt_idetification", - "scanner_extrinsic_para_cali", - "toohead_homing", - "nozzle_tip_cleaning", - "extruder_temp_protect_cali", - "user_pause", - "toolhead_shell_off_pause", - "scanner_laser_para_cali", - "extruder_absolute_flow_cali", - "hotend_temperature_error_pause", // 20 - "heated_bed_temperature_error_pause", - "filament_unloading", - "skip_step_pause", - "filament_loading", - "motor_noise_calibration", - "ams_lost_pause", - "heat_break_fan_pause", - "chamber_temperature_control_error_pause", - "chamber_cooling", - "user_insert_gcode_pause", - "motor_noise_showoff", - "nozzle_filament_covered_detected_pause", - "cutter_error_pause", - "first_layer_error_pause", - "nozzle_clog_pause" - }; - - - - - wxString get_stage_string(int stage) { switch(stage) { From 40be2d5ef061c22a73d42a5245e851fc9e3a5798 Mon Sep 17 00:00:00 2001 From: Stone Li Date: Thu, 26 Dec 2024 14:23:20 +0800 Subject: [PATCH 124/127] ENH: format to utf8 when parse_json failed JIRA: STUDIO-none Change-Id: I3bb7b209962c15e94ef24d24f752e8cdafc42975 Signed-off-by: Stone Li (cherry picked from commit d5f9b35b911aabc0bf3683744f980838934f5bf7) (cherry picked from commit 499b0d8e4f2295dd07a5d84e4917e04a404efd53) --- src/slic3r/GUI/DeviceManager.cpp | 67 +++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index ff30a9b4c9f..950071fbc2a 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -134,6 +134,57 @@ std::string to_string_nozzle_diameter(float nozzle_diameter) return "0"; } +void sanitizeToUtf8(std::string& str) { + std::string result; + size_t i = 0; + + while (i < str.size()) { + unsigned char c = str[i]; + size_t remainingBytes = 0; + bool valid = true; + + if ((c & 0x80) == 0x00) { // 1-byte character (ASCII) + remainingBytes = 0; + } + else if ((c & 0xE0) == 0xC0) { // 2-byte character + remainingBytes = 1; + } + else if ((c & 0xF0) == 0xE0) { // 3-byte character + remainingBytes = 2; + } + else if ((c & 0xF8) == 0xF0) { // 4-byte character + remainingBytes = 3; + } + else { + valid = false; // Invalid first byte + } + + if (valid && i + remainingBytes < str.size()) { + for (size_t j = 1; j <= remainingBytes; ++j) { + if ((str[i + j] & 0xC0) != 0x80) { + valid = false; // Invalid continuation byte + break; + } + } + } + else { + valid = false; // Truncated character + } + + if (valid) { + // Append valid UTF-8 character + result.append(str, i, remainingBytes + 1); + i += remainingBytes + 1; + } + else { + // Replace invalid character with space + result += ' '; + ++i; // Skip the invalid byte + } + } + str = std::move(result); +} + namespace Slic3r { /* Common Functions */ @@ -2851,10 +2902,24 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) /* update last received time */ last_update_time = std::chrono::system_clock::now(); + json j_pre; + bool parse_ok = false; + try { + j_pre = json::parse(payload); + parse_ok = true; + } + catch(...) { + parse_ok = false; + /* post process payload */ + sanitizeToUtf8(payload); + BOOST_LOG_TRIVIAL(info) << "parse_json: sanitize to utf8"; + } + try { bool restored_json = false; json j; - json j_pre = json::parse(payload); + if (!parse_ok) + j_pre = json::parse(payload); CNumericLocalesSetter locales_setter; if (j_pre.empty()) { return 0; From 57e5f5c4c4fd9d7104d46054d9bd3f38c68419e1 Mon Sep 17 00:00:00 2001 From: "xin.zhang" Date: Fri, 3 Jan 2025 12:14:28 +0800 Subject: [PATCH 125/127] FIX: wrong update info about AMS1 jira: [STUDIO-9089] Change-Id: I7ce5b1069abddd8aaa187ade03d0271b0b16dc9e (cherry picked from commit 032b34eded21f452535086f672dd408200461d5a) --- src/slic3r/GUI/DeviceManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 950071fbc2a..4164e481cc0 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -3071,6 +3071,8 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) ver_info.product_name = wxString::FromUTF8((*it)["product_name"].get()); if ((*it).contains("sw_ver")) ver_info.sw_ver = (*it)["sw_ver"].get(); + if ((*it).contains("sw_new_ver")) + ver_info.sw_new_ver = (*it)["sw_new_ver"].get(); if ((*it).contains("sn")) ver_info.sn = (*it)["sn"].get(); if ((*it).contains("hw_ver")) @@ -3796,7 +3798,7 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) upgrade_progress = jj["upgrade_state"]["progress"].get(); } if (jj["upgrade_state"].contains("new_version_state")) upgrade_new_version = jj["upgrade_state"]["new_version_state"].get() == 1 ? true : false; - if (jj["upgrade_state"].contains("ams_new_version_number")) + if (!check_enable_np(jj) && jj["upgrade_state"].contains("ams_new_version_number"))/* is not used in new np, by AP*/ ams_new_version_number = jj["upgrade_state"]["ams_new_version_number"].get(); if (jj["upgrade_state"].contains("ota_new_version_number")) ota_new_version_number = jj["upgrade_state"]["ota_new_version_number"].get(); From aac6e2a3d0c45703f205149174c245e725436655 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 2 Jun 2025 19:18:11 +0800 Subject: [PATCH 126/127] Fix potential crash during calib --- src/slic3r/GUI/DeviceManager.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 4164e481cc0..bf9d3cd62fd 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4481,8 +4481,10 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } else if (jj["command"].get() == "ams_filament_setting" && !key_field_only) { if (jj.contains("result") && jj.contains("reason")) { if (jj["result"].get() == "fail") { - auto err_code = jj["err_code"].get(); - print_error = err_code; + if (jj.contains("err_code")) { + auto err_code = jj["err_code"].get(); + print_error = err_code; + } } } @@ -4622,8 +4624,10 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) } else if (jj["command"].get() == "extrusion_cali_set") { if (jj.contains("result") && jj.contains("reason")) { if (jj["result"].get() == "fail") { - auto err_code = jj["err_code"].get(); - print_error = err_code; + if (jj.contains("err_code")) { + auto err_code = jj["err_code"].get(); + print_error = err_code; + } } } #ifdef CALI_DEBUG @@ -4672,8 +4676,10 @@ int MachineObject::parse_json(std::string payload, bool key_field_only) else if (jj["command"].get() == "extrusion_cali_sel") { if (jj.contains("result") && jj.contains("reason")) { if (jj["result"].get() == "fail") { - auto err_code = jj["err_code"].get(); - print_error = err_code; + if (jj.contains("err_code")) { + auto err_code = jj["err_code"].get(); + print_error = err_code; + } } } From 7d7308feb20c0028a5d57c0a018f31b482d755f8 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Mon, 2 Jun 2025 21:19:52 +0800 Subject: [PATCH 127/127] Log network msg --- src/slic3r/GUI/GUI_App.cpp | 10 ++++++++++ src/slic3r/GUI/GUI_App.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 21563ef19cf..fa128a7d275 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1780,6 +1780,8 @@ void GUI_App::init_networking_callbacks() CallAfter([this, dev_id, msg] { if (m_is_closing) return; + this->process_network_msg(dev_id, msg); + MachineObject* obj = this->m_device_manager->get_user_machine(dev_id); if (obj) { obj->is_ams_need_update = false; @@ -1832,6 +1834,7 @@ void GUI_App::init_networking_callbacks() if (m_is_closing) return; + this->process_network_msg(dev_id, msg); MachineObject* obj = m_device_manager->get_my_machine(dev_id); if (!obj || !obj->is_lan_mode_printer()) { obj = m_device_manager->get_local_machine(dev_id); @@ -4474,6 +4477,13 @@ void GUI_App::check_new_version_sf(bool show_tips, int by_user) .perform(); } +void GUI_App::process_network_msg(std::string dev_id, std::string msg) +{ + if (dev_id.empty()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << msg; + } +} + //BBS pop up a dialog and download files void GUI_App::request_new_version(int by_user) { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index c246adc5a96..7f390d1f66c 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -477,6 +477,7 @@ class GUI_App : public wxApp void check_update(bool show_tips, int by_user); void check_new_version(bool show_tips = false, int by_user = 0); void check_new_version_sf(bool show_tips = false, int by_user = 0); + void process_network_msg(std::string dev_id, std::string msg); void request_new_version(int by_user); void enter_force_upgrade(); void set_skip_version(bool skip = true);