moved interactive layer control to settings dialog

This commit is contained in:
Florens Wasserfall 2017-04-05 18:53:49 +02:00
parent 8f2ff28cd9
commit 95d33df2f0
5 changed files with 196 additions and 201 deletions

View File

@ -25,7 +25,6 @@ use Slic3r::GUI::Plater::3D;
use Slic3r::GUI::Plater::3DPreview;
use Slic3r::GUI::Plater::ObjectPartsPanel;
use Slic3r::GUI::Plater::ObjectCutDialog;
use Slic3r::GUI::Plater::ObjectLayersDialog;
use Slic3r::GUI::Plater::ObjectSettingsDialog;
use Slic3r::GUI::Plater::LambdaObjectDialog;
use Slic3r::GUI::Plater::OverrideSettingsPanel;

View File

@ -172,7 +172,7 @@ sub new {
$self->{htoolbar}->AddTool(TB_CUT, "Cut…", Wx::Bitmap->new($Slic3r::var->("package.png"), wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddSeparator;
$self->{htoolbar}->AddTool(TB_SETTINGS, "Settings…", Wx::Bitmap->new($Slic3r::var->("cog.png"), wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_LAYERS, "Layer heights…", Wx::Bitmap->new($Slic3r::var->("layers.png"), wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_LAYERS, "Layer heights…", Wx::Bitmap->new($Slic3r::var->("variable_layer_height.png"), wxBITMAP_TYPE_PNG), '');
} else {
my %tbar_buttons = (
add => "Add…",
@ -1386,7 +1386,7 @@ sub async_apply_config {
# reset preview canvases (invalidated contents will be hidden)
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
$self->{preview3D}->reload_print if $self->{preview3D};
$self->{ObjectLayersDialog}->reload_preview if $self->{ObjectLayersDialog};
$self->{AdaptiveLayersDialog}->reload_preview if $self->{AdaptiveLayersDialog};
if ($invalidated) {
if (!$Slic3r::GUI::Settings->{_}{background_processing}) {
@ -1463,7 +1463,7 @@ sub stop_background_process {
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
$self->{preview3D}->reload_print if $self->{preview3D};
$self->{ObjectLayersDialog}->reload_preview if $self->{ObjectLayersDialog};
$self->{AdaptiveLayersDialog}->reload_preview if $self->{AdaptiveLayersDialog};
if ($self->{process_thread}) {
Slic3r::debugf "Killing background process.\n";
@ -1610,7 +1610,7 @@ sub on_process_completed {
return if $error;
$self->{toolpaths2D}->reload_print if $self->{toolpaths2D};
$self->{preview3D}->reload_print if $self->{preview3D};
$self->{ObjectLayersDialog}->reload_preview if $self->{ObjectLayersDialog};
$self->{AdaptiveLayersDialog}->reload_preview if $self->{AdaptiveLayersDialog};
# if we have an export filename, start a new thread for exporting G-code
if ($self->{export_gcode_output_file}) {
@ -2108,32 +2108,12 @@ sub object_layers_dialog {
my $self = shift;
my ($obj_idx) = @_;
if (!defined $obj_idx) {
($obj_idx, undef) = $self->selected_object;
}
if (!$Slic3r::GUI::have_OpenGL) {
Slic3r::GUI::show_error($self, "Please install the OpenGL modules to use this feature (see build instructions).");
return;
}
$self->{ObjectLayersDialog} = Slic3r::GUI::Plater::ObjectLayersDialog->new($self,
object => $self->{objects}[$obj_idx],
model_object => $self->{model}->objects->[$obj_idx],
obj_idx => $obj_idx,
);
$self->{ObjectLayersDialog}->Show();
EVT_CLOSE($self->{ObjectLayersDialog}, sub {
my ($dlg, $event) = @_;
$dlg->Destroy;
$self->{ObjectLayersDialog} = undef;
});
$self->object_settings_dialog($obj_idx, adaptive_layers => 1);
}
sub object_settings_dialog {
my $self = shift;
my ($obj_idx) = @_;
my ($obj_idx, %params) = @_;
if (!defined $obj_idx) {
($obj_idx, undef) = $self->selected_object;
@ -2148,9 +2128,15 @@ sub object_settings_dialog {
my $dlg = Slic3r::GUI::Plater::ObjectSettingsDialog->new($self,
object => $self->{objects}[$obj_idx],
model_object => $model_object,
obj_idx => $obj_idx,
);
# store pointer to the adaptive layer tab to push preview updates
$self->{AdaptiveLayersDialog} = $dlg->{adaptive_layers};
# and jump directly to the tab if called by "promo-button"
$dlg->{tabpanel}->SetSelection(1) if $params{adaptive_layers};
$self->pause_background_process;
$dlg->ShowModal;
$self->{AdaptiveLayersDialog} = undef;
# update thumbnail since parts may have changed
if ($dlg->PartsChanged) {

View File

@ -1,150 +0,0 @@
package Slic3r::GUI::Plater::ObjectLayersDialog;
use strict;
use warnings;
use utf8;
use Slic3r::Geometry qw(PI X Y Z scale unscale);
use Slic3r::Print::State ':steps';
use List::Util qw(min max sum first);
use Wx qw(wxTheApp :dialog :id :misc :sizer :slider :statictext wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON EVT_SLIDER);
use base 'Wx::Dialog';
sub new {
my $class = shift;
my ($parent, %params) = @_;
my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
$self->{model_object} = $params{model_object};
my $model_object = $self->{model_object} = $params{model_object};
my $obj_idx = $self->{obj_idx} = $params{obj_idx};
my $plater = $self->{plater} = $parent;
my $object = $self->{plater}->{print}->get_object($self->{obj_idx});
$self->{update_spline_control} = 0;
# Initialize 3D toolpaths preview
if ($Slic3r::GUI::have_OpenGL) {
$self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self, $plater->{print});
$self->{preview3D}->canvas->set_auto_bed_shape;
$self->{preview3D}->canvas->SetSize([500,500]);
$self->{preview3D}->canvas->SetMinSize($self->{preview3D}->canvas->GetSize);
$self->{preview3D}->load_print;
$self->{preview3D}->canvas->zoom_to_volumes;
}
$self->{splineControl} = Slic3r::GUI::Plater::SplineControl->new($self, Wx::Size->new(150, 200), $model_object);
my $optgroup;
$optgroup = $self->{optgroup} = Slic3r::GUI::OptionsGroup->new(
parent => $self,
title => 'Adaptive quality %',
on_change => sub {
my ($opt_id) = @_;
# There seems to be an issue with wxWidgets 3.0.2/3.0.3, where the slider
# genates tens of events for a single value change.
# Only trigger the recalculation if the value changes
# or a live preview was activated and the mesh cut is not valid yet.
if ($self->{adaptive_quality} != $optgroup->get_value($opt_id)) {
$self->{adaptive_quality} = $optgroup->get_value($opt_id);
$self->{model_object}->config->set('adaptive_slicing_quality', $optgroup->get_value($opt_id));
# trigger re-slicing
$self->_trigger_slicing;
}
},
label_width => 0,
);
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'adaptive_slicing_quality',
type => 'slider',
label => '',
default => $object->config->get('adaptive_slicing_quality'),
min => 0,
max => 100,
full_width => 1,
));
$optgroup->get_field('adaptive_slicing_quality')->set_scale(1);
$self->{adaptive_quality} = $object->config->get('adaptive_slicing_quality');
# init quality slider
if(!$object->config->get('adaptive_slicing')) {
# disable slider
$optgroup->get_field('adaptive_slicing_quality')->disable;
}
my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
$right_sizer->Add($self->{splineControl}, 1, wxEXPAND | wxALL, 0);
$right_sizer->Add($optgroup->sizer, 0, wxEXPAND | wxALL, 0);
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{sizer}->Add($self->{preview3D}, 3, wxEXPAND | wxTOP | wxBOTTOM, 0) if $self->{preview3D};
$self->{sizer}->Add($right_sizer, 1, wxEXPAND | wxTOP | wxBOTTOM, 10);
$self->SetSizerAndFit($self->{sizer});
$self->SetSize([800, 600]);
$self->SetMinSize($self->GetSize);
# init spline control values
# determine min and max layer height from perimeter extruder capabilities.
my %extruders;
for my $region_id (0 .. ($object->region_count - 1)) {
foreach (qw(perimeter_extruder infill_extruder solid_infill_extruder)) {
my $extruder_id = $self->{plater}->{print}->get_region($region_id)->config->get($_)-1;
$extruders{$extruder_id} = $extruder_id;
}
}
my $min_height = max(map {$self->{plater}->{print}->config->get_at('min_layer_height', $_)} (values %extruders));
my $max_height = min(map {$self->{plater}->{print}->config->get_at('max_layer_height', $_)} (values %extruders));
$self->{splineControl}->set_size_parameters($min_height, $max_height, unscale($object->size->z));
$self->{splineControl}->on_layer_update(sub {
# trigger re-slicing
$self->_trigger_slicing;
});
$self->{splineControl}->on_z_indicator(sub {
my ($z) = @_;
$self->{preview3D}->canvas->SetCuttingPlane(Z, $z, []);
$self->{preview3D}->canvas->Render;
});
return $self;
}
sub _trigger_slicing {
my ($self) = @_;
my $object = $self->{plater}->{print}->get_object($self->{obj_idx});
$self->{plater}->pause_background_process;
$self->{plater}->stop_background_process;
if (!$Slic3r::GUI::Settings->{_}{background_processing}) {
$self->{plater}->statusbar->SetCancelCallback(sub {
$self->{plater}->stop_background_process;
$self->{plater}->statusbar->SetStatusText("Slicing cancelled");
$self->{plater}->preview_notebook->SetSelection(0);
});
$self->{plater}->{print}->reload_object($self->{obj_idx});
$self->{plater}->on_model_change;
$self->{plater}->start_background_process;
}else{
$self->{plater}->{print}->reload_object($self->{obj_idx});
$self->{plater}->on_model_change;
$self->{plater}->schedule_background_process;
}
}
sub reload_preview {
my ($self) = @_;
$self->{splineControl}->update;
$self->{preview3D}->reload_print;
my $object = $self->{plater}->{print}->get_object($self->{obj_idx});
if($object->layer_count-1 > 0) {
# causes segfault...
my $top_layer = $object->get_layer($object->layer_count-1);
$self->{preview3D}->set_z($top_layer->print_z);
}
}
1;

View File

@ -14,11 +14,16 @@ use base 'Wx::Dialog';
sub new {
my $class = shift;
my ($parent, %params) = @_;
my $self = $class->SUPER::new($parent, -1, "Settings for " . $params{object}->name, wxDefaultPosition, [700,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
my $self = $class->SUPER::new($parent, -1, "Settings for " . $params{object}->name, wxDefaultPosition, [1000,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
$self->{$_} = $params{$_} for keys %params;
$self->{tabpanel} = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL);
$self->{tabpanel}->AddPage($self->{parts} = Slic3r::GUI::Plater::ObjectPartsPanel->new($self->{tabpanel}, model_object => $params{model_object}), "Parts");
$self->{tabpanel}->AddPage($self->{adaptive_layers} = Slic3r::GUI::Plater::ObjectDialog::AdaptiveLayersTab->new( $self->{tabpanel},
plater => $parent,
model_object => $params{model_object},
obj_idx => $params{obj_idx}
), "Adaptive Layers");
$self->{tabpanel}->AddPage($self->{layers} = Slic3r::GUI::Plater::ObjectDialog::LayersTab->new($self->{tabpanel}), "Layers");
my $buttons = $self->CreateStdDialogButtonSizer(wxOK);
@ -62,6 +67,157 @@ sub model_object {
return $self->GetParent->GetParent->{model_object};
}
package Slic3r::GUI::Plater::ObjectDialog::AdaptiveLayersTab;
use Slic3r::Geometry qw(X Y Z scale unscale);
use List::Util qw(min max sum first);
use Wx qw(wxTheApp :dialog :id :misc :sizer :systemsettings :statictext wxTAB_TRAVERSAL);
use base 'Slic3r::GUI::Plater::ObjectDialog::BaseTab';
sub new {
my $class = shift;
my ($parent, %params) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize);
my $model_object = $self->{model_object} = $params{model_object};
my $obj_idx = $self->{obj_idx} = $params{obj_idx};
my $plater = $self->{plater} = $params{plater};
my $object = $self->{plater}->{print}->get_object($self->{obj_idx});
# Initialize 3D toolpaths preview
if ($Slic3r::GUI::have_OpenGL) {
$self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self, $plater->{print});
$self->{preview3D}->canvas->set_auto_bed_shape;
$self->{preview3D}->canvas->SetSize([500,500]);
$self->{preview3D}->canvas->SetMinSize($self->{preview3D}->canvas->GetSize);
# object already processed?
wxTheApp->CallAfter(sub {
if (!$plater->{processed}) {
$self->_trigger_slicing;
}else{
$self->{preview3D}->load_print;
$self->{preview3D}->canvas->zoom_to_volumes;
$self->{preview_zoomed} = 1;
}
});
}
$self->{splineControl} = Slic3r::GUI::Plater::SplineControl->new($self, Wx::Size->new(150, 200), $model_object);
my $optgroup;
$optgroup = $self->{optgroup} = Slic3r::GUI::OptionsGroup->new(
parent => $self,
title => 'Adaptive quality %',
on_change => sub {
my ($opt_id) = @_;
# There seems to be an issue with wxWidgets 3.0.2/3.0.3, where the slider
# genates tens of events for a single value change.
# Only trigger the recalculation if the value changes
# or a live preview was activated and the mesh cut is not valid yet.
if ($self->{adaptive_quality} != $optgroup->get_value($opt_id)) {
$self->{adaptive_quality} = $optgroup->get_value($opt_id);
$self->{model_object}->config->set('adaptive_slicing_quality', $optgroup->get_value($opt_id));
# trigger re-slicing
$self->_trigger_slicing;
}
},
label_width => 0,
);
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
opt_id => 'adaptive_slicing_quality',
type => 'slider',
label => '',
default => $object->config->get('adaptive_slicing_quality'),
min => 0,
max => 100,
full_width => 1,
));
$optgroup->get_field('adaptive_slicing_quality')->set_scale(1);
$self->{adaptive_quality} = $object->config->get('adaptive_slicing_quality');
# init quality slider
if(!$object->config->get('adaptive_slicing')) {
# disable slider
$optgroup->get_field('adaptive_slicing_quality')->disable;
}
my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
$right_sizer->Add($self->{splineControl}, 1, wxEXPAND | wxALL, 0);
$right_sizer->Add($optgroup->sizer, 0, wxEXPAND | wxALL, 0);
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{sizer}->Add($self->{preview3D}, 3, wxEXPAND | wxTOP | wxBOTTOM, 0) if $self->{preview3D};
$self->{sizer}->Add($right_sizer, 1, wxEXPAND | wxTOP | wxBOTTOM, 10);
$self->SetSizerAndFit($self->{sizer});
# init spline control values
# determine min and max layer height from perimeter extruder capabilities.
my %extruders;
for my $region_id (0 .. ($object->region_count - 1)) {
foreach (qw(perimeter_extruder infill_extruder solid_infill_extruder)) {
my $extruder_id = $self->{plater}->{print}->get_region($region_id)->config->get($_)-1;
$extruders{$extruder_id} = $extruder_id;
}
}
my $min_height = max(map {$self->{plater}->{print}->config->get_at('min_layer_height', $_)} (values %extruders));
my $max_height = min(map {$self->{plater}->{print}->config->get_at('max_layer_height', $_)} (values %extruders));
$self->{splineControl}->set_size_parameters($min_height, $max_height, unscale($object->size->z));
$self->{splineControl}->on_layer_update(sub {
# trigger re-slicing
$self->_trigger_slicing;
});
$self->{splineControl}->on_z_indicator(sub {
my ($z) = @_;
$self->{preview3D}->canvas->SetCuttingPlane(Z, $z, []);
$self->{preview3D}->canvas->Render;
});
return $self;
}
# This is called by the plater after processing to update the preview and spline
sub reload_preview {
my ($self) = @_;
$self->{splineControl}->update;
$self->{preview3D}->reload_print;
my $object = $self->{plater}->{print}->get_object($self->{obj_idx});
if($object->layer_count-1 > 0) {
my $top_layer = $object->get_layer($object->layer_count-1);
$self->{preview3D}->set_z($top_layer->print_z);
if(!$self->{preview_zoomed}) {
$self->{preview3D}->canvas->set_auto_bed_shape;
$self->{preview3D}->canvas->zoom_to_volumes;
$self->{preview_zoomed} = 1;
}
}
}
# Trigger background slicing at the plater
sub _trigger_slicing {
my ($self) = @_;
my $object = $self->{plater}->{print}->get_object($self->{obj_idx});
$self->{plater}->pause_background_process;
$self->{plater}->stop_background_process;
if (!$Slic3r::GUI::Settings->{_}{background_processing}) {
$self->{plater}->statusbar->SetCancelCallback(sub {
$self->{plater}->stop_background_process;
$self->{plater}->statusbar->SetStatusText("Slicing cancelled");
$self->{plater}->preview_notebook->SetSelection(0);
});
$self->{plater}->{print}->reload_object($self->{obj_idx});
$self->{plater}->on_model_change;
$self->{plater}->start_background_process;
}else{
$self->{plater}->{print}->reload_object($self->{obj_idx});
$self->{plater}->on_model_change;
$self->{plater}->schedule_background_process;
}
}
package Slic3r::GUI::Plater::ObjectDialog::LayersTab;
use Wx qw(:dialog :id :misc :sizer :systemsettings);
use Wx::Grid;

View File

@ -16,6 +16,7 @@ sub new {
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, $size, wxTAB_TRAVERSAL);
$self->{object} = $object;
$self->{is_valid} = 0;
# This has only effect on MacOS. On Windows and Linux/GTK, the background is painted by $self->repaint().
$self->SetBackgroundColour(Wx::wxWHITE);
@ -74,31 +75,33 @@ sub repaint {
$dc->DrawLabel(sprintf('%.4g', $self->{min_layer_height}), Wx::Rect->new(0, $size[1]/2, $size[0], $size[1]/2), wxALIGN_LEFT | wxALIGN_BOTTOM);
$dc->DrawLabel(sprintf('%.4g', $self->{max_layer_height}), Wx::Rect->new(0, $size[1]/2, $size[0], $size[1]/2), wxALIGN_RIGHT | wxALIGN_BOTTOM);
if($self->{is_valid}) {
# draw original spline as reference
if($self->{original_height_spline}) {
#draw spline
$self->_draw_layer_height_spline($dc, $self->{original_height_spline}, $self->{original_pen});
}
# draw interactive (currently modified by the user) layers as lines and spline
if($self->{interactive_height_spline}) {
# draw layer lines
my @interpolated_layers = @{$self->{interactive_height_spline}->getInterpolatedLayers};
$self->_draw_layers_as_lines($dc, $self->{interactive_pen}, \@interpolated_layers);
#draw spline
$self->_draw_layer_height_spline($dc, $self->{interactive_height_spline}, $self->{interactive_pen});
# draw original spline as reference
if($self->{original_height_spline}) {
#draw spline
$self->_draw_layer_height_spline($dc, $self->{original_height_spline}, $self->{original_pen});
}
# draw interactive (currently modified by the user) layers as lines and spline
if($self->{interactive_height_spline}) {
# draw layer lines
my @interpolated_layers = @{$self->{interactive_height_spline}->getInterpolatedLayers};
$self->_draw_layers_as_lines($dc, $self->{interactive_pen}, \@interpolated_layers);
#draw spline
$self->_draw_layer_height_spline($dc, $self->{interactive_height_spline}, $self->{interactive_pen});
}
# draw resulting layers as lines
unless($self->{interactive_heights}) {
$self->_draw_layers_as_lines($dc, $self->{resulting_pen}, $self->{interpolated_layers});
}
# Always draw current BSpline, gives a reference during a modification
$self->_draw_layer_height_spline($dc, $self->{object}->layer_height_spline, $self->{line_pen});
}
# draw resulting layers as lines
unless($self->{interactive_heights}) {
$self->_draw_layers_as_lines($dc, $self->{resulting_pen}, $self->{interpolated_layers});
}
# Always draw current BSpline, gives a reference during a modification
$self->_draw_layer_height_spline($dc, $self->{object}->layer_height_spline, $self->{line_pen});
$event->Skip;
}
@ -120,7 +123,7 @@ sub set_size_parameters {
sub update {
my $self = shift;
if($self->{object}->layer_height_spline->layersUpdated || !$self->{heights}) {
if(($self->{object}->layer_height_spline->layersUpdated || !$self->{heights}) && $self->{object}->layer_height_spline->hasData) {
$self->{original_height_spline} = $self->{object}->layer_height_spline->clone; # make a copy to display the unmodified original spline
$self->{original_layers} = $self->{object}->layer_height_spline->getOriginalLayers;
$self->{interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers; # Initialize to current values
@ -131,6 +134,7 @@ sub update {
foreach my $z (@{$self->{original_layers}}) {
push (@{$self->{heights}}, $self->{object}->layer_height_spline->getLayerHeightAt($z));
}
$self->{is_valid} = 1;
}
$self->Refresh;
}