diff --git a/lib/Slic3r/GUI/2DBed.pm b/lib/Slic3r/GUI/2DBed.pm index dd2cbdb1e..6a3e26a9f 100644 --- a/lib/Slic3r/GUI/2DBed.pm +++ b/lib/Slic3r/GUI/2DBed.pm @@ -5,8 +5,8 @@ use warnings; use List::Util qw(min max); use Slic3r::Geometry qw(PI X Y unscale deg2rad); use Slic3r::Geometry::Clipper qw(intersection_pl); -use Wx qw(:misc :pen :brush :font wxTAB_TRAVERSAL); -use Wx::Event qw(EVT_PAINT EVT_MOUSE_EVENTS); +use Wx qw(:misc :pen :brush :font :systemsettings wxTAB_TRAVERSAL wxSOLID); +use Wx::Event qw(EVT_PAINT EVT_ERASE_BACKGROUND EVT_MOUSE_EVENTS EVT_SIZE); use base qw(Wx::Panel Class::Accessor); __PACKAGE__->mk_accessors(qw(bed_shape interactive pos _scale_factor _shift on_move)); @@ -15,19 +15,33 @@ sub new { my ($class, $parent, $bed_shape) = @_; my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, [250,-1], wxTAB_TRAVERSAL); + $self->{user_drawn_background} = $^O ne 'darwin'; $self->bed_shape($bed_shape // []); EVT_PAINT($self, \&_repaint); + EVT_ERASE_BACKGROUND($self, sub {}) if $self->{user_drawn_background}; EVT_MOUSE_EVENTS($self, \&_mouse_event); - + EVT_SIZE($self, sub { $self->Refresh; }); return $self; } sub _repaint { - my ($self) = @_; + my ($self, $event) = @_; my $dc = Wx::AutoBufferedPaintDC->new($self); my ($cw, $ch) = $self->GetSizeWH; return if $cw == 0; # when canvas is not rendered yet, size is 0,0 + + if ($self->{user_drawn_background}) { + # On all systems the AutoBufferedPaintDC() achieves double buffering. + # On MacOS the background is erased, on Windows the background is not erased + # and on Linux/GTK the background is erased to gray color. + # Fill DC with the background on Windows & Linux/GTK. + my $color = Wx::SystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT); + $dc->SetPen(Wx::Pen->new($color, 1, wxSOLID)); + $dc->SetBrush(Wx::Brush->new($color, wxSOLID)); + my $rect = $self->GetUpdateRegion()->GetBox(); + $dc->DrawRectangle($rect->GetLeft(), $rect->GetTop(), $rect->GetWidth(), $rect->GetHeight()); + } # turn $cw and $ch from sizes to max coordinates $cw--; @@ -39,11 +53,12 @@ sub _repaint { ]); # leave space for origin point - $cbb->set_x_min($cbb->x_min + 2); - $cbb->set_y_max($cbb->y_max - 2); + $cbb->set_x_min($cbb->x_min + 4); + $cbb->set_x_max($cbb->x_max - 4); + $cbb->set_y_max($cbb->y_max - 4); # leave space for origin label - $cbb->set_y_max($cbb->y_max - 10); + $cbb->set_y_max($cbb->y_max - 13); # read new size ($cw, $ch) = @{$cbb->size}; diff --git a/lib/Slic3r/GUI/BedShapeDialog.pm b/lib/Slic3r/GUI/BedShapeDialog.pm index ee794a261..49c8b9e07 100644 --- a/lib/Slic3r/GUI/BedShapeDialog.pm +++ b/lib/Slic3r/GUI/BedShapeDialog.pm @@ -133,11 +133,14 @@ sub on_change { $self->{on_change} = $cb // sub {}; } +# Called from the constructor. +# Set the initial bed shape from a list of points. +# Deduce the bed shape type (rect, circle, custom) +# This routine shall be smart enough if the user messes up +# with the list of points in the ini file directly. sub _set_shape { my ($self, $points) = @_; - $self->{bed_shape} = $points; - # is this a rectangle? if (@$points == 4) { my $polygon = Slic3r::Polygon->new_scale(@$points); @@ -164,6 +167,7 @@ sub _set_shape { # is this a circle? { + # Analyze the array of points. Do they reside on a circle? my $polygon = Slic3r::Polygon->new_scale(@$points); my $center = $polygon->bounding_box->center; my @vertex_distances = map $center->distance_to($_), @$polygon; @@ -178,10 +182,24 @@ sub _set_shape { } } + if (@$points < 3) { + # Invalid polygon. Revert to default bed dimensions. + $self->{shape_options_book}->SetSelection(SHAPE_RECTANGULAR); + my $optgroup = $self->{optgroups}[SHAPE_RECTANGULAR]; + $optgroup->set_value('rect_size', [200, 200]); + $optgroup->set_value('rect_origin', [0, 0]); + $self->_update_shape; + return; + } + + # This is a custom bed shape, use the polygon provided. $self->{shape_options_book}->SetSelection(SHAPE_CUSTOM); + # Copy the polygon to the canvas, make a copy of the array. + $self->{canvas}->bed_shape([@$points]); $self->_update_shape; } +# Update the bed shape from the dialog fields. sub _update_shape { my ($self) = @_; @@ -229,8 +247,11 @@ sub _update_shape { sub _update_preview { my ($self) = @_; $self->{canvas}->Refresh if $self->{canvas}; + $self->Refresh; } +# Called from the constructor. +# Create a panel for a rectangular / circular / custom bed shape. sub _init_shape_options_page { my ($self, $title) = @_; @@ -252,6 +273,7 @@ sub _init_shape_options_page { return $optgroup; } +# Loads an stl file, projects it to the XY plane and calculates a polygon. sub _load_stl { my ($self) = @_; @@ -266,7 +288,7 @@ sub _load_stl { my $model = Slic3r::Model->read_from_file($input_file); my $mesh = $model->raw_mesh; my $expolygons = $mesh->horizontal_projection; - + if (@$expolygons == 0) { Slic3r::GUI::show_error($self, "The selected file contains no geometry."); return; @@ -277,9 +299,11 @@ sub _load_stl { } my $polygon = $expolygons->[0]->contour; - $self->{canvas}->bed_shape([ map [ unscale($_->x), unscale($_->y) ], @$polygon ]); #)) + $self->{canvas}->bed_shape([ map [ unscale($_->x), unscale($_->y) ], @$polygon ]); + $self->_update_preview(); } +# Returns the resulting bed shape polygon. This value will be stored to the ini file. sub GetValue { my ($self) = @_; return $self->{canvas}->bed_shape;