Merge branch 'main' into dev/ams-heat

# Conflicts:
#	src/libslic3r/Preset.cpp
#	src/libslic3r/PrintConfig.hpp
#	src/slic3r/GUI/DeviceCore/CMakeLists.txt
#	src/slic3r/GUI/DeviceCore/DevDefs.h
#	src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp
#	src/slic3r/GUI/DeviceCore/DevFilaSystem.h
#	src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp
#	src/slic3r/GUI/DeviceCore/DevUtilBackend.h
#	src/slic3r/GUI/DeviceManager.cpp
#	src/slic3r/GUI/DeviceManager.hpp
#	src/slic3r/GUI/SelectMachine.cpp
#	src/slic3r/GUI/SelectMachine.hpp
This commit is contained in:
Noisyfox
2026-07-14 09:48:35 +08:00
702 changed files with 85605 additions and 2732 deletions

View File

@@ -34,6 +34,8 @@
#include "DeviceCore/DevManager.h"
#include "DeviceCore/DevPrintTaskInfo.h"
#include "DeviceTab/wgtDeviceNozzleRack.h"
#include "PrintOptionsDialog.hpp"
@@ -1611,13 +1613,26 @@ wxBoxSizer *StatusBasePanel::create_machine_control_page(wxWindow *parent)
wxBoxSizer *bSizer_control = new wxBoxSizer(wxVERTICAL);
auto temp_axis_ctrl_sizer = create_temp_axis_group(parent);
auto m_ams_ctrl_sizer = create_ams_group(parent);
auto m_filament_load_sizer = create_filament_group(parent);
/* ams control box or live nozzle-rack panel (rack printers switch between the two) */
wxSizer *ams_rack_sizer = new wxBoxSizer(wxHORIZONTAL);
ams_rack_sizer->Add(create_ams_group(parent), 0, wxEXPAND | wxLEFT);
m_panel_nozzle_rack = new wgtDeviceNozzleRack(parent);
m_panel_nozzle_rack->Show(false);
ams_rack_sizer->Add(m_panel_nozzle_rack, 0, wxEXPAND | wxLEFT);
m_ams_rack_switch = new SwitchBoard(parent, _L("Filament"), _L("Hotends"), wxSize(FromDIP(126), FromDIP(26)));
m_ams_rack_switch->updateState("left");
m_ams_rack_switch->Hide();
m_ams_rack_switch->Bind(wxCUSTOMEVT_SWITCH_POS, &StatusBasePanel::on_ams_rack_switch, this);
bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(8));
bSizer_control->Add(temp_axis_ctrl_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8));
bSizer_control->Add(m_ams_rack_switch, 0, wxALIGN_CENTRE|wxTOP, FromDIP(6));
bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(6));
bSizer_control->Add(m_ams_ctrl_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8));
bSizer_control->Add(ams_rack_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8));
bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(6));
bSizer_control->Add(m_filament_load_sizer, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, FromDIP(8));
bSizer_control->Add(0, 0, 0, wxTOP, FromDIP(4));
@@ -2163,7 +2178,19 @@ void StatusBasePanel::expand_filament_loading(wxMouseEvent& e)
else if (obj->is_series_o())
{
const auto& ext_system = obj->GetExtderSystem();
if (ext_system->GetTotalExtderCount() == 2)
// Prefer the config-driven filament-load image: H2C ships per-extruder bitmaps, and a printer
// fitted with an induction hotend rack picks the rack-specific set (filament_load_image_nozzle_rack).
// Printers whose profile carries no such key (e.g. H2D) get an empty name here and fall through to
// the generic O-series bitmaps below, so their monitor page stays byte-identical. Rack-driven, so
// there is no behavior change for any non-rack printer.
int cur_ext_id = (ext_system && ext_system->GetTotalExtderCount() > 1) ? ext_system->GetCurrentExtderId() : 0;
bool has_nozzle_rack = obj->GetNozzleSystem()->GetNozzleRack()->IsSupported();
std::string img_name = DevPrinterConfigUtil::get_filament_load_img(obj->printer_type, cur_ext_id, has_nozzle_rack);
if (!img_name.empty())
{
m_filament_load_img->SetBitmap(create_scaled_bitmap(img_name, this, load_img_size));
}
else if (ext_system->GetTotalExtderCount() == 2)
{
int cur_extder_id = ext_system->GetCurrentExtderId();
if (cur_extder_id == MAIN_EXTRUDER_ID)
@@ -2202,6 +2229,10 @@ void StatusBasePanel::show_ams_group(bool show)
wxGetApp().mainframe->m_monitor->Layout();
}
// On rack printers, don't clobber the rack view when the user has the switch on "Hotends".
// Inert for every non-rack printer: the switch stays hidden, so this guard never triggers.
if (show && m_ams_rack_switch->IsShown() && (m_ams_rack_switch->switch_left != true)) { return; }
if (m_ams_control_box->IsShown() != show) {
m_ams_control_box->Show(show);
m_ams_control->Layout();
@@ -2227,7 +2258,7 @@ void StatusBasePanel::show_filament_load_group(bool show)
}
auto cur_ext = obj->GetExtderSystem()->GetCurrentExtder();
m_filament_step->SetupSteps(cur_ext ? cur_ext->HasFilamentInExt() : false);
m_filament_step->SetupSteps(obj, cur_ext ? cur_ext->HasFilamentInExt() : false);
Layout();
Fit();
@@ -2237,6 +2268,31 @@ void StatusBasePanel::show_filament_load_group(bool show)
}
}
void StatusBasePanel::jump_to_Rack()
{
if (obj && obj->GetNozzleSystem()->GetNozzleRack()->IsSupported()) {
m_ams_rack_switch->updateState("right");
m_ams_control_box->Show(false);
m_panel_nozzle_rack->Show(true);
Layout();
}
}
void StatusBasePanel::on_ams_rack_switch(wxCommandEvent &e)
{
if (!m_ams_control_box->IsShown() && e.GetInt() == 1) {
m_ams_control_box->Show(e.GetInt() == 1);
m_panel_nozzle_rack->Show(e.GetInt() == 0);
Layout();
} else if (!m_panel_nozzle_rack->IsShown() && e.GetInt() == 0) {
m_ams_control_box->Show(e.GetInt() == 1);
m_panel_nozzle_rack->Show(e.GetInt() == 0);
Layout();
}
e.Skip();
}
void StatusPanel::update_camera_state(MachineObject* obj)
{
if (!obj) return;
@@ -2778,6 +2834,8 @@ void StatusPanel::update(MachineObject *obj)
update_ams(obj);
update_cali(obj);
update_rack(obj);
if (obj) {
//nozzle ui
//m_button_left_of_extruder->SetSelected();
@@ -3413,7 +3471,14 @@ void StatusPanel::update_ams(MachineObject *obj)
int tray_id_int = atoi(tray_id.c_str());
// new protocol
if (ams_id_int < 128) {
if ((obj->tray_reading_bits & (1 << (ams_id_int * 4 + tray_id_int))) != 0) {
if (ams_it->second->IsAmsLiteMixed()) {
// Mixed AMS-Lite (A2L / N9) RFID-reading bits occupy positions 24..27.
if ((obj->tray_reading_bits & (1 << (AMS_LITE_MIXED_TRAY_INDEX_OFFSET + tray_id_int))) != 0) {
m_ams_control->PlayRridLoading(ams_id, tray_id);
} else {
m_ams_control->StopRridLoading(ams_id, tray_id);
}
} else if ((obj->tray_reading_bits & (1 << (ams_id_int * 4 + tray_id_int))) != 0) {
m_ams_control->PlayRridLoading(ams_id, tray_id);
} else {
m_ams_control->StopRridLoading(ams_id, tray_id);
@@ -3462,6 +3527,14 @@ void StatusPanel::update_ams_control_state(std::string ams_id, std::string slot_
if (ams_id.empty() || slot_id.empty()) {
load_error_info = _L("Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament.");
unload_error_info = _L("Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament.");
} else if (obj->GetFilaSwitch()->IsInstalled() && devPrinterUtil::IsVirtualSlot(ams_id)) {
// Orca: with a Filament Track Switch installed the external spool cannot be routed, so both actions are blocked.
load_error_info = _L("\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch.");
unload_error_info = load_error_info;
} else if (obj->GetFilaSwitch()->IsInstalled() && !obj->GetFilaSwitch()->IsReady()) {
// Orca: an un-calibrated Filament Track Switch cannot route filament to either extruder, so block both actions.
load_error_info = _L("The Filament Track Switch has not been setup. Please setup on printer.");
unload_error_info = load_error_info;
} else if (ams_id == std::to_string(VIRTUAL_TRAY_MAIN_ID) || ams_id == std::to_string(VIRTUAL_TRAY_DEPUTY_ID)) {
for (auto ext : obj->GetExtderSystem()->GetExtruders()) {
if (ext.GetSlotNow().ams_id == ams_id && ext.GetSlotNow().slot_id == slot_id)
@@ -3471,6 +3544,8 @@ void StatusPanel::update_ams_control_state(std::string ams_id, std::string slot_
}
} else {
for (auto ext : obj->GetExtderSystem()->GetExtruders()) {
// Orca: with a Filament Track Switch installed a slot is not bound to a single extruder, so skip the "already loaded" identity check.
if (obj->GetFilaSwitch()->IsInstalled()) { continue; }
if (ext.GetSlotNow().ams_id == ams_id && ext.GetSlotNow().slot_id == slot_id)
{
load_error_info = _L("Current slot has already been loaded.");
@@ -4167,6 +4242,43 @@ 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);
std::optional<int> extruder_id = std::nullopt;
if (obj->GetFilaSwitch() && obj->GetFilaSwitch()->IsInstalled()) {
if (!obj->GetFilaSwitch()->IsReady()) {
MessageDialog msg_dlg(nullptr, _L("The Filament Track Switch has not been setup. Please setup on printer."), wxEmptyString, wxICON_WARNING | wxOK);
msg_dlg.ShowModal();
return;
}
// Filament Track Switch is calibrated: the load can go to either extruder, so ask the
// user which. Record each extruder's currently-loaded slot so the dialog can grey out a
// side that already holds this filament.
std::vector<std::pair<std::string, std::string>> extruderSlots(2, {"", ""});
if (auto ext = obj->GetExtderSystem()->GetExtderById(MAIN_EXTRUDER_ID); ext.has_value())
{
if (ext->HasFilamentInExt())
{
extruderSlots[MAIN_EXTRUDER_ID] = {ext->GetSlotNow().ams_id, ext->GetSlotNow().slot_id};
}
}
if (auto ext = obj->GetExtderSystem()->GetExtderById(DEPUTY_EXTRUDER_ID); ext.has_value())
{
if (ext->HasFilamentInExt())
{
extruderSlots[DEPUTY_EXTRUDER_ID] = {ext->GetSlotNow().ams_id, ext->GetSlotNow().slot_id};
}
}
FeedDirectionDialog dialog(nullptr, 2, obj->printer_type);
dialog.SetExtruderMapping(obj, curr_ams_id, curr_can_id, extruderSlots);
auto rtn = dialog.ShowModal();
if (rtn != wxID_OK)
{
return;
}
extruder_id = dialog.GetExtruderID();
}
update_load_with_temp();
//virtual tray
@@ -4198,11 +4310,11 @@ void StatusPanel::on_ams_load_curr()
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);
obj->command_ams_change_filament(true, curr_ams_id, "0", old_temp, new_temp, extruder_id);
}
} catch (...) {}
} else {
obj->command_ams_change_filament(true, "254", "0", old_temp, new_temp);
obj->command_ams_change_filament(true, "254", "0", old_temp, new_temp, extruder_id);
}
}
@@ -4238,12 +4350,12 @@ void StatusPanel::on_ams_load_curr()
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);
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp, extruder_id);
}
}
catch (...){}
} else {
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp);
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp, extruder_id);
}
}
}
@@ -5086,6 +5198,9 @@ void StatusPanel::set_default()
m_ams_control->Hide();
m_ams_control_box->Hide();
m_ams_control->Reset();
m_ams_rack_switch->updateState("left");
m_ams_rack_switch->Hide();
m_panel_nozzle_rack->Hide();
m_scale_panel->Hide();
m_filament_load_box->Hide();
m_filament_step->Hide();
@@ -5263,6 +5378,7 @@ void StatusPanel::msw_rescale()
m_extruder_switching_status->msw_rescale();
m_ams_control->msw_rescale();
m_panel_nozzle_rack->Rescale();
// m_filament_step->Rescale();
@@ -5284,6 +5400,20 @@ void StatusPanel::msw_rescale()
Refresh();
}
void StatusPanel::update_rack(MachineObject *obj)
{
// Rack switch + live rack panel are shown only for printers whose nozzle system reports a rack
// (H2C). Every other Bambu printer keeps the switch hidden and the panel collapsed -> the AMS
// monitor page is unchanged for X1/P1/A1/H2D/H2S.
if (obj && obj->GetNozzleSystem()->GetNozzleRack()->IsSupported()) {
m_ams_rack_switch->Show();
m_panel_nozzle_rack->UpdateRackInfo(obj->GetNozzleSystem()->GetNozzleRack());
} else {
m_ams_rack_switch->Show(false);
m_panel_nozzle_rack->Show(false);
}
}
void StatusPanel::update_filament_loading_panel(MachineObject* obj)
{
if (!obj) {
@@ -5723,7 +5853,7 @@ wxBoxSizer *ScoreDialog::get_photo_btn_sizer() {
m_add_photo->Bind(wxEVT_LEFT_DOWN, [this](auto &e) {
// add photo logic
wxFileDialog openFileDialog(this, "Select Images", "", "", "Image files (*.png;*.jpg;*jpeg)|*.png;*.jpg;*.jpeg", wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);
wxFileDialog openFileDialog(this, _L("Select Images"), "", "", _L("Image files (*.png;*.jpg;*jpeg)|*.png;*.jpg;*.jpeg"), wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);
if (openFileDialog.ShowModal() == wxID_CANCEL) return;