Merge branch 'main' into dev/p2s-pr

# Conflicts:
#	src/slic3r/GUI/Jobs/PrintJob.cpp
#	src/slic3r/GUI/SelectMachine.cpp
#	src/slic3r/GUI/SendToPrinter.cpp
#	src/slic3r/Utils/CalibUtils.cpp
This commit is contained in:
Noisyfox
2025-10-29 21:03:22 +08:00
37 changed files with 7726 additions and 4803 deletions
+3
View File
@@ -266,6 +266,9 @@ void AppConfig::set_defaults()
if (get("stealth_mode").empty()) {
set_bool("stealth_mode", false);
}
if (get("allow_abnormal_storage").empty()) {
set_bool("allow_abnormal_storage", false);
}
if (get("legacy_networking").empty()) {
set_bool("legacy_networking", false);
}
+27 -3
View File
@@ -869,6 +869,13 @@ void MenuFactory::append_menu_item_replace_with_stl(wxMenu *menu)
[]() { return plater()->can_replace_with_stl(); }, m_parent);
}
void MenuFactory::append_menu_item_replace_all_with_stl(wxMenu *menu)
{
append_menu_item(menu, wxID_ANY, _L("Replace all with STL"), _L("Replace all selected parts with STL from folder"),
[](wxCommandEvent &) { plater()->replace_all_with_stl(); }, "", menu,
[]() { return plater()->can_replace_all_with_stl(); }, m_parent);
}
void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
{
// BBS
@@ -1350,6 +1357,7 @@ void MenuFactory::create_extra_object_menu()
m_object_menu.AppendSeparator();
append_menu_item_reload_from_disk(&m_object_menu);
append_menu_item_replace_with_stl(&m_object_menu);
append_menu_item_replace_all_with_stl(&m_object_menu);
append_menu_item_export_stl(&m_object_menu);
}
@@ -1465,6 +1473,7 @@ void MenuFactory::create_bbl_part_menu()
append_menu_item_change_type(menu);
append_menu_item_reload_from_disk(menu);
append_menu_item_replace_with_stl(menu);
append_menu_item_replace_all_with_stl(menu);
}
void MenuFactory::create_bbl_assemble_part_menu()
@@ -1615,6 +1624,7 @@ void MenuFactory::create_plate_menu()
[](wxCommandEvent&) { plater()->add_file(); }, "", menu,
[]() {return wxGetApp().plater()->can_add_model(); }, m_parent);
#endif
append_menu_item_replace_all_with_stl(menu);
return;
@@ -1721,14 +1731,26 @@ wxMenu* MenuFactory::multi_selection_menu()
wxDataViewItemArray sels;
obj_list()->GetSelections(sels);
bool multi_volume = true;
bool undefined_type = false;
bool all_plates = true;
for (const wxDataViewItem& item : sels) {
multi_volume = list_model()->GetItemType(item) & itVolume;
if (!(list_model()->GetItemType(item) & (itVolume | itObject | itInstance)))
Slic3r::GUI::ItemType item_type = list_model()->GetItemType(item);
if ((item_type & itPlate) == 0)
all_plates = false;
multi_volume = item_type & itVolume;
if (!(item_type & (itVolume | itObject | itInstance)))
// show this menu only for Objects(Instances mixed with Objects)/Volumes selection
return nullptr;
undefined_type = true;
}
if (all_plates) {
wxMenu* menu = new MenuWithSeparators();
append_menu_item_replace_all_with_stl(menu);
return menu;
}
if (undefined_type)
return nullptr;
wxMenu* menu = new MenuWithSeparators();
if (!multi_volume) {
int index = 0;
@@ -1747,6 +1769,7 @@ wxMenu* MenuFactory::multi_selection_menu()
append_menu_item_per_object_process(menu);
menu->AppendSeparator();
append_menu_items_convert_unit(menu);
append_menu_item_replace_all_with_stl(menu);
//BBS
append_menu_item_change_filament(menu);
menu->AppendSeparator();
@@ -1759,6 +1782,7 @@ wxMenu* MenuFactory::multi_selection_menu()
//append_menu_item_simplify(menu);
append_menu_item_delete(menu);
append_menu_items_convert_unit(menu);
append_menu_item_replace_all_with_stl(menu);
append_menu_item_change_filament(menu);
wxMenu* split_menu = new wxMenu();
if (split_menu) {
+1
View File
@@ -143,6 +143,7 @@ private:
void append_menu_item_export_stl(wxMenu* menu, bool is_mulity_menu = false);
void append_menu_item_reload_from_disk(wxMenu* menu);
void append_menu_item_replace_with_stl(wxMenu* menu);
void append_menu_item_replace_all_with_stl(wxMenu* menu);
void append_menu_item_change_extruder(wxMenu* menu);
void append_menu_item_set_visible(wxMenu* menu);
void append_menu_item_delete(wxMenu* menu);
+25 -3
View File
@@ -579,12 +579,34 @@ void PrintJob::process(Ctl &ctl)
}
}
} else {
if (this->has_sdcard || this->could_emmc_print) {
if (this->could_emmc_print) {
ctl.update_status(curr_percent, _u8L("Sending print job over LAN"));
result = m_agent->start_local_print(params, update_fn, cancel_fn);
} else {
ctl.update_status(curr_percent, _u8L("Storage needs to be inserted before printing via LAN."));
return;
switch(this->sdcard_state) {
case DevStorage::SdcardState::NO_SDCARD:
ctl.update_status(curr_percent, _u8L("A Storage needs to be inserted before printing via LAN."));
return;
case DevStorage::SdcardState::HAS_SDCARD_ABNORMAL:
if(this->has_sdcard) {
// means the storage is abnormal but can be used option is enabled
ctl.update_status(curr_percent, _u8L("Sending print job over LAN, but the Storage in the printer is abnormal and print-issues may be caused by this."));
result = m_agent->start_local_print(params, update_fn, cancel_fn);
break;
}
ctl.update_status(curr_percent, _u8L("The Storage in the printer is abnormal. Please replace it with a normal Storage before sending print job to printer."));
return;
case DevStorage::SdcardState::HAS_SDCARD_READONLY:
ctl.update_status(curr_percent, _u8L("The Storage in the printer is read-only. Please replace it with a normal Storage before sending print job to printer."));
return;
case DevStorage::SdcardState::HAS_SDCARD_NORMAL:
ctl.update_status(curr_percent, _u8L("Sending print job over LAN"));
result = m_agent->start_local_print(params, update_fn, cancel_fn);
break;
default:
ctl.update_status(curr_percent, _u8L("Encountered an unknown error with the Storage status. Please try again."));
return;
}
}
}
+3
View File
@@ -5,6 +5,7 @@
#include <boost/filesystem/operations.hpp>
#include "libslic3r/PrintConfig.hpp"
#include "Job.hpp"
#include "slic3r/GUI/DeviceCore/DevStorage.h"
namespace fs = boost::filesystem;
@@ -84,6 +85,8 @@ public:
bool has_sdcard { false };
bool could_emmc_print { false };
bool task_use_ams { true };
DevStorage::SdcardState sdcard_state = DevStorage::SdcardState::NO_SDCARD;
bool task_ext_change_assist { false };
int auto_bed_leveling{0};
+24 -7
View File
@@ -297,13 +297,30 @@ void SendJob::process(Ctl &ctl)
ctl.update_status(curr_percent, _u8L("Sending G-code file over LAN"));
}
} else {
if (this->has_sdcard) {
ctl.update_status(curr_percent, _u8L("Sending G-code file over LAN"));
result = m_agent->start_send_gcode_to_sdcard(params, update_fn, cancel_fn, nullptr);
} else {
ctl.update_status(curr_percent, _u8L("Storage needs to be inserted before sending to printer."));
return;
}
switch(this->sdcard_state) {
case DevStorage::SdcardState::NO_SDCARD:
ctl.update_status(curr_percent, _u8L("Storage needs to be inserted before sending to printer."));
return;
case DevStorage::SdcardState::HAS_SDCARD_ABNORMAL:
if(this->has_sdcard) {
// means the sdcard is abnormal but can be used option is enabled
ctl.update_status(curr_percent, _u8L("Sending G-code file over LAN, but the Storage in the printer is abnormal and print-issues may be caused by this."));
result = m_agent->start_send_gcode_to_sdcard(params, update_fn, cancel_fn, nullptr);
break;
}
ctl.update_status(curr_percent, _u8L("The Storage in the printer is abnormal. Please replace it with a normal Storage before sending to printer."));
return;
case DevStorage::SdcardState::HAS_SDCARD_READONLY:
ctl.update_status(curr_percent, _u8L("The Storage in the printer is read-only. Please replace it with a normal Storage before sending to printer."));
return;
case DevStorage::SdcardState::HAS_SDCARD_NORMAL:
ctl.update_status(curr_percent, _u8L("Sending G-code file over LAN"));
result = m_agent->start_send_gcode_to_sdcard(params, update_fn, cancel_fn, nullptr);
break;
default:
ctl.update_status(curr_percent, _u8L("Encountered an unknown error with the Storage status. Please try again."));
return;
}
}
if (ctl.was_canceled()) {
+3
View File
@@ -3,6 +3,7 @@
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include "slic3r/GUI/DeviceCore/DevStorage.h"
#include "Job.hpp"
#include "PrintJob.hpp"
@@ -46,6 +47,8 @@ public:
bool has_sdcard { false };
bool task_use_ams { true };
DevStorage::SdcardState sdcard_state = DevStorage::SdcardState::NO_SDCARD;
wxWindow* m_parent{nullptr};
int status_range() const
+141 -1
View File
@@ -4171,6 +4171,7 @@ struct Plater::priv
void reload_from_disk();
bool replace_volume_with_stl(int object_idx, int volume_idx, const fs::path& new_path, const std::string& snapshot = "");
void replace_with_stl();
void replace_all_with_stl();
void reload_all_from_disk();
//BBS: add no_slice option
@@ -4284,6 +4285,7 @@ struct Plater::priv
bool can_fillcolor() const;
bool has_assemble_view() const;
bool can_replace_with_stl() const;
bool can_replace_all_with_stl() const;
bool can_split(bool to_objects) const;
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
bool can_scale_to_print_volume() const;
@@ -7636,6 +7638,132 @@ void Plater::priv::replace_with_stl()
}
}
void Plater::priv::replace_all_with_stl()
{
if (! q->get_view3D_canvas3D()->get_gizmos_manager().check_gizmos_closed_except(GLGizmosManager::EType::Undefined))
return;
const Selection& selection = get_selection();
if (selection.is_wipe_tower())
return;
fs::path input_path;
Selection::IndicesList volume_idxs = selection.get_volume_idxs();
// when plates are selected instead of volumes
// then selection is inaccurate, we need to
// find volumes contained in selected plates
if (selection.is_empty() || volume_idxs.empty()) {
std::vector<int> selected_plate_idxs;
wxDataViewItemArray sels;
wxGetApp().obj_list()->GetSelections(sels);
for (const wxDataViewItem& item : sels) {
Slic3r::GUI::ItemType item_type = wxGetApp().obj_list()->GetModel()->GetItemType(item);
if (item_type & itPlate) {
if (item.IsOk()) {
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode *>(item.GetID());
selected_plate_idxs.push_back(node->GetPlateIdx());
}
}
}
PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
for (int obj_idx = 0; obj_idx < selection.get_model()->objects.size(); obj_idx++) {
for (int plate_idx : selected_plate_idxs) {
PartPlate* plate = plate_list.get_plate(plate_idx);
if (plate && plate->contain_instance_totally(obj_idx, 0)) {
std::vector<unsigned int> indices = selection.get_volume_idxs_from_object(obj_idx);
volume_idxs.insert(indices.begin(), indices.end());
}
}
}
}
// find path for initializing the file selection dialog
for (unsigned int idx : volume_idxs) {
const GLVolume* v = selection.get_volume(idx);
int object_idx = v->object_idx();
int volume_idx = v->volume_idx();
const ModelObject* object = model.objects[object_idx];
const ModelVolume* volume = object->volumes[volume_idx];
if (!volume->source.input_file.empty() && fs::exists(volume->source.input_file)) {
input_path = volume->source.input_file;
break;
}
}
wxString title = _L("Select folder to replace from");
title += ":";
wxDirDialog dialog(q, title, from_u8(input_path.parent_path().string()), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
if (dialog.ShowModal() != wxID_OK)
return;
fs::path out_path = dialog.GetPath().ToUTF8().data();
if (out_path.empty()) {
MessageDialog dlg(q, _L("Directory for the replace wasn't selected"), _L("Error during replace"), wxOK | wxOK_DEFAULT | wxICON_WARNING);
dlg.ShowModal();
return;
}
std::string status = _L("Replaced with STLs from directory:\n").ToStdString() + out_path.string() + "\n\n";
for (unsigned int idx : volume_idxs) {
const GLVolume* v = selection.get_volume(idx);
int object_idx = v->object_idx();
int volume_idx = v->volume_idx();
const ModelObject* object = model.objects[object_idx];
const ModelVolume* volume = object->volumes[volume_idx];
if (volume->source.input_file.empty())
continue;
input_path = volume->source.input_file;
fs::path new_path = out_path / input_path.filename();
std::string volume_name = volume->name;
if (new_path == input_path) {
status += boost::str(boost::format(_L("✖ Skipped %1%: same file.\n").ToStdString()) % volume_name);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " skipping replace volume : same filename " << new_path;
continue;
}
if (!fs::exists(new_path)) {
status += boost::str(boost::format(_L("✖ Skipped %1%: file does not exist.\n").ToStdString()) % volume_name);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cannot replace volume : filen does not exist " << new_path;
continue;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " replacing volume : " << input_path << " with " << new_path;
if (!replace_volume_with_stl(object_idx, volume_idx, new_path, "Replace with STL")) {
status += boost::str(boost::format(_L("✖ Skipped %1%: failed to replace.\n").ToStdString()) % volume_name);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " cannot replace volume : failed to replace with " << new_path;
continue;
}
status += boost::str(boost::format(_L("✔ Replaced %1%.\n").ToStdString()) % volume_name);
}
// update 3D scene
update();
// new GLVolumes have been created at this point, so update their printable state
for (size_t i = 0; i < model.objects.size(); ++i) {
view3D->get_canvas3d()->update_instance_printable_state_for_object(i);
}
MessageDialog dlg(q, status, _L("Replaced volumes"), wxOK | wxOK_DEFAULT | wxICON_INFORMATION);
dlg.ShowModal();
}
#if ENABLE_RELOAD_FROM_DISK_REWORK
static std::vector<std::pair<int, int>> reloadable_volumes(const Model &model, const Selection &selection)
{
@@ -10198,6 +10326,12 @@ bool Plater::priv::can_replace_with_stl() const
&& get_selection().get_volume_idxs().size() == 1;
}
bool Plater::priv::can_replace_all_with_stl() const
{
return !sidebar->obj_list()->has_selected_cut_object()
&& get_selection().get_volume_idxs().size() != 1;
}
bool Plater::priv::can_reload_from_disk() const
{
if (sidebar->obj_list()->has_selected_cut_object())
@@ -14044,7 +14178,7 @@ bool Plater::check_printer_initialized(MachineObject *obj, bool only_warning, bo
break;
}
}
if (extruder.GetNozzleFlowType() == NozzleType::ntUndefine) {
if (extruder.GetNozzleFlowType() == NozzleFlowType::NONE_FLOWTYPE) {
has_been_initialized = false;
break;
}
@@ -14729,6 +14863,11 @@ void Plater::replace_with_stl()
p->replace_with_stl();
}
void Plater::replace_all_with_stl()
{
p->replace_all_with_stl();
}
void Plater::reload_all_from_disk()
{
p->reload_all_from_disk();
@@ -17331,6 +17470,7 @@ bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
bool Plater::can_fillcolor() const { return p->can_fillcolor(); }
bool Plater::has_assmeble_view() const { return p->has_assemble_view(); }
bool Plater::can_replace_with_stl() const { return p->can_replace_with_stl(); }
bool Plater::can_replace_all_with_stl() const { return p->can_replace_all_with_stl(); }
bool Plater::can_mirror() const { return p->can_mirror(); }
bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); }
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
+2
View File
@@ -494,6 +494,7 @@ public:
void reload_from_disk();
void replace_with_stl();
void replace_all_with_stl();
void reload_all_from_disk();
bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj() const;
@@ -670,6 +671,7 @@ public:
bool can_redo() const;
bool can_reload_from_disk() const;
bool can_replace_with_stl() const;
bool can_replace_all_with_stl() const;
bool can_mirror() const;
bool can_split(bool to_objects) const;
#if ENABLE_ENHANCED_PRINT_VOLUME_FIT
+1 -1
View File
@@ -81,7 +81,7 @@ wxString PrePrintChecker::get_pre_state_msg(PrintDialogStatus status)
case PrintStatusAmsMappingMixInvalid: return _L("Please do not mix-use the Ext with AMS");
case PrintStatusNozzleDataInvalid: return _L("Invalid nozzle information, please refresh or manually set nozzle information.");
case PrintStatusLanModeNoSdcard: return _L("Storage needs to be inserted before printing via LAN.");
case PrintStatusLanModeSDcardNotAvailable: return _L("Storage is not available or is in read-only mode.");
case PrintStatusLanModeSDcardNotAvailable: return _L("Storage is in abnormal state or is in read-only mode.");
case PrintStatusNoSdcard: return _L("Storage needs to be inserted before printing.");
case PrintStatusNeedForceUpgrading: return _L("Cannot send the print job to a printer whose firmware is required to get updated.");
case PrintStatusNeedConsistencyUpgrading: return _L("Cannot send the print job to a printer whose firmware is required to get updated.");
+4
View File
@@ -1404,6 +1404,10 @@ void PreferencesDialog::create_items()
auto item_mix_print_high_low_temperature = create_item_checkbox(_L("Remove mixed temperature restriction"), _L("With this option enabled, you can print materials with a large temperature difference together."), "enable_high_low_temp_mixed_printing");
g_sizer->Add(item_mix_print_high_low_temperature);
g_sizer->Add(create_item_title(_L("Storage")), 1, wxEXPAND);
auto item_allow_abnormal_storage = create_item_checkbox(_L("Allow Abnormal Storage"), _L("This allows the use of Storage that is marked as abnormal by the Printer.\nUse at your own risk, can cause issues!"), "allow_abnormal_storage");
g_sizer->Add(item_allow_abnormal_storage);
g_sizer->Add(create_item_title(_L("Log Level")), 1, wxEXPAND);
auto log_level_list = std::vector<wxString>{_L("fatal"), _L("error"), _L("warning"), _L("info"), _L("debug"), _L("trace")};
auto loglevel_combox = create_item_loglevel_combobox(_L("Log Level"), _L("Log Level"), log_level_list);
+10 -2
View File
@@ -2520,7 +2520,12 @@ void SelectMachineDialog::on_send_print()
BOOST_LOG_TRIVIAL(error) << "build_nozzle_info errors";
}
m_print_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_NORMAL;
m_print_job->sdcard_state = obj_->GetStorage()->get_sdcard_state();
m_print_job->has_sdcard = wxGetApp().app_config->get("allow_abnormal_storage") == "true"
? (m_print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL
|| m_print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL)
: m_print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL;
m_print_job->could_emmc_print = obj_->is_support_print_with_emmc;
@@ -3324,7 +3329,10 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
&& !obj_->is_support_print_with_emmc) {
show_status(PrintDialogStatus::PrintStatusLanModeNoSdcard);
return;
} else if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL || obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_READONLY) {
} else if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_READONLY) {
show_status(PrintDialogStatus::PrintStatusLanModeSDcardNotAvailable);
return;
} else if(obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL && (wxGetApp().app_config->get("allow_abnormal_storage") == "false")){
show_status(PrintDialogStatus::PrintStatusLanModeSDcardNotAvailable);
return;
}
+5 -1
View File
@@ -980,7 +980,11 @@ void SendToPrinterDialog::on_ok(wxCommandEvent &event)
#endif
m_send_job->connection_type = obj_->connection_type();
m_send_job->cloud_print_only = true;
m_send_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_NORMAL;
m_send_job->sdcard_state = obj_->GetStorage()->get_sdcard_state();
m_send_job->has_sdcard = wxGetApp().app_config->get("allow_abnormal_storage") == "true"
? (m_send_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL
|| m_send_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL)
: m_send_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL;
m_send_job->set_project_name(m_current_project_name.utf8_string());
enable_prepare_mode = false;
+6 -1
View File
@@ -1,6 +1,7 @@
#include "CalibUtils.hpp"
#include "../GUI/I18N.hpp"
#include "../GUI/GUI_App.hpp"
#include "../GUI/DeviceCore/DevStorage.h"
#include "../GUI/DeviceManager.hpp"
#include "../GUI/Jobs/ProgressIndicator.hpp"
#include "../GUI/PartPlate.hpp"
@@ -1827,7 +1828,11 @@ 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_->GetStorage()->get_sdcard_state() == DevStorage::HAS_SDCARD_NORMAL;
print_job->sdcard_state = obj_->GetStorage()->get_sdcard_state();
print_job->has_sdcard = wxGetApp().app_config->get("allow_abnormal_storage") == "true"
? (print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL
|| print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL)
: print_job->sdcard_state == DevStorage::SdcardState::HAS_SDCARD_NORMAL;
print_job->could_emmc_print = obj_->is_support_print_with_emmc;
print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true, false, 0, 0, 0);
print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name);