mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into new_main_page_ui
This commit is contained in:
		
						commit
						0371f368a4
					
				
					 87 changed files with 12046 additions and 4249 deletions
				
			
		| 
						 | 
				
			
			@ -7,7 +7,6 @@ use File::Basename qw(basename);
 | 
			
		|||
use FindBin;
 | 
			
		||||
use List::Util qw(first);
 | 
			
		||||
use Slic3r::GUI::2DBed;
 | 
			
		||||
use Slic3r::GUI::BedShapeDialog;
 | 
			
		||||
use Slic3r::GUI::Controller;
 | 
			
		||||
use Slic3r::GUI::Controller::ManualControlDialog;
 | 
			
		||||
use Slic3r::GUI::Controller::PrinterPanel;
 | 
			
		||||
| 
						 | 
				
			
			@ -223,8 +222,8 @@ sub system_info {
 | 
			
		|||
    my $opengl_info_txt = '';
 | 
			
		||||
    if (defined($self->{mainframe}) && defined($self->{mainframe}->{plater}) &&
 | 
			
		||||
        defined($self->{mainframe}->{plater}->{canvas3D})) {
 | 
			
		||||
        $opengl_info = $self->{mainframe}->{plater}->{canvas3D}->opengl_info(format => 'html');
 | 
			
		||||
        $opengl_info_txt = $self->{mainframe}->{plater}->{canvas3D}->opengl_info;
 | 
			
		||||
        $opengl_info = Slic3r::GUI::_3DScene::get_gl_info(1, 1);
 | 
			
		||||
        $opengl_info_txt = Slic3r::GUI::_3DScene::get_gl_info(0, 1);
 | 
			
		||||
    }
 | 
			
		||||
    my $about = Slic3r::GUI::SystemInfo->new(
 | 
			
		||||
        parent      => undef, 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,316 +0,0 @@
 | 
			
		|||
# The bed shape dialog.
 | 
			
		||||
# The dialog opens from Print Settins tab -> Bed Shape: Set...
 | 
			
		||||
 | 
			
		||||
package Slic3r::GUI::BedShapeDialog;
 | 
			
		||||
use strict;
 | 
			
		||||
use warnings;
 | 
			
		||||
use utf8;
 | 
			
		||||
 | 
			
		||||
use List::Util qw(min max);
 | 
			
		||||
use Slic3r::Geometry qw(X Y unscale);
 | 
			
		||||
use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL);
 | 
			
		||||
use Wx::Event qw(EVT_CLOSE);
 | 
			
		||||
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 sum first);
 | 
			
		||||
use Scalar::Util qw(looks_like_number);
 | 
			
		||||
use Slic3r::Geometry qw(PI X Y unscale scaled_epsilon);
 | 
			
		||||
use Wx qw(:font :id :misc :sizer :choicebook :filedialog :pen :brush wxTAB_TRAVERSAL);
 | 
			
		||||
