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