#include "DevConfigUtil.h" #include #include #include "../I18N.hpp" using namespace nlohmann; namespace Slic3r { // Translation markers for xgettext extraction. // These strings are configured in printers/*.json (tool_head_display_names) // and passed to _L() at runtime. xgettext cannot scan dynamic strings, // so we mark them here with L() for extraction into .pot file. // This block is never executed at runtime. static void _toolhead_translation_markers() { // Possible runtime values of tool_head_display_names, marked for extraction. static const char *const markers[] = { L("Main Extruder"), L("Main extruder"), L("main extruder"), L("Auxiliary Extruder"), L("Auxiliary extruder"), L("auxiliary extruder"), L("Left Extruder"), L("Left extruder"), L("left extruder"), L("Right Extruder"), L("Right extruder"), L("right extruder"), L("Main Nozzle"), L("Main nozzle"), L("main nozzle"), L("Auxiliary Nozzle"), L("Auxiliary nozzle"), L("auxiliary nozzle"), L("Left Nozzle"), L("Left nozzle"), L("left nozzle"), L("Right Nozzle"), L("Right nozzle"), L("right nozzle"), L("Main Hotend"), L("Main hotend"), L("main hotend"), L("Auxiliary Hotend"), L("Auxiliary hotend"), L("auxiliary hotend"), L("Left Hotend"), L("Left hotend"), L("left hotend"), L("Right Hotend"), L("Right hotend"), L("right hotend"), // standalone position words (short_name=true runtime results) L("main"), L("auxiliary"), L("Main"), L("Auxiliary"), L("left"), L("right"), L("Left"), L("Right"), }; (void) markers; } std::string DevPrinterConfigUtil::m_resource_file_path = ""; std::map DevPrinterConfigUtil::get_all_model_id_with_name() { { std::map models; wxDir dir(m_resource_file_path + "/printers/"); if (!dir.IsOpened()) { return models; } wxString filename; std::vector m_files; bool hasFile = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES); while (hasFile) { m_files.push_back(filename); hasFile = dir.GetNext(&filename); } for (wxString file : m_files) { if (!file.Lower().ends_with(".json")) continue; std::string config_file = m_resource_file_path + "/printers/" + file.ToStdString(); boost::nowide::ifstream json_file(config_file.c_str()); try { json jj; if (json_file.is_open()) { json_file >> jj; if (jj.contains("00.00.00.00")) { json const& printer = jj["00.00.00.00"]; std::string model_id; std::string display_name; if (printer.contains("model_id")) { model_id = printer["model_id"].get(); } if (printer.contains("display_name")) { display_name = printer["display_name"].get(); } models[display_name] = model_id; } } } catch (...) {} } return models; } } PrinterArch DevPrinterConfigUtil::get_printer_arch(std::string type_str) { const std::string& arch_str = get_value_from_config(type_str, "printer_arch"); if (arch_str == "i3") { return PrinterArch::ARCH_I3; } else if (arch_str == "core_xy") { return PrinterArch::ARCH_CORE_XY; } return PrinterArch::ARCH_CORE_XY; } std::string DevPrinterConfigUtil::get_printer_ext_img(const std::string& type_str, int pos) { const auto& vec = get_value_from_config>(type_str, "printer_ext_image"); return (vec.size() > pos) ? vec[pos] : std::string(); }; std::string DevPrinterConfigUtil::get_filament_load_img(const std::string &type_str, int ext_id, bool has_nozzle_rack) { if (has_nozzle_rack) { const auto &rack_vec = get_value_from_config>(type_str, "filament_load_image_nozzle_rack") ; if (!rack_vec.empty()) { if (ext_id >= 0 && static_cast(ext_id) < rack_vec.size()) { return rack_vec[ext_id]; } return rack_vec[0]; } } const auto &vec = get_value_from_config>(type_str, "filament_load_image"); if (ext_id >= 0 && static_cast(ext_id) < vec.size()) { return vec[ext_id]; } return vec.empty() ? std::string() : vec[0]; } std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, const std::string& key) { std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; boost::nowide::ifstream json_file(config_file.c_str()); try { json jj; if (json_file.is_open()) { json_file >> jj; if (jj.contains("00.00.00.00")) { json const& printer = jj["00.00.00.00"]; if (printer.contains("fan") && printer["fan"].contains(key)) { return printer["fan"][key].get(); } } } } catch (...) {} return std::string(); } std::vector DevPrinterConfigUtil::get_fan_text_params(const std::string& type_str, const std::string& key) { std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; boost::nowide::ifstream json_file(config_file.c_str()); try { json jj; if (json_file.is_open()) { json_file >> jj; if (jj.contains("00.00.00.00")) { json const& printer = jj["00.00.00.00"]; if (printer.contains("fan") && printer["fan"].contains(key)) { return printer["fan"][key].get>(); } } } } catch (...) {} return std::vector(); } std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, int airduct_mode, int airduct_func, int submode) { std::vector filaments; std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; boost::nowide::ifstream json_file(config_file.c_str()); try { json jj; if (json_file.is_open()) { json_file >> jj; if (jj.contains("00.00.00.00")) { json const& printer = jj["00.00.00.00"]; if (!printer.contains("fan")) { return std::string(); } json const& fan_item = printer["fan"]; const auto& airduct_mode_str = std::to_string(airduct_mode); if (!fan_item.contains(airduct_mode_str)) { return std::string(); } json const& airduct_item = fan_item[airduct_mode_str]; const auto& airduct_func_str = std::to_string(airduct_func); if (airduct_item.contains(airduct_func_str)) { const auto& airduct_func_item = airduct_item[airduct_func_str]; if (airduct_func_item.is_object()) { return airduct_func_item[std::to_string(submode)].get(); } else if (airduct_func_item.is_string()) { return airduct_func_item.get(); } } } } } catch (...) {} return std::string(); } std::string DevPrinterConfigUtil::get_fan_mode_text(const std::string& type_str, int airduct_mode, const std::string& key) { std::vector filaments; std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; boost::nowide::ifstream json_file(config_file.c_str()); try { json jj; if (json_file.is_open()) { json_file >> jj; if (jj.contains("00.00.00.00")) { json const& printer = jj["00.00.00.00"]; if (!printer.contains("fan")) { return std::string(); } json const& fan_item = printer["fan"]; const auto& airduct_mode_str = std::to_string(airduct_mode); if (!fan_item.contains(airduct_mode_str)) { return std::string(); } if (fan_item[airduct_mode_str].contains(key)) { return fan_item[airduct_mode_str][key].get(); } } } } catch (...) {} return std::string(); } std::map> DevPrinterConfigUtil::get_all_subseries(std::string type_str) { std::map> subseries; #if !BBL_RELEASE_TO_PUBLIC BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": path= " << m_resource_file_path + "/printers/"; #endif try { const auto& from_dir = m_resource_file_path + "/printers/"; if (!boost::filesystem::exists(from_dir)) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": direction does not exist "; return subseries; } for (const auto& entry : boost::filesystem::directory_iterator(from_dir)) { const boost::filesystem::path& file_path = entry.path(); if (boost::filesystem::is_regular_file(file_path) && file_path.extension() == ".json") { try { json jj; boost::nowide::ifstream json_file(file_path.string()); if (json_file.is_open()) { json_file >> jj; if (jj.contains("00.00.00.00")) { json const& printer = jj["00.00.00.00"]; if (printer.contains("subseries")) { std::vector subs; std::string model_id = printer["model_id"].get(); if (model_id == type_str || type_str.empty()) { for (auto res : printer["subseries"]) { subs.emplace_back(res.get()); } } subseries.insert(make_pair(model_id, subs)); } } } } catch (...) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to load " << file_path.filename().string(); } } } } catch (const std::exception& e) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": std::exception: " << e.what(); } catch (...) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": unknown exception"; } #if !BBL_RELEASE_TO_PUBLIC wxString result_str; for (auto item : subseries) { wxString item_str = item.first; item_str += ": "; for (auto to_item : item.second) { item_str += to_item; item_str += " "; } result_str += item_str + ", "; } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": result= " << result_str; #endif if (subseries.empty()) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": result= " << "empty"; } return subseries; } std::string DevPrinterConfigUtil::get_toolhead_display_name( const std::string& type_str, int ext_id, ToolHeadComponent component, ToolHeadNameCase name_case, bool short_name) { static const std::map comp_keys = { { ToolHeadComponent::Extruder, "extruder" }, { ToolHeadComponent::Nozzle, "nozzle" }, { ToolHeadComponent::Hotend, "hotend" } }; int case_index = static_cast(name_case); // 0, 1, 2 // Try to read from printer config json auto names_json = get_value_from_config(type_str, "tool_head_display_names"); std::string role_key = std::to_string(ext_id); // "0" or "1" const std::string& comp_key = comp_keys.at(component); std::string result; if (!names_json.is_null() && names_json.contains(role_key) && names_json[role_key].contains(comp_key)) { auto& arr = names_json[role_key][comp_key]; if (arr.is_array() && case_index < static_cast(arr.size())) { result = arr[case_index].get(); } } // Orca: models that ship no tool_head_display_names (e.g. H2D/H2S) must still get distinct // per-extruder labels, so fall back to the previous programmatic Left/Right construction. // Engages only when the config lookup above yields nothing, so models that ship the key // behave exactly like the reference. if (result.empty()) { const std::string side = ext_id == DEPUTY_EXTRUDER_ID ? "Left" : "Right"; const std::string component_name = component == ToolHeadComponent::Extruder ? "Extruder" : component == ToolHeadComponent::Hotend ? "Hotend" : "Nozzle"; result = side + " " + component_name; if (name_case == ToolHeadNameCase::SentenceCase && result.size() > side.size() + 1) result[side.size() + 1] = static_cast(std::tolower(static_cast(result[side.size() + 1]))); else if (name_case == ToolHeadNameCase::LowerCase) std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); } // short_name: return only the role prefix (e.g. "Main" from "Main Nozzle") if (short_name) { auto sp = result.find(' '); if (sp != std::string::npos) { result = result.substr(0, sp); } } return result; } };