2012-05-04 10:15:33 +02:00
package Slic3r::GUI::Plater ;
2012-04-30 14:56:01 +02:00
use strict ;
use warnings ;
use utf8 ;
use File::Basename qw(basename dirname) ;
use Math::ConvexHull qw(convex_hull) ;
2012-04-30 17:10:54 +02:00
use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 scale unscale) ;
2012-04-30 18:54:36 +02:00
use Slic3r::Geometry::Clipper qw(JT_ROUND) ;
2012-05-19 21:13:10 +02:00
use threads::shared qw(shared_clone) ;
2012-07-03 01:20:30 +02:00
use Wx qw(:bitmap :brush :button :dialog :filedialog :font :icon :id :listctrl :misc :pen :sizer :toolbar :window) ;
2012-07-01 19:24:06 +02:00
use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL) ;
2012-04-30 14:56:01 +02:00
use base 'Wx::Panel' ;
2012-05-04 11:22:56 +02:00
use constant TB_MORE => 1 ;
use constant TB_LESS => 2 ;
use constant TB_45CW => 3 ;
use constant TB_45CCW => 4 ;
use constant TB_ROTATE => 5 ;
use constant TB_SCALE => 6 ;
use constant TB_SPLIT => 7 ;
2012-05-05 21:08:15 +02:00
my $THUMBNAIL_DONE_EVENT : shared = Wx:: NewEventType ;
my $PROGRESS_BAR_EVENT : shared = Wx:: NewEventType ;
my $MESSAGE_DIALOG_EVENT : shared = Wx:: NewEventType ;
my $EXPORT_COMPLETED_EVENT : shared = Wx:: NewEventType ;
2012-05-19 21:13:10 +02:00
my $EXPORT_FAILED_EVENT : shared = Wx:: NewEventType ;
2012-04-30 20:59:14 +02:00
2012-04-30 14:56:01 +02:00
sub new {
my $class = shift ;
my ( $parent ) = @_ ;
my $self = $class -> SUPER:: new ( $parent , - 1 );
2012-07-03 01:20:30 +02:00
$self -> { canvas } = Wx::Panel -> new ( $self , - 1 , wxDefaultPosition , [ 300 , 300 ]);
2012-04-30 14:56:01 +02:00
$self -> { canvas } -> SetBackgroundColour ( Wx:: wxWHITE );
EVT_PAINT ( $self -> { canvas }, \& repaint );
EVT_MOUSE_EVENTS ( $self -> { canvas }, \& mouse_event );
2012-07-01 19:24:06 +02:00
$self -> { objects_brush } = Wx::Brush -> new ( Wx::Colour -> new ( 210 , 210 , 210 ), wxSOLID );
$self -> { selected_brush } = Wx::Brush -> new ( Wx::Colour -> new ( 255 , 128 , 128 ), wxSOLID );
$self -> { transparent_brush } = Wx::Brush -> new ( Wx::Colour -> new ( 0 , 0 , 0 ), wxTRANSPARENT );
$self -> { grid_pen } = Wx::Pen -> new ( Wx::Colour -> new ( 230 , 230 , 230 ), 1 , wxSOLID );
$self -> { print_center_pen } = Wx::Pen -> new ( Wx::Colour -> new ( 200 , 200 , 200 ), 1 , wxSOLID );
$self -> { clearance_pen } = Wx::Pen -> new ( Wx::Colour -> new ( 0 , 0 , 200 ), 1 , wxSOLID );
$self -> { skirt_pen } = Wx::Pen -> new ( Wx::Colour -> new ( 150 , 150 , 150 ), 1 , wxSOLID );
2012-04-30 14:56:01 +02:00
2012-07-15 22:14:34 +02:00
$self -> { list } = Wx::ListView -> new ( $self , - 1 , wxDefaultPosition , [ - 1 , 180 ], wxLC_SINGLE_SEL | wxLC_REPORT | wxBORDER_SUNKEN );
2012-07-01 19:24:06 +02:00
$self -> { list } -> InsertColumn ( 0 , "Name" , wxLIST_FORMAT_LEFT , 300 );
$self -> { list } -> InsertColumn ( 1 , "Copies" , wxLIST_FORMAT_CENTER , 50 );
$self -> { list } -> InsertColumn ( 2 , "Scale" , wxLIST_FORMAT_CENTER , wxLIST_AUTOSIZE_USEHEADER );
2012-04-30 14:56:01 +02:00
EVT_LIST_ITEM_SELECTED ( $self , $self -> { list }, \& list_item_selected );
EVT_LIST_ITEM_DESELECTED ( $self , $self -> { list }, \& list_item_deselected );
2012-05-04 11:22:56 +02:00
# toolbar for object manipulation
2012-05-20 16:24:10 +02:00
if ( !& Wx:: wxMSW ) {
2012-05-04 12:56:15 +02:00
Wx::ToolTip:: Enable ( 1 );
2012-07-15 22:14:34 +02:00
$self -> { htoolbar } = Wx::ToolBar -> new ( $self , - 1 , wxDefaultPosition , wxDefaultSize , wxTB_HORIZONTAL | wxTB_TEXT | wxBORDER_SIMPLE );
2012-07-01 19:24:06 +02:00
$self -> { htoolbar } -> AddTool ( TB_MORE , "More" , Wx::Bitmap -> new ( "$Slic3r::var/add.png" , wxBITMAP_TYPE_PNG ), '' );
$self -> { htoolbar } -> AddTool ( TB_LESS , "Less" , Wx::Bitmap -> new ( "$Slic3r::var/delete.png" , wxBITMAP_TYPE_PNG ), '' );
2012-05-04 11:22:56 +02:00
$self -> { htoolbar } -> AddSeparator ;
2012-07-01 19:24:06 +02:00
$self -> { htoolbar } -> AddTool ( TB_45CCW , "45° ccw" , Wx::Bitmap -> new ( "$Slic3r::var/arrow_rotate_anticlockwise.png" , wxBITMAP_TYPE_PNG ), '' );
$self -> { htoolbar } -> AddTool ( TB_45CW , "45° cw" , Wx::Bitmap -> new ( "$Slic3r::var/arrow_rotate_clockwise.png" , wxBITMAP_TYPE_PNG ), '' );
2012-07-01 23:29:56 +02:00
$self -> { htoolbar } -> AddTool ( TB_ROTATE , "Rotate…" , Wx::Bitmap -> new ( "$Slic3r::var/arrow_rotate_clockwise.png" , wxBITMAP_TYPE_PNG ), '' );
2012-05-04 11:22:56 +02:00
$self -> { htoolbar } -> AddSeparator ;
2012-07-01 23:29:56 +02:00
$self -> { htoolbar } -> AddTool ( TB_SCALE , "Scale…" , Wx::Bitmap -> new ( "$Slic3r::var/arrow_out.png" , wxBITMAP_TYPE_PNG ), '' );
2012-05-04 11:22:56 +02:00
$self -> { htoolbar } -> AddSeparator ;
2012-07-01 19:24:06 +02:00
$self -> { htoolbar } -> AddTool ( TB_SPLIT , "Split" , Wx::Bitmap -> new ( "$Slic3r::var/shape_ungroup.png" , wxBITMAP_TYPE_PNG ), '' );
2012-05-20 16:24:10 +02:00
} else {
my %tbar_buttons = ( increase => "More" , decrease => "Less" , rotate45ccw => "45°" , rotate45cw => "45°" ,
rotate => "Rotate…" , changescale => "Scale…" , split => "Split" );
$self -> { btoolbar } = Wx::BoxSizer -> new ( wxHORIZONTAL );
for ( qw(increase decrease rotate45ccw rotate45cw rotate changescale split) ) {
2012-07-03 01:20:30 +02:00
$self -> { "btn_$_" } = Wx::Button -> new ( $self , - 1 , $tbar_buttons { $_ }, wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT );
2012-05-20 16:24:10 +02:00
$self -> { btoolbar } -> Add ( $self -> { "btn_$_" });
}
2012-05-04 11:22:56 +02:00
}
# general buttons
2012-07-03 01:20:30 +02:00
$self -> { btn_load } = Wx::Button -> new ( $self , - 1 , "Add…" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
$self -> { btn_remove } = Wx::Button -> new ( $self , - 1 , "Delete" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
$self -> { btn_reset } = Wx::Button -> new ( $self , - 1 , "Delete All" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
$self -> { btn_arrange } = Wx::Button -> new ( $self , - 1 , "Autoarrange" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
$self -> { btn_export_gcode } = Wx::Button -> new ( $self , - 1 , "Export G-code…" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
2012-04-30 14:56:01 +02:00
$self -> { btn_export_gcode } -> SetDefault ;
2012-07-03 01:20:30 +02:00
$self -> { btn_export_stl } = Wx::Button -> new ( $self , - 1 , "Export STL…" , wxDefaultPosition , wxDefaultSize , wxBU_LEFT );
2012-05-04 11:22:56 +02:00
2012-05-01 16:49:34 +02:00
if ( & Wx:: wxVERSION_STRING =~ / 2\.9\.[1-9]/ ) {
2012-05-04 11:22:56 +02:00
my %icons = qw(
load brick_add.png
remove brick_delete.png
reset cross.png
arrange bricks.png
2012-05-19 15:02:23 +02:00
export_gcode cog_go.png
2012-05-04 11:22:56 +02:00
export_stl brick_go.png
increase add.png
decrease delete.png
rotate45cw arrow_rotate_clockwise.png
rotate45ccw arrow_rotate_anticlockwise.png
rotate arrow_rotate_clockwise.png
changescale arrow_out.png
split shape_ungroup.png
) ;
2012-05-20 16:24:10 +02:00
for ( grep $self -> { "btn_$_" }, keys %icons ) {
2012-07-01 19:24:06 +02:00
$self -> { "btn_$_" } -> SetBitmap ( Wx::Bitmap -> new ( "$Slic3r::var/$icons{$_}" , wxBITMAP_TYPE_PNG ));
2012-05-20 16:24:10 +02:00
}
2012-05-01 16:49:34 +02:00
}
2012-04-30 14:56:01 +02:00
$self -> selection_changed ( 0 );
$self -> object_list_changed ;
EVT_BUTTON ( $self , $self -> { btn_load }, \& load );
EVT_BUTTON ( $self , $self -> { btn_remove }, \& remove );
EVT_BUTTON ( $self , $self -> { btn_reset }, \& reset );
EVT_BUTTON ( $self , $self -> { btn_arrange }, \& arrange );
EVT_BUTTON ( $self , $self -> { btn_export_gcode }, \& export_gcode );
2012-04-30 17:10:54 +02:00
EVT_BUTTON ( $self , $self -> { btn_export_stl }, \& export_stl );
2012-04-30 14:56:01 +02:00
2012-05-04 11:22:56 +02:00
if ( $self -> { htoolbar }) {
EVT_TOOL ( $self , TB_MORE , \& increase );
EVT_TOOL ( $self , TB_LESS , \& decrease );
EVT_TOOL ( $self , TB_45CW , sub { $_ [ 0 ] -> rotate ( - 45 ) });
EVT_TOOL ( $self , TB_45CCW , sub { $_ [ 0 ] -> rotate ( 45 ) });
2012-05-04 12:56:15 +02:00
EVT_TOOL ( $self , TB_ROTATE , sub { $_ [ 0 ] -> rotate ( undef ) });
EVT_TOOL ( $self , TB_SCALE , \& changescale );
2012-05-04 11:22:56 +02:00
EVT_TOOL ( $self , TB_SPLIT , \& split_object );
} else {
EVT_BUTTON ( $self , $self -> { btn_increase }, \& increase );
EVT_BUTTON ( $self , $self -> { btn_decrease }, \& decrease );
EVT_BUTTON ( $self , $self -> { btn_rotate45cw }, sub { $_ [ 0 ] -> rotate ( - 45 ) });
EVT_BUTTON ( $self , $self -> { btn_rotate45ccw }, sub { $_ [ 0 ] -> rotate ( 45 ) });
EVT_BUTTON ( $self , $self -> { btn_changescale }, \& changescale );
EVT_BUTTON ( $self , $self -> { btn_rotate }, sub { $_ [ 0 ] -> rotate ( undef ) });
EVT_BUTTON ( $self , $self -> { btn_split }, \& split_object );
}
2012-05-04 10:15:33 +02:00
$_ -> SetDropTarget ( Slic3r::GUI::Plater::DropTarget -> new ( $self ))
2012-04-30 17:10:54 +02:00
for $self , $self -> { canvas }, $self -> { list };
2012-04-30 14:56:01 +02:00
2012-04-30 20:59:14 +02:00
EVT_COMMAND ( $self , - 1 , $THUMBNAIL_DONE_EVENT , sub {
my ( $self , $event ) = @_ ;
my ( $obj_idx , $thumbnail ) = @ { $event -> GetData };
$self -> { thumbnails }[ $obj_idx ] = $thumbnail ;
2012-04-30 22:34:41 +02:00
$self -> make_thumbnail2 ;
2012-04-30 20:59:14 +02:00
});
2012-05-05 21:08:15 +02:00
EVT_COMMAND ( $self , - 1 , $PROGRESS_BAR_EVENT , sub {
my ( $self , $event ) = @_ ;
my ( $percent , $message ) = @ { $event -> GetData };
$self -> statusbar -> SetProgress ( $percent );
2012-07-01 23:29:56 +02:00
$self -> statusbar -> SetStatusText ( "$message…" );
2012-05-05 21:08:15 +02:00
});
EVT_COMMAND ( $self , - 1 , $MESSAGE_DIALOG_EVENT , sub {
my ( $self , $event ) = @_ ;
Wx::MessageDialog -> new ( $self , @ { $event -> GetData }) -> ShowModal ;
});
EVT_COMMAND ( $self , - 1 , $EXPORT_COMPLETED_EVENT , sub {
my ( $self , $event ) = @_ ;
$self -> on_export_completed ( @ { $event -> GetData });
});
2012-05-19 21:13:10 +02:00
EVT_COMMAND ( $self , - 1 , $EXPORT_FAILED_EVENT , sub {
my ( $self , $event ) = @_ ;
$self -> on_export_failed ;
});
2012-04-30 22:34:41 +02:00
$self -> update_bed_size ;
2012-04-30 14:56:01 +02:00
$self -> { print } = Slic3r::Print -> new ;
$self -> { thumbnails } = [] ; # polygons, each one aligned to 0,0
$self -> { scale } = [] ;
$self -> { object_previews } = [] ; # [ obj_idx, copy_idx, positioned polygon ]
$self -> { selected_objects } = [] ;
$self -> recenter ;
{
2012-05-04 11:22:56 +02:00
my $buttons = Wx::GridSizer -> new ( 2 , 3 , 5 , 5 );
$buttons -> Add ( $self -> { "btn_load" }, 0 , wxEXPAND | wxALL );
$buttons -> Add ( $self -> { "btn_arrange" }, 0 , wxEXPAND | wxALL );
$buttons -> Add ( $self -> { "btn_export_gcode" }, 0 , wxEXPAND | wxALL );
$buttons -> Add ( $self -> { "btn_remove" }, 0 , wxEXPAND | wxALL );
$buttons -> Add ( $self -> { "btn_reset" }, 0 , wxEXPAND | wxALL );
$buttons -> Add ( $self -> { "btn_export_stl" }, 0 , wxEXPAND | wxALL );
2012-04-30 14:56:01 +02:00
2012-05-04 10:41:24 +02:00
my $list_sizer = Wx::BoxSizer -> new ( wxHORIZONTAL );
$list_sizer -> Add ( $self -> { list }, 1 , wxEXPAND | wxALL , 0 );
2012-04-30 14:56:01 +02:00
my $vertical_sizer = Wx::BoxSizer -> new ( wxVERTICAL );
2012-05-04 11:22:56 +02:00
$vertical_sizer -> Add ( $self -> { htoolbar }, 0 , wxEXPAND , 0 ) if $self -> { htoolbar };
2012-05-20 16:24:10 +02:00
$vertical_sizer -> Add ( $self -> { btoolbar }, 0 , wxEXPAND , 0 ) if $self -> { btoolbar };
2012-07-01 19:24:06 +02:00
$vertical_sizer -> Add ( $list_sizer , 0 , wxEXPAND | wxBOTTOM , 10 );
2012-05-04 11:22:56 +02:00
$vertical_sizer -> Add ( $buttons , 0 , wxEXPAND );
2012-04-30 14:56:01 +02:00
2012-06-19 17:23:10 +02:00
my $hsizer = Wx::BoxSizer -> new ( wxHORIZONTAL );
$hsizer -> Add ( $self -> { canvas }, 0 , wxALL , 10 );
$hsizer -> Add ( $vertical_sizer , 1 , wxEXPAND | wxALL , 10 );
my $presets = Wx::BoxSizer -> new ( wxHORIZONTAL );
my %group_labels = (
print => 'Print settings' ,
filament => 'Filament' ,
printer => 'Printer' ,
);
$self -> { preset_choosers } = {};
for my $group ( qw(print filament printer) ) {
2012-07-03 01:20:30 +02:00
my $text = Wx::StaticText -> new ( $self , - 1 , "$group_labels{$group}:" , wxDefaultPosition , wxDefaultSize , wxALIGN_RIGHT );
$self -> { preset_choosers }{ $group } = Wx::Choice -> new ( $self , - 1 , wxDefaultPosition , [ 150 , - 1 ], [] );
2012-06-20 22:50:38 +02:00
$presets -> Add ( $text , 0 , wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT , 4 );
$presets -> Add ( $self -> { preset_choosers }{ $group }, 0 , wxALIGN_CENTER_VERTICAL | wxRIGHT , 15 );
2012-06-19 17:23:10 +02:00
}
my $sizer = Wx::BoxSizer -> new ( wxVERTICAL );
$sizer -> Add ( $hsizer , 0 , wxEXPAND | wxBOTTOM , 10 );
$sizer -> Add ( $presets , 0 , wxEXPAND | wxLEFT | wxRIGHT , 20 );
2012-04-30 14:56:01 +02:00
$sizer -> SetSizeHints ( $self );
$self -> SetSizer ( $sizer );
}
return $self ;
}
sub load {
my $self = shift ;
my $dir = $ Slic3r::GUI::SkeinPanel:: last_skein_dir || $ Slic3r::GUI::SkeinPanel:: last_config_dir || "" ;
2012-07-01 19:24:06 +02:00
my $dialog = Wx::FileDialog -> new ( $self , 'Choose one or more files (STL/OBJ/AMF):' , $dir , "" , $ Slic3r::GUI::SkeinPanel:: model_wildcard , wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST );
2012-04-30 14:56:01 +02:00
if ( $dialog -> ShowModal != wxID_OK ) {
$dialog -> Destroy ;
return ;
}
2012-05-31 09:26:30 +02:00
my @input_files = $dialog -> GetPaths ;
2012-04-30 14:56:01 +02:00
$dialog -> Destroy ;
2012-05-31 09:26:30 +02:00
$self -> load_file ( $_ ) for @input_files ;
2012-04-30 14:56:01 +02:00
}
sub load_file {
my $self = shift ;
my ( $input_file ) = @_ ;
2012-06-27 20:27:46 +02:00
$ Slic3r::GUI::SkeinPanel:: last_skein_dir = dirname ( $input_file );
2012-04-30 14:56:01 +02:00
2012-07-01 23:29:56 +02:00
my $process_dialog = Wx::ProgressDialog -> new ( 'Loading…' , "Processing input file…" , 100 , $self , 0 );
2012-04-30 21:49:44 +02:00
$process_dialog -> Pulse ;
2012-04-30 14:56:01 +02:00
local $SIG { __WARN__ } = Slic3r::GUI:: warning_catcher ( $self );
2012-05-01 00:30:46 +02:00
$self -> { print } -> add_object_from_file ( $input_file );
2012-04-30 14:56:01 +02:00
my $obj_idx = $# { $self -> { print } -> objects };
2012-04-30 21:49:44 +02:00
$process_dialog -> Destroy ;
2012-04-30 14:56:01 +02:00
2012-05-01 00:30:46 +02:00
$self -> object_loaded ( $obj_idx );
2012-05-04 12:56:15 +02:00
$self -> statusbar -> SetStatusText ( "Loaded $input_file" );
2012-05-01 00:30:46 +02:00
}
sub object_loaded {
my $self = shift ;
my ( $obj_idx , %params ) = @_ ;
my $object = $self -> { print } -> objects -> [ $obj_idx ];
$self -> { list } -> InsertStringItem ( $obj_idx , basename ( $object -> input_file ));
2012-04-30 14:56:01 +02:00
$self -> { list } -> SetItem ( $obj_idx , 1 , "1" );
$self -> { list } -> SetItem ( $obj_idx , 2 , "100%" );
push @ { $self -> { scale }}, 1 ;
$self -> make_thumbnail ( $obj_idx );
2012-05-01 00:30:46 +02:00
$self -> arrange unless $params { no_arrange };
2012-04-30 14:56:01 +02:00
$self -> { list } -> Update ;
$self -> { list } -> Select ( $obj_idx , 1 );
$self -> object_list_changed ;
}
sub remove {
my $self = shift ;
foreach my $pobj ( @ { $self -> { selected_objects }}) {
my ( $obj_idx , $copy_idx ) = ( $pobj -> [ 0 ], $pobj -> [ 1 ]);
$self -> { print } -> copies -> [ $obj_idx ][ $copy_idx ] = undef ;
}
my @objects_to_remove = ();
for my $obj_idx ( 0 .. $# { $self -> { print } -> objects }) {
my $copies = $self -> { print } -> copies -> [ $obj_idx ];
# filter out removed copies
@$copies = grep defined $_ , @$copies ;
# update copies count in list
$self -> { list } -> SetItem ( $obj_idx , 1 , scalar @$copies );
# if no copies are left, remove the object itself
push @objects_to_remove , $obj_idx if ! @$copies ;
}
for my $obj_idx ( sort { $b <=> $a } @objects_to_remove ) {
splice @ { $self -> { print } -> objects }, $obj_idx , 1 ;
splice @ { $self -> { print } -> copies }, $obj_idx , 1 ;
splice @ { $self -> { thumbnails }}, $obj_idx , 1 ;
splice @ { $self -> { scale }}, $obj_idx , 1 ;
$self -> { list } -> DeleteItem ( $obj_idx );
}
$self -> { selected_objects } = [] ;
$self -> selection_changed ( 0 );
$self -> object_list_changed ;
$self -> recenter ;
$self -> { canvas } -> Refresh ;
}
sub reset {
my $self = shift ;
@ { $self -> { print } -> objects } = ();
@ { $self -> { print } -> copies } = ();
@ { $self -> { thumbnails }} = ();
@ { $self -> { scale }} = ();
$self -> { list } -> DeleteAllItems ;
$self -> { selected_objects } = [] ;
$self -> selection_changed ( 0 );
$self -> object_list_changed ;
$self -> { canvas } -> Refresh ;
}
sub increase {
my $self = shift ;
my $obj_idx = $self -> selected_object_idx ;
my $copies = $self -> { print } -> copies -> [ $obj_idx ];
push @$copies , [ $copies -> [ - 1 ] -> [ X ] + scale 10 , $copies -> [ - 1 ] -> [ Y ] + scale 10 ];
$self -> { list } -> SetItem ( $obj_idx , 1 , scalar @$copies );
$self -> arrange ;
}
sub decrease {
my $self = shift ;
my $obj_idx = $self -> selected_object_idx ;
$self -> { selected_objects } = [ + ( grep { $_ -> [ 0 ] == $obj_idx } @ { $self -> { object_previews }})[ - 1 ] ];
$self -> remove ;
if ( $self -> { print } -> objects -> [ $obj_idx ]) {
$self -> { list } -> Select ( $obj_idx , 0 );
$self -> { list } -> Select ( $obj_idx , 1 );
}
}
sub rotate {
my $self = shift ;
my ( $angle ) = @_ ;
my $obj_idx = $self -> selected_object_idx ;
my $object = $self -> { print } -> objects -> [ $obj_idx ];
2012-04-30 22:14:27 +02:00
if ( ! defined $angle ) {
$angle = Wx:: GetNumberFromUser ( "" , "Enter the rotation angle:" , "Rotate" , 0 , - 364 , 364 , $self );
return if ! $angle || $angle == - 1 ;
}
2012-07-01 23:29:56 +02:00
$self -> statusbar -> SetStatusText ( "Rotating object…" );
2012-05-04 12:56:15 +02:00
$self -> statusbar -> StartBusy ;
2012-04-30 14:56:01 +02:00
# rotate, realign to 0,0 and update size
$object -> mesh -> rotate ( $angle );
$object -> mesh -> align_to_origin ;
my @size = $object -> mesh -> size ;
$object -> x_length ( $size [ X ]);
$object -> y_length ( $size [ Y ]);
$self -> make_thumbnail ( $obj_idx );
2012-05-17 19:32:50 +02:00
$self -> recenter ;
$self -> { canvas } -> Refresh ;
2012-05-04 12:56:15 +02:00
$self -> statusbar -> StopBusy ;
$self -> statusbar -> SetStatusText ( "" );
2012-04-30 14:56:01 +02:00
}
sub arrange {
my $self = shift ;
2012-04-30 17:25:08 +02:00
eval {
$self -> { print } -> arrange_objects ;
};
2012-05-19 20:48:26 +02:00
# ignore arrange warnings on purpose
2012-04-30 17:25:08 +02:00
2012-04-30 14:56:01 +02:00
$self -> recenter ;
$self -> { canvas } -> Refresh ;
}
sub changescale {
my $self = shift ;
my $obj_idx = $self -> selected_object_idx ;
my $scale = $self -> { scale }[ $obj_idx ];
2012-06-29 20:46:51 +02:00
# max scale factor should be above 2540 to allow importing files exported in inches
$scale = Wx:: GetNumberFromUser ( "" , "Enter the scale % for the selected object:" , "Scale" , $scale * 100 , 0 , 5000 , $self );
2012-04-30 14:56:01 +02:00
return if ! $scale || $scale == - 1 ;
2012-07-01 23:29:56 +02:00
$self -> statusbar -> SetStatusText ( "Scaling object…" );
2012-05-04 12:56:15 +02:00
$self -> statusbar -> StartBusy ;
2012-04-30 14:56:01 +02:00
my $object = $self -> { print } -> objects -> [ $obj_idx ];
my $mesh = $object -> mesh ;
$mesh -> scale ( $scale /100 / $self -> { scale }[ $obj_idx ]);
$object -> mesh -> align_to_origin ;
my @size = $object -> mesh -> size ;
$object -> x_length ( $size [ X ]);
$object -> y_length ( $size [ Y ]);
$self -> { scale }[ $obj_idx ] = $scale / 100 ;
$self -> { list } -> SetItem ( $obj_idx , 2 , "$scale%" );
$self -> make_thumbnail ( $obj_idx );
2012-04-30 17:25:08 +02:00
$self -> arrange ;
2012-05-04 12:56:15 +02:00
$self -> statusbar -> StopBusy ;
$self -> statusbar -> SetStatusText ( "" );
2012-04-30 14:56:01 +02:00
}
2012-05-01 00:30:46 +02:00
sub split_object {
my $self = shift ;
my $obj_idx = $self -> selected_object_idx ;
my $current_object = $self -> { print } -> objects -> [ $obj_idx ];
2012-05-04 11:26:15 +02:00
my $current_copies_num = @ { $self -> { print } -> copies -> [ $obj_idx ]};
2012-05-01 00:30:46 +02:00
my $mesh = $current_object -> mesh -> clone ;
$mesh -> scale ( $ Slic3r:: scaling_factor );
2012-05-04 10:17:36 +02:00
my @new_meshes = $mesh -> split_mesh ;
2012-06-06 19:00:34 +02:00
if ( @new_meshes == 1 ) {
Slic3r::GUI:: warning_catcher ( $self ) -> ( "The selected object couldn't be splitted because it contained already a single part." );
return ;
}
2012-05-04 10:17:36 +02:00
foreach my $mesh ( @new_meshes ) {
2012-05-01 00:30:46 +02:00
my $object = $self -> { print } -> add_object_from_mesh ( $mesh );
$object -> input_file ( $current_object -> input_file );
2012-05-04 11:26:15 +02:00
my $new_obj_idx = $# { $self -> { print } -> objects };
push @ { $self -> { print } -> copies -> [ $new_obj_idx ]}, [ 0 , 0 ] for 2 .. $current_copies_num ;
$self -> object_loaded ( $new_obj_idx , no_arrange => 1 );
2012-05-01 00:30:46 +02:00
}
$self -> { list } -> Select ( $obj_idx , 1 );
$self -> remove ;
$self -> arrange ;
}
2012-04-30 14:56:01 +02:00
sub export_gcode {
my $self = shift ;
2012-05-05 21:08:15 +02:00
if ( $self -> { export_thread }) {
2012-07-01 19:24:06 +02:00
Wx::MessageDialog -> new ( $self , "Another slicing job is currently running." , 'Error' , wxOK | wxICON_ERROR ) -> ShowModal ;
2012-05-05 21:08:15 +02:00
return ;
}
# select output file
$self -> { output_file } = $ main:: opt { output };
{
$self -> { output_file } = $self -> { print } -> expanded_output_filepath ( $self -> { output_file });
my $dlg = Wx::FileDialog -> new ( $self , 'Save G-code file as:' , dirname ( $self -> { output_file }),
basename ( $self -> { output_file }), $ Slic3r::GUI::SkeinPanel:: gcode_wildcard , wxFD_SAVE );
if ( $dlg -> ShowModal != wxID_OK ) {
$dlg -> Destroy ;
return ;
}
$self -> { output_file } = $ Slic3r::GUI::SkeinPanel:: last_output_file = $dlg -> GetPath ;
$dlg -> Destroy ;
}
$self -> statusbar -> StartBusy ;
2012-05-19 21:13:10 +02:00
if ( $ Slic3r:: have_threads ) {
2012-05-05 21:08:15 +02:00
$self -> { export_thread } = threads -> create ( sub {
$self -> export_gcode2 (
$self -> { output_file },
progressbar => sub { Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $PROGRESS_BAR_EVENT , shared_clone ([ @_ ]))) },
message_dialog => sub { Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $MESSAGE_DIALOG_EVENT , shared_clone ([ @_ ]))) },
on_completed => sub { Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $EXPORT_COMPLETED_EVENT , shared_clone ([ @_ ]))) },
catch_error => sub {
2012-05-19 21:13:10 +02:00
Slic3r::GUI:: catch_error ( $self , $_ [ 0 ], sub {
Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $MESSAGE_DIALOG_EVENT , shared_clone ([ @_ ])));
Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $EXPORT_FAILED_EVENT , undef ));
});
2012-05-05 21:08:15 +02:00
},
);
});
$self -> statusbar -> SetCancelCallback ( sub {
$self -> { export_thread } -> kill ( 'KILL' );
$self -> { export_thread } = undef ;
$self -> statusbar -> StopBusy ;
$self -> statusbar -> SetStatusText ( "Export cancelled" );
});
} else {
$self -> export_gcode2 (
$self -> { output_file },
progressbar => sub {
my ( $percent , $message ) = @_ ;
$self -> statusbar -> SetProgress ( $percent );
2012-07-01 23:29:56 +02:00
$self -> statusbar -> SetStatusText ( "$message…" );
2012-05-05 21:08:15 +02:00
},
message_dialog => sub { Wx::MessageDialog -> new ( $self , @_ ) -> ShowModal },
on_completed => sub { $self -> on_export_completed ( @_ ) },
2012-05-23 11:47:52 +02:00
catch_error => sub { Slic3r::GUI:: catch_error ( $self , @_ ) && $self -> on_export_failed },
2012-05-05 21:08:15 +02:00
);
}
}
sub export_gcode2 {
my $self = shift ;
my ( $output_file , %params ) = @_ ;
$ Slic3r::Geometry::Clipper:: clipper = Math::Clipper -> new ;
local $SIG { 'KILL' } = sub {
Slic3r:: debugf "Exporting cancelled; exiting thread...\n" ;
threads -> exit ();
2012-05-19 21:13:10 +02:00
} if $ Slic3r:: have_threads ;
2012-05-05 21:08:15 +02:00
2012-04-30 14:56:01 +02:00
eval {
# validate configuration
Slic3r::Config -> validate ;
my $print = $self -> { print };
2012-05-23 11:47:52 +02:00
$print -> validate ;
2012-04-30 14:56:01 +02:00
{
my @warnings = ();
local $SIG { __WARN__ } = sub { push @warnings , $_ [ 0 ] };
my %params = (
output_file => $output_file ,
2012-05-05 21:08:15 +02:00
status_cb => sub { $params { progressbar } -> ( @_ ) },
2012-04-30 14:56:01 +02:00
keep_meshes => 1 ,
);
if ( $params { export_svg }) {
$print -> export_svg ( %params );
} else {
$print -> export_gcode ( %params );
}
2012-05-29 17:02:47 +02:00
Slic3r::GUI:: warning_catcher ( $self , $ Slic3r:: have_threads ? sub {
2012-05-05 21:08:15 +02:00
Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $MESSAGE_DIALOG_EVENT , shared_clone ([ @_ ])));
2012-05-29 17:02:47 +02:00
} : undef ) -> ( $_ ) for @warnings ;
2012-04-30 14:56:01 +02:00
}
my $message = "Your files were successfully sliced" ;
2012-07-08 22:16:46 +02:00
if ( $print -> processing_time ) {
$message .= ' in' ;
my $minutes = int ( $print -> processing_time / 60 );
$message .= sprintf " %d minutes and" , $minutes if $minutes ;
$message .= sprintf " %.1f seconds" , $print -> processing_time - $minutes * 60 ;
}
2012-04-30 14:56:01 +02:00
$message .= "." ;
2012-05-05 21:08:15 +02:00
$params { on_completed } -> ( $message );
2012-05-04 12:56:15 +02:00
$print -> cleanup ;
2012-04-30 14:56:01 +02:00
};
2012-05-19 21:13:10 +02:00
$params { catch_error } -> ();
2012-04-30 14:56:01 +02:00
}
2012-05-05 21:08:15 +02:00
sub on_export_completed {
my $self = shift ;
my ( $message ) = @_ ;
2012-05-20 17:21:31 +02:00
$self -> { export_thread } -> detach if $self -> { export_thread };
2012-05-05 21:26:19 +02:00
$self -> { export_thread } = undef ;
$self -> statusbar -> SetCancelCallback ( undef );
2012-05-05 21:08:15 +02:00
$self -> statusbar -> StopBusy ;
$self -> statusbar -> SetStatusText ( "G-code file exported to $self->{output_file}" );
2012-07-15 23:57:31 +02:00
& Wx::wxTheApp -> notify ( $message );
2012-05-05 21:08:15 +02:00
}
2012-05-19 21:13:10 +02:00
sub on_export_failed {
my $self = shift ;
2012-05-20 17:21:31 +02:00
$self -> { export_thread } -> detach if $self -> { export_thread };
2012-05-19 21:13:10 +02:00
$self -> { export_thread } = undef ;
$self -> statusbar -> SetCancelCallback ( undef );
$self -> statusbar -> StopBusy ;
$self -> statusbar -> SetStatusText ( "Export failed" );
}
2012-04-30 17:10:54 +02:00
sub export_stl {
my $self = shift ;
my $print = $self -> { print };
# select output file
my $output_file = $ main:: opt { output };
{
$output_file = $print -> expanded_output_filepath ( $output_file );
$output_file =~ s/\.gcode$/.stl/i ;
my $dlg = Wx::FileDialog -> new ( $self , 'Save STL file as:' , dirname ( $output_file ),
2012-07-01 19:24:06 +02:00
basename ( $output_file ), $ Slic3r::GUI::SkeinPanel:: model_wildcard , wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
2012-04-30 17:10:54 +02:00
if ( $dlg -> ShowModal != wxID_OK ) {
$dlg -> Destroy ;
return ;
}
$output_file = $ Slic3r::GUI::SkeinPanel:: last_output_file = $dlg -> GetPath ;
$dlg -> Destroy ;
}
my $mesh = Slic3r::TriangleMesh -> new ( facets => [] , vertices => [] );
for my $obj_idx ( 0 .. $# { $print -> objects }) {
for my $copy ( @ { $print -> copies -> [ $obj_idx ]}) {
my $cloned_mesh = $print -> objects -> [ $obj_idx ] -> mesh -> clone ;
$cloned_mesh -> move ( @$copy );
my $vertices_offset = scalar @ { $mesh -> vertices };
push @ { $mesh -> vertices }, @ { $cloned_mesh -> vertices };
2012-05-29 09:35:57 +02:00
push @ { $mesh -> facets }, map [ $_ -> [ 0 ], map $vertices_offset + $_ , @$_ [ - 3 ..- 1 ] ], @ { $cloned_mesh -> facets };
2012-04-30 17:10:54 +02:00
}
}
$mesh -> scale ( $ Slic3r:: scaling_factor );
$mesh -> align_to_origin ;
Slic3r::Format::STL -> write_file ( $output_file , $mesh , 1 );
2012-05-04 12:56:15 +02:00
$self -> statusbar -> SetStatusText ( "STL file exported to $output_file" );
2012-04-30 17:10:54 +02:00
}
2012-04-30 14:56:01 +02:00
sub make_thumbnail {
my $self = shift ;
my ( $obj_idx ) = @_ ;
2012-04-30 20:59:14 +02:00
my $cb = sub {
my $object = $self -> { print } -> objects -> [ $obj_idx ];
my @points = map [ @$_ [ X , Y ] ], @ { $object -> mesh -> vertices };
my $convex_hull = Slic3r::Polygon -> new ( convex_hull ( \ @points ));
for ( @$convex_hull ) {
@$_ = map $self -> to_pixel ( $_ ), @$_ ;
}
$convex_hull -> simplify ( 0.3 );
$self -> { thumbnails } -> [ $obj_idx ] = $convex_hull ; # ignored in multithread environment
2012-05-19 21:13:10 +02:00
if ( $ Slic3r:: have_threads ) {
2012-04-30 22:34:41 +02:00
Wx:: PostEvent ( $self , Wx::PlThreadEvent -> new ( - 1 , $THUMBNAIL_DONE_EVENT , shared_clone ([ $obj_idx , $convex_hull ])));
threads -> exit ;
} else {
$self -> make_thumbnail2 ;
}
2012-04-30 20:59:14 +02:00
};
2012-05-20 16:29:52 +02:00
$ Slic3r:: have_threads ? threads -> create ( $cb ) -> detach : $cb -> ();
2012-04-30 14:56:01 +02:00
}
2012-04-30 22:34:41 +02:00
sub make_thumbnail2 {
my $self = shift ;
$self -> recenter ;
$self -> { canvas } -> Refresh ;
}
2012-04-30 14:56:01 +02:00
sub recenter {
my $self = shift ;
# calculate displacement needed to center the print
my @print_bb = $self -> { print } -> bounding_box ;
@print_bb = ( 0 , 0 , 0 , 0 ) if ! defined $print_bb [ 0 ];
$self -> { shift } = [
( $self -> { canvas } -> GetSize -> GetWidth - ( $self -> to_pixel ( $print_bb [ X2 ] + $print_bb [ X1 ]))) / 2 ,
( $self -> { canvas } -> GetSize -> GetHeight - ( $self -> to_pixel ( $print_bb [ Y2 ] + $print_bb [ Y1 ]))) / 2 ,
];
}
2012-04-30 22:34:41 +02:00
sub update_bed_size {
my $self = shift ;
# supposing the preview canvas is square, calculate the scaling factor
# to constrain print bed area inside preview
my $canvas_side = $self -> { canvas } -> GetSize -> GetWidth ;
my $bed_largest_side = $ Slic3r:: bed_size -> [ X ] > $ Slic3r:: bed_size -> [ Y ]
2012-06-06 16:18:41 +02:00
? $ Slic3r:: bed_size -> [ X ] : $ Slic3r:: bed_size -> [ Y ];
2012-04-30 22:34:41 +02:00
my $old_scaling_factor = $self -> { scaling_factor };
$self -> { scaling_factor } = $canvas_side / $bed_largest_side ;
if ( defined $old_scaling_factor && $self -> { scaling_factor } != $old_scaling_factor ) {
$self -> make_thumbnail ( $_ ) for 0 .. $# { $self -> { thumbnails }};
}
}
2012-04-30 14:56:01 +02:00
sub repaint {
my ( $self , $event ) = @_ ;
my $parent = $self -> GetParent ;
my $print = $parent -> { print };
my $dc = Wx::PaintDC -> new ( $self );
my $size = $self -> GetSize ;
my @size = ( $size -> GetWidth , $size -> GetHeight );
2012-04-30 22:34:41 +02:00
# calculate scaling factor for preview
$parent -> update_bed_size ;
2012-04-30 14:56:01 +02:00
# draw grid
$dc -> SetPen ( $parent -> { grid_pen });
my $step = 10 * $parent -> { scaling_factor };
for ( my $x = $step ; $x <= $size [ X ]; $x += $step ) {
$dc -> DrawLine ( $x , 0 , $x , $size [ Y ]);
}
for ( my $y = $step ; $y <= $size [ Y ]; $y += $step ) {
$dc -> DrawLine ( 0 , $y , $size [ X ], $y );
}
2012-05-04 11:47:53 +02:00
# draw print center
if ( @ { $print -> objects }) {
$dc -> SetPen ( $parent -> { print_center_pen });
$dc -> DrawLine ( $size [ X ] /2, 0, $size[X]/ 2 , $size [ Y ]);
$dc -> DrawLine ( 0 , $size [ Y ] /2, $size[X], $size[Y]/ 2 );
$dc -> SetTextForeground ( Wx::Colour -> new ( 0 , 0 , 0 ));
$dc -> SetFont ( Wx::Font -> new ( 10 , wxDEFAULT , wxNORMAL , wxNORMAL ));
2012-07-01 19:24:06 +02:00
$dc -> DrawLabel ( "X = " . $ Slic3r:: print_center -> [ X ], Wx::Rect -> new ( 0 , 0 , $self -> GetSize -> GetWidth , $self -> GetSize -> GetHeight ), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM );
2012-05-04 11:47:53 +02:00
$dc -> DrawRotatedText ( "Y = " . $ Slic3r:: print_center -> [ Y ], 0 , $size [ Y ] / 2 + 15 , 90 );
}
2012-04-30 14:56:01 +02:00
# draw frame
2012-07-01 19:24:06 +02:00
$dc -> SetPen ( wxBLACK_PEN );
2012-04-30 14:56:01 +02:00
$dc -> SetBrush ( $parent -> { transparent_brush });
$dc -> DrawRectangle ( 0 , 0 , @size );
# draw text if plate is empty
if ( ! @ { $print -> objects }) {
$dc -> SetTextForeground ( Wx::Colour -> new ( 150 , 50 , 50 ));
2012-05-04 11:47:53 +02:00
$dc -> SetFont ( Wx::Font -> new ( 14 , wxDEFAULT , wxNORMAL , wxNORMAL ));
2012-07-01 19:24:06 +02:00
$dc -> DrawLabel ( "Drag your objects here" , Wx::Rect -> new ( 0 , 0 , $self -> GetSize -> GetWidth , $self -> GetSize -> GetHeight ), wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL );
2012-04-30 14:56:01 +02:00
}
# draw thumbnails
2012-07-01 19:24:06 +02:00
$dc -> SetPen ( wxBLACK_PEN );
2012-04-30 14:56:01 +02:00
@ { $parent -> { object_previews }} = ();
for my $obj_idx ( 0 .. $# { $print -> objects }) {
2012-04-30 17:55:32 +02:00
next unless $parent -> { thumbnails }[ $obj_idx ];
2012-04-30 14:56:01 +02:00
for my $copy_idx ( 0 .. $# { $print -> copies -> [ $obj_idx ]}) {
my $copy = $print -> copies -> [ $obj_idx ][ $copy_idx ];
push @ { $parent -> { object_previews }}, [ $obj_idx , $copy_idx , $parent -> { thumbnails }[ $obj_idx ] -> clone ];
$parent -> { object_previews } -> [ - 1 ][ 2 ] -> translate ( map $parent -> to_pixel ( $copy -> [ $_ ]) + $parent -> { shift }[ $_ ], ( X , Y ));
if ( grep { $_ -> [ 0 ] == $obj_idx } @ { $parent -> { selected_objects }}) {
$dc -> SetBrush ( $parent -> { selected_brush });
} else {
$dc -> SetBrush ( $parent -> { objects_brush });
}
$dc -> DrawPolygon ( $parent -> _y ( $parent -> { object_previews } -> [ - 1 ][ 2 ]), 0 , 0 );
2012-05-23 11:47:52 +02:00
# if sequential printing is enabled and we have more than one object
if ( $ Slic3r:: complete_objects && ( map @$_ , @ { $print -> copies }) > 1 ) {
my $clearance = + ( $parent -> { object_previews } -> [ - 1 ][ 2 ] -> offset ( $ Slic3r:: extruder_clearance_radius / 2 * $parent -> { scaling_factor }, 1 , JT_ROUND ))[ 0 ];
$dc -> SetPen ( $parent -> { clearance_pen });
$dc -> SetBrush ( $parent -> { transparent_brush });
$dc -> DrawPolygon ( $parent -> _y ( $clearance ), 0 , 0 );
}
2012-04-30 14:56:01 +02:00
}
}
# draw skirt
if ( @ { $parent -> { object_previews }} && $ Slic3r:: skirts ) {
my $convex_hull = Slic3r::Polygon -> new ( convex_hull ([ map @ { $_ -> [ 2 ]}, @ { $parent -> { object_previews }} ]));
2012-04-30 18:54:36 +02:00
$convex_hull = + ( $convex_hull -> offset ( $ Slic3r:: skirt_distance * $parent -> { scaling_factor }, 1 , JT_ROUND ))[ 0 ];
2012-04-30 14:56:01 +02:00
$dc -> SetPen ( $parent -> { skirt_pen });
$dc -> SetBrush ( $parent -> { transparent_brush });
$dc -> DrawPolygon ( $parent -> _y ( $convex_hull ), 0 , 0 ) if $convex_hull ;
}
$event -> Skip ;
}
sub mouse_event {
my ( $self , $event ) = @_ ;
my $parent = $self -> GetParent ;
my $print = $parent -> { print };
my $point = $event -> GetPosition ;
my $pos = $parent -> _y ([[ $point -> x , $point -> y ]]) -> [ 0 ]; #]]
if ( $event -> ButtonDown ( & Wx:: wxMOUSE_BTN_LEFT )) {
$parent -> { selected_objects } = [] ;
$parent -> { list } -> Select ( $parent -> { list } -> GetFirstSelected , 0 );
$parent -> selection_changed ( 0 );
for my $preview ( @ { $parent -> { object_previews }}) {
if ( $preview -> [ 2 ] -> encloses_point ( $pos )) {
$parent -> { selected_objects } = [ $preview ];
$parent -> { list } -> Select ( $preview -> [ 0 ], 1 );
$parent -> selection_changed ( 1 );
my $copy = $print -> copies -> [ $preview -> [ 0 ] ] -> [ $preview -> [ 1 ] ];
$self -> { drag_start_pos } = [ map $pos -> [ $_ ] - $parent -> { shift }[ $_ ] - $parent -> to_pixel ( $copy -> [ $_ ]), X , Y ]; # displacement between the click and the copy's origin
$self -> { drag_object } = $preview ;
}
}
$parent -> Refresh ;
} elsif ( $event -> ButtonUp ( & Wx:: wxMOUSE_BTN_LEFT )) {
$parent -> recenter ;
$parent -> Refresh ;
$self -> { drag_start_pos } = undef ;
$self -> { drag_object } = undef ;
} elsif ( $event -> Dragging ) {
return if ! $self -> { drag_start_pos }; # concurrency problems
for my $obj ( $self -> { drag_object }) {
my $copy = $print -> copies -> [ $obj -> [ 0 ] ] -> [ $obj -> [ 1 ] ];
$copy -> [ $_ ] = $parent -> to_scaled ( $pos -> [ $_ ] - $self -> { drag_start_pos }[ $_ ] - $parent -> { shift }[ $_ ]) for X , Y ;
$parent -> Refresh ;
}
}
}
sub list_item_deselected {
my ( $self , $event ) = @_ ;
if ( $self -> { list } -> GetFirstSelected == - 1 ) {
$self -> { selected_objects } = [] ;
$self -> { canvas } -> Refresh ;
$self -> selection_changed ( 0 );
}
}
sub list_item_selected {
my ( $self , $event ) = @_ ;
my $obj_idx = $event -> GetIndex ;
$self -> { selected_objects } = [ grep $_ -> [ 0 ] == $obj_idx , @ { $self -> { object_previews }} ];
$self -> { canvas } -> Refresh ;
$self -> selection_changed ( 1 );
}
sub object_list_changed {
my $self = shift ;
my $method = $self -> { print } && @ { $self -> { print } -> objects } ? 'Enable' : 'Disable' ;
2012-05-01 00:30:46 +02:00
$self -> { "btn_$_" } -> $method
2012-05-04 11:22:56 +02:00
for grep $self -> { "btn_$_" }, qw(reset arrange export_gcode export_stl) ;
2012-04-30 14:56:01 +02:00
}
sub selection_changed {
my $self = shift ;
my ( $have_sel ) = @_ ;
my $method = $have_sel ? 'Enable' : 'Disable' ;
2012-05-01 00:30:46 +02:00
$self -> { "btn_$_" } -> $method
2012-05-04 11:22:56 +02:00
for grep $self -> { "btn_$_" }, qw(remove increase decrease rotate45cw rotate45ccw rotate changescale split) ;
if ( $self -> { htoolbar }) {
$self -> { htoolbar } -> EnableTool ( $_ , $have_sel ) for 1 .. $self -> { htoolbar } -> GetToolsCount ;
}
2012-04-30 14:56:01 +02:00
}
sub selected_object_idx {
my $self = shift ;
2012-04-30 23:24:01 +02:00
return $self -> { selected_objects }[ 0 ] ? $self -> { selected_objects }[ 0 ][ 0 ] : $self -> { list } -> GetFirstSelected ;
2012-04-30 14:56:01 +02:00
}
2012-05-04 12:56:15 +02:00
sub statusbar {
my $self = shift ;
return $self -> GetParent -> GetParent -> GetParent -> { statusbar };
}
2012-04-30 14:56:01 +02:00
sub to_pixel {
my $self = shift ;
return unscale $_ [ 0 ] * $self -> { scaling_factor };
}
sub to_scaled {
my $self = shift ;
return scale $_ [ 0 ] / $self -> { scaling_factor };
}
sub _y {
my $self = shift ;
my ( $points ) = @_ ;
my $height = $self -> { canvas } -> GetSize -> GetHeight ;
return [ map [ $_ -> [ X ], $height - $_ -> [ Y ] ], @$points ];
}
2012-05-04 10:15:33 +02:00
package Slic3r::GUI::Plater::DropTarget ;
2012-04-30 14:56:01 +02:00
use Wx::DND ;
use base 'Wx::FileDropTarget' ;
sub new {
my $class = shift ;
my ( $window ) = @_ ;
my $self = $class -> SUPER:: new ;
$self -> { window } = $window ;
return $self ;
}
sub OnDropFiles {
my $self = shift ;
my ( $x , $y , $filenames ) = @_ ;
2012-07-21 14:45:45 +02:00
# stop scalars leaking on older perl
# https://rt.perl.org/rt3/Public/Bug/Display.html?id=70602
@_ = ();
2012-04-30 14:56:01 +02:00
# only accept STL and AMF files
return 0 if grep ! /\.(?:stl|amf(?:\.xml)?)$/i , @$filenames ;
$self -> { window } -> load_file ( $_ ) for @$filenames ;
}
1 ;