diff --git a/lib/Slic3r/GCode/PlaceholderParser.pm b/lib/Slic3r/GCode/PlaceholderParser.pm index 9f45dfe9b..d391456b2 100644 --- a/lib/Slic3r/GCode/PlaceholderParser.pm +++ b/lib/Slic3r/GCode/PlaceholderParser.pm @@ -34,7 +34,9 @@ sub apply_config { my ($self, $config) = @_; # options with single value - my @opt_keys = grep !$Slic3r::Config::Options->{$_}{multiline}, @{$config->get_keys}; + my @opt_keys = grep $Slic3r::Config::Options->{$_}{cli} !~ /\@$/, + grep !$Slic3r::Config::Options->{$_}{multiline}, + @{$config->get_keys}; $self->_single_set($_, $config->serialize($_)) for @opt_keys; # options with multiple values diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 4946d5a34..e3b8dbd4a 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -33,6 +33,7 @@ our $PROGRESS_BAR_EVENT : shared = Wx::NewEventType; our $MESSAGE_DIALOG_EVENT : shared = Wx::NewEventType; our $EXPORT_COMPLETED_EVENT : shared = Wx::NewEventType; our $EXPORT_FAILED_EVENT : shared = Wx::NewEventType; +our $PROCESS_COMPLETED_EVENT : shared = Wx::NewEventType; use constant CANVAS_SIZE => [335,335]; use constant FILAMENT_CHOOSERS_SPACING => 3; @@ -218,6 +219,14 @@ sub new { $self->on_export_failed; }); + EVT_COMMAND($self, -1, $PROCESS_COMPLETED_EVENT, sub { + my ($self, $event) = @_; + + Slic3r::debugf "Background processing completed.\n"; + $self->{process_thread}->detach if $self->{process_thread}; + $self->{process_thread} = undef; + }); + $self->{canvas}->update_bed_size; $self->update; @@ -439,6 +448,9 @@ sub objects_loaded { $self->{list}->Update; $self->{list}->Select($obj_idxs->[-1], 1); $self->object_list_changed; + + # TODO: start timer for new export thread + $self->start_background_process; } sub remove { @@ -664,10 +676,60 @@ sub split_object { $self->load_model_objects(@model_objects); } +sub start_background_process { + my ($self) = @_; + + return if !$Slic3r::have_threads; + return if !@{$self->{objects}}; + + if ($self->{process_thread}) { + warn "Can't start new process thread because one is already running\n"; + return; + } + + # It looks like declaring a local $SIG{__WARN__} prevents the ugly + # "Attempt to free unreferenced scalar" warning... + local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); + + # don't start process thread if config is not valid + eval { + # this will throw errors if config is not valid + $self->skeinpanel->config->validate; + $self->{print}->validate; + }; + return if $@; + + # apply extra variables + { + my $extra = $self->skeinpanel->extra_variables; + $self->{print}->placeholder_parser->set($_, $extra->{$_}) for keys %$extra; + } + + # start thread + $self->{process_thread} = threads->create(sub { + $self->{print}->process; + Wx::PostEvent($self, Wx::PlThreadEvent->new(-1, $PROCESS_COMPLETED_EVENT, undef)); + Slic3r::thread_cleanup(); + }); + Slic3r::debugf "Background processing started.\n"; +} + +sub stop_background_process { + my ($self) = @_; + + if ($self->{process_thread}) { + Slic3r::debugf "Killing background process.\n"; + $self->{process_thread}->kill('KILL')->join; + $self->{process_thread} = undef; + } else { + Slic3r::debugf "No background process running.\n"; + } +} + sub export_gcode { my $self = shift; - if ($self->{export_thread}) { + if ($self->{export_gcode_output_file}) { Wx::MessageDialog->new($self, "Another slicing job is currently running.", 'Error', wxOK | wxICON_ERROR)->ShowModal; return; } @@ -912,6 +974,7 @@ sub update { sub on_config_change { my $self = shift; my ($opt_key, $value) = @_; + if ($opt_key eq 'extruders_count' && defined $value) { my $choices = $self->{preset_choosers}{filament}; while (@$choices < $value) { @@ -937,6 +1000,17 @@ sub on_config_change { } $self->update if $opt_key eq 'print_center'; } + + return if !$self->skeinpanel->is_loaded; + # TODO: pause export thread + my $invalidated = $self->{print}->apply_config($self->skeinpanel->config); + if ($invalidated) { + # kill export thread + $self->stop_background_process; + + # TODO: start timer for new export thread + $self->start_background_process; + } } sub list_item_deselected { diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm index 13b532635..e489394a4 100644 --- a/lib/Slic3r/GUI/SkeinPanel.pm +++ b/lib/Slic3r/GUI/SkeinPanel.pm @@ -31,6 +31,7 @@ sub new { my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); $self->{mode} = $params{mode}; $self->{mode} = 'expert' if $self->{mode} !~ /^(?:simple|expert)$/; + $self->{loaded} = 0; $self->{tabpanel} = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL); $self->{tabpanel}->AddPage($self->{plater} = Slic3r::GUI::Plater->new($self->{tabpanel}), "Plater") @@ -81,9 +82,15 @@ sub new { $self->SetSizer($sizer); $self->Layout; + $self->{loaded} = 1; return $self; } +sub is_loaded { + my ($self) = @_; + return $self->{loaded}; +} + sub quick_slice { my $self = shift; my %params = @_; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index c9853a1a4..56664fb54 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -50,10 +50,8 @@ sub apply_config { if (@$print_diff) { $self->config->apply_dynamic($config); - my $res; - $res = $self->invalidate_all_steps - if !$self->invalidate_state_by_config_options($print_diff); - $invalidated = 1 if $res; + $invalidated = 1 + if $self->invalidate_state_by_config_options($print_diff); } # handle changes to object config defaults @@ -74,10 +72,8 @@ sub apply_config { if (@$diff) { $object->config->apply($new); - my $res; - $res = $object->invalidate_all_steps - if !$object->invalidate_state_by_config_options($diff); - $invalidated = 1 if $res; + $invalidated = 1 + if $self->invalidate_state_by_config_options($diff); } } @@ -131,10 +127,8 @@ sub apply_config { if (@$region_config_diff) { $region->config->apply($new); foreach my $o (@{$self->objects}) { - my $res; - $res = $o->invalidate_all_steps - if !$o->invalidate_state_by_config_options($region_config_diff); - $invalidated = 1 if $res; + $invalidated = 1 + if $o->invalidate_state_by_config_options($region_config_diff); } } } diff --git a/xs/src/Print.cpp b/xs/src/Print.cpp index 4afb16278..90d758b6d 100644 --- a/xs/src/Print.cpp +++ b/xs/src/Print.cpp @@ -5,48 +5,39 @@ namespace Slic3r { template bool -PrintState::started(StepClass step) const +PrintState::is_started(StepClass step) const { - return this->_started.find(step) != this->_started.end(); + return this->started.find(step) != this->started.end(); } template bool -PrintState::done(StepClass step) const +PrintState::is_done(StepClass step) const { - return this->_done.find(step) != this->_done.end(); + return this->done.find(step) != this->done.end(); } template void PrintState::set_started(StepClass step) { - this->_started.insert(step); + this->started.insert(step); } template void PrintState::set_done(StepClass step) { - this->_done.insert(step); -} - -template -void -PrintState::invalidate(StepClass step) -{ - this->_started.erase(step); - this->_done.erase(step); + this->done.insert(step); } template bool -PrintState::invalidate_all() +PrintState::invalidate(StepClass step) { - bool empty = this->_started.empty(); - this->_started.clear(); - this->_done.clear(); - return !empty; // return true if we invalidated something + bool invalidated = this->started.erase(step) > 0; + this->done.erase(step); + return invalidated; } template class PrintState; @@ -256,21 +247,23 @@ PrintObject::invalidate_state_by_config_options(const std::vectorinvalidate_all_steps(); } } - for (std::set::const_iterator step = steps.begin(); step != steps.end(); ++step) - this->invalidate_step(*step); + bool invalidated = false; + for (std::set::const_iterator step = steps.begin(); step != steps.end(); ++step) { + if (this->invalidate_step(*step)) invalidated = true; + } - return true; + return invalidated; } -void +bool PrintObject::invalidate_step(PrintObjectStep step) { - this->state.invalidate(step); + bool invalidated = this->state.invalidate(step); // propagate to dependent steps if (step == posPerimeters) { @@ -286,6 +279,21 @@ PrintObject::invalidate_step(PrintObjectStep step) this->invalidate_step(posPerimeters); this->invalidate_step(posSupportMaterial); } + + return invalidated; +} + +bool +PrintObject::invalidate_all_steps() +{ + // make a copy because when invalidating steps the iterators are not working anymore + std::set steps = this->state.started; + + bool invalidated = false; + for (std::set::const_iterator step = steps.begin(); step != steps.end(); ++step) { + if (this->invalidate_step(*step)) invalidated = true; + } + return invalidated; } @@ -403,21 +411,23 @@ Print::invalidate_state_by_config_options(const std::vector } else if (*opt_key == "brim_width") { steps.insert(psBrim); } else { - // for legacy, if we can't handle this option let's signal the caller to invalidate all steps - return false; + // for legacy, if we can't handle this option let's invalidate all steps + return this->invalidate_all_steps(); } } - for (std::set::const_iterator step = steps.begin(); step != steps.end(); ++step) - this->invalidate_step(*step); + bool invalidated = false; + for (std::set::const_iterator step = steps.begin(); step != steps.end(); ++step) { + if (this->invalidate_step(*step)) invalidated = true; + } - return true; + return invalidated; } -void +bool Print::invalidate_step(PrintStep step) { - this->state.invalidate(step); + bool invalidated = this->state.invalidate(step); // propagate to dependent steps if (step == psSkirt) { @@ -428,6 +438,21 @@ Print::invalidate_step(PrintStep step) (*object)->invalidate_step(posSupportMaterial); } } + + return invalidated; +} + +bool +Print::invalidate_all_steps() +{ + // make a copy because when invalidating steps the iterators are not working anymore + std::set steps = this->state.started; + + bool invalidated = false; + for (std::set::const_iterator step = steps.begin(); step != steps.end(); ++step) { + if (this->invalidate_step(*step)) invalidated = true; + } + return invalidated; } diff --git a/xs/src/Print.hpp b/xs/src/Print.hpp index de9fad731..7b1734be9 100644 --- a/xs/src/Print.hpp +++ b/xs/src/Print.hpp @@ -27,16 +27,14 @@ enum PrintObjectStep { template class PrintState { - private: - std::set _started, _done; - public: - bool started(StepType step) const; - bool done(StepType step) const; + std::set started, done; + + bool is_started(StepType step) const; + bool is_done(StepType step) const; void set_started(StepType step); void set_done(StepType step); - void invalidate(StepType step); - bool invalidate_all(); + bool invalidate(StepType step); }; // A PrintRegion object represents a group of volumes to print @@ -108,7 +106,8 @@ class PrintObject // methods for handling state bool invalidate_state_by_config_options(const std::vector &opt_keys); - void invalidate_step(PrintObjectStep step); + bool invalidate_step(PrintObjectStep step); + bool invalidate_all_steps(); private: Print* _print; @@ -155,7 +154,8 @@ class Print // methods for handling state bool invalidate_state_by_config_options(const std::vector &opt_keys); - void invalidate_step(PrintStep step); + bool invalidate_step(PrintStep step); + bool invalidate_all_steps(); private: void clear_regions(); diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 6510cd38e..d246dbfe5 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -86,11 +86,10 @@ _constant() void delete_support_layer(int idx); bool invalidate_state_by_config_options(std::vector opt_keys); - void invalidate_step(PrintObjectStep step); - bool invalidate_all_steps() - %code%{ RETVAL = THIS->state.invalidate_all(); %}; + bool invalidate_step(PrintObjectStep step); + bool invalidate_all_steps(); bool step_done(PrintObjectStep step) - %code%{ RETVAL = THIS->state.done(step); %}; + %code%{ RETVAL = THIS->state.is_done(step); %}; void set_step_done(PrintObjectStep step) %code%{ THIS->state.set_done(step); %}; void set_step_started(PrintObjectStep step) @@ -141,11 +140,10 @@ _constant() %code%{ RETVAL = THIS->regions.size(); %}; bool invalidate_state_by_config_options(std::vector opt_keys); - void invalidate_step(PrintStep step); - bool invalidate_all_steps() - %code%{ RETVAL = THIS->state.invalidate_all(); %}; + bool invalidate_step(PrintStep step); + bool invalidate_all_steps(); bool step_done(PrintStep step) - %code%{ RETVAL = THIS->state.done(step); %}; + %code%{ RETVAL = THIS->state.is_done(step); %}; void set_step_done(PrintStep step) %code%{ THIS->state.set_done(step); %}; void set_step_started(PrintStep step)