use Wx::Event qw(EVT_CLOSE EVT_CHOICEBOOK_PAGE_CHANGED EVT_BUTTON);
 | 
			
		||||
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} = [];
 | 
			
		||||
    {
 | 
			
		||||
        my $optgroup = $self->_init_shape_options_page('Rectangular');
 | 
			
		||||
        $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
 | 
			
		||||
            opt_id      => 'rect_size',
 | 
			
		||||
            type        => 'point',
 | 
			
		||||
            label       => 'Size',
 | 
			
		||||
            tooltip     => 'Size in X and Y of the rectangular plate.',
 | 
			
		||||
            default     => [200,200],
 | 
			
		||||
        ));
 | 
			
		||||
        $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
 | 
			
		||||
            opt_id      => 'rect_origin',
 | 
			
		||||
            type        => 'point',
 | 
			
		||||
            label       => 'Origin',
 | 
			
		||||
            tooltip     => 'Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.',
 | 
			
		||||
            default     => [0,0],
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        my $optgroup = $self->_init_shape_options_page('Circular');
 | 
			
		||||
        $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
 | 
			
		||||
            opt_id      => 'diameter',
 | 
			
		||||
            type        => 'f',
 | 
			
		||||
            label       => 'Diameter',
 | 
			
		||||
            tooltip     => 'Diameter of the print bed. It is assumed that origin (0,0) is located in the center.',
 | 
			
		||||
            sidetext    => 'mm',
 | 
			
		||||
            default     => 200,
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        my $optgroup = $self->_init_shape_options_page('Custom');
 | 
			
		||||
        $optgroup->append_line(Slic3r::GUI::OptionsGroup::Line->new(
 | 
			
		||||
            full_width  => 1,
 | 
			
		||||
            widget      => sub {
 | 
			
		||||
                my ($parent) = @_;
 | 
			
		||||
                
 | 
			
		||||
                my $btn = Wx::Button->new($parent, -1, "Load shape from STL...", wxDefaultPosition, wxDefaultSize);
 | 
			
		||||
                EVT_BUTTON($self, $btn, sub { $self->_load_stl });
 | 
			
		||||
                return $btn;
 | 
			
		||||
            }
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    EVT_CHOICEBOOK_PAGE_CHANGED($self, -1, sub {
 | 
			
		||||
        $self->_update_shape;
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    # right pane with preview canvas
 | 
			
		||||
    my $canvas = $self->{canvas} = Slic3r::GUI::2DBed->new($self);
 | 
			
		||||
    
 | 
			
		||||
    # 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, 10) 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 {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# 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) = @_;
 | 
			
		||||
    
 | 
			
		||||
    # 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
 | 
			
		||||
            
 | 
			
		||||
            # find origin
 | 
			
		||||
            # the || 0 hack prevents "-0" which might confuse the user
 | 
			
		||||
            my $x_min = min(map $_->[X], @$points) || 0;
 | 
			
		||||
            my $x_max = max(map $_->[X], @$points) || 0;
 | 
			
		||||
            my $y_min = min(map $_->[Y], @$points) || 0;
 | 
			
		||||
            my $y_max = max(map $_->[Y], @$points) || 0;
 | 
			
		||||
            my $origin = [-$x_min, -$y_min];
 | 
			
		||||
            
 | 
			
		||||
            $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);
 | 
			
		||||
            $self->_update_shape;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    # 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;
 | 
			
		||||
        my $avg_dist = sum(@vertex_distances)/@vertex_distances;
 | 
			
		||||
        if (!defined first { abs($_ - $avg_dist) > 10*scaled_epsilon } @vertex_distances) {
 | 
			
		||||
            # all vertices are equidistant to center
 | 
			
		||||
            $self->{shape_options_book}->SetSelection(SHAPE_CIRCULAR);
 | 
			
		||||
            my $optgroup = $self->{optgroups}[SHAPE_CIRCULAR];
 | 
			
		||||
            $optgroup->set_value('diameter', sprintf("%.0f", unscale($avg_dist*2)));
 | 
			
		||||
            $self->_update_shape;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    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) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $page_idx = $self->{shape_options_book}->GetSelection;
 | 
			
		||||
    if ($page_idx == SHAPE_RECTANGULAR) {
 | 
			
		||||
        my $rect_size = $self->{optgroups}[SHAPE_RECTANGULAR]->get_value('rect_size');
 | 
			
		||||
        my $rect_origin = $self->{optgroups}[SHAPE_RECTANGULAR]->get_value('rect_origin');
 | 
			
		||||
        my ($x, $y) = @$rect_size;
 | 
			
		||||
        return if !looks_like_number($x) || !looks_like_number($y);  # empty strings or '-' or other things
 | 
			
		||||
        return if !$x || !$y or $x == 0 or $y == 0;
 | 
			
		||||
        my ($x0, $y0) = (0,0);
 | 
			
		||||
        my ($x1, $y1) = ($x ,$y);
 | 
			
		||||
        {
 | 
			
		||||
            my ($dx, $dy) = @$rect_origin;
 | 
			
		||||
            return if !looks_like_number($dx) || !looks_like_number($dy);  # empty strings or '-' or other things
 | 
			
		||||
            $x0 -= $dx;
 | 
			
		||||
            $x1 -= $dx;
 | 
			
		||||
            $y0 -= $dy;
 | 
			
		||||
            $y1 -= $dy;
 | 
			
		||||
        }
 | 
			
		||||
        $self->{canvas}->bed_shape([
 | 
			
		||||
            [$x0,$y0],
 | 
			
		||||
            [$x1,$y0],
 | 
			
		||||
            [$x1,$y1],
 | 
			
		||||
            [$x0,$y1],
 | 
			
		||||
        ]);
 | 
			
		||||
    } elsif ($page_idx == SHAPE_CIRCULAR) {
 | 
			
		||||
        my $diameter = $self->{optgroups}[SHAPE_CIRCULAR]->get_value('diameter');
 | 
			
		||||
        return if !$diameter or $diameter == 0;
 | 
			
		||||
        my $r = $diameter/2;
 | 
			
		||||
        my $twopi = 2*PI;
 | 
			
		||||
        my $edges = 60;
 | 
			
		||||
        my $polygon = Slic3r::Polygon->new_scale(
 | 
			
		||||
            map [ $r * cos $_, $r * sin $_ ],
 | 
			
		||||
                map { $twopi/$edges*$_ } 1..$edges
 | 
			
		||||
        );
 | 
			
		||||
        $self->{canvas}->bed_shape([
 | 
			
		||||
            map [ unscale($_->x), unscale($_->y) ], @$polygon  #))
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->{on_change}->();
 | 
			
		||||
    $self->_update_preview;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $panel = Wx::Panel->new($self->{shape_options_book});
 | 
			
		||||
    my $optgroup;
 | 
			
		||||
    push @{$self->{optgroups}}, $optgroup = Slic3r::GUI::OptionsGroup->new(
 | 
			
		||||
        parent      => $panel,
 | 
			
		||||
        title       => 'Settings',
 | 
			
		||||
        label_width => 100,
 | 
			
		||||
        on_change   => sub {
 | 
			
		||||
            my ($opt_id) = @_;
 | 
			
		||||
            #$self->{"_$opt_id"} = $optgroup->get_value($opt_id);
 | 
			
		||||
            $self->_update_shape;
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    $panel->SetSizerAndFit($optgroup->sizer);
 | 
			
		||||
    $self->{shape_options_book}->AddPage($panel, $title);
 | 
			
		||||
    
 | 
			
		||||
    return $optgroup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Loads an stl file, projects it to the XY plane and calculates a polygon.
 | 
			
		||||
sub _load_stl {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $dialog = Wx::FileDialog->new($self, 'Choose a file to import bed shape from (STL/OBJ/AMF/PRUSA):', "", "", &Slic3r::GUI::MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
 | 
			
		||||
    if ($dialog->ShowModal != wxID_OK) {
 | 
			
		||||
        $dialog->Destroy;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    my $input_file = $dialog->GetPaths;
 | 
			
		||||
    $dialog->Destroy;
 | 
			
		||||
    
 | 
			
		||||
    my $model = Slic3r::Model->read_from_file($input_file);
 | 
			
		||||
    my $mesh = $model->mesh;
 | 
			
		||||
    my $expolygons = $mesh->horizontal_projection;
 | 
			
		||||
 | 
			
		||||
    if (@$expolygons == 0) {
 | 
			
		||||
        Slic3r::GUI::show_error($self, "The selected file contains no geometry.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (@$expolygons > 1) {
 | 
			
		||||
        Slic3r::GUI::show_error($self, "The selected file contains several disjoint areas. This is not supported.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    my $polygon = $expolygons->[0]->contour;
 | 
			
		||||
    $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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
| 
						 | 
				
			
			@ -32,9 +32,9 @@ our $OBJECT_SETTINGS_CHANGED_EVENT = Wx::NewEventType;
 | 
			
		|||
 | 
			
		||||
sub new {
 | 
			
		||||
    my ($class, %params) = @_;
 | 
			
		||||
    
 | 
			
		||||
        
 | 
			
		||||
    my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE);
 | 
			
		||||
    Slic3r::GUI::set_main_frame($self);
 | 
			
		||||
        Slic3r::GUI::set_main_frame($self);
 | 
			
		||||
    if ($^O eq 'MSWin32') {
 | 
			
		||||
        # Load the icon either from the exe, or from the ico file.
 | 
			
		||||
        my $iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe';
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ sub new {
 | 
			
		|||
    } else {
 | 
			
		||||
        $self->SetIcon(Wx::Icon->new(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG));        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
        
 | 
			
		||||
    # store input params
 | 
			
		||||
    # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
 | 
			
		||||
    $self->{no_controller} = $params{no_controller};
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ sub new {
 | 
			
		|||
    $self->{loaded} = 0;
 | 
			
		||||
    $self->{lang_ch_event} = $params{lang_ch_event};
 | 
			
		||||
    $self->{preferences_event} = $params{preferences_event};
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    # initialize tabpanel and menubar
 | 
			
		||||
    $self->_init_tabpanel;
 | 
			
		||||
    $self->_init_menubar;
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ sub new {
 | 
			
		|||
    $self->SetStatusBar($self->{statusbar});
 | 
			
		||||
    
 | 
			
		||||
    $self->{loaded} = 1;
 | 
			
		||||
    
 | 
			
		||||
        
 | 
			
		||||
    # initialize layout
 | 
			
		||||
    {
 | 
			
		||||
        my $sizer = Wx::BoxSizer->new(wxVERTICAL);
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +94,8 @@ sub new {
 | 
			
		|||
        # Save the slic3r.ini. Usually the ini file is saved from "on idle" callback,
 | 
			
		||||
        # but in rare cases it may not have been called yet.
 | 
			
		||||
        wxTheApp->{app_config}->save;
 | 
			
		||||
        $self->{plater}->{print} = undef if($self->{plater});
 | 
			
		||||
        Slic3r::GUI::_3DScene::remove_all_canvases();
 | 
			
		||||
        # propagate event
 | 
			
		||||
        $event->Skip;
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ sub new {
 | 
			
		|||
        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
 | 
			
		||||
        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
 | 
			
		||||
	wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model
 | 
			
		||||
    )]);
 | 
			
		||||
 | 
			
		||||
    # store input params
 | 
			
		||||
| 
						 | 
				
			
			@ -81,19 +81,19 @@ sub new {
 | 
			
		|||
    my $on_select_object = sub {
 | 
			
		||||
        my ($obj_idx) = @_;
 | 
			
		||||
        # Ignore the special objects (the wipe tower proxy and such).
 | 
			
		||||
        $self->select_object((defined($obj_idx) && $obj_idx < 1000) ? $obj_idx : undef);
 | 
			
		||||
        $self->select_object((defined($obj_idx) && $obj_idx >= 0 && $obj_idx < 1000) ? $obj_idx : undef);
 | 
			
		||||
    };
 | 
			
		||||
    my $on_double_click = sub {
 | 
			
		||||
        $self->object_settings_dialog if $self->selected_object;
 | 
			
		||||
    };
 | 
			
		||||
    my $on_right_click = sub {
 | 
			
		||||
        my ($canvas, $click_pos) = @_;
 | 
			
		||||
        
 | 
			
		||||
        my ($canvas, $click_pos_x, $click_pos_y) = @_;
 | 
			
		||||
 | 
			
		||||
        my ($obj_idx, $object) = $self->selected_object;
 | 
			
		||||
        return if !defined $obj_idx;
 | 
			
		||||
        
 | 
			
		||||
        my $menu = $self->object_menu;
 | 
			
		||||
        $canvas->PopupMenu($menu, $click_pos);
 | 
			
		||||
        $canvas->PopupMenu($menu, $click_pos_x, $click_pos_y);
 | 
			
		||||
        $menu->Destroy;
 | 
			
		||||
    };
 | 
			
		||||
    my $on_instances_moved = sub {
 | 
			
		||||
| 
						 | 
				
			
			@ -108,32 +108,65 @@ sub new {
 | 
			
		|||
        $self->{btn_print}->Enable($enable);
 | 
			
		||||
        $self->{btn_send_gcode}->Enable($enable);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    # callback to react to gizmo scale
 | 
			
		||||
    my $on_gizmo_scale_uniformly = sub {
 | 
			
		||||
        my ($scale) = @_;
 | 
			
		||||
 | 
			
		||||
        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];
 | 
			
		||||
        
 | 
			
		||||
        my $variation = $scale / $model_instance->scaling_factor;
 | 
			
		||||
        #FIXME Scale the layer height profile?
 | 
			
		||||
        foreach my $range (@{ $model_object->layer_height_ranges }) {
 | 
			
		||||
            $range->[0] *= $variation;
 | 
			
		||||
            $range->[1] *= $variation;
 | 
			
		||||
        }
 | 
			
		||||
        $_->set_scaling_factor($scale) for @{ $model_object->instances };
 | 
			
		||||
        $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.)
 | 
			
		||||
        $self->update;
 | 
			
		||||
        $self->schedule_background_process;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    # 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});
 | 
			
		||||
        $self->{preview_notebook}->AddPage($self->{canvas3D}, L('3D'));
 | 
			
		||||
        $self->{canvas3D}->set_on_select_object($on_select_object);
 | 
			
		||||
        $self->{canvas3D}->set_on_double_click($on_double_click);
 | 
			
		||||
        $self->{canvas3D}->set_on_right_click(sub { $on_right_click->($self->{canvas3D}, @_); });
 | 
			
		||||
        $self->{canvas3D}->set_on_arrange(sub { $self->arrange });
 | 
			
		||||
        $self->{canvas3D}->set_on_rotate_object_left(sub { $self->rotate(-45, Z, 'relative') });
 | 
			
		||||
        $self->{canvas3D}->set_on_rotate_object_right(sub { $self->rotate( 45, Z, 'relative') });
 | 
			
		||||
        $self->{canvas3D}->set_on_scale_object_uniformly(sub { $self->changescale(undef) });
 | 
			
		||||
        $self->{canvas3D}->set_on_increase_objects(sub { $self->increase() });
 | 
			
		||||
        $self->{canvas3D}->set_on_decrease_objects(sub { $self->decrease() });
 | 
			
		||||
        $self->{canvas3D}->set_on_remove_object(sub { $self->remove() });
 | 
			
		||||
        $self->{canvas3D}->set_on_instances_moved($on_instances_moved);
 | 
			
		||||
        $self->{canvas3D}->set_on_enable_action_buttons($enable_action_buttons);
 | 
			
		||||
        $self->{canvas3D}->use_plain_shader(1);
 | 
			
		||||
        $self->{canvas3D}->set_on_wipe_tower_moved(sub {
 | 
			
		||||
            my ($new_pos_3f) = @_;
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_select_object_callback($self->{canvas3D}, $on_select_object);
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_double_click_callback($self->{canvas3D}, $on_double_click);
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_right_click_callback($self->{canvas3D}, sub { $on_right_click->($self->{canvas3D}, @_); });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_arrange_callback($self->{canvas3D}, sub { $self->arrange });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_rotate_object_left_callback($self->{canvas3D}, sub { $self->rotate(-45, Z, 'relative') });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_rotate_object_right_callback($self->{canvas3D}, sub { $self->rotate( 45, Z, 'relative') });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_scale_object_uniformly_callback($self->{canvas3D}, sub { $self->changescale(undef) });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_increase_objects_callback($self->{canvas3D}, sub { $self->increase() });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_decrease_objects_callback($self->{canvas3D}, sub { $self->decrease() });
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_remove_object_callback($self->{canvas3D}, sub { $self->remove() });
 | 
			
		||||
        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::enable_shader($self->{canvas3D}, 1);
 | 
			
		||||
        Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1);
 | 
			
		||||
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_wipe_tower_moved_callback($self->{canvas3D}, sub {
 | 
			
		||||
            my ($x, $y) = @_;
 | 
			
		||||
            my $cfg = Slic3r::Config->new;
 | 
			
		||||
            $cfg->set('wipe_tower_x', $new_pos_3f->x);
 | 
			
		||||
            $cfg->set('wipe_tower_y', $new_pos_3f->y);
 | 
			
		||||
            $cfg->set('wipe_tower_x', $x);
 | 
			
		||||
            $cfg->set('wipe_tower_y', $y);
 | 
			
		||||
            $self->GetFrame->{options_tabs}{print}->load_config($cfg);
 | 
			
		||||
        });
 | 
			
		||||
        $self->{canvas3D}->set_on_model_update(sub {
 | 
			
		||||
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_model_update_callback($self->{canvas3D}, sub {
 | 
			
		||||
            if (wxTheApp->{app_config}->get("background_processing")) {
 | 
			
		||||
                $self->schedule_background_process;
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -141,9 +174,8 @@ sub new {
 | 
			
		|||
                $self->{"print_info_box_show"}->(0);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        $self->{canvas3D}->on_viewport_changed(sub {
 | 
			
		||||
            $self->{preview3D}->canvas->set_viewport_from_scene($self->{canvas3D});
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); });
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    # Initialize 2D preview canvas
 | 
			
		||||
| 
						 | 
				
			
			@ -157,9 +189,9 @@ sub new {
 | 
			
		|||
    # 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});
 | 
			
		||||
        $self->{preview3D}->canvas->on_viewport_changed(sub {
 | 
			
		||||
            $self->{canvas3D}->set_viewport_from_scene($self->{preview3D}->canvas);
 | 
			
		||||
        });
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 0);
 | 
			
		||||
        Slic3r::GUI::_3DScene::enable_legend_texture($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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -172,15 +204,28 @@ sub new {
 | 
			
		|||
    
 | 
			
		||||
    EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{preview_notebook}, sub {
 | 
			
		||||
        my $preview = $self->{preview_notebook}->GetCurrentPage;
 | 
			
		||||
        if ($preview == $self->{preview3D})
 | 
			
		||||
        {
 | 
			
		||||
            $self->{preview3D}->canvas->set_legend_enabled(1);
 | 
			
		||||
            $self->{preview3D}->load_print(1);
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{preview3D}->canvas->set_legend_enabled(0);
 | 
			
		||||
        if (($preview != $self->{preview3D}) && ($preview != $self->{canvas3D})) {
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 0);
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_active($self->{canvas3D}, 0);
 | 
			
		||||
            Slic3r::GUI::_3DScene::reset_current_canvas();
 | 
			
		||||
            $preview->OnActivate if $preview->can('OnActivate');        
 | 
			
		||||
        } elsif ($preview == $self->{preview3D}) {
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 1);
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_active($self->{canvas3D}, 0);
 | 
			
		||||
            $self->{preview3D}->load_print;
 | 
			
		||||
            # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_as_dirty($self->{preview3D}->canvas);
 | 
			
		||||
        } elsif ($preview == $self->{canvas3D}) {
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_active($self->{canvas3D}, 1);
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_active($self->{preview3D}->canvas, 0);
 | 
			
		||||
            if (Slic3r::GUI::_3DScene::is_reload_delayed($self->{canvas3D})) {
 | 
			
		||||
                my $selections = $self->collect_selections;
 | 
			
		||||
                Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
 | 
			
		||||
                Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
 | 
			
		||||
            }            
 | 
			
		||||
            # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_as_dirty($self->{canvas3D});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $preview->OnActivate if $preview->can('OnActivate');        
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    # toolbar for object manipulation
 | 
			
		||||
| 
						 | 
				
			
			@ -295,7 +340,7 @@ sub new {
 | 
			
		|||
        EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog });
 | 
			
		||||
        EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog });
 | 
			
		||||
        EVT_TOOL($self, TB_LAYER_EDITING, sub {
 | 
			
		||||
            my $state = $self->{canvas3D}->layer_editing_enabled;
 | 
			
		||||
            my $state = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
 | 
			
		||||
            $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state);
 | 
			
		||||
            $self->on_layer_editing_toggled(! $state);
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -350,11 +395,11 @@ sub new {
 | 
			
		|||
    
 | 
			
		||||
    $self->{canvas}->update_bed_size;
 | 
			
		||||
    if ($self->{canvas3D}) {
 | 
			
		||||
        $self->{canvas3D}->update_bed_size;
 | 
			
		||||
        $self->{canvas3D}->zoom_to_bed;
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape);
 | 
			
		||||
        Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D});
 | 
			
		||||
    }
 | 
			
		||||
    if ($self->{preview3D}) {
 | 
			
		||||
        $self->{preview3D}->set_bed_shape($self->{config}->bed_shape);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape);
 | 
			
		||||
    }
 | 
			
		||||
    $self->update;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -613,8 +658,8 @@ sub _on_select_preset {
 | 
			
		|||
 | 
			
		||||
sub on_layer_editing_toggled {
 | 
			
		||||
    my ($self, $new_state) = @_;
 | 
			
		||||
    $self->{canvas3D}->layer_editing_enabled($new_state);
 | 
			
		||||
    if ($new_state && ! $self->{canvas3D}->layer_editing_enabled) {
 | 
			
		||||
    Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, $new_state);
 | 
			
		||||
    if ($new_state && ! Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D})) {
 | 
			
		||||
        # Initialization of the OpenGL shaders failed. Disable the tool.
 | 
			
		||||
        if ($self->{htoolbar}) {
 | 
			
		||||
            $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -845,8 +890,7 @@ sub load_model_objects {
 | 
			
		|||
    $self->update;
 | 
			
		||||
    
 | 
			
		||||
    # zoom to objects
 | 
			
		||||
    $self->{canvas3D}->zoom_to_volumes
 | 
			
		||||
        if $self->{canvas3D};
 | 
			
		||||
    Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
 | 
			
		||||
    
 | 
			
		||||
    $self->object_list_changed;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -1242,8 +1286,7 @@ sub async_apply_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);
 | 
			
		||||
    $self->{canvas3D}->Refresh if ($self->{canvas3D}->layer_editing_enabled);
 | 
			
		||||
    $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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1644,6 +1687,34 @@ sub export_object_stl {
 | 
			
		|||
    $self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub fix_through_netfabb {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    my ($obj_idx, $object) = $self->selected_object;
 | 
			
		||||
    return if !defined $obj_idx;
 | 
			
		||||
    my $model_object = $self->{model}->objects->[$obj_idx];
 | 
			
		||||
    my $model_fixed = Slic3r::Model->new;
 | 
			
		||||
    Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed);
 | 
			
		||||
 | 
			
		||||
    my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects});
 | 
			
		||||
    return if !@new_obj_idx;
 | 
			
		||||
    
 | 
			
		||||
    foreach my $new_obj_idx (@new_obj_idx) {
 | 
			
		||||
        my $o = $self->{model}->objects->[$new_obj_idx];
 | 
			
		||||
        $o->clear_instances;
 | 
			
		||||
        $o->add_instance($_) for @{$model_object->instances};
 | 
			
		||||
        #$o->invalidate_bounding_box;
 | 
			
		||||
        
 | 
			
		||||
        if ($o->volumes_count == $model_object->volumes_count) {
 | 
			
		||||
            for my $i (0..($o->volumes_count-1)) {
 | 
			
		||||
                $o->get_volume($i)->config->apply($model_object->get_volume($i)->config);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        #FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->remove($obj_idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub export_amf {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    return if !@{$self->{objects}};
 | 
			
		||||
| 
						 | 
				
			
			@ -1748,7 +1819,9 @@ sub update {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{canvas}->reload_scene if $self->{canvas};
 | 
			
		||||
    $self->{canvas3D}->reload_scene if $self->{canvas3D};
 | 
			
		||||
    my $selections = $self->collect_selections;
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
 | 
			
		||||
    Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
 | 
			
		||||
    $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
 | 
			
		||||
    $self->{preview3D}->reload_print if $self->{preview3D};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1803,9 +1876,8 @@ sub on_config_change {
 | 
			
		|||
        $self->{config}->set($opt_key, $config->get($opt_key));
 | 
			
		||||
        if ($opt_key eq 'bed_shape') {
 | 
			
		||||
            $self->{canvas}->update_bed_size;
 | 
			
		||||
            $self->{canvas3D}->update_bed_size if $self->{canvas3D};
 | 
			
		||||
            $self->{preview3D}->set_bed_shape($self->{config}->bed_shape)
 | 
			
		||||
                if $self->{preview3D};
 | 
			
		||||
            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;
 | 
			
		||||
        } elsif ($opt_key =~ '^wipe_tower' || $opt_key eq 'single_extruder_multi_material') {
 | 
			
		||||
            $update_scheduled = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -1824,10 +1896,10 @@ sub on_config_change {
 | 
			
		|||
                    $self->{"btn_layer_editing"}->Disable;
 | 
			
		||||
                    $self->{"btn_layer_editing"}->SetValue(0);
 | 
			
		||||
                }
 | 
			
		||||
                $self->{canvas3D}->layer_editing_enabled(0);
 | 
			
		||||
                Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, 0);
 | 
			
		||||
                $self->{canvas3D}->Refresh;
 | 
			
		||||
                $self->{canvas3D}->Update;
 | 
			
		||||
            } elsif ($self->{canvas3D}->layer_editing_allowed) {
 | 
			
		||||
            } elsif (Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D})) {
 | 
			
		||||
                # Want to allow the layer editing, but do it only if the OpenGL supports it.
 | 
			
		||||
                if ($self->{htoolbar}) {
 | 
			
		||||
                    $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -1841,6 +1913,9 @@ sub on_config_change {
 | 
			
		|||
            $self->{preview3D}->set_number_extruders(scalar(@{$extruder_colors}));
 | 
			
		||||
        } elsif ($opt_key eq 'max_print_height') {
 | 
			
		||||
            $update_scheduled = 1;
 | 
			
		||||
        } elsif ($opt_key eq 'printer_model') {
 | 
			
		||||
            # update to force bed selection (for texturing)
 | 
			
		||||
            $update_scheduled = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1852,16 +1927,36 @@ sub on_config_change {
 | 
			
		|||
    $self->schedule_background_process;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub list_item_deselected {
 | 
			
		||||
    my ($self, $event) = @_;
 | 
			
		||||
    return if $PreventListEvents;
 | 
			
		||||
    $self->{_lecursor} = Wx::BusyCursor->new();
 | 
			
		||||
    if ($self->{list}->GetFirstSelected == -1) {
 | 
			
		||||
        $self->select_object(undef);
 | 
			
		||||
        $self->{canvas}->Refresh;
 | 
			
		||||
        Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}) if $self->{canvas3D};
 | 
			
		||||
        Slic3r::GUI::_3DScene::render($self->{canvas3D}) if $self->{canvas3D};
 | 
			
		||||
    }
 | 
			
		||||
    undef $self->{_lecursor};
 | 
			
		||||
}
 | 
			
		||||
sub item_changed_selection{
 | 
			
		||||
    my ($self, $obj_idx) = @_;
 | 
			
		||||
 | 
			
		||||
    $self->{canvas}->Refresh;
 | 
			
		||||
    if ($self->{canvas3D}){
 | 
			
		||||
        $self->{canvas3D}->deselect_volumes;
 | 
			
		||||
        if ($obj_idx >= 0) {
 | 
			
		||||
            $self->{canvas3D}->update_volumes_selection};
 | 
			
		||||
    if ($self->{canvas3D}) {
 | 
			
		||||
        my $selections = $self->collect_selections;
 | 
			
		||||
        Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
 | 
			
		||||
        Slic3r::GUI::_3DScene::render($self->{canvas3D});
 | 
			
		||||
    }
 | 
			
		||||
    $self->{canvas3D}->Render if $self->{canvas3D};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub collect_selections {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    my $selections = [];
 | 
			
		||||
    foreach my $o (@{$self->{objects}}) {
 | 
			
		||||
        push(@$selections, $o->selected);
 | 
			
		||||
    }            
 | 
			
		||||
    return $selections;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# doesn't used now
 | 
			
		||||
| 
						 | 
				
			
			@ -1921,7 +2016,7 @@ sub object_cut_dialog {
 | 
			
		|||
	    $self->remove($obj_idx);
 | 
			
		||||
	    $self->load_model_objects(grep defined($_), @new_objects);
 | 
			
		||||
	    $self->arrange;
 | 
			
		||||
        $self->{canvas3D}->zoom_to_volumes if $self->{canvas3D};
 | 
			
		||||
        Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1957,7 +2052,9 @@ sub object_settings_dialog {
 | 
			
		|||
        $self->{print}->reload_object($obj_idx);
 | 
			
		||||
        $self->schedule_background_process;
 | 
			
		||||
        $self->{canvas}->reload_scene if $self->{canvas};
 | 
			
		||||
        $self->{canvas3D}->reload_scene if $self->{canvas3D};
 | 
			
		||||
        my $selections = $self->collect_selections;
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
 | 
			
		||||
        Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
 | 
			
		||||
    } else {
 | 
			
		||||
        $self->resume_background_process;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1993,7 +2090,7 @@ sub object_list_changed {
 | 
			
		|||
        
 | 
			
		||||
    # Enable/disable buttons depending on whether there are any objects on the platter.
 | 
			
		||||
    my $have_objects = @{$self->{objects}} ? 1 : 0;
 | 
			
		||||
    my $variable_layer_height_allowed = $self->{config}->variable_layer_height && $self->{canvas3D}->layer_editing_allowed;
 | 
			
		||||
    my $variable_layer_height_allowed = $self->{config}->variable_layer_height && Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D});
 | 
			
		||||
    if ($self->{htoolbar}) {
 | 
			
		||||
        # On OSX or Linux
 | 
			
		||||
        $self->{htoolbar}->EnableTool($_, $have_objects)
 | 
			
		||||
| 
						 | 
				
			
			@ -2008,7 +2105,7 @@ sub object_list_changed {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
 | 
			
		||||
    my $model_fits = $self->{canvas3D} ? $self->{canvas3D}->volumes->check_outside_state($self->{config}) : 1;
 | 
			
		||||
    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';
 | 
			
		||||
    $self->{"btn_$_"}->$method
 | 
			
		||||
        for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
 | 
			
		||||
| 
						 | 
				
			
			@ -2211,6 +2308,11 @@ sub object_menu {
 | 
			
		|||
    $frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub {
 | 
			
		||||
        $self->export_object_stl;
 | 
			
		||||
    }, undef, 'brick_go.png');
 | 
			
		||||
    if (Slic3r::GUI::is_windows10) {
 | 
			
		||||
        $frame->_append_menu_item($menu, L("Fix STL through Netfabb"), L('Fix the model by sending it to a Netfabb cloud service through Windows 10 API'), sub {
 | 
			
		||||
            $self->fix_through_netfabb;
 | 
			
		||||
        }, undef, 'brick_go.png');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return $menu;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2221,11 +2323,11 @@ sub select_view {
 | 
			
		|||
    my $idx_page = $self->{preview_notebook}->GetSelection;
 | 
			
		||||
    my $page = ($idx_page == &Wx::wxNOT_FOUND) ? L('3D') : $self->{preview_notebook}->GetPageText($idx_page);
 | 
			
		||||
    if ($page eq L('Preview')) {
 | 
			
		||||
        $self->{preview3D}->canvas->select_view($direction);
 | 
			
		||||
        $self->{canvas3D}->set_viewport_from_scene($self->{preview3D}->canvas);
 | 
			
		||||
        Slic3r::GUI::_3DScene::select_view($self->{preview3D}->canvas, $direction);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas);
 | 
			
		||||
    } else {
 | 
			
		||||
        $self->{canvas3D}->select_view($direction);
 | 
			
		||||
        $self->{preview3D}->canvas->set_viewport_from_scene($self->{canvas3D});
 | 
			
		||||
        Slic3r::GUI::_3DScene::select_view($self->{canvas3D}, $direction);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -222,7 +222,7 @@ sub mouse_event {
 | 
			
		|||
                        ];
 | 
			
		||||
                        $self->{drag_object} = [ $obj_idx, $instance_idx ];
 | 
			
		||||
                    } elsif ($event->RightDown) {
 | 
			
		||||
                        $self->{on_right_click}->($pos);
 | 
			
		||||
                        $self->{on_right_click}->($pos->x, $pos->y);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    last OBJECTS;
 | 
			
		||||
| 
						 | 
				
			
			@ -231,8 +231,10 @@ sub mouse_event {
 | 
			
		|||
        }
 | 
			
		||||
        $self->Refresh;
 | 
			
		||||
    } elsif ($event->LeftUp) {
 | 
			
		||||
        $self->{on_instances_moved}->()
 | 
			
		||||
            if $self->{drag_object};
 | 
			
		||||
        if ($self->{drag_object}) {
 | 
			
		||||
            $self->{on_instances_moved}->();
 | 
			
		||||
            Slic3r::GUI::_3DScene::reset_current_canvas();            
 | 
			
		||||
        }
 | 
			
		||||
        $self->{drag_start_pos} = undef;
 | 
			
		||||
        $self->{drag_object} = undef;
 | 
			
		||||
        $self->SetCursor(wxSTANDARD_CURSOR);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,264 +5,279 @@ use utf8;
 | 
			
		|||
 | 
			
		||||
use List::Util qw();
 | 
			
		||||
use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL);
 | 
			
		||||
use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR);
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
#use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR);
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
use base qw(Slic3r::GUI::3DScene Class::Accessor);
 | 
			
		||||
 | 
			
		||||
use Wx::Locale gettext => 'L';
 | 
			
		||||
 | 
			
		||||
__PACKAGE__->mk_accessors(qw(
 | 
			
		||||
    on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly
 | 
			
		||||
    on_remove_object on_increase_objects on_decrease_objects on_enable_action_buttons));
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
#use Wx::Locale gettext => 'L';
 | 
			
		||||
#
 | 
			
		||||
#__PACKAGE__->mk_accessors(qw(
 | 
			
		||||
#    on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly
 | 
			
		||||
#    on_remove_object on_increase_objects on_decrease_objects on_enable_action_buttons));
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
 | 
			
		||||
sub new {
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my ($parent, $objects, $model, $print, $config) = @_;
 | 
			
		||||
    
 | 
			
		||||
    my $self = $class->SUPER::new($parent);
 | 
			
		||||
    $self->enable_picking(1);
 | 
			
		||||
    $self->enable_moving(1);
 | 
			
		||||
    $self->select_by('object');
 | 
			
		||||
    $self->drag_by('instance');
 | 
			
		||||
    
 | 
			
		||||
    $self->{objects}            = $objects;
 | 
			
		||||
    $self->{model}              = $model;
 | 
			
		||||
    $self->{print}              = $print;
 | 
			
		||||
    $self->{config}             = $config;
 | 
			
		||||
    $self->{on_select_object}   = sub {};
 | 
			
		||||
    $self->{on_instances_moved} = sub {};
 | 
			
		||||
    $self->{on_wipe_tower_moved} = sub {};
 | 
			
		||||
 | 
			
		||||
    $self->{objects_volumes_idxs} = [];
 | 
			
		||||
        
 | 
			
		||||
    $self->on_select(sub {
 | 
			
		||||
        my ($volume_idx) = @_;
 | 
			
		||||
        $self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx)
 | 
			
		||||
            if ($self->{on_select_object});
 | 
			
		||||
    });
 | 
			
		||||
    $self->on_move(sub {
 | 
			
		||||
        my @volume_idxs = @_;
 | 
			
		||||
        
 | 
			
		||||
        my %done = ();  # prevent moving instances twice
 | 
			
		||||
        my $object_moved;
 | 
			
		||||
        my $wipe_tower_moved;
 | 
			
		||||
        foreach my $volume_idx (@volume_idxs) {
 | 
			
		||||
            my $volume = $self->volumes->[$volume_idx];
 | 
			
		||||
            my $obj_idx = $volume->object_idx;
 | 
			
		||||
            my $instance_idx = $volume->instance_idx;
 | 
			
		||||
            next if $done{"${obj_idx}_${instance_idx}"};
 | 
			
		||||
            $done{"${obj_idx}_${instance_idx}"} = 1;
 | 
			
		||||
            if ($obj_idx < 1000) {
 | 
			
		||||
                # Move a regular object.
 | 
			
		||||
                my $model_object = $self->{model}->get_object($obj_idx);
 | 
			
		||||
                $model_object
 | 
			
		||||
                    ->instances->[$instance_idx]
 | 
			
		||||
                    ->offset
 | 
			
		||||
                    ->translate($volume->origin->x, $volume->origin->y); #))
 | 
			
		||||
                $model_object->invalidate_bounding_box;
 | 
			
		||||
                $object_moved = 1;
 | 
			
		||||
            } elsif ($obj_idx == 1000) {
 | 
			
		||||
                # Move a wipe tower proxy.
 | 
			
		||||
                $wipe_tower_moved = $volume->origin;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $self->{on_instances_moved}->()
 | 
			
		||||
            if $object_moved && $self->{on_instances_moved};
 | 
			
		||||
        $self->{on_wipe_tower_moved}->($wipe_tower_moved)
 | 
			
		||||
            if $wipe_tower_moved && $self->{on_wipe_tower_moved};
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    EVT_KEY_DOWN($self, sub {
 | 
			
		||||
        my ($s, $event) = @_;
 | 
			
		||||
        if ($event->HasModifiers) {
 | 
			
		||||
            $event->Skip;
 | 
			
		||||
        } else {
 | 
			
		||||
            my $key = $event->GetKeyCode;
 | 
			
		||||
            if ($key == WXK_DELETE) {
 | 
			
		||||
                $self->on_remove_object->() if $self->on_remove_object;
 | 
			
		||||
            } else {
 | 
			
		||||
                $event->Skip;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    EVT_CHAR($self, sub {
 | 
			
		||||
        my ($s, $event) = @_;
 | 
			
		||||
        if ($event->HasModifiers) {
 | 
			
		||||
            $event->Skip;
 | 
			
		||||
        } else {
 | 
			
		||||
            my $key = $event->GetKeyCode;
 | 
			
		||||
            if ($key == ord('a')) {
 | 
			
		||||
                $self->on_arrange->() if $self->on_arrange;
 | 
			
		||||
            } elsif ($key == ord('l')) {
 | 
			
		||||
                $self->on_rotate_object_left->() if $self->on_rotate_object_left;
 | 
			
		||||
            } elsif ($key == ord('r')) {
 | 
			
		||||
                $self->on_rotate_object_right->() if $self->on_rotate_object_right;
 | 
			
		||||
            } elsif ($key == ord('s')) {
 | 
			
		||||
                $self->on_scale_object_uniformly->() if $self->on_scale_object_uniformly;
 | 
			
		||||
            } elsif ($key == ord('+')) {
 | 
			
		||||
                $self->on_increase_objects->() if $self->on_increase_objects;
 | 
			
		||||
            } elsif ($key == ord('-')) {
 | 
			
		||||
                $self->on_decrease_objects->() if $self->on_decrease_objects;
 | 
			
		||||
            } else {
 | 
			
		||||
                $event->Skip;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
    Slic3r::GUI::_3DScene::enable_picking($self, 1);
 | 
			
		||||
    Slic3r::GUI::_3DScene::enable_moving($self, 1);
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_select_by($self, 'object');
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_drag_by($self, 'instance');
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_model($self, $model);
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_print($self, $print);
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_config($self, $config);
 | 
			
		||||
#    $self->enable_picking(1);
 | 
			
		||||
#    $self->enable_moving(1);
 | 
			
		||||
#    $self->select_by('object');
 | 
			
		||||
#    $self->drag_by('instance');
 | 
			
		||||
#    
 | 
			
		||||
#    $self->{objects}            = $objects;
 | 
			
		||||
#    $self->{model}              = $model;
 | 
			
		||||
#    $self->{print}              = $print;
 | 
			
		||||
#    $self->{config}             = $config;
 | 
			
		||||
#    $self->{on_select_object}   = sub {};
 | 
			
		||||
#    $self->{on_instances_moved} = sub {};
 | 
			
		||||
#    $self->{on_wipe_tower_moved} = sub {};
 | 
			
		||||
#
 | 
			
		||||
#    $self->{objects_volumes_idxs} = [];
 | 
			
		||||
#
 | 
			
		||||
#    $self->on_select(sub {
 | 
			
		||||
#        my ($volume_idx) = @_;
 | 
			
		||||
#        $self->{on_select_object}->(($volume_idx == -1) ? undef : $self->volumes->[$volume_idx]->object_idx)
 | 
			
		||||
#            if ($self->{on_select_object});
 | 
			
		||||
#    });
 | 
			
		||||
#
 | 
			
		||||
#    $self->on_move(sub {
 | 
			
		||||
#        my @volume_idxs = @_;
 | 
			
		||||
#        my %done = ();  # prevent moving instances twice
 | 
			
		||||
#        my $object_moved;
 | 
			
		||||
#        my $wipe_tower_moved;
 | 
			
		||||
#        foreach my $volume_idx (@volume_idxs) {
 | 
			
		||||
#            my $volume = $self->volumes->[$volume_idx];
 | 
			
		||||
#            my $obj_idx = $volume->object_idx;
 | 
			
		||||
#            my $instance_idx = $volume->instance_idx;
 | 
			
		||||
#            next if $done{"${obj_idx}_${instance_idx}"};
 | 
			
		||||
#            $done{"${obj_idx}_${instance_idx}"} = 1;
 | 
			
		||||
#            if ($obj_idx < 1000) {
 | 
			
		||||
#                # Move a regular object.
 | 
			
		||||
#                my $model_object = $self->{model}->get_object($obj_idx);
 | 
			
		||||
#                $model_object
 | 
			
		||||
#                    ->instances->[$instance_idx]
 | 
			
		||||
#                    ->offset
 | 
			
		||||
#                    ->translate($volume->origin->x, $volume->origin->y); #))
 | 
			
		||||
#                $model_object->invalidate_bounding_box;
 | 
			
		||||
#                $object_moved = 1;
 | 
			
		||||
#            } elsif ($obj_idx == 1000) {
 | 
			
		||||
#                # Move a wipe tower proxy.
 | 
			
		||||
#                $wipe_tower_moved = $volume->origin;
 | 
			
		||||
#            }
 | 
			
		||||
#        }
 | 
			
		||||
#        
 | 
			
		||||
#        $self->{on_instances_moved}->()
 | 
			
		||||
#            if $object_moved && $self->{on_instances_moved};
 | 
			
		||||
#        $self->{on_wipe_tower_moved}->($wipe_tower_moved)
 | 
			
		||||
#            if $wipe_tower_moved && $self->{on_wipe_tower_moved};
 | 
			
		||||
#    });
 | 
			
		||||
#
 | 
			
		||||
#    EVT_KEY_DOWN($self, sub {
 | 
			
		||||
#        my ($s, $event) = @_;
 | 
			
		||||
#        if ($event->HasModifiers) {
 | 
			
		||||
#            $event->Skip;
 | 
			
		||||
#        } else {
 | 
			
		||||
#            my $key = $event->GetKeyCode;
 | 
			
		||||
#            if ($key == WXK_DELETE) {
 | 
			
		||||
#                $self->on_remove_object->() if $self->on_remove_object;
 | 
			
		||||
#            } else {
 | 
			
		||||
#                $event->Skip;
 | 
			
		||||
#            }
 | 
			
		||||
#        }
 | 
			
		||||
#    });
 | 
			
		||||
#
 | 
			
		||||
#    EVT_CHAR($self, sub {
 | 
			
		||||
#        my ($s, $event) = @_;
 | 
			
		||||
#        if ($event->HasModifiers) {
 | 
			
		||||
#            $event->Skip;
 | 
			
		||||
#        } else {
 | 
			
		||||
#            my $key = $event->GetKeyCode;
 | 
			
		||||
#            if ($key == ord('a')) {
 | 
			
		||||
#                $self->on_arrange->() if $self->on_arrange;
 | 
			
		||||
#            } elsif ($key == ord('l')) {
 | 
			
		||||
#                $self->on_rotate_object_left->() if $self->on_rotate_object_left;
 | 
			
		||||
#            } elsif ($key == ord('r')) {
 | 
			
		||||
#                $self->on_rotate_object_right->() if $self->on_rotate_object_right;
 | 
			
		||||
#            } elsif ($key == ord('s')) {
 | 
			
		||||
#                $self->on_scale_object_uniformly->() if $self->on_scale_object_uniformly;
 | 
			
		||||
#            } elsif ($key == ord('+')) {
 | 
			
		||||
#                $self->on_increase_objects->() if $self->on_increase_objects;
 | 
			
		||||
#            } elsif ($key == ord('-')) {
 | 
			
		||||
#                $self->on_decrease_objects->() if $self->on_decrease_objects;
 | 
			
		||||
#            } else {
 | 
			
		||||
#                $event->Skip;
 | 
			
		||||
#            }
 | 
			
		||||
#        }
 | 
			
		||||
#    });
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
    
 | 
			
		||||
    return $self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_select_object {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->{on_select_object} = $cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_double_click {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_double_click($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_right_click {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_right_click($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_arrange {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_arrange($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_rotate_object_left {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_rotate_object_left($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_rotate_object_right {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_rotate_object_right($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_scale_object_uniformly {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_scale_object_uniformly($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_increase_objects {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_increase_objects($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_decrease_objects {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_decrease_objects($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_remove_object {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_remove_object($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_instances_moved {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->{on_instances_moved} = $cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_wipe_tower_moved {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->{on_wipe_tower_moved} = $cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_model_update {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_model_update($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_on_enable_action_buttons {
 | 
			
		||||
    my ($self, $cb) = @_;
 | 
			
		||||
    $self->on_enable_action_buttons($cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub update_volumes_selection {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
 | 
			
		||||
    foreach my $obj_idx (0..$#{$self->{model}->objects}) {
 | 
			
		||||
        if ($self->{objects}[$obj_idx]->selected) {
 | 
			
		||||
            my $volume_idxs = $self->{objects_volumes_idxs}->[$obj_idx];
 | 
			
		||||
            $self->select_volume($_) for @{$volume_idxs};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub reload_scene {
 | 
			
		||||
    my ($self, $force) = @_;
 | 
			
		||||
 | 
			
		||||
    $self->reset_objects;
 | 
			
		||||
    $self->update_bed_size;
 | 
			
		||||
 | 
			
		||||
    if (! $self->IsShown && ! $force) {
 | 
			
		||||
        $self->{reload_delayed} = 1;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->{reload_delayed} = 0;
 | 
			
		||||
 | 
			
		||||
    $self->{objects_volumes_idxs} = [];    
 | 
			
		||||
    foreach my $obj_idx (0..$#{$self->{model}->objects}) {
 | 
			
		||||
        my @volume_idxs = $self->load_object($self->{model}, $self->{print}, $obj_idx);
 | 
			
		||||
        push(@{$self->{objects_volumes_idxs}}, \@volume_idxs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->update_volumes_selection;
 | 
			
		||||
        
 | 
			
		||||
    if (defined $self->{config}->nozzle_diameter) {
 | 
			
		||||
        # Should the wipe tower be visualized?
 | 
			
		||||
        my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
 | 
			
		||||
        # Height of a print.
 | 
			
		||||
        my $height = $self->{model}->bounding_box->z_max;
 | 
			
		||||
        # Show at least a slab.
 | 
			
		||||
        $height = 10 if $height < 10;
 | 
			
		||||
        if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
 | 
			
		||||
            ! $self->{config}->complete_objects) {
 | 
			
		||||
            $self->volumes->load_wipe_tower_preview(1000, 
 | 
			
		||||
                $self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width,
 | 
			
		||||
		#$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete
 | 
			
		||||
		15 * ($extruders_count - 1),
 | 
			
		||||
                $self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->update_volumes_colors_by_extruder($self->{config});
 | 
			
		||||
    
 | 
			
		||||
    # checks for geometry outside the print volume to render it accordingly
 | 
			
		||||
    if (scalar @{$self->volumes} > 0)
 | 
			
		||||
    {
 | 
			
		||||
        my $contained = $self->volumes->check_outside_state($self->{config});
 | 
			
		||||
        if (!$contained) {
 | 
			
		||||
            $self->set_warning_enabled(1);
 | 
			
		||||
            Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume"));
 | 
			
		||||
            $self->on_enable_action_buttons->(0) if ($self->on_enable_action_buttons);
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->set_warning_enabled(0);
 | 
			
		||||
            $self->volumes->reset_outside_state();
 | 
			
		||||
            Slic3r::GUI::_3DScene::reset_warning_texture();
 | 
			
		||||
            $self->on_enable_action_buttons->(scalar @{$self->{model}->objects} > 0) if ($self->on_enable_action_buttons);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        $self->set_warning_enabled(0);
 | 
			
		||||
        Slic3r::GUI::_3DScene::reset_warning_texture();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub update_bed_size {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    $self->set_bed_shape($self->{config}->bed_shape);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Called by the Platter wxNotebook when this page is activated.
 | 
			
		||||
sub OnActivate {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    $self->reload_scene(1) if ($self->{reload_delayed});
 | 
			
		||||
}
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
#sub set_on_select_object {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->{on_select_object} = $cb;
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_double_click {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_double_click($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_right_click {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_right_click($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_arrange {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_arrange($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_rotate_object_left {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_rotate_object_left($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_rotate_object_right {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_rotate_object_right($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_scale_object_uniformly {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_scale_object_uniformly($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_increase_objects {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_increase_objects($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_decrease_objects {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_decrease_objects($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_remove_object {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_remove_object($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_instances_moved {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->{on_instances_moved} = $cb;
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_wipe_tower_moved {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->{on_wipe_tower_moved} = $cb;
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_model_update {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_model_update($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub set_on_enable_action_buttons {
 | 
			
		||||
#    my ($self, $cb) = @_;
 | 
			
		||||
#    $self->on_enable_action_buttons($cb);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub update_volumes_selection {
 | 
			
		||||
#    my ($self) = @_;
 | 
			
		||||
#
 | 
			
		||||
#    foreach my $obj_idx (0..$#{$self->{model}->objects}) {
 | 
			
		||||
#        if ($self->{objects}[$obj_idx]->selected) {
 | 
			
		||||
#            my $volume_idxs = $self->{objects_volumes_idxs}->[$obj_idx];
 | 
			
		||||
#            $self->select_volume($_) for @{$volume_idxs};
 | 
			
		||||
#        }
 | 
			
		||||
#    }
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub reload_scene {
 | 
			
		||||
#    my ($self, $force) = @_;
 | 
			
		||||
#
 | 
			
		||||
#    $self->reset_objects;
 | 
			
		||||
#    $self->update_bed_size;
 | 
			
		||||
#
 | 
			
		||||
#    if (! $self->IsShown && ! $force) {
 | 
			
		||||
#        $self->{reload_delayed} = 1;
 | 
			
		||||
#        return;
 | 
			
		||||
#    }
 | 
			
		||||
#
 | 
			
		||||
#    $self->{reload_delayed} = 0;
 | 
			
		||||
#
 | 
			
		||||
#    $self->{objects_volumes_idxs} = [];    
 | 
			
		||||
#    foreach my $obj_idx (0..$#{$self->{model}->objects}) {
 | 
			
		||||
#        my @volume_idxs = $self->load_object($self->{model}, $self->{print}, $obj_idx);
 | 
			
		||||
#        push(@{$self->{objects_volumes_idxs}}, \@volume_idxs);
 | 
			
		||||
#    }
 | 
			
		||||
#    
 | 
			
		||||
#    $self->update_volumes_selection;
 | 
			
		||||
#        
 | 
			
		||||
#    if (defined $self->{config}->nozzle_diameter) {
 | 
			
		||||
#        # Should the wipe tower be visualized?
 | 
			
		||||
#        my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
 | 
			
		||||
#        # Height of a print.
 | 
			
		||||
#        my $height = $self->{model}->bounding_box->z_max;
 | 
			
		||||
#        # Show at least a slab.
 | 
			
		||||
#        $height = 10 if $height < 10;
 | 
			
		||||
#        if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
 | 
			
		||||
#            ! $self->{config}->complete_objects) {
 | 
			
		||||
#            $self->volumes->load_wipe_tower_preview(1000, 
 | 
			
		||||
#                $self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width,
 | 
			
		||||
#		#$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete
 | 
			
		||||
#		15 * ($extruders_count - 1),
 | 
			
		||||
#                $self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs);
 | 
			
		||||
#        }
 | 
			
		||||
#    }
 | 
			
		||||
#
 | 
			
		||||
#    $self->update_volumes_colors_by_extruder($self->{config});
 | 
			
		||||
#    
 | 
			
		||||
#    # checks for geometry outside the print volume to render it accordingly
 | 
			
		||||
#    if (scalar @{$self->volumes} > 0)
 | 
			
		||||
#    {
 | 
			
		||||
#        my $contained = $self->volumes->check_outside_state($self->{config});
 | 
			
		||||
#        if (!$contained) {
 | 
			
		||||
#            $self->set_warning_enabled(1);
 | 
			
		||||
#            Slic3r::GUI::_3DScene::generate_warning_texture(L("Detected object outside print volume"));
 | 
			
		||||
#            $self->on_enable_action_buttons->(0) if ($self->on_enable_action_buttons);
 | 
			
		||||
#        } else {
 | 
			
		||||
#            $self->set_warning_enabled(0);
 | 
			
		||||
#            $self->volumes->reset_outside_state();
 | 
			
		||||
#            Slic3r::GUI::_3DScene::reset_warning_texture();
 | 
			
		||||
#            $self->on_enable_action_buttons->(scalar @{$self->{model}->objects} > 0) if ($self->on_enable_action_buttons);
 | 
			
		||||
#        }
 | 
			
		||||
#    } else {
 | 
			
		||||
#        $self->set_warning_enabled(0);
 | 
			
		||||
#        Slic3r::GUI::_3DScene::reset_warning_texture();
 | 
			
		||||
#    }
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
#sub update_bed_size {
 | 
			
		||||
#    my ($self) = @_;
 | 
			
		||||
#    $self->set_bed_shape($self->{config}->bed_shape);
 | 
			
		||||
#}
 | 
			
		||||
#
 | 
			
		||||
## Called by the Platter wxNotebook when this page is activated.
 | 
			
		||||
#sub OnActivate {
 | 
			
		||||
#    my ($self) = @_;
 | 
			
		||||
#    $self->reload_scene(1) if ($self->{reload_delayed});
 | 
			
		||||
#}
 | 
			
		||||
#==============================================================================================================================
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ sub new {
 | 
			
		|||
 | 
			
		||||
    # init GUI elements
 | 
			
		||||
    my $canvas = Slic3r::GUI::3DScene->new($self);
 | 
			
		||||
    $canvas->use_plain_shader(1);
 | 
			
		||||
    Slic3r::GUI::_3DScene::enable_shader($canvas, 1);
 | 
			
		||||
    $self->canvas($canvas);
 | 
			
		||||
    my $slider_low = Wx::Slider->new(
 | 
			
		||||
        $self, -1,
 | 
			
		||||
| 
						 | 
				
			
			@ -277,8 +277,8 @@ sub new {
 | 
			
		|||
 | 
			
		||||
sub reload_print {
 | 
			
		||||
    my ($self, $force) = @_;
 | 
			
		||||
    
 | 
			
		||||
    $self->canvas->reset_objects;
 | 
			
		||||
 | 
			
		||||
    Slic3r::GUI::_3DScene::reset_volumes($self->canvas);
 | 
			
		||||
    $self->_loaded(0);
 | 
			
		||||
 | 
			
		||||
    if (! $self->IsShown && ! $force) {
 | 
			
		||||
| 
						 | 
				
			
			@ -304,7 +304,7 @@ sub refresh_print {
 | 
			
		|||
sub reset_gcode_preview_data {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    $self->gcode_preview_data->reset;
 | 
			
		||||
    $self->canvas->reset_legend_texture();
 | 
			
		||||
    Slic3r::GUI::_3DScene::reset_legend_texture();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub load_print {
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +329,7 @@ sub load_print {
 | 
			
		|||
 | 
			
		||||
    if ($n_layers == 0) {
 | 
			
		||||
        $self->reset_sliders;
 | 
			
		||||
        $self->canvas->reset_legend_texture();
 | 
			
		||||
        Slic3r::GUI::_3DScene::reset_legend_texture();
 | 
			
		||||
        $self->canvas->Refresh;  # clears canvas
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -364,23 +364,25 @@ sub load_print {
 | 
			
		|||
 | 
			
		||||
        if ($self->gcode_preview_data->empty) {
 | 
			
		||||
            # load skirt and brim
 | 
			
		||||
            $self->canvas->load_print_toolpaths($self->print, \@colors);
 | 
			
		||||
            $self->canvas->load_wipe_tower_toolpaths($self->print, \@colors);        
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
 | 
			
		||||
            Slic3r::GUI::_3DScene::load_print_toolpaths($self->canvas);
 | 
			
		||||
            Slic3r::GUI::_3DScene::load_wipe_tower_toolpaths($self->canvas, \@colors);
 | 
			
		||||
            foreach my $object (@{$self->print->objects}) {
 | 
			
		||||
                $self->canvas->load_print_object_toolpaths($object, \@colors);            
 | 
			
		||||
                Slic3r::GUI::_3DScene::load_print_object_toolpaths($self->canvas, $object, \@colors);
 | 
			
		||||
                # Show the objects in very transparent color.
 | 
			
		||||
                #my @volume_ids = $self->canvas->load_object($object->model_object);
 | 
			
		||||
                #$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids;
 | 
			
		||||
            }
 | 
			
		||||
            $self->show_hide_ui_elements('simple');
 | 
			
		||||
            $self->canvas->reset_legend_texture();
 | 
			
		||||
            Slic3r::GUI::_3DScene::reset_legend_texture();
 | 
			
		||||
        } else {
 | 
			
		||||
            $self->{force_sliders_full_range} = (scalar(@{$self->canvas->volumes}) == 0);
 | 
			
		||||
            $self->canvas->load_gcode_preview($self->print, $self->gcode_preview_data, \@colors);
 | 
			
		||||
            $self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0);
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
 | 
			
		||||
            Slic3r::GUI::_3DScene::load_gcode_preview($self->canvas, $self->gcode_preview_data, \@colors);
 | 
			
		||||
            $self->show_hide_ui_elements('full');
 | 
			
		||||
 | 
			
		||||
            # recalculates zs and update sliders accordingly
 | 
			
		||||
            $self->{layers_z} = $self->canvas->get_current_print_zs(1);
 | 
			
		||||
            $self->{layers_z} = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 1);
 | 
			
		||||
            $n_layers = scalar(@{$self->{layers_z}});            
 | 
			
		||||
            if ($n_layers == 0) {
 | 
			
		||||
                # all layers filtered out
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +468,7 @@ sub set_z_range
 | 
			
		|||
    $self->{z_label_low}->SetLabel(sprintf '%.2f', $z_low);
 | 
			
		||||
    $self->{z_label_high}->SetLabel(sprintf '%.2f', $z_high);
 | 
			
		||||
    
 | 
			
		||||
    my $layers_z = $self->canvas->get_current_print_zs(0);
 | 
			
		||||
    my $layers_z = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 0);
 | 
			
		||||
    for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
 | 
			
		||||
        if (($z_low - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_low + 1e-6)) {
 | 
			
		||||
            $self->{z_label_low_idx}->SetLabel(sprintf '%d', $i + 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -480,7 +482,7 @@ sub set_z_range
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $self->canvas->set_toolpaths_range($z_low - 1e-6, $z_high + 1e-6);
 | 
			
		||||
    Slic3r::GUI::_3DScene::set_toolpaths_range($self->canvas, $z_low - 1e-6, $z_high + 1e-6);
 | 
			
		||||
    $self->canvas->Refresh if $self->IsShown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -510,11 +512,6 @@ sub set_z_idx_high
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_bed_shape {
 | 
			
		||||
    my ($self, $bed_shape) = @_;
 | 
			
		||||
    $self->canvas->set_bed_shape($bed_shape);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub set_number_extruders {
 | 
			
		||||
    my ($self, $number_extruders) = @_;
 | 
			
		||||
    if ($self->{number_extruders} != $number_extruders) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ use utf8;
 | 
			
		|||
use Slic3r::Geometry qw(PI X);
 | 
			
		||||
use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
 | 
			
		||||
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
 | 
			
		||||
use List::Util qw(max);
 | 
			
		||||
use base 'Wx::Dialog';
 | 
			
		||||
 | 
			
		||||
sub new {
 | 
			
		||||
| 
						 | 
				
			
			@ -112,10 +113,13 @@ sub new {
 | 
			
		|||
    my $canvas;
 | 
			
		||||
    if ($Slic3r::GUI::have_OpenGL) {
 | 
			
		||||
        $canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
 | 
			
		||||
        $canvas->load_object($self->{model_object}, undef, undef, [0]);
 | 
			
		||||
        $canvas->set_auto_bed_shape;
 | 
			
		||||
        Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $self->{model_object}, 0, [0]);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_axes_length($canvas, 2.0 * max(@{ Slic3r::GUI::_3DScene::get_volumes_bounding_box($canvas)->size }));
 | 
			
		||||
        $canvas->SetSize([500,500]);
 | 
			
		||||
        $canvas->SetMinSize($canvas->GetSize);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_config($canvas, $self->GetParent->{config});
 | 
			
		||||
        Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($canvas, 1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
 | 
			
		||||
| 
						 | 
				
			
			@ -144,6 +148,7 @@ sub new {
 | 
			
		|||
        # Note that the window was already closed, so a pending update will not be executed.
 | 
			
		||||
        $self->{already_closed} = 1;
 | 
			
		||||
        $self->EndModal(wxID_OK);
 | 
			
		||||
        $self->{canvas}->Destroy;
 | 
			
		||||
        $self->Destroy();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +156,7 @@ sub new {
 | 
			
		|||
        # Note that the window was already closed, so a pending update will not be executed.
 | 
			
		||||
        $self->{already_closed} = 1;
 | 
			
		||||
        $self->EndModal(wxID_CANCEL);
 | 
			
		||||
        $self->{canvas}->Destroy;
 | 
			
		||||
        $self->Destroy();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -241,15 +247,12 @@ sub _update {
 | 
			
		|||
                    for @$expolygon;
 | 
			
		||||
                $expolygon->translate(map Slic3r::Geometry::scale($_), @{ $self->{model_object}->instances->[0]->offset });
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $self->{canvas}->reset_objects;
 | 
			
		||||
            $self->{canvas}->load_object($_, undef, undef, [0]) for @objects;
 | 
			
		||||
            $self->{canvas}->SetCuttingPlane(
 | 
			
		||||
                $self->{cut_options}{z},
 | 
			
		||||
                [@expolygons],
 | 
			
		||||
            );
 | 
			
		||||
            $self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->{config});
 | 
			
		||||
            $self->{canvas}->Render;
 | 
			
		||||
 | 
			
		||||
            Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
 | 
			
		||||
            Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $_, 0, [0]) for @objects;
 | 
			
		||||
            Slic3r::GUI::_3DScene::set_cutting_plane($self->{canvas}, $self->{cut_options}{z}, [@expolygons]);
 | 
			
		||||
            Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
 | 
			
		||||
            Slic3r::GUI::_3DScene::render($self->{canvas});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ use File::Basename qw(basename);
 | 
			
		|||
use Wx qw(:misc :sizer :treectrl :button :keycode wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL wxMOD_CONTROL
 | 
			
		||||
    wxTheApp);
 | 
			
		||||
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_KEY_DOWN EVT_KEY_DOWN);
 | 
			
		||||
use List::Util qw(max);
 | 
			
		||||
use base 'Wx::Panel';
 | 
			
		||||
 | 
			
		||||
use constant ICON_OBJECT        => 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -150,19 +151,19 @@ sub new {
 | 
			
		|||
    my $canvas;
 | 
			
		||||
    if ($Slic3r::GUI::have_OpenGL) {
 | 
			
		||||
        $canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
 | 
			
		||||
        $canvas->enable_picking(1);
 | 
			
		||||
        $canvas->select_by('volume');
 | 
			
		||||
        
 | 
			
		||||
        $canvas->on_select(sub {
 | 
			
		||||
        Slic3r::GUI::_3DScene::enable_picking($canvas, 1);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_select_by($canvas, 'volume');
 | 
			
		||||
        Slic3r::GUI::_3DScene::register_on_select_object_callback($canvas, sub {
 | 
			
		||||
            my ($volume_idx) = @_;
 | 
			
		||||
            # convert scene volume to model object volume
 | 
			
		||||
            $self->reload_tree(($volume_idx == -1) ? undef : $canvas->volumes->[$volume_idx]->volume_idx);
 | 
			
		||||
            $self->reload_tree($volume_idx);
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        $canvas->load_object($self->{model_object}, undef, undef, [0]);
 | 
			
		||||
        $canvas->set_auto_bed_shape;
 | 
			
		||||
        Slic3r::GUI::_3DScene::load_model_object($canvas, $self->{model_object}, 0, [0]);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas);
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_axes_length($canvas, 2.0 * max(@{ Slic3r::GUI::_3DScene::get_volumes_bounding_box($canvas)->size }));
 | 
			
		||||
        $canvas->SetSize([500,700]);
 | 
			
		||||
        $canvas->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
 | 
			
		||||
        Slic3r::GUI::_3DScene::set_config($canvas, $self->GetParent->GetParent->GetParent->{config});
 | 
			
		||||
        Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($canvas);
 | 
			
		||||
        Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($canvas, 1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
 | 
			
		||||
| 
						 | 
				
			
			@ -262,7 +263,7 @@ sub selection_changed {
 | 
			
		|||
    
 | 
			
		||||
    # deselect all meshes
 | 
			
		||||
    if ($self->{canvas}) {
 | 
			
		||||
        $_->set_selected(0) for @{$self->{canvas}->volumes};
 | 
			
		||||
        Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas});
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    # disable things as if nothing is selected
 | 
			
		||||
| 
						 | 
				
			
			@ -290,7 +291,7 @@ sub selection_changed {
 | 
			
		|||
        if ($itemData->{type} eq 'volume') {
 | 
			
		||||
            # select volume in 3D preview
 | 
			
		||||
            if ($self->{canvas}) {
 | 
			
		||||
                $self->{canvas}->volumes->[ $itemData->{volume_id} ]->set_selected(1);
 | 
			
		||||
                Slic3r::GUI::_3DScene::select_volume($self->{canvas}, $itemData->{volume_id});
 | 
			
		||||
            }
 | 
			
		||||
            $self->{btn_delete}->Enable;
 | 
			
		||||
            $self->{btn_split}->Enable;
 | 
			
		||||
| 
						 | 
				
			
			@ -333,7 +334,7 @@ sub selection_changed {
 | 
			
		|||
        $self->{settings_panel}->enable;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $self->{canvas}->Render if $self->{canvas};
 | 
			
		||||
    Slic3r::GUI::_3DScene::render($self->{canvas}) if $self->{canvas};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub on_btn_load {
 | 
			
		||||
| 
						 | 
				
			
			@ -429,7 +430,7 @@ sub on_btn_move_up {
 | 
			
		|||
    if ($itemData && $itemData->{type} eq 'volume') {
 | 
			
		||||
        my $volume_id = $itemData->{volume_id};
 | 
			
		||||
        if ($self->{model_object}->move_volume_up($volume_id)) {
 | 
			
		||||
            $self->{canvas}->volumes->move_volume_up($volume_id);
 | 
			
		||||
            Slic3r::GUI::_3DScene::move_volume_up($self->{canvas}, $volume_id);
 | 
			
		||||
            $self->{parts_changed} = 1;
 | 
			
		||||
            $self->reload_tree($volume_id - 1);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -442,7 +443,7 @@ sub on_btn_move_down {
 | 
			
		|||
    if ($itemData && $itemData->{type} eq 'volume') {
 | 
			
		||||
        my $volume_id = $itemData->{volume_id};
 | 
			
		||||
        if ($self->{model_object}->move_volume_down($volume_id)) {
 | 
			
		||||
            $self->{canvas}->volumes->move_volume_down($volume_id);
 | 
			
		||||
            Slic3r::GUI::_3DScene::move_volume_down($self->{canvas}, $volume_id);
 | 
			
		||||
            $self->{parts_changed} = 1;
 | 
			
		||||
            $self->reload_tree($volume_id + 1);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -487,11 +488,11 @@ sub _parts_changed {
 | 
			
		|||
    
 | 
			
		||||
    $self->reload_tree;
 | 
			
		||||
    if ($self->{canvas}) {
 | 
			
		||||
        $self->{canvas}->reset_objects;
 | 
			
		||||
        $self->{canvas}->load_object($self->{model_object});
 | 
			
		||||
        $self->{canvas}->zoom_to_volumes;
 | 
			
		||||
        $self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
 | 
			
		||||
        $self->{canvas}->Render;
 | 
			
		||||
        Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
 | 
			
		||||
        Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $self->{model_object}, 0, [0]);
 | 
			
		||||
        Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas});
 | 
			
		||||
        Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
 | 
			
		||||
        Slic3r::GUI::_3DScene::render($self->{canvas});        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -511,6 +512,11 @@ sub CanClose {
 | 
			
		|||
    return ! Slic3r::GUI::catch_error($self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub Destroy {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    $self->{canvas}->Destroy if ($self->{canvas});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub PartsChanged {
 | 
			
		||||
    my ($self) = @_;
 | 
			
		||||
    return $self->{parts_changed};
 | 
			
		||||
| 
						 | 
				
			
			@ -525,18 +531,18 @@ sub _update_canvas {
 | 
			
		|||
    my ($self) = @_;
 | 
			
		||||
    
 | 
			
		||||
    if ($self->{canvas}) {
 | 
			
		||||
        $self->{canvas}->reset_objects;
 | 
			
		||||
        $self->{canvas}->load_object($self->{model_object});
 | 
			
		||||
        Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
 | 
			
		||||
        Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $self->{model_object}, 0, [0]);
 | 
			
		||||
 | 
			
		||||
        # restore selection, if any
 | 
			
		||||
        if (my $itemData = $self->get_selection) {
 | 
			
		||||
            if ($itemData->{type} eq 'volume') {
 | 
			
		||||
                $self->{canvas}->volumes->[ $itemData->{volume_id} ]->set_selected(1);
 | 
			
		||||
                Slic3r::GUI::_3DScene::select_volume($self->{canvas}, $itemData->{volume_id});
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
                
 | 
			
		||||
        $self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
 | 
			
		||||
        $self->{canvas}->Render;
 | 
			
		||||
 | 
			
		||||
        Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
 | 
			
		||||
        Slic3r::GUI::_3DScene::render($self->{canvas});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -558,10 +564,10 @@ sub _update {
 | 
			
		|||
    $self->{parts_changed} = 1;
 | 
			
		||||
    my @objects = ();
 | 
			
		||||
    push @objects, $self->{model_object};
 | 
			
		||||
    $self->{canvas}->reset_objects;
 | 
			
		||||
    $self->{canvas}->load_object($_, undef, [0]) for @objects;
 | 
			
		||||
    $self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
 | 
			
		||||
    $self->{canvas}->Render;
 | 
			
		||||
    Slic3r::GUI::_3DScene::reset_volumes($self->{canvas});
 | 
			
		||||
    Slic3r::GUI::_3DScene::load_model_object($self->{canvas}, $_, 0, [0]) for @objects;
 | 
			
		||||
    Slic3r::GUI::_3DScene::update_volumes_colors_by_extruder($self->{canvas});
 | 
			
		||||
    Slic3r::GUI::_3DScene::render($self->{canvas});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ sub new {
 | 
			
		|||
        wxTheApp->save_window_pos($self, "object_settings");
 | 
			
		||||
        
 | 
			
		||||
        $self->EndModal(wxID_OK);
 | 
			
		||||
        $self->{parts}->Destroy;
 | 
			
		||||
        $self->Destroy;
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue