mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-28 03:11:47 +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:
@@ -18332,6 +18332,16 @@ msgstr ""
|
|||||||
msgid "Set the physical nozzle count..."
|
msgid "Set the physical nozzle count..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#, possible-c-format, possible-boost-format
|
||||||
|
msgid "Error: %s extruder has no available %s nozzle, current group result is invalid."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Please adjust your grouping or click "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid " to set nozzle count"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Prime tower is required for nozzle changing. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?"
|
msgid "Prime tower is required for nozzle changing. There may be flaws on the model without prime tower. Are you sure you want to disable prime tower?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -5945,6 +5945,72 @@ int CLI::run(int argc, char **argv)
|
|||||||
else
|
else
|
||||||
filament_maps = part_plate->get_real_filament_maps(m_print_config);
|
filament_maps = part_plate->get_real_filament_maps(m_print_config);
|
||||||
|
|
||||||
|
// Multi-nozzle printers need the per-filament volume assignment as a grouping
|
||||||
|
// input in the manual modes: synthesize it from the per-extruder flow types when
|
||||||
|
// the caller did not provide one (an extruder whose nozzle stats span several
|
||||||
|
// volume types keeps the per-filament choice), and require explicit maps in
|
||||||
|
// nozzle-manual mode.
|
||||||
|
auto max_nozzle_counts_opt = m_print_config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
|
||||||
|
// Skip nil entries: a nullable-int nil is INT_MAX (> 1) and would otherwise falsely pass the gate.
|
||||||
|
bool support_multi_nozzle =
|
||||||
|
max_nozzle_counts_opt &&
|
||||||
|
std::any_of(max_nozzle_counts_opt->values.begin(), max_nozzle_counts_opt->values.end(),
|
||||||
|
[](int v) { return v > 1 && v != ConfigOptionIntsNullable::nil_value(); });
|
||||||
|
if (support_multi_nozzle && (mode == fmmManual || mode == fmmNozzleManual) && (plate_to_slice != 0)) {
|
||||||
|
// Orca: the grouping result is reconstructed purely from the passed maps in
|
||||||
|
// nozzle-manual mode, so all of them must be present (there are no separate
|
||||||
|
// per-nozzle CLI parameters to rebuild them from).
|
||||||
|
if (mode == FilamentMapMode::fmmNozzleManual &&
|
||||||
|
(!m_extra_config.has("filament_volume_map") || !m_extra_config.has("filament_nozzle_map") ||
|
||||||
|
!m_extra_config.has("filament_map"))) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< boost::format("%1%, can not find filament_volume_map/filament_nozzle_map/filament_map under Nozzle Manual mode") % __LINE__;
|
||||||
|
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, index + 1, cli_errors[CLI_INVALID_PARAMS], sliced_info);
|
||||||
|
flush_and_exit(CLI_INVALID_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == fmmManual) {
|
||||||
|
// Build the volume map when absent: filaments on a single-volume extruder
|
||||||
|
// print with that extruder's volume; a mixed-volume extruder keeps the
|
||||||
|
// per-filament choice (default Standard).
|
||||||
|
std::vector<NozzleVolumeType> using_nozzle_volume_type = new_nozzle_volume_type;
|
||||||
|
using_nozzle_volume_type.resize(new_extruder_count, nvtStandard);
|
||||||
|
if (auto extruder_nozzle_stats_opt = m_print_config.option<ConfigOptionStrings>("extruder_nozzle_stats")) {
|
||||||
|
auto nozzle_stats = get_extruder_nozzle_stats(extruder_nozzle_stats_opt->values);
|
||||||
|
for (int e_index = 0; e_index < new_extruder_count && e_index < (int) nozzle_stats.size(); e_index++) {
|
||||||
|
if (nozzle_stats[e_index].size() > 1) {
|
||||||
|
using_nozzle_volume_type[e_index] = nvtHybrid;
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("%1% : extruder %2%, set nozzle_volume_type to hybrid ") % __LINE__ % (e_index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<int> &manual_volume_maps = m_extra_config.option<ConfigOptionInts>("filament_volume_map", true)->values;
|
||||||
|
// default to standard flow
|
||||||
|
manual_volume_maps.resize(filament_count, (int) (nvtStandard));
|
||||||
|
for (int f_index = 0; f_index < filament_count && f_index < (int) filament_maps.size(); f_index++) {
|
||||||
|
int f_extruder_index = filament_maps[f_index] - 1;
|
||||||
|
if (f_extruder_index >= 0 && f_extruder_index < new_extruder_count &&
|
||||||
|
using_nozzle_volume_type[f_extruder_index] != nvtHybrid) {
|
||||||
|
manual_volume_maps[f_index] = int(using_nozzle_volume_type[f_extruder_index]);
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("%1% : filament %2% extruder %3%, set filament_volume_map to %4% ") % __LINE__ % (f_index + 1) % (f_extruder_index + 1) % manual_volume_maps[f_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_extra_config.has("filament_volume_map")) {
|
||||||
|
part_plate->set_filament_volume_maps(m_extra_config.option<ConfigOptionInts>("filament_volume_map")->values);
|
||||||
|
}
|
||||||
|
if (m_extra_config.has("filament_nozzle_map")) {
|
||||||
|
part_plate->set_filament_nozzle_maps(m_extra_config.option<ConfigOptionInts>("filament_nozzle_map")->values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!support_multi_nozzle && (mode == fmmNozzleManual)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< boost::format("%1%, Nozzle Manual mode not supported for %2%") % __LINE__ % new_printer_name;
|
||||||
|
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, index + 1, cli_errors[CLI_INVALID_PARAMS], sliced_info);
|
||||||
|
flush_and_exit(CLI_INVALID_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < filament_maps.size(); index++)
|
for (int index = 0; index < filament_maps.size(); index++)
|
||||||
{
|
{
|
||||||
int filament_extruder = filament_maps[index];
|
int filament_extruder = filament_maps[index];
|
||||||
@@ -6183,6 +6249,22 @@ int CLI::run(int argc, char **argv)
|
|||||||
BOOST_LOG_TRIVIAL(info) << "print::process: first time_using_cache is " << time_using_cache << " secs.";
|
BOOST_LOG_TRIVIAL(info) << "print::process: first time_using_cache is " << time_using_cache << " secs.";
|
||||||
}
|
}
|
||||||
if (printer_technology == ptFFF) {
|
if (printer_technology == ptFFF) {
|
||||||
|
// Read the engine's final grouping back onto the plate so an exported
|
||||||
|
// project (--export-3mf / gcode.3mf) carries the concrete maps in its
|
||||||
|
// plate settings, matching what a GUI slice persists.
|
||||||
|
// Orca: deliberately gated to multi-extruder printers so single-extruder
|
||||||
|
// exports keep their plate settings unchanged.
|
||||||
|
if (new_extruder_count > 1) {
|
||||||
|
FilamentMapMode current_map_mode = print_fff->config().filament_map_mode.value;
|
||||||
|
if (is_auto_filament_map_mode(current_map_mode)) {
|
||||||
|
part_plate->set_filament_maps(print_fff->get_filament_maps());
|
||||||
|
part_plate->set_filament_volume_maps(print_fff->get_filament_volume_maps());
|
||||||
|
}
|
||||||
|
if (current_map_mode != FilamentMapMode::fmmNozzleManual) {
|
||||||
|
part_plate->set_filament_nozzle_maps(print_fff->get_filament_nozzle_maps());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string conflict_result = print_fff->get_conflict_string();
|
std::string conflict_result = print_fff->get_conflict_string();
|
||||||
if (!conflict_result.empty()) {
|
if (!conflict_result.empty()) {
|
||||||
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": found slicing result conflict!"<< std::endl;
|
BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": found slicing result conflict!"<< std::endl;
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ static std::vector<std::string> s_project_options {
|
|||||||
// Per-filament nozzle-volume choice; project-level like filament_map so the per-filament
|
// Per-filament nozzle-volume choice; project-level like filament_map so the per-filament
|
||||||
// slot resolution survives preset switches.
|
// slot resolution survives preset switches.
|
||||||
"filament_volume_map",
|
"filament_volume_map",
|
||||||
|
// Per-filament physical-nozzle choice the grouping engine writes back; project-level so a
|
||||||
|
// saved project round-trips the assignment alongside filament_map/filament_volume_map.
|
||||||
|
"filament_nozzle_map",
|
||||||
// Filament Track Switch device state: whether the switch is installed and ready, and
|
// Filament Track Switch device state: whether the switch is installed and ready, and
|
||||||
// whether dynamic per-nozzle filament mapping is active. Persisted with the project and
|
// whether dynamic per-nozzle filament mapping is active. Persisted with the project and
|
||||||
// restored from a saved 3mf; reset to false on load and set true only by live device sync.
|
// restored from a saved 3mf; reset to false on load and set true only by live device sync.
|
||||||
@@ -2717,6 +2720,9 @@ void PresetBundle::update_selections(AppConfig &config)
|
|||||||
std::vector<int> filament_maps(filament_colors.size(), 1);
|
std::vector<int> filament_maps(filament_colors.size(), 1);
|
||||||
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
||||||
|
|
||||||
|
std::vector<int> filament_nozzle_maps(filament_colors.size(), 0);
|
||||||
|
project_config.option<ConfigOptionInts>("filament_nozzle_map")->values = filament_nozzle_maps;
|
||||||
|
|
||||||
std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
|
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
|
||||||
|
|
||||||
@@ -2864,6 +2870,9 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
|
|||||||
std::vector<int> filament_maps(filament_colors.size(), 1);
|
std::vector<int> filament_maps(filament_colors.size(), 1);
|
||||||
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
|
||||||
|
|
||||||
|
std::vector<int> filament_nozzle_maps(filament_colors.size(), 0);
|
||||||
|
project_config.option<ConfigOptionInts>("filament_nozzle_map")->values = filament_nozzle_maps;
|
||||||
|
|
||||||
std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
|
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
|
||||||
|
|
||||||
@@ -3043,6 +3052,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::vector<std::string> ne
|
|||||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts* filament_nozzle_map = project_config.option<ConfigOptionInts>("filament_nozzle_map");
|
||||||
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
|
|
||||||
filament_color->resize(n);
|
filament_color->resize(n);
|
||||||
@@ -3053,6 +3063,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::vector<std::string> ne
|
|||||||
}
|
}
|
||||||
filament_color_type->resize(n);
|
filament_color_type->resize(n);
|
||||||
filament_map->values.resize(n, 1);
|
filament_map->values.resize(n, 1);
|
||||||
|
filament_nozzle_map->values.resize(n, 0);
|
||||||
filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
|
filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
ams_multi_color_filment.resize(n);
|
ams_multi_color_filment.resize(n);
|
||||||
|
|
||||||
@@ -3081,6 +3092,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||||
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts* filament_nozzle_map = project_config.option<ConfigOptionInts>("filament_nozzle_map");
|
||||||
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
|
|
||||||
filament_color->resize(n);
|
filament_color->resize(n);
|
||||||
@@ -3091,6 +3103,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||||||
}
|
}
|
||||||
filament_color_type->resize(n);
|
filament_color_type->resize(n);
|
||||||
filament_map->values.resize(n, 1);
|
filament_map->values.resize(n, 1);
|
||||||
|
filament_nozzle_map->values.resize(n, 0);
|
||||||
filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
|
filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
ams_multi_color_filment.resize(n);
|
ams_multi_color_filment.resize(n);
|
||||||
|
|
||||||
@@ -3132,12 +3145,16 @@ void PresetBundle::update_num_filaments(unsigned int to_del_flament_id)
|
|||||||
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
|
||||||
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts* filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
|
ConfigOptionInts* filament_nozzle_map = project_config.option<ConfigOptionInts>("filament_nozzle_map");
|
||||||
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
if (filament_color->values.size() > to_del_flament_id) {
|
if (filament_color->values.size() > to_del_flament_id) {
|
||||||
filament_color->values.erase(filament_color->values.begin() + to_del_flament_id);
|
filament_color->values.erase(filament_color->values.begin() + to_del_flament_id);
|
||||||
if (filament_map->values.size() > to_del_flament_id) {
|
if (filament_map->values.size() > to_del_flament_id) {
|
||||||
filament_map->values.erase(filament_map->values.begin() + to_del_flament_id);
|
filament_map->values.erase(filament_map->values.begin() + to_del_flament_id);
|
||||||
}
|
}
|
||||||
|
if (filament_nozzle_map->values.size() > to_del_flament_id) {
|
||||||
|
filament_nozzle_map->values.erase(filament_nozzle_map->values.begin() + to_del_flament_id);
|
||||||
|
}
|
||||||
if (filament_volume_map->values.size() > to_del_flament_id) {
|
if (filament_volume_map->values.size() > to_del_flament_id) {
|
||||||
filament_volume_map->values.erase(filament_volume_map->values.begin() + to_del_flament_id);
|
filament_volume_map->values.erase(filament_volume_map->values.begin() + to_del_flament_id);
|
||||||
}
|
}
|
||||||
@@ -3145,6 +3162,7 @@ void PresetBundle::update_num_filaments(unsigned int to_del_flament_id)
|
|||||||
else {
|
else {
|
||||||
filament_color->values.resize(to_del_flament_id);
|
filament_color->values.resize(to_del_flament_id);
|
||||||
filament_map->values.resize(to_del_flament_id, 1);
|
filament_map->values.resize(to_del_flament_id, 1);
|
||||||
|
filament_nozzle_map->values.resize(to_del_flament_id, 0);
|
||||||
filament_volume_map->values.resize(to_del_flament_id, static_cast<int>(NozzleVolumeType::nvtStandard));
|
filament_volume_map->values.resize(to_del_flament_id, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
#include "DragDropPanel.hpp"
|
#include "DragDropPanel.hpp"
|
||||||
|
#include "GUI_App.hpp"
|
||||||
|
#include "I18N.hpp"
|
||||||
#include "Widgets/Label.hpp"
|
#include "Widgets/Label.hpp"
|
||||||
|
#include "Widgets/StateColor.hpp"
|
||||||
#include <slic3r/GUI/wxExtensions.hpp>
|
#include <slic3r/GUI/wxExtensions.hpp>
|
||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
wxDEFINE_EVENT(wxEVT_DRAG_DROP_COMPLETED, wxCommandEvent);
|
||||||
|
|
||||||
struct CustomData
|
struct CustomData
|
||||||
{
|
{
|
||||||
int filament_id;
|
int filament_id;
|
||||||
@@ -201,7 +206,7 @@ wxDragResult ColorDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def)
|
|||||||
/////////////// ColorDropTarget end ////////////////////////
|
/////////////// ColorDropTarget end ////////////////////////
|
||||||
|
|
||||||
|
|
||||||
DragDropPanel::DragDropPanel(wxWindow *parent, const wxString &label, bool is_auto)
|
DragDropPanel::DragDropPanel(wxWindow *parent, const wxString &label, bool is_auto, bool has_title, bool is_sub)
|
||||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
|
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
|
||||||
, m_is_auto(is_auto)
|
, m_is_auto(is_auto)
|
||||||
{
|
{
|
||||||
@@ -209,22 +214,31 @@ DragDropPanel::DragDropPanel(wxWindow *parent, const wxString &label, bool is_au
|
|||||||
|
|
||||||
m_sizer = new wxBoxSizer(wxVERTICAL);
|
m_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
auto title_panel = new wxPanel(this);
|
if (has_title) {
|
||||||
title_panel->SetBackgroundColour(0xEEEEEE);
|
auto title_panel = new wxPanel(this);
|
||||||
auto title_sizer = new wxBoxSizer(wxHORIZONTAL);
|
title_panel->SetBackgroundColour(is_sub ? wxColour(0xF8F8F8) : wxColour(0xEEEEEE));
|
||||||
title_panel->SetSizer(title_sizer);
|
auto title_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
title_panel->SetSizer(title_sizer);
|
||||||
|
|
||||||
Label* static_text = new Label(this, label);
|
m_title_label = new Label(this, label);
|
||||||
static_text->SetFont(Label::Head_13);
|
m_title_label->SetFont(is_sub ? Label::Body_12 : Label::Head_13);
|
||||||
static_text->SetBackgroundColour(0xEEEEEE);
|
if (is_sub)
|
||||||
|
m_title_label->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#6B6B6B")));
|
||||||
|
m_title_label->SetBackgroundColour(is_sub ? wxColour(0xF8F8F8) : wxColour(0xEEEEEE));
|
||||||
|
|
||||||
title_sizer->Add(static_text, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
title_sizer->Add(m_title_label, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||||
|
|
||||||
m_sizer->Add(title_panel, 0, wxEXPAND);
|
m_sizer->Add(title_panel, 0, wxEXPAND);
|
||||||
m_sizer->AddSpacer(10);
|
m_sizer->AddSpacer(10);
|
||||||
|
}
|
||||||
|
|
||||||
m_grid_item_sizer = new wxGridSizer(0, 6, FromDIP(8), FromDIP(8)); // row = 0, col = 3, 10 10 is space
|
if (is_sub) {
|
||||||
m_sizer->Add(m_grid_item_sizer, 1, wxEXPAND | wxALL, FromDIP(8));
|
m_grid_item_sizer = new wxGridSizer(0, 3, FromDIP(6), FromDIP(6));
|
||||||
|
m_sizer->Add(m_grid_item_sizer, 0, wxEXPAND);
|
||||||
|
} else {
|
||||||
|
m_grid_item_sizer = new wxGridSizer(0, 6, FromDIP(8), FromDIP(8)); // row = 0, col = 3, 10 10 is space
|
||||||
|
m_sizer->Add(m_grid_item_sizer, 1, wxEXPAND | wxALL, FromDIP(8));
|
||||||
|
}
|
||||||
|
|
||||||
// set droptarget
|
// set droptarget
|
||||||
auto drop_target = new ColorDropTarget(this);
|
auto drop_target = new ColorDropTarget(this);
|
||||||
@@ -242,20 +256,35 @@ void DragDropPanel::AddColorBlock(const wxColour &color, const std::string &type
|
|||||||
m_grid_item_sizer->Add(panel, 0);
|
m_grid_item_sizer->Add(panel, 0);
|
||||||
m_filament_blocks.push_back(panel);
|
m_filament_blocks.push_back(panel);
|
||||||
if (update_ui) {
|
if (update_ui) {
|
||||||
m_filament_blocks.front()->Refresh(); // FIX BUG: STUDIO-8467
|
Freeze();
|
||||||
|
|
||||||
|
m_grid_item_sizer->Layout();
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
GetParent()->GetParent()->Layout();
|
GetParent()->GetParent()->Layout();
|
||||||
GetParent()->GetParent()->Fit();
|
GetParent()->GetParent()->Fit();
|
||||||
|
m_filament_blocks.front()->Refresh(); // FIX BUG: STUDIO-8467
|
||||||
|
|
||||||
|
Thaw();
|
||||||
|
NotifyDragDropCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DragDropPanel::RemoveColorBlock(ColorPanel *panel, bool update_ui)
|
void DragDropPanel::RemoveColorBlock(ColorPanel *panel, bool update_ui)
|
||||||
{
|
{
|
||||||
m_sizer->Detach(panel);
|
m_grid_item_sizer->Detach(panel);
|
||||||
panel->Destroy();
|
panel->Destroy();
|
||||||
m_filament_blocks.erase(std::remove(m_filament_blocks.begin(), m_filament_blocks.end(), panel), m_filament_blocks.end());
|
m_filament_blocks.erase(std::remove(m_filament_blocks.begin(), m_filament_blocks.end(), panel), m_filament_blocks.end());
|
||||||
if (update_ui) {
|
if (update_ui) {
|
||||||
|
Freeze();
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
GetParent()->GetParent()->Layout();
|
GetParent()->GetParent()->Layout();
|
||||||
GetParent()->GetParent()->Fit();
|
GetParent()->GetParent()->Fit();
|
||||||
|
|
||||||
|
Thaw();
|
||||||
|
NotifyDragDropCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +299,15 @@ void DragDropPanel::DoDragDrop(ColorPanel *panel, const wxColour &color, const s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DragDropPanel::UpdateLabel(const wxString &label)
|
||||||
|
{
|
||||||
|
if (m_title_label) {
|
||||||
|
m_title_label->SetLabel(label);
|
||||||
|
m_title_label->Refresh();
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> DragDropPanel::GetAllFilaments() const
|
std::vector<int> DragDropPanel::GetAllFilaments() const
|
||||||
{
|
{
|
||||||
std::vector<int> filaments;
|
std::vector<int> filaments;
|
||||||
@@ -287,4 +325,327 @@ std::vector<int> DragDropPanel::GetAllFilaments() const
|
|||||||
return filaments;
|
return filaments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DragDropPanel::NotifyDragDropCompleted()
|
||||||
|
{
|
||||||
|
wxCommandEvent event(wxEVT_DRAG_DROP_COMPLETED);
|
||||||
|
event.SetEventObject(this);
|
||||||
|
|
||||||
|
wxWindow *parent = GetParent();
|
||||||
|
while (parent) {
|
||||||
|
auto name = parent->GetName();
|
||||||
|
if (name == wxT("FilamentMapManualPanel")) {
|
||||||
|
parent->GetEventHandler()->ProcessEvent(event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = parent->GetParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SeparatedColorDropTarget : public wxDropTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SeparatedColorDropTarget(SeparatedDragDropPanel *panel) : wxDropTarget(), m_panel(panel)
|
||||||
|
{
|
||||||
|
m_data = new ColorDataObject();
|
||||||
|
SetDataObject(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) override;
|
||||||
|
virtual bool OnDrop(wxCoord x, wxCoord y) override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SeparatedDragDropPanel *m_panel;
|
||||||
|
ColorDataObject *m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
wxDragResult SeparatedColorDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def)
|
||||||
|
{
|
||||||
|
if (!GetData()) return wxDragNone;
|
||||||
|
|
||||||
|
m_panel->AddColorBlock(m_data->GetColor(), m_data->GetType(), m_data->GetFilament(), false);
|
||||||
|
return wxDragCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
SeparatedDragDropPanel::SeparatedDragDropPanel(wxWindow *parent, const wxString &label, bool use_separation) : wxPanel(parent), m_use_separation(use_separation)
|
||||||
|
{
|
||||||
|
SetBackgroundColour(0xF8F8F8);
|
||||||
|
|
||||||
|
m_main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
auto title_panel = new wxPanel(this);
|
||||||
|
title_panel->SetBackgroundColour(0xEEEEEE);
|
||||||
|
auto title_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
title_panel->SetSizer(title_sizer);
|
||||||
|
|
||||||
|
m_label = new Label(title_panel, label);
|
||||||
|
m_label->SetFont(Label::Head_13);
|
||||||
|
m_label->SetBackgroundColour(0xEEEEEE);
|
||||||
|
|
||||||
|
title_sizer->Add(m_label, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||||
|
|
||||||
|
m_main_sizer->Add(title_panel, 0, wxEXPAND);
|
||||||
|
m_main_sizer->AddSpacer(10);
|
||||||
|
|
||||||
|
m_content_panel = new wxPanel(this);
|
||||||
|
m_content_panel->SetBackgroundColour(0xF8F8F8);
|
||||||
|
m_content_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
m_content_panel->SetSizer(m_content_sizer);
|
||||||
|
|
||||||
|
m_high_flow_panel = new DragDropPanel(m_content_panel, _L("High Flow"), false, true, true);
|
||||||
|
m_standard_panel = new DragDropPanel(m_content_panel, _L("Standard"), false, true, true);
|
||||||
|
m_unified_panel = new DragDropPanel(m_content_panel, wxEmptyString, false, false);
|
||||||
|
|
||||||
|
m_high_flow_panel->SetBackgroundColour(0xF8F8F8);
|
||||||
|
m_standard_panel->SetBackgroundColour(0xF8F8F8);
|
||||||
|
m_unified_panel->SetBackgroundColour(0xF8F8F8);
|
||||||
|
m_unified_panel->SetMinSize({FromDIP(260), -1});
|
||||||
|
|
||||||
|
m_main_sizer->Add(m_content_panel, 1, wxEXPAND);
|
||||||
|
|
||||||
|
UpdateLayout();
|
||||||
|
|
||||||
|
auto drop_target = new SeparatedColorDropTarget(this);
|
||||||
|
SetDropTarget(drop_target);
|
||||||
|
|
||||||
|
SetSizer(m_main_sizer);
|
||||||
|
Layout();
|
||||||
|
wxGetApp().UpdateDarkUIWin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeparatedDragDropPanel::UpdateLayout()
|
||||||
|
{
|
||||||
|
m_content_sizer->Clear(false);
|
||||||
|
|
||||||
|
if (m_use_separation) {
|
||||||
|
m_unified_panel->Hide();
|
||||||
|
m_high_flow_panel->Show();
|
||||||
|
m_standard_panel->Show();
|
||||||
|
|
||||||
|
wxSize content_size = m_content_panel->GetSize();
|
||||||
|
int panel_width = (content_size.GetWidth() - FromDIP(1) - FromDIP(8)) / 2;
|
||||||
|
if (panel_width > 0) {
|
||||||
|
m_high_flow_panel->SetMinSize(wxSize(panel_width, -1));
|
||||||
|
m_standard_panel->SetMinSize(wxSize(panel_width, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_content_sizer->Add(m_high_flow_panel, 1, wxEXPAND | wxLEFT, FromDIP(8));
|
||||||
|
|
||||||
|
// Create the separator once and re-attach it on relayout; Clear(false) above only
|
||||||
|
// detaches, so allocating here would leak a window per relayout.
|
||||||
|
if (!m_separator) {
|
||||||
|
m_separator = new wxPanel(m_content_panel, wxID_ANY);
|
||||||
|
m_separator->SetBackgroundColour(StateColor::darkModeColorFor(wxColour(0xCE, 0xCE, 0xCE)));
|
||||||
|
m_separator->SetMinSize(wxSize(FromDIP(1), -1));
|
||||||
|
}
|
||||||
|
m_separator->Show();
|
||||||
|
m_content_sizer->Add(m_separator, 0, wxEXPAND | wxALL, FromDIP(4));
|
||||||
|
|
||||||
|
m_content_sizer->Add(m_standard_panel, 1, wxEXPAND | wxRIGHT, FromDIP(8));
|
||||||
|
} else {
|
||||||
|
m_high_flow_panel->Hide();
|
||||||
|
m_standard_panel->Hide();
|
||||||
|
if (m_separator)
|
||||||
|
m_separator->Hide();
|
||||||
|
m_unified_panel->Show();
|
||||||
|
|
||||||
|
m_content_sizer->Add(m_unified_panel, 1, wxEXPAND);
|
||||||
|
}
|
||||||
|
m_content_sizer->Layout();
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
if (GetParent()) {
|
||||||
|
GetParent()->Layout();
|
||||||
|
if (GetParent()->GetParent()) {
|
||||||
|
GetParent()->GetParent()->Layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeparatedDragDropPanel::UpdateLabel(const wxString &label)
|
||||||
|
{
|
||||||
|
if (m_label) {
|
||||||
|
m_label->SetLabel(label);
|
||||||
|
m_label->Refresh();
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeparatedDragDropPanel::SetUseSeparation(bool use_separation)
|
||||||
|
{
|
||||||
|
if (m_use_separation != use_separation) {
|
||||||
|
m_use_separation = use_separation;
|
||||||
|
|
||||||
|
if (use_separation) {
|
||||||
|
auto blocks = m_unified_panel->get_filament_blocks();
|
||||||
|
for (auto &block : blocks) {
|
||||||
|
m_standard_panel->AddColorBlock(block->GetColor(), block->GetType(), block->GetFilamentId(), false);
|
||||||
|
m_unified_panel->RemoveColorBlock(block, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto high_flow_blocks = m_high_flow_panel->get_filament_blocks();
|
||||||
|
auto standard_blocks = m_standard_panel->get_filament_blocks();
|
||||||
|
|
||||||
|
for (auto &block : high_flow_blocks) {
|
||||||
|
m_unified_panel->AddColorBlock(block->GetColor(), block->GetType(), block->GetFilamentId(), false);
|
||||||
|
m_high_flow_panel->RemoveColorBlock(block, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &block : standard_blocks) {
|
||||||
|
m_unified_panel->AddColorBlock(block->GetColor(), block->GetType(), block->GetFilamentId(), false);
|
||||||
|
m_standard_panel->RemoveColorBlock(block, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeparatedDragDropPanel::AddColorBlock(const wxColour &color, const std::string &type, int filament_id, bool is_high_flow, bool update_ui)
|
||||||
|
{
|
||||||
|
if (m_use_separation) {
|
||||||
|
if (is_high_flow) {
|
||||||
|
m_high_flow_panel->AddColorBlock(color, type, filament_id, update_ui);
|
||||||
|
} else {
|
||||||
|
m_standard_panel->AddColorBlock(color, type, filament_id, update_ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_ui) {
|
||||||
|
CallAfter([this]() {
|
||||||
|
Layout();
|
||||||
|
GetParent()->Layout();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_unified_panel->AddColorBlock(color, type, filament_id, update_ui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeparatedDragDropPanel::RemoveColorBlock(ColorPanel *panel, bool update_ui)
|
||||||
|
{
|
||||||
|
auto high_flow_blocks = m_high_flow_panel->get_filament_blocks();
|
||||||
|
auto standard_blocks = m_standard_panel->get_filament_blocks();
|
||||||
|
auto unified_blocks = m_unified_panel->get_filament_blocks();
|
||||||
|
|
||||||
|
if (std::find(high_flow_blocks.begin(), high_flow_blocks.end(), panel) != high_flow_blocks.end()) {
|
||||||
|
m_high_flow_panel->RemoveColorBlock(panel, update_ui);
|
||||||
|
} else if (std::find(standard_blocks.begin(), standard_blocks.end(), panel) != standard_blocks.end()) {
|
||||||
|
m_standard_panel->RemoveColorBlock(panel, update_ui);
|
||||||
|
} else if (std::find(unified_blocks.begin(), unified_blocks.end(), panel) != unified_blocks.end()) {
|
||||||
|
m_unified_panel->RemoveColorBlock(panel, update_ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_ui && m_use_separation) {
|
||||||
|
CallAfter([this]() {
|
||||||
|
Layout();
|
||||||
|
GetParent()->Layout();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> SeparatedDragDropPanel::GetAllFilaments() const
|
||||||
|
{
|
||||||
|
if (m_use_separation) {
|
||||||
|
auto high_flow = m_high_flow_panel->GetAllFilaments();
|
||||||
|
auto standard = m_standard_panel->GetAllFilaments();
|
||||||
|
|
||||||
|
std::vector<int> result;
|
||||||
|
result.insert(result.end(), high_flow.begin(), high_flow.end());
|
||||||
|
result.insert(result.end(), standard.begin(), standard.end());
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return m_unified_panel->GetAllFilaments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> SeparatedDragDropPanel::GetHighFlowFilaments() const
|
||||||
|
{
|
||||||
|
if (m_use_separation) {
|
||||||
|
return m_high_flow_panel->GetAllFilaments();
|
||||||
|
}
|
||||||
|
auto nozzle_volumes = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||||
|
const int right_eid = 1;
|
||||||
|
if (nozzle_volumes->values.size() > right_eid) {
|
||||||
|
int volume_type = nozzle_volumes->values[right_eid];
|
||||||
|
if (volume_type == static_cast<int>(NozzleVolumeType::nvtHighFlow)) {
|
||||||
|
return m_unified_panel->GetAllFilaments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> SeparatedDragDropPanel::GetStandardFilaments() const
|
||||||
|
{
|
||||||
|
if (m_use_separation) {
|
||||||
|
return m_standard_panel->GetAllFilaments();
|
||||||
|
}
|
||||||
|
auto nozzle_volumes = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||||
|
const int right_eid = 1;
|
||||||
|
if (nozzle_volumes->values.size() > right_eid) {
|
||||||
|
int volume_type = nozzle_volumes->values[right_eid];
|
||||||
|
if (volume_type == static_cast<int>(NozzleVolumeType::nvtStandard)) {
|
||||||
|
return m_unified_panel->GetAllFilaments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> SeparatedDragDropPanel::GetTPUHighFlowFilaments() const
|
||||||
|
{
|
||||||
|
if (m_use_separation) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto nozzle_volumes = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||||
|
const int right_eid = 1;
|
||||||
|
if (nozzle_volumes->values.size() > right_eid) {
|
||||||
|
int volume_type = nozzle_volumes->values[right_eid];
|
||||||
|
if (volume_type == static_cast<int>(NozzleVolumeType::nvtTPUHighFlow)) {
|
||||||
|
return m_unified_panel->GetAllFilaments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ColorPanel *> SeparatedDragDropPanel::get_filament_blocks() const
|
||||||
|
{
|
||||||
|
if (m_use_separation) {
|
||||||
|
auto high_flow = m_high_flow_panel->get_filament_blocks();
|
||||||
|
auto standard = m_standard_panel->get_filament_blocks();
|
||||||
|
|
||||||
|
std::vector<ColorPanel *> result;
|
||||||
|
result.insert(result.end(), high_flow.begin(), high_flow.end());
|
||||||
|
result.insert(result.end(), standard.begin(), standard.end());
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return m_unified_panel->get_filament_blocks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ColorPanel *> SeparatedDragDropPanel::get_high_flow_blocks() const
|
||||||
|
{
|
||||||
|
return m_high_flow_panel->get_filament_blocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ColorPanel *> SeparatedDragDropPanel::get_standard_blocks() const
|
||||||
|
{
|
||||||
|
return m_standard_panel->get_filament_blocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SeparatedDragDropPanel::ClearAllBlocks()
|
||||||
|
{
|
||||||
|
auto high_flow_blocks = m_high_flow_panel->get_filament_blocks();
|
||||||
|
for (auto &block : high_flow_blocks) {
|
||||||
|
m_high_flow_panel->RemoveColorBlock(block, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto standard_blocks = m_standard_panel->get_filament_blocks();
|
||||||
|
for (auto &block : standard_blocks) {
|
||||||
|
m_standard_panel->RemoveColorBlock(block, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unified_blocks = m_unified_panel->get_filament_blocks();
|
||||||
|
for (auto &block : unified_blocks) {
|
||||||
|
m_unified_panel->RemoveColorBlock(block, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "GUI.hpp"
|
#include "GUI.hpp"
|
||||||
#include "GUI_Utils.hpp"
|
#include "GUI_Utils.hpp"
|
||||||
|
#include "Widgets/Label.hpp"
|
||||||
|
|
||||||
#include <wx/simplebook.h>
|
#include <wx/simplebook.h>
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
@@ -13,17 +14,20 @@
|
|||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
wxDECLARE_EVENT(wxEVT_DRAG_DROP_COMPLETED, wxCommandEvent);
|
||||||
|
|
||||||
wxColor Hex2Color(const std::string& str);
|
wxColor Hex2Color(const std::string& str);
|
||||||
|
|
||||||
class ColorPanel;
|
class ColorPanel;
|
||||||
class DragDropPanel : public wxPanel
|
class DragDropPanel : public wxPanel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DragDropPanel(wxWindow *parent, const wxString &label, bool is_auto);
|
DragDropPanel(wxWindow *parent, const wxString &label, bool is_auto, bool has_title = true, bool is_sub = false);
|
||||||
|
|
||||||
void AddColorBlock(const wxColour &color, const std::string &type, int filament_id, bool update_ui = true);
|
void AddColorBlock(const wxColour &color, const std::string &type, int filament_id, bool update_ui = true);
|
||||||
void RemoveColorBlock(ColorPanel *panel, bool update_ui = true);
|
void RemoveColorBlock(ColorPanel *panel, bool update_ui = true);
|
||||||
void DoDragDrop(ColorPanel *panel, const wxColour &color, const std::string &type, int filament_id);
|
void DoDragDrop(ColorPanel *panel, const wxColour &color, const std::string &type, int filament_id);
|
||||||
|
void UpdateLabel(const wxString &label);
|
||||||
|
|
||||||
std::vector<int> GetAllFilaments() const;
|
std::vector<int> GetAllFilaments() const;
|
||||||
|
|
||||||
@@ -35,9 +39,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
wxBoxSizer *m_sizer;
|
wxBoxSizer *m_sizer;
|
||||||
wxGridSizer *m_grid_item_sizer;
|
wxGridSizer *m_grid_item_sizer;
|
||||||
|
Label *m_title_label = nullptr;
|
||||||
bool m_is_auto;
|
bool m_is_auto;
|
||||||
|
|
||||||
std::vector<ColorPanel *> m_filament_blocks;
|
std::vector<ColorPanel *> m_filament_blocks;
|
||||||
|
|
||||||
|
void NotifyDragDropCompleted();
|
||||||
private:
|
private:
|
||||||
bool m_is_draging = false;
|
bool m_is_draging = false;
|
||||||
};
|
};
|
||||||
@@ -64,6 +71,49 @@ private:
|
|||||||
int m_filament_id;
|
int m_filament_id;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Drop zone for one extruder that can split into two sub-zones (High Flow / Standard)
|
||||||
|
// when the extruder mixes nozzle volume types (Hybrid flow), and collapses back to a
|
||||||
|
// single unified zone otherwise.
|
||||||
|
class SeparatedDragDropPanel : public wxPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SeparatedDragDropPanel(wxWindow *parent, const wxString &label, bool use_separation = false);
|
||||||
|
|
||||||
|
void AddColorBlock(const wxColour &color, const std::string &type, int filament_id, bool is_high_flow = false, bool update_ui = true);
|
||||||
|
void RemoveColorBlock(ColorPanel *panel, bool update_ui = true);
|
||||||
|
|
||||||
|
std::vector<int> GetAllFilaments() const;
|
||||||
|
std::vector<int> GetHighFlowFilaments() const;
|
||||||
|
std::vector<int> GetStandardFilaments() const;
|
||||||
|
std::vector<int> GetTPUHighFlowFilaments() const;
|
||||||
|
|
||||||
|
std::vector<ColorPanel *> get_filament_blocks() const;
|
||||||
|
std::vector<ColorPanel *> get_high_flow_blocks() const;
|
||||||
|
std::vector<ColorPanel *> get_standard_blocks() const;
|
||||||
|
|
||||||
|
void SetUseSeparation(bool use_separation);
|
||||||
|
bool IsUseSeparation() const { return m_use_separation; }
|
||||||
|
void ClearAllBlocks();
|
||||||
|
void UpdateLabel(const wxString &label);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdateLayout();
|
||||||
|
|
||||||
|
wxBoxSizer *m_main_sizer;
|
||||||
|
wxPanel *m_content_panel;
|
||||||
|
wxBoxSizer *m_content_sizer;
|
||||||
|
wxPanel *m_separator = nullptr;
|
||||||
|
Label *m_label;
|
||||||
|
|
||||||
|
DragDropPanel *m_high_flow_panel;
|
||||||
|
DragDropPanel *m_standard_panel;
|
||||||
|
|
||||||
|
DragDropPanel *m_unified_panel;
|
||||||
|
|
||||||
|
bool m_use_separation;
|
||||||
|
};
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|
||||||
#endif /* slic3r_DragDropPanel_hpp_ */
|
#endif /* slic3r_DragDropPanel_hpp_ */
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ static std::vector<int> get_applied_map(DynamicConfig& proj_config, const Plater
|
|||||||
return plater_ref->get_global_filament_map();
|
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_left_extruder_unprintable_text();
|
||||||
extern std::string& get_right_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;
|
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);
|
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_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_maps.resize(filament_colors.size(), 1);
|
||||||
|
applied_volume_maps.resize(filament_colors.size(), 0);
|
||||||
|
|
||||||
if (!force_pop_up && applied_mode != fmmManual)
|
if (!force_pop_up && applied_mode != fmmManual)
|
||||||
return true;
|
return true;
|
||||||
@@ -141,6 +150,7 @@ bool try_pop_up_before_slice(bool is_slice_all, Plater* plater_ref, PartPlate* p
|
|||||||
filament_colors,
|
filament_colors,
|
||||||
filament_types,
|
filament_types,
|
||||||
applied_maps,
|
applied_maps,
|
||||||
|
applied_volume_maps,
|
||||||
filament_lists,
|
filament_lists,
|
||||||
applied_mode,
|
applied_mode,
|
||||||
plater_ref->get_machine_sync_status(),
|
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) {
|
if (ret == wxID_OK) {
|
||||||
FilamentMapMode new_mode = map_dlg.get_mode();
|
FilamentMapMode new_mode = map_dlg.get_mode();
|
||||||
std::vector<int> new_maps = map_dlg.get_filament_maps();
|
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 (sync_plate) {
|
||||||
if (is_slice_all) {
|
if (is_slice_all) {
|
||||||
auto plate_list = plater_ref->get_partplate_list().get_plate_list();
|
auto plate_list = plater_ref->get_partplate_list().get_plate_list();
|
||||||
for (int i = 0; i < plate_list.size(); ++i) {
|
for (int i = 0; i < plate_list.size(); ++i) {
|
||||||
plate_list[i]->set_filament_map_mode(new_mode);
|
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_maps(new_maps);
|
||||||
|
plate_list[i]->set_filament_volume_maps(new_volume_maps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
partplate_ref->set_filament_map_mode(new_mode);
|
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_maps(new_maps);
|
||||||
|
partplate_ref->set_filament_volume_maps(new_volume_maps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
plater_ref->set_global_filament_map_mode(new_mode);
|
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_map(new_maps);
|
||||||
|
plater_ref->set_global_filament_volume_map(new_volume_maps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
plater_ref->update();
|
plater_ref->update();
|
||||||
// check whether able to slice, if not, return false
|
// 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_color,
|
||||||
const std::vector<std::string> &filament_type,
|
const std::vector<std::string> &filament_type,
|
||||||
const std::vector<int> &filament_map,
|
const std::vector<int> &filament_map,
|
||||||
|
const std::vector<int> &filament_volume_map,
|
||||||
const std::vector<int> &filaments,
|
const std::vector<int> &filaments,
|
||||||
const FilamentMapMode mode,
|
const FilamentMapMode mode,
|
||||||
bool machine_synced,
|
bool machine_synced,
|
||||||
bool show_default,
|
bool show_default,
|
||||||
bool with_checkbox)
|
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);
|
SetBackgroundColour(*wxWHITE);
|
||||||
|
|
||||||
@@ -244,7 +266,20 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
|||||||
mode == fmmAutoForMatch && !auto_match_available ? fmmAutoForFlush :
|
mode == fmmAutoForMatch && !auto_match_available ? fmmAutoForFlush :
|
||||||
mode;
|
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);
|
m_auto_map_panel = new FilamentMapAutoPanel(this, default_auto_mode, auto_match_available);
|
||||||
if (show_default)
|
if (show_default)
|
||||||
m_default_map_panel = new FilamentMapDefaultPanel(this);
|
m_default_map_panel = new FilamentMapDefaultPanel(this);
|
||||||
@@ -351,16 +386,8 @@ void FilamentMapDialog::on_checkbox(wxCommandEvent &event)
|
|||||||
void FilamentMapDialog::on_ok(wxCommandEvent &event)
|
void FilamentMapDialog::on_ok(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
if (m_page_type == PageType::ptManual) {
|
if (m_page_type == PageType::ptManual) {
|
||||||
std::vector<int> left_filaments = m_manual_map_panel->GetLeftFilaments();
|
m_filament_map = m_manual_map_panel->GetFilamentMaps();
|
||||||
std::vector<int> right_filaments = m_manual_map_panel->GetRightFilaments();
|
m_filament_volume_map = m_manual_map_panel->GetFilamentVolumeMaps();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EndModal(wxID_OK);
|
EndModal(wxID_OK);
|
||||||
@@ -398,6 +425,11 @@ void FilamentMapDialog::update_panel_status(PageType page)
|
|||||||
m_auto_map_panel->Show();
|
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)
|
if (m_smart_filament)
|
||||||
m_smart_filament->Show(get_mode() == fmmAutoForFlush);
|
m_smart_filament->Show(get_mode() == fmmAutoForFlush);
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
const std::vector<std::string>& filament_color,
|
const std::vector<std::string>& filament_color,
|
||||||
const std::vector<std::string>& filament_type,
|
const std::vector<std::string>& filament_type,
|
||||||
const std::vector<int> &filament_map,
|
const std::vector<int> &filament_map,
|
||||||
|
const std::vector<int> &filament_volume_map,
|
||||||
const std::vector<int> &filaments,
|
const std::vector<int> &filaments,
|
||||||
const FilamentMapMode mode,
|
const FilamentMapMode mode,
|
||||||
bool machine_synced,
|
bool machine_synced,
|
||||||
@@ -57,6 +58,12 @@ public:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int> get_filament_volume_maps() const {
|
||||||
|
if (m_page_type == PageType::ptManual)
|
||||||
|
return m_filament_volume_map;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int ShowModal();
|
int ShowModal();
|
||||||
void set_modal_btn_labels(const wxString& left_label, const wxString& right_label);
|
void set_modal_btn_labels(const wxString& left_label, const wxString& right_label);
|
||||||
private:
|
private:
|
||||||
@@ -87,6 +94,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<int> m_filament_map;
|
std::vector<int> m_filament_map;
|
||||||
|
std::vector<int> m_filament_volume_map;
|
||||||
std::vector<std::string> m_filament_color;
|
std::vector<std::string> m_filament_color;
|
||||||
std::vector<std::string> m_filament_type;
|
std::vector<std::string> m_filament_type;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "FilamentMapPanel.hpp"
|
#include "FilamentMapPanel.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
|
#include "Plater.hpp"
|
||||||
#include "Widgets/MultiNozzleSync.hpp" // manuallySetNozzleCount producer for extruder_nozzle_stats
|
#include "Widgets/MultiNozzleSync.hpp" // manuallySetNozzleCount producer for extruder_nozzle_stats
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <wx/dcbuffer.h>
|
#include <wx/dcbuffer.h>
|
||||||
@@ -19,28 +20,278 @@ static const wxColour BorderDisableColor = wxColour("#EEEEEE");
|
|||||||
static const wxColour TextNormalBlackColor = wxColour("#262E30");
|
static const wxColour TextNormalBlackColor = wxColour("#262E30");
|
||||||
static const wxColour TextNormalGreyColor = wxColour("#6B6B6B");
|
static const wxColour TextNormalGreyColor = wxColour("#6B6B6B");
|
||||||
static const wxColour TextDisableColor = wxColour("#CECECE");
|
static const wxColour TextDisableColor = wxColour("#CECECE");
|
||||||
|
static const wxColour TextErrorColor = wxColour("#E14747");
|
||||||
|
|
||||||
|
wxDEFINE_EVENT(wxEVT_INVALID_MANUAL_MAP, wxCommandEvent);
|
||||||
|
|
||||||
|
// Orca: whether the edited printer has an extruder that can physically carry several nozzles
|
||||||
|
// (only such extruders track a per-volume-type nozzle inventory worth validating against).
|
||||||
|
static bool printer_has_multi_nozzle_extruder()
|
||||||
|
{
|
||||||
|
auto *max_nozzle_counts_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
|
||||||
|
// Skip nil entries: a nullable-int nil is INT_MAX (> 1) and would otherwise falsely pass the gate.
|
||||||
|
return max_nozzle_counts_opt &&
|
||||||
|
std::any_of(max_nozzle_counts_opt->values.begin(), max_nozzle_counts_opt->values.end(),
|
||||||
|
[](int v) { return v > 1 && v != ConfigOptionIntsNullable::nil_value(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentMapManualPanel::OnTimer(wxTimerEvent &)
|
||||||
|
{
|
||||||
|
bool valid = true;
|
||||||
|
int invalid_eid = -1;
|
||||||
|
NozzleVolumeType invalid_nozzle = NozzleVolumeType::nvtStandard;
|
||||||
|
auto preset_bundle = wxGetApp().preset_bundle;
|
||||||
|
auto proj_config = preset_bundle->project_config;
|
||||||
|
auto nozzle_volume_values = proj_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
|
||||||
|
std::vector<int> filament_map = GetFilamentMaps();
|
||||||
|
std::vector<int> filament_volume_map = GetFilamentVolumeMaps();
|
||||||
|
// Orca: only multi-nozzle extruders carry a meaningful nozzle inventory; validating a plain
|
||||||
|
// dual-extruder printer against it would flag every grouping whenever the stats are stale.
|
||||||
|
if (printer_has_multi_nozzle_extruder()) {
|
||||||
|
for (size_t eid = 0; eid < nozzle_volume_values.size(); ++eid) {
|
||||||
|
NozzleVolumeType extruder_volume_type = NozzleVolumeType(nozzle_volume_values[eid]);
|
||||||
|
bool extruder_used = std::find_if(m_filament_list.begin(), m_filament_list.end(),
|
||||||
|
[&filament_map, eid](int fid) {
|
||||||
|
return fid - 1 < (int) filament_map.size() && (filament_map[fid - 1] - 1) == (int) eid;
|
||||||
|
}) != m_filament_list.end();
|
||||||
|
|
||||||
|
if (!extruder_used) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extruder_volume_type == nvtHybrid) {
|
||||||
|
int standard_count = getExtruderNozzleCount(preset_bundle, eid, NozzleVolumeType::nvtStandard);
|
||||||
|
int highflow_count = getExtruderNozzleCount(preset_bundle, eid, NozzleVolumeType::nvtHighFlow);
|
||||||
|
|
||||||
|
auto has_material_of_type = [this, eid, &filament_map, &filament_volume_map](NozzleVolumeType volume_type) {
|
||||||
|
return std::find_if(m_filament_list.begin(), m_filament_list.end(),
|
||||||
|
[eid, &filament_map, &filament_volume_map, volume_type](int fid) {
|
||||||
|
return fid - 1 < (int) filament_map.size() && (filament_map[fid - 1] - 1) == (int) eid &&
|
||||||
|
fid - 1 < (int) filament_volume_map.size() &&
|
||||||
|
filament_volume_map[fid - 1] == static_cast<int>(volume_type);
|
||||||
|
}) != m_filament_list.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool has_standard = has_material_of_type(NozzleVolumeType::nvtStandard);
|
||||||
|
bool has_highflow = has_material_of_type(NozzleVolumeType::nvtHighFlow);
|
||||||
|
|
||||||
|
if ((has_standard && standard_count == 0) ||
|
||||||
|
(has_highflow && highflow_count == 0)) {
|
||||||
|
valid = false;
|
||||||
|
invalid_eid = eid;
|
||||||
|
invalid_nozzle = (has_standard && standard_count == 0) ? NozzleVolumeType::nvtStandard : NozzleVolumeType::nvtHighFlow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int count = getExtruderNozzleCount(preset_bundle, eid, extruder_volume_type);
|
||||||
|
if (count == 0) {
|
||||||
|
valid = false;
|
||||||
|
invalid_eid = eid;
|
||||||
|
invalid_nozzle = extruder_volume_type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update_ui = m_invalid_id != invalid_eid;
|
||||||
|
bool send_event = update_ui || m_force_validation;
|
||||||
|
|
||||||
|
m_invalid_id = invalid_eid;
|
||||||
|
|
||||||
|
if (update_ui) {
|
||||||
|
if (valid) {
|
||||||
|
m_errors->Hide();
|
||||||
|
m_suggestion_panel->Hide();
|
||||||
|
} else {
|
||||||
|
m_errors->SetLabel(wxString::Format(_L("Error: %s extruder has no available %s nozzle, current group result is invalid."),
|
||||||
|
invalid_eid == 0 ? _L("Left") : _L("Right"),
|
||||||
|
invalid_nozzle == NozzleVolumeType::nvtStandard ? _L("Standard") : _L("High Flow")));
|
||||||
|
// Re-wrap: wrapping only applies to the label text present when Wrap is called,
|
||||||
|
// and the label was empty at construction time.
|
||||||
|
m_errors->Wrap(FromDIP(520));
|
||||||
|
m_errors->Show();
|
||||||
|
m_suggestion_panel->Show();
|
||||||
|
}
|
||||||
|
m_left_panel->Freeze();
|
||||||
|
m_right_panel->Freeze();
|
||||||
|
m_tips->Freeze();
|
||||||
|
m_description->Freeze();
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
this->GetParent()->Layout();
|
||||||
|
this->GetParent()->Fit();
|
||||||
|
m_left_panel->Thaw();
|
||||||
|
m_right_panel->Thaw();
|
||||||
|
m_tips->Thaw();
|
||||||
|
m_description->Thaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_event) {
|
||||||
|
wxCommandEvent event(wxEVT_INVALID_MANUAL_MAP);
|
||||||
|
event.SetInt(valid);
|
||||||
|
ProcessEvent(event);
|
||||||
|
m_force_validation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentMapManualPanel::OnSuggestionClicked(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
wxWindow *current = this;
|
||||||
|
while (current && !wxDynamicCast(current, wxDialog)) {
|
||||||
|
current = current->GetParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
wxDialog *dlg = wxDynamicCast(current, wxDialog);
|
||||||
|
if (dlg) {
|
||||||
|
int invalid_eid = m_invalid_id;
|
||||||
|
dlg->EndModal(wxID_CANCEL);
|
||||||
|
|
||||||
|
if (invalid_eid >= 0) {
|
||||||
|
manuallySetNozzleCount(invalid_eid);
|
||||||
|
}
|
||||||
|
wxGetApp().plater()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> FilamentMapManualPanel::GetFilamentMaps() const
|
||||||
|
{
|
||||||
|
std::vector<int> new_filament_map = m_filament_map;
|
||||||
|
std::vector<int> left_filaments = this->GetLeftFilaments();
|
||||||
|
std::vector<int> right_filaments = this->GetRightFilaments();
|
||||||
|
|
||||||
|
for (int i = 0; i < (int) new_filament_map.size(); ++i) {
|
||||||
|
if (std::find(left_filaments.begin(), left_filaments.end(), i + 1) != left_filaments.end()) {
|
||||||
|
new_filament_map[i] = 1;
|
||||||
|
} else if (std::find(right_filaments.begin(), right_filaments.end(), i + 1) != right_filaments.end()) {
|
||||||
|
new_filament_map[i] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new_filament_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> FilamentMapManualPanel::GetFilamentVolumeMaps() const
|
||||||
|
{
|
||||||
|
std::vector<int> volume_map(m_filament_map.size(), 0);
|
||||||
|
|
||||||
|
std::vector<int> left_filaments = this->GetLeftFilaments();
|
||||||
|
std::vector<int> right_high_flow_filaments = this->GetRightHighFlowFilaments();
|
||||||
|
std::vector<int> right_standard_filaments = this->GetRightStandardFilaments();
|
||||||
|
std::vector<int> right_tpu_high_flow_filaments = this->GetRightTPUHighFlowFilaments();
|
||||||
|
|
||||||
|
auto preset_bundle = wxGetApp().preset_bundle;
|
||||||
|
auto proj_config = preset_bundle->project_config;
|
||||||
|
auto nozzle_volume_values = proj_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int) volume_map.size(); ++i) {
|
||||||
|
int filament_id = i + 1;
|
||||||
|
|
||||||
|
if (std::find(left_filaments.begin(), left_filaments.end(), filament_id) != left_filaments.end()) {
|
||||||
|
if (nozzle_volume_values.size() > 0) {
|
||||||
|
// Orca: never emit the Hybrid marker as a per-filament value; on a Hybrid
|
||||||
|
// extruder each filament prints with a concrete flow, defaulting to Standard.
|
||||||
|
volume_map[i] = nozzle_volume_values[0] == static_cast<int>(NozzleVolumeType::nvtHybrid) ?
|
||||||
|
static_cast<int>(NozzleVolumeType::nvtStandard) :
|
||||||
|
nozzle_volume_values[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (std::find(right_high_flow_filaments.begin(), right_high_flow_filaments.end(), filament_id) != right_high_flow_filaments.end()) {
|
||||||
|
volume_map[i] = static_cast<int>(NozzleVolumeType::nvtHighFlow);
|
||||||
|
}
|
||||||
|
else if (std::find(right_standard_filaments.begin(), right_standard_filaments.end(), filament_id) != right_standard_filaments.end()) {
|
||||||
|
volume_map[i] = static_cast<int>(NozzleVolumeType::nvtStandard);
|
||||||
|
}
|
||||||
|
else if (std::find(right_tpu_high_flow_filaments.begin(), right_tpu_high_flow_filaments.end(), filament_id) != right_tpu_high_flow_filaments.end()) {
|
||||||
|
volume_map[i] = static_cast<int>(NozzleVolumeType::nvtTPUHighFlow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentMapManualPanel::SyncPanelHeights()
|
||||||
|
{
|
||||||
|
if (!m_left_panel || !m_right_panel) return;
|
||||||
|
|
||||||
|
auto curr_left = m_left_panel->GetMinSize();
|
||||||
|
auto curr_right = m_right_panel->GetMinSize();
|
||||||
|
|
||||||
|
m_left_panel->SetMinSize(wxSize(FromDIP(260), FromDIP(110)));
|
||||||
|
m_right_panel->SetMinSize(wxSize(FromDIP(260), FromDIP(110)));
|
||||||
|
|
||||||
|
m_left_panel->Layout();
|
||||||
|
m_left_panel->Fit();
|
||||||
|
m_right_panel->Layout();
|
||||||
|
m_right_panel->Fit();
|
||||||
|
|
||||||
|
wxSize left_best_size = m_left_panel->GetBestSize();
|
||||||
|
wxSize right_best_size = m_right_panel->GetBestSize();
|
||||||
|
|
||||||
|
int max_height = std::max(left_best_size.GetHeight(), right_best_size.GetHeight());
|
||||||
|
bool height_changed = curr_left.GetHeight() != max_height || curr_right.GetHeight() != max_height;
|
||||||
|
if (!height_changed) {
|
||||||
|
if (curr_left.GetHeight() > 0)
|
||||||
|
m_left_panel->SetMinSize(curr_left);
|
||||||
|
if (curr_right.GetHeight() > 0)
|
||||||
|
m_right_panel->SetMinSize(curr_right);
|
||||||
|
if (GetParent()) {
|
||||||
|
GetParent()->Layout();
|
||||||
|
GetParent()->Fit();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_left_panel->SetMinSize(wxSize(FromDIP(260), max_height));
|
||||||
|
m_right_panel->SetMinSize(wxSize(FromDIP(260), max_height));
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
|
||||||
|
if (GetParent()) {
|
||||||
|
GetParent()->Layout();
|
||||||
|
GetParent()->Fit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentMapManualPanel::OnDragDropCompleted(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
SyncPanelHeights();
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *parent,
|
FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *parent,
|
||||||
const std::vector<std::string> &color,
|
const std::vector<std::string> &color,
|
||||||
const std::vector<std::string> &type,
|
const std::vector<std::string> &type,
|
||||||
const std::vector<int> &filament_list,
|
const std::vector<int> &filament_list,
|
||||||
const std::vector<int> &filament_map)
|
const std::vector<int> &filament_map,
|
||||||
: wxPanel(parent), m_filament_map(filament_map), m_filament_color(color), m_filament_type(type), m_filament_list(filament_list)
|
const std::vector<int> &filament_volume_map)
|
||||||
|
: wxPanel(parent)
|
||||||
|
, m_filament_map(filament_map)
|
||||||
|
, m_filament_volume_map(filament_volume_map)
|
||||||
|
, m_filament_list(filament_list)
|
||||||
|
, m_filament_color(color)
|
||||||
|
, m_filament_type(type)
|
||||||
{
|
{
|
||||||
|
SetName(wxT("FilamentMapManualPanel"));
|
||||||
SetBackgroundColour(BgNormalColor);
|
SetBackgroundColour(BgNormalColor);
|
||||||
|
|
||||||
auto top_sizer = new wxBoxSizer(wxVERTICAL);
|
auto top_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
m_description = new Label(this, _L("We will slice according to this grouping method:"));
|
m_description = new Label(this, _L("We will slice according to this grouping method:"));
|
||||||
top_sizer->Add(m_description, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
|
top_sizer->Add(m_description, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
|
||||||
|
m_description->Wrap(FromDIP(520));
|
||||||
top_sizer->AddSpacer(FromDIP(8));
|
top_sizer->AddSpacer(FromDIP(8));
|
||||||
|
|
||||||
auto drag_sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto drag_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
m_left_panel = new DragDropPanel(this, _L("Left Nozzle"), false);
|
m_left_panel = new DragDropPanel(this, _L("Left Nozzle"), false);
|
||||||
m_right_panel = new DragDropPanel(this, _L("Right Nozzle"), false);
|
m_right_panel = new SeparatedDragDropPanel(this, _L("Right Nozzle"), false);
|
||||||
m_switch_btn = new ScalableButton(this, wxID_ANY, "switch_filament_maps");
|
m_switch_btn = new ScalableButton(this, wxID_ANY, "switch_filament_maps");
|
||||||
|
|
||||||
|
UpdateNozzleVolumeType();
|
||||||
|
|
||||||
for (size_t idx = 0; idx < m_filament_map.size(); ++idx) {
|
for (size_t idx = 0; idx < m_filament_map.size(); ++idx) {
|
||||||
auto iter = std::find(m_filament_list.begin(), m_filament_list.end(), idx + 1);
|
auto iter = std::find(m_filament_list.begin(), m_filament_list.end(), idx + 1);
|
||||||
if (iter == m_filament_list.end()) continue;
|
if (iter == m_filament_list.end()) continue;
|
||||||
@@ -50,29 +301,55 @@ FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *p
|
|||||||
m_left_panel->AddColorBlock(color, type, idx + 1);
|
m_left_panel->AddColorBlock(color, type, idx + 1);
|
||||||
} else {
|
} else {
|
||||||
assert(m_filament_map[idx] == 2);
|
assert(m_filament_map[idx] == 2);
|
||||||
m_right_panel->AddColorBlock(color, type, idx + 1);
|
bool is_high_flow = (idx < m_filament_volume_map.size()) && (m_filament_volume_map[idx] == static_cast<int>(NozzleVolumeType::nvtHighFlow));
|
||||||
|
m_right_panel->AddColorBlock(color, type, idx + 1, is_high_flow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_left_panel->SetMinSize({ FromDIP(260),-1 });
|
m_left_panel->SetMinSize({FromDIP(260), FromDIP(110)});
|
||||||
m_right_panel->SetMinSize({ FromDIP(260),-1 });
|
m_right_panel->SetMinSize({FromDIP(260), FromDIP(110)});
|
||||||
|
|
||||||
drag_sizer->AddStretchSpacer();
|
|
||||||
drag_sizer->Add(m_left_panel, 1, wxEXPAND);
|
drag_sizer->Add(m_left_panel, 1, wxEXPAND);
|
||||||
drag_sizer->AddSpacer(FromDIP(7));
|
drag_sizer->Add(m_switch_btn, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(8));
|
||||||
drag_sizer->Add(m_switch_btn, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(1));
|
|
||||||
drag_sizer->AddSpacer(FromDIP(7));
|
|
||||||
drag_sizer->Add(m_right_panel, 1, wxEXPAND);
|
drag_sizer->Add(m_right_panel, 1, wxEXPAND);
|
||||||
drag_sizer->AddStretchSpacer();
|
|
||||||
|
|
||||||
top_sizer->Add(drag_sizer, 0, wxEXPAND);
|
top_sizer->Add(drag_sizer, 0, wxEXPAND);
|
||||||
|
|
||||||
m_tips = new Label(this, _L("Tip: You can drag the filaments to reassign them to different nozzles."));
|
m_tips = new Label(this, _L("Tip: You can drag the filaments to reassign them to different nozzles."));
|
||||||
m_tips->SetFont(Label::Body_14);
|
m_tips->SetFont(Label::Body_14);
|
||||||
m_tips->SetForegroundColour(TextNormalGreyColor);
|
m_tips->SetForegroundColour(TextNormalGreyColor);
|
||||||
|
m_tips->Wrap(FromDIP(520));
|
||||||
top_sizer->AddSpacer(FromDIP(20));
|
top_sizer->AddSpacer(FromDIP(20));
|
||||||
top_sizer->Add(m_tips, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
|
top_sizer->Add(m_tips, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
|
||||||
|
|
||||||
m_switch_btn->Bind(wxEVT_BUTTON, &FilamentMapManualPanel::OnSwitchFilament, this);
|
m_errors = new Label(this, "");
|
||||||
|
m_errors->SetFont(Label::Body_13);
|
||||||
|
m_errors->SetForegroundColour(TextErrorColor);
|
||||||
|
m_errors->Wrap(FromDIP(520));
|
||||||
|
top_sizer->AddSpacer(FromDIP(10));
|
||||||
|
top_sizer->Add(m_errors, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
|
||||||
|
|
||||||
|
m_errors->Hide();
|
||||||
|
|
||||||
|
m_suggestion_panel = new wxPanel(this, wxID_ANY);
|
||||||
|
m_suggestion_panel->SetBackgroundColour(*wxWHITE);
|
||||||
|
auto suggestion_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
auto suggestion_text = new Label(m_suggestion_panel, _L("Please adjust your grouping or click "));
|
||||||
|
suggestion_text->SetFont(Label::Body_13);
|
||||||
|
suggestion_text->SetForegroundColour(TextErrorColor);
|
||||||
|
suggestion_text->SetBackgroundColour(*wxWHITE);
|
||||||
|
auto suggestion_btn = new ScalableButton(m_suggestion_panel, wxID_ANY, "edit", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true, 14);
|
||||||
|
suggestion_btn->SetBackgroundColour(*wxWHITE);
|
||||||
|
auto suggestion_text2 = new Label(m_suggestion_panel, _L(" to set nozzle count"));
|
||||||
|
suggestion_text2->SetFont(Label::Body_13);
|
||||||
|
suggestion_text2->SetForegroundColour(TextErrorColor);
|
||||||
|
suggestion_text2->SetBackgroundColour(*wxWHITE);
|
||||||
|
suggestion_sizer->Add(suggestion_text, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
suggestion_sizer->Add(suggestion_btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
suggestion_sizer->Add(suggestion_text2, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
m_suggestion_panel->SetSizer(suggestion_sizer);
|
||||||
|
top_sizer->Add(m_suggestion_panel, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
|
||||||
|
m_suggestion_panel->Hide();
|
||||||
|
suggestion_btn->Bind(wxEVT_BUTTON, &FilamentMapManualPanel::OnSuggestionClicked, this);
|
||||||
|
|
||||||
// Multi-nozzle: give the user a reachable way to declare, per extruder, how many
|
// Multi-nozzle: give the user a reachable way to declare, per extruder, how many
|
||||||
// physical nozzles of each volume type a multi-nozzle extruder carries. This is the
|
// physical nozzles of each volume type a multi-nozzle extruder carries. This is the
|
||||||
@@ -80,11 +357,8 @@ FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *p
|
|||||||
// auto-sync is deferred). Gated on the edited printer preset having an extruder with
|
// auto-sync is deferred). Gated on the edited printer preset having an extruder with
|
||||||
// extruder_max_nozzle_count > 1, so the trigger is not even created for any single-nozzle or
|
// extruder_max_nozzle_count > 1, so the trigger is not even created for any single-nozzle or
|
||||||
// dual-extruder ({1,1}, H2D) printer - zero UI change for every existing profile.
|
// dual-extruder ({1,1}, H2D) printer - zero UI change for every existing profile.
|
||||||
auto *max_nozzle_counts_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
|
if (printer_has_multi_nozzle_extruder()) {
|
||||||
// Skip nil entries: a nullable-int nil is INT_MAX (> 1) and would otherwise falsely pass the gate.
|
auto *max_nozzle_counts_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
|
||||||
if (max_nozzle_counts_opt &&
|
|
||||||
std::any_of(max_nozzle_counts_opt->values.begin(), max_nozzle_counts_opt->values.end(),
|
|
||||||
[](int v) { return v > 1 && v != ConfigOptionIntsNullable::nil_value(); })) {
|
|
||||||
auto *set_count_link = new Label(this, _L("Set the physical nozzle count..."));
|
auto *set_count_link = new Label(this, _L("Set the physical nozzle count..."));
|
||||||
set_count_link->SetFont(Label::Body_14);
|
set_count_link->SetFont(Label::Body_14);
|
||||||
set_count_link->SetForegroundColour(BorderSelectedColor);
|
set_count_link->SetForegroundColour(BorderSelectedColor);
|
||||||
@@ -94,26 +368,88 @@ FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *p
|
|||||||
const std::vector<int> max_counts = max_nozzle_counts_opt->values;
|
const std::vector<int> max_counts = max_nozzle_counts_opt->values;
|
||||||
set_count_link->Bind(wxEVT_LEFT_DOWN, [max_counts](wxMouseEvent &evt) {
|
set_count_link->Bind(wxEVT_LEFT_DOWN, [max_counts](wxMouseEvent &evt) {
|
||||||
for (int extruder_id = 0; extruder_id < (int) max_counts.size(); ++extruder_id) {
|
for (int extruder_id = 0; extruder_id < (int) max_counts.size(); ++extruder_id) {
|
||||||
if (max_counts[extruder_id] > 1)
|
if (max_counts[extruder_id] > 1 && max_counts[extruder_id] != ConfigOptionIntsNullable::nil_value())
|
||||||
GUI::manuallySetNozzleCount(extruder_id);
|
GUI::manuallySetNozzleCount(extruder_id);
|
||||||
}
|
}
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_timer = new wxTimer(this);
|
||||||
|
Bind(wxEVT_TIMER, &FilamentMapManualPanel::OnTimer, this);
|
||||||
|
Bind(wxEVT_DRAG_DROP_COMPLETED, &FilamentMapManualPanel::OnDragDropCompleted, this);
|
||||||
|
|
||||||
|
m_switch_btn->Bind(wxEVT_BUTTON, &FilamentMapManualPanel::OnSwitchFilament, this);
|
||||||
|
|
||||||
SetSizer(top_sizer);
|
SetSizer(top_sizer);
|
||||||
|
SetMinSize(wxSize(FromDIP(580), -1));
|
||||||
Layout();
|
Layout();
|
||||||
Fit();
|
Fit();
|
||||||
GUI::wxGetApp().UpdateDarkUIWin(this);
|
GUI::wxGetApp().UpdateDarkUIWin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FilamentMapManualPanel::UpdateNozzleVolumeType()
|
||||||
|
{
|
||||||
|
auto check_separation = []() {
|
||||||
|
auto preset_bundle = wxGetApp().preset_bundle;
|
||||||
|
auto nozzle_volume_values = preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
|
||||||
|
if (nozzle_volume_values.size() <= 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return nozzle_volume_values[1] == static_cast<int>(NozzleVolumeType::nvtHybrid);
|
||||||
|
};
|
||||||
|
bool should_separate = check_separation();
|
||||||
|
m_right_panel->SetUseSeparation(should_separate);
|
||||||
|
|
||||||
|
UpdateNozzleCountDisplay();
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentMapManualPanel::UpdateNozzleCountDisplay()
|
||||||
|
{
|
||||||
|
auto preset_bundle = wxGetApp().preset_bundle;
|
||||||
|
|
||||||
|
// Orca: nozzle counts are only tracked (and only meaningful) for multi-nozzle extruders;
|
||||||
|
// plain dual-extruder printers keep their unadorned zone titles.
|
||||||
|
if (!printer_has_multi_nozzle_extruder()) {
|
||||||
|
m_left_panel->UpdateLabel(_L("Left Nozzle"));
|
||||||
|
m_right_panel->UpdateLabel(_L("Right Nozzle"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the count suffix separately so a translation containing '%' cannot
|
||||||
|
// corrupt the wxString::Format output.
|
||||||
|
int left_count = getExtruderNozzleCountTotal(preset_bundle, 0);
|
||||||
|
wxString left_title = _L("Left Nozzle") + wxString::Format("(%d)", left_count);
|
||||||
|
m_left_panel->UpdateLabel(left_title);
|
||||||
|
|
||||||
|
if (m_right_panel->IsUseSeparation()) {
|
||||||
|
int standard_count = getExtruderNozzleCount(preset_bundle, 1, NozzleVolumeType::nvtStandard);
|
||||||
|
int highflow_count = getExtruderNozzleCount(preset_bundle, 1, NozzleVolumeType::nvtHighFlow);
|
||||||
|
wxString right_title = _L("Right Nozzle") + wxString::Format("(Std: %d, HF: %d)", standard_count, highflow_count);
|
||||||
|
m_right_panel->UpdateLabel(right_title);
|
||||||
|
} else {
|
||||||
|
int right_count = getExtruderNozzleCountTotal(preset_bundle, 1);
|
||||||
|
wxString right_title = _L("Right Nozzle") + wxString::Format("(%d)", right_count);
|
||||||
|
m_right_panel->UpdateLabel(right_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilamentMapManualPanel::~FilamentMapManualPanel()
|
||||||
|
{
|
||||||
|
m_timer->Stop();
|
||||||
|
delete m_timer;
|
||||||
|
}
|
||||||
|
|
||||||
void FilamentMapManualPanel::OnSwitchFilament(wxCommandEvent &)
|
void FilamentMapManualPanel::OnSwitchFilament(wxCommandEvent &)
|
||||||
{
|
{
|
||||||
auto left_blocks = m_left_panel->get_filament_blocks();
|
auto left_blocks = m_left_panel->get_filament_blocks();
|
||||||
auto right_blocks = m_right_panel->get_filament_blocks();
|
auto right_blocks = m_right_panel->get_filament_blocks();
|
||||||
|
|
||||||
for (auto &block : left_blocks) {
|
for (auto &block : left_blocks) {
|
||||||
m_right_panel->AddColorBlock(block->GetColor(), block->GetType(), block->GetFilamentId(), false);
|
m_right_panel->AddColorBlock(block->GetColor(), block->GetType(), block->GetFilamentId(), false, false);
|
||||||
m_left_panel->RemoveColorBlock(block, false);
|
m_left_panel->RemoveColorBlock(block, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,22 +459,27 @@ void FilamentMapManualPanel::OnSwitchFilament(wxCommandEvent &)
|
|||||||
}
|
}
|
||||||
this->GetParent()->Layout();
|
this->GetParent()->Layout();
|
||||||
this->GetParent()->Fit();
|
this->GetParent()->Fit();
|
||||||
|
|
||||||
|
if (m_right_panel->IsUseSeparation()) {
|
||||||
|
m_left_panel->Layout();
|
||||||
|
m_left_panel->Fit();
|
||||||
|
m_right_panel->Layout();
|
||||||
|
m_right_panel->Fit();
|
||||||
|
SyncPanelHeights();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentMapManualPanel::Hide()
|
bool FilamentMapManualPanel::Show(bool show)
|
||||||
{
|
{
|
||||||
m_left_panel->Hide();
|
m_force_validation = show;
|
||||||
m_right_panel->Hide();
|
if (show) {
|
||||||
m_switch_btn->Hide();
|
m_timer->Start(500);
|
||||||
wxPanel::Hide();
|
SyncPanelHeights();
|
||||||
}
|
} else {
|
||||||
|
m_timer->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
void FilamentMapManualPanel::Show()
|
return wxPanel::Show(show);
|
||||||
{
|
|
||||||
m_left_panel->Show();
|
|
||||||
m_right_panel->Show();
|
|
||||||
m_switch_btn->Show();
|
|
||||||
wxPanel::Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI::FilamentMapBtnPanel::FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon) : wxPanel(parent)
|
GUI::FilamentMapBtnPanel::FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon) : wxPanel(parent)
|
||||||
|
|||||||
@@ -9,32 +9,60 @@
|
|||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
// Fired by the manual panel's validation timer: the event int is 1 when the current manual
|
||||||
|
// grouping is printable with the installed nozzles, 0 when some zone has no matching nozzle.
|
||||||
|
wxDECLARE_EVENT(wxEVT_INVALID_MANUAL_MAP, wxCommandEvent);
|
||||||
|
|
||||||
class FilamentMapManualPanel : public wxPanel
|
class FilamentMapManualPanel : public wxPanel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FilamentMapManualPanel(wxWindow *parent, const std::vector<std::string> &color, const std::vector<std::string> &type, const std::vector<int> &filament_list, const std::vector<int> &filament_map);
|
FilamentMapManualPanel(wxWindow *parent,
|
||||||
|
const std::vector<std::string> &color,
|
||||||
|
const std::vector<std::string> &type,
|
||||||
|
const std::vector<int> &filament_list,
|
||||||
|
const std::vector<int> &filament_map,
|
||||||
|
const std::vector<int> &filament_volume_map);
|
||||||
|
~FilamentMapManualPanel();
|
||||||
|
|
||||||
std::vector<int> GetFilamentMaps() const { return m_filament_map; }
|
std::vector<int> GetFilamentMaps() const;
|
||||||
|
std::vector<int> GetFilamentVolumeMaps() const;
|
||||||
std::vector<int> GetLeftFilaments() const { return m_left_panel->GetAllFilaments(); }
|
std::vector<int> GetLeftFilaments() const { return m_left_panel->GetAllFilaments(); }
|
||||||
std::vector<int> GetRightFilaments() const { return m_right_panel->GetAllFilaments(); }
|
std::vector<int> GetRightFilaments() const { return m_right_panel->GetAllFilaments(); }
|
||||||
|
|
||||||
void Hide();
|
std::vector<int> GetRightHighFlowFilaments() const { return m_right_panel->GetHighFlowFilaments(); }
|
||||||
void Show();
|
std::vector<int> GetRightStandardFilaments() const { return m_right_panel->GetStandardFilaments(); }
|
||||||
|
std::vector<int> GetRightTPUHighFlowFilaments() const { return m_right_panel->GetTPUHighFlowFilaments(); }
|
||||||
|
void UpdateNozzleVolumeType();
|
||||||
|
void UpdateNozzleCountDisplay();
|
||||||
|
|
||||||
|
bool Show(bool show = true) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnSwitchFilament(wxCommandEvent &);
|
void OnTimer(wxTimerEvent &evt);
|
||||||
DragDropPanel *m_left_panel;
|
void OnSwitchFilament(wxCommandEvent &);
|
||||||
DragDropPanel *m_right_panel;
|
void SyncPanelHeights();
|
||||||
|
void OnDragDropCompleted(wxCommandEvent &evt);
|
||||||
|
void OnSuggestionClicked(wxCommandEvent &event);
|
||||||
|
|
||||||
Label *m_description;
|
DragDropPanel *m_left_panel;
|
||||||
Label *m_tips;
|
SeparatedDragDropPanel *m_right_panel;
|
||||||
|
|
||||||
|
Label *m_description;
|
||||||
|
Label *m_tips;
|
||||||
|
Label *m_errors;
|
||||||
|
wxPanel *m_suggestion_panel;
|
||||||
|
|
||||||
ScalableButton *m_switch_btn;
|
ScalableButton *m_switch_btn;
|
||||||
|
|
||||||
std::vector<int> m_filament_map;
|
std::vector<int> m_filament_map;
|
||||||
|
std::vector<int> m_filament_volume_map;
|
||||||
std::vector<int> m_filament_list;
|
std::vector<int> m_filament_list;
|
||||||
std::vector<std::string> m_filament_color;
|
std::vector<std::string> m_filament_color;
|
||||||
std::vector<std::string> m_filament_type;
|
std::vector<std::string> m_filament_type;
|
||||||
|
|
||||||
|
wxTimer *m_timer;
|
||||||
|
int m_invalid_id{-1};
|
||||||
|
bool m_force_validation{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilamentMapBtnPanel : public wxPanel
|
class FilamentMapBtnPanel : public wxPanel
|
||||||
|
|||||||
@@ -3894,6 +3894,16 @@ void PartPlate::set_filament_count(int filament_count)
|
|||||||
std::vector<int>& filament_maps = m_config.option<ConfigOptionInts>("filament_map")->values;
|
std::vector<int>& filament_maps = m_config.option<ConfigOptionInts>("filament_map")->values;
|
||||||
filament_maps.resize(filament_count, 1);
|
filament_maps.resize(filament_count, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_config.has("filament_nozzle_map")) {
|
||||||
|
std::vector<int>& filament_nozzle_map = m_config.option<ConfigOptionInts>("filament_nozzle_map")->values;
|
||||||
|
filament_nozzle_map.resize(filament_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_config.has("filament_volume_map")) {
|
||||||
|
std::vector<int>& filament_volume_map = m_config.option<ConfigOptionInts>("filament_volume_map")->values;
|
||||||
|
filament_volume_map.resize(filament_count, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartPlate::on_filament_added()
|
void PartPlate::on_filament_added()
|
||||||
@@ -3902,6 +3912,27 @@ void PartPlate::on_filament_added()
|
|||||||
std::vector<int>& filament_maps = m_config.option<ConfigOptionInts>("filament_map")->values;
|
std::vector<int>& filament_maps = m_config.option<ConfigOptionInts>("filament_map")->values;
|
||||||
filament_maps.push_back(1);
|
filament_maps.push_back(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_config.has("filament_nozzle_map")) {
|
||||||
|
std::vector<int>& filament_nozzle_map = m_config.option<ConfigOptionInts>("filament_nozzle_map")->values;
|
||||||
|
filament_nozzle_map.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_config.has("filament_volume_map")) {
|
||||||
|
std::vector<int>& filament_volume_map = m_config.option<ConfigOptionInts>("filament_volume_map")->values;
|
||||||
|
// A new filament defaults onto the first extruder, so seed its volume value from
|
||||||
|
// that extruder's flow type.
|
||||||
|
int volume_type = static_cast<int>(NozzleVolumeType::nvtStandard);
|
||||||
|
auto nozzle_volumes = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
|
||||||
|
if (nozzle_volumes && !nozzle_volumes->values.empty())
|
||||||
|
volume_type = nozzle_volumes->values[0];
|
||||||
|
// Orca: never store the Hybrid marker as a per-filament value; on a Hybrid extruder
|
||||||
|
// each filament still prints with a concrete flow, defaulting to Standard.
|
||||||
|
if (volume_type == static_cast<int>(NozzleVolumeType::nvtHybrid))
|
||||||
|
volume_type = static_cast<int>(NozzleVolumeType::nvtStandard);
|
||||||
|
|
||||||
|
filament_volume_map.push_back(volume_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartPlate::on_filament_deleted(int filament_count, int filament_id)
|
void PartPlate::on_filament_deleted(int filament_count, int filament_id)
|
||||||
@@ -3914,6 +3945,19 @@ void PartPlate::on_filament_deleted(int filament_count, int filament_id)
|
|||||||
if (filament_id >= 0 && filament_id < (int) filament_maps.size())
|
if (filament_id >= 0 && filament_id < (int) filament_maps.size())
|
||||||
filament_maps.erase(filament_maps.begin() + filament_id);
|
filament_maps.erase(filament_maps.begin() + filament_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_config.has("filament_nozzle_map")) {
|
||||||
|
std::vector<int>& filament_nozzle_map = m_config.option<ConfigOptionInts>("filament_nozzle_map")->values;
|
||||||
|
if (filament_id >= 0 && filament_id < (int) filament_nozzle_map.size())
|
||||||
|
filament_nozzle_map.erase(filament_nozzle_map.begin() + filament_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_config.has("filament_volume_map")) {
|
||||||
|
std::vector<int>& filament_volume_map = m_config.option<ConfigOptionInts>("filament_volume_map")->values;
|
||||||
|
if (filament_id >= 0 && filament_id < (int) filament_volume_map.size())
|
||||||
|
filament_volume_map.erase(filament_volume_map.begin() + filament_id);
|
||||||
|
}
|
||||||
|
|
||||||
update_first_layer_print_sequence_when_delete_filament(filament_id);
|
update_first_layer_print_sequence_when_delete_filament(filament_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1213,9 +1213,16 @@ ExtruderGroup::ExtruderGroup(wxWindow * parent, int index, wxString const &title
|
|||||||
combo_flow->GetDropDown().SetUseContentWidth(true);
|
combo_flow->GetDropDown().SetUseContentWidth(true);
|
||||||
combo_flow->Bind(wxEVT_COMBOBOX, [this, index, combo_flow](wxCommandEvent &evt) {
|
combo_flow->Bind(wxEVT_COMBOBOX, [this, index, combo_flow](wxCommandEvent &evt) {
|
||||||
auto printer_tab = dynamic_cast<TabPrinter *>(wxGetApp().get_tab(Preset::TYPE_PRINTER));
|
auto printer_tab = dynamic_cast<TabPrinter *>(wxGetApp().get_tab(Preset::TYPE_PRINTER));
|
||||||
printer_tab->set_extruder_volume_type(index, NozzleVolumeType(intptr_t(combo_flow->GetClientData(evt.GetInt()))));
|
NozzleVolumeType volume_type = NozzleVolumeType(intptr_t(combo_flow->GetClientData(evt.GetInt())));
|
||||||
if (GUI::wxGetApp().plater())
|
printer_tab->set_extruder_volume_type(index, volume_type);
|
||||||
GUI::wxGetApp().plater()->update_machine_sync_status();
|
auto plater = GUI::wxGetApp().plater();
|
||||||
|
if (plater) {
|
||||||
|
// A new Flow type invalidates the per-filament volume choices stored on the
|
||||||
|
// plates for this extruder; rewrite them so the next apply/grouping sees the
|
||||||
|
// selected volume instead of a stale one.
|
||||||
|
plater->update_filament_volume_map(index, static_cast<int>(volume_type));
|
||||||
|
plater->update_machine_sync_status();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this->combo_flow = combo_flow;
|
this->combo_flow = combo_flow;
|
||||||
|
|
||||||
@@ -7328,6 +7335,16 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||||||
filament_map->values.resize(filament_count, 1);
|
filament_map->values.resize(filament_count, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigOptionInts* filament_nozzle_map = proj_cfg.opt<ConfigOptionInts>("filament_nozzle_map", true);
|
||||||
|
if (filament_nozzle_map->size() != filament_count) {
|
||||||
|
filament_nozzle_map->values.resize(filament_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigOptionInts* filament_volume_map = proj_cfg.opt<ConfigOptionInts>("filament_volume_map", true);
|
||||||
|
if (filament_volume_map->size() != filament_count) {
|
||||||
|
filament_volume_map->values.resize(filament_count, static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
|
}
|
||||||
|
|
||||||
// Sync filament multi colour
|
// Sync filament multi colour
|
||||||
ConfigOptionStrings* filament_multi_color = proj_cfg.opt<ConfigOptionStrings>("filament_multi_colour", true);
|
ConfigOptionStrings* filament_multi_color = proj_cfg.opt<ConfigOptionStrings>("filament_multi_colour", true);
|
||||||
if (filament_multi_color->size() != filament_count) {
|
if (filament_multi_color->size() != filament_count) {
|
||||||
@@ -17799,12 +17816,24 @@ void Plater::set_global_filament_map(const std::vector<int>& filament_map)
|
|||||||
project_config.option<ConfigOptionInts>("filament_map")->values = filament_map;
|
project_config.option<ConfigOptionInts>("filament_map")->values = filament_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::set_global_filament_volume_map(const std::vector<int>& filament_volume_map)
|
||||||
|
{
|
||||||
|
auto& project_config = wxGetApp().preset_bundle->project_config;
|
||||||
|
project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_map;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> Plater::get_global_filament_map() const
|
std::vector<int> Plater::get_global_filament_map() const
|
||||||
{
|
{
|
||||||
auto& project_config = wxGetApp().preset_bundle->project_config;
|
auto& project_config = wxGetApp().preset_bundle->project_config;
|
||||||
return project_config.option<ConfigOptionInts>("filament_map")->values;
|
return project_config.option<ConfigOptionInts>("filament_map")->values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int> Plater::get_global_filament_volume_map() const
|
||||||
|
{
|
||||||
|
auto& project_config = wxGetApp().preset_bundle->project_config;
|
||||||
|
return project_config.option<ConfigOptionInts>("filament_volume_map")->values;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FilamentMapMode Plater::get_global_filament_map_mode() const
|
FilamentMapMode Plater::get_global_filament_map_mode() const
|
||||||
{
|
{
|
||||||
@@ -18721,13 +18750,17 @@ void Plater::open_filament_map_setting_dialog(wxCommandEvent &evt)
|
|||||||
|
|
||||||
auto plate_filament_maps = curr_plate->get_real_filament_maps(project_config);
|
auto plate_filament_maps = curr_plate->get_real_filament_maps(project_config);
|
||||||
auto plate_filament_map_mode = curr_plate->get_filament_map_mode();
|
auto plate_filament_map_mode = curr_plate->get_filament_map_mode();
|
||||||
|
auto plate_filament_volume_maps = curr_plate->get_real_filament_volume_maps(project_config);
|
||||||
if (plate_filament_maps.size() != filament_colors.size()) // refine it later, save filament map to app config
|
if (plate_filament_maps.size() != filament_colors.size()) // refine it later, save filament map to app config
|
||||||
plate_filament_maps.resize(filament_colors.size(), 1);
|
plate_filament_maps.resize(filament_colors.size(), 1);
|
||||||
|
if (plate_filament_volume_maps.size() != filament_colors.size())
|
||||||
|
plate_filament_volume_maps.resize(filament_colors.size(), 0);
|
||||||
|
|
||||||
FilamentMapDialog filament_dlg(this,
|
FilamentMapDialog filament_dlg(this,
|
||||||
filament_colors,
|
filament_colors,
|
||||||
filament_types,
|
filament_types,
|
||||||
plate_filament_maps,
|
plate_filament_maps,
|
||||||
|
plate_filament_volume_maps,
|
||||||
curr_plate->get_extruders(true),
|
curr_plate->get_extruders(true),
|
||||||
plate_filament_map_mode,
|
plate_filament_map_mode,
|
||||||
this->get_machine_sync_status(),
|
this->get_machine_sync_status(),
|
||||||
@@ -18741,16 +18774,21 @@ void Plater::open_filament_map_setting_dialog(wxCommandEvent &evt)
|
|||||||
FilamentMapMode old_map_mode = curr_plate->get_filament_map_mode();
|
FilamentMapMode old_map_mode = curr_plate->get_filament_map_mode();
|
||||||
FilamentMapMode new_map_mode = filament_dlg.get_mode();
|
FilamentMapMode new_map_mode = filament_dlg.get_mode();
|
||||||
|
|
||||||
|
std::vector<int> new_filament_volume_maps = filament_dlg.get_filament_volume_maps();
|
||||||
|
std::vector<int> old_filament_volume_maps = curr_plate->get_real_filament_volume_maps(project_config);
|
||||||
|
|
||||||
if (new_map_mode != old_map_mode) {
|
if (new_map_mode != old_map_mode) {
|
||||||
curr_plate->set_filament_map_mode(new_map_mode);
|
curr_plate->set_filament_map_mode(new_map_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_map_mode == fmmManual){
|
if (new_map_mode == fmmManual){
|
||||||
curr_plate->set_filament_maps(new_filament_maps);
|
curr_plate->set_filament_maps(new_filament_maps);
|
||||||
|
curr_plate->set_filament_volume_maps(new_filament_volume_maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool need_invalidate = (old_map_mode != new_map_mode ||
|
bool need_invalidate = (old_map_mode != new_map_mode ||
|
||||||
old_filament_maps != new_filament_maps);
|
old_filament_maps != new_filament_maps ||
|
||||||
|
old_filament_volume_maps != new_filament_volume_maps);
|
||||||
|
|
||||||
if (need_invalidate) {
|
if (need_invalidate) {
|
||||||
if (need_slice) {
|
if (need_slice) {
|
||||||
@@ -19216,6 +19254,30 @@ bool Plater::get_machine_sync_status()
|
|||||||
return p->get_machine_sync_status();
|
return p->get_machine_sync_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::update_filament_volume_map(int extruder_id, int volume_type)
|
||||||
|
{
|
||||||
|
// Hybrid is a per-extruder mix, not a per-filament volume; reset the affected filaments
|
||||||
|
// to Standard so the manual grouping dialog starts from a concrete assignment.
|
||||||
|
int selected_volume_type = volume_type == static_cast<int>(NozzleVolumeType::nvtHybrid) ? static_cast<int>(NozzleVolumeType::nvtStandard) : volume_type;
|
||||||
|
auto& partplate_list = get_partplate_list();
|
||||||
|
for (int idx = 0; idx < partplate_list.get_plate_count(); ++idx) {
|
||||||
|
auto plate = partplate_list.get_plate(idx);
|
||||||
|
if (!plate) continue;
|
||||||
|
auto filament_map = plate->get_filament_maps();
|
||||||
|
auto filament_volume_map = plate->get_filament_volume_maps();
|
||||||
|
if (filament_map.empty() || filament_volume_map.empty()) continue;
|
||||||
|
if (filament_volume_map.size() < filament_map.size()) {
|
||||||
|
filament_volume_map.resize(filament_map.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < filament_map.size(); ++i) {
|
||||||
|
if (filament_map[i] == extruder_id + 1) {
|
||||||
|
filament_volume_map[i] = selected_volume_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plate->set_filament_volume_maps(filament_volume_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if ENABLE_ENVIRONMENT_MAP
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
void Plater::init_environment_texture()
|
void Plater::init_environment_texture()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -586,7 +586,9 @@ public:
|
|||||||
|
|
||||||
void set_global_filament_map_mode(FilamentMapMode mode);
|
void set_global_filament_map_mode(FilamentMapMode mode);
|
||||||
void set_global_filament_map(const std::vector<int>& filament_map);
|
void set_global_filament_map(const std::vector<int>& filament_map);
|
||||||
|
void set_global_filament_volume_map(const std::vector<int>& filament_volume_map);
|
||||||
std::vector<int> get_global_filament_map() const;
|
std::vector<int> get_global_filament_map() const;
|
||||||
|
std::vector<int> get_global_filament_volume_map() const;
|
||||||
FilamentMapMode get_global_filament_map_mode() const;
|
FilamentMapMode get_global_filament_map_mode() const;
|
||||||
|
|
||||||
void update_menus();
|
void update_menus();
|
||||||
@@ -748,6 +750,11 @@ public:
|
|||||||
|
|
||||||
void update_machine_sync_status();
|
void update_machine_sync_status();
|
||||||
|
|
||||||
|
// Rewrite every plate's per-filament volume choice for the filaments grouped onto this
|
||||||
|
// extruder after its Flow type changed (Hybrid resets them to Standard so the user
|
||||||
|
// re-assigns concrete volumes in the grouping dialog).
|
||||||
|
void update_filament_volume_map(int extruder_id, int volume_type);
|
||||||
|
|
||||||
#if ENABLE_ENVIRONMENT_MAP
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
void init_environment_texture();
|
void init_environment_texture();
|
||||||
unsigned int get_environment_texture_id() const;
|
unsigned int get_environment_texture_id() const;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ static const int RightExtruderIdx = 1;
|
|||||||
// config key (ConfigOptionStrings, one encoded map per extruder) via get_extruder_nozzle_stats /
|
// config key (ConfigOptionStrings, one encoded map per extruder) via get_extruder_nozzle_stats /
|
||||||
// save_extruder_nozzle_stats_to_string. These helpers read and write that config.
|
// save_extruder_nozzle_stats_to_string. These helpers read and write that config.
|
||||||
|
|
||||||
static int extruder_nozzle_count(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType volume_type)
|
int getExtruderNozzleCount(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType volume_type)
|
||||||
{
|
{
|
||||||
if (!preset_bundle)
|
if (!preset_bundle)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -49,7 +49,7 @@ static int extruder_nozzle_count(PresetBundle *preset_bundle, int extruder_id, N
|
|||||||
return it == stats[extruder_id].end() ? 0 : it->second;
|
return it == stats[extruder_id].end() ? 0 : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int extruder_nozzle_count_total(PresetBundle *preset_bundle, int extruder_id)
|
int getExtruderNozzleCountTotal(PresetBundle *preset_bundle, int extruder_id)
|
||||||
{
|
{
|
||||||
if (!preset_bundle)
|
if (!preset_bundle)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -230,8 +230,8 @@ void updateNozzleCountDisplay(PresetBundle *preset_bundle, int extruder_id, Nozz
|
|||||||
|
|
||||||
int display_count = -1; // hides the badge
|
int display_count = -1; // hides the badge
|
||||||
if (support_multi_nozzle)
|
if (support_multi_nozzle)
|
||||||
display_count = volume_type == nvtHybrid ? extruder_nozzle_count_total(preset_bundle, extruder_id)
|
display_count = volume_type == nvtHybrid ? getExtruderNozzleCountTotal(preset_bundle, extruder_id)
|
||||||
: extruder_nozzle_count(preset_bundle, extruder_id, volume_type);
|
: getExtruderNozzleCount(preset_bundle, extruder_id, volume_type);
|
||||||
plater->sidebar().set_extruder_nozzle_count(extruder_id, display_count);
|
plater->sidebar().set_extruder_nozzle_count(extruder_id, display_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +269,7 @@ void onNozzleVolumeTypeSwitch(PresetBundle *preset_bundle, int extruder_id, Nozz
|
|||||||
// Hybrid is a mix, not a type every nozzle shares, so there is nothing to carry over.
|
// Hybrid is a mix, not a type every nozzle shares, so there is nothing to carry over.
|
||||||
if (type == nvtHybrid)
|
if (type == nvtHybrid)
|
||||||
return;
|
return;
|
||||||
const int total = extruder_nozzle_count_total(preset_bundle, extruder_id);
|
const int total = getExtruderNozzleCountTotal(preset_bundle, extruder_id);
|
||||||
setExtruderNozzleCount(preset_bundle, extruder_id, type, total, true);
|
setExtruderNozzleCount(preset_bundle, extruder_id, type, total, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,14 +294,14 @@ void manuallySetNozzleCount(int extruder_id)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volume_type_opt->values[extruder_id]);
|
const NozzleVolumeType volume_type = NozzleVolumeType(nozzle_volume_type_opt->values[extruder_id]);
|
||||||
const int standard_count = extruder_nozzle_count(preset_bundle, extruder_id, nvtStandard);
|
const int standard_count = getExtruderNozzleCount(preset_bundle, extruder_id, nvtStandard);
|
||||||
const int highflow_count = extruder_nozzle_count(preset_bundle, extruder_id, nvtHighFlow);
|
const int highflow_count = getExtruderNozzleCount(preset_bundle, extruder_id, nvtHighFlow);
|
||||||
|
|
||||||
// Require at least one nozzle for a Hybrid extruder (an empty mix is meaningless) and when the other
|
// Require at least one nozzle for a Hybrid extruder (an empty mix is meaningless) and when the other
|
||||||
// extruder currently has none.
|
// extruder currently has none.
|
||||||
bool force_no_zero = volume_type == nvtHybrid;
|
bool force_no_zero = volume_type == nvtHybrid;
|
||||||
if (nozzle_volume_type_opt->values.size() > 1)
|
if (nozzle_volume_type_opt->values.size() > 1)
|
||||||
force_no_zero |= extruder_nozzle_count_total(preset_bundle, 1 - extruder_id) == 0;
|
force_no_zero |= getExtruderNozzleCountTotal(preset_bundle, 1 - extruder_id) == 0;
|
||||||
|
|
||||||
ManualNozzleCountDialog dialog(wxGetApp().plater(), volume_type, standard_count, highflow_count, max_nozzle_count->values[extruder_id], force_no_zero);
|
ManualNozzleCountDialog dialog(wxGetApp().plater(), volume_type, standard_count, highflow_count, max_nozzle_count->values[extruder_id], force_no_zero);
|
||||||
if (dialog.ShowModal() == wxID_OK) {
|
if (dialog.ShowModal() == wxID_OK) {
|
||||||
|
|||||||
@@ -219,6 +219,11 @@ std::optional<NozzleOption> tryPopUpMultiNozzleDialog(MachineObject* obj);
|
|||||||
// counts are reset first.
|
// counts are reset first.
|
||||||
void setExtruderNozzleCount(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType type, int nozzle_count, bool clear_all);
|
void setExtruderNozzleCount(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType type, int nozzle_count, bool clear_all);
|
||||||
|
|
||||||
|
// Read one extruder's nozzle count for a volume type (or its total) from the edited printer preset's
|
||||||
|
// `extruder_nozzle_stats` config key. Returns 0 when the stats are absent or the extruder is unknown.
|
||||||
|
int getExtruderNozzleCount(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType volume_type);
|
||||||
|
int getExtruderNozzleCountTotal(PresetBundle *preset_bundle, int extruder_id);
|
||||||
|
|
||||||
// Refresh the sidebar nozzle-count badge for one extruder: shows the extruder's physical nozzle count on
|
// Refresh the sidebar nozzle-count badge for one extruder: shows the extruder's physical nozzle count on
|
||||||
// multi-nozzle printers, hides it (count -1) everywhere else.
|
// multi-nozzle printers, hides it (count -1) everywhere else.
|
||||||
void updateNozzleCountDisplay(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType volume_type);
|
void updateNozzleCountDisplay(PresetBundle *preset_bundle, int extruder_id, NozzleVolumeType volume_type);
|
||||||
|
|||||||
Reference in New Issue
Block a user