Merge branch 'upstream/main' into harktech/k2-discovery

Consolidates #13744 (CFS filament sync) into this PR per maintainer
request and resyncs with main. Conflicts resolved:

* src/slic3r/GUI/Plater.cpp -- parallel else-if added by both sides
  (htCrealityPrint + flashforge_local_api branches); kept both.
* src/slic3r/GUI/PhysicalPrinterDialog.cpp -- both sides added a
  host-specific Browse dialog (Creality DNS-SD + Flashforge); kept
  both as early-return branches, fall through to BonjourDialog.
* src/slic3r/GUI/PrintHostDialogs.hpp -- parallel class declarations
  (CrealityPrintHostSendDialog + FlashforgePrintHostSendDialog);
  kept both.
This commit is contained in:
grant0013
2026-05-28 07:56:06 +00:00
1008 changed files with 31791 additions and 25415 deletions

View File

@@ -1854,6 +1854,14 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
// Orca: if the edit button is already hidden the handler has no
// state to change, so skip the expensive wxFindWindowAtPoint tree
// walk. Without this guard, when the parent window is on an
// inactive Hyprland/Wayland workspace, GTK keeps delivering
// synthetic leave events and the Hide()+Layout() below re-enters
// the same handler in a feedback loop that pegs a CPU core.
// (IsShownOnScreen() can't be used here — see Plater.cpp:9304.)
if (!p->btn_edit_printer->IsShown()) { e.Skip(); return; }
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
@@ -6852,12 +6860,12 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
double preset_nozzle_diameter = 0.4;
const ConfigOption *opt = printer_preset.config.option("nozzle_diameter");
if (opt) preset_nozzle_diameter = static_cast<const ConfigOptionFloats *>(opt)->values[0];
float machine_nozzle_diameter = obj->GetExtderSystem()->GetNozzleDiameter(0);
std::string machine_type = obj->printer_type;
if (obj->is_support_upgrade_kit && obj->installed_upgrade_kit) machine_type = "C12";
if (printer_preset.get_current_printer_type(preset_bundle) != machine_type || !is_approx((float) preset_nozzle_diameter, machine_nozzle_diameter)) {
bool nozzle_mismatch = !obj->GetExtderSystem()->NozzleDiameterMatchesOrUnknown(0, (float) preset_nozzle_diameter);
if (printer_preset.get_current_printer_type(preset_bundle) != machine_type || nozzle_mismatch) {
Preset *machine_preset = get_printer_preset(obj);
if (machine_preset != nullptr) {
std::string printer_model = machine_preset->config.option<ConfigOptionString>("printer_model")->value;
@@ -9568,7 +9576,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
const auto& extruders = obj->GetExtderSystem()->GetExtruders();
for (const DevExtder &extruder : extruders) {
if (!is_approx(extruder.GetNozzleDiameter(), float(preset_nozzle_diameter))) {
if (!obj->GetExtderSystem()->NozzleDiameterMatchesOrUnknown(extruder.GetExtId(), float(preset_nozzle_diameter))) {
same_nozzle_diameter = false;
}
}
@@ -16083,6 +16091,18 @@ void Plater::send_gcode_legacy(int plate_idx, Export3mfProgressFn proFn, bool us
if (upload_job.empty())
return;
const auto host_type_opt = physical_printer_config->option<ConfigOptionEnum<PrintHostType>>("host_type");
const auto host_type = host_type_opt != nullptr ? host_type_opt->value : htElegooLink;
const auto* ff_serial_opt = physical_printer_config->option<ConfigOptionString>("flashforge_serial_number");
const auto* ff_code_opt = physical_printer_config->option<ConfigOptionString>("printhost_apikey");
const bool flashforge_local_api =
host_type == htFlashforge &&
ff_serial_opt != nullptr && !ff_serial_opt->value.empty() &&
ff_code_opt != nullptr && !ff_code_opt->value.empty();
if (flashforge_local_api)
use_3mf = true;
upload_job.upload_data.use_3mf = use_3mf;
// Obtain default output path
@@ -16130,8 +16150,6 @@ void Plater::send_gcode_legacy(int plate_idx, Export3mfProgressFn proFn, bool us
{
auto preset_bundle = wxGetApp().preset_bundle;
const auto opt = physical_printer_config->option<ConfigOptionEnum<PrintHostType>>("host_type");
const auto host_type = opt != nullptr ? opt->value : htElegooLink;
auto config = get_app_config();
std::unique_ptr<PrintHostSendDialog> pDlg;
@@ -16144,6 +16162,77 @@ void Plater::send_gcode_legacy(int plate_idx, Export3mfProgressFn proFn, bool us
storage_paths, storage_names,
config->get_bool("open_device_tab_post_upload"),
upload_job.printhost.get());
} else if (flashforge_local_api) {
auto* flashforge_host = dynamic_cast<Flashforge*>(upload_job.printhost.get());
if (flashforge_host == nullptr) {
show_error(this, _L("Flashforge host is not available."), false);
return;
}
std::vector<FlashforgeMaterialSlot> slots;
bool supports_material_station = false;
{
wxBusyCursor wait;
wxString msg;
if (!flashforge_host->fetch_material_slots(slots, &supports_material_station, msg)) {
show_error(this, msg.empty() ? _L("Unable to log in to the Flashforge printer.") : msg, false);
return;
}
}
std::vector<FilamentInfo> project_filaments;
PlateDataPtrs plate_data_list;
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config();
const auto* filament_color = dynamic_cast<const ConfigOptionStrings*>(cfg.option("filament_colour"));
const auto* filament_id_opt = dynamic_cast<const ConfigOptionStrings*>(cfg.option("filament_ids"));
const int resolved_plate_idx = plate_idx == PLATE_CURRENT_IDX ? get_partplate_list().get_curr_plate_index() : plate_idx;
auto enrich_project_filaments = [&](std::vector<FilamentInfo>& filaments) {
for (auto& filament : filaments) {
if (filament.id < 0)
continue;
std::string display_filament_type;
try {
filament.type = cfg.get_filament_type(display_filament_type, filament.id);
} catch (...) {
}
if (filament.type.empty())
filament.type = display_filament_type;
if (filament.type.empty())
filament.type = "Unknown";
filament.filament_id = filament_id_opt ? filament_id_opt->get_at(static_cast<size_t>(filament.id)) : "";
filament.color = filament_color ? filament_color->get_at(static_cast<size_t>(filament.id)) : "#FFFFFF";
if (filament.color.empty())
filament.color = "#FFFFFF";
}
};
p->partplate_list.store_to_3mf_structure(plate_data_list, true, plate_idx);
PlateData* selected_plate_data = (resolved_plate_idx >= 0 && resolved_plate_idx < static_cast<int>(plate_data_list.size())) ? plate_data_list[resolved_plate_idx] : nullptr;
if (selected_plate_data == nullptr && !plate_data_list.empty())
selected_plate_data = plate_data_list.front();
if (selected_plate_data != nullptr)
project_filaments = selected_plate_data->slice_filaments_info;
if (project_filaments.empty()) {
if (PartPlate* plate = get_partplate_list().get_plate(resolved_plate_idx); plate != nullptr)
project_filaments = plate->get_slice_filaments_info();
}
if (!project_filaments.empty())
enrich_project_filaments(project_filaments);
release_PlateData_list(plate_data_list);
pDlg = std::make_unique<FlashforgePrintHostSendDialog>(default_output_file, upload_job.printhost->get_post_upload_actions(), groups,
storage_paths, storage_names,
config->get_bool("open_device_tab_post_upload"),
flashforge_host,
supports_material_station,
std::move(slots),
project_filaments);
} else {
pDlg = std::make_unique<PrintHostSendDialog>(default_output_file, upload_job.printhost->get_post_upload_actions(), groups,
storage_paths, storage_names, config->get_bool("open_device_tab_post_upload"));
@@ -16173,7 +16262,8 @@ void Plater::send_gcode_legacy(int plate_idx, Export3mfProgressFn proFn, bool us
if (use_3mf) {
// Process gcode
const int result = send_gcode(plate_idx, nullptr);
const int export_plate_idx = plate_idx == PLATE_CURRENT_IDX ? get_partplate_list().get_curr_plate_index() : plate_idx;
const int result = send_gcode(export_plate_idx, nullptr);
if (result < 0) {
wxString msg = _L("Abnormal print file data. Please slice again");