From 8d22fad30b6cf6bd99b2a69951e410322973fd41 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sat, 31 Jan 2026 01:04:21 +0800 Subject: [PATCH] badge support --- CLAUDE.md | 58 ++-------- src/libslic3r/PresetBundle.cpp | 72 +++++++++++-- src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp | 3 + src/slic3r/GUI/DeviceCore/DevFilaSystem.h | 1 + src/slic3r/GUI/GUI_App.cpp | 13 ++- src/slic3r/GUI/GUI_App.hpp | 2 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 4 +- src/slic3r/GUI/Plater.cpp | 12 ++- src/slic3r/GUI/Tab.cpp | 15 --- src/slic3r/Utils/MoonrakerPrinterAgent.cpp | 8 +- src/slic3r/Utils/MoonrakerPrinterAgent.hpp | 4 +- src/slic3r/Utils/NetworkAgentFactory.cpp | 114 +++++--------------- src/slic3r/Utils/NetworkAgentFactory.hpp | 34 ------ src/slic3r/Utils/QidiPrinterAgent.cpp | 2 +- 14 files changed, 134 insertions(+), 208 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index eb35833082..a6e48cd862 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,69 +9,25 @@ OrcaSlicer is an open-source 3D slicer application forked from Bambu Studio, bui ## Build Commands ### Building on Windows +**Always use this command to build the project when testing build issues on Windows.** ```bash -# Build everything -build_release_vs2022.bat - -# Build with debug symbols -build_release_vs2022.bat debug - -# Build only dependencies -build_release_vs2022.bat deps - -# Build only slicer (after deps are built) -build_release_vs2022.bat slicer - - +cmake --build . --config %build_type% --target ALL_BUILD -- -m ``` ### Building on macOS +**Always use this command to build the project when testing build issues on macOS.** ```bash -# Build everything (dependencies and slicer) -./build_release_macos.sh - -# Build only dependencies -./build_release_macos.sh -d - -# Build only slicer (after deps are built) -./build_release_macos.sh -s - -# Use Ninja generator for faster builds -./build_release_macos.sh -x - -# Build for specific architecture -./build_release_macos.sh -a arm64 # or x86_64 or universal - -# Build for specific macOS version target -./build_release_macos.sh -t 11.3 +cmake --build build/arm64 --config RelWithDebInfo --target all -- ``` ### Building on Linux + **Always use this command to build the project when testing build issues on Linux.** ```bash -# First time setup - install system dependencies -./build_linux.sh -u +cmake --build build/arm64 --config RelWithDebInfo --target all -- -# Build dependencies and slicer -./build_linux.sh -dsi - -# Build everything (alternative) -./build_linux.sh -dsi - -# Individual options: -./build_linux.sh -d # dependencies only -./build_linux.sh -s # slicer only -./build_linux.sh -i # build AppImage - -# Performance and debug options: -./build_linux.sh -j N # limit to N cores -./build_linux.sh -1 # single core build -./build_linux.sh -b # Debug build -./build_linux.sh -e # RelWithDebInfo build -./build_linux.sh -c # clean build -./build_linux.sh -r # skip RAM/disk checks -./build_linux.sh -l # use Clang instead of GCC ``` + ### Build System - Uses CMake with minimum version 3.13 (maximum 3.31.x on Windows) - Primary build directory: `build/` diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index 6a3844ce09..f45c4e0653 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -2342,6 +2342,7 @@ unsigned int PresetBundle::sync_ams_list(std::vector("filament_multi_colour")->values; auto ams_id = ams.opt_string("ams_id", 0u); auto slot_id = ams.opt_string("slot_id", 0u); - ams_infos.push_back({filament_id.empty() ? false : true,false, filament_color}); + auto is_placeholder = ams.has("filament_slot_placeholder") && ams.opt_bool("filament_slot_placeholder", 0u); + ams_infos.push_back({filament_id.empty() ? false : true, false, is_placeholder, filament_color}); AMSMapInfo temp = {ams_id, slot_id}; ams_array_maps.push_back(temp); index++; @@ -2378,6 +2380,12 @@ unsigned int PresetBundle::sync_ams_list(std::vectorvalues.resize(exist_filament_presets.size(), 1); } else {//overwrite; - filament_color->values = ams_filament_colors; - filament_color_type->values = ams_filament_color_types; - this->filament_presets = ams_filament_presets; - filament_map->values.resize(ams_filament_colors.size(), 1); + bool has_placeholders = std::any_of(ams_infos.begin(), ams_infos.end(), + [](const AmsInfo& a) { return a.is_placeholder; }); + if (has_placeholders) { + // Orca: merge — keep existing filaments for empty slots + auto exist_colors = filament_color->values; + auto exist_color_types = filament_color_type->values; + auto exist_presets = this->filament_presets; + + size_t tray_count = ams_filament_presets.size(); + size_t total = std::max(tray_count, exist_presets.size()); + + std::vector result_colors; + std::vector result_color_types; + std::vector result_presets; + std::vector> result_multi_colors; + + for (size_t i = 0; i < total; i++) { + bool is_loaded = (i < ams_infos.size() && ams_infos[i].valid); + + if (is_loaded) { + // Loaded tray: use tray's filament data + result_colors.push_back(ams_filament_colors[i]); + result_color_types.push_back(ams_filament_color_types[i]); + result_presets.push_back(ams_filament_presets[i]); + result_multi_colors.push_back( + i < ams_multi_color_filment.size() ? ams_multi_color_filment[i] + : std::vector{ams_filament_colors[i]}); + } else if (i < exist_presets.size()) { + // Empty tray or beyond tray count: keep existing filament + result_colors.push_back(exist_colors[i]); + result_color_types.push_back(exist_color_types[i]); + result_presets.push_back(exist_presets[i]); + result_multi_colors.push_back({exist_colors[i]}); + } else { + // New slot beyond existing count: use first visible filament as fallback + result_colors.push_back("#CECECE"); + result_color_types.push_back("1"); + result_presets.push_back(this->filaments.first_visible().name); + result_multi_colors.push_back({"#CECECE"}); + } + } + + filament_color->values = result_colors; + filament_color_type->values = result_color_types; + this->filament_presets = result_presets; + ams_multi_color_filment = result_multi_colors; + filament_map->values.resize(total, 1); + } else { + // BBL: existing wholesale replace + filament_color->values = ams_filament_colors; + filament_color_type->values = ams_filament_color_types; + this->filament_presets = ams_filament_presets; + filament_map->values.resize(ams_filament_colors.size(), 1); + } auto& print_config = this->prints.get_edited_preset().config; auto support_filament_opt = print_config.option("support_filament"); auto support_interface_filament_opt = print_config.option("support_interface_filament"); - if (support_filament_opt->value > ams_filament_color_types.size()) + if (support_filament_opt->value > filament_color_type->values.size()) support_filament_opt->value = 0; - if (support_interface_filament_opt->value > ams_filament_color_types.size()) + if (support_interface_filament_opt->value > filament_color_type->values.size()) support_interface_filament_opt->value = 0; } // Update ams_multi_color_filment diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp index 5cf3f6b885..8f35ccf454 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp @@ -612,6 +612,9 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS { curr_tray->remain = -1; } + if (tray_it->contains("tray_slot_placeholder")) { + curr_tray->is_slot_placeholder = true; + } int ams_id_int = 0; int tray_id_int = 0; try diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h index f6c1a2d420..e76834aca9 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h @@ -53,6 +53,7 @@ public: wxColour wx_color; bool is_bbl; bool is_exists = false; + bool is_slot_placeholder = false; // Orca: True for empty tray slots from pull-mode agents int hold_count = 0; int remain = 0; // filament remain: 0 ~ 100 diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e490374c95..50f76fd2c0 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3469,16 +3469,25 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour) )); } -void GUI_App::switch_printer_agent(const std::string& agent_id) +void GUI_App::switch_printer_agent() { if (!m_agent) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": no agent exists"; return; } + std::string agent_id; + + const DynamicPrintConfig& config = preset_bundle->printers.get_edited_preset().config; + if (config.has("printer_agent")) { + std::string value = config.option("printer_agent")->value; + if (!value.empty()) { + agent_id = value; + } + } // Use registry to validate and create agent // If empty, use default - std::string effective_agent_id = agent_id.empty() ? NetworkAgentFactory::get_default_printer_agent_id() : agent_id; + std::string effective_agent_id = agent_id.empty() ? ORCA_PRINTER_AGENT_ID : agent_id; // Check if agent is registered if (!NetworkAgentFactory::is_printer_agent_registered(effective_agent_id)) { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 6f0c0e028e..ecdab5a676 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -342,7 +342,7 @@ public: NetworkAgent* getAgent() { return m_agent; } // Dynamic printer agent switching - void switch_printer_agent(const std::string& agent_id); + void switch_printer_agent(); FilamentColorCodeQuery* get_filament_color_code_query(); bool is_editor() const { return m_app_mode == EAppMode::Editor; } diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index d2fa243919..3806215e56 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -177,13 +177,13 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr std::string selected_agent = current_agent; if (selected_agent.empty()) { - selected_agent = NetworkAgentFactory::get_default_printer_agent_id(); + selected_agent = ORCA_PRINTER_AGENT_ID; } // Verify selected agent is valid auto it = std::find_if(agents.begin(), agents.end(), [&selected_agent](const auto& a) { return a.id == selected_agent; }); if (it == agents.end()) { - selected_agent = NetworkAgentFactory::get_default_printer_agent_id(); + selected_agent = ORCA_PRINTER_AGENT_ID; } // Set default value for the enum (using the index) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 76ecc16727..7bfd3da5dc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3230,6 +3230,7 @@ std::map Sidebar::build_filament_ams_list(MachineObject tray_config.set_key_value("filament_multi_colour", new ConfigOptionStrings{}); tray_config.set_key_value("filament_colour_type", new ConfigOptionStrings{std::to_string(tray.ctype)}); tray_config.set_key_value("filament_exist", new ConfigOptionBools{tray.is_exists}); + tray_config.set_key_value("filament_slot_placeholder", new ConfigOptionBools{tray.is_slot_placeholder}); std::optional info; if (wxGetApp().preset_bundle) { info = wxGetApp().preset_bundle->get_filament_by_filament_id(tray.setting_id); @@ -3520,8 +3521,15 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn) { // badge ams filament clear_combos_filament_badge(); if (sync_result.direct_sync) { - for (auto &c : p->combos_filament) { - badge_combox_filament(c); + auto& ams_list = wxGetApp().preset_bundle->filament_ams_list; + size_t tray_idx = 0; + for (auto& entry : ams_list) { + if (tray_idx >= p->combos_filament.size()) break; + auto filament_id = entry.second.opt_string("filament_id", 0u); + if (!filament_id.empty()) { + badge_combox_filament(p->combos_filament[tray_idx]); + } + tray_idx++; } } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0487c2840e..08656a01ed 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2136,22 +2136,7 @@ void Tab::on_presets_changed() void Tab::update_printer_agent_if_needed() { - std::string agent_id = "orca"; - if (m_preset_bundle) { - if (wxGetApp().preset_bundle->is_bbl_vendor()) { - agent_id = "bbl"; - } else if (wxGetApp().preset_bundle->is_qidi_vendor()) { - agent_id = "qidi"; - } - } - const DynamicPrintConfig& config = m_preset_bundle->printers.get_edited_preset().config; - if (config.has("printer_agent")) { - std::string value = config.option("printer_agent")->value; - if (!value.empty()) { - agent_id = value; - } - } // Switch agent in GUI_App wxGetApp().switch_printer_agent(agent_id); } diff --git a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp index 127e2d19bb..b150b7df96 100644 --- a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp +++ b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp @@ -455,7 +455,7 @@ int MoonrakerPrinterAgent::set_queue_on_main_fn(QueueOnMainFn fn) return BAMBU_NETWORK_SUCCESS; } -void MoonrakerPrinterAgent::build_ams_payload(int ams_count, const std::vector& trays) +void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index, const std::vector& trays) { // Look up MachineObject via DeviceManager @@ -520,7 +520,8 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, const std::vector& trays); + void build_ams_payload(int ams_count, int max_lane_index, const std::vector& trays); // Methods that derived classes may need to override or access virtual bool init_device_info(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); diff --git a/src/slic3r/Utils/NetworkAgentFactory.cpp b/src/slic3r/Utils/NetworkAgentFactory.cpp index 1e23291399..63e30dc0c8 100644 --- a/src/slic3r/Utils/NetworkAgentFactory.cpp +++ b/src/slic3r/Utils/NetworkAgentFactory.cpp @@ -6,6 +6,8 @@ #include "QidiPrinterAgent.hpp" #include "MoonrakerPrinterAgent.hpp" #include +#include +#include namespace Slic3r { namespace { @@ -18,10 +20,22 @@ std::map& get_printer_agents() return agents; } -std::string& get_default_agent_id() +// Helper to register a printer agent type with the standard factory pattern. +// AgentTypes that take a log_dir constructor arg use the default; BBLPrinterAgent +// (no log_dir) is registered separately. +template +void register_agent() { - static std::string default_id; - return default_id; + auto info = T::get_agent_info_static(); + NetworkAgentFactory::register_printer_agent( + info.id, info.name, + [](std::shared_ptr cloud_agent, + const std::string& log_dir) -> std::shared_ptr { + auto agent = std::make_shared(log_dir); + if (cloud_agent) + agent->set_cloud_agent(cloud_agent); + return agent; + }); } } // anonymous namespace @@ -30,18 +44,7 @@ bool NetworkAgentFactory::register_printer_agent(const std::string& id, const st { std::lock_guard lock(s_registry_mutex); auto& agents = get_printer_agents(); - - auto result = agents.emplace(id, PrinterAgentInfo(id, display_name, std::move(factory))); - - if (result.second) { - auto& default_id = get_default_agent_id(); - if (default_id.empty()) { - default_id = id; - } - return true; - } else { - return false; - } + return agents.emplace(id, PrinterAgentInfo(id, display_name, std::move(factory))).second; } bool NetworkAgentFactory::is_printer_agent_registered(const std::string& id) @@ -51,14 +54,6 @@ bool NetworkAgentFactory::is_printer_agent_registered(const std::string& id) return agents.find(id) != agents.end(); } -const PrinterAgentInfo* NetworkAgentFactory::get_printer_agent_info(const std::string& id) -{ - std::lock_guard lock(s_registry_mutex); - auto& agents = get_printer_agents(); - auto it = agents.find(id); - return (it != agents.end()) ? &it->second : nullptr; -} - std::vector NetworkAgentFactory::get_registered_printer_agents() { std::lock_guard lock(s_registry_mutex); @@ -89,80 +84,24 @@ std::shared_ptr NetworkAgentFactory::create_printer_agent_by_id(c return it->second.factory(cloud_agent, log_dir); } -std::string NetworkAgentFactory::get_default_printer_agent_id() -{ - std::lock_guard lock(s_registry_mutex); - return get_default_agent_id(); -} - -void NetworkAgentFactory::set_default_printer_agent_id(const std::string& id) -{ - std::lock_guard lock(s_registry_mutex); - auto& agents = get_printer_agents(); - - if (agents.find(id) != agents.end()) { - get_default_agent_id() = id; - } -} - void NetworkAgentFactory::register_all_agents() { - // Register Orca printer agent - { - auto info = OrcaPrinterAgent::get_agent_info_static(); - register_printer_agent(info.id, info.name, - [](std::shared_ptr cloud_agent, - const std::string& log_dir) -> std::shared_ptr { - auto agent = std::make_shared(log_dir); - if (cloud_agent) { - agent->set_cloud_agent(cloud_agent); - } - return agent; - }); - } + register_agent(); + register_agent(); + register_agent(); - // Register Qidi printer agent - { - auto info = QidiPrinterAgent::get_agent_info_static(); - register_printer_agent(info.id, info.name, - [](std::shared_ptr cloud_agent, - const std::string& log_dir) -> std::shared_ptr { - auto agent = std::make_shared(log_dir); - if (cloud_agent) { - agent->set_cloud_agent(cloud_agent); - } - return agent; - }); - } - - // Register Moonraker printer agent - { - auto info = MoonrakerPrinterAgent::get_agent_info_static(); - register_printer_agent(info.id, info.name, - [](std::shared_ptr cloud_agent, - const std::string& log_dir) -> std::shared_ptr { - auto agent = std::make_shared(log_dir); - if (cloud_agent) { - agent->set_cloud_agent(cloud_agent); - } - return agent; - }); - } - - // Register BBL printer agent (only if bbl network agent is available) + // BBLPrinterAgent takes no constructor args, so register manually { auto info = BBLPrinterAgent::get_agent_info_static(); register_printer_agent(info.id, info.name, [](std::shared_ptr cloud_agent, - const std::string& log_dir) -> std::shared_ptr { + const std::string& /*log_dir*/) -> std::shared_ptr { auto agent = std::make_shared(); - if (cloud_agent) { + if (cloud_agent) agent->set_cloud_agent(cloud_agent); - } return agent; }); } - } std::unique_ptr create_agent_from_config(const std::string& log_dir, AppConfig* app_config) @@ -187,9 +126,8 @@ std::unique_ptr create_agent_from_config(const std::string& log_di } } - // Create NetworkAgent with cloud agent only (printer agent added later) - // We will create the printer agent later when the printer is selected, so we pass nullptr for the printer agent here. - auto agent = NetworkAgentFactory::create_from_agents(std::move(cloud_agent), nullptr); + // Create NetworkAgent with cloud agent only (printer agent added later when printer is selected) + auto agent = std::make_unique(std::move(cloud_agent), nullptr); if (agent && app_config && use_orca_cloud) { auto* orca_cloud = dynamic_cast(agent->get_cloud_agent().get()); diff --git a/src/slic3r/Utils/NetworkAgentFactory.hpp b/src/slic3r/Utils/NetworkAgentFactory.hpp index aa7f54dccb..d4a379365e 100644 --- a/src/slic3r/Utils/NetworkAgentFactory.hpp +++ b/src/slic3r/Utils/NetworkAgentFactory.hpp @@ -12,8 +12,6 @@ #include #include #include -#include -#include namespace Slic3r { @@ -99,11 +97,6 @@ public: */ static bool is_printer_agent_registered(const std::string& id); - /** - * Get info about a registered agent - */ - static const PrinterAgentInfo* get_printer_agent_info(const std::string& id); - /** * Get all registered printer agents (for UI population) */ @@ -121,16 +114,6 @@ public: std::shared_ptr cloud_agent, const std::string& log_dir); - /** - * Get default printer agent ID - */ - static std::string get_default_printer_agent_id(); - - /** - * Set a specific agent as the default - */ - static void set_default_printer_agent_id(const std::string& id); - // ======================================================================== // Cloud Agent Factory // ======================================================================== @@ -164,23 +147,6 @@ public: } } - // ======================================================================== - // NetworkAgent Facade Creation - // ======================================================================== - - /** - * Create a NetworkAgent from pre-created sub-agents - * - * @param cloud_agent Cloud service agent (required, includes auth) - * @param printer_agent Printer agent (optional, can be nullptr) - * @return Unique pointer to NetworkAgent facade - */ - static std::unique_ptr create_from_agents(std::shared_ptr cloud_agent, - std::shared_ptr printer_agent) - { - return std::make_unique(std::move(cloud_agent), std::move(printer_agent)); - } - private: // Factory is not instantiable NetworkAgentFactory() = delete; diff --git a/src/slic3r/Utils/QidiPrinterAgent.cpp b/src/slic3r/Utils/QidiPrinterAgent.cpp index dc0262e3c2..bf724d98d8 100644 --- a/src/slic3r/Utils/QidiPrinterAgent.cpp +++ b/src/slic3r/Utils/QidiPrinterAgent.cpp @@ -49,7 +49,7 @@ bool QidiPrinterAgent::fetch_filament_info(std::string dev_id) } // 4. Build the AMS payload - build_ams_payload(box_count, trays); + build_ams_payload(box_count, box_count * 4 - 1, trays); return true; }