mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-18 00:12:09 +00:00
Port the pre-send checks and wire the AMS best-position popup
This commit is contained in:
@@ -65,6 +65,10 @@ std::string PrePrintChecker::get_print_status_info(PrintDialogStatus status)
|
||||
case PrintStatusHasUnreliableNozzleWarning: return "PrintStatusHasUnreliableNozzleWarning";
|
||||
case PrintStatusWarningExtFilamentNotMatch: return "PrintStatusWarningExtFilamentNotMatch";
|
||||
case PrintStatusFilamentWarningNozzleHRC: return "PrintStatusFilamentWarningNozzleHRC";
|
||||
case PrintStatusTPUUnsupportCaliOn: return "PrintStatusTPUUnsupportCaliOn";
|
||||
case PrintStatusSmartNozzleBlobNeedAuto: return "PrintStatusSmartNozzleBlobNeedAuto";
|
||||
case PrintStatusFilamentWarningRemainNotEnough: return "PrintStatusFilamentWarningRemainNotEnough";
|
||||
case PrintStatusPrintTimeEstimateWarning: return "PrintStatusPrintTimeEstimateWarning";
|
||||
case PrintStatusReadingFinished: return "PrintStatusReadingFinished";
|
||||
case PrintStatusSendingCanceled: return "PrintStatusSendingCanceled";
|
||||
case PrintStatusAmsMappingSuccess: return "PrintStatusAmsMappingSuccess";
|
||||
@@ -103,8 +107,14 @@ wxString PrePrintChecker::get_pre_state_msg(PrintDialogStatus status)
|
||||
case PrintStatusTPUUnsupportAutoCali: return _L("TPU 90A/TPU 85A is too soft and does not support automatic Flow Dynamics calibration.");
|
||||
case PrintStatusWarningKvalueNotUsed: return _L("Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value.");
|
||||
case PrintStatusNotSupportedPrintAll: return _L("This printer does not support printing all plates.");
|
||||
case PrintStatusColorQuantityExceed: return _L("The current firmware supports a maximum of 16 materials. You can either reduce the number of materials to 16 or fewer on the Preparation Page, or try updating the firmware. If you are still restricted after the update, please wait for subsequent firmware support.");
|
||||
// Orca: %s-parameterized so the real per-printer max color count can be filled in by the caller
|
||||
// (SelectMachine formats it via get_pre_state_msg before add()); default templates keep the wording.
|
||||
case PrintStatusColorQuantityExceed: return _L("The current firmware supports a maximum of %s materials. You can either reduce the number of materials to %s or fewer on the Preparation Page, or try updating the firmware. If you are still restricted after the update, please wait for subsequent firmware support.");
|
||||
case PrintStatusWarningExtFilamentNotMatch: return _L("The type of external filament is unknown or does not match with the filament type in the slicing file. Please make sure you have installed the correct filament in the external spool.");
|
||||
case PrintStatusTPUUnsupportCaliOn: return _L("TPU 90A/TPU 85A is too soft. It is recommended to perform manual flow calibration on the 'Calibration' page. If 'Dynamic Flow Calibration' is set to on, the system will use the previous calibration value and skip the flow calibration process.");
|
||||
case PrintStatusSmartNozzleBlobNeedAuto: return _L("There is stringing-prone filament in this file. For best print quality, we recommend switching nozzle clumping detection to Auto mode.");
|
||||
case PrintStatusFilamentWarningRemainNotEnough: return _L("The filament in the AMS may be insufficient for this print. Please refill or replace it.");
|
||||
case PrintStatusPrintTimeEstimateWarning: return _L("The print time estimate may be inaccurate for the current AMS configuration.");
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,13 @@ enum PrintDialogStatus : unsigned int {
|
||||
PrintStatusWarningExtFilamentNotMatch,
|
||||
PrintStatusFilamentWarningNozzleHRC,
|
||||
PrintStatusFilamentCrossExtruderWarning,
|
||||
// Orca: resynced pre-send-check statuses. SmartNozzleBlobNeedAuto + TPUUnsupportCaliOn are wired
|
||||
// (see SelectMachine); FilamentWarningRemainNotEnough + PrintTimeEstimateWarning are declared for
|
||||
// forward-compat but their feature wiring stays deferred (missing device-model surface).
|
||||
PrintStatusTPUUnsupportCaliOn,
|
||||
PrintStatusSmartNozzleBlobNeedAuto,
|
||||
PrintStatusFilamentWarningRemainNotEnough,
|
||||
PrintStatusPrintTimeEstimateWarning,
|
||||
PrintStatusFilamentWarningEnd,
|
||||
|
||||
PrintStatusWarningEnd,//->end error<-
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#include "DeviceCore/DevMapping.h"
|
||||
#include "DeviceCore/DevUtilBackend.h"
|
||||
#include "DeviceCore/DevMappingNozzle.h"
|
||||
#include "DeviceCore/DevPrintOptions.h" // Orca: smart-nozzle-blob detection option (resync)
|
||||
#include "libslic3r/MultiNozzleUtils.hpp" // Orca: filament-change-gap model for the best-position popup (resync)
|
||||
#include "BackgroundSlicingProcess.hpp" // Orca: complete type for background_process().get_current_gcode_result() (resync)
|
||||
#include "DeviceCore/DevStorage.h"
|
||||
|
||||
#include <wx/progdlg.h>
|
||||
@@ -326,6 +329,17 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
|
||||
m_text_printer_msg_tips->Hide();
|
||||
m_text_printer_msg_tips->GetAlignment();
|
||||
|
||||
// Orca: best-position "recommended arrangement saves X" clickable tip (resync). Hidden unless the
|
||||
// printer has a filament switcher and a better arrangement exists; click opens the best-position popup.
|
||||
m_saveTimeText = new Label(m_basic_panel, wxEmptyString);
|
||||
m_saveTimeText->SetForegroundColour(wxColour("#FF6F00"));
|
||||
m_saveTimeText->SetFont(::Label::Body_13);
|
||||
m_saveTimeText->Hide();
|
||||
m_saveTimeText->Bind(wxEVT_LEFT_UP, &SelectMachineDialog::on_reselect_dialog_btn_clicked, this);
|
||||
m_saveTimeText->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent&) { m_saveTimeText->SetCursor(wxCURSOR_HAND); });
|
||||
m_saveTimeText->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent&) { m_saveTimeText->SetCursor(wxCURSOR_DEFAULT); });
|
||||
Bind(wxEVT_REFRESH_DATA, &SelectMachineDialog::update_best_pos_dialog, this);
|
||||
|
||||
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);
|
||||
@@ -335,6 +349,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
|
||||
sizer_basic_right_info->Add(m_text_printer_msg, 0, wxLEFT, 0);
|
||||
sizer_basic_right_info->AddSpacer(FromDIP(10));
|
||||
sizer_basic_right_info->Add(m_text_printer_msg_tips, 0, wxLEFT, 0);
|
||||
sizer_basic_right_info->Add(m_saveTimeText, 0, wxTOP, 0); // Orca: best-position tip (resync)
|
||||
|
||||
|
||||
m_basicl_sizer->Add(m_sizer_thumbnail_area, 0, wxLEFT, 0);
|
||||
@@ -1911,6 +1926,290 @@ bool SelectMachineDialog::CheckWarningFilamentCrossExtruder(MachineObject* obj_)
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== Orca: resynced pre-send checks + AMS best-position popup (cluster 7) =====
|
||||
|
||||
bool SelectMachineDialog::CheckWarningSmartNozzleBlobAuto(MachineObject* obj_)
|
||||
{
|
||||
if (!obj_ || m_print_type != PrintFromType::FROM_NORMAL) return true;
|
||||
|
||||
// Only relevant when the printer firmware supports the smart wrap detection feature.
|
||||
auto* opts = obj_->GetPrintOptions();
|
||||
if (!opts) return true;
|
||||
const auto* opt = opts->GetDetectionOption(PrintOptionEnum::Smart_Nozzle_Blob_Detection);
|
||||
if (!opt || !opt->is_support_detect) return true;
|
||||
|
||||
// Already in Auto (cfg == 2): nothing to recommend.
|
||||
if (opt->current_detect_value == 2) return true;
|
||||
|
||||
// Need at least one stringing-prone filament in the sliced project for any nozzle on the current
|
||||
// printer config; iterating the diameters covers single- and dual-extruder printers.
|
||||
if (!wxGetApp().preset_bundle) return true;
|
||||
const auto& full_config = wxGetApp().preset_bundle->full_config();
|
||||
const auto* opt_nozzle_diameters = full_config.option<ConfigOptionFloats>("nozzle_diameter");
|
||||
if (!opt_nozzle_diameters || opt_nozzle_diameters->values.empty()) return true;
|
||||
|
||||
for (const auto& fila : m_filaments) {
|
||||
if (fila.filament_id.empty()) continue;
|
||||
for (double d : opt_nozzle_diameters->values) {
|
||||
if (Slic3r::is_stringing_prone_filament(fila.filament_id, static_cast<float>(d)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<FilamentInfo> SelectMachineDialog::get_slicing_filament_info(int fila_logic_id) const
|
||||
{
|
||||
for (const auto& fila : m_filaments)
|
||||
if (fila.id == fila_logic_id) return fila;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<FilamentInfo> SelectMachineDialog::get_mapped_filament_info(int fila_logic_id) const
|
||||
{
|
||||
for (const auto& fila : m_ams_mapping_result)
|
||||
if (fila.id == fila_logic_id) return fila;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool SelectMachineDialog::is_used_filament(int fila_logic_id) const
|
||||
{
|
||||
for (const auto& fila : m_ams_mapping_result)
|
||||
if (fila.id == fila_logic_id) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString SelectMachineDialog::FormatTime(float totalSeconds)
|
||||
{
|
||||
totalSeconds = std::abs(totalSeconds);
|
||||
int secs = static_cast<int>(std::round(totalSeconds));
|
||||
int hours = secs / 3600;
|
||||
int remaining = secs % 3600;
|
||||
int minutes = remaining / 60;
|
||||
int seconds = remaining % 60;
|
||||
if (hours > 0) return wxString::Format("%dm%ds", hours * 60 + minutes, seconds);
|
||||
if (minutes > 0) return wxString::Format("%dm%ds", minutes, seconds);
|
||||
return wxString::Format("%ds", seconds);
|
||||
}
|
||||
|
||||
// Orca: estimated filament-change time gap (actual vs. sliced) for the current AMS arrangement. Inlines
|
||||
// REF's calc_filament_change_gap_for_assignment (a thin wrapper over simulate_filament_change_time, which
|
||||
// Orca keeps) so no libslic3r change is needed. std::nullopt unless a filament switcher is installed.
|
||||
std::optional<float> SelectMachineDialog::get_filament_change_gap_time(MachineObject* obj_) const
|
||||
{
|
||||
if (m_print_type != PrintFromType::FROM_NORMAL) return std::nullopt;
|
||||
if (!m_plater || !obj_ || !obj_->GetFilaSwitch() || !obj_->GetFilaSwitch()->IsInstalled()) return std::nullopt;
|
||||
|
||||
GCodeProcessorResult* gcode_result = m_plater->background_process().get_current_gcode_result();
|
||||
auto nozzle_group_res = DevUtilBackend::GetNozzleGroupResult(m_plater);
|
||||
if (!nozzle_group_res || !gcode_result) return std::nullopt;
|
||||
|
||||
const std::vector<unsigned int>& used_u = nozzle_group_res->get_used_filaments();
|
||||
const std::vector<int> logic_filaments(used_u.begin(), used_u.end());
|
||||
|
||||
std::vector<int> group_of_filaments;
|
||||
for (const auto& fila_idx : logic_filaments) {
|
||||
bool found = false;
|
||||
for (const auto& item : m_ams_mapping_result) {
|
||||
if (fila_idx != item.id) continue;
|
||||
const auto& ams_item = obj_->GetFilaSystem()->GetAmsById(item.ams_id);
|
||||
if (ams_item && ams_item->GetSwitcherPos().has_value()) {
|
||||
if (ams_item->GetSwitcherPos().value() == DevFilaSwitch::POS_IN_A) { group_of_filaments.push_back(0); found = true; break; }
|
||||
else if (ams_item->GetSwitcherPos().value() == DevFilaSwitch::POS_IN_B) { group_of_filaments.push_back(1); found = true; break; }
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
if (!found) return std::nullopt;
|
||||
}
|
||||
|
||||
const std::vector<MultiNozzleUtils::NozzleInfo> nozzle_list = nozzle_group_res->get_used_nozzles_in_extruder();
|
||||
const std::vector<int> fila_change_seq(gcode_result->filament_change_sequence.begin(), gcode_result->filament_change_sequence.end());
|
||||
const std::vector<int> nozzle_change_seq(gcode_result->nozzle_change_sequence.begin(), gcode_result->nozzle_change_sequence.end());
|
||||
|
||||
MultiNozzleUtils::FilamentChangeTimeParams params;
|
||||
const auto& full_config = wxGetApp().preset_bundle->full_config();
|
||||
if (const auto* load_time_opt = full_config.option<ConfigOptionFloat>("machine_load_filament_time"))
|
||||
params.standard_load_time = load_time_opt->value;
|
||||
if (const auto* unload_time_opt = full_config.option<ConfigOptionFloat>("machine_unload_filament_time"))
|
||||
params.standard_unload_time = unload_time_opt->value;
|
||||
params.selector_load_time = params.standard_load_time * 0.5;
|
||||
params.selector_unload_time = params.standard_unload_time * 0.5;
|
||||
|
||||
int group_count = group_of_filaments.empty() ? 0 : *std::max_element(group_of_filaments.begin(), group_of_filaments.end()) + 1;
|
||||
// Orca: kept device model has no ams_preload_version; assume no AMS pre-load (conservative).
|
||||
std::vector<bool> ams_preload_enabled(group_count, false);
|
||||
|
||||
try {
|
||||
auto r = MultiNozzleUtils::simulate_filament_change_time(logic_filaments, nozzle_list, fila_change_seq,
|
||||
nozzle_change_seq, group_of_filaments, params,
|
||||
ams_preload_enabled, /*calc_sliced_time=*/true);
|
||||
return static_cast<float>(r.actual_time - r.sliced_time);
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": exception: " << e.what();
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
// Suggested switch position per logic filament from the slicing result + AMS mapping.
|
||||
std::map<int, DevFilaSwitch::SwitchPos> SelectMachineDialog::get_filament_suggest_pos(MachineObject* obj_) const
|
||||
{
|
||||
std::map<int, DevFilaSwitch::SwitchPos> suggest_pos_map;
|
||||
if (m_print_type != PrintFromType::FROM_NORMAL) return suggest_pos_map;
|
||||
if (!m_plater || !obj_ || !obj_->GetFilaSwitch() || !obj_->GetFilaSwitch()->IsInstalled()) return suggest_pos_map;
|
||||
|
||||
GCodeProcessorResult* gcode_result = m_plater->background_process().get_current_gcode_result();
|
||||
if (!gcode_result) return suggest_pos_map;
|
||||
|
||||
std::map<int, std::set<int>> pos2group;
|
||||
const auto& optimal_assignment = gcode_result->optimal_assignment;
|
||||
for (int fila_idx = 0; fila_idx < (int) optimal_assignment.size(); fila_idx++) {
|
||||
if (is_used_filament(fila_idx))
|
||||
pos2group[optimal_assignment.at(fila_idx)].insert(fila_idx);
|
||||
}
|
||||
|
||||
std::set<int> in_a_fila_set;
|
||||
std::set<int> in_b_fila_set;
|
||||
for (const auto& item : m_ams_mapping_result) {
|
||||
const auto& ams_item = obj_->GetFilaSystem()->GetAmsById(item.ams_id);
|
||||
if (ams_item && ams_item->GetSwitcherPos().has_value()) {
|
||||
if (ams_item->GetSwitcherPos().value() == DevFilaSwitch::POS_IN_A) in_a_fila_set.insert(item.id);
|
||||
else if (ams_item->GetSwitcherPos().value() == DevFilaSwitch::POS_IN_B) in_b_fila_set.insert(item.id);
|
||||
} else {
|
||||
return suggest_pos_map;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos2group.size() == 1) {
|
||||
DevFilaSwitch::SwitchPos target = (in_a_fila_set.size() >= in_b_fila_set.size()) ? DevFilaSwitch::POS_IN_A : DevFilaSwitch::POS_IN_B;
|
||||
for (const auto& item : m_ams_mapping_result)
|
||||
suggest_pos_map[item.id] = target;
|
||||
} else if (pos2group.size() == 2) {
|
||||
auto iter = pos2group.begin();
|
||||
const auto& group_1 = iter->second;
|
||||
++iter;
|
||||
const auto& group_2 = iter->second;
|
||||
|
||||
int offset_1 = 0; // place group1->INA, group2->INB
|
||||
for (const auto& g1 : group_1) if (in_a_fila_set.count(g1) == 0) offset_1++;
|
||||
for (const auto& g2 : group_2) if (in_b_fila_set.count(g2) == 0) offset_1++;
|
||||
|
||||
int offset_2 = 0; // place group2->INA, group1->INB
|
||||
for (const auto& g1 : group_1) if (in_b_fila_set.count(g1) == 0) offset_2++;
|
||||
for (const auto& g2 : group_2) if (in_a_fila_set.count(g2) == 0) offset_2++;
|
||||
|
||||
if (offset_1 <= offset_2) {
|
||||
for (const auto& fila_idx : group_1) suggest_pos_map[fila_idx] = DevFilaSwitch::POS_IN_A;
|
||||
for (const auto& fila_idx : group_2) suggest_pos_map[fila_idx] = DevFilaSwitch::POS_IN_B;
|
||||
} else {
|
||||
for (const auto& fila_idx : group_1) suggest_pos_map[fila_idx] = DevFilaSwitch::POS_IN_B;
|
||||
for (const auto& fila_idx : group_2) suggest_pos_map[fila_idx] = DevFilaSwitch::POS_IN_A;
|
||||
}
|
||||
}
|
||||
return suggest_pos_map;
|
||||
}
|
||||
|
||||
std::optional<DevFilaSwitch::SwitchPos> SelectMachineDialog::get_filament_suggest_pos(MachineObject* obj_, int filament_logic_id) const
|
||||
{
|
||||
const auto& suggest_pos_opt = get_filament_suggest_pos(obj_);
|
||||
if (suggest_pos_opt.empty()) return std::nullopt;
|
||||
for (const auto& item : m_ams_mapping_result) {
|
||||
if (item.id == filament_logic_id) {
|
||||
if (suggest_pos_opt.count(item.id) != 0) return suggest_pos_opt.at(item.id);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool SelectMachineDialog::is_at_suggested_pos(MachineObject* obj_, int filament_logic_id) const
|
||||
{
|
||||
auto opt = get_filament_suggest_pos(obj_, filament_logic_id);
|
||||
if (!opt.has_value()) return true;
|
||||
const auto& mapped_filament_info = get_mapped_filament_info(filament_logic_id);
|
||||
if (mapped_filament_info.has_value()) {
|
||||
const auto& ams_item = obj_->GetFilaSystem()->GetAmsById(mapped_filament_info->ams_id);
|
||||
if (ams_item)
|
||||
return ams_item->GetSwitcherPos() == opt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Orca adaptation: drives only the "saves X" tip (m_saveTimeText); unlike REF it does NOT re-set the
|
||||
// print-time label m_stext_time, so Orca's existing time display is untouched. No-op unless a filament
|
||||
// switcher is installed and a better arrangement exists.
|
||||
void SelectMachineDialog::refresh_save_time(MachineObject* obj)
|
||||
{
|
||||
if (m_print_type != PrintFromType::FROM_NORMAL || !m_saveTimeText) return;
|
||||
|
||||
auto save_time = get_filament_change_gap_time(obj);
|
||||
bool is_all_at_suggest_pos = true;
|
||||
for (const auto& mapping_item : m_ams_mapping_result) {
|
||||
is_all_at_suggest_pos = is_at_suggested_pos(obj, mapping_item.id);
|
||||
if (!is_all_at_suggest_pos) break;
|
||||
}
|
||||
|
||||
if (save_time.has_value() && save_time.value() >= 1 && !is_all_at_suggest_pos) {
|
||||
m_saveTimeText->SetLabel(wxString::Format(_L("Recommended filament arrangement saves %s->"), FormatTime(*save_time)));
|
||||
m_saveTimeText->Wrap(-1);
|
||||
m_saveTimeText->Show();
|
||||
m_basic_panel->Layout();
|
||||
m_basic_panel->Fit();
|
||||
} else {
|
||||
m_saveTimeText->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SelectMachineDialog::on_reselect_dialog_btn_clicked(wxMouseEvent&)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__;
|
||||
DeviceManager* dev = wxGetApp().getDeviceManager();
|
||||
MachineObject* obj = dev ? dev->get_selected_machine() : nullptr;
|
||||
if (!obj) return;
|
||||
if (m_best_pos_dialog == nullptr)
|
||||
m_best_pos_dialog = new ReselectMachineDialog(static_cast<wxWindow*>(this));
|
||||
|
||||
auto save_time = get_filament_change_gap_time(obj);
|
||||
wxString text{};
|
||||
if (save_time.has_value() && save_time.value() >= 1)
|
||||
text = FormatTime(*save_time);
|
||||
|
||||
std::map<int, int> best_pos_map; // key: logic id, value: pos id
|
||||
for (const auto& slot : m_ams_mapping_result) {
|
||||
if (!is_at_suggested_pos(obj, slot.id)) {
|
||||
auto pos = get_filament_suggest_pos(obj, slot.id);
|
||||
if (pos.has_value())
|
||||
best_pos_map[slot.id] = pos.value();
|
||||
}
|
||||
}
|
||||
m_best_pos_dialog->Update(obj, best_pos_map, m_ams_mapping_result, text);
|
||||
m_best_pos_dialog->ShowModal();
|
||||
}
|
||||
|
||||
void SelectMachineDialog::update_best_pos_dialog(wxCommandEvent& evt)
|
||||
{
|
||||
if (!m_best_pos_dialog) return; // Orca: only relevant while the popup is open
|
||||
DeviceManager* dev = wxGetApp().getDeviceManager();
|
||||
MachineObject* obj_ = dev ? dev->get_selected_machine() : nullptr;
|
||||
if (!obj_) return;
|
||||
update_show_status(obj_);
|
||||
|
||||
auto save_time = get_filament_change_gap_time(obj_);
|
||||
wxString text{};
|
||||
if (save_time.has_value() && save_time.value() >= 1)
|
||||
text = FormatTime(*save_time);
|
||||
|
||||
std::map<int, int> best_pos_map;
|
||||
for (const auto& slot : m_ams_mapping_result) {
|
||||
if (!is_at_suggested_pos(obj_, slot.id)) {
|
||||
auto pos = get_filament_suggest_pos(obj_, slot.id);
|
||||
if (pos.has_value())
|
||||
best_pos_map[slot.id] = pos.value();
|
||||
}
|
||||
}
|
||||
m_best_pos_dialog->Update(obj_, best_pos_map, m_ams_mapping_result, text);
|
||||
}
|
||||
|
||||
void SelectMachineDialog::show_status(PrintDialogStatus status, std::vector<wxString> params, wxString wiki_url)
|
||||
{
|
||||
wxString msg;
|
||||
@@ -1985,6 +2284,9 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vector<wxSt
|
||||
} else if (status == PrintStatusColorQuantityExceed) {
|
||||
Enable_Refresh_Button(true);
|
||||
Enable_Send_Button(false);
|
||||
// Orca: fill the real per-printer max color count into the %s template (resync).
|
||||
if (!params.empty())
|
||||
msg = wxString::Format(m_pre_print_checker.get_pre_state_msg(status), params[0], params[0]);
|
||||
}
|
||||
|
||||
else if (status == PrintDialogStatus::PrintStatusAmsMappingU0Invalid) {
|
||||
@@ -2098,6 +2400,9 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vector<wxSt
|
||||
} else if (status == PrintStatusTPUUnsupportAutoCali) {
|
||||
Enable_Refresh_Button(true);
|
||||
Enable_Send_Button(false);
|
||||
} else if (status == PrintStatusTPUUnsupportCaliOn) { // Orca: TPU manual-cali-on gate (resync)
|
||||
Enable_Refresh_Button(true);
|
||||
Enable_Send_Button(false);
|
||||
} else if (status == PrintStatusHasFilamentInBlackListError) {
|
||||
Enable_Refresh_Button(true);
|
||||
Enable_Send_Button(false);
|
||||
@@ -4429,13 +4734,13 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
// Orca: gate against the printer's real max filament-color count instead of a hardcoded 16, so
|
||||
// high-color firmware (is_support_filament_32_colors -> 32) isn't wrongly blocked. Floor at 16 so
|
||||
// printers that report 0 (e.g. series X/O) keep their prior limit; every other class is unchanged.
|
||||
// The max shown in the message is owned by PrePrintChecker (out of this cluster's scope).
|
||||
// The real max is passed as a param so the %s message shows the actual count.
|
||||
int max_color = obj_->get_max_filament_color_count();
|
||||
if (max_color < 16) max_color = 16;
|
||||
if (wxGetApp().preset_bundle->filament_presets.size() > (size_t)max_color && m_print_type != PrintFromType::FROM_SDCARD_VIEW) {
|
||||
if (!obj_->is_enable_ams_np && !obj_->is_enable_np)
|
||||
{
|
||||
show_status(PrintDialogStatus::PrintStatusColorQuantityExceed);
|
||||
show_status(PrintDialogStatus::PrintStatusColorQuantityExceed, {wxString::Format("%d", max_color)});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4455,14 +4760,18 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
}
|
||||
}
|
||||
|
||||
// Orca: also gate the "auto" flow-cali case (REF parity — closes a pre-existing gap where TPU/Aero
|
||||
// with Flow Dynamics Calibration set to Auto was not blocked on printers that don't support PA
|
||||
// auto-cali). Both auto and on map to the one available status enum; REF's distinct "CaliOn"
|
||||
// message lives in PrePrintChecker (out of this cluster's scope).
|
||||
if (!can_support_pa_auto_cali() && m_checkbox_list["flow_cali"]->IsShown()
|
||||
&& (m_checkbox_list["flow_cali"]->getValue() == "on" || m_checkbox_list["flow_cali"]->getValue() == "auto")) {
|
||||
show_status(PrintDialogStatus::PrintStatusTPUUnsupportAutoCali);
|
||||
return;
|
||||
// Orca: gate both flow-cali cases for TPU/Aero on printers that don't support PA auto-cali (REF
|
||||
// parity). "auto" -> AutoCali, "on" -> CaliOn, matching REF's distinct messages now that the
|
||||
// CaliOn status exists in PrePrintChecker (this cluster). Both block Send.
|
||||
if (!can_support_pa_auto_cali() && m_checkbox_list["flow_cali"]->IsShown()) {
|
||||
if (m_checkbox_list["flow_cali"]->getValue() == "auto") {
|
||||
show_status(PrintDialogStatus::PrintStatusTPUUnsupportAutoCali);
|
||||
return;
|
||||
}
|
||||
if (m_checkbox_list["flow_cali"]->getValue() == "on") {
|
||||
show_status(PrintDialogStatus::PrintStatusTPUUnsupportCaliOn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*disable print when there is no mapping*/
|
||||
@@ -4674,6 +4983,27 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
"may affect print quality. Enabling Flow Dynamics Calibration is recommended.");
|
||||
show_status(PrintDialogStatus::PrintStatusFilamentCrossExtruderWarning, { warning_msg });
|
||||
}
|
||||
|
||||
// Orca: smart-nozzle-blob pre-send suggestion (resync). When the file has stringing-prone filament
|
||||
// and the printer's clumping detection isn't already Auto, offer a clickable "Switch" that sets the
|
||||
// detection to Auto (mode 2). Rendered via the Orca callback-link path (add_with_link).
|
||||
if (!CheckWarningSmartNozzleBlobAuto(obj_)) {
|
||||
show_status(PrintDialogStatus::PrintStatusSmartNozzleBlobNeedAuto);
|
||||
m_pre_print_checker.add_with_link(
|
||||
PrintDialogStatus::PrintStatusSmartNozzleBlobNeedAuto,
|
||||
m_pre_print_checker.get_pre_state_msg(PrintDialogStatus::PrintStatusSmartNozzleBlobNeedAuto),
|
||||
_L("Switch"),
|
||||
[] {
|
||||
DeviceManager* dev = wxGetApp().getDeviceManager();
|
||||
MachineObject* o = dev ? dev->get_selected_machine() : nullptr;
|
||||
if (o && o->GetPrintOptions())
|
||||
o->GetPrintOptions()->command_smart_nozzle_blob_detect_mode(2);
|
||||
});
|
||||
}
|
||||
|
||||
// Orca: refresh the best-position "saves X" tip (resync); no-op for printers without a switcher.
|
||||
refresh_save_time(obj_);
|
||||
|
||||
if (m_ams_mapping_res) {
|
||||
if (has_timelapse_warning()) {
|
||||
show_status(PrintDialogStatus::PrintStatusTimelapseWarning);
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#include "Widgets/ScrolledWindow.hpp"
|
||||
#include "Widgets/PopupWindow.hpp"
|
||||
#include "Widgets/HyperLink.hpp" // ORCA
|
||||
#include "DeviceTab/uiAMSBestPositionPopup.hpp" // Orca: AMS best-position popup (resync)
|
||||
#include "DeviceCore/DevFilaSwitch.h" // Orca: DevFilaSwitch::SwitchPos for best-position helpers
|
||||
#include <optional>
|
||||
#include <wx/simplebook.h>
|
||||
#include <wx/hashmap.h>
|
||||
|
||||
@@ -396,6 +399,7 @@ protected:
|
||||
wxStaticText* m_rename_text{nullptr};
|
||||
Label* m_stext_time{ nullptr };
|
||||
Label* m_stext_weight{ nullptr };
|
||||
Label* m_saveTimeText{ nullptr }; // Orca: best-position "saves X" clickable tip (resync)
|
||||
PrinterMsgPanel * m_statictext_ams_msg{nullptr};
|
||||
Label* m_txt_change_filament_times{ nullptr };
|
||||
CheckBox* m_check_ext_change_assist{ nullptr };
|
||||
@@ -442,6 +446,7 @@ protected:
|
||||
wxGridSizer* m_sizer_ams_mapping_right{ nullptr };
|
||||
|
||||
PrePrintChecker m_pre_print_checker;
|
||||
ReselectMachineDialog* m_best_pos_dialog{ nullptr }; // Orca: AMS best-position popup (resync)
|
||||
|
||||
public:
|
||||
static std::vector<wxString> MACHINE_BED_TYPE_STRING;
|
||||
@@ -548,6 +553,22 @@ public:
|
||||
// Warn (without blocking) when a mapped filament would be printed from both extruders on a
|
||||
// dual-extruder printer, so per-nozzle manual K-value can't follow it across the whole print.
|
||||
bool CheckWarningFilamentCrossExtruder(MachineObject* obj_);
|
||||
// Orca: smart-nozzle-blob pre-send suggestion (resync). Recommends switching nozzle clumping
|
||||
// detection to Auto when the file has stringing-prone filament and the printer isn't in Auto.
|
||||
bool CheckWarningSmartNozzleBlobAuto(MachineObject* obj_);
|
||||
// Orca: AMS best-switch-position popup (resync). Suggests the filament arrangement that minimizes
|
||||
// filament-change time on filament-switcher printers; no-op for printers without a switcher.
|
||||
void on_reselect_dialog_btn_clicked(wxMouseEvent&);
|
||||
void update_best_pos_dialog(wxCommandEvent& evt);
|
||||
void refresh_save_time(MachineObject* obj);
|
||||
std::optional<float> get_filament_change_gap_time(MachineObject* obj_) const;
|
||||
std::map<int, DevFilaSwitch::SwitchPos> get_filament_suggest_pos(MachineObject* obj_) const;
|
||||
std::optional<DevFilaSwitch::SwitchPos> get_filament_suggest_pos(MachineObject* obj_, int fila_logic_id) const;
|
||||
bool is_at_suggested_pos(MachineObject* obj_, int fila_logic_id) const;
|
||||
wxString FormatTime(float totalSeconds);
|
||||
std::optional<FilamentInfo> get_slicing_filament_info(int fila_logic_id) const;
|
||||
std::optional<FilamentInfo> get_mapped_filament_info(int fila_logic_id) const;
|
||||
bool is_used_filament(int fila_logic_id) const;
|
||||
|
||||
// Rack print-dispatch nozzle mapping (H2C): request the printer's auto-mapping and consume the
|
||||
// result, gating the Send button while the printer computes. Both are no-ops for non-rack printers.
|
||||
|
||||
Reference in New Issue
Block a user