diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 572bf2a56..d38629edf 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -408,6 +408,7 @@ sub load_model_objects { $o->add_instance(offset => [ @{$self->{config}->print_center} ]); } + $self->{print}->auto_assign_extruders($o); $self->{print}->add_model_object($o); } diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm index 0665ba3ce..7db156393 100644 --- a/lib/Slic3r/GUI/SkeinPanel.pm +++ b/lib/Slic3r/GUI/SkeinPanel.pm @@ -392,7 +392,7 @@ sub config { $filament_config = $config; next; } - foreach my $opt_key (keys %$config) { + foreach my $opt_key (@{$config->get_keys}) { next unless ref $filament_config->get($opt_key) eq 'ARRAY'; push @{ $filament_config->get($opt_key) }, $config->get($opt_key)->[0]; } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 347f3458f..7643d4721 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -1090,10 +1090,11 @@ sub auto_assign_extruders { my $material = $model_object->model->materials->{ $volume->material_id }; my $config = $material->config; my $extruder_id = $i + 1; - $config->set_ifndef('perimeter_extruder', $extruder_id); - $config->set_ifndef('infill_extruder', $extruder_id); - $config->set_ifndef('support_material_extruder', $extruder_id); - $config->set_ifndef('support_material_interface_extruder', $extruder_id); + $config->set_ifndef('extruder', $extruder_id); + #$config->set_ifndef('perimeter_extruder', $extruder_id); + #$config->set_ifndef('infill_extruder', $extruder_id); + #$config->set_ifndef('support_material_extruder', $extruder_id); + #$config->set_ifndef('support_material_interface_extruder', $extruder_id); } } } diff --git a/xs/src/Config.cpp b/xs/src/Config.cpp index 6f59290b7..de99b96ec 100644 --- a/xs/src/Config.cpp +++ b/xs/src/Config.cpp @@ -8,7 +8,7 @@ ConfigBase::has(const t_config_option_key opt_key) { } void -ConfigBase::apply(ConfigBase &other, bool ignore_nonexistent) { +ConfigBase::apply(const ConfigBase &other, bool ignore_nonexistent) { // get list of option keys to apply t_config_option_keys opt_keys; other.keys(&opt_keys); @@ -169,13 +169,6 @@ ConfigBase::set(t_config_option_key opt_key, SV* value) { ConfigOption* opt = this->option(opt_key, true); if (opt == NULL) CONFESS("Trying to set non-existing option"); - ConfigOptionDef* optdef = &(*this->def)[opt_key]; - if (!optdef->shortcut.empty()) { - for (std::vector::iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) - this->set(*it, value); - return; - } - if (ConfigOptionFloat* optv = dynamic_cast(opt)) { optv->value = SvNV(value); } else if (ConfigOptionFloats* optv = dynamic_cast(opt)) { @@ -241,6 +234,11 @@ DynamicConfig::~DynamicConfig () { } } +DynamicConfig::DynamicConfig (const DynamicConfig& other) { + this->def = other.def; + this->apply(other, false); +} + ConfigOption* DynamicConfig::option(const t_config_option_key opt_key, bool create) { if (this->options.count(opt_key) == 0) { @@ -287,8 +285,13 @@ DynamicConfig::option(const t_config_option_key opt_key, bool create) { return this->options[opt_key]; } +const ConfigOption* +DynamicConfig::option(const t_config_option_key opt_key) const { + return const_cast(this)->option(opt_key, false); +} + void -DynamicConfig::keys(t_config_option_keys *keys) { +DynamicConfig::keys(t_config_option_keys *keys) const { for (t_options_map::const_iterator it = this->options.begin(); it != this->options.end(); ++it) keys->push_back(it->first); } @@ -299,11 +302,62 @@ DynamicConfig::erase(const t_config_option_key opt_key) { } void -StaticConfig::keys(t_config_option_keys *keys) { +StaticConfig::keys(t_config_option_keys *keys) const { for (t_optiondef_map::const_iterator it = this->def->begin(); it != this->def->end(); ++it) { - ConfigOption* opt = this->option(it->first); + const ConfigOption* opt = this->option(it->first); if (opt != NULL) keys->push_back(it->first); } } +void +StaticConfig::apply(const DynamicConfig &other, bool ignore_nonexistent) { + // clone the other config so that we can remove shortcut options after applying them + DynamicConfig other_clone = other; + + // get list of option keys to apply + t_config_option_keys opt_keys; + other_clone.keys(&opt_keys); + + // loop through options and apply them + for (t_config_option_keys::const_iterator opt_key = opt_keys.begin(); opt_key != opt_keys.end(); ++opt_key) { + // if this is not a shortcut, skip it + ConfigOptionDef* optdef = &(*this->def)[*opt_key]; + if (optdef->shortcut.empty()) continue; + + // expand the option into other_clone if it does not exist already + for (std::vector::iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) { + if (other_clone.has(*it)) continue; + ConfigOption* my_opt = other_clone.option(*it, true); + + // not the most efficient way, but easier than casting pointers to subclasses + my_opt->deserialize( other_clone.option(*opt_key)->serialize() ); + } + + // remove the shortcut option from other_clone + other_clone.erase(*opt_key); + } + + static_cast(this)->apply(other_clone, ignore_nonexistent); +} + +const ConfigOption* +StaticConfig::option(const t_config_option_key opt_key) const +{ + return const_cast(this)->option(opt_key, false); +} + +#ifdef SLIC3RXS +void +StaticConfig::set(t_config_option_key opt_key, SV* value) { + ConfigOptionDef* optdef = &(*this->def)[opt_key]; + if (!optdef->shortcut.empty()) { + for (std::vector::iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) + this->set(*it, value); + return; + } + + static_cast(this)->set(opt_key, value); +} +#endif + } diff --git a/xs/src/Config.hpp b/xs/src/Config.hpp index d5f280f28..226ebe7a9 100644 --- a/xs/src/Config.hpp +++ b/xs/src/Config.hpp @@ -431,8 +431,9 @@ class ConfigBase ConfigBase() : def(NULL) {}; bool has(const t_config_option_key opt_key); virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0; - virtual void keys(t_config_option_keys *keys) = 0; - void apply(ConfigBase &other, bool ignore_nonexistent = false); + virtual const ConfigOption* option(const t_config_option_key opt_key) const = 0; + virtual void keys(t_config_option_keys *keys) const = 0; + void apply(const ConfigBase &other, bool ignore_nonexistent = false); std::string serialize(const t_config_option_key opt_key); void set_deserialize(const t_config_option_key opt_key, std::string str); double get_abs_value(const t_config_option_key opt_key); @@ -450,13 +451,14 @@ class DynamicConfig : public ConfigBase { public: DynamicConfig() {}; + DynamicConfig(const DynamicConfig& other); ~DynamicConfig(); ConfigOption* option(const t_config_option_key opt_key, bool create = false); - void keys(t_config_option_keys *keys); + const ConfigOption* option(const t_config_option_key opt_key) const; + void keys(t_config_option_keys *keys) const; void erase(const t_config_option_key opt_key); private: - DynamicConfig(const DynamicConfig& other); // we disable this by making it private and unimplemented DynamicConfig& operator= (const DynamicConfig& other); // we disable this by making it private and unimplemented typedef std::map t_options_map; t_options_map options; @@ -465,7 +467,18 @@ class DynamicConfig : public ConfigBase class StaticConfig : public ConfigBase { public: - void keys(t_config_option_keys *keys); + void keys(t_config_option_keys *keys) const; + void apply(const ConfigBase &other, bool ignore_nonexistent = false) { + // this proxy appears to be needed otherwise the inherited signature couldn't be found from .xsp + ConfigBase::apply(other, ignore_nonexistent); + }; + void apply(const DynamicConfig &other, bool ignore_nonexistent = false); + virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0; + const ConfigOption* option(const t_config_option_key opt_key) const; + + #ifdef SLIC3RXS + void set(t_config_option_key opt_key, SV* value); + #endif }; } diff --git a/xs/src/PrintConfig.hpp b/xs/src/PrintConfig.hpp index 096c7c7da..6ef881b86 100644 --- a/xs/src/PrintConfig.hpp +++ b/xs/src/PrintConfig.hpp @@ -172,10 +172,11 @@ class PrintConfigDef Options["extra_perimeters"].cli = "extra-perimeters!"; Options["extruder"].type = coInt; - Options["extruder"].label = "Extruder"; + Options["extruder"].label = "Default extruder"; Options["extruder"].cli = "extruder=i"; - Options["extruder"].shortcut.push_back("perimeter_extruder"); + Options["extruder"].min = 1; Options["extruder"].shortcut.push_back("infill_extruder"); + Options["extruder"].shortcut.push_back("perimeter_extruder"); Options["extruder"].shortcut.push_back("support_material_extruder"); Options["extruder"].shortcut.push_back("support_material_interface_extruder"); @@ -397,6 +398,7 @@ class PrintConfigDef Options["infill_extruder"].category = "Extruders"; Options["infill_extruder"].tooltip = "The extruder to use when printing infill."; Options["infill_extruder"].cli = "infill-extruder=i"; + Options["infill_extruder"].min = 1; Options["infill_extrusion_width"].type = coFloatOrPercent; Options["infill_extrusion_width"].label = "Infill"; @@ -515,6 +517,7 @@ class PrintConfigDef Options["perimeter_extruder"].tooltip = "The extruder to use when printing perimeters."; Options["perimeter_extruder"].cli = "perimeter-extruder=i"; Options["perimeter_extruder"].aliases.push_back("perimeters_extruder"); + Options["perimeter_extruder"].min = 1; Options["perimeter_extrusion_width"].type = coFloatOrPercent; Options["perimeter_extrusion_width"].label = "Perimeters"; @@ -762,6 +765,7 @@ class PrintConfigDef Options["support_material_extruder"].category = "Extruders"; Options["support_material_extruder"].tooltip = "The extruder to use when printing support material. This affects brim and raft too."; Options["support_material_extruder"].cli = "support-material-extruder=i"; + Options["support_material_extruder"].min = 1; Options["support_material_extrusion_width"].type = coFloatOrPercent; Options["support_material_extrusion_width"].label = "Support material"; @@ -775,6 +779,7 @@ class PrintConfigDef Options["support_material_interface_extruder"].category = "Extruders"; Options["support_material_interface_extruder"].tooltip = "The extruder to use when printing support material interface. This affects raft too."; Options["support_material_interface_extruder"].cli = "support-material-interface-extruder=i"; + Options["support_material_interface_extruder"].min = 1; Options["support_material_interface_layers"].type = coInt; Options["support_material_interface_layers"].label = "Interface layers"; diff --git a/xs/t/15_config.t b/xs/t/15_config.t index f2df960da..c281e2225 100644 --- a/xs/t/15_config.t +++ b/xs/t/15_config.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 91; +use Test::More tests => 94; foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) { $config->set('layer_height', 0.3); @@ -97,8 +97,6 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) { { my $config = Slic3r::Config->new; $config->set('perimeters', 2); - $config->set('solid_layers', 2); - is $config->get('top_solid_layers'), 2, 'shortcut'; # test that no crash happens when using set_deserialize() with a key that hasn't been set() yet $config->set_deserialize('filament_diameter', '3'); @@ -128,4 +126,22 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) { is $config->get('fill_pattern'), 'line', 'no interferences between DynamicConfig objects'; } +{ + my $config = Slic3r::Config->new; + $config->set('extruder', 2); + is $config->get('extruder'), 2, 'shortcut option value is kept in dynamic config'; + ok !$config->has('perimeter_extruder'), 'shortcut is not expanded in dynamic config'; + + { + my $config2 = Slic3r::Config::Full->new; + $config2->set('extruder', 2); + is $config2->get('perimeter_extruder'), 2, 'shortcut is expanded in static config (set)'; + } + { + my $config3 = Slic3r::Config::Full->new; + $config3->apply_dynamic($config); + is $config3->get('perimeter_extruder'), 2, 'shortcut is expanded in static config (apply)'; + } +} + __END__