Merge branch 'bedshape'

This commit is contained in:
Alessandro Ranellucci 2014-06-16 22:57:04 +02:00
commit 7cc0bce97d
20 changed files with 497 additions and 130 deletions

View file

@ -0,0 +1,200 @@
package Slic3r::GUI::BedShapeDialog;
use strict;
use warnings;
use utf8;
use List::Util qw(min max);
use Slic3r::Geometry qw(PI X Y unscale);
use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON EVT_CHOICE);
use base 'Wx::Dialog';
sub new {
my $class = shift;
my ($parent, $default) = @_;
my $self = $class->SUPER::new($parent, -1, "Bed Shape", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
$self->{panel} = my $panel = Slic3r::GUI::BedShapePanel->new($self, $default);
my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
$main_sizer->Add($panel, 1, wxEXPAND);
$main_sizer->Add($self->CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND);
$self->SetSizer($main_sizer);
$self->SetMinSize($self->GetSize);
$main_sizer->SetSizeHints($self);
# needed to actually free memory
EVT_CLOSE($self, sub {
$self->EndModal(wxID_OK);
$self->Destroy;
});
return $self;
}
sub GetValue {
my ($self) = @_;
return $self->{panel}->GetValue;
}
package Slic3r::GUI::BedShapePanel;
use List::Util qw(min max);
use Slic3r::Geometry qw(PI X Y unscale);
use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON EVT_CHOICE);
use base 'Wx::Panel';
use constant SHAPE_RECTANGULAR => 0;
use constant SHAPE_CIRCULAR => 1;
use constant SHAPE_CUSTOM => 2;
sub new {
my $class = shift;
my ($parent, $default) = @_;
my $self = $class->SUPER::new($parent, -1);
$self->on_change(undef);
my $box = Wx::StaticBox->new($self, -1, "Shape");
my $sbsizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
# shape options
$self->{shape_options_book} = Wx::Choicebook->new($self, -1, wxDefaultPosition, [300,-1], wxCHB_TOP);
$sbsizer->Add($self->{shape_options_book});
$self->{optgroups} = [];
$self->_init_shape_options_page('Rectangular', [
{
opt_key => 'rect_size',
type => 'point',
label => 'Size',
tooltip => 'Size in X and Y of the rectangular plate.',
default => [200,200],
},
{
opt_key => 'rect_origin',
type => 'select',
label => 'Origin',
tooltip => 'Position of the 0,0 point.',
labels => ['Front left corner','Center'],
values => ['corner','center'],
default => 'corner',
},
]);
# right pane with preview canvas
my $canvas;
# main sizer
my $top_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$top_sizer->Add($sbsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
$top_sizer->Add($canvas, 1, wxEXPAND | wxALL, 0) if $canvas;
$self->SetSizerAndFit($top_sizer);
$self->_set_shape($default);
$self->_update_preview;
return $self;
}
sub on_change {
my ($self, $cb) = @_;
$self->{on_change} = $cb // sub {};
}
sub _set_shape {
my ($self, $points) = @_;
$self->{bed_shape} = $points;
# is this a rectangle?
if (@$points == 4) {
my $polygon = Slic3r::Polygon->new_scale(@$points);
my $lines = $polygon->lines;
if ($lines->[0]->parallel_to_line($lines->[2]) && $lines->[1]->parallel_to_line($lines->[3])) {
# okay, it's a rectangle
# let's check whether origin is at a known point
my $x_min = min(map $_->[X], @$points);
my $x_max = max(map $_->[X], @$points);
my $y_min = min(map $_->[Y], @$points);
my $y_max = max(map $_->[Y], @$points);
my $origin;
if ($x_min == 0 && $y_min == 0) {
$origin = 'corner';
} elsif (($x_min + $x_max)/2 == 0 && ($y_min + $y_max)/2 == 0) {
$origin = 'center';
}
if (defined $origin) {
$self->{shape_options_book}->SetSelection(SHAPE_RECTANGULAR);
my $optgroup = $self->{optgroups}[SHAPE_RECTANGULAR];
$optgroup->set_value('rect_size', [ $x_max-$x_min, $y_max-$y_min ]);
$optgroup->set_value('rect_origin', $origin);
return;
}
}
}
$self->{shape_options_book}->SetSelection(SHAPE_CUSTOM);
}
sub _update_shape {
my ($self) = @_;
my $page_idx = $self->{shape_options_book}->GetSelection;
if ($page_idx == SHAPE_RECTANGULAR) {
return if grep !defined($self->{"_$_"}), qw(rect_size rect_origin); # not loaded yet
my ($x, $y) = @{$self->{_rect_size}};
my ($x0, $y0) = (0,0);
my ($x1, $y1) = ($x,$y);
if ($self->{_rect_origin} eq 'center') {
$x0 -= $x/2;
$x1 -= $x/2;
$y0 -= $y/2;
$y1 -= $y/2;
}
$self->{bed_shape} = [
[$x0,$y0],
[$x1,$y0],
[$x1,$y1],
[$x0,$y1],
];
}
$self->{on_change}->();
$self->_update_preview;
}
sub _update_preview {
my ($self) = @_;
}
sub _init_shape_options_page {
my ($self, $title, $options) = @_;
my $panel = Wx::Panel->new($self->{shape_options_book});
push @{$self->{optgroups}}, my $optgroup = Slic3r::GUI::OptionsGroup->new(
parent => $panel,
title => 'Settings',
options => $options,
on_change => sub {
my ($opt_key, $value) = @_;
$self->{"_$opt_key"} = $value;
$self->_update_shape;
},
label_width => 100,
);
$panel->SetSizerAndFit($optgroup->sizer);
$self->{shape_options_book}->AddPage($panel, $title);
}
sub GetValue {
my ($self) = @_;
return $self->{bed_shape};
}
1;

View file

@ -5,6 +5,7 @@ use utf8;
use Wx;
use base 'Wx::Wizard';
use Slic3r::Geometry qw(unscale);
# adhere to various human interface guidelines
our $wizard = 'Wizard';
@ -52,9 +53,13 @@ sub run {
# it would be cleaner to have these defined inside each page class,
# in some event getting called before leaving the page
{
# set print_center to centre of bed_size
my $bed_size = $self->{config}->bed_size;
$self->{config}->set('print_center', [$bed_size->[0]/2, $bed_size->[1]/2]);
# set print_center to center of bed_shape
{
my $bed_shape = $self->{config}->bed_shape;
my $polygon = Slic3r::Polygon->new_scale(@$bed_shape);
my $center = $polygon->centroid;
$self->{config}->set('print_center', [ map unscale($_), @$center ]);
}
# set first_layer_height + layer_height based on nozzle_diameter
my $nozzle = $self->{config}->nozzle_diameter;
@ -204,19 +209,24 @@ sub append_option {
# populate repository with the factory default
my $opt_key = $full_key;
$opt_key =~ s/#.+//;
$self->GetParent->{config}->apply(Slic3r::Config->new_from_defaults($opt_key));
$self->config->apply(Slic3r::Config->new_from_defaults($opt_key));
# draw the control
my $optgroup = Slic3r::GUI::ConfigOptionsGroup->new(
parent => $self,
title => '',
config => $self->GetParent->{config},
config => $self->config,
options => [$full_key],
full_labels => 1,
);
$self->{vsizer}->Add($optgroup->sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
}
sub append_panel {
my ($self, $panel) = @_;
$self->{vsizer}->Add($panel, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
}
sub set_previous_page {
my $self = shift;
my ($previous_page) = @_;
@ -253,6 +263,11 @@ sub build_index {
$self->{index}->append_title($page->get_short_title) while ($page = $page->GetNext);
}
sub config {
my ($self) = @_;
return $self->GetParent->{config};
}
package Slic3r::GUI::ConfigWizard::Page::Welcome;
use base 'Slic3r::GUI::ConfigWizard::Page';
@ -290,9 +305,14 @@ sub new {
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Bed Size');
$self->append_text('Enter the size of your printers bed, then click Next.');
$self->append_option('bed_size');
$self->append_text('Set the shape of your printer\'s bed, then click Next.');
$self->config->apply(Slic3r::Config->new_from_defaults('bed_shape'));
$self->{bed_shape_panel} = my $panel = Slic3r::GUI::BedShapePanel->new($self, $self->config->bed_shape);
$self->{bed_shape_panel}->on_change(sub {
$self->config->set('bed_shape', $self->{bed_shape_panel}->GetValue);
});
$self->append_panel($self->{bed_shape_panel});
return $self;
}
@ -304,7 +324,7 @@ sub new {
my ($parent) = @_;
my $self = $class->SUPER::new($parent, 'Nozzle Diameter');
$self->append_text('Enter the diameter of your printers hot end nozzle, then click Next.');
$self->append_text('Enter the diameter of your printer\'s hot end nozzle, then click Next.');
$self->append_option('nozzle_diameter#0');
return $self;

View file

@ -48,6 +48,7 @@ has 'options' => (is => 'ro', required => 1, trigger => 1);
has 'lines' => (is => 'lazy');
has 'on_change' => (is => 'ro', default => sub { sub {} });
has 'no_labels' => (is => 'ro', default => sub { 0 });
has 'staticbox' => (is => 'ro', default => sub { 1 });
has 'label_width' => (is => 'ro', default => sub { 180 });
has 'extra_column' => (is => 'ro');
has 'label_font' => (is => 'ro');
@ -63,9 +64,11 @@ sub _trigger_options {}
sub BUILD {
my $self = shift;
{
if ($self->staticbox) {
my $box = Wx::StaticBox->new($self->parent, -1, $self->title);
$self->sizer(Wx::StaticBoxSizer->new($box, wxVERTICAL));
} else {
$self->sizer(Wx::BoxSizer->new(wxVERTICAL));
}
my $num_columns = $self->extra_column ? 3 : 2;
@ -77,11 +80,18 @@ sub BUILD {
$self->sizer->Add($grid_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 5);
foreach my $line (@{$self->lines}) {
# build default callbacks in case we don't call _build_line() below
foreach my $opt_key (@{$line->{options}}) {
my $opt = first { $_->{opt_key} eq $opt_key } @{$self->options};
$self->_setters->{$opt_key} //= sub {};
$self->_triggers->{$opt_key} = $opt->{on_change} || sub { return 1 };
}
if ($line->{sizer}) {
$self->sizer->Add($line->{sizer}, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
} elsif ($line->{widget}) {
my $window = $line->{widget}->GetWindow($self->parent);
$self->sizer->Add($window, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
} elsif ($line->{widget} && $line->{full_width}) {
my $sizer = $line->{widget}->($self->parent);
$self->sizer->Add($sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
} else {
$self->_build_line($line, $grid_sizer);
}
@ -140,10 +150,10 @@ sub _build_line {
my @field_labels = ();
foreach my $opt_key (@{$line->{options}}) {
my $opt = first { $_->{opt_key} eq $opt_key } @{$self->options};
push @fields, $self->_build_field($opt);
push @fields, $self->_build_field($opt) unless $line->{widget};
push @field_labels, $opt->{label};
}
if (@fields > 1 || $line->{sidetext}) {
if (@fields > 1 || $line->{widget} || $line->{sidetext}) {
my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
for my $i (0 .. $#fields) {
if (@fields > 1 && $field_labels[$i]) {
@ -153,7 +163,10 @@ sub _build_line {
}
$sizer->Add($fields[$i], 0, wxALIGN_CENTER_VERTICAL, 0);
}
if ($line->{sidetext}) {
if ($line->{widget}) {
my $widget_sizer = $line->{widget}->($self->parent);
$sizer->Add($widget_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15);
} elsif ($line->{sidetext}) {
my $sidetext = Wx::StaticText->new($self->parent, -1, $line->{sidetext}, wxDefaultPosition, wxDefaultSize);
$sidetext->SetFont($self->sidetext_font);
$sizer->Add($sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL , 4);
@ -169,7 +182,6 @@ sub _build_field {
my ($opt) = @_;
my $opt_key = $opt->{opt_key};
$self->_triggers->{$opt_key} = $opt->{on_change} || sub { return 1 };
my $on_kill_focus = sub {
my ($s, $event) = @_;
@ -363,6 +375,7 @@ has '+ignore_on_change_return' => (is => 'ro', default => sub { 0 });
sub _trigger_options {
my $self = shift;
$self->SUPER::_trigger_options;
@{$self->options} = map {
my $opt = $_;
if (ref $opt ne 'HASH') {
@ -408,10 +421,17 @@ sub set_value {
if ($key eq $opt_key) {
$self->config->set($key, $value);
$self->SUPER::set_value($full_key, $self->_get_config($key, $index));
$changed = 1;
return 1;
}
}
return $changed;
# if we're here, we know this option but we found no setter, so we just propagate it
if ($self->config->has($opt_key)) {
$self->config->set($opt_key, $value);
$self->SUPER::set_value($opt_key, $value);
return 1;
}
return 0;
}
sub on_kill_focus {
@ -479,26 +499,24 @@ sub _config_methods {
}
package Slic3r::GUI::OptionsGroup::StaticTextLine;
use Moo;
use Wx qw(:misc :systemsettings);
use base 'Wx::StaticText';
sub GetWindow {
my $self = shift;
my ($parent) = @_;
sub new {
my ($class, $parent) = @_;
$self->{statictext} = Wx::StaticText->new($parent, -1, "foo", wxDefaultPosition, wxDefaultSize);
my $self = $class->SUPER::new($parent, -1, "", wxDefaultPosition, wxDefaultSize);
my $font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
$self->{statictext}->SetFont($font);
return $self->{statictext};
$self->SetFont($font);
return $self;
}
sub SetText {
my $self = shift;
my ($value) = @_;
my ($self, $value) = @_;
$self->{statictext}->SetLabel($value);
$self->{statictext}->Wrap(400);
$self->{statictext}->GetParent->Layout;
$self->SetLabel($value);
$self->Wrap(400);
$self->GetParent->Layout;
}
1;

View file

@ -38,7 +38,6 @@ our $ERROR_EVENT : shared = Wx::NewEventType;
our $EXPORT_COMPLETED_EVENT : shared = Wx::NewEventType;
our $PROCESS_COMPLETED_EVENT : shared = Wx::NewEventType;
use constant CANVAS_SIZE => [335,335];
use constant FILAMENT_CHOOSERS_SPACING => 3;
use constant PROCESS_DELAY => 0.5 * 1000; # milliseconds
@ -51,7 +50,7 @@ sub new {
my ($parent) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
$self->{config} = Slic3r::Config->new_from_defaults(qw(
bed_size print_center complete_objects extruder_clearance_radius skirts skirt_distance
bed_shape print_center complete_objects extruder_clearance_radius skirts skirt_distance
));
$self->{model} = Slic3r::Model->new;
$self->{print} = Slic3r::Print->new;
@ -69,7 +68,7 @@ sub new {
}
});
$self->{canvas} = Slic3r::GUI::Plater::2D->new($self, CANVAS_SIZE, $self->{objects}, $self->{model}, $self->{config});
$self->{canvas} = Slic3r::GUI::Plater::2D->new($self, [335,335], $self->{objects}, $self->{model}, $self->{config});
$self->{canvas}->on_select_object(sub {
my ($obj_idx) = @_;
$self->select_object($obj_idx);
@ -133,7 +132,7 @@ sub new {
}
}
$self->{list} = Wx::ListView->new($self, -1, wxDefaultPosition, wxDefaultSize, wxLC_SINGLE_SEL | wxLC_REPORT | wxBORDER_SUNKEN | wxTAB_TRAVERSAL | wxWANTS_CHARS);
$self->{list} = Wx::ListView->new($self, -1, wxDefaultPosition, [250,-1], wxLC_SINGLE_SEL | wxLC_REPORT | wxBORDER_SUNKEN | wxTAB_TRAVERSAL | wxWANTS_CHARS);
$self->{list}->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 145);
$self->{list}->InsertColumn(1, "Copies", wxLIST_FORMAT_CENTER, 45);
$self->{list}->InsertColumn(2, "Scale", wxLIST_FORMAT_CENTER, wxLIST_AUTOSIZE_USEHEADER);
@ -285,6 +284,7 @@ sub new {
{
my $box = Wx::StaticBox->new($self, -1, "Info");
$object_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
$object_info_sizer->SetMinSize([350,-1]);
my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5);
$grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
$grid_sizer->AddGrowableCol(1, 1);
@ -300,14 +300,14 @@ sub new {
);
while (my $field = shift @info) {
my $label = shift @info;
my $text = Wx::StaticText->new($self, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
my $text = Wx::StaticText->new($box, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
$text->SetFont($Slic3r::GUI::small_font);
$grid_sizer->Add($text, 0);
$self->{"object_info_$field"} = Wx::StaticText->new($self, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
$self->{"object_info_$field"} = Wx::StaticText->new($box, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
$self->{"object_info_$field"}->SetFont($Slic3r::GUI::small_font);
if ($field eq 'manifold') {
$self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self, -1, Wx::Bitmap->new("$Slic3r::var/error.png", wxBITMAP_TYPE_PNG));
$self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($box, -1, Wx::Bitmap->new("$Slic3r::var/error.png", wxBITMAP_TYPE_PNG));
$self->{object_info_manifold_warning_icon}->Hide;
my $h_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
@ -334,8 +334,8 @@ sub new {
$right_sizer->Add($object_info_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
$hsizer->Add($self->{canvas}, 0, wxTOP, 1);
$hsizer->Add($right_sizer, 1, wxEXPAND | wxBOTTOM, 0);
$hsizer->Add($self->{canvas}, 1, wxEXPAND | wxTOP, 1);
$hsizer->Add($right_sizer, 0, wxEXPAND | wxBOTTOM, 0);
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar};
@ -677,12 +677,7 @@ sub changescale {
sub arrange {
my $self = shift;
# get the bounding box of the model area shown in the viewport
my $bb = Slic3r::Geometry::BoundingBox->new_from_points([
Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units([0,0]) }),
Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units(CANVAS_SIZE) }),
]);
my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape);
eval {
$self->{model}->arrange_objects($self->GetFrame->config->min_object_distance, $bb);
};
@ -758,7 +753,8 @@ sub split_object {
sub schedule_background_process {
my ($self) = @_;
$self->{apply_config_timer}->Start(PROCESS_DELAY, 1); # 1 = one shot
$self->{apply_config_timer}->Start(PROCESS_DELAY, 1) # 1 = one shot
if defined $self->{apply_config_timer};
}
sub async_apply_config {
@ -841,7 +837,7 @@ sub start_background_process {
sub stop_background_process {
my ($self) = @_;
$self->{apply_config_timer}->Stop;
$self->{apply_config_timer}->Stop if defined $self->{apply_config_timer};
$self->statusbar->SetCancelCallback(undef);
$self->statusbar->StopBusy;
$self->statusbar->SetStatusText("");
@ -1147,7 +1143,7 @@ sub on_config_change {
$self->Layout;
} elsif ($self->{config}->has($opt_key)) {
$self->{config}->set($opt_key, $value);
if ($opt_key eq 'bed_size') {
if ($opt_key eq 'bed_shape') {
$self->{canvas}->update_bed_size;
$self->update;
}

View file

@ -3,11 +3,11 @@ use strict;
use warnings;
use utf8;
use List::Util qw(max first);
use List::Util qw(min max first);
use Slic3r::Geometry qw(X Y scale unscale convex_hull);
use Slic3r::Geometry::Clipper qw(offset JT_ROUND);
use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT);
use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT EVT_SIZE);
use base 'Wx::Panel';
use constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8'
@ -40,6 +40,9 @@ sub new {
EVT_PAINT($self, \&repaint);
EVT_MOUSE_EVENTS($self, \&mouse_event);
EVT_SIZE($self, sub {
$self->update_bed_size;
});
return $self;
}
@ -71,25 +74,27 @@ sub repaint {
my $size = $self->GetSize;
my @size = ($size->GetWidth, $size->GetHeight);
# draw grid
$dc->SetPen($self->{grid_pen});
my $step = 10 * $self->{scaling_factor};
for (my $x = $step; $x <= $size[X]; $x += $step) {
$dc->DrawLine($x, 0, $x, $size[Y]);
}
for (my $y = $step; $y <= $size[Y]; $y += $step) {
$dc->DrawLine(0, $y, $size[X], $y);
# draw bed
{
$dc->SetPen($self->{print_center_pen});
$dc->SetBrush($self->{transparent_brush});
$dc->DrawPolygon($self->scaled_points_to_pixel($self->{bed_polygon}, 1), 0, 0);
}
# draw grid
$dc->SetPen($self->{grid_pen});
$dc->DrawLine(map @$_, @$_) for @{$self->{grid}};
# draw print center
if (@{$self->{objects}}) {
if (@{$self->{objects}} && $Slic3r::GUI::Settings->{_}{autocenter}) {
my $center = $self->unscaled_point_to_pixel($self->{config}->print_center);
$dc->SetPen($self->{print_center_pen});
$dc->DrawLine($size[X]/2, 0, $size[X]/2, $size[Y]);
$dc->DrawLine(0, $size[Y]/2, $size[X], $size[Y]/2);
$dc->DrawLine($center->[X], 0, $center->[X], $size[Y]);
$dc->DrawLine(0, $center->[Y], $size[X], $center->[Y]);
$dc->SetTextForeground(Wx::Colour->new(0,0,0));
$dc->SetFont(Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL));
$dc->DrawLabel("X = " . $self->{config}->print_center->[X], Wx::Rect->new(0, 0, $self->GetSize->GetWidth, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM);
$dc->DrawRotatedText("Y = " . $self->{config}->print_center->[Y], 0, $size[Y]/2+15, 90);
$dc->DrawLabel("X = " . $self->{config}->print_center->[X], Wx::Rect->new(0, 0, $center->[X]*2, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM);
$dc->DrawRotatedText("Y = " . $self->{config}->print_center->[Y], 0, $center->[Y]+15, 90);
}
# draw frame
@ -131,7 +136,7 @@ sub repaint {
}
foreach my $expolygon (@$thumbnail) {
foreach my $points (@{$expolygon->pp}) {
$dc->DrawPolygon($self->points_to_pixel($points, 1), 0, 0);
$dc->DrawPolygon($self->scaled_points_to_pixel($points, 1), 0, 0);
}
}
@ -151,7 +156,7 @@ sub repaint {
my ($clearance) = @{offset([$thumbnail->convex_hull], (scale($self->{config}->extruder_clearance_radius) / 2), 1, JT_ROUND, scale(0.1))};
$dc->SetPen($self->{clearance_pen});
$dc->SetBrush($self->{transparent_brush});
$dc->DrawPolygon($self->points_to_pixel($clearance, 1), 0, 0);
$dc->DrawPolygon($self->scaled_points_to_pixel($clearance, 1), 0, 0);
}
}
}
@ -163,7 +168,7 @@ sub repaint {
my ($convex_hull) = @{offset([convex_hull(\@points)], scale($self->{config}->skirt_distance), 1, JT_ROUND, scale(0.1))};
$dc->SetPen($self->{skirt_pen});
$dc->SetBrush($self->{transparent_brush});
$dc->DrawPolygon($self->points_to_pixel($convex_hull, 1), 0, 0);
$dc->DrawPolygon($self->scaled_points_to_pixel($convex_hull, 1), 0, 0);
}
}
@ -173,16 +178,15 @@ sub repaint {
sub mouse_event {
my ($self, $event) = @_;
my $point = $event->GetPosition;
my $pos = $self->point_to_model_units([ $point->x, $point->y ]); #]]
$pos = Slic3r::Point->new_scale(@$pos);
my $pos = $event->GetPosition;
my $point = $self->point_to_model_units([ $pos->x, $pos->y ]); #]]
if ($event->ButtonDown) {
$self->{on_select_object}->(undef);
OBJECTS: for my $obj_idx (0 .. $#{$self->{objects}}) {
my $object = $self->{objects}->[$obj_idx];
for my $instance_idx (0 .. $#{ $object->instance_thumbnails }) {
my $thumbnail = $object->instance_thumbnails->[$instance_idx];
if (defined first { $_->contour->contains_point($pos) } @$thumbnail) {
if (defined first { $_->contour->contains_point($point) } @$thumbnail) {
$self->{on_select_object}->($obj_idx);
if ($event->LeftDown) {
@ -190,12 +194,12 @@ sub mouse_event {
my $instance = $self->{model}->objects->[$obj_idx]->instances->[$instance_idx];
my $instance_origin = [ map scale($_), @{$instance->offset} ];
$self->{drag_start_pos} = [ # displacement between the click and the instance origin in scaled model units
$pos->x - $instance_origin->[X],
$pos->y - $instance_origin->[Y], #-
$point->x - $instance_origin->[X],
$point->y - $instance_origin->[Y], #-
];
$self->{drag_object} = [ $obj_idx, $instance_idx ];
} elsif ($event->RightDown) {
$self->{on_right_click}->($point);
$self->{on_right_click}->($pos);
}
last OBJECTS;
@ -217,14 +221,14 @@ sub mouse_event {
my $model_object = $self->{model}->objects->[$obj_idx];
$model_object->instances->[$instance_idx]->set_offset(
Slic3r::Pointf->new(
unscale($pos->[X] - $self->{drag_start_pos}[X]),
unscale($pos->[Y] - $self->{drag_start_pos}[Y]),
unscale($point->[X] - $self->{drag_start_pos}[X]),
unscale($point->[Y] - $self->{drag_start_pos}[Y]),
));
$model_object->update_bounding_box;
$self->Refresh;
} elsif ($event->Moving) {
my $cursor = wxSTANDARD_CURSOR;
if (defined first { $_->contour->contains_point($pos) } map @$_, map @{$_->instance_thumbnails}, @{ $self->{objects} }) {
if (defined first { $_->contour->contains_point($point) } map @$_, map @{$_->instance_thumbnails}, @{ $self->{objects} }) {
$cursor = Wx::Cursor->new(wxCURSOR_HAND);
}
$self->SetCursor($cursor);
@ -234,13 +238,37 @@ sub mouse_event {
sub update_bed_size {
my $self = shift;
# supposing the preview canvas is square, calculate the scaling factor
# to constrain print bed area inside preview
# when the canvas is not rendered yet, its GetSize() method returns 0,0
my $canvas_size = $self->GetSize;
my ($canvas_w, $canvas_h) = ($canvas_size->GetWidth, $canvas_size->GetHeight);
return if $canvas_w == 0;
# get bed shape polygon
$self->{bed_polygon} = my $polygon = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape});
my $bb = $polygon->bounding_box;
my $size = $bb->size;
# calculate the scaling factor needed for constraining print bed area inside preview
# scaling_factor is expressed in pixel / mm
my $width = $self->GetSize->GetWidth;
$self->{scaling_factor} = $width / max(@{ $self->{config}->bed_size })
if $width != 0;
$self->{scaling_factor} = min($canvas_w / unscale($size->x), $canvas_h / unscale($size->y)); #)
# calculate the displacement needed to center bed
$self->{bed_origin} = [
$self->GetSize->GetWidth/2 - (unscale($bb->x_max + $bb->x_min)/2 * $self->{scaling_factor}),
$canvas_h - ($self->GetSize->GetHeight/2 - (unscale($bb->y_max + $bb->y_min)/2 * $self->{scaling_factor})),
];
# cache bed contours and grid
{
my $step = scale 10; # 1cm grid
$self->{grid} = my $grid = []; # arrayref of lines
for (my $x = $bb->x_min + $step; $x < $bb->x_max; $x += $step) {
push @$grid, $self->scaled_points_to_pixel([[$x, $bb->y_min], [$x, $bb->y_max]], 1);
}
for (my $y = $bb->y_min + $step; $y < $bb->y_max; $y += $step) {
push @$grid, $self->scaled_points_to_pixel([[$bb->x_min, $y], [$bb->x_max, $y]], 1);
}
}
}
sub clean_instance_thumbnails {
@ -251,35 +279,25 @@ sub clean_instance_thumbnails {
}
}
# coordinates of the model origin (0,0) in pixels
sub model_origin_to_pixel {
my ($self) = @_;
return [
$self->GetSize->GetWidth/2 - ($self->{config}->print_center->[X] * $self->{scaling_factor}),
$self->GetSize->GetHeight/2 - ($self->{config}->print_center->[Y] * $self->{scaling_factor}),
];
}
# convert a model coordinate into a pixel coordinate, assuming preview has square shape
sub point_to_pixel {
# convert a model coordinate into a pixel coordinate
sub unscaled_point_to_pixel {
my ($self, $point) = @_;
my $canvas_height = $self->GetSize->GetHeight;
my $zero = $self->model_origin_to_pixel;
my $zero = $self->{bed_origin};
return [
$point->[X] * $self->{scaling_factor} + $zero->[X],
$canvas_height - ($point->[Y] * $self->{scaling_factor} + $zero->[Y]),
$point->[X] * $self->{scaling_factor} + $zero->[X],
$canvas_height - $point->[Y] * $self->{scaling_factor} + ($zero->[Y] - $canvas_height),
];
}
sub points_to_pixel {
sub scaled_points_to_pixel {
my ($self, $points, $unscale) = @_;
my $result = [];
foreach my $point (@$points) {
$point = [ map unscale($_), @$point ] if $unscale;
push @$result, $self->point_to_pixel($point);
push @$result, $self->unscaled_point_to_pixel($point);
}
return $result;
}
@ -287,12 +305,11 @@ sub points_to_pixel {
sub point_to_model_units {
my ($self, $point) = @_;
my $canvas_height = $self->GetSize->GetHeight;
my $zero = $self->model_origin_to_pixel;
return [
($point->[X] - $zero->[X]) / $self->{scaling_factor},
(($canvas_height - $point->[Y] - $zero->[Y]) / $self->{scaling_factor}),
];
my $zero = $self->{bed_origin};
return Slic3r::Point->new(
scale ($point->[X] - $zero->[X]) / $self->{scaling_factor},
scale ($zero->[Y] - $point->[Y]) / $self->{scaling_factor},
);
}
1;

View file

@ -599,7 +599,11 @@ sub build {
Slic3r::GUI::OptionsGroup->single_option_line('cooling'),
{
label => '',
widget => ($self->{description_line} = Slic3r::GUI::OptionsGroup::StaticTextLine->new),
full_width => 1,
widget => sub {
my ($parent) = @_;
return $self->{description_line} = Slic3r::GUI::OptionsGroup::StaticTextLine->new($parent);
},
},
],
},
@ -662,6 +666,8 @@ sub on_value_change {
package Slic3r::GUI::Tab::Printer;
use base 'Slic3r::GUI::Tab';
use Wx qw(:sizer :button :bitmap :misc :id);
use Wx::Event qw(EVT_BUTTON);
sub name { 'printer' }
sub title { 'Printer Settings' }
@ -671,10 +677,43 @@ sub build {
$self->{extruders_count} = 1;
my $bed_shape_widget = sub {
my ($parent) = @_;
my $btn = Wx::Button->new($parent, -1, "Set…", wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
$btn->SetFont($Slic3r::GUI::small_font);
if ($Slic3r::GUI::have_button_icons) {
$btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG));
}
my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
$sizer->Add($btn);
EVT_BUTTON($self, $btn, sub {
my $dlg = Slic3r::GUI::BedShapeDialog->new($self, $self->{config}->bed_shape);
if ($dlg->ShowModal == wxID_OK) {
my $value = $dlg->GetValue;
$self->{config}->set('bed_shape', $value);
$self->on_value_change('bed_shape', $value);
}
});
return $sizer;
};
$self->add_options_page('General', 'printer_empty.png', optgroups => [
{
title => 'Size and coordinates',
options => [qw(bed_size print_center z_offset)],
options => [qw(bed_shape print_center z_offset)],
lines => [
{
label => 'Bed shape',
widget => $bed_shape_widget,
options => ['bed_shape'],
},
Slic3r::GUI::OptionsGroup->single_option_line('print_center'),
Slic3r::GUI::OptionsGroup->single_option_line('z_offset'),
],
},
{
title => 'Firmware',