Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Slic3r/GUI/Plater.pm')
-rw-r--r--lib/Slic3r/GUI/Plater.pm441
1 files changed, 279 insertions, 162 deletions
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 3f069c0e4..48b82237f 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -14,6 +14,7 @@ use Wx qw(:button :colour :cursor :dialog :filedialog :keycode :icon :font :id :
use Wx::Event qw(EVT_BUTTON EVT_TOGGLEBUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED
EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_LEFT_DOWN EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL
EVT_CHOICE EVT_COMBOBOX EVT_TIMER EVT_NOTEBOOK_PAGE_CHANGED);
+use Slic3r::Geometry qw(PI);
use base 'Wx::Panel';
use constant TB_ADD => &Wx::NewId;
@@ -45,13 +46,14 @@ use constant FILAMENT_CHOOSERS_SPACING => 0;
use constant PROCESS_DELAY => 0.5 * 1000; # milliseconds
my $PreventListEvents = 0;
+our $appController;
sub new {
my ($class, $parent) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
$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
+ serial_port serial_speed host_type print_host printhost_apikey printhost_cafile
nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model
)]);
@@ -115,6 +117,8 @@ sub new {
my $model_object = $self->{model}->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
+
+ $self->stop_background_process;
my $variation = $scale / $model_instance->scaling_factor;
#FIXME Scale the layer height profile?
@@ -123,10 +127,11 @@ sub new {
$range->[1] *= $variation;
}
$_->set_scaling_factor($scale) for @{ $model_object->instances };
- $object->transform_thumbnail($self->{model}, $obj_idx);
+
+ $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
+# $object->transform_thumbnail($self->{model}, $obj_idx);
#update print and start background processing
- $self->stop_background_process;
$self->{print}->add_model_object($model_object, $obj_idx);
$self->selection_changed(1); # refresh info (size, volume etc.)
@@ -134,6 +139,34 @@ sub new {
$self->schedule_background_process;
};
+ # callback to react to gizmo rotate
+ # omitting last three parameters means rotation around Z
+ # otherwise they are the components of the rotation axis vector
+ my $on_gizmo_rotate = sub {
+ my ($angle, $axis_x, $axis_y, $axis_z) = @_;
+ if (!defined $axis_x) {
+ $self->rotate(rad2deg($angle), Z, 'absolute');
+ }
+ else {
+ $self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0;
+ }
+ };
+
+ # callback to update object's geometry info while using gizmos
+ my $on_update_geometry_info = sub {
+ my ($size_x, $size_y, $size_z, $scale_factor) = @_;
+
+ my ($obj_idx, $object) = $self->selected_object;
+
+ if ((defined $obj_idx) && ($self->{object_info_size})) { # have we already loaded the info pane?
+ $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", $size_x, $size_y, $size_z));
+ my $model_object = $self->{model}->objects->[$obj_idx];
+ if (my $stats = $model_object->mesh_stats) {
+ $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * $scale_factor**3));
+ }
+ }
+ };
+
# Initialize 3D plater
if ($Slic3r::GUI::have_OpenGL) {
$self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config});
@@ -151,7 +184,9 @@ sub new {
Slic3r::GUI::_3DScene::register_on_instance_moved_callback($self->{canvas3D}, $on_instances_moved);
Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons);
Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly);
-# Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1);
+ Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate);
+ Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info);
+ Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1);
Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1);
Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1);
@@ -168,25 +203,28 @@ sub new {
$self->schedule_background_process;
} else {
# Hide the print info box, it is no more valid.
- $self->{"print_info_box_show"}->(0);
+ $self->print_info_box_show(0);
}
});
Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); });
}
+
+ Slic3r::GUI::register_on_request_update_callback(sub { $self->schedule_background_process; });
- # Initialize 2D preview canvas
- $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config});
- $self->{preview_notebook}->AddPage($self->{canvas}, L('2D'));
- $self->{canvas}->on_select_object($on_select_object);
- $self->{canvas}->on_double_click($on_double_click);
- $self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); });
- $self->{canvas}->on_instances_moved($on_instances_moved);
+# # Initialize 2D preview canvas
+# $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config});
+# $self->{preview_notebook}->AddPage($self->{canvas}, L('2D'));
+# $self->{canvas}->on_select_object($on_select_object);
+# $self->{canvas}->on_double_click($on_double_click);
+# $self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); });
+# $self->{canvas}->on_instances_moved($on_instances_moved);
# Initialize 3D toolpaths preview
if ($Slic3r::GUI::have_OpenGL) {
$self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config});
Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1);
+ Slic3r::GUI::_3DScene::enable_dynamic_background($self->{preview3D}->canvas, 1);
Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{preview3D}->canvas, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); });
$self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview'));
$self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1;
@@ -266,9 +304,9 @@ sub new {
$self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
### Scrolled Window for info boxes
- my $scrolled_window_sizer = Wx::BoxSizer->new(wxVERTICAL);
+ my $scrolled_window_sizer = $self->{scrolled_window_sizer} = Wx::BoxSizer->new(wxVERTICAL);
$scrolled_window_sizer->SetMinSize([310, -1]);
- my $scrolled_window_panel = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+ my $scrolled_window_panel = $self->{scrolled_window_panel} = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
$scrolled_window_panel->SetSizer($scrolled_window_sizer);
$scrolled_window_panel->SetScrollbars(1, 1, 1, 1);
@@ -284,6 +322,9 @@ sub new {
my ($list, $event) = @_;
if ($event->GetKeyCode == WXK_TAB) {
$list->Navigate($event->ShiftDown ? &Wx::wxNavigateBackward : &Wx::wxNavigateForward);
+ } elsif ($event->GetKeyCode == WXK_DELETE ||
+ ($event->GetKeyCode == WXK_BACK && &Wx::wxMAC) ) {
+ $self->remove;
} else {
$event->Skip;
}
@@ -373,7 +414,8 @@ sub new {
$_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self))
for grep defined($_),
- $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list};
+ $self, $self->{canvas3D}, $self->{preview3D}, $self->{list};
+# $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list};
EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub {
my ($self, $event) = @_;
@@ -404,7 +446,7 @@ sub new {
});
}
- $self->{canvas}->update_bed_size;
+# $self->{canvas}->update_bed_size;
if ($self->{canvas3D}) {
Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape);
Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D});
@@ -494,34 +536,9 @@ sub new {
}
}
- my $print_info_sizer;
- {
- my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info"));
- $print_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
- $print_info_sizer->SetMinSize([300,-1]);
- my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5);
- $grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
- $grid_sizer->AddGrowableCol(1, 1);
- $grid_sizer->AddGrowableCol(3, 1);
- $print_info_sizer->Add($grid_sizer, 0, wxEXPAND);
- my @info = (
- fil_m => L("Used Filament (m)"),
- fil_mm3 => L("Used Filament (mm³)"),
- fil_g => L("Used Filament (g)"),
- cost => L("Cost"),
- time => L("Estimated printing time"),
- );
- while (my $field = shift @info) {
- my $label = shift @info;
- my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
- $text->SetFont($Slic3r::GUI::small_font);
- $grid_sizer->Add($text, 0);
-
- $self->{"print_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
- $self->{"print_info_$field"}->SetFont($Slic3r::GUI::small_font);
- $grid_sizer->Add($self->{"print_info_$field"}, 0);
- }
- }
+ my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new(
+ Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info")), wxVERTICAL);
+ $print_info_sizer->SetMinSize([300,-1]);
my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{buttons_sizer} = $buttons_sizer;
@@ -542,19 +559,8 @@ sub new {
$right_sizer->Add($frequently_changed_parameters_sizer, 0, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
$right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM, 5);
$right_sizer->Add($scrolled_window_panel, 1, wxEXPAND | wxALL, 1);
- # Callback for showing / hiding the print info box.
- $self->{"print_info_box_show"} = sub {
-# if ($right_sizer->IsShown(5) != $_[0]) {
-# $right_sizer->Show(5, $_[0]);
-# $self->Layout
-# }
- if ($scrolled_window_sizer->IsShown(2) != $_[0]) {
- $scrolled_window_sizer->Show(2, $_[0]);
- $scrolled_window_panel->Layout
- }
- };
# Show the box initially, let it be shown after the slicing is finished.
- $self->{"print_info_box_show"}->(0);
+ $self->print_info_box_show(0);
$self->{right_panel}->SetSizer($right_sizer);
@@ -761,6 +767,15 @@ sub load_files {
$model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES;
}
+ # objects imported from 3mf require a call to center_around_origin to have gizmos working properly and this call
+ # need to be done after looks_like_multipart_object detection
+ if ($input_file =~ /.3[mM][fF]$/)
+ {
+ foreach my $model_object (@{$model->objects}) {
+ $model_object->center_around_origin; # also aligns object to Z = 0
+ }
+ }
+
if ($one_by_one) {
push @obj_idx, $self->load_model_objects(@{$model->objects});
} else {
@@ -855,8 +870,8 @@ sub load_model_objects {
$self->{list}->SetItem($obj_idx, 1, $model_object->instances_count);
$self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
-
- $self->reset_thumbnail($obj_idx);
+
+# $self->reset_thumbnail($obj_idx);
}
$self->arrange if $need_arrange;
$self->update;
@@ -996,9 +1011,10 @@ sub set_number_of_copies {
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 $copies = -1;
+ $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) {
+ if ($diff == 0 || $copies == -1) {
# no variation
$self->resume_background_process;
} elsif ($diff > 0) {
@@ -1031,43 +1047,67 @@ sub _get_number_from_user {
}
sub rotate {
- my ($self, $angle, $axis, $relative_key) = @_;
+ my ($self, $angle, $axis, $relative_key, $axis_x, $axis_y, $axis_z) = @_;
$relative_key //= 'absolute'; # relative or absolute coordinates
- $axis //= Z; # angle is in degrees
-
+ $axis_x //= 0;
+ $axis_y //= 0;
+ $axis_z //= 0;
my $relative = $relative_key eq 'relative';
-
+
my ($obj_idx, $object) = $self->selected_object;
return if !defined $obj_idx;
-
+
my $model_object = $self->{model}->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
-
+
if (!defined $angle) {
my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
my $default = $axis == Z ? rad2deg($model_instance->rotation) : 0;
$angle = $self->_get_number_from_user(L("Enter the rotation angle:"), L("Rotate around ").$axis_name.(" axis"), L("Invalid rotation angle entered"), $default);
return if $angle eq '';
}
+
+ # Let's calculate vector of rotation axis (if we don't have it already)
+ # The minus is there so that the direction is the same as was established
+ if (defined $axis) {
+ if ($axis == X) {
+ $axis_x = -1;
+ }
+ if ($axis == Y) {
+ $axis_y = -1;
+ }
+ }
$self->stop_background_process;
- if ($axis == Z) {
+ if (defined $axis && $axis == Z) {
my $new_angle = deg2rad($angle);
- $_->set_rotation(($relative ? $_->rotation : 0.) + $new_angle) for @{ $model_object->instances };
- $object->transform_thumbnail($self->{model}, $obj_idx);
+ foreach my $inst (@{ $model_object->instances }) {
+ my $rotation = ($relative ? $inst->rotation : 0.) + $new_angle;
+ while ($rotation > 2.0 * PI) {
+ $rotation -= 2.0 * PI;
+ }
+ while ($rotation < 0.0) {
+ $rotation += 2.0 * PI;
+ }
+ $inst->set_rotation($rotation);
+ Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
+ }
+# $object->transform_thumbnail($self->{model}, $obj_idx);
} else {
- # rotation around X and Y needs to be performed on mesh
- # so we first apply any Z rotation
- if ($model_instance->rotation != 0) {
- $model_object->rotate($model_instance->rotation, Z);
- $_->set_rotation(0) for @{ $model_object->instances };
+ if (defined $axis) {
+ # rotation around X and Y needs to be performed on mesh
+ # so we first apply any Z rotation
+ if ($model_instance->rotation != 0) {
+ $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, -1));
+ $_->set_rotation(0) for @{ $model_object->instances };
+ }
}
- $model_object->rotate(deg2rad($angle), $axis);
+ $model_object->rotate(deg2rad($angle), Slic3r::Pointf3->new($axis_x, $axis_y, $axis_z));
- # realign object to Z = 0
- $model_object->center_around_origin;
- $self->reset_thumbnail($obj_idx);
+# # realign object to Z = 0
+# $model_object->center_around_origin;
+# $self->reset_thumbnail($obj_idx);
}
# update print and start background processing
@@ -1089,15 +1129,15 @@ sub mirror {
# apply Z rotation before mirroring
if ($model_instance->rotation != 0) {
- $model_object->rotate($model_instance->rotation, Z);
+ $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1));
$_->set_rotation(0) for @{ $model_object->instances };
}
$model_object->mirror($axis);
- # realign object to Z = 0
- $model_object->center_around_origin;
- $self->reset_thumbnail($obj_idx);
+# # realign object to Z = 0
+# $model_object->center_around_origin;
+# $self->reset_thumbnail($obj_idx);
# update print and start background processing
$self->stop_background_process;
@@ -1117,8 +1157,7 @@ sub changescale {
my $model_object = $self->{model}->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
- my $object_size = $model_object->bounding_box->size;
- my $bed_size = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape})->bounding_box->size;
+ my $object_size = $model_object->instance_bounding_box(0)->size;
if (defined $axis) {
my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
@@ -1126,7 +1165,7 @@ sub changescale {
if ($tosize) {
my $cursize = $object_size->[$axis];
my $newsize = $self->_get_number_from_user(
- sprintf(L('Enter the new size for the selected object (print bed: %smm):'), unscale($bed_size->[$axis])),
+ L('Enter the new size for the selected object:'),
L("Scale along ").$axis_name, L('Invalid scaling value entered'), $cursize, 1);
return if $newsize eq '';
$scale = $newsize / $cursize * 100;
@@ -1137,7 +1176,7 @@ sub changescale {
# apply Z rotation before scaling
if ($model_instance->rotation != 0) {
- $model_object->rotate($model_instance->rotation, Z);
+ $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1));
$_->set_rotation(0) for @{ $model_object->instances };
}
@@ -1147,7 +1186,7 @@ sub changescale {
#FIXME Scale the layer height profile when $axis == Z?
#FIXME Scale the layer height ranges $axis == Z?
# object was already aligned to Z = 0, so no need to realign it
- $self->reset_thumbnail($obj_idx);
+# $self->reset_thumbnail($obj_idx);
} else {
my $scale;
if ($tosize) {
@@ -1171,7 +1210,7 @@ sub changescale {
$range->[1] *= $variation;
}
$_->set_scaling_factor($scale) for @{ $model_object->instances };
- $object->transform_thumbnail($self->{model}, $obj_idx);
+# $object->transform_thumbnail($self->{model}, $obj_idx);
}
# update print and start background processing
@@ -1188,13 +1227,17 @@ sub arrange {
$self->pause_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);
+ # 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);
+
+ # Update is not implemented in C++ so we cannot call this for now
+ $self->{appController}->arrange_model;
+
# ignore arrange failures on purpose: user has visual feedback and we don't need to warn him
# when parts don't fit in print bed
# Force auto center of the aligned grid of of objects on the print bed.
- $self->update(1);
+ $self->update(0);
}
sub split_object {
@@ -1256,7 +1299,7 @@ sub async_apply_config {
$self->{canvas3D}->Refresh if Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
# Hide the slicing results if the current slicing status is no more valid.
- $self->{"print_info_box_show"}->(0) if $invalidated;
+ $self->print_info_box_show(0) if $invalidated;
if (wxTheApp->{app_config}->get("background_processing")) {
if ($invalidated) {
@@ -1275,6 +1318,13 @@ sub async_apply_config {
$self->{gcode_preview_data}->reset;
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
$self->{preview3D}->reload_print if $self->{preview3D};
+
+ # We also need to reload 3D scene because of the wipe tower preview box
+ if ($self->{config}->wipe_tower) {
+ my $selections = $self->collect_selections;
+ Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
+ Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1) if $self->{canvas3D}
+ }
}
}
@@ -1487,6 +1537,11 @@ sub on_process_completed {
return if $error;
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
$self->{preview3D}->reload_print if $self->{preview3D};
+
+ # in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth:
+ my $selections = $self->collect_selections;
+ Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
+ Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
# if we have an export filename, start a new thread for exporting G-code
if ($self->{export_gcode_output_file}) {
@@ -1548,7 +1603,7 @@ sub on_export_completed {
$message = L("File added to print queue");
$do_print = 1;
} elsif ($self->{send_gcode_file}) {
- $message = L("Sending G-code file to the OctoPrint server...");
+ $message = L("Sending G-code file to the Printer Host ...");
$send_gcode = 1;
} else {
$message = L("G-code file exported to ") . $self->{export_gcode_output_file};
@@ -1564,9 +1619,10 @@ sub on_export_completed {
# Send $self->{send_gcode_file} to OctoPrint.
if ($send_gcode) {
- my $op = Slic3r::OctoPrint->new($self->{config});
- if ($op->send_gcode($self->{send_gcode_file})) {
- $self->statusbar->SetStatusText(L("OctoPrint upload finished."));
+ my $host = Slic3r::PrintHost::get_print_host($self->{config});
+
+ if ($host->send_gcode($self->{send_gcode_file})) {
+ $self->statusbar->SetStatusText(L("Upload to host finished."));
} else {
$self->statusbar->SetStatusText("");
}
@@ -1574,12 +1630,7 @@ sub on_export_completed {
$self->{print_file} = undef;
$self->{send_gcode_file} = undef;
- $self->{"print_info_cost"}->SetLabel(sprintf("%.2f" , $self->{print}->total_cost));
- $self->{"print_info_fil_g"}->SetLabel(sprintf("%.2f" , $self->{print}->total_weight));
- $self->{"print_info_fil_mm3"}->SetLabel(sprintf("%.2f" , $self->{print}->total_extruded_volume));
- $self->{"print_info_time"}->SetLabel($self->{print}->estimated_print_time);
- $self->{"print_info_fil_m"}->SetLabel(sprintf("%.2f" , $self->{print}->total_used_filament / 1000));
- $self->{"print_info_box_show"}->(1);
+ $self->print_info_box_show(1);
# this updates buttons status
$self->object_list_changed;
@@ -1589,6 +1640,69 @@ sub on_export_completed {
$self->{preview3D}->reload_print if $self->{preview3D};
}
+# Fill in the "Sliced info" box with the result of the G-code generator.
+sub print_info_box_show {
+ my ($self, $show) = @_;
+ my $scrolled_window_panel = $self->{scrolled_window_panel};
+ my $scrolled_window_sizer = $self->{scrolled_window_sizer};
+ return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show));
+
+ if ($show) {
+ my $print_info_sizer = $self->{print_info_sizer};
+ $print_info_sizer->Clear(1);
+ my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5);
+ $grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
+ $grid_sizer->AddGrowableCol(1, 1);
+ $grid_sizer->AddGrowableCol(3, 1);
+ $print_info_sizer->Add($grid_sizer, 0, wxEXPAND);
+ my $is_wipe_tower = $self->{print}->total_wipe_tower_filament > 0;
+ my @info = (
+ L("Used Filament (m)")
+ => $is_wipe_tower ?
+ sprintf("%.2f (%.2f %s + %.2f %s)" , $self->{print}->total_used_filament / 1000,
+ ($self->{print}->total_used_filament - $self->{print}->total_wipe_tower_filament) / 1000,
+ L("objects"),
+ $self->{print}->total_wipe_tower_filament / 1000,
+ L("wipe tower")) :
+ sprintf("%.2f" , $self->{print}->total_used_filament / 1000),
+
+ L("Used Filament (mm³)")
+ => sprintf("%.2f" , $self->{print}->total_extruded_volume),
+ L("Used Filament (g)"),
+ => sprintf("%.2f" , $self->{print}->total_weight),
+ L("Cost"),
+ => $is_wipe_tower ?
+ sprintf("%.2f (%.2f %s + %.2f %s)" , $self->{print}->total_cost,
+ ($self->{print}->total_cost - $self->{print}->total_wipe_tower_cost),
+ L("objects"),
+ $self->{print}->total_wipe_tower_cost,
+ L("wipe tower")) :
+ sprintf("%.2f" , $self->{print}->total_cost),
+ L("Estimated printing time (normal mode)")
+ => $self->{print}->estimated_normal_print_time,
+ L("Estimated printing time (silent mode)")
+ => $self->{print}->estimated_silent_print_time
+ );
+ # if there is a wipe tower, insert number of toolchanges info into the array:
+ splice (@info, 8, 0, L("Number of tool changes") => sprintf("%.d", $self->{print}->m_wipe_tower_number_of_toolchanges)) if ($is_wipe_tower);
+
+ while ( my $label = shift @info) {
+ my $value = shift @info;
+ next if $value eq "N/A";
+ my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+ $text->SetFont($Slic3r::GUI::small_font);
+ $grid_sizer->Add($text, 0);
+ my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+ $field->SetFont($Slic3r::GUI::small_font);
+ $grid_sizer->Add($field, 0);
+ }
+ }
+
+ $scrolled_window_sizer->Show(2, $show);
+ $scrolled_window_panel->Layout;
+ $self->Layout;
+}
+
sub do_print {
my ($self) = @_;
@@ -1621,7 +1735,7 @@ sub reload_from_disk {
my $model_object = $self->{model}->objects->[$obj_idx];
#FIXME convert to local file encoding
return if !$model_object->input_file
- || !-e $model_object->input_file;
+ || !-e Slic3r::encode_path($model_object->input_file);
my @new_obj_idx = $self->load_files([$model_object->input_file]);
return if !@new_obj_idx;
@@ -1758,10 +1872,10 @@ sub _get_export_file {
return $output_file;
}
-sub reset_thumbnail {
- my ($self, $obj_idx) = @_;
- $self->{objects}[$obj_idx]->thumbnail(undef);
-}
+#sub reset_thumbnail {
+# my ($self, $obj_idx) = @_;
+# $self->{objects}[$obj_idx]->thumbnail(undef);
+#}
# this method gets called whenever print center is changed or the objects' bounding box changes
# (i.e. when an object is added/removed/moved/rotated/scaled)
@@ -1785,7 +1899,9 @@ sub update {
$self->resume_background_process;
}
- $self->{canvas}->reload_scene if $self->{canvas};
+ $self->print_info_box_show(0);
+
+# $self->{canvas}->reload_scene if $self->{canvas};
my $selections = $self->collect_selections;
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
@@ -1842,7 +1958,7 @@ sub on_config_change {
foreach my $opt_key (@{$self->{config}->diff($config)}) {
$self->{config}->set($opt_key, $config->get($opt_key));
if ($opt_key eq 'bed_shape') {
- $self->{canvas}->update_bed_size;
+# $self->{canvas}->update_bed_size;
Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D};
Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
$update_scheduled = 1;
@@ -1851,8 +1967,8 @@ sub on_config_change {
} elsif ($opt_key eq 'serial_port') {
$self->{btn_print}->Show($config->get('serial_port'));
$self->Layout;
- } elsif ($opt_key eq 'octoprint_host') {
- $self->{btn_send_gcode}->Show($config->get('octoprint_host'));
+ } elsif ($opt_key eq 'print_host') {
+ $self->{btn_send_gcode}->Show($config->get('print_host'));
$self->Layout;
} elsif ($opt_key eq 'variable_layer_height') {
if ($config->get('variable_layer_height') != 1) {
@@ -1902,7 +2018,7 @@ sub list_item_deselected {
$self->{_lecursor} = Wx::BusyCursor->new();
if ($self->{list}->GetFirstSelected == -1) {
$self->select_object(undef);
- $self->{canvas}->Refresh;
+# $self->{canvas}->Refresh;
Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}) if $self->{canvas3D};
Slic3r::GUI::_3DScene::render($self->{canvas3D}) if $self->{canvas3D};
}
@@ -1915,7 +2031,7 @@ sub list_item_selected {
$self->{_lecursor} = Wx::BusyCursor->new();
my $obj_idx = $event->GetIndex;
$self->select_object($obj_idx);
- $self->{canvas}->Refresh;
+# $self->{canvas}->Refresh;
if ($self->{canvas3D}) {
my $selections = $self->collect_selections;
Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
@@ -2012,19 +2128,19 @@ sub object_settings_dialog {
$self->pause_background_process;
$dlg->ShowModal;
- # update thumbnail since parts may have changed
- if ($dlg->PartsChanged) {
- # recenter and re-align to Z = 0
- $model_object->center_around_origin;
- $self->reset_thumbnail($obj_idx);
- }
+# # update thumbnail since parts may have changed
+# if ($dlg->PartsChanged) {
+# # recenter and re-align to Z = 0
+# $model_object->center_around_origin;
+# $self->reset_thumbnail($obj_idx);
+# }
# 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->{canvas}->reload_scene if $self->{canvas};
my $selections = $self->collect_selections;
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
@@ -2056,7 +2172,8 @@ sub object_list_changed {
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
my $model_fits = $self->{canvas3D} ? Slic3r::GUI::_3DScene::check_volumes_outside_state($self->{canvas3D}, $self->{config}) : 1;
- my $method = ($have_objects && ! $export_in_progress && $model_fits) ? 'Enable' : 'Disable';
+ # $model_fits == 1 -> ModelInstance::PVS_Partly_Outside
+ my $method = ($have_objects && ! $export_in_progress && ($model_fits != 1)) ? 'Enable' : 'Disable';
$self->{"btn_$_"}->$method
for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
}
@@ -2309,48 +2426,48 @@ package Slic3r::GUI::Plater::Object;
use Moo;
has 'name' => (is => 'rw', required => 1);
-has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms
-has 'transformed_thumbnail' => (is => 'rw');
-has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units
+#has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms
+#has 'transformed_thumbnail' => (is => 'rw');
+#has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units
has 'selected' => (is => 'rw', default => sub { 0 });
-sub make_thumbnail {
- my ($self, $model, $obj_idx) = @_;
- # make method idempotent
- $self->thumbnail->clear;
- # raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
- my $mesh = $model->objects->[$obj_idx]->raw_mesh;
-#FIXME The "correct" variant could be extremely slow.
-# if ($mesh->facets_count <= 5000) {
-# # remove polygons with area <= 1mm
-# my $area_threshold = Slic3r::Geometry::scale 1;
-# $self->thumbnail->append(
-# grep $_->area >= $area_threshold,
-# @{ $mesh->horizontal_projection }, # horizontal_projection returns scaled expolygons
-# );
-# $self->thumbnail->simplify(0.5);
-# } else {
- my $convex_hull = Slic3r::ExPolygon->new($mesh->convex_hull);
- $self->thumbnail->append($convex_hull);
-# }
- return $self->thumbnail;
-}
-
-sub transform_thumbnail {
- my ($self, $model, $obj_idx) = @_;
-
- return unless defined $self->thumbnail;
-
- my $model_object = $model->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- # the order of these transformations MUST be the same everywhere, including
- # in Slic3r::Print->add_model_object()
- my $t = $self->thumbnail->clone;
- $t->rotate($model_instance->rotation, Slic3r::Point->new(0,0));
- $t->scale($model_instance->scaling_factor);
-
- $self->transformed_thumbnail($t);
-}
+#sub make_thumbnail {
+# my ($self, $model, $obj_idx) = @_;
+# # make method idempotent
+# $self->thumbnail->clear;
+# # raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
+# my $mesh = $model->objects->[$obj_idx]->raw_mesh;
+##FIXME The "correct" variant could be extremely slow.
+## if ($mesh->facets_count <= 5000) {
+## # remove polygons with area <= 1mm
+## my $area_threshold = Slic3r::Geometry::scale 1;
+## $self->thumbnail->append(
+## grep $_->area >= $area_threshold,
+## @{ $mesh->horizontal_projection }, # horizontal_projection returns scaled expolygons
+## );
+## $self->thumbnail->simplify(0.5);
+## } else {
+# my $convex_hull = Slic3r::ExPolygon->new($mesh->convex_hull);
+# $self->thumbnail->append($convex_hull);
+## }
+# return $self->thumbnail;
+#}
+#
+#sub transform_thumbnail {
+# my ($self, $model, $obj_idx) = @_;
+#
+# return unless defined $self->thumbnail;
+#
+# my $model_object = $model->objects->[$obj_idx];
+# my $model_instance = $model_object->instances->[0];
+#
+# # the order of these transformations MUST be the same everywhere, including
+# # in Slic3r::Print->add_model_object()
+# my $t = $self->thumbnail->clone;
+# $t->rotate($model_instance->rotation, Slic3r::Point->new(0,0));
+# $t->scale($model_instance->scaling_factor);
+#
+# $self->transformed_thumbnail($t);
+#}
1;