mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Work in progress: Good bye, Perl Threads!
This commit is contained in:
		
							parent
							
								
									86b79f89ad
								
							
						
					
					
						commit
						e931f75010
					
				
					 31 changed files with 833 additions and 1069 deletions
				
			
		|  | @ -101,12 +101,6 @@ use constant GIMBALL_LOCK_THETA_MAX => 170; | |||
| use constant VARIABLE_LAYER_THICKNESS_BAR_WIDTH => 70; | ||||
| use constant VARIABLE_LAYER_THICKNESS_RESET_BUTTON_HEIGHT => 22; | ||||
| 
 | ||||
| # make OpenGL::Array thread-safe | ||||
| { | ||||
|     no warnings 'redefine'; | ||||
|     *OpenGL::Array::CLONE_SKIP = sub { 1 }; | ||||
| } | ||||
| 
 | ||||
| sub new { | ||||
|     my ($class, $parent) = @_; | ||||
|      | ||||
|  |  | |||
|  | @ -25,6 +25,10 @@ our $last_config; | |||
| our $VALUE_CHANGE_EVENT    = Wx::NewEventType; | ||||
| # 2) To inform about a preset selection change or a "modified" status change. | ||||
| our $PRESETS_CHANGED_EVENT = Wx::NewEventType; | ||||
| # 3) To update the status bar with the progress information. | ||||
| our $PROGRESS_BAR_EVENT    = Wx::NewEventType; | ||||
| # 4) To display an error dialog box from a thread on the UI thread. | ||||
| our $ERROR_EVENT             = Wx::NewEventType; | ||||
| 
 | ||||
| sub new { | ||||
|     my ($class, %params) = @_; | ||||
|  | @ -48,6 +52,11 @@ sub new { | |||
|     $self->{lang_ch_event} = $params{lang_ch_event}; | ||||
|     $self->{preferences_event} = $params{preferences_event}; | ||||
| 
 | ||||
|     # initialize status bar | ||||
|     $self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, -1); | ||||
|     $self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases")); | ||||
|     $self->SetStatusBar($self->{statusbar}); | ||||
| 
 | ||||
|     # initialize tabpanel and menubar | ||||
|     $self->_init_tabpanel; | ||||
|     $self->_init_menubar; | ||||
|  | @ -56,12 +65,7 @@ sub new { | |||
|     # SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values | ||||
|     # (SetAutoPop is not available on GTK.) | ||||
|     eval { Wx::ToolTip::SetAutoPop(32767) }; | ||||
|      | ||||
|     # initialize status bar | ||||
|     $self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, -1); | ||||
|     $self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases")); | ||||
|     $self->SetStatusBar($self->{statusbar}); | ||||
|      | ||||
|          | ||||
|     $self->{loaded} = 1; | ||||
|      | ||||
|     # initialize layout | ||||
|  | @ -170,6 +174,24 @@ sub _init_tabpanel { | |||
|     for my $tab_name (qw(print filament printer)) { | ||||
|         $self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name"); | ||||
|     } | ||||
| 
 | ||||
|     # Update progress bar with an event sent by the slicing core. | ||||
|     EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub { | ||||
|         my ($self, $event) = @_; | ||||
|         if (defined $self->{progress_dialog}) { | ||||
|             # If a progress dialog is open, update it. | ||||
|             $self->{progress_dialog}->Update($event->GetInt, $event->GetString . "…"); | ||||
|         } else { | ||||
|             # Otherwise update the main window status bar. | ||||
|             $self->{statusbar}->SetProgress($event->GetInt); | ||||
|             $self->{statusbar}->SetStatusText($event->GetString . "…"); | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     EVT_COMMAND($self, -1, $ERROR_EVENT, sub { | ||||
|         my ($self, $event) = @_; | ||||
|         Slic3r::GUI::show_error($self, $event->GetString); | ||||
|     }); | ||||
|      | ||||
|     if ($self->{plater}) { | ||||
|         $self->{plater}->on_select_preset(sub { | ||||
|  | @ -388,7 +410,6 @@ sub on_plater_selection_changed { | |||
| sub quick_slice { | ||||
|     my ($self, %params) = @_; | ||||
|      | ||||
|     my $progress_dialog; | ||||
|     eval { | ||||
|         # validate configuration | ||||
|         my $config = wxTheApp->{preset_bundle}->full_config(); | ||||
|  | @ -429,13 +450,9 @@ sub quick_slice { | |||
|             $print_center = Slic3r::Pointf->new_unscale(@{$bed_shape->bounding_box->center}); | ||||
|         } | ||||
|          | ||||
|         my $sprint = Slic3r::Print::Simple->new( | ||||
|             print_center    => $print_center, | ||||
|             status_cb       => sub { | ||||
|                 my ($percent, $message) = @_; | ||||
|                 $progress_dialog->Update($percent, "$message…"); | ||||
|             }, | ||||
|         ); | ||||
|         my $sprint = Slic3r::Print::Simple->new(print_center => $print_center); | ||||
|         # The C++ slicing core will post a wxCommand message to the main window. | ||||
|         Slic3r::GUI::set_print_callback_event($sprint, $PROGRESS_BAR_EVENT); | ||||
|          | ||||
|         # keep model around | ||||
|         my $model = Slic3r::Model->read_from_file($input_file); | ||||
|  | @ -468,9 +485,9 @@ sub quick_slice { | |||
|         } | ||||
|          | ||||
|         # show processbar dialog | ||||
|         $progress_dialog = Wx::ProgressDialog->new(L('Slicing…'), L("Processing ").$input_file_basename."…",  | ||||
|         $self->{progress_dialog} = Wx::ProgressDialog->new(L('Slicing…'), L("Processing ").$input_file_basename."…",  | ||||
|             100, $self, 0); | ||||
|         $progress_dialog->Pulse; | ||||
|         $self->{progress_dialog}->Pulse; | ||||
|          | ||||
|         { | ||||
|             my @warnings = (); | ||||
|  | @ -482,18 +499,17 @@ sub quick_slice { | |||
|             } else { | ||||
|                 $sprint->export_gcode; | ||||
|             } | ||||
|             $sprint->status_cb(undef); | ||||
|             Slic3r::GUI::warning_catcher($self)->($_) for @warnings; | ||||
|         } | ||||
|         $progress_dialog->Destroy; | ||||
|         undef $progress_dialog; | ||||
|         $self->{progress_dialog}->Destroy; | ||||
|         undef $self->{progress_dialog}; | ||||
|          | ||||
|         my $message = $input_file_basename.L(" was successfully sliced."); | ||||
|         wxTheApp->notify($message); | ||||
|         Wx::MessageDialog->new($self, $message, L('Slicing Done!'),  | ||||
|             wxOK | wxICON_INFORMATION)->ShowModal; | ||||
|     }; | ||||
|     Slic3r::GUI::catch_error($self, sub { $progress_dialog->Destroy if $progress_dialog }); | ||||
|     Slic3r::GUI::catch_error($self, sub { $self->{progress_dialog}->Destroy if $self->{progress_dialog} }); | ||||
| } | ||||
| 
 | ||||
| sub reslice_now { | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ use utf8; | |||
| use File::Basename qw(basename dirname); | ||||
| use List::Util qw(sum first max); | ||||
| use Slic3r::Geometry qw(X Y Z scale unscale deg2rad rad2deg); | ||||
| use threads::shared qw(shared_clone); | ||||
| use Wx qw(:button :colour :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc  | ||||
|     :panel :sizer :toolbar :window wxTheApp :notebook :combobox wxNullBitmap); | ||||
| use Wx::Event qw(EVT_BUTTON EVT_TOGGLEBUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED  | ||||
|  | @ -34,21 +33,16 @@ use constant TB_LAYER_EDITING => &Wx::NewId; | |||
| 
 | ||||
| use Wx::Locale gettext => 'L'; | ||||
| 
 | ||||
| # package variables to avoid passing lexicals to threads | ||||
| our $PROGRESS_BAR_EVENT      : shared = Wx::NewEventType; | ||||
| our $ERROR_EVENT             : shared = Wx::NewEventType; | ||||
| # Emitted from the worker thread when the G-code export is finished. | ||||
| our $EXPORT_COMPLETED_EVENT  : shared = Wx::NewEventType; | ||||
| our $PROCESS_COMPLETED_EVENT : shared = Wx::NewEventType; | ||||
| 
 | ||||
| use constant FILAMENT_CHOOSERS_SPACING => 0; | ||||
| use constant PROCESS_DELAY => 0.5 * 1000; # milliseconds | ||||
| our $SLICING_COMPLETED_EVENT = Wx::NewEventType; | ||||
| our $PROCESS_COMPLETED_EVENT = Wx::NewEventType; | ||||
| 
 | ||||
| my $PreventListEvents = 0; | ||||
| 
 | ||||
| sub new { | ||||
|     my ($class, $parent) = @_; | ||||
|     my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); | ||||
|     Slic3r::GUI::set_plater($self); | ||||
|     $self->{config} = Slic3r::Config::new_from_defaults_keys([qw( | ||||
|         bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height | ||||
|         serial_port serial_speed octoprint_host octoprint_apikey octoprint_cafile | ||||
|  | @ -63,14 +57,14 @@ sub new { | |||
|     # List of Perl objects Slic3r::GUI::Plater::Object, representing a 2D preview of the platter. | ||||
|     $self->{objects} = []; | ||||
|     $self->{gcode_preview_data} = Slic3r::GCode::PreviewData->new; | ||||
|      | ||||
|     $self->{print}->set_status_cb(sub { | ||||
|         my ($percent, $message) = @_; | ||||
|         my $event = Wx::CommandEvent->new($PROGRESS_BAR_EVENT); | ||||
|         $event->SetString($message); | ||||
|         $event->SetInt($percent); | ||||
|         Wx::PostEvent($self, $event); | ||||
|     }); | ||||
|     $self->{background_slicing_process} = Slic3r::GUI::BackgroundSlicingProcess->new; | ||||
|     $self->{background_slicing_process}->set_print($self->{print}); | ||||
|     $self->{background_slicing_process}->set_gcode_preview_data($self->{gcode_preview_data}); | ||||
|     $self->{background_slicing_process}->set_sliced_event($SLICING_COMPLETED_EVENT); | ||||
|     $self->{background_slicing_process}->set_finished_event($PROCESS_COMPLETED_EVENT); | ||||
| 
 | ||||
|     # The C++ slicing core will post a wxCommand message to the main window.     | ||||
|     Slic3r::GUI::set_print_callback_event($self->{print}, $Slic3r::GUI::MainFrame::PROGRESS_BAR_EVENT); | ||||
|      | ||||
|     # Initialize preview notebook | ||||
|     $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [335,335], wxNB_BOTTOM); | ||||
|  | @ -319,19 +313,9 @@ sub new { | |||
|         for grep defined($_), | ||||
|             $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list}; | ||||
|      | ||||
|     EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub { | ||||
|     EVT_COMMAND($self, -1, $SLICING_COMPLETED_EVENT, sub { | ||||
|         my ($self, $event) = @_; | ||||
|         $self->on_progress_event($event->GetInt, $event->GetString); | ||||
|     }); | ||||
|      | ||||
|     EVT_COMMAND($self, -1, $ERROR_EVENT, sub { | ||||
|         my ($self, $event) = @_; | ||||
|         Slic3r::GUI::show_error($self, $event->GetString); | ||||
|     }); | ||||
|      | ||||
|     EVT_COMMAND($self, -1, $EXPORT_COMPLETED_EVENT, sub { | ||||
|         my ($self, $event) = @_; | ||||
|         $self->on_export_completed($event->GetInt); | ||||
|         $self->on_update_print_preview; | ||||
|     }); | ||||
|      | ||||
|     EVT_COMMAND($self, -1, $PROCESS_COMPLETED_EVENT, sub { | ||||
|  | @ -788,8 +772,7 @@ sub bed_centerf { | |||
| } | ||||
| 
 | ||||
| sub remove { | ||||
|     my $self = shift; | ||||
|     my ($obj_idx) = @_; | ||||
|     my ($self, $obj_idx) = @_; | ||||
|      | ||||
|     $self->stop_background_process; | ||||
|      | ||||
|  | @ -797,7 +780,7 @@ sub remove { | |||
|     $self->{toolpaths2D}->enabled(0) if $self->{toolpaths2D}; | ||||
|     $self->{preview3D}->enabled(0) if $self->{preview3D}; | ||||
|      | ||||
|     # if no object index is supplied, remove the selected one | ||||
|     # If no object index is supplied, remove the selected one. | ||||
|     if (! defined $obj_idx) { | ||||
|         ($obj_idx, undef) = $self->selected_object; | ||||
|         return if ! defined $obj_idx; | ||||
|  | @ -811,11 +794,10 @@ sub remove { | |||
|      | ||||
|     $self->select_object(undef); | ||||
|     $self->update; | ||||
|     $self->schedule_background_process; | ||||
| } | ||||
| 
 | ||||
| sub reset { | ||||
|     my $self = shift; | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     $self->stop_background_process; | ||||
|      | ||||
|  | @ -840,6 +822,7 @@ sub increase { | |||
|     return if ! defined $obj_idx; | ||||
|     my $model_object = $self->{model}->objects->[$obj_idx]; | ||||
|     my $instance = $model_object->instances->[-1]; | ||||
|     $self->stop_background_process; | ||||
|     for my $i (1..$copies) { | ||||
|         $instance = $model_object->add_instance( | ||||
|             offset          => Slic3r::Pointf->new(map 10+$_, @{$instance->offset}), | ||||
|  | @ -849,15 +832,8 @@ sub increase { | |||
|         $self->{print}->objects->[$obj_idx]->add_copy($instance->offset); | ||||
|     } | ||||
|     $self->{list}->SetItem($obj_idx, 1, $model_object->instances_count); | ||||
|      | ||||
|     # only autoarrange if user has autocentering enabled | ||||
|     $self->stop_background_process; | ||||
|     if (wxTheApp->{app_config}->get("autocenter")) { | ||||
|         $self->arrange; | ||||
|     } else { | ||||
|         $self->update; | ||||
|     } | ||||
|     $self->schedule_background_process; | ||||
|     # Only autoarrange if user has autocentering enabled. | ||||
|     wxTheApp->{app_config}->get("autocenter") ? $self->arrange : $self->update; | ||||
| } | ||||
| 
 | ||||
| sub decrease { | ||||
|  | @ -866,10 +842,9 @@ sub decrease { | |||
|     my ($obj_idx, $object) = $self->selected_object; | ||||
|     return if ! defined $obj_idx; | ||||
| 
 | ||||
|     $self->stop_background_process; | ||||
|      | ||||
|     my $model_object = $self->{model}->objects->[$obj_idx]; | ||||
|     if ($model_object->instances_count > $copies) { | ||||
|         $self->stop_background_process; | ||||
|         for my $i (1..$copies) { | ||||
|             $model_object->delete_last_instance; | ||||
|             $self->{print}->objects->[$obj_idx]->delete_last_copy; | ||||
|  | @ -877,10 +852,10 @@ sub decrease { | |||
|         $self->{list}->SetItem($obj_idx, 1, $model_object->instances_count); | ||||
|     } elsif (defined $copies_asked) { | ||||
|         # The "decrease" came from the "set number of copies" dialog. | ||||
|         $self->stop_background_process; | ||||
|         $self->remove; | ||||
|     } else { | ||||
|         # The "decrease" came from the "-" button. Don't allow the object to disappear. | ||||
|         $self->resume_background_process; | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|  | @ -889,24 +864,18 @@ sub decrease { | |||
|         $self->{list}->Select($obj_idx, 1); | ||||
|     } | ||||
|     $self->update; | ||||
|     $self->schedule_background_process; | ||||
| } | ||||
| 
 | ||||
| sub set_number_of_copies { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     $self->pause_background_process; | ||||
|      | ||||
|     # get current number of copies | ||||
|     my ($obj_idx, $object) = $self->selected_object; | ||||
|     my $model_object = $self->{model}->objects->[$obj_idx]; | ||||
|      | ||||
|     my $model_object = $self->{model}->objects->[$obj_idx];     | ||||
|     # prompt user | ||||
|     my $copies = Wx::GetNumberFromUser("", L("Enter the number of copies of the selected object:"), L("Copies"), $model_object->instances_count, 0, 1000, $self); | ||||
|     my $diff = $copies - $model_object->instances_count; | ||||
|     if ($diff == 0) { | ||||
|         # no variation | ||||
|         $self->resume_background_process; | ||||
|     } elsif ($diff > 0) { | ||||
|         $self->increase($diff); | ||||
|     } elsif ($diff < 0) { | ||||
|  | @ -981,7 +950,6 @@ sub rotate { | |||
|      | ||||
|     $self->selection_changed;  # refresh info (size etc.) | ||||
|     $self->update; | ||||
|     $self->schedule_background_process; | ||||
| } | ||||
| 
 | ||||
| sub mirror { | ||||
|  | @ -1011,7 +979,6 @@ sub mirror { | |||
|      | ||||
|     $self->selection_changed;  # refresh info (size etc.) | ||||
|     $self->update; | ||||
|     $self->schedule_background_process; | ||||
| } | ||||
| 
 | ||||
| sub changescale { | ||||
|  | @ -1086,14 +1053,12 @@ sub changescale { | |||
|      | ||||
|     $self->selection_changed(1);  # refresh info (size, volume etc.) | ||||
|     $self->update; | ||||
|     $self->schedule_background_process; | ||||
| } | ||||
| 
 | ||||
| sub arrange { | ||||
|     my $self = shift; | ||||
|      | ||||
|     $self->pause_background_process; | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     $self->stop_background_process; | ||||
|     my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape); | ||||
|     my $success = $self->{model}->arrange_objects(wxTheApp->{preset_bundle}->full_config->min_object_distance, $bb); | ||||
|     # ignore arrange failures on purpose: user has visual feedback and we don't need to warn him | ||||
|  | @ -1118,84 +1083,62 @@ sub split_object { | |||
|         return; | ||||
|     } | ||||
|      | ||||
|     $self->pause_background_process; | ||||
|     $self->stop_background_process; | ||||
|      | ||||
|     my @model_objects = @{$current_model_object->split_object}; | ||||
|     if (@model_objects == 1) { | ||||
|         $self->resume_background_process; | ||||
|         Slic3r::GUI::warning_catcher($self)->(L("The selected object couldn't be split because it contains only one part.")); | ||||
|         $self->resume_background_process; | ||||
|         return; | ||||
|         $self->schedule_background_process; | ||||
|     } else { | ||||
|         $_->center_around_origin for (@model_objects); | ||||
|         $self->remove($obj_idx); | ||||
|         $current_object = $obj_idx = undef; | ||||
|         # load all model objects at once, otherwise the plate would be rearranged after each one | ||||
|         # causing original positions not to be kept | ||||
|         $self->load_model_objects(@model_objects); | ||||
|     } | ||||
|      | ||||
|     $_->center_around_origin for (@model_objects); | ||||
| 
 | ||||
|     $self->remove($obj_idx); | ||||
|     $current_object = $obj_idx = undef; | ||||
|      | ||||
|     # load all model objects at once, otherwise the plate would be rearranged after each one | ||||
|     # causing original positions not to be kept | ||||
|     $self->load_model_objects(@model_objects); | ||||
| } | ||||
| 
 | ||||
| # Trigger $self->async_apply_config() after 500ms. | ||||
| # The call is delayed to avoid restarting the background processing during typing into an edit field. | ||||
| sub schedule_background_process { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     if (defined $self->{apply_config_timer}) { | ||||
|         $self->{apply_config_timer}->Start(PROCESS_DELAY, 1);  # 1 = one shot | ||||
|     } | ||||
|     $self->{apply_config_timer}->Start(0.5 * 1000, 1);  # 1 = one shot, every half a second. | ||||
| } | ||||
| 
 | ||||
| # Executed asynchronously by a timer every PROCESS_DELAY (0.5 second). | ||||
| # The timer is started by schedule_background_process(),  | ||||
| sub async_apply_config { | ||||
|     my ($self) = @_; | ||||
| 
 | ||||
|     # pause process thread before applying new config | ||||
|     # since we don't want to touch data that is being used by the threads | ||||
|     $self->pause_background_process; | ||||
|      | ||||
|     # apply new config | ||||
|     my $invalidated = $self->{print}->apply_config(wxTheApp->{preset_bundle}->full_config); | ||||
| 
 | ||||
|     # Just redraw the 3D canvas without reloading the scene. | ||||
| #    $self->{canvas3D}->Refresh if ($invalidated && $self->{canvas3D}->layer_editing_enabled); | ||||
|     # Apply new config to the possibly running background task. | ||||
|     my $was_running = $self->{background_slicing_process}->running; | ||||
|     my $invalidated = $self->{background_slicing_process}->apply_config(wxTheApp->{preset_bundle}->full_config); | ||||
|     # Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. | ||||
|     $self->{canvas3D}->Refresh if ($self->{canvas3D}->layer_editing_enabled); | ||||
| 
 | ||||
|     # Hide the slicing results if the current slicing status is no more valid.     | ||||
|     $self->{"print_info_box_show"}->(0) if $invalidated; | ||||
| 
 | ||||
|     if (wxTheApp->{app_config}->get("background_processing")) {     | ||||
|         if ($invalidated) { | ||||
|             # kill current thread if any | ||||
|             $self->stop_background_process; | ||||
|         } else { | ||||
|             $self->resume_background_process; | ||||
|         } | ||||
|         # schedule a new process thread in case it wasn't running | ||||
|         $self->start_background_process; | ||||
|     } | ||||
| 
 | ||||
|     # Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. | ||||
|     # Otherwise they will be just refreshed. | ||||
|     # If the apply_config caused the calculation to stop, or it was not running yet: | ||||
|     if ($invalidated) { | ||||
|         $self->{gcode_preview_data}->reset; | ||||
|         $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; | ||||
|         $self->{preview3D}->reload_print if $self->{preview3D}; | ||||
|         if ($was_running) { | ||||
|             # Hide the slicing results if the current slicing status is no more valid. | ||||
|             $self->{"print_info_box_show"}->(0); | ||||
|         } | ||||
|         if (wxTheApp->{app_config}->get("background_processing")) { | ||||
|             $self->{background_slicing_process}->start; | ||||
|         } | ||||
|         if ($was_running) { | ||||
|             # Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. | ||||
|             # Otherwise they will be just refreshed. | ||||
|             $self->{gcode_preview_data}->reset; | ||||
|             $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; | ||||
|             $self->{preview3D}->reload_print if $self->{preview3D}; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| # Background processing is started either by the "Slice now" button, by the "Export G-code button" or by async_apply_config(). | ||||
| sub start_background_process { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     return if !@{$self->{objects}}; | ||||
|     return if $self->{process_thread}; | ||||
|      | ||||
|     # 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 | ||||
|     return if ! @{$self->{objects}} || $self->{background_slicing_process}->running; | ||||
|     # Don't start process thread if config is not valid. | ||||
|     eval { | ||||
|         # this will throw errors if config is not valid | ||||
|         wxTheApp->{preset_bundle}->full_config->validate; | ||||
|  | @ -1204,79 +1147,29 @@ sub start_background_process { | |||
|     if ($@) { | ||||
|         $self->statusbar->SetStatusText($@); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     }    | ||||
|     # Copy the names of active presets into the placeholder parser. | ||||
|     wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser); | ||||
|      | ||||
|     # start thread | ||||
|     @_ = (); | ||||
|     $self->{process_thread} = Slic3r::spawn_thread(sub { | ||||
|         eval { | ||||
|             $self->{print}->process; | ||||
|         }; | ||||
|         my $event = Wx::CommandEvent->new($PROCESS_COMPLETED_EVENT); | ||||
|         if ($@) { | ||||
|             Slic3r::debugf "Background process error: $@\n"; | ||||
|             $event->SetInt(0); | ||||
|             $event->SetString($@); | ||||
|         } else { | ||||
|             $event->SetInt(1); | ||||
|         } | ||||
|         Wx::PostEvent($self, $event); | ||||
|         Slic3r::thread_cleanup(); | ||||
|     }); | ||||
|     Slic3r::debugf "Background processing started.\n"; | ||||
|     # Start the background process. | ||||
|     $self->{background_slicing_process}->start; | ||||
| } | ||||
| 
 | ||||
| # Stop the background processing | ||||
| sub stop_background_process { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     $self->{apply_config_timer}->Stop if defined $self->{apply_config_timer}; | ||||
|     # Don't call async_apply_config() while stopped. | ||||
|     $self->{apply_config_timer}->Stop; | ||||
|     $self->statusbar->SetCancelCallback(undef); | ||||
|     $self->statusbar->StopBusy; | ||||
|     $self->statusbar->SetStatusText(""); | ||||
|     # Stop the background task. | ||||
|     $self->{background_slicing_process}->stop; | ||||
|     # Update the UI with the slicing results. | ||||
|     $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; | ||||
|     $self->{preview3D}->reload_print if $self->{preview3D}; | ||||
|      | ||||
|     if ($self->{process_thread}) { | ||||
|         Slic3r::debugf "Killing background process.\n"; | ||||
|         Slic3r::kill_all_threads(); | ||||
|         $self->{process_thread} = undef; | ||||
|     } else { | ||||
|         Slic3r::debugf "No background process running.\n"; | ||||
|     } | ||||
|      | ||||
|     # if there's an export process, kill that one as well | ||||
|     if ($self->{export_thread}) { | ||||
|         Slic3r::debugf "Killing background export process.\n"; | ||||
|         Slic3r::kill_all_threads(); | ||||
|         $self->{export_thread} = undef; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| sub pause_background_process { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     if ($self->{process_thread} || $self->{export_thread}) { | ||||
|         Slic3r::pause_all_threads(); | ||||
|         return 1; | ||||
|     } elsif (defined $self->{apply_config_timer} && $self->{apply_config_timer}->IsRunning) { | ||||
|         $self->{apply_config_timer}->Stop; | ||||
|         return 1; | ||||
|     } | ||||
|      | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| sub resume_background_process { | ||||
|     my ($self) = @_; | ||||
|      | ||||
|     if ($self->{process_thread} || $self->{export_thread}) { | ||||
|         Slic3r::resume_all_threads(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| # Called by the "Slice now" button, which is visible only if the background processing is disabled. | ||||
| sub reslice { | ||||
|     # explicitly cancel a previous thread and start a new one. | ||||
|     my ($self) = @_; | ||||
|  | @ -1371,79 +1264,22 @@ sub export_gcode { | |||
|     return $self->{export_gcode_output_file}; | ||||
| } | ||||
| 
 | ||||
| # This gets called only if we have threads. | ||||
| sub on_process_completed { | ||||
|     my ($self, $error) = @_; | ||||
|      | ||||
|     $self->statusbar->SetCancelCallback(undef); | ||||
|     $self->statusbar->StopBusy; | ||||
|     $self->statusbar->SetStatusText($error // ""); | ||||
|      | ||||
|     Slic3r::debugf "Background processing completed.\n"; | ||||
|     $self->{process_thread}->detach if $self->{process_thread}; | ||||
|     $self->{process_thread} = undef; | ||||
|      | ||||
|     # if we're supposed to perform an explicit export let's display the error in a dialog | ||||
|     if ($error && $self->{export_gcode_output_file}) { | ||||
|         $self->{export_gcode_output_file} = undef; | ||||
|         Slic3r::GUI::show_error($self, $error); | ||||
|     } | ||||
|      | ||||
|     return if $error; | ||||
| # This message should be called by the background process synchronously. | ||||
| sub on_update_print_preview { | ||||
|     my ($self) = @_; | ||||
|     $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; | ||||
|     $self->{preview3D}->reload_print if $self->{preview3D}; | ||||
|      | ||||
|     # if we have an export filename, start a new thread for exporting G-code | ||||
|     if ($self->{export_gcode_output_file}) { | ||||
|         @_ = (); | ||||
|          | ||||
|         # workaround for "Attempt to free un referenced scalar..." | ||||
|         our $_thread_self = $self; | ||||
|          | ||||
|         $self->{export_thread} = Slic3r::spawn_thread(sub { | ||||
|             eval { | ||||
|                 $_thread_self->{print}->export_gcode(output_file => $_thread_self->{export_gcode_output_file}, gcode_preview_data => $_thread_self->{gcode_preview_data}); | ||||
|             }; | ||||
|             my $export_completed_event = Wx::CommandEvent->new($EXPORT_COMPLETED_EVENT); | ||||
|             if ($@) { | ||||
|                 { | ||||
|                     my $error_event = Wx::CommandEvent->new($ERROR_EVENT); | ||||
|                     $error_event->SetString($@); | ||||
|                     Wx::PostEvent($_thread_self, $error_event); | ||||
|                 } | ||||
|                 $export_completed_event->SetInt(0); | ||||
|                 $export_completed_event->SetString($@); | ||||
|             } else { | ||||
|                 $export_completed_event->SetInt(1); | ||||
|             } | ||||
|             Wx::PostEvent($_thread_self, $export_completed_event); | ||||
|             Slic3r::thread_cleanup(); | ||||
|         }); | ||||
|         Slic3r::debugf "Background G-code export started.\n"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| # This gets called also if we have no threads. | ||||
| sub on_progress_event { | ||||
|     my ($self, $percent, $message) = @_; | ||||
|      | ||||
|     $self->statusbar->SetProgress($percent); | ||||
|     $self->statusbar->SetStatusText("$message…"); | ||||
| } | ||||
| 
 | ||||
| # Called when the G-code export finishes, either successfully or with an error. | ||||
| # This gets called also if we don't have threads. | ||||
| sub on_export_completed { | ||||
| sub on_process_completed { | ||||
|     my ($self, $result) = @_; | ||||
|      | ||||
|     $self->statusbar->SetCancelCallback(undef); | ||||
|     $self->statusbar->StopBusy; | ||||
|     $self->statusbar->SetStatusText(""); | ||||
|      | ||||
|     Slic3r::debugf "Background export process completed.\n"; | ||||
|     $self->{export_thread}->detach if $self->{export_thread}; | ||||
|     $self->{export_thread} = undef; | ||||
|      | ||||
|     my $message; | ||||
|     my $send_gcode = 0; | ||||
|     my $do_print = 0; | ||||
|  | @ -1470,7 +1306,7 @@ sub on_export_completed { | |||
|     # Send $self->{send_gcode_file} to OctoPrint. | ||||
|     if ($send_gcode) { | ||||
|         my $op = Slic3r::OctoPrint->new($self->{config}); | ||||
|         $op->send_gcode($self->GetId(), $PROGRESS_BAR_EVENT, $ERROR_EVENT, $self->{send_gcode_file}); | ||||
|         $op->send_gcode($self->GetId(), $Slic3r::GUI::MainFrame::PROGRESS_BAR_EVENT, $Slic3r::GUI::MainFrame::ERROR_EVENT, $self->{send_gcode_file}); | ||||
|     } | ||||
| 
 | ||||
|     $self->{print_file} = undef; | ||||
|  | @ -1636,27 +1472,15 @@ sub reset_thumbnail { | |||
| # (i.e. when an object is added/removed/moved/rotated/scaled) | ||||
| sub update { | ||||
|     my ($self, $force_autocenter) = @_; | ||||
| 
 | ||||
|     if (wxTheApp->{app_config}->get("autocenter") || $force_autocenter) { | ||||
|         $self->{model}->center_instances_around_point($self->bed_centerf); | ||||
|     } | ||||
|      | ||||
|     my $running = $self->pause_background_process; | ||||
|     my $invalidated = $self->{print}->reload_model_instances(); | ||||
|      | ||||
|     # The mere fact that no steps were invalidated when reloading model instances  | ||||
|     # doesn't mean that all steps were done: for example, validation might have  | ||||
|     # failed upon previous instance move, so we have no running thread and no steps | ||||
|     # are invalidated on this move, thus we need to schedule a new run. | ||||
|     if ($invalidated || !$running) { | ||||
|         $self->schedule_background_process; | ||||
|     } else { | ||||
|         $self->resume_background_process; | ||||
|     } | ||||
| 
 | ||||
|     $self->stop_background_process; | ||||
|     $self->{print}->reload_model_instances(); | ||||
|     $self->{canvas}->reload_scene if $self->{canvas}; | ||||
|     $self->{canvas3D}->reload_scene if $self->{canvas3D}; | ||||
|     $self->{preview3D}->reload_print if $self->{preview3D}; | ||||
|     $self->schedule_background_process; | ||||
| } | ||||
| 
 | ||||
| # When a number of extruders changes, the UI needs to be updated to show a single filament selection combo box per extruder. | ||||
|  | @ -1679,7 +1503,7 @@ sub on_extruders_change { | |||
|         $choice->SetItemBitmap($_, $choices->[0]->GetItemBitmap($_)) for 0..$#presets; | ||||
|         # insert new choice into sizer | ||||
|         $self->{presets_sizer}->Insert(4 + ($#$choices-1)*2, 0, 0); | ||||
|         $self->{presets_sizer}->Insert(5 + ($#$choices-1)*2, $choice, 0, wxEXPAND | wxBOTTOM, FILAMENT_CHOOSERS_SPACING); | ||||
|         $self->{presets_sizer}->Insert(5 + ($#$choices-1)*2, $choice, 0, wxEXPAND | wxBOTTOM, 0); | ||||
|         # setup the listener | ||||
|         EVT_COMBOBOX($choice, $choice, sub { | ||||
|             my ($choice) = @_; | ||||
|  | @ -1854,7 +1678,7 @@ sub object_settings_dialog { | |||
| 		model_object    => $model_object, | ||||
|         config          => wxTheApp->{preset_bundle}->full_config, | ||||
| 	); | ||||
| 	$self->pause_background_process; | ||||
| 	$self->stop_background_process; | ||||
| 	$dlg->ShowModal; | ||||
| 	 | ||||
|     # update thumbnail since parts may have changed | ||||
|  | @ -1866,13 +1690,12 @@ sub object_settings_dialog { | |||
| 	 | ||||
| 	# update print | ||||
| 	if ($dlg->PartsChanged || $dlg->PartSettingsChanged) { | ||||
| 	    $self->stop_background_process; | ||||
|         $self->{print}->reload_object($obj_idx); | ||||
|         $self->schedule_background_process; | ||||
|         $self->{canvas}->reload_scene if $self->{canvas}; | ||||
|         $self->{canvas3D}->reload_scene if $self->{canvas3D}; | ||||
|     } else { | ||||
|         $self->resume_background_process; | ||||
|         $self->schedule_background_process; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -152,12 +152,6 @@ __PACKAGE__->mk_accessors(qw( | |||
|     _simulation_mode | ||||
| )); | ||||
| 
 | ||||
| # make OpenGL::Array thread-safe | ||||
| { | ||||
|     no warnings 'redefine'; | ||||
|     *OpenGL::Array::CLONE_SKIP = sub { 1 }; | ||||
| } | ||||
| 
 | ||||
| sub new { | ||||
|     my ($class, $parent, $print) = @_; | ||||
|      | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv