mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-20 01:12:09 +00:00
feat(gui): per-filament nozzle volume selection and persistence
- FilamentMapDialog's manual page understands volume types: a mixed (Hybrid) extruder shows separate Standard / High Flow drop zones with live sub-nozzle counts, a validation timer with an inline error + "set nozzle count" suggestion, and composes a per-filament volume map on OK (persisted to the plate or globally) - switching an extruder's Flow type rewrites the affected plate map entries; plate maps stay sized across filament add/delete/count changes (values keep their filament, no index shift) - CLI: manual mapping on multi-nozzle printers synthesizes the volume map from extruder flow types when absent; nozzle-manual mode requires explicit maps; computed maps land on the plate so exported projects carry filament_volume_maps - filament_nozzle_map joins the project options (selection seeding + filament-count resizing) - pot entries for the new dialog strings All 19 reference fixtures byte-identical; slicing an exported Hybrid project reproduces its g-code byte-for-byte with the volume map round-tripped through model_settings.config.
This commit is contained in:
@@ -36,6 +36,13 @@ static std::vector<int> get_applied_map(DynamicConfig& proj_config, const Plater
|
||||
return plater_ref->get_global_filament_map();
|
||||
}
|
||||
|
||||
static std::vector<int> get_applied_volume_map(DynamicConfig& proj_config, const Plater* plater_ref, const PartPlate* partplate_ref, const bool sync_plate)
|
||||
{
|
||||
if (sync_plate)
|
||||
return partplate_ref->get_real_filament_volume_maps(proj_config);
|
||||
return plater_ref->get_global_filament_volume_map();
|
||||
}
|
||||
|
||||
extern std::string& get_left_extruder_unprintable_text();
|
||||
extern std::string& get_right_extruder_unprintable_text();
|
||||
|
||||
@@ -123,7 +130,9 @@ bool try_pop_up_before_slice(bool is_slice_all, Plater* plater_ref, PartPlate* p
|
||||
std::vector<std::string> filament_types = full_config.option<ConfigOptionStrings>("filament_type")->values;
|
||||
FilamentMapMode applied_mode = get_applied_map_mode(full_config, plater_ref,partplate_ref, sync_plate);
|
||||
std::vector<int> applied_maps = get_applied_map(full_config, plater_ref, partplate_ref, sync_plate);
|
||||
std::vector<int> applied_volume_maps = get_applied_volume_map(full_config, plater_ref, partplate_ref, sync_plate);
|
||||
applied_maps.resize(filament_colors.size(), 1);
|
||||
applied_volume_maps.resize(filament_colors.size(), 0);
|
||||
|
||||
if (!force_pop_up && applied_mode != fmmManual)
|
||||
return true;
|
||||
@@ -141,6 +150,7 @@ bool try_pop_up_before_slice(bool is_slice_all, Plater* plater_ref, PartPlate* p
|
||||
filament_colors,
|
||||
filament_types,
|
||||
applied_maps,
|
||||
applied_volume_maps,
|
||||
filament_lists,
|
||||
applied_mode,
|
||||
plater_ref->get_machine_sync_status(),
|
||||
@@ -152,25 +162,32 @@ bool try_pop_up_before_slice(bool is_slice_all, Plater* plater_ref, PartPlate* p
|
||||
if (ret == wxID_OK) {
|
||||
FilamentMapMode new_mode = map_dlg.get_mode();
|
||||
std::vector<int> new_maps = map_dlg.get_filament_maps();
|
||||
std::vector<int> new_volume_maps = map_dlg.get_filament_volume_maps();
|
||||
if (sync_plate) {
|
||||
if (is_slice_all) {
|
||||
auto plate_list = plater_ref->get_partplate_list().get_plate_list();
|
||||
for (int i = 0; i < plate_list.size(); ++i) {
|
||||
plate_list[i]->set_filament_map_mode(new_mode);
|
||||
if(new_mode == fmmManual)
|
||||
if (new_mode == fmmManual) {
|
||||
plate_list[i]->set_filament_maps(new_maps);
|
||||
plate_list[i]->set_filament_volume_maps(new_volume_maps);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
partplate_ref->set_filament_map_mode(new_mode);
|
||||
if (new_mode == fmmManual)
|
||||
if (new_mode == fmmManual) {
|
||||
partplate_ref->set_filament_maps(new_maps);
|
||||
partplate_ref->set_filament_volume_maps(new_volume_maps);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
plater_ref->set_global_filament_map_mode(new_mode);
|
||||
if (new_mode == fmmManual)
|
||||
if (new_mode == fmmManual) {
|
||||
plater_ref->set_global_filament_map(new_maps);
|
||||
plater_ref->set_global_filament_volume_map(new_volume_maps);
|
||||
}
|
||||
}
|
||||
plater_ref->update();
|
||||
// check whether able to slice, if not, return false
|
||||
@@ -186,12 +203,17 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
||||
const std::vector<std::string> &filament_color,
|
||||
const std::vector<std::string> &filament_type,
|
||||
const std::vector<int> &filament_map,
|
||||
const std::vector<int> &filament_volume_map,
|
||||
const std::vector<int> &filaments,
|
||||
const FilamentMapMode mode,
|
||||
bool machine_synced,
|
||||
bool show_default,
|
||||
bool with_checkbox)
|
||||
: wxDialog(parent, wxID_ANY, _L("Filament grouping"), wxDefaultPosition, wxDefaultSize,wxDEFAULT_DIALOG_STYLE), m_filament_color(filament_color), m_filament_type(filament_type), m_filament_map(filament_map)
|
||||
: wxDialog(parent, wxID_ANY, _L("Filament grouping"), wxDefaultPosition, wxDefaultSize,wxDEFAULT_DIALOG_STYLE)
|
||||
, m_filament_color(filament_color)
|
||||
, m_filament_type(filament_type)
|
||||
, m_filament_map(filament_map)
|
||||
, m_filament_volume_map(filament_volume_map)
|
||||
{
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
|
||||
@@ -244,7 +266,20 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
||||
mode == fmmAutoForMatch && !auto_match_available ? fmmAutoForFlush :
|
||||
mode;
|
||||
|
||||
m_manual_map_panel = new FilamentMapManualPanel(this, m_filament_color, m_filament_type, filaments, filament_map);
|
||||
m_manual_map_panel = new FilamentMapManualPanel(this, m_filament_color, m_filament_type, filaments, filament_map, filament_volume_map);
|
||||
// A manual grouping can point filaments at a nozzle volume the extruder does not physically
|
||||
// carry; the panel's validation timer reports that here so OK is gated on a printable map.
|
||||
m_manual_map_panel->Bind(wxEVT_INVALID_MANUAL_MAP, [this](wxCommandEvent &event) {
|
||||
if (m_page_type != PageType::ptManual) {
|
||||
if (!m_ok_btn->IsEnabled()) { m_ok_btn->Enable(); }
|
||||
return;
|
||||
}
|
||||
if (event.GetInt()) {
|
||||
if (!m_ok_btn->IsEnabled()) { m_ok_btn->Enable(); }
|
||||
} else {
|
||||
if (m_ok_btn->IsEnabled()) { m_ok_btn->Disable(); }
|
||||
}
|
||||
});
|
||||
m_auto_map_panel = new FilamentMapAutoPanel(this, default_auto_mode, auto_match_available);
|
||||
if (show_default)
|
||||
m_default_map_panel = new FilamentMapDefaultPanel(this);
|
||||
@@ -351,16 +386,8 @@ void FilamentMapDialog::on_checkbox(wxCommandEvent &event)
|
||||
void FilamentMapDialog::on_ok(wxCommandEvent &event)
|
||||
{
|
||||
if (m_page_type == PageType::ptManual) {
|
||||
std::vector<int> left_filaments = m_manual_map_panel->GetLeftFilaments();
|
||||
std::vector<int> right_filaments = m_manual_map_panel->GetRightFilaments();
|
||||
|
||||
for (int i = 0; i < m_filament_map.size(); ++i) {
|
||||
if (std::find(left_filaments.begin(), left_filaments.end(), i + 1) != left_filaments.end()) {
|
||||
m_filament_map[i] = 1;
|
||||
} else if (std::find(right_filaments.begin(), right_filaments.end(), i + 1) != right_filaments.end()) {
|
||||
m_filament_map[i] = 2;
|
||||
}
|
||||
}
|
||||
m_filament_map = m_manual_map_panel->GetFilamentMaps();
|
||||
m_filament_volume_map = m_manual_map_panel->GetFilamentVolumeMaps();
|
||||
}
|
||||
|
||||
EndModal(wxID_OK);
|
||||
@@ -398,6 +425,11 @@ void FilamentMapDialog::update_panel_status(PageType page)
|
||||
m_auto_map_panel->Show();
|
||||
}
|
||||
|
||||
// The nozzle-availability gate only constrains manual grouping; every other page must
|
||||
// leave OK usable even if the manual page had disabled it.
|
||||
if (page != PageType::ptManual && m_ok_btn && !m_ok_btn->IsEnabled())
|
||||
m_ok_btn->Enable();
|
||||
|
||||
if (m_smart_filament)
|
||||
m_smart_filament->Show(get_mode() == fmmAutoForFlush);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user