2016-09-14 09:22:41 +00:00
# The "Plater" tab. It contains the "3D", "2D", "Preview" and "Layers" subtabs.
2012-05-04 08:15:33 +00:00
package Slic3r::GUI::Plater ;
2012-04-30 12:56:01 +00:00
use strict ;
use warnings ;
use utf8 ;
use File::Basename qw( basename dirname ) ;
2015-05-25 17:51:47 +00:00
use List::Util qw( sum first max ) ;
2017-07-21 14:29:40 +00:00
use Slic3r::Geometry qw( X Y Z scale unscale deg2rad rad2deg ) ;
2017-05-24 13:20:20 +00:00
use Wx qw( :button :colour :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc
2016-12-14 14:36:18 +00:00
: panel : sizer : toolbar : window wxTheApp : notebook : combobox wxNullBitmap ) ;
2016-12-12 17:02:24 +00:00
use Wx::Event qw( EVT_BUTTON EVT_TOGGLEBUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED
2017-05-24 13:20:20 +00:00
EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_LEFT_DOWN EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL
2015-05-26 00:01:43 +00:00
EVT_CHOICE EVT_COMBOBOX EVT_TIMER EVT_NOTEBOOK_PAGE_CHANGED ) ;
2018-06-19 07:46:26 +00:00
use Slic3r::Geometry qw( PI ) ;
2012-04-30 12:56:01 +00:00
use base 'Wx::Panel' ;
2013-12-12 19:19:33 +00:00
use constant TB_ADD = > & Wx:: NewId ;
2013-08-25 10:22:05 +00:00
use constant TB_REMOVE = > & Wx:: NewId ;
use constant TB_RESET = > & Wx:: NewId ;
use constant TB_ARRANGE = > & Wx:: NewId ;
use constant TB_EXPORT_GCODE = > & Wx:: NewId ;
use constant TB_EXPORT_STL = > & Wx:: NewId ;
2012-08-02 19:11:36 +00:00
use constant TB_MORE = > & Wx:: NewId ;
2013-08-25 13:45:22 +00:00
use constant TB_FEWER = > & Wx:: NewId ;
2012-08-02 19:11:36 +00:00
use constant TB_45CW = > & Wx:: NewId ;
use constant TB_45CCW = > & Wx:: NewId ;
use constant TB_SCALE = > & Wx:: NewId ;
use constant TB_SPLIT = > & Wx:: NewId ;
2014-12-10 16:34:59 +00:00
use constant TB_CUT = > & Wx:: NewId ;
2013-08-25 16:01:59 +00:00
use constant TB_SETTINGS = > & Wx:: NewId ;
2016-12-12 17:02:24 +00:00
use constant TB_LAYER_EDITING = > & Wx:: NewId ;
2012-05-04 09:22:56 +00:00
2018-02-22 14:13:07 +00:00
use Wx::Locale gettext = > 'L' ;
2016-10-25 11:24:42 +00:00
# Emitted from the worker thread when the G-code export is finished.
2018-03-23 10:41:20 +00:00
our $ SLICING_COMPLETED_EVENT = Wx:: NewEventType ;
our $ PROCESS_COMPLETED_EVENT = Wx:: NewEventType ;
2012-07-27 19:13:03 +00:00
2014-03-25 14:30:56 +00:00
my $ PreventListEvents = 0 ;
2018-06-28 17:16:36 +00:00
our $ appController ;
2014-03-25 14:30:56 +00:00
2018-10-08 17:14:55 +00:00
# XXX: VK: done, except callback handling and timer
2012-04-30 12:56:01 +00:00
sub new {
2018-06-06 22:55:09 +00:00
my ( $ class , $ parent , % params ) = @ _ ;
2012-07-24 12:28:21 +00:00
my $ self = $ class - > SUPER:: new ( $ parent , - 1 , wxDefaultPosition , wxDefaultSize , wxTAB_TRAVERSAL ) ;
2018-03-23 10:41:20 +00:00
Slic3r::GUI:: set_plater ( $ self ) ;
2017-10-27 20:49:59 +00:00
$ self - > { config } = Slic3r::Config:: new_from_defaults_keys ( [ qw(
2017-02-10 09:21:50 +00:00
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
2018-07-08 12:32:48 +00:00
serial_port serial_speed host_type print_host printhost_apikey printhost_cafile
2018-03-16 13:06:23 +00:00
nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
2018-06-21 08:43:01 +00:00
wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model
2017-10-27 20:49:59 +00:00
) ] ) ;
2018-06-06 22:55:09 +00:00
# store input params
$ self - > { event_object_selection_changed } = $ params { event_object_selection_changed } ;
2018-06-12 17:15:03 +00:00
$ self - > { event_object_settings_changed } = $ params { event_object_settings_changed } ;
2018-07-04 06:54:30 +00:00
$ self - > { event_remove_object } = $ params { event_remove_object } ;
2018-07-26 08:59:03 +00:00
$ self - > { event_update_scene } = $ params { event_update_scene } ;
2018-06-06 22:55:09 +00:00
2017-02-07 17:28:53 +00:00
# C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm
2013-12-12 19:19:33 +00:00
$ self - > { model } = Slic3r::Model - > new ;
2017-02-07 17:28:53 +00:00
# C++ Slic3r::Print with Perl extensions in Slic3r/Print.pm
2013-12-13 13:02:01 +00:00
$ self - > { print } = Slic3r::Print - > new ;
2016-09-13 09:24:55 +00:00
# List of Perl objects Slic3r::GUI::Plater::Object, representing a 2D preview of the platter.
2012-09-12 14:30:44 +00:00
$ self - > { objects } = [] ;
2018-02-14 19:35:59 +00:00
$ self - > { gcode_preview_data } = Slic3r::GCode::PreviewData - > new ;
2018-03-23 10:41:20 +00:00
$ self - > { background_slicing_process } = Slic3r::GUI::BackgroundSlicingProcess - > new ;
$ self - > { background_slicing_process } - > set_print ( $ self - > { print } ) ;
$ self - > { background_slicing_process } - > set_gcode_preview_data ( $ self - > { gcode_preview_data } ) ;
$ self - > { background_slicing_process } - > set_sliced_event ( $ SLICING_COMPLETED_EVENT ) ;
$ self - > { background_slicing_process } - > set_finished_event ( $ PROCESS_COMPLETED_EVENT ) ;
# The C++ slicing core will post a wxCommand message to the main window.
Slic3r::GUI:: set_print_callback_event ( $ self - > { print } , $ Slic3r:: GUI:: MainFrame:: PROGRESS_BAR_EVENT ) ;
2014-06-13 12:27:55 +00:00
2014-07-13 10:10:34 +00:00
# Initialize preview notebook
2018-05-04 16:32:20 +00:00
$ self - > { preview_notebook } = Wx::Notebook - > new ( $ self , - 1 , wxDefaultPosition , [ - 1 , 335 ] , wxNB_BOTTOM ) ;
2014-07-13 10:10:34 +00:00
2014-12-13 19:41:03 +00:00
# Initialize handlers for canvases
my $ on_select_object = sub {
2018-09-06 14:10:31 +00:00
my ( $ obj_idx , $ vol_idx ) = @ _ ;
if ( ( $ obj_idx != - 1 ) && ( $ vol_idx == - 1 ) ) {
# Ignore the special objects (the wipe tower proxy and such).
$ self - > select_object ( ( defined ( $ obj_idx ) && $ obj_idx >= 0 && $ obj_idx < 1000 ) ? $ obj_idx : undef ) ;
$ self - > item_changed_selection ( $ obj_idx ) if ( defined ( $ obj_idx ) ) ;
}
2014-12-13 19:41:03 +00:00
} ;
my $ on_right_click = sub {
2018-05-31 11:51:50 +00:00
my ( $ canvas , $ click_pos_x , $ click_pos_y ) = @ _ ;
2014-06-14 19:36:28 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
return if ! defined $ obj_idx ;
my $ menu = $ self - > object_menu ;
2018-05-31 11:51:50 +00:00
$ canvas - > PopupMenu ( $ menu , $ click_pos_x , $ click_pos_y ) ;
2014-06-14 19:36:28 +00:00
$ menu - > Destroy ;
2014-12-13 19:41:03 +00:00
} ;
2015-01-13 17:41:23 +00:00
my $ on_instances_moved = sub {
2014-05-28 10:29:43 +00:00
$ self - > update ;
2014-12-13 19:41:03 +00:00
} ;
2018-03-21 14:21:03 +00:00
# callback to enable/disable action buttons
my $ enable_action_buttons = sub {
my ( $ enable ) = @ _ ;
2018-09-17 13:12:13 +00:00
Slic3r::GUI:: enable_action_buttons ( $ enable ) ;
# $self->{btn_export_gcode}->Enable($enable);
# $self->{btn_reslice}->Enable($enable);
# $self->{btn_print}->Enable($enable);
# $self->{btn_send_gcode}->Enable($enable);
2018-03-21 14:21:03 +00:00
} ;
2018-06-18 13:07:17 +00:00
# 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 ] ;
2018-06-21 06:37:04 +00:00
$ self - > stop_background_process ;
2018-06-18 13:07:17 +00:00
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 } ;
2018-07-23 06:57:00 +00:00
2018-07-26 10:10:45 +00:00
# Set object scale on c++ side
2018-08-29 11:11:30 +00:00
# Slic3r::GUI::set_object_scale($obj_idx, $model_object->instances->[0]->scaling_factor * 100);
2018-07-26 10:10:45 +00:00
2018-07-25 07:42:03 +00:00
# $object->transform_thumbnail($self->{model}, $obj_idx);
2018-06-18 13:07:17 +00:00
#update print and start background processing
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
$ self - > selection_changed ( 1 ) ; # refresh info (size, volume etc.)
$ self - > update ;
$ self - > schedule_background_process ;
} ;
2018-03-21 14:21:03 +00:00
2018-09-24 13:54:09 +00:00
# callback to react to gizmo scale
my $ on_gizmo_scale_3D = sub {
my ( $ scale_x , $ scale_y , $ scale_z ) = @ _ ;
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 ] ;
$ self - > stop_background_process ;
#FIXME Scale the layer height profile?
# my $variation = $scale / $model_instance->scaling_factor;
# foreach my $range (@{ $model_object->layer_height_ranges }) {
# $range->[0] *= $variation;
# $range->[1] *= $variation;
# }
my $ scale = Slic3r::Pointf3 - > new ( $ scale_x , $ scale_y , $ scale_z ) ;
foreach my $ inst ( @ { $ model_object - > instances } ) {
$ inst - > set_scaling_factors ( $ scale ) ;
}
Slic3r::GUI::_3DScene:: update_gizmos_data ( $ self - > { canvas3D } ) if ( $ self - > { canvas3D } ) ;
#update print and start background processing
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
$ self - > selection_changed ( 1 ) ; # refresh info (size, volume etc.)
$ self - > update ;
$ self - > schedule_background_process ;
} ;
2018-06-19 07:46:26 +00:00
# callback to react to gizmo rotate
my $ on_gizmo_rotate = sub {
2018-09-10 12:10:08 +00:00
my ( $ angle ) = @ _ ;
$ self - > rotate ( rad2deg ( $ angle ) , Z , 'absolute' ) ;
} ;
2018-09-20 13:00:40 +00:00
# callback to react to gizmo rotate
my $ on_gizmo_rotate_3D = sub {
my ( $ angle_x , $ angle_y , $ angle_z ) = @ _ ;
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 ] ;
$ self - > stop_background_process ;
my $ rotation = Slic3r::Pointf3 - > new ( $ angle_x , $ angle_y , $ angle_z ) ;
foreach my $ inst ( @ { $ model_object - > instances } ) {
$ inst - > set_rotations ( $ rotation ) ;
}
Slic3r::GUI::_3DScene:: update_gizmos_data ( $ self - > { canvas3D } ) if ( $ self - > { canvas3D } ) ;
# update print and start background processing
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
$ self - > selection_changed ; # refresh info (size etc.)
$ self - > update ;
$ self - > schedule_background_process ;
} ;
2018-09-10 12:10:08 +00:00
# callback to react to gizmo flatten
my $ on_gizmo_flatten = sub {
2018-08-21 13:40:11 +00:00
my ( $ angle , $ axis_x , $ axis_y , $ axis_z ) = @ _ ;
2018-09-10 12:10:08 +00:00
$ self - > rotate ( rad2deg ( $ angle ) , undef , 'absolute' , $ axis_x , $ axis_y , $ axis_z ) if $ angle != 0 ;
2018-06-19 07:46:26 +00:00
} ;
2018-08-01 13:34:33 +00:00
2018-09-20 13:00:40 +00:00
# callback to react to gizmo flatten
my $ on_gizmo_flatten_3D = sub {
my ( $ angle_x , $ angle_y , $ angle_z ) = @ _ ;
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 ] ;
$ self - > stop_background_process ;
my $ rotation = Slic3r::Pointf3 - > new ( $ angle_x , $ angle_y , $ angle_z ) ;
foreach my $ inst ( @ { $ model_object - > instances } ) {
$ inst - > set_rotations ( $ rotation ) ;
}
Slic3r::GUI::_3DScene:: update_gizmos_data ( $ self - > { canvas3D } ) if ( $ self - > { canvas3D } ) ;
# update print and start background processing
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
$ self - > selection_changed ; # refresh info (size etc.)
$ self - > update ;
$ self - > schedule_background_process ;
} ;
2018-06-22 09:19:38 +00:00
# callback to update object's geometry info while using gizmos
my $ on_update_geometry_info = sub {
my ( $ size_x , $ size_y , $ size_z , $ scale_factor ) = @ _ ;
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
if ( ( defined $ obj_idx ) && ( $ self - > { object_info_size } ) ) { # have we already loaded the info pane?
$ self - > { object_info_size } - > SetLabel ( sprintf ( "%.2f x %.2f x %.2f" , $ size_x , $ size_y , $ size_z ) ) ;
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
if ( my $ stats = $ model_object - > mesh_stats ) {
$ self - > { object_info_volume } - > SetLabel ( sprintf ( '%.2f' , $ stats - > { volume } * $ scale_factor ** 3 ) ) ;
}
}
} ;
2018-07-27 10:08:33 +00:00
2018-09-24 13:54:09 +00:00
# callback to update object's geometry info while using gizmos
my $ on_update_geometry_3D_info = sub {
my ( $ size_x , $ size_y , $ size_z , $ scale_x , $ scale_y , $ scale_z ) = @ _ ;
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
if ( ( defined $ obj_idx ) && ( $ self - > { object_info_size } ) ) { # have we already loaded the info pane?
$ self - > { object_info_size } - > SetLabel ( sprintf ( "%.2f x %.2f x %.2f" , $ size_x , $ size_y , $ size_z ) ) ;
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
if ( my $ stats = $ model_object - > mesh_stats ) {
$ self - > { object_info_volume } - > SetLabel ( sprintf ( '%.2f' , $ stats - > { volume } * $ scale_x * $ scale_y * $ scale_z ) ) ;
}
}
} ;
2018-07-27 10:08:33 +00:00
# callbacks for toolbar
my $ on_action_add = sub {
$ self - > add ;
} ;
my $ on_action_delete = sub {
$ self - > remove ( ) ;
} ;
my $ on_action_deleteall = sub {
$ self - > reset ;
} ;
my $ on_action_arrange = sub {
$ self - > arrange ;
} ;
my $ on_action_more = sub {
$ self - > increase ;
} ;
my $ on_action_fewer = sub {
$ self - > decrease ;
} ;
my $ on_action_split = sub {
$ self - > split_object ;
} ;
2018-06-22 09:19:38 +00:00
2018-07-27 10:08:33 +00:00
my $ on_action_cut = sub {
$ self - > object_cut_dialog ;
} ;
my $ on_action_settings = sub {
$ self - > object_settings_dialog ;
} ;
my $ on_action_layersediting = sub {
my $ state = Slic3r::GUI::_3DScene:: is_toolbar_item_pressed ( $ self - > { canvas3D } , "layersediting" ) ;
$ self - > on_layer_editing_toggled ( $ state ) ;
} ;
2018-09-06 14:10:31 +00:00
my $ on_action_selectbyparts = sub {
my $ curr = Slic3r::GUI::_3DScene:: get_select_by ( $ self - > { canvas3D } ) ;
if ( $ curr eq 'volume' ) {
Slic3r::GUI::_3DScene:: set_select_by ( $ self - > { canvas3D } , 'object' ) ;
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 1 ) ;
}
elsif ( $ curr eq 'object' ) {
Slic3r::GUI::_3DScene:: set_select_by ( $ self - > { canvas3D } , 'volume' ) ;
my $ selections = [] ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: deselect_volumes ( $ self - > { canvas3D } ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 1 ) ;
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
if ( defined $ obj_idx ) {
my $ vol_idx = Slic3r::GUI::_3DScene:: get_first_volume_id ( $ self - > { canvas3D } , $ obj_idx ) ;
2018-09-17 13:12:13 +00:00
#Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx) if ($vol_idx != -1);
my $ inst_cnt = $ self - > { model } - > objects - > [ $ obj_idx ] - > instances_count ;
for ( 0 .. $ inst_cnt - 1 ) {
Slic3r::GUI::_3DScene:: select_volume ( $ self - > { canvas3D } , $ _ + $ vol_idx ) if ( $ vol_idx != - 1 ) ;
}
my $ volume_idx = Slic3r::GUI::_3DScene:: get_in_object_volume_id ( $ self - > { canvas3D } , $ vol_idx ) ;
Slic3r::GUI:: select_current_volume ( $ obj_idx , $ volume_idx ) if ( $ volume_idx != - 1 ) ;
2018-09-06 14:10:31 +00:00
}
}
} ;
2018-07-27 10:08:33 +00:00
2015-01-18 18:36:47 +00:00
# Initialize 3D plater
2015-01-17 09:53:01 +00:00
if ( $ Slic3r:: GUI:: have_OpenGL ) {
2016-12-12 17:02:24 +00:00
$ self - > { canvas3D } = Slic3r::GUI::Plater:: 3 D - > new ( $ self - > { preview_notebook } , $ self - > { objects } , $ self - > { model } , $ self - > { print } , $ self - > { config } ) ;
2018-02-22 14:13:07 +00:00
$ self - > { preview_notebook } - > AddPage ( $ self - > { canvas3D } , L ( '3D' ) ) ;
2018-06-08 09:37:07 +00:00
Slic3r::GUI::_3DScene:: register_on_select_object_callback ( $ self - > { canvas3D } , $ on_select_object ) ;
2018-09-14 09:16:54 +00:00
# Slic3r::GUI::_3DScene::register_on_double_click_callback($self->{canvas3D}, $on_double_click);
2018-05-31 11:51:50 +00:00
Slic3r::GUI::_3DScene:: register_on_right_click_callback ( $ self - > { canvas3D } , sub { $ on_right_click - > ( $ self - > { canvas3D } , @ _ ) ; } ) ;
2018-06-07 07:22:19 +00:00
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 ( ) } ) ;
2018-06-07 09:18:28 +00:00
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 ) ;
2018-06-08 07:40:00 +00:00
Slic3r::GUI::_3DScene:: register_on_enable_action_buttons_callback ( $ self - > { canvas3D } , $ enable_action_buttons ) ;
2018-06-18 13:07:17 +00:00
Slic3r::GUI::_3DScene:: register_on_gizmo_scale_uniformly_callback ( $ self - > { canvas3D } , $ on_gizmo_scale_uniformly ) ;
2018-09-24 13:54:09 +00:00
Slic3r::GUI::_3DScene:: register_on_gizmo_scale_3D_callback ( $ self - > { canvas3D } , $ on_gizmo_scale_3D ) ;
2018-06-19 07:46:26 +00:00
Slic3r::GUI::_3DScene:: register_on_gizmo_rotate_callback ( $ self - > { canvas3D } , $ on_gizmo_rotate ) ;
2018-09-20 13:00:40 +00:00
Slic3r::GUI::_3DScene:: register_on_gizmo_rotate_3D_callback ( $ self - > { canvas3D } , $ on_gizmo_rotate_3D ) ;
2018-09-10 12:10:08 +00:00
Slic3r::GUI::_3DScene:: register_on_gizmo_flatten_callback ( $ self - > { canvas3D } , $ on_gizmo_flatten ) ;
2018-09-20 13:00:40 +00:00
Slic3r::GUI::_3DScene:: register_on_gizmo_flatten_3D_callback ( $ self - > { canvas3D } , $ on_gizmo_flatten_3D ) ;
2018-06-22 09:19:38 +00:00
Slic3r::GUI::_3DScene:: register_on_update_geometry_info_callback ( $ self - > { canvas3D } , $ on_update_geometry_info ) ;
2018-09-24 13:54:09 +00:00
Slic3r::GUI::_3DScene:: register_on_update_geometry_3D_info_callback ( $ self - > { canvas3D } , $ on_update_geometry_3D_info ) ;
2018-07-27 10:08:33 +00:00
Slic3r::GUI::_3DScene:: register_action_add_callback ( $ self - > { canvas3D } , $ on_action_add ) ;
Slic3r::GUI::_3DScene:: register_action_delete_callback ( $ self - > { canvas3D } , $ on_action_delete ) ;
Slic3r::GUI::_3DScene:: register_action_deleteall_callback ( $ self - > { canvas3D } , $ on_action_deleteall ) ;
Slic3r::GUI::_3DScene:: register_action_arrange_callback ( $ self - > { canvas3D } , $ on_action_arrange ) ;
Slic3r::GUI::_3DScene:: register_action_more_callback ( $ self - > { canvas3D } , $ on_action_more ) ;
Slic3r::GUI::_3DScene:: register_action_fewer_callback ( $ self - > { canvas3D } , $ on_action_fewer ) ;
Slic3r::GUI::_3DScene:: register_action_split_callback ( $ self - > { canvas3D } , $ on_action_split ) ;
Slic3r::GUI::_3DScene:: register_action_cut_callback ( $ self - > { canvas3D } , $ on_action_cut ) ;
Slic3r::GUI::_3DScene:: register_action_settings_callback ( $ self - > { canvas3D } , $ on_action_settings ) ;
Slic3r::GUI::_3DScene:: register_action_layersediting_callback ( $ self - > { canvas3D } , $ on_action_layersediting ) ;
2018-09-06 14:10:31 +00:00
Slic3r::GUI::_3DScene:: register_action_selectbyparts_callback ( $ self - > { canvas3D } , $ on_action_selectbyparts ) ;
2018-06-13 07:12:16 +00:00
Slic3r::GUI::_3DScene:: enable_gizmos ( $ self - > { canvas3D } , 1 ) ;
2018-07-23 11:49:48 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar ( $ self - > { canvas3D } , 1 ) ;
2018-05-23 07:57:44 +00:00
Slic3r::GUI::_3DScene:: enable_shader ( $ self - > { canvas3D } , 1 ) ;
2018-06-05 08:56:55 +00:00
Slic3r::GUI::_3DScene:: enable_force_zoom_to_bed ( $ self - > { canvas3D } , 1 ) ;
2018-06-08 07:40:00 +00:00
2018-06-07 09:18:28 +00:00
Slic3r::GUI::_3DScene:: register_on_wipe_tower_moved_callback ( $ self - > { canvas3D } , sub {
my ( $ x , $ y ) = @ _ ;
2017-05-19 19:48:32 +00:00
my $ cfg = Slic3r::Config - > new ;
2018-06-07 09:18:28 +00:00
$ cfg - > set ( 'wipe_tower_x' , $ x ) ;
$ cfg - > set ( 'wipe_tower_y' , $ y ) ;
2017-05-19 19:48:32 +00:00
$ self - > GetFrame - > { options_tabs } { print } - > load_config ( $ cfg ) ;
} ) ;
2018-06-07 09:18:28 +00:00
2018-05-31 14:04:59 +00:00
Slic3r::GUI::_3DScene:: register_on_model_update_callback ( $ self - > { canvas3D } , sub {
2017-11-02 15:21:34 +00:00
if ( wxTheApp - > { app_config } - > get ( "background_processing" ) ) {
2017-06-09 11:27:35 +00:00
$ self - > schedule_background_process ;
2017-02-15 15:02:54 +00:00
} else {
# Hide the print info box, it is no more valid.
2018-07-18 12:52:19 +00:00
$ self - > print_info_box_show ( 0 ) ;
2017-02-09 13:56:13 +00:00
}
} ) ;
2018-06-04 13:42:34 +00:00
2018-09-18 11:35:05 +00:00
Slic3r::GUI::_3DScene:: register_on_viewport_changed_callback ( $ self - > { canvas3D } ,
sub {
$ self - > { preview_iface } - > 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}); });
2015-01-17 09:53:01 +00:00
}
2018-08-01 13:34:33 +00:00
2018-08-05 21:36:25 +00:00
Slic3r::GUI:: register_on_request_update_callback ( sub { $ self - > schedule_background_process ; } ) ;
2015-01-17 09:53:01 +00:00
2015-01-18 19:55:44 +00:00
# Initialize 3D toolpaths preview
2014-07-13 10:10:34 +00:00
if ( $ Slic3r:: GUI:: have_OpenGL ) {
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } = Slic3r::GUI:: create_preview_iface ( $ self - > { preview_notebook } , $ self - > { config } , $ self - > { print } , $ self - > { gcode_preview_data } ) ;
$ self - > { preview_page_idx } = $ self - > { preview_notebook } - > GetPageCount - 1 ;
$ self - > { preview_iface } - > register_on_viewport_changed_callback ( sub { $ self - > { preview_iface } - > set_viewport_into_scene ( $ self - > { canvas3D } ) ; } ) ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config});
# Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1);
# Slic3r::GUI::_3DScene::enable_dynamic_background($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'));
2015-01-18 19:55:44 +00:00
$ self - > { preview3D_page_idx } = $ self - > { preview_notebook } - > GetPageCount - 1 ;
2014-07-13 10:10:34 +00:00
}
2015-01-18 18:36:47 +00:00
EVT_NOTEBOOK_PAGE_CHANGED ( $ self , $ self - > { preview_notebook } , sub {
2017-06-01 14:31:29 +00:00
my $ preview = $ self - > { preview_notebook } - > GetCurrentPage ;
2018-09-18 13:50:52 +00:00
my $ page_id = $ self - > { preview_notebook } - > GetSelection ;
2018-09-18 14:13:18 +00:00
if ( ( $ preview != $ self - > { canvas3D } ) && ( $ page_id != $ self - > { preview_page_idx } ) ) {
2018-09-18 11:35:05 +00:00
# if (($preview != $self->{preview3D}) && ($preview != $self->{canvas3D})) {
2018-06-25 13:17:13 +00:00
$ preview - > OnActivate if $ preview - > can ( 'OnActivate' ) ;
2018-09-18 13:50:52 +00:00
} elsif ( $ page_id == $ self - > { preview_page_idx } ) {
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > reload_print ;
# sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
$ self - > { preview_iface } - > set_canvas_as_dirty ;
2018-09-18 14:13:18 +00:00
# } elsif ($preview == $self->{preview3D}) {
# $self->{preview3D}->reload_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);
2018-06-25 13:17:13 +00:00
} elsif ( $ preview == $ self - > { canvas3D } ) {
2018-06-08 07:40:00 +00:00
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 ) ;
}
2018-06-22 14:06:37 +00:00
# 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 } ) ;
2018-01-16 13:59:06 +00:00
}
2015-01-18 18:36:47 +00:00
} ) ;
2018-08-15 11:19:58 +00:00
# # toolbar for object manipulation
# if (!&Wx::wxMSW) {
# Wx::ToolTip::Enable(1);
# $self->{htoolbar} = Wx::ToolBar->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxTB_TEXT | wxBORDER_SIMPLE | wxTAB_TRAVERSAL);
# $self->{htoolbar}->AddTool(TB_ADD, L("Add…"), Wx::Bitmap->new(Slic3r::var("brick_add.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_REMOVE, L("Delete"), Wx::Bitmap->new(Slic3r::var("brick_delete.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_RESET, L("Delete All"), Wx::Bitmap->new(Slic3r::var("cross.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_ARRANGE, L("Arrange"), Wx::Bitmap->new(Slic3r::var("bricks.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddSeparator;
# $self->{htoolbar}->AddTool(TB_MORE, L("More"), Wx::Bitmap->new(Slic3r::var("add.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_FEWER, L("Fewer"), Wx::Bitmap->new(Slic3r::var("delete.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddSeparator;
# $self->{htoolbar}->AddTool(TB_45CCW, L("45° ccw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_anticlockwise.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_45CW, L("45° cw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_clockwise.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_SCALE, L("Scale…"), Wx::Bitmap->new(Slic3r::var("arrow_out.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_SPLIT, L("Split"), Wx::Bitmap->new(Slic3r::var("shape_ungroup.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_CUT, L("Cut…"), Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddSeparator;
# $self->{htoolbar}->AddTool(TB_SETTINGS, L("Settings…"), Wx::Bitmap->new(Slic3r::var("cog.png"), wxBITMAP_TYPE_PNG), '');
# $self->{htoolbar}->AddTool(TB_LAYER_EDITING, L('Layer Editing'), Wx::Bitmap->new(Slic3r::var("variable_layer_height.png"), wxBITMAP_TYPE_PNG), wxNullBitmap, 1, 0, 'Layer Editing');
# } else {
# my %tbar_buttons = (
# add => L("Add…"),
# remove => L("Delete"),
# reset => L("Delete All"),
# arrange => L("Arrange"),
# increase => "",
# decrease => "",
# rotate45ccw => "",
# rotate45cw => "",
# changescale => L("Scale…"),
# split => L("Split"),
# cut => L("Cut…"),
# settings => L("Settings…"),
# layer_editing => L("Layer editing"),
# );
# $self->{btoolbar} = Wx::BoxSizer->new(wxHORIZONTAL);
# for (qw(add remove reset arrange increase decrease rotate45ccw rotate45cw changescale split cut settings)) {
# $self->{"btn_$_"} = Wx::Button->new($self, -1, $tbar_buttons{$_}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
# $self->{btoolbar}->Add($self->{"btn_$_"});
# }
# $self->{"btn_layer_editing"} = Wx::ToggleButton->new($self, -1, $tbar_buttons{'layer_editing'}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
# $self->{btoolbar}->Add($self->{"btn_layer_editing"});
# }
2012-07-24 12:42:38 +00:00
2018-05-18 11:56:51 +00:00
### Panel for right column
2018-09-17 13:12:13 +00:00
$ self - > { right_panel } = Wx::Panel - > new ( $ self , - 1 , wxDefaultPosition , wxDefaultSize , wxTAB_TRAVERSAL ) ;
# $self->{right_panel} = Wx::ScrolledWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
# $self->{right_panel}->SetScrollbars(0, 1, 1, 1);
### Scrolled Window for panel without "Export G-code" and "Slice now" buttons
my $ scrolled_window_sizer = $ self - > { scrolled_window_sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ scrolled_window_sizer - > SetMinSize ( [ 320 , - 1 ] ) ;
my $ scrolled_window_panel = $ self - > { scrolled_window_panel } = Wx::ScrolledWindow - > new ( $ self - > { right_panel } , - 1 , wxDefaultPosition , wxDefaultSize , wxTAB_TRAVERSAL ) ;
$ scrolled_window_panel - > SetSizer ( $ scrolled_window_sizer ) ;
$ scrolled_window_panel - > SetScrollbars ( 0 , 1 , 1 , 1 ) ;
2012-05-04 09:22:56 +00:00
2013-08-25 10:22:05 +00:00
# right pane buttons
2018-09-17 13:12:13 +00:00
$ self - > { btn_export_gcode } = Wx::Button - > new ( $ self - > { right_panel } , - 1 , L ( "Export G-code…" ) , wxDefaultPosition , [ - 1 , 30 ] , ) ; # wxNO_BORDER);#, wxBU_LEFT);
$ self - > { btn_reslice } = Wx::Button - > new ( $ self - > { right_panel } , - 1 , L ( "Slice now" ) , wxDefaultPosition , [ - 1 , 30 ] ) ; #, wxNO_BORDER);#, wxBU_LEFT);
# $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
# $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
$ self - > { btn_print } = Wx::Button - > new ( $ scrolled_window_panel , - 1 , L ( "Print…" ) , wxDefaultPosition , [ - 1 , 30 ] , wxBU_LEFT ) ;
$ self - > { btn_send_gcode } = Wx::Button - > new ( $ scrolled_window_panel , - 1 , L ( "Send to printer" ) , wxDefaultPosition , [ - 1 , 30 ] , wxBU_LEFT ) ;
#$self->{btn_export_stl} = Wx::Button->new($self->{right_panel}, -1, L("Export STL…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
2014-12-25 17:50:02 +00:00
#$self->{btn_export_gcode}->SetFont($Slic3r::GUI::small_font);
#$self->{btn_export_stl}->SetFont($Slic3r::GUI::small_font);
2015-01-03 22:25:55 +00:00
$ self - > { btn_print } - > Hide ;
2014-12-28 00:30:05 +00:00
$ self - > { btn_send_gcode } - > Hide ;
2012-05-04 09:22:56 +00:00
2018-08-24 14:20:19 +00:00
# export_gcode cog_go.png
2018-09-17 13:12:13 +00:00
#! reslice reslice.png
2017-08-03 15:47:18 +00:00
my % icons = qw(
print arrow_up . png
send_gcode arrow_up . png
export_stl brick_go . png
) ;
for ( grep $ self - > { "btn_$_" } , keys % icons ) {
2017-10-25 10:53:31 +00:00
$ self - > { "btn_$_" } - > SetBitmap ( Wx::Bitmap - > new ( Slic3r:: var ( $ icons { $ _ } ) , wxBITMAP_TYPE_PNG ) ) ;
2012-05-01 14:49:34 +00:00
}
2012-04-30 12:56:01 +00:00
$ self - > selection_changed ( 0 ) ;
$ self - > object_list_changed ;
2014-06-13 17:23:51 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_export_gcode } , sub {
$ self - > export_gcode ;
} ) ;
2015-01-03 22:25:55 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_print } , sub {
$ self - > { print_file } = $ self - > export_gcode ( Wx::StandardPaths::Get - > GetTempDir ( ) ) ;
} ) ;
2014-12-28 00:30:05 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_send_gcode } , sub {
$ self - > { send_gcode_file } = $ self - > export_gcode ( Wx::StandardPaths::Get - > GetTempDir ( ) ) ;
} ) ;
2016-10-25 11:24:42 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_reslice } , \ & reslice ) ;
2014-12-28 13:58:24 +00:00
EVT_BUTTON ( $ self , $ self - > { btn_export_stl } , \ & export_stl ) ;
2012-04-30 12:56:01 +00:00
2018-08-15 11:19:58 +00:00
# if ($self->{htoolbar}) {
# EVT_TOOL($self, TB_ADD, sub { $self->add; });
# EVT_TOOL($self, TB_REMOVE, sub { $self->remove() }); # explicitly pass no argument to remove
# EVT_TOOL($self, TB_RESET, sub { $self->reset; });
# EVT_TOOL($self, TB_ARRANGE, sub { $self->arrange; });
# EVT_TOOL($self, TB_MORE, sub { $self->increase; });
# EVT_TOOL($self, TB_FEWER, sub { $self->decrease; });
# EVT_TOOL($self, TB_45CW, sub { $_[0]->rotate(-45, Z, 'relative') });
# EVT_TOOL($self, TB_45CCW, sub { $_[0]->rotate(45, Z, 'relative') });
# EVT_TOOL($self, TB_SCALE, sub { $self->changescale(undef); });
# EVT_TOOL($self, TB_SPLIT, sub { $self->split_object; });
# 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 = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state);
# $self->on_layer_editing_toggled(! $state);
# });
# } else {
# EVT_BUTTON($self, $self->{btn_add}, sub { $self->add; });
# EVT_BUTTON($self, $self->{btn_remove}, sub { $self->remove() }); # explicitly pass no argument to remove
2018-08-24 13:01:26 +00:00
# EVT_BUTTON($self, $self->{btn_remove}, sub { Slic3r::GUI::remove_obj() }); # explicitly pass no argument to remove
2018-08-15 11:19:58 +00:00
# EVT_BUTTON($self, $self->{btn_reset}, sub { $self->reset; });
# EVT_BUTTON($self, $self->{btn_arrange}, sub { $self->arrange; });
# EVT_BUTTON($self, $self->{btn_increase}, sub { $self->increase; });
# EVT_BUTTON($self, $self->{btn_decrease}, sub { $self->decrease; });
# EVT_BUTTON($self, $self->{btn_rotate45cw}, sub { $_[0]->rotate(-45, Z, 'relative') });
# EVT_BUTTON($self, $self->{btn_rotate45ccw}, sub { $_[0]->rotate(45, Z, 'relative') });
# EVT_BUTTON($self, $self->{btn_changescale}, sub { $self->changescale(undef); });
# EVT_BUTTON($self, $self->{btn_split}, sub { $self->split_object; });
# EVT_BUTTON($self, $self->{btn_cut}, sub { $_[0]->object_cut_dialog });
# EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog });
# EVT_TOGGLEBUTTON($self, $self->{btn_layer_editing}, sub { $self->on_layer_editing_toggled($self->{btn_layer_editing}->GetValue); });
# }
2012-05-04 09:22:56 +00:00
2012-05-04 08:15:33 +00:00
$ _ - > SetDropTarget ( Slic3r::GUI::Plater::DropTarget - > new ( $ self ) )
2015-01-18 18:36:47 +00:00
for grep defined ( $ _ ) ,
2018-09-18 14:13:18 +00:00
$ self , $ self - > { canvas3D } , $ self - > { preview_iface } , $ self - > { list } ;
2018-09-18 11:35:05 +00:00
# $self, $self->{canvas3D}, $self->{preview3D}, $self->{list};
2018-08-24 13:01:26 +00:00
# $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D};
2012-04-30 12:56:01 +00:00
2018-03-23 10:41:20 +00:00
EVT_COMMAND ( $ self , - 1 , $ SLICING_COMPLETED_EVENT , sub {
2012-05-05 19:08:15 +00:00
my ( $ self , $ event ) = @ _ ;
2018-03-23 10:41:20 +00:00
$ self - > on_update_print_preview ;
2012-05-19 19:13:10 +00:00
} ) ;
2014-06-13 09:19:53 +00:00
EVT_COMMAND ( $ self , - 1 , $ PROCESS_COMPLETED_EVENT , sub {
my ( $ self , $ event ) = @ _ ;
2018-02-13 17:31:34 +00:00
$ self - > on_process_completed ( $ event - > GetInt ? undef : $ event - > GetString ) ;
2014-06-13 09:19:53 +00:00
} ) ;
2018-10-11 08:03:38 +00:00
# XXX: not done
2017-11-02 15:21:34 +00:00
{
2015-01-18 20:31:09 +00:00
my $ timer_id = Wx:: NewId ( ) ;
$ self - > { apply_config_timer } = Wx::Timer - > new ( $ self , $ timer_id ) ;
EVT_TIMER ( $ self , $ timer_id , sub {
my ( $ self , $ event ) = @ _ ;
$ self - > async_apply_config ;
} ) ;
}
2014-06-13 13:54:13 +00:00
2018-07-25 07:42:03 +00:00
# $self->{canvas}->update_bed_size;
2014-12-16 00:12:37 +00:00
if ( $ self - > { canvas3D } ) {
2018-06-06 13:17:10 +00:00
Slic3r::GUI::_3DScene:: set_bed_shape ( $ self - > { canvas3D } , $ self - > { config } - > bed_shape ) ;
2018-05-24 14:11:34 +00:00
Slic3r::GUI::_3DScene:: zoom_to_bed ( $ self - > { canvas3D } ) ;
2014-12-16 00:12:37 +00:00
}
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_bed_shape ( $ self - > { config } - > bed_shape ) if ( $ self - > { preview_iface } ) ;
2018-09-18 14:13:18 +00:00
# if ($self->{preview3D}) {
# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape);
# }
2013-12-18 17:54:11 +00:00
$ self - > update ;
2012-04-30 12:56:01 +00:00
{
2013-08-25 10:22:05 +00:00
my $ presets ;
2017-06-14 09:48:08 +00:00
{
2018-08-07 15:23:48 +00:00
$ presets = $ self - > { presets_sizer } = Wx::FlexGridSizer - > new ( 4 , 2 , 1 , 2 ) ;
2014-12-25 17:50:02 +00:00
$ presets - > AddGrowableCol ( 1 , 1 ) ;
$ presets - > SetFlexibleDirection ( wxHORIZONTAL ) ;
2013-01-03 14:49:20 +00:00
my % group_labels = (
2018-02-22 14:13:07 +00:00
print = > L ( 'Print settings' ) ,
filament = > L ( 'Filament' ) ,
2018-08-08 14:22:56 +00:00
sla_material = > L ( 'SLA material' ) ,
2018-02-22 14:13:07 +00:00
printer = > L ( 'Printer' ) ,
2013-01-03 14:49:20 +00:00
) ;
2018-08-07 15:23:48 +00:00
# UI Combo boxes for a print, multiple filaments, SLA material and a printer.
2016-10-24 14:07:36 +00:00
# Initially a single filament combo box is created, but the number of combo boxes for the filament selection may increase,
# once a printer preset with multiple extruders is activated.
# $self->{preset_choosers}{$group}[$idx]
2013-01-03 14:49:20 +00:00
$ self - > { preset_choosers } = { } ;
2018-08-08 14:22:56 +00:00
for my $ group ( qw( print filament sla_material printer ) ) {
2018-09-17 13:12:13 +00:00
# my $text = Wx::StaticText->new($self->{right_panel}, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
my $ text = Wx::StaticText - > new ( $ scrolled_window_panel , - 1 , "$group_labels{$group}:" , wxDefaultPosition , wxDefaultSize , wxALIGN_RIGHT ) ;
2013-08-25 10:22:05 +00:00
$ text - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2018-09-17 13:12:13 +00:00
# my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY);
my $ choice = Wx::BitmapComboBox - > new ( $ scrolled_window_panel , - 1 , "" , wxDefaultPosition , wxDefaultSize , [] , wxCB_READONLY ) ;
2018-02-15 15:41:26 +00:00
if ( $ group eq 'filament' ) {
EVT_LEFT_DOWN ( $ choice , sub { $ self - > filament_color_box_lmouse_down ( 0 , @ _ ) ; } ) ;
}
2013-01-03 14:49:20 +00:00
$ self - > { preset_choosers } { $ group } = [ $ choice ] ;
2015-06-02 09:19:11 +00:00
# setup the listener
EVT_COMBOBOX ( $ choice , $ choice , sub {
my ( $ choice ) = @ _ ;
wxTheApp - > CallAfter ( sub {
2017-10-26 15:17:39 +00:00
$ self - > _on_select_preset ( $ group , $ choice , 0 ) ;
2015-06-02 09:19:11 +00:00
} ) ;
} ) ;
2014-12-25 18:42:24 +00:00
$ presets - > Add ( $ text , 0 , wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT , 4 ) ;
2018-03-09 16:17:51 +00:00
$ presets - > Add ( $ choice , 1 , wxALIGN_CENTER_VERTICAL | wxEXPAND | wxBOTTOM , 1 ) ;
2013-08-25 10:22:05 +00:00
}
2018-05-20 21:39:52 +00:00
$ presets - > Layout ;
2013-08-25 10:22:05 +00:00
}
2018-03-09 16:17:51 +00:00
2018-08-24 13:01:26 +00:00
my $ frequently_changed_parameters_sizer = $ self - > { frequently_changed_parameters_sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
2018-09-17 13:12:13 +00:00
#! Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets);
Slic3r::GUI:: add_frequently_changed_parameters ( $ self - > { scrolled_window_panel } , $ frequently_changed_parameters_sizer , $ presets ) ;
2018-05-13 19:00:03 +00:00
2013-08-25 10:22:05 +00:00
my $ object_info_sizer ;
{
2018-09-17 13:12:13 +00:00
my $ box = Wx::StaticBox - > new ( $ scrolled_window_panel , - 1 , L ( "Info" ) ) ;
# my $box = Wx::StaticBox->new($self->{right_panel}, -1, L("Info"));
2018-05-28 09:10:09 +00:00
$ box - > SetFont ( $ Slic3r:: GUI:: small_bold_font ) ;
2013-08-25 10:22:05 +00:00
$ object_info_sizer = Wx::StaticBoxSizer - > new ( $ box , wxVERTICAL ) ;
2018-05-13 19:00:03 +00:00
$ object_info_sizer - > SetMinSize ( [ 300 , - 1 ] ) ;
2018-06-07 09:54:42 +00:00
#!my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5);
my $ grid_sizer = Wx::FlexGridSizer - > new ( 2 , 4 , 5 , 5 ) ;
2013-08-25 15:26:55 +00:00
$ grid_sizer - > SetFlexibleDirection ( wxHORIZONTAL ) ;
$ grid_sizer - > AddGrowableCol ( 1 , 1 ) ;
$ grid_sizer - > AddGrowableCol ( 3 , 1 ) ;
$ object_info_sizer - > Add ( $ grid_sizer , 0 , wxEXPAND ) ;
2013-08-25 10:22:05 +00:00
my @ info = (
2018-02-22 14:13:07 +00:00
size = > L ( "Size" ) ,
volume = > L ( "Volume" ) ,
facets = > L ( "Facets" ) ,
materials = > L ( "Materials" ) ,
manifold = > L ( "Manifold" ) ,
2013-08-25 10:22:05 +00:00
) ;
while ( my $ field = shift @ info ) {
my $ label = shift @ info ;
2018-09-17 13:12:13 +00:00
my $ text = Wx::StaticText - > new ( $ scrolled_window_panel , - 1 , "$label:" , wxDefaultPosition , wxDefaultSize , wxALIGN_LEFT ) ;
# my $text = Wx::StaticText->new($self->{right_panel}, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
2013-08-25 10:22:05 +00:00
$ text - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2018-06-07 09:54:42 +00:00
#!$grid_sizer->Add($text, 0);
2013-08-25 10:22:05 +00:00
2018-09-17 13:12:13 +00:00
$ self - > { "object_info_$field" } = Wx::StaticText - > new ( $ scrolled_window_panel , - 1 , "" , wxDefaultPosition , wxDefaultSize , wxALIGN_LEFT ) ;
# $self->{"object_info_$field"} = Wx::StaticText->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
2013-08-25 10:22:05 +00:00
$ self - > { "object_info_$field" } - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
2013-08-25 15:26:55 +00:00
if ( $ field eq 'manifold' ) {
2018-09-17 13:12:13 +00:00
$ self - > { object_info_manifold_warning_icon } = Wx::StaticBitmap - > new ( $ scrolled_window_panel , - 1 , Wx::Bitmap - > new ( Slic3r:: var ( "error.png" ) , wxBITMAP_TYPE_PNG ) ) ;
# $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self->{right_panel}, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
2018-05-18 09:39:49 +00:00
#$self->{object_info_manifold_warning_icon}->Hide;
$ self - > { "object_info_manifold_warning_icon_show" } = sub {
if ( $ self - > { object_info_manifold_warning_icon } - > IsShown ( ) != $ _ [ 0 ] ) {
2018-09-17 13:12:13 +00:00
# this fuction show/hide info_manifold_warning_icon on the c++ side now
2018-05-18 09:39:49 +00:00
Slic3r::GUI:: set_show_manifold_warning_icon ( $ _ [ 0 ] ) ;
2018-09-17 13:12:13 +00:00
#my $mode = wxTheApp->{app_config}->get("view_mode");
#return if ($mode eq "" || $mode eq "simple");
#$self->{object_info_manifold_warning_icon}->Show($_[0]);
#$self->Layout
2018-05-18 09:39:49 +00:00
}
} ;
$ self - > { "object_info_manifold_warning_icon_show" } - > ( 0 ) ;
2013-08-25 15:26:55 +00:00
my $ h_sizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
2018-06-07 09:54:42 +00:00
$ h_sizer - > Add ( $ text , 0 ) ;
$ h_sizer - > Add ( $ self - > { object_info_manifold_warning_icon } , 0 , wxLEFT , 2 ) ;
$ h_sizer - > Add ( $ self - > { "object_info_$field" } , 0 , wxLEFT , 2 ) ;
#!$grid_sizer->Add($h_sizer, 0, wxEXPAND);
$ object_info_sizer - > Add ( $ h_sizer , 0 , wxEXPAND | wxTOP , 4 ) ;
2013-08-25 15:26:55 +00:00
} else {
2018-06-07 09:54:42 +00:00
$ grid_sizer - > Add ( $ text , 0 ) ;
2013-08-25 15:26:55 +00:00
$ grid_sizer - > Add ( $ self - > { "object_info_$field" } , 0 ) ;
}
2013-01-03 14:49:20 +00:00
}
}
2017-01-21 03:21:57 +00:00
2018-09-17 13:12:13 +00:00
my $ print_info_box = Wx::StaticBox - > new ( $ scrolled_window_panel , - 1 , L ( "Sliced Info" ) ) ;
$ print_info_box - > SetFont ( $ Slic3r:: GUI:: small_bold_font ) ;
my $ print_info_sizer = $ self - > { print_info_sizer } = Wx::StaticBoxSizer - > new ( $ print_info_box , wxVERTICAL ) ;
# Wx::StaticBox->new($self->{right_panel}, -1, L("Sliced Info")), wxVERTICAL);
2018-07-18 12:52:19 +00:00
$ print_info_sizer - > SetMinSize ( [ 300 , - 1 ] ) ;
2012-06-19 15:23:10 +00:00
2014-12-25 17:50:02 +00:00
my $ buttons_sizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
2016-10-25 11:24:42 +00:00
$ self - > { buttons_sizer } = $ buttons_sizer ;
2014-12-25 17:50:02 +00:00
$ buttons_sizer - > AddStretchSpacer ( 1 ) ;
2018-09-17 13:12:13 +00:00
# $buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0);
#! $buttons_sizer->Add($self->{btn_reslice}, 0, wxALIGN_RIGHT, 0);
$ buttons_sizer - > Add ( $ self - > { btn_print } , 0 , wxALIGN_RIGHT | wxBOTTOM | wxTOP , 5 ) ;
$ buttons_sizer - > Add ( $ self - > { btn_send_gcode } , 0 , wxALIGN_RIGHT | wxBOTTOM | wxTOP , 5 ) ;
2013-08-25 10:22:05 +00:00
2018-08-24 13:01:26 +00:00
# $scrolled_window_sizer->Add($self->{list}, 1, wxEXPAND, 5);
# $scrolled_window_sizer->Add($object_info_sizer, 0, wxEXPAND, 0);
# $scrolled_window_sizer->Add($print_info_sizer, 0, wxEXPAND, 0);
2018-05-27 20:12:01 +00:00
#$buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0);
2018-05-13 19:00:03 +00:00
2018-05-28 15:08:48 +00:00
### Sizer for info boxes
2018-07-26 10:10:45 +00:00
my $ info_sizer = $ self - > { info_sizer } = Wx::BoxSizer - > new ( wxVERTICAL ) ;
2018-07-04 10:38:34 +00:00
$ info_sizer - > SetMinSize ( [ 318 , - 1 ] ) ;
2018-09-17 13:12:13 +00:00
$ info_sizer - > Add ( $ object_info_sizer , 0 , wxEXPAND | wxTOP , 20 ) ;
$ info_sizer - > Add ( $ print_info_sizer , 0 , wxEXPAND | wxTOP , 20 ) ;
$ scrolled_window_sizer - > Add ( $ presets , 0 , wxEXPAND | wxLEFT , 2 ) if defined $ presets ;
$ scrolled_window_sizer - > Add ( $ frequently_changed_parameters_sizer , 1 , wxEXPAND | wxLEFT , 0 ) if defined $ frequently_changed_parameters_sizer ;
$ scrolled_window_sizer - > Add ( $ buttons_sizer , 0 , wxEXPAND , 0 ) ;
$ scrolled_window_sizer - > Add ( $ info_sizer , 0 , wxEXPAND | wxLEFT , 20 ) ;
# Show the box initially, let it be shown after the slicing is finished.
$ self - > print_info_box_show ( 0 ) ;
### Sizer for "Export G-code" & "Slice now" buttons
my $ btns_sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
$ btns_sizer - > SetMinSize ( [ 318 , - 1 ] ) ;
$ btns_sizer - > Add ( $ self - > { btn_reslice } , 0 , wxEXPAND , 0 ) ;
$ btns_sizer - > Add ( $ self - > { btn_export_gcode } , 0 , wxEXPAND | wxTOP , 5 ) ;
2018-05-13 19:00:03 +00:00
2013-08-25 10:22:05 +00:00
my $ right_sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
2018-05-18 11:56:51 +00:00
$ self - > { right_panel } - > SetSizer ( $ right_sizer ) ;
2018-05-23 14:21:42 +00:00
$ right_sizer - > SetMinSize ( [ 320 , - 1 ] ) ;
2018-09-17 13:12:13 +00:00
#! $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets;
#! $right_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
#! $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, 10);
#! $right_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
2017-02-15 15:02:54 +00:00
# Show the box initially, let it be shown after the slicing is finished.
2018-09-17 13:12:13 +00:00
#! $self->print_info_box_show(0);
$ right_sizer - > Add ( $ scrolled_window_panel , 1 , wxEXPAND | wxTOP , 5 ) ;
# $right_sizer->Add($self->{btn_reslice}, 0, wxEXPAND | wxLEFT | wxTOP, 20);
# $right_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxLEFT | wxTOP, 20);
$ right_sizer - > Add ( $ btns_sizer , 0 , wxEXPAND | wxLEFT | wxTOP , 20 ) ;
2017-02-15 15:02:54 +00:00
2013-08-25 10:22:05 +00:00
my $ hsizer = Wx::BoxSizer - > new ( wxHORIZONTAL ) ;
2014-07-13 10:10:34 +00:00
$ hsizer - > Add ( $ self - > { preview_notebook } , 1 , wxEXPAND | wxTOP , 1 ) ;
2018-09-17 13:12:13 +00:00
$ hsizer - > Add ( $ self - > { right_panel } , 0 , wxEXPAND | wxLEFT | wxRIGHT , 0 ) ; #3);
2018-08-15 11:19:58 +00:00
2013-08-25 10:22:05 +00:00
my $ sizer = Wx::BoxSizer - > new ( wxVERTICAL ) ;
2018-08-15 11:19:58 +00:00
# $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar};
# $sizer->Add($self->{btoolbar}, 0, wxEXPAND, 0) if $self->{btoolbar};
2013-08-25 10:22:05 +00:00
$ sizer - > Add ( $ hsizer , 1 , wxEXPAND , 0 ) ;
2012-04-30 12:56:01 +00:00
$ sizer - > SetSizeHints ( $ self ) ;
$ self - > SetSizer ( $ sizer ) ;
2018-05-17 08:46:32 +00:00
# Send sizers/buttons to C++
2018-09-17 13:12:13 +00:00
Slic3r::GUI:: set_objects_from_perl ( $ self - > { scrolled_window_panel } ,
$ frequently_changed_parameters_sizer ,
$ info_sizer ,
$ self - > { btn_export_gcode } ,
# $self->{btn_export_stl},
$ self - > { btn_reslice } ,
$ self - > { btn_print } ,
$ self - > { btn_send_gcode } ,
$ self - > { object_info_manifold_warning_icon } ) ;
Slic3r::GUI:: set_model_events_from_perl ( $ self - > { model } ,
$ self - > { event_object_selection_changed } ,
$ self - > { event_object_settings_changed } ,
$ self - > { event_remove_object } ,
$ self - > { event_update_scene } ) ;
2012-04-30 12:56:01 +00:00
}
2016-10-25 11:24:42 +00:00
2018-04-20 15:32:08 +00:00
# Last correct selected item for each preset
{
$ self - > { selected_item_print } = 0 ;
$ self - > { selected_item_filament } = 0 ;
$ self - > { selected_item_printer } = 0 ;
2012-04-30 12:56:01 +00:00
}
2016-10-25 11:24:42 +00:00
$ self - > update_ui_from_settings ( ) ;
2018-05-04 16:32:20 +00:00
$ self - > Layout ;
2014-07-01 14:40:56 +00:00
2012-04-30 12:56:01 +00:00
return $ self ;
}
2018-10-08 17:14:55 +00:00
# XXX: VK: WIP
2014-07-01 14:40:56 +00:00
# sets the callback
2012-10-24 18:24:11 +00:00
sub on_select_preset {
2014-07-01 14:40:56 +00:00
my ( $ self , $ cb ) = @ _ ;
$ self - > { on_select_preset } = $ cb ;
}
2018-10-08 17:14:55 +00:00
# XXX: merged with on_select_preset
2017-10-26 15:17:39 +00:00
# Called from the platter combo boxes selecting the active print, filament or printer.
2014-07-01 14:40:56 +00:00
sub _on_select_preset {
2017-10-26 15:17:39 +00:00
my ( $ self , $ group , $ choice , $ idx ) = @ _ ;
2016-10-24 14:07:36 +00:00
# If user changed a filament preset and the selected machine is equipped with multiple extruders,
# there are multiple filament selection combo boxes shown at the platter. In that case
# don't propagate the filament selection changes to the tab.
2017-10-26 15:17:39 +00:00
if ( $ group eq 'filament' ) {
wxTheApp - > { preset_bundle } - > set_filament_preset ( $ idx , $ choice - > GetStringSelection ) ;
}
2012-10-24 18:24:11 +00:00
if ( $ group eq 'filament' && @ { $ self - > { preset_choosers } { filament } } > 1 ) {
2017-12-13 13:00:14 +00:00
# Only update the platter UI for the 2nd and other filaments.
2017-11-10 16:27:05 +00:00
wxTheApp - > { preset_bundle } - > update_platter_filament_ui ( $ idx , $ choice ) ;
2017-05-24 13:20:20 +00:00
} else {
2018-04-20 15:32:08 +00:00
my $ selected_item = $ choice - > GetSelection ( ) ;
2018-05-22 12:00:42 +00:00
return if ( $ selected_item == $ self - > { "selected_item_$group" } &&
! Slic3r::GUI:: get_preset_tab ( $ group ) - > current_preset_is_dirty ) ;
2018-04-20 15:32:08 +00:00
my $ selected_string = $ choice - > GetString ( $ selected_item ) ;
2018-05-02 11:20:36 +00:00
if ( $ selected_string eq ( "------- " . L ( "System presets" ) . " -------" ) ||
$ selected_string eq ( "------- " . L ( "User presets" ) . " -------" ) ) {
2018-04-20 15:32:08 +00:00
$ choice - > SetSelection ( $ self - > { "selected_item_$group" } ) ;
return ;
}
2017-05-24 13:20:20 +00:00
# call GetSelection() in scalar context as it's context-aware
2018-04-20 15:32:08 +00:00
# $self->{on_select_preset}->($group, $choice->GetStringSelection)
$ self - > { on_select_preset } - > ( $ group , $ selected_string )
if $ self - > { on_select_preset } ;
$ self - > { "selected_item_$group" } = $ selected_item ;
2017-05-24 13:20:20 +00:00
}
2017-11-02 15:21:34 +00:00
# Synchronize config.ini with the current selections.
wxTheApp - > { preset_bundle } - > export_selections ( wxTheApp - > { app_config } ) ;
2014-07-01 14:40:56 +00:00
# get new config and generate on_config_change() event for updating plater and other things
2017-10-25 10:53:31 +00:00
$ self - > on_config_change ( wxTheApp - > { preset_bundle } - > full_config ) ;
2012-10-24 18:24:11 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2016-12-12 17:02:24 +00:00
sub on_layer_editing_toggled {
my ( $ self , $ new_state ) = @ _ ;
2018-05-25 12:05:08 +00:00
Slic3r::GUI::_3DScene:: enable_layers_editing ( $ self - > { canvas3D } , $ new_state ) ;
if ( $ new_state && ! Slic3r::GUI::_3DScene:: is_layers_editing_enabled ( $ self - > { canvas3D } ) ) {
2017-02-19 17:01:03 +00:00
# Initialization of the OpenGL shaders failed. Disable the tool.
2018-08-15 11:19:58 +00:00
# if ($self->{htoolbar}) {
# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0);
# } else {
# $self->{"btn_layer_editing"}->Disable;
# $self->{"btn_layer_editing"}->SetValue(0);
# }
2018-07-23 11:49:48 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "layersediting" , 0 ) ;
2017-02-19 17:01:03 +00:00
}
2017-05-17 14:53:40 +00:00
$ self - > { canvas3D } - > Refresh ;
$ self - > { canvas3D } - > Update ;
2016-12-12 17:02:24 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done (Plater::priv::main_frame)
sub GetFrame {
2014-06-14 16:58:56 +00:00
my ( $ self ) = @ _ ;
2014-06-14 17:54:18 +00:00
return & Wx:: GetTopLevelParent ( $ self ) ;
2012-07-27 19:13:03 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2016-10-25 11:24:42 +00:00
# Called after the Preferences dialog is closed and the program settings are saved.
# Update the UI based on the current preferences.
sub update_ui_from_settings
{
my ( $ self ) = @ _ ;
2017-11-02 15:21:34 +00:00
if ( defined ( $ self - > { btn_reslice } ) && $ self - > { buttons_sizer } - > IsShown ( $ self - > { btn_reslice } ) != ( ! wxTheApp - > { app_config } - > get ( "background_processing" ) ) ) {
$ self - > { buttons_sizer } - > Show ( $ self - > { btn_reslice } , ! wxTheApp - > { app_config } - > get ( "background_processing" ) ) ;
2016-10-25 11:24:42 +00:00
$ self - > { buttons_sizer } - > Layout ;
}
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2018-08-07 15:23:48 +00:00
# Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs.
2016-10-24 14:07:36 +00:00
# Called by
# Slic3r::GUI::Tab::Print::_on_presets_changed
# Slic3r::GUI::Tab::Filament::_on_presets_changed
2018-08-07 15:23:48 +00:00
# Slic3r::GUI::Tab::Material::_on_presets_changed
2016-10-24 14:07:36 +00:00
# Slic3r::GUI::Tab::Printer::_on_presets_changed
# when the presets are loaded or the user selects another preset.
# For Print settings and Printer, synchronize the selection index with their tabs.
# For Filament, synchronize the selection index for a single extruder printer only, otherwise keep the selection.
2012-08-07 16:44:47 +00:00
sub update_presets {
2018-08-08 14:22:56 +00:00
# $group: one of qw(print filament sla_material printer)
2017-10-26 15:17:39 +00:00
# $presets: PresetCollection
my ( $ self , $ group , $ presets ) = @ _ ;
my @ choosers = @ { $ self - > { preset_choosers } { $ group } } ;
if ( $ group eq 'filament' ) {
my $ choice_idx = 0 ;
if ( int ( @ choosers ) == 1 ) {
# Single filament printer, synchronize the filament presets.
wxTheApp - > { preset_bundle } - > set_filament_preset ( 0 , wxTheApp - > { preset_bundle } - > filament - > get_selected_preset - > name ) ;
}
foreach my $ choice ( @ choosers ) {
wxTheApp - > { preset_bundle } - > update_platter_filament_ui ( $ choice_idx , $ choice ) ;
$ choice_idx += 1 ;
}
} elsif ( $ group eq 'print' ) {
2017-11-10 16:27:05 +00:00
wxTheApp - > { preset_bundle } - > print - > update_platter_ui ( $ choosers [ 0 ] ) ;
2018-08-08 14:22:56 +00:00
} elsif ( $ group eq 'sla_material' ) {
2018-08-07 15:23:48 +00:00
wxTheApp - > { preset_bundle } - > sla_material - > update_platter_ui ( $ choosers [ 0 ] ) ;
2017-10-26 15:17:39 +00:00
} elsif ( $ group eq 'printer' ) {
2017-11-10 16:27:05 +00:00
# Update the print choosers to only contain the compatible presets, update the dirty flags.
wxTheApp - > { preset_bundle } - > print - > update_platter_ui ( $ self - > { preset_choosers } { print } - > [ 0 ] ) ;
# Update the printer choosers, update the dirty flags.
wxTheApp - > { preset_bundle } - > printer - > update_platter_ui ( $ choosers [ 0 ] ) ;
# Update the filament choosers to only contain the compatible presets, update the color preview,
# update the dirty flags.
2017-10-26 15:17:39 +00:00
my $ choice_idx = 0 ;
foreach my $ choice ( @ { $ self - > { preset_choosers } { filament } } ) {
2017-11-10 16:27:05 +00:00
wxTheApp - > { preset_bundle } - > update_platter_filament_ui ( $ choice_idx , $ choice ) ;
2017-10-26 15:17:39 +00:00
$ choice_idx += 1 ;
}
}
2017-11-02 15:21:34 +00:00
# Synchronize config.ini with the current selections.
wxTheApp - > { preset_bundle } - > export_selections ( wxTheApp - > { app_config } ) ;
2012-08-07 16:44:47 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done, in on_action_add()
2013-12-12 19:19:33 +00:00
sub add {
2017-10-27 20:49:59 +00:00
my ( $ self ) = @ _ ;
2014-06-14 17:59:59 +00:00
my @ input_files = wxTheApp - > open_model ( $ self ) ;
2017-07-11 11:55:55 +00:00
$ self - > load_files ( \ @ input_files ) ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2017-07-11 11:55:55 +00:00
sub load_files {
my ( $ self , $ input_files ) = @ _ ;
return if ! defined ( $ input_files ) || ! scalar ( @$ input_files ) ;
my $ nozzle_dmrs = $ self - > { config } - > get ( 'nozzle_diameter' ) ;
# One of the files is potentionally a bundle of files. Don't bundle them, but load them one by one.
# Only bundle .stls or .objs if the printer has multiple extruders.
my $ one_by_one = ( @$ nozzle_dmrs <= 1 ) || ( @$ input_files == 1 ) ||
2018-02-14 13:30:03 +00:00
defined ( first { $ _ =~ /.[aA][mM][fF]$/ || $ _ =~ /.[aA][mM][fF].[xX][mM][lL]$/ || $ _ =~ /.[zZ][iI][pP].[aA][mM][fF]$/ || $ _ =~ /.3[mM][fF]$/ || $ _ =~ /.[pP][rR][uI][sS][aA]$/ } @$ input_files ) ;
2017-07-11 11:55:55 +00:00
2018-02-22 14:13:07 +00:00
my $ process_dialog = Wx::ProgressDialog - > new ( L ( 'Loading…' ) , L ( "Processing input file\n" ) . basename ( $ input_files - > [ 0 ] ) , 100 , $ self , 0 ) ;
2012-04-30 19:49:44 +00:00
$ process_dialog - > Pulse ;
2012-04-30 12:56:01 +00:00
local $ SIG { __WARN__ } = Slic3r::GUI:: warning_catcher ( $ self ) ;
2017-07-11 11:55:55 +00:00
# new_model to collect volumes, if all of them come from .stl or .obj and there is a chance, that they will be
# possibly merged into a single multi-part object.
my $ new_model = $ one_by_one ? undef : Slic3r::Model - > new ;
# Object indices for the UI.
2016-12-17 20:47:45 +00:00
my @ obj_idx = ( ) ;
2017-07-11 11:55:55 +00:00
# Collected file names to display the final message on the status bar.
2018-09-17 10:15:11 +00:00
my @ loaded_files = ( ) ; # XXX: used???
2017-07-11 11:55:55 +00:00
# For all input files.
for ( my $ i = 0 ; $ i < @$ input_files ; $ i += 1 ) {
my $ input_file = $ input_files - > [ $ i ] ;
2018-02-22 14:13:07 +00:00
$ process_dialog - > Update ( 100 . * $ i / @$ input_files , L ( "Processing input file\n" ) . basename ( $ input_file ) ) ;
2017-07-11 11:55:55 +00:00
2018-02-13 14:19:55 +00:00
my $ model ;
2018-02-14 13:30:03 +00:00
if ( ( $ input_file =~ /.3[mM][fF]$/ ) || ( $ input_file =~ /.[zZ][iI][pP].[aA][mM][fF]$/ ) )
2018-02-13 14:19:55 +00:00
{
$ model = eval { Slic3r::Model - > read_from_archive ( $ input_file , wxTheApp - > { preset_bundle } , 0 ) } ;
Slic3r::GUI:: show_error ( $ self , $@ ) if $@ ;
$ _ - > load_current_preset for ( values % { $ self - > GetFrame - > { options_tabs } } ) ;
wxTheApp - > { app_config } - > update_config_dir ( dirname ( $ input_file ) ) ;
2018-04-25 08:59:06 +00:00
# forces the update of the config here, or it will invalidate the imported layer heights profile if done using the timer
# and if the config contains a "layer_height" different from the current defined one
$ self - > async_apply_config ;
2018-02-13 14:19:55 +00:00
}
else
{
$ model = eval { Slic3r::Model - > read_from_file ( $ input_file , 0 ) } ;
Slic3r::GUI:: show_error ( $ self , $@ ) if $@ ;
}
2017-07-11 11:55:55 +00:00
next if ! defined $ model ;
2016-03-19 21:22:11 +00:00
if ( $ model - > looks_like_multipart_object ) {
my $ dialog = Wx::MessageDialog - > new ( $ self ,
2018-02-22 14:13:07 +00:00
L ( "This file contains several objects positioned at multiple heights. "
2016-03-19 21:22:11 +00:00
. "Instead of considering them as multiple objects, should I consider\n"
2018-02-22 14:13:07 +00:00
. "this file as a single object having multiple parts?\n" ) ,
L ( 'Multi-part object detected' ) , wxICON_WARNING | wxYES | wxNO ) ;
2018-05-10 16:07:22 +00:00
$ model - > convert_multipart_object ( scalar ( @$ nozzle_dmrs ) ) if $ dialog - > ShowModal ( ) == wxID_YES ;
2017-07-11 11:55:55 +00:00
}
2018-09-10 11:15:12 +00:00
# objects imported from 3mf require a call to center_around_origin to have gizmos working properly and this call
# need to be done after looks_like_multipart_object detection
2018-09-17 10:15:11 +00:00
if ( $ input_file =~ /[.]3[mM][fF]$/ )
2018-09-10 11:15:12 +00:00
{
foreach my $ model_object ( @ { $ model - > objects } ) {
$ model_object - > center_around_origin ; # also aligns object to Z = 0
}
2017-07-11 11:55:55 +00:00
}
if ( $ one_by_one ) {
push @ obj_idx , $ self - > load_model_objects ( @ { $ model - > objects } ) ;
} else {
# This must be an .stl or .obj file, which may contain a maximum of one volume.
$ new_model - > add_object ( $ _ ) for ( @ { $ model - > objects } ) ;
2016-03-19 21:22:11 +00:00
}
2014-03-25 18:06:51 +00:00
}
2017-07-11 11:55:55 +00:00
if ( $ new_model ) {
my $ dialog = Wx::MessageDialog - > new ( $ self ,
2018-02-22 14:13:07 +00:00
L ( "Multiple objects were loaded for a multi-material printer.\n"
2017-07-11 11:55:55 +00:00
. "Instead of considering them as multiple objects, should I consider\n"
2018-02-22 14:13:07 +00:00
. "these files to represent a single object having multiple parts?\n" ) ,
L ( 'Multi-part object detected' ) , wxICON_WARNING | wxYES | wxNO ) ;
2018-05-10 16:07:22 +00:00
$ new_model - > convert_multipart_object ( scalar ( @$ nozzle_dmrs ) ) if $ dialog - > ShowModal ( ) == wxID_YES ;
2017-07-11 11:55:55 +00:00
push @ obj_idx , $ self - > load_model_objects ( @ { $ new_model - > objects } ) ;
}
# Note the current directory for the file open dialog.
2017-11-02 15:21:34 +00:00
wxTheApp - > { app_config } - > update_skein_dir ( dirname ( $ input_files - > [ - 1 ] ) ) ;
2013-12-12 19:19:33 +00:00
$ process_dialog - > Destroy ;
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "Loaded " ) . join ( ',' , @ loaded_files ) ) ;
2016-12-17 20:47:45 +00:00
return @ obj_idx ;
2013-12-12 19:19:33 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done, except a few todos
2014-01-05 13:04:32 +00:00
sub load_model_objects {
my ( $ self , @ model_objects ) = @ _ ;
2013-12-12 19:19:33 +00:00
2014-06-16 21:58:45 +00:00
my $ bed_centerf = $ self - > bed_centerf ;
2015-05-25 17:51:47 +00:00
my $ bed_shape = Slic3r::Polygon - > new_scale ( @ { $ self - > { config } - > bed_shape } ) ;
my $ bed_size = $ bed_shape - > bounding_box - > size ;
2014-06-16 21:58:45 +00:00
2014-01-05 13:04:32 +00:00
my $ need_arrange = 0 ;
2015-05-25 17:51:47 +00:00
my $ scaled_down = 0 ;
2014-01-05 13:04:32 +00:00
my @ obj_idx = ( ) ;
foreach my $ model_object ( @ model_objects ) {
my $ o = $ self - > { model } - > add_object ( $ model_object ) ;
2017-02-09 13:56:13 +00:00
my $ object_name = $ model_object - > name ;
$ object_name = basename ( $ model_object - > input_file ) if ( $ object_name eq '' ) ;
push @ { $ self - > { objects } } , Slic3r::GUI::Plater::Object - > new ( name = > $ object_name ) ;
2014-01-05 13:04:32 +00:00
push @ obj_idx , $# { $ self - > { objects } } ;
2013-12-12 19:19:33 +00:00
2014-05-10 14:59:17 +00:00
if ( $ model_object - > instances_count == 0 ) {
2014-01-05 13:04:32 +00:00
# if object has no defined position(s) we need to rearrange everything after loading
$ need_arrange = 1 ;
2012-09-12 14:30:44 +00:00
2014-01-05 13:04:32 +00:00
# add a default instance and center object around origin
2014-12-12 21:43:04 +00:00
$ o - > center_around_origin ; # also aligns object to Z = 0
2014-06-16 21:58:45 +00:00
$ o - > add_instance ( offset = > $ bed_centerf ) ;
2014-01-05 13:04:32 +00:00
}
2015-05-25 17:51:47 +00:00
{
# if the object is too large (more than 5 times the bed), scale it down
my $ size = $ o - > bounding_box - > size ;
2018-04-10 11:39:10 +00:00
my $ ratio = max ( $ size - > x / unscale($bed_size->x), $size->y / unscale ( $ bed_size - > y ) ) ;
2018-04-13 11:59:36 +00:00
if ( $ ratio > 10000 ) {
# the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
# so scale down the mesh
$ o - > scale_xyz ( Slic3r::Pointf3 - > new ( 1 /$ratio, 1/ $ ratio , 1 / $ ratio ) ) ;
$ scaled_down = 1 ;
}
elsif ( $ ratio > 5 ) {
2015-05-25 17:51:47 +00:00
$ _ - > set_scaling_factor ( 1 / $ ratio ) for @ { $ o - > instances } ;
$ scaled_down = 1 ;
}
}
2012-04-30 12:56:01 +00:00
2014-03-22 19:12:54 +00:00
$ self - > { print } - > auto_assign_extruders ( $ o ) ;
2014-05-06 23:11:49 +00:00
$ self - > { print } - > add_model_object ( $ o ) ;
2014-01-05 13:04:32 +00:00
}
2013-12-13 13:02:01 +00:00
2013-12-18 18:11:20 +00:00
# if user turned autocentering off, automatic arranging would disappoint them
2017-11-02 15:21:34 +00:00
if ( ! wxTheApp - > { app_config } - > get ( "autocenter" ) ) {
2013-12-18 18:11:20 +00:00
$ need_arrange = 0 ;
}
2015-05-25 17:51:47 +00:00
if ( $ scaled_down ) {
Slic3r::GUI:: show_info (
$ self ,
2018-02-22 14:13:07 +00:00
L ( 'Your object appears to be too large, so it was automatically scaled down to fit your print bed.' ) ,
L ( 'Object too large?' ) ,
2015-05-25 17:51:47 +00:00
) ;
}
2012-04-30 22:30:46 +00:00
2015-05-25 17:51:47 +00:00
foreach my $ obj_idx ( @ obj_idx ) {
2014-01-05 13:04:32 +00:00
my $ object = $ self - > { objects } [ $ obj_idx ] ;
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2018-06-04 13:59:55 +00:00
# Add object to list on c++ side
2018-06-14 13:33:42 +00:00
Slic3r::GUI:: add_object_to_list ( $ object - > name , $ model_object ) ;
2012-04-30 12:56:01 +00:00
2018-07-25 07:42:03 +00:00
# $self->reset_thumbnail($obj_idx);
2014-01-05 13:04:32 +00:00
}
2015-05-25 17:51:47 +00:00
$ self - > arrange if $ need_arrange ;
2013-12-18 17:54:11 +00:00
$ self - > update ;
2014-12-16 00:12:37 +00:00
# zoom to objects
2018-05-24 14:11:34 +00:00
Slic3r::GUI::_3DScene:: zoom_to_volumes ( $ self - > { canvas3D } ) if $ self - > { canvas3D } ;
2014-12-16 00:12:37 +00:00
2012-04-30 12:56:01 +00:00
$ self - > object_list_changed ;
2014-06-13 09:19:53 +00:00
2014-06-13 18:36:45 +00:00
$ self - > schedule_background_process ;
2016-12-17 20:47:45 +00:00
return @ obj_idx ;
2012-04-30 12:56:01 +00:00
}
2018-10-09 07:35:19 +00:00
# XXX: Removed, replaced with bed_shape_bb()
2014-06-16 21:58:45 +00:00
sub bed_centerf {
my ( $ self ) = @ _ ;
my $ bed_shape = Slic3r::Polygon - > new_scale ( @ { $ self - > { config } - > bed_shape } ) ;
my $ bed_center = $ bed_shape - > bounding_box - > center ;
return Slic3r::Pointf - > new ( unscale ( $ bed_center - > x ) , unscale ( $ bed_center - > y ) ) ; #)
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2012-04-30 12:56:01 +00:00
sub remove {
2018-03-23 10:41:20 +00:00
my ( $ self , $ obj_idx ) = @ _ ;
2012-04-30 12:56:01 +00:00
2014-06-14 18:26:53 +00:00
$ self - > stop_background_process ;
2014-12-07 19:23:00 +00:00
# Prevent toolpaths preview from rendering while we modify the Print object
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_enabled ( 0 ) if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->enabled(0) if $self->{preview3D};
2014-12-07 19:23:00 +00:00
2018-03-23 10:41:20 +00:00
# If no object index is supplied, remove the selected one.
2017-07-21 14:29:40 +00:00
if ( ! defined $ obj_idx ) {
2012-08-29 17:37:27 +00:00
( $ obj_idx , undef ) = $ self - > selected_object ;
2017-07-21 14:29:40 +00:00
return if ! defined $ obj_idx ;
2012-04-30 12:56:01 +00:00
}
2012-08-29 17:37:27 +00:00
splice @ { $ self - > { objects } } , $ obj_idx , 1 ;
2013-12-12 19:19:33 +00:00
$ self - > { model } - > delete_object ( $ obj_idx ) ;
2013-12-15 15:17:12 +00:00
$ self - > { print } - > delete_object ( $ obj_idx ) ;
2018-06-04 13:59:55 +00:00
# Delete object from list on c++ side
Slic3r::GUI:: delete_object_from_list ( ) ;
2012-04-30 12:56:01 +00:00
$ self - > object_list_changed ;
2013-12-12 19:19:33 +00:00
$ self - > select_object ( undef ) ;
2013-12-18 17:54:11 +00:00
$ self - > update ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2012-04-30 12:56:01 +00:00
sub reset {
2018-03-23 10:41:20 +00:00
my ( $ self ) = @ _ ;
2012-04-30 12:56:01 +00:00
2014-06-14 18:26:53 +00:00
$ self - > stop_background_process ;
2014-12-07 19:23:00 +00:00
# Prevent toolpaths preview from rendering while we modify the Print object
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_enabled ( 0 ) if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->enabled(0) if $self->{preview3D};
2014-12-07 19:23:00 +00:00
2012-08-29 17:37:27 +00:00
@ { $ self - > { objects } } = ( ) ;
2014-05-06 22:58:29 +00:00
$ self - > { model } - > clear_objects ;
$ self - > { print } - > clear_objects ;
2018-06-04 13:59:55 +00:00
# Delete all objects from list on c++ side
Slic3r::GUI:: delete_all_objects_from_list ( ) ;
2012-04-30 12:56:01 +00:00
$ self - > object_list_changed ;
2013-12-12 19:19:33 +00:00
$ self - > select_object ( undef ) ;
2014-07-14 09:58:00 +00:00
$ self - > update ;
2012-04-30 12:56:01 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: VK: done
2012-04-30 12:56:01 +00:00
sub increase {
2015-01-14 22:19:13 +00:00
my ( $ self , $ copies ) = @ _ ;
$ copies // = 1 ;
2012-08-29 17:37:27 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
2017-08-14 10:50:35 +00:00
return if ! defined $ obj_idx ;
2013-12-12 19:19:33 +00:00
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2015-01-14 22:19:13 +00:00
my $ instance = $ model_object - > instances - > [ - 1 ] ;
2018-03-23 10:41:20 +00:00
$ self - > stop_background_process ;
2015-01-14 22:19:13 +00:00
for my $ i ( 1 .. $ copies ) {
$ instance = $ model_object - > add_instance (
offset = > Slic3r::Pointf - > new ( map 10 + $ _ , @ { $ instance - > offset } ) ,
scaling_factor = > $ instance - > scaling_factor ,
rotation = > $ instance - > rotation ,
) ;
$ self - > { print } - > objects - > [ $ obj_idx ] - > add_copy ( $ instance - > offset ) ;
}
2018-09-12 09:59:02 +00:00
# Set count of object on c++ side
2018-06-05 11:17:24 +00:00
Slic3r::GUI:: set_object_count ( $ obj_idx , $ model_object - > instances_count ) ;
2013-12-18 18:11:20 +00:00
# only autoarrange if user has autocentering enabled
2014-09-21 08:56:51 +00:00
$ self - > stop_background_process ;
2017-11-02 15:21:34 +00:00
if ( wxTheApp - > { app_config } - > get ( "autocenter" ) ) {
2013-12-18 18:11:20 +00:00
$ self - > arrange ;
} else {
2014-07-13 10:10:34 +00:00
$ self - > update ;
2013-12-18 18:11:20 +00:00
}
2018-07-27 12:38:19 +00:00
$ self - > selection_changed ; # refresh info (size, volume etc.)
2014-09-21 08:56:51 +00:00
$ self - > schedule_background_process ;
2012-04-30 12:56:01 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: VK: done
2012-04-30 12:56:01 +00:00
sub decrease {
2017-06-06 13:38:27 +00:00
my ( $ self , $ copies_asked ) = @ _ ;
my $ copies = $ copies_asked // 1 ;
2017-08-14 10:50:35 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
return if ! defined $ obj_idx ;
2013-12-12 19:19:33 +00:00
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2015-01-14 22:19:13 +00:00
if ( $ model_object - > instances_count > $ copies ) {
2018-03-23 10:41:20 +00:00
$ self - > stop_background_process ;
2015-01-14 22:19:13 +00:00
for my $ i ( 1 .. $ copies ) {
$ model_object - > delete_last_instance ;
$ self - > { print } - > objects - > [ $ obj_idx ] - > delete_last_copy ;
}
2018-06-05 11:17:24 +00:00
# Set conut of object on c++ side
Slic3r::GUI:: set_object_count ( $ obj_idx , $ model_object - > instances_count ) ;
2017-06-06 13:38:27 +00:00
} elsif ( defined $ copies_asked ) {
# The "decrease" came from the "set number of copies" dialog.
2018-03-23 10:41:20 +00:00
$ self - > stop_background_process ;
2012-09-12 14:30:44 +00:00
$ self - > remove ;
2017-06-06 13:38:27 +00:00
} else {
# The "decrease" came from the "-" button. Don't allow the object to disappear.
return ;
2012-09-12 14:30:44 +00:00
}
2018-06-07 09:12:09 +00:00
2013-12-18 17:54:11 +00:00
$ self - > update ;
2012-04-30 12:56:01 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: VK: done
2015-01-14 22:19:13 +00:00
sub set_number_of_copies {
my ( $ self ) = @ _ ;
# get current number of copies
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
2018-03-23 10:41:20 +00:00
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2015-01-14 22:19:13 +00:00
# prompt user
2018-08-24 14:52:06 +00:00
my $ copies = - 1 ;
$ copies = Wx:: GetNumberFromUser ( "" , L ( "Enter the number of copies of the selected object:" ) , L ( "Copies" ) , $ model_object - > instances_count , 0 , 1000 , $ self ) ;
2015-01-14 22:19:13 +00:00
my $ diff = $ copies - $ model_object - > instances_count ;
2018-08-24 14:52:06 +00:00
if ( $ diff == 0 || $ copies == - 1 ) {
2015-01-14 22:19:13 +00:00
# no variation
} elsif ( $ diff > 0 ) {
$ self - > increase ( $ diff ) ;
} elsif ( $ diff < 0 ) {
$ self - > decrease ( - $ diff ) ;
}
}
2018-10-11 08:03:38 +00:00
# XXX: VK: removed
sub _get_number_from_user {
2017-03-23 13:32:19 +00:00
my ( $ self , $ title , $ prompt_message , $ error_message , $ default , $ only_positive ) = @ _ ;
for ( ; ; ) {
my $ value = Wx:: GetTextFromUser ( $ prompt_message , $ title , $ default , $ self ) ;
# Accept both dashes and dots as a decimal separator.
$ value =~ s/,/./ ;
# If scaling value is being entered, remove the trailing percent sign.
$ value =~ s/%$// if $ only_positive ;
# User canceled the selection, return undef.
return if $ value eq '' ;
# Validate a numeric value.
return $ value if ( $ value =~ /^-?\d*(?:\.\d*)?$/ ) && ( ! $ only_positive || $ value > 0 ) ;
Wx:: MessageBox (
$ error_message .
( ( $ only_positive && $ value <= 0 ) ?
2018-02-22 14:13:07 +00:00
": " . $ value . L ( "\nNon-positive value." ) :
": " . $ value . L ( "\nNot a numeric value." ) ) ,
L ( "Slic3r Error" ) , wxOK | wxICON_EXCLAMATION , $ self ) ;
2017-03-23 13:32:19 +00:00
$ default = $ value ;
}
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2012-04-30 12:56:01 +00:00
sub rotate {
2018-08-21 13:40:11 +00:00
my ( $ self , $ angle , $ axis , $ relative_key , $ axis_x , $ axis_y , $ axis_z ) = @ _ ;
2017-03-23 10:53:59 +00:00
$ relative_key // = 'absolute' ; # relative or absolute coordinates
2018-08-21 13:40:11 +00:00
$ axis_x // = 0 ;
$ axis_y // = 0 ;
$ axis_z // = 0 ;
2017-03-23 10:53:59 +00:00
my $ relative = $ relative_key eq 'relative' ;
2018-08-21 13:40:11 +00:00
2012-08-29 17:37:27 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
2014-06-14 18:52:21 +00:00
return if ! defined $ obj_idx ;
2018-08-21 13:40:11 +00:00
2013-12-12 19:19:33 +00:00
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
my $ model_instance = $ model_object - > instances - > [ 0 ] ;
2018-08-21 13:40:11 +00:00
2012-04-30 20:14:27 +00:00
if ( ! defined $ angle ) {
2014-06-14 18:52:21 +00:00
my $ axis_name = $ axis == X ? 'X' : $ axis == Y ? 'Y' : 'Z' ;
2016-12-16 23:26:57 +00:00
my $ default = $ axis == Z ? rad2deg ( $ model_instance - > rotation ) : 0 ;
2018-02-23 08:16:35 +00:00
$ angle = $ self - > _get_number_from_user ( L ( "Enter the rotation angle:" ) , L ( "Rotate around " ) . $ axis_name . ( " axis" ) , L ( "Invalid rotation angle entered" ) , $ default ) ;
2017-03-23 13:32:19 +00:00
return if $ angle eq '' ;
2012-04-30 20:14:27 +00:00
}
2018-08-21 13:40:11 +00:00
# Let's calculate vector of rotation axis (if we don't have it already)
if ( defined $ axis ) {
if ( $ axis == X ) {
2018-09-04 12:42:14 +00:00
$ axis_x = 1 ;
2018-08-21 13:40:11 +00:00
}
if ( $ axis == Y ) {
2018-09-04 12:42:14 +00:00
$ axis_y = 1 ;
2018-08-21 13:40:11 +00:00
}
}
2012-04-30 20:14:27 +00:00
2014-07-01 14:40:56 +00:00
$ self - > stop_background_process ;
2018-08-21 13:40:11 +00:00
if ( defined $ axis && $ axis == Z ) {
2016-12-16 23:26:57 +00:00
my $ new_angle = deg2rad ( $ angle ) ;
2018-06-19 07:46:26 +00:00
foreach my $ inst ( @ { $ model_object - > instances } ) {
my $ rotation = ( $ relative ? $ inst - > rotation : 0 . ) + $ new_angle ;
while ( $ rotation > 2.0 * PI ) {
$ rotation -= 2.0 * PI ;
}
while ( $ rotation < 0.0 ) {
$ rotation += 2.0 * PI ;
}
$ inst - > set_rotation ( $ rotation ) ;
Slic3r::GUI::_3DScene:: update_gizmos_data ( $ self - > { canvas3D } ) if ( $ self - > { canvas3D } ) ;
}
2018-07-25 07:42:03 +00:00
# $object->transform_thumbnail($self->{model}, $obj_idx);
2014-07-01 14:40:56 +00:00
} else {
2018-08-21 13:40:11 +00:00
if ( defined $ axis ) {
# rotation around X and Y needs to be performed on mesh
# so we first apply any Z rotation
if ( $ model_instance - > rotation != 0 ) {
$ model_object - > rotate ( $ model_instance - > rotation , Slic3r::Pointf3 - > new ( 0 , 0 , - 1 ) ) ;
$ _ - > set_rotation ( 0 ) for @ { $ model_object - > instances } ;
}
2014-06-14 18:52:21 +00:00
}
2018-08-21 13:40:11 +00:00
$ model_object - > rotate ( deg2rad ( $ angle ) , Slic3r::Pointf3 - > new ( $ axis_x , $ axis_y , $ axis_z ) ) ;
2015-01-08 23:47:40 +00:00
2018-07-25 07:42:03 +00:00
# # realign object to Z = 0
# $model_object->center_around_origin;
# $self->reset_thumbnail($obj_idx);
2013-12-12 19:19:33 +00:00
}
2018-09-05 14:22:48 +00:00
2014-07-01 14:40:56 +00:00
# update print and start background processing
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
2013-12-12 19:19:33 +00:00
$ self - > selection_changed ; # refresh info (size etc.)
2013-12-18 17:54:11 +00:00
$ self - > update ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2015-11-04 22:11:30 +00:00
sub mirror {
2014-06-14 19:14:33 +00:00
my ( $ self , $ axis ) = @ _ ;
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 ] ;
2015-11-04 22:11:30 +00:00
# apply Z rotation before mirroring
2014-06-14 19:14:33 +00:00
if ( $ model_instance - > rotation != 0 ) {
2018-08-21 13:40:11 +00:00
$ model_object - > rotate ( $ model_instance - > rotation , Slic3r::Pointf3 - > new ( 0 , 0 , 1 ) ) ;
2014-06-14 19:14:33 +00:00
$ _ - > set_rotation ( 0 ) for @ { $ model_object - > instances } ;
}
2015-11-04 22:11:30 +00:00
$ model_object - > mirror ( $ axis ) ;
2015-01-08 23:47:40 +00:00
2018-07-25 07:42:03 +00:00
# # realign object to Z = 0
# $model_object->center_around_origin;
# $self->reset_thumbnail($obj_idx);
2014-06-14 19:14:33 +00:00
# update print and start background processing
$ self - > stop_background_process ;
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
$ self - > selection_changed ; # refresh info (size etc.)
$ self - > update ;
}
2018-10-09 07:35:19 +00:00
# XXX: not done, renamed as Plater::priv::scale()
2012-04-30 12:56:01 +00:00
sub changescale {
2015-12-05 18:37:57 +00:00
my ( $ self , $ axis , $ tosize ) = @ _ ;
2012-04-30 12:56:01 +00:00
2012-08-29 17:37:27 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
2014-06-16 22:50:44 +00:00
return if ! defined $ obj_idx ;
2013-12-12 19:19:33 +00:00
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
my $ model_instance = $ model_object - > instances - > [ 0 ] ;
2012-08-29 17:37:27 +00:00
2018-08-17 08:12:43 +00:00
my $ object_size = $ model_object - > instance_bounding_box ( 0 ) - > size ;
2015-12-05 18:37:57 +00:00
2014-06-16 22:50:44 +00:00
if ( defined $ axis ) {
my $ axis_name = $ axis == X ? 'X' : $ axis == Y ? 'Y' : 'Z' ;
2015-12-05 18:37:57 +00:00
my $ scale ;
if ( $ tosize ) {
my $ cursize = $ object_size - > [ $ axis ] ;
2017-03-23 13:32:19 +00:00
my $ newsize = $ self - > _get_number_from_user (
2018-08-17 08:12:43 +00:00
L ( 'Enter the new size for the selected object:' ) ,
2018-02-22 14:13:07 +00:00
L ( "Scale along " ) . $ axis_name , L ( 'Invalid scaling value entered' ) , $ cursize , 1 ) ;
2017-03-23 13:32:19 +00:00
return if $ newsize eq '' ;
2015-12-05 18:37:57 +00:00
$ scale = $ newsize / $ cursize * 100 ;
} else {
2018-02-23 08:16:35 +00:00
$ scale = $ self - > _get_number_from_user ( L ( 'Enter the scale % for the selected object:' ) , L ( "Scale along " ) . $ axis_name , L ( 'Invalid scaling value entered' ) , 100 , 1 ) ;
2017-03-23 13:32:19 +00:00
return if $ scale eq '' ;
2015-12-05 18:37:57 +00:00
}
2014-06-16 22:50:44 +00:00
# apply Z rotation before scaling
if ( $ model_instance - > rotation != 0 ) {
2018-08-21 13:40:11 +00:00
$ model_object - > rotate ( $ model_instance - > rotation , Slic3r::Pointf3 - > new ( 0 , 0 , 1 ) ) ;
2014-06-16 22:50:44 +00:00
$ _ - > set_rotation ( 0 ) for @ { $ model_object - > instances } ;
}
my $ versor = [ 1 , 1 , 1 ] ;
$ versor - > [ $ axis ] = $ scale / 100 ;
2014-09-21 08:51:36 +00:00
$ model_object - > scale_xyz ( Slic3r::Pointf3 - > new ( @$ versor ) ) ;
2017-02-28 09:29:52 +00:00
#FIXME Scale the layer height profile when $axis == Z?
#FIXME Scale the layer height ranges $axis == Z?
2015-01-08 23:47:40 +00:00
# object was already aligned to Z = 0, so no need to realign it
2018-07-25 07:42:03 +00:00
# $self->reset_thumbnail($obj_idx);
2014-06-16 22:50:44 +00:00
} else {
2015-12-05 18:37:57 +00:00
my $ scale ;
if ( $ tosize ) {
my $ cursize = max ( @$ object_size ) ;
2018-02-22 14:13:07 +00:00
my $ newsize = $ self - > _get_number_from_user ( L ( 'Enter the new max size for the selected object:' ) , L ( 'Scale' ) , L ( 'Invalid scaling value entered' ) , $ cursize , 1 ) ;
2017-07-21 14:29:40 +00:00
return if ! defined ( $ newsize ) || $ newsize eq '' ;
2017-03-23 13:32:19 +00:00
$ scale = $ model_instance - > scaling_factor * $ newsize / $ cursize * 100 ;
2015-12-05 18:37:57 +00:00
} else {
# max scale factor should be above 2540 to allow importing files exported in inches
2018-02-22 14:13:07 +00:00
$ scale = $ self - > _get_number_from_user ( L ( 'Enter the scale % for the selected object:' ) , L ( 'Scale' ) , L ( 'Invalid scaling value entered' ) , $ model_instance - > scaling_factor * 100 , 1 ) ;
2017-07-21 14:29:40 +00:00
return if ! defined ( $ scale ) || $ scale eq '' ;
2015-12-05 18:37:57 +00:00
}
2018-06-07 09:12:09 +00:00
2018-06-05 11:17:24 +00:00
# Set object scale on c++ side
2018-08-29 11:11:30 +00:00
# Slic3r::GUI::set_object_scale($obj_idx, $scale);
2014-06-16 22:50:44 +00:00
$ scale /= 100 ; # turn percent into factor
2013-12-12 19:19:33 +00:00
my $ variation = $ scale / $ model_instance - > scaling_factor ;
2017-02-28 09:29:52 +00:00
#FIXME Scale the layer height profile?
2013-12-12 19:19:33 +00:00
foreach my $ range ( @ { $ model_object - > layer_height_ranges } ) {
$ range - > [ 0 ] *= $ variation ;
$ range - > [ 1 ] *= $ variation ;
}
2014-04-29 23:04:49 +00:00
$ _ - > set_scaling_factor ( $ scale ) for @ { $ model_object - > instances } ;
2018-07-25 07:42:03 +00:00
# $object->transform_thumbnail($self->{model}, $obj_idx);
2013-12-12 19:19:33 +00:00
}
2014-06-16 22:50:44 +00:00
# update print and start background processing
$ self - > stop_background_process ;
$ self - > { print } - > add_model_object ( $ model_object , $ obj_idx ) ;
2013-08-25 10:22:05 +00:00
$ self - > selection_changed ( 1 ) ; # refresh info (size, volume etc.)
2013-12-18 18:11:20 +00:00
$ self - > update ;
2012-08-29 17:37:27 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: VK: WIP
2012-08-29 17:37:27 +00:00
sub arrange {
2018-03-23 10:41:20 +00:00
my ( $ self ) = @ _ ;
2014-11-12 23:23:31 +00:00
2018-03-23 10:41:20 +00:00
$ self - > stop_background_process ;
2018-06-28 17:16:36 +00:00
# my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape);
# my $success = $self->{model}->arrange_objects(wxTheApp->{preset_bundle}->full_config->min_object_distance, $bb);
2018-06-29 15:46:21 +00:00
# Update is not implemented in C++ so we cannot call this for now
2018-06-28 17:16:36 +00:00
$ self - > { appController } - > arrange_model ;
2013-12-23 23:30:51 +00:00
# ignore arrange failures on purpose: user has visual feedback and we don't need to warn him
# when parts don't fit in print bed
2012-04-30 12:56:01 +00:00
2017-06-13 09:35:24 +00:00
# Force auto center of the aligned grid of of objects on the print bed.
2018-06-29 15:46:21 +00:00
$ self - > update ( 0 ) ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2012-04-30 22:30:46 +00:00
sub split_object {
my $ self = shift ;
2013-12-12 19:19:33 +00:00
my ( $ obj_idx , $ current_object ) = $ self - > selected_object ;
2014-11-30 19:53:53 +00:00
# we clone model object because split_object() adds the split volumes
2014-12-30 12:16:28 +00:00
# into the same model object, thus causing duplicates when we call load_model_objects()
my $ new_model = $ self - > { model } - > clone ; # store this before calling get_object()
my $ current_model_object = $ new_model - > get_object ( $ obj_idx ) ;
2012-10-21 18:56:19 +00:00
2014-12-30 12:16:28 +00:00
if ( $ current_model_object - > volumes_count > 1 ) {
2018-02-22 14:13:07 +00:00
Slic3r::GUI:: warning_catcher ( $ self ) - > ( L ( "The selected object can't be split because it contains more than one volume/material." ) ) ;
2012-10-21 18:56:19 +00:00
return ;
}
2018-03-23 10:41:20 +00:00
$ self - > stop_background_process ;
2014-11-12 21:36:03 +00:00
my @ model_objects = @ { $ current_model_object - > split_object } ;
if ( @ model_objects == 1 ) {
2018-02-22 14:13:07 +00:00
Slic3r::GUI:: warning_catcher ( $ self ) - > ( L ( "The selected object couldn't be split because it contains only one part." ) ) ;
2018-03-23 10:41:20 +00:00
$ self - > schedule_background_process ;
} else {
$ _ - > center_around_origin for ( @ model_objects ) ;
$ self - > remove ( $ obj_idx ) ;
$ current_object = $ obj_idx = undef ;
# load all model objects at once, otherwise the plate would be rearranged after each one
# causing original positions not to be kept
$ self - > load_model_objects ( @ model_objects ) ;
2012-06-06 17:00:34 +00:00
}
2012-04-30 22:30:46 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2018-03-23 10:41:20 +00:00
# Trigger $self->async_apply_config() after 500ms.
# The call is delayed to avoid restarting the background processing during typing into an edit field.
2014-06-13 18:36:45 +00:00
sub schedule_background_process {
my ( $ self ) = @ _ ;
2018-03-23 10:41:20 +00:00
$ self - > { apply_config_timer } - > Start ( 0.5 * 1000 , 1 ) ; # 1 = one shot, every half a second.
2014-06-13 18:36:45 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2016-09-13 09:24:55 +00:00
# Executed asynchronously by a timer every PROCESS_DELAY (0.5 second).
# The timer is started by schedule_background_process(),
2014-06-13 17:23:51 +00:00
sub async_apply_config {
2014-06-13 13:54:13 +00:00
my ( $ self ) = @ _ ;
2018-03-23 10:41:20 +00:00
# Apply new config to the possibly running background task.
my $ was_running = $ self - > { background_slicing_process } - > running ;
my $ invalidated = $ self - > { background_slicing_process } - > apply_config ( wxTheApp - > { preset_bundle } - > full_config ) ;
# Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
2018-05-25 12:05:08 +00:00
$ self - > { canvas3D } - > Refresh if Slic3r::GUI::_3DScene:: is_layers_editing_enabled ( $ self - > { canvas3D } ) ;
2018-03-23 10:41:20 +00:00
# If the apply_config caused the calculation to stop, or it was not running yet:
2017-05-31 15:05:11 +00:00
if ( $ invalidated ) {
2018-03-23 10:41:20 +00:00
if ( $ was_running ) {
# Hide the slicing results if the current slicing status is no more valid.
2018-09-12 09:59:02 +00:00
$ self - > print_info_box_show ( 0 )
2018-03-23 10:41:20 +00:00
}
if ( wxTheApp - > { app_config } - > get ( "background_processing" ) ) {
$ self - > { background_slicing_process } - > start ;
}
if ( $ was_running ) {
# Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
# Otherwise they will be just refreshed.
$ self - > { gcode_preview_data } - > reset ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > reload_print if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->reload_print if $self->{preview3D};
2018-09-12 09:59:02 +00:00
# We also need to reload 3D scene because of the wipe tower preview box
if ( $ self - > { config } - > wipe_tower ) {
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 1 ) if $ self - > { canvas3D }
}
2018-03-23 10:41:20 +00:00
}
2017-05-31 15:05:11 +00:00
}
2014-06-13 13:54:13 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2018-03-23 10:41:20 +00:00
# Background processing is started either by the "Slice now" button, by the "Export G-code button" or by async_apply_config().
2014-06-13 09:19:53 +00:00
sub start_background_process {
my ( $ self ) = @ _ ;
2018-03-23 10:41:20 +00:00
return if ! @ { $ self - > { objects } } || $ self - > { background_slicing_process } - > running ;
# Don't start process thread if config is not valid.
2014-06-13 09:19:53 +00:00
eval {
# this will throw errors if config is not valid
2017-10-25 10:53:31 +00:00
wxTheApp - > { preset_bundle } - > full_config - > validate ;
2014-06-13 09:19:53 +00:00
$ self - > { print } - > validate ;
} ;
2014-11-30 23:15:45 +00:00
if ( $@ ) {
$ self - > statusbar - > SetStatusText ( $@ ) ;
return ;
2018-03-23 10:41:20 +00:00
}
2017-11-02 15:21:34 +00:00
# Copy the names of active presets into the placeholder parser.
wxTheApp - > { preset_bundle } - > export_selections_pp ( $ self - > { print } - > placeholder_parser ) ;
2018-03-23 10:41:20 +00:00
# Start the background process.
$ self - > { background_slicing_process } - > start ;
2014-06-13 09:19:53 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2018-03-23 10:41:20 +00:00
# Stop the background processing
2014-06-13 09:19:53 +00:00
sub stop_background_process {
my ( $ self ) = @ _ ;
2018-09-14 07:28:00 +00:00
$ self - > { background_slicing_process } - > stop ( ) ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > reload_print if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->reload_print if $self->{preview3D};
2014-07-12 09:52:19 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2018-03-23 10:41:20 +00:00
# Called by the "Slice now" button, which is visible only if the background processing is disabled.
2016-10-25 11:24:42 +00:00
sub reslice {
# explicitly cancel a previous thread and start a new one.
my ( $ self ) = @ _ ;
# Don't reslice if export of G-code or sending to OctoPrint is running.
2017-11-02 15:21:34 +00:00
if ( ! defined ( $ self - > { export_gcode_output_file } ) && ! defined ( $ self - > { send_gcode_file } ) ) {
2017-02-09 13:56:13 +00:00
# Stop the background processing threads, stop the async update timer.
2016-10-25 11:24:42 +00:00
$ self - > stop_background_process ;
2017-02-09 13:56:13 +00:00
# Rather perform one additional unnecessary update of the print object instead of skipping a pending async update.
$ self - > async_apply_config ;
2016-10-25 11:24:42 +00:00
$ self - > statusbar - > SetCancelCallback ( sub {
$ self - > stop_background_process ;
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "Slicing cancelled" ) ) ;
2016-10-25 11:24:42 +00:00
# this updates buttons status
$ self - > object_list_changed ;
} ) ;
$ self - > start_background_process ;
}
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2012-04-30 12:56:01 +00:00
sub export_gcode {
2014-12-28 00:30:05 +00:00
my ( $ self , $ output_file ) = @ _ ;
2012-04-30 12:56:01 +00:00
2014-06-14 20:40:37 +00:00
return if ! @ { $ self - > { objects } } ;
2014-06-13 09:19:53 +00:00
if ( $ self - > { export_gcode_output_file } ) {
2018-02-22 14:13:07 +00:00
Wx::MessageDialog - > new ( $ self , L ( "Another export job is currently running." ) , L ( 'Error' ) , wxOK | wxICON_ERROR ) - > ShowModal ;
2012-05-05 19:08:15 +00:00
return ;
}
2014-06-13 12:27:55 +00:00
# if process is not running, validate config
# (we assume that if it is running, config is valid)
eval {
# this will throw errors if config is not valid
2017-10-25 10:53:31 +00:00
wxTheApp - > { preset_bundle } - > full_config - > validate ;
2014-06-13 12:27:55 +00:00
$ self - > { print } - > validate ;
} ;
Slic3r::GUI:: catch_error ( $ self ) and return ;
2014-03-16 23:39:07 +00:00
# apply config and validate print
2017-10-25 10:53:31 +00:00
my $ config = wxTheApp - > { preset_bundle } - > full_config ;
2014-03-16 23:39:07 +00:00
eval {
# this will throw errors if config is not valid
$ config - > validate ;
2018-09-14 07:28:00 +00:00
#FIXME it shall use the background processing!
2014-03-16 23:39:07 +00:00
$ self - > { print } - > apply_config ( $ config ) ;
$ self - > { print } - > validate ;
} ;
2017-11-02 15:21:34 +00:00
Slic3r::GUI:: catch_error ( $ self ) and return ;
2012-08-01 14:06:03 +00:00
2018-05-16 10:16:30 +00:00
# Copy the names of active presets into the placeholder parser.
wxTheApp - > { preset_bundle } - > export_selections_pp ( $ self - > { print } - > placeholder_parser ) ;
2012-05-05 19:08:15 +00:00
# select output file
2014-12-28 00:30:05 +00:00
if ( $ output_file ) {
2017-12-05 14:54:24 +00:00
$ self - > { export_gcode_output_file } = eval { $ self - > { print } - > output_filepath ( $ output_file ) } ;
Slic3r::GUI:: catch_error ( $ self ) and return ;
2014-12-28 00:30:05 +00:00
} else {
2017-12-05 14:54:24 +00:00
my $ default_output_file = eval { $ self - > { print } - > output_filepath ( $ main:: opt { output } // '' ) } ;
Slic3r::GUI:: catch_error ( $ self ) and return ;
2018-03-16 17:20:47 +00:00
# If possible, remove accents from accented latin characters.
# This function is useful for generating file names to be processed by legacy firmwares.
$ default_output_file = Slic3r::GUI:: fold_utf8_to_ascii ( $ default_output_file ) ;
2018-02-22 14:13:07 +00:00
my $ dlg = Wx::FileDialog - > new ( $ self , L ( 'Save G-code file as:' ) ,
2017-11-02 15:21:34 +00:00
wxTheApp - > { app_config } - > get_last_output_dir ( dirname ( $ default_output_file ) ) ,
2015-06-03 11:19:43 +00:00
basename ( $ default_output_file ) , & Slic3r::GUI::FILE_WILDCARDS - > { gcode } , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
2012-05-05 19:08:15 +00:00
if ( $ dlg - > ShowModal != wxID_OK ) {
$ dlg - > Destroy ;
return ;
}
2017-08-03 15:31:31 +00:00
my $ path = $ dlg - > GetPath ;
2017-11-02 15:21:34 +00:00
wxTheApp - > { app_config } - > update_last_output_dir ( dirname ( $ path ) ) ;
2015-06-02 20:27:11 +00:00
$ self - > { export_gcode_output_file } = $ path ;
2012-05-05 19:08:15 +00:00
$ dlg - > Destroy ;
}
$ self - > statusbar - > StartBusy ;
2013-05-20 08:57:27 +00:00
2017-11-02 15:21:34 +00:00
$ self - > statusbar - > SetCancelCallback ( sub {
$ self - > stop_background_process ;
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "Export cancelled" ) ) ;
2017-11-02 15:21:34 +00:00
$ self - > { export_gcode_output_file } = undef ;
$ self - > { send_gcode_file } = undef ;
2014-06-13 12:27:55 +00:00
2017-11-02 15:21:34 +00:00
# this updates buttons status
$ self - > object_list_changed ;
} ) ;
2018-09-14 07:28:00 +00:00
$ self - > { background_slicing_process } - > set_output_path ( $ self - > { export_gcode_output_file } ) ;
2017-11-02 15:21:34 +00:00
# start background process, whose completion event handler
# will detect $self->{export_gcode_output_file} and proceed with export
$ self - > start_background_process ;
2014-12-28 00:30:05 +00:00
2015-01-04 18:29:34 +00:00
# this updates buttons status
$ self - > object_list_changed ;
2014-12-28 00:30:05 +00:00
return $ self - > { export_gcode_output_file } ;
2012-05-05 19:08:15 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2018-03-23 10:41:20 +00:00
# This message should be called by the background process synchronously.
sub on_update_print_preview {
my ( $ self ) = @ _ ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > reload_print if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->reload_print if $self->{preview3D};
2018-07-27 13:56:27 +00:00
# in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth:
2018-08-17 07:16:34 +00:00
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
2018-07-27 13:56:27 +00:00
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 1 ) ;
2014-06-13 12:27:55 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2014-06-13 12:27:55 +00:00
# This gets called also if we have no threads.
sub on_progress_event {
my ( $ self , $ percent , $ message ) = @ _ ;
$ self - > statusbar - > SetProgress ( $ percent ) ;
2018-08-30 09:40:06 +00:00
# TODO: three dot character is not properly translated into C++
# $self->statusbar->SetStatusText("$message…");
$ self - > statusbar - > SetStatusText ( "$message..." ) ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2016-10-25 11:24:42 +00:00
# Called when the G-code export finishes, either successfully or with an error.
2014-06-13 12:27:55 +00:00
# This gets called also if we don't have threads.
2018-03-23 10:41:20 +00:00
sub on_process_completed {
2014-06-13 12:27:55 +00:00
my ( $ self , $ result ) = @ _ ;
2018-03-28 15:05:31 +00:00
# Stop the background task, wait until the thread goes into the "Idle" state.
# At this point of time the thread should be either finished or canceled,
# so the following call just confirms, that the produced data were consumed.
$ self - > { background_slicing_process } - > stop ;
2018-09-14 08:59:50 +00:00
$ self - > statusbar - > ResetCancelCallback ( ) ;
2012-05-05 19:08:15 +00:00
$ self - > statusbar - > StopBusy ;
2014-06-13 12:27:55 +00:00
$ self - > statusbar - > SetStatusText ( "" ) ;
2012-05-19 19:13:10 +00:00
2014-06-13 12:27:55 +00:00
my $ message ;
2014-12-28 00:30:05 +00:00
my $ send_gcode = 0 ;
2015-01-03 22:25:55 +00:00
my $ do_print = 0 ;
2018-09-14 07:28:00 +00:00
# print "Process completed, message: ", $message, "\n";
if ( defined ( $ result ) ) {
$ message = L ( "Export failed" ) ;
} else {
2016-10-25 11:24:42 +00:00
# G-code file exported successfully.
2015-01-03 22:25:55 +00:00
if ( $ self - > { print_file } ) {
2018-02-22 14:13:07 +00:00
$ message = L ( "File added to print queue" ) ;
2015-01-03 22:25:55 +00:00
$ do_print = 1 ;
} elsif ( $ self - > { send_gcode_file } ) {
2018-07-08 12:32:48 +00:00
$ message = L ( "Sending G-code file to the Printer Host ..." ) ;
2014-12-28 00:30:05 +00:00
$ send_gcode = 1 ;
2018-09-14 07:28:00 +00:00
} elsif ( defined $ self - > { export_gcode_output_file } ) {
2018-02-22 14:13:07 +00:00
$ message = L ( "G-code file exported to " ) . $ self - > { export_gcode_output_file } ;
2018-09-14 07:28:00 +00:00
} else {
$ message = L ( "Slicing complete" ) ;
2014-12-28 00:30:05 +00:00
}
2014-06-13 12:27:55 +00:00
}
$ self - > { export_gcode_output_file } = undef ;
2014-06-14 17:59:59 +00:00
wxTheApp - > notify ( $ message ) ;
2014-12-28 00:30:05 +00:00
2015-01-03 22:25:55 +00:00
$ self - > do_print if $ do_print ;
2018-02-07 10:37:15 +00:00
2016-10-25 11:24:42 +00:00
# Send $self->{send_gcode_file} to OctoPrint.
2018-02-07 10:37:15 +00:00
if ( $ send_gcode ) {
2018-08-21 09:10:32 +00:00
my $ host = Slic3r::PrintHost:: get_print_host ( $ self - > { config } ) ;
2018-07-08 12:32:48 +00:00
if ( $ host - > send_gcode ( $ self - > { send_gcode_file } ) ) {
2018-09-14 07:28:00 +00:00
$ message = L ( "Upload to host finished." ) ;
2018-04-04 09:18:22 +00:00
} else {
2018-09-14 07:28:00 +00:00
$ message = "" ;
2018-04-04 09:18:22 +00:00
}
2018-02-07 10:37:15 +00:00
}
2018-09-14 07:28:00 +00:00
# As of now, the BackgroundProcessing thread posts status bar update messages to a queue on the MainFrame.pm,
# but the "Processing finished" message is posted to this window.
# Delay the following status bar update, so it will be called later than what is received by MainFrame.pm.
wxTheApp - > CallAfter ( sub {
$ self - > statusbar - > SetStatusText ( $ message ) ;
} ) ;
2015-01-03 22:25:55 +00:00
$ self - > { print_file } = undef ;
2014-12-28 00:30:05 +00:00
$ self - > { send_gcode_file } = undef ;
2018-07-18 12:52:19 +00:00
$ self - > print_info_box_show ( 1 ) ;
2017-02-15 15:02:54 +00:00
2015-01-04 18:29:34 +00:00
# this updates buttons status
$ self - > object_list_changed ;
2018-01-08 12:44:10 +00:00
# refresh preview
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > reload_print if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->reload_print if $self->{preview3D};
2014-12-28 00:30:05 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: partially done in the Sidebar
2018-07-18 12:52:19 +00:00
# Fill in the "Sliced info" box with the result of the G-code generator.
sub print_info_box_show {
my ( $ self , $ show ) = @ _ ;
2018-07-26 10:10:45 +00:00
# my $scrolled_window_panel = $self->{scrolled_window_panel};
# my $scrolled_window_sizer = $self->{scrolled_window_sizer};
2018-08-24 13:01:26 +00:00
# return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show));
2018-09-17 13:12:13 +00:00
my $ panel = $ self - > { scrolled_window_panel } ; #$self->{right_panel};
2018-07-26 10:10:45 +00:00
my $ sizer = $ self - > { info_sizer } ;
2018-09-17 13:12:13 +00:00
# return if (!$sizer || !$show && ($sizer->IsShown(1) == $show));
return if ( ! $ sizer ) ;
2018-07-26 10:10:45 +00:00
Slic3r::GUI:: set_show_print_info ( $ show ) ;
2018-09-17 13:12:13 +00:00
# return if (wxTheApp->{app_config}->get("view_mode") eq "simple");
2018-07-18 12:52:19 +00:00
2018-09-17 13:12:13 +00:00
# if ($show)
{
2018-07-18 12:52:19 +00:00
my $ print_info_sizer = $ self - > { print_info_sizer } ;
$ print_info_sizer - > Clear ( 1 ) ;
my $ grid_sizer = Wx::FlexGridSizer - > new ( 2 , 2 , 5 , 5 ) ;
$ grid_sizer - > SetFlexibleDirection ( wxHORIZONTAL ) ;
$ grid_sizer - > AddGrowableCol ( 1 , 1 ) ;
$ grid_sizer - > AddGrowableCol ( 3 , 1 ) ;
$ print_info_sizer - > Add ( $ grid_sizer , 0 , wxEXPAND ) ;
2018-09-17 13:12:13 +00:00
my $ is_wipe_tower = $ self - > { print } - > total_wipe_tower_filament > 0 ;
2018-07-18 12:52:19 +00:00
my @ info = (
L ( "Used Filament (m)" )
2018-09-17 13:12:13 +00:00
= > $ is_wipe_tower ?
sprintf ( "%.2f (%.2f %s + %.2f %s)" , $ self - > { print } - > total_used_filament / 1000 ,
( $ self - > { print } - > total_used_filament - $ self - > { print } - > total_wipe_tower_filament ) / 1000 ,
L ( "objects" ) ,
$ self - > { print } - > total_wipe_tower_filament / 1000 ,
L ( "wipe tower" ) ) :
sprintf ( "%.2f" , $ self - > { print } - > total_used_filament / 1000 ) ,
2018-07-18 12:52:19 +00:00
L ( "Used Filament (mm³)" )
= > sprintf ( "%.2f" , $ self - > { print } - > total_extruded_volume ) ,
2018-07-19 11:58:25 +00:00
L ( "Used Filament (g)" ) ,
= > sprintf ( "%.2f" , $ self - > { print } - > total_weight ) ,
2018-07-18 12:52:19 +00:00
L ( "Cost" ) ,
2018-09-17 13:12:13 +00:00
= > $ is_wipe_tower ?
sprintf ( "%.2f (%.2f %s + %.2f %s)" , $ self - > { print } - > total_cost ,
( $ self - > { print } - > total_cost - $ self - > { print } - > total_wipe_tower_cost ) ,
L ( "objects" ) ,
$ self - > { print } - > total_wipe_tower_cost ,
L ( "wipe tower" ) ) :
sprintf ( "%.2f" , $ self - > { print } - > total_cost ) ,
2018-07-18 12:52:19 +00:00
L ( "Estimated printing time (normal mode)" )
2018-07-19 11:58:25 +00:00
= > $ self - > { print } - > estimated_normal_print_time ,
2018-07-18 12:52:19 +00:00
L ( "Estimated printing time (silent mode)" )
2018-07-19 11:58:25 +00:00
= > $ self - > { print } - > estimated_silent_print_time
2018-07-18 12:52:19 +00:00
) ;
2018-09-17 13:12:13 +00:00
# if there is a wipe tower, insert number of toolchanges info into the array:
splice ( @ info , 8 , 0 , L ( "Number of tool changes" ) = > sprintf ( "%.d" , $ self - > { print } - > wipe_tower_number_of_toolchanges ) ) if ( $ is_wipe_tower ) ;
2018-07-18 12:52:19 +00:00
while ( my $ label = shift @ info ) {
my $ value = shift @ info ;
next if $ value eq "N/A" ;
2018-07-26 10:10:45 +00:00
# my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
my $ text = Wx::StaticText - > new ( $ panel , - 1 , "$label:" , wxDefaultPosition , wxDefaultSize , wxALIGN_RIGHT ) ;
2018-07-18 12:52:19 +00:00
$ text - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
$ grid_sizer - > Add ( $ text , 0 ) ;
2018-07-26 10:10:45 +00:00
# my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
my $ field = Wx::StaticText - > new ( $ panel , - 1 , $ value , wxDefaultPosition , wxDefaultSize , wxALIGN_LEFT ) ;
2018-07-18 12:52:19 +00:00
$ field - > SetFont ( $ Slic3r:: GUI:: small_font ) ;
$ grid_sizer - > Add ( $ field , 0 ) ;
}
}
2018-07-26 10:10:45 +00:00
# $scrolled_window_sizer->Show(2, $show);
# $scrolled_window_panel->Layout;
2018-09-17 13:12:13 +00:00
$ sizer - > Show ( 1 , $ show && wxTheApp - > { app_config } - > get ( "view_mode" ) ne "simple" ) ;
2018-07-26 10:10:45 +00:00
2018-08-24 14:20:19 +00:00
$ self - > Layout ;
$ panel - > Refresh ;
2018-07-18 12:52:19 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done - to be removed
2015-01-03 22:25:55 +00:00
sub do_print {
my ( $ self ) = @ _ ;
2015-01-04 22:18:23 +00:00
my $ controller = $ self - > GetFrame - > { controller } ;
2017-10-25 10:53:31 +00:00
my $ printer_preset = wxTheApp - > { preset_bundle } - > printer - > get_edited_preset ;
my $ printer_panel = $ controller - > add_printer ( $ printer_preset - > name , $ printer_preset - > config ) ;
2015-01-03 22:25:55 +00:00
my $ filament_stats = $ self - > { print } - > filament_stats ;
2017-12-19 20:12:24 +00:00
my $ filament_names = wxTheApp - > { preset_bundle } - > filament_presets ;
$ filament_stats = { map { $ filament_names - > [ $ _ ] = > $ filament_stats - > { $ _ } } keys %$ filament_stats } ;
2015-01-03 22:25:55 +00:00
$ printer_panel - > load_print_job ( $ self - > { print_file } , $ filament_stats ) ;
2012-05-19 19:13:10 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2012-04-30 15:10:54 +00:00
sub export_stl {
2017-10-27 20:49:59 +00:00
my ( $ self ) = @ _ ;
2014-06-14 20:40:37 +00:00
return if ! @ { $ self - > { objects } } ;
2017-10-27 20:49:59 +00:00
# Ask user for a file name to write into.
2012-08-29 15:11:56 +00:00
my $ output_file = $ self - > _get_export_file ( 'STL' ) or return ;
2017-10-27 20:49:59 +00:00
# Store a binary STL.
2017-08-03 15:31:31 +00:00
$ self - > { model } - > store_stl ( $ output_file , 1 ) ;
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "STL file exported to " ) . $ output_file ) ;
2012-08-29 15:11:56 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2016-12-22 11:13:28 +00:00
sub reload_from_disk {
my ( $ self ) = @ _ ;
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
return if ! defined $ obj_idx ;
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2017-11-30 19:13:05 +00:00
#FIXME convert to local file encoding
2016-12-22 11:13:28 +00:00
return if ! $ model_object - > input_file
2018-07-24 07:23:19 +00:00
|| ! - e Slic3r:: encode_path ( $ model_object - > input_file ) ;
2016-12-22 11:13:28 +00:00
2017-07-11 11:55:55 +00:00
my @ new_obj_idx = $ self - > load_files ( [ $ model_object - > input_file ] ) ;
2016-12-22 11:13:28 +00:00
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 } ;
2017-11-30 19:13:05 +00:00
#$o->invalidate_bounding_box;
2016-12-22 11:13:28 +00:00
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 ) ;
}
}
2017-11-30 19:13:05 +00:00
#FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
2016-12-22 11:13:28 +00:00
}
$ self - > remove ( $ obj_idx ) ;
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2015-01-03 14:48:53 +00:00
sub export_object_stl {
2017-10-27 20:49:59 +00:00
my ( $ self ) = @ _ ;
2015-01-03 14:48:53 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
return if ! defined $ obj_idx ;
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2017-10-27 20:49:59 +00:00
# Ask user for a file name to write into.
2015-01-03 14:48:53 +00:00
my $ output_file = $ self - > _get_export_file ( 'STL' ) or return ;
2017-08-03 15:31:31 +00:00
$ model_object - > mesh - > write_binary ( $ output_file ) ;
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "STL file exported to " ) . $ output_file ) ;
2015-01-03 14:48:53 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2018-07-17 19:31:54 +00:00
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 ) ;
}
2018-10-08 17:55:30 +00:00
# XXX: VK: done
2012-08-29 15:11:56 +00:00
sub export_amf {
2017-10-27 20:49:59 +00:00
my ( $ self ) = @ _ ;
2014-06-14 20:40:37 +00:00
return if ! @ { $ self - > { objects } } ;
2017-10-27 20:49:59 +00:00
# Ask user for a file name to write into.
2012-08-29 15:11:56 +00:00
my $ output_file = $ self - > _get_export_file ( 'AMF' ) or return ;
2018-03-22 12:49:48 +00:00
my $ res = $ self - > { model } - > store_amf ( $ output_file , $ self - > { print } , $ self - > { export_option } ) ;
2018-02-14 13:30:03 +00:00
if ( $ res )
{
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "AMF file exported to " ) . $ output_file ) ;
2018-02-14 13:30:03 +00:00
}
else
{
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "Error exporting AMF file " ) . $ output_file ) ;
2018-02-14 13:30:03 +00:00
}
2012-08-29 15:11:56 +00:00
}
2018-10-08 17:55:30 +00:00
# XXX: VK: done
2018-02-08 12:26:50 +00:00
sub export_3mf {
my ( $ self ) = @ _ ;
return if ! @ { $ self - > { objects } } ;
# Ask user for a file name to write into.
my $ output_file = $ self - > _get_export_file ( '3MF' ) or return ;
2018-03-22 12:49:48 +00:00
my $ res = $ self - > { model } - > store_3mf ( $ output_file , $ self - > { print } , $ self - > { export_option } ) ;
2018-02-08 12:26:50 +00:00
if ( $ res )
{
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "3MF file exported to " ) . $ output_file ) ;
2018-02-08 12:26:50 +00:00
}
else
{
2018-02-22 14:13:07 +00:00
$ self - > statusbar - > SetStatusText ( L ( "Error exporting 3MF file " ) . $ output_file ) ;
2018-02-08 12:26:50 +00:00
}
2012-08-29 15:11:56 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2017-10-27 20:49:59 +00:00
# Ask user to select an output file for a given file format (STl, AMF, 3MF).
# Propose a default file name based on the 'output_filename_format' configuration value.
2012-08-29 15:11:56 +00:00
sub _get_export_file {
2017-10-27 20:49:59 +00:00
my ( $ self , $ format ) = @ _ ;
2018-02-08 12:26:50 +00:00
my $ suffix = '' ;
2018-02-19 14:33:01 +00:00
my $ wildcard = 'known' ;
2018-02-08 12:26:50 +00:00
if ( $ format eq 'STL' )
{
$ suffix = '.stl' ;
2018-02-19 14:33:01 +00:00
$ wildcard = 'stl' ;
2018-02-08 12:26:50 +00:00
}
elsif ( $ format eq 'AMF' )
{
2018-02-20 10:33:38 +00:00
if ( & Wx:: wxMAC ) {
# It seems that MacOS does not like double extension
$ suffix = '.amf' ;
} else {
$ suffix = '.zip.amf' ;
}
2018-02-19 14:33:01 +00:00
$ wildcard = 'amf' ;
2018-02-08 12:26:50 +00:00
}
elsif ( $ format eq '3MF' )
{
$ suffix = '.3mf' ;
2018-02-19 14:33:01 +00:00
$ wildcard = 'threemf' ;
2018-02-08 12:26:50 +00:00
}
2018-05-16 10:16:30 +00:00
# Copy the names of active presets into the placeholder parser.
wxTheApp - > { preset_bundle } - > export_selections_pp ( $ self - > { print } - > placeholder_parser ) ;
2017-12-05 14:54:24 +00:00
my $ output_file = eval { $ self - > { print } - > output_filepath ( $ main:: opt { output } // '' ) } ;
Slic3r::GUI:: catch_error ( $ self ) and return undef ;
2017-10-27 20:49:59 +00:00
$ output_file =~ s/\.[gG][cC][oO][dD][eE]$/$suffix/ ;
2018-02-22 14:13:07 +00:00
my $ dlg = Wx::FileDialog - > new ( $ self , L ( "Save " ) . $ format . L ( " file as:" ) , dirname ( $ output_file ) ,
2018-02-19 14:33:01 +00:00
basename ( $ output_file ) , & Slic3r::GUI::FILE_WILDCARDS - > { $ wildcard } , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
2018-03-22 12:49:48 +00:00
Slic3r::GUI:: add_export_option ( $ dlg , $ format ) ;
2017-10-27 20:49:59 +00:00
if ( $ dlg - > ShowModal != wxID_OK ) {
2012-04-30 15:10:54 +00:00
$ dlg - > Destroy ;
2017-10-27 20:49:59 +00:00
return undef ;
2012-04-30 15:10:54 +00:00
}
2017-10-27 20:49:59 +00:00
$ output_file = $ dlg - > GetPath ;
2018-03-22 12:49:48 +00:00
$ self - > { export_option } = Slic3r::GUI:: get_export_option ( $ dlg ) ;
2017-10-27 20:49:59 +00:00
$ dlg - > Destroy ;
2012-08-29 15:11:56 +00:00
return $ output_file ;
2012-08-29 14:49:38 +00:00
}
2018-07-25 07:42:03 +00:00
#sub reset_thumbnail {
# my ($self, $obj_idx) = @_;
# $self->{objects}[$obj_idx]->thumbnail(undef);
#}
2012-04-30 20:34:41 +00:00
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2013-12-15 22:50:05 +00:00
# this method gets called whenever print center is changed or the objects' bounding box changes
2013-12-12 19:19:33 +00:00
# (i.e. when an object is added/removed/moved/rotated/scaled)
2013-12-18 17:54:11 +00:00
sub update {
2013-12-18 18:11:20 +00:00
my ( $ self , $ force_autocenter ) = @ _ ;
2018-09-17 13:12:13 +00:00
$ self - > Freeze ;
2017-11-02 15:21:34 +00:00
if ( wxTheApp - > { app_config } - > get ( "autocenter" ) || $ force_autocenter ) {
2014-06-16 21:58:45 +00:00
$ self - > { model } - > center_instances_around_point ( $ self - > bed_centerf ) ;
2013-12-18 18:11:20 +00:00
}
2018-03-23 10:41:20 +00:00
$ self - > stop_background_process ;
$ self - > { print } - > reload_model_instances ( ) ;
2017-06-12 12:25:35 +00:00
$ self - > { canvas } - > reload_scene if $ self - > { canvas } ;
2018-07-25 07:42:03 +00:00
# $self->{canvas}->reload_scene if $self->{canvas};
2018-06-08 07:40:00 +00:00
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 0 ) ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > reset_gcode_preview_data if $ self - > { preview_iface } ;
$ self - > { preview_iface } - > reload_print if $ self - > { preview_iface } ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
# $self->{preview3D}->reload_print if $self->{preview3D};
2018-03-23 10:41:20 +00:00
$ self - > schedule_background_process ;
2018-09-17 13:12:13 +00:00
$ self - > Thaw ;
2012-04-30 12:56:01 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: YS: done
2018-08-07 15:23:48 +00:00
# When a printer technology is changed, the UI needs to be updated to show/hide needed preset combo boxes.
sub show_preset_comboboxes {
my ( $ self , $ showSLA ) = @ _ ; #if showSLA is oposite value to "ptFFF"
my $ choices = $ self - > { preset_choosers } { filament } ;
my $ print_filament_ctrls_cnt = 2 + 2 * ( $#$ choices + 1 ) ;
foreach ( 0 .. $ print_filament_ctrls_cnt - 1 ) {
$ self - > { presets_sizer } - > Show ( $ _ , ! $ showSLA ) ;
}
$ self - > { presets_sizer } - > Show ( $ print_filament_ctrls_cnt , $ showSLA ) ;
$ self - > { presets_sizer } - > Show ( $ print_filament_ctrls_cnt + 1 , $ showSLA ) ;
$ self - > { frequently_changed_parameters_sizer } - > Show ( 0 , ! $ showSLA ) ;
$ self - > Layout ;
}
2018-10-11 08:03:38 +00:00
# XXX: YS: done
2016-10-24 14:07:36 +00:00
# When a number of extruders changes, the UI needs to be updated to show a single filament selection combo box per extruder.
2017-10-26 15:17:39 +00:00
# Also the wxTheApp->{preset_bundle}->filament_presets needs to be resized accordingly
# and some reasonable default has to be selected for the additional extruders.
2014-07-01 14:40:56 +00:00
sub on_extruders_change {
my ( $ self , $ num_extruders ) = @ _ ;
my $ choices = $ self - > { preset_choosers } { filament } ;
2017-10-26 15:17:39 +00:00
while ( int ( @$ choices ) < $ num_extruders ) {
2015-06-01 21:58:34 +00:00
# copy strings from first choice
2014-07-01 14:40:56 +00:00
my @ presets = $ choices - > [ 0 ] - > GetStrings ;
2015-06-01 21:58:34 +00:00
# initialize new choice
2018-09-17 13:12:13 +00:00
# my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY);
my $ choice = Wx::BitmapComboBox - > new ( $ self - > { scrolled_window_panel } , - 1 , "" , wxDefaultPosition , wxDefaultSize , [ @ presets ] , wxCB_READONLY ) ;
2017-05-24 13:20:20 +00:00
my $ extruder_idx = scalar @$ choices ;
EVT_LEFT_DOWN ( $ choice , sub { $ self - > filament_color_box_lmouse_down ( $ extruder_idx , @ _ ) ; } ) ;
2015-06-01 21:58:34 +00:00
push @$ choices , $ choice ;
# copy icons from first choice
$ choice - > SetItemBitmap ( $ _ , $ choices - > [ 0 ] - > GetItemBitmap ( $ _ ) ) for 0 .. $# presets ;
# insert new choice into sizer
2014-12-25 18:14:18 +00:00
$ self - > { presets_sizer } - > Insert ( 4 + ( $#$ choices - 1 ) * 2 , 0 , 0 ) ;
2018-03-23 10:41:20 +00:00
$ self - > { presets_sizer } - > Insert ( 5 + ( $#$ choices - 1 ) * 2 , $ choice , 0 , wxEXPAND | wxBOTTOM , 0 ) ;
2015-06-01 21:58:34 +00:00
# setup the listener
2015-06-02 09:19:11 +00:00
EVT_COMBOBOX ( $ choice , $ choice , sub {
my ( $ choice ) = @ _ ;
wxTheApp - > CallAfter ( sub {
2017-10-26 15:17:39 +00:00
$ self - > _on_select_preset ( 'filament' , $ choice , $ extruder_idx ) ;
2015-06-02 09:19:11 +00:00
} ) ;
} ) ;
2015-06-01 21:58:34 +00:00
# initialize selection
2017-10-26 15:17:39 +00:00
wxTheApp - > { preset_bundle } - > update_platter_filament_ui ( $ extruder_idx , $ choice ) ;
2014-07-01 14:40:56 +00:00
}
2015-06-01 21:58:34 +00:00
# remove unused choices if any
2014-07-01 14:40:56 +00:00
while ( @$ choices > $ num_extruders ) {
2014-12-25 18:14:18 +00:00
$ self - > { presets_sizer } - > Remove ( 4 + ( $#$ choices - 1 ) * 2 ) ; # label
$ self - > { presets_sizer } - > Remove ( 4 + ( $#$ choices - 1 ) * 2 ) ; # wxChoice
2014-07-01 14:40:56 +00:00
$ choices - > [ - 1 ] - > Destroy ;
pop @$ choices ;
}
2018-09-17 13:12:13 +00:00
$ self - > { right_panel } - > Layout ;
2014-07-01 14:40:56 +00:00
$ self - > Layout ;
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2012-07-27 19:13:03 +00:00
sub on_config_change {
2017-10-26 15:17:39 +00:00
my ( $ self , $ config ) = @ _ ;
2014-07-01 14:40:56 +00:00
2017-05-17 14:53:40 +00:00
my $ update_scheduled ;
2014-07-01 14:40:56 +00:00
foreach my $ opt_key ( @ { $ self - > { config } - > diff ( $ config ) } ) {
$ self - > { config } - > set ( $ opt_key , $ config - > get ( $ opt_key ) ) ;
2014-06-16 13:18:39 +00:00
if ( $ opt_key eq 'bed_shape' ) {
2018-07-25 07:42:03 +00:00
# $self->{canvas}->update_bed_size;
2018-06-06 13:17:10 +00:00
Slic3r::GUI::_3DScene:: set_bed_shape ( $ self - > { canvas3D } , $ self - > { config } - > bed_shape ) if $ self - > { canvas3D } ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_bed_shape ( $ self - > { config } - > bed_shape ) if ( $ self - > { preview_iface } ) ;
2018-09-18 14:13:18 +00:00
# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
2017-05-17 14:53:40 +00:00
$ update_scheduled = 1 ;
2017-05-19 19:48:32 +00:00
} elsif ( $ opt_key =~ '^wipe_tower' || $ opt_key eq 'single_extruder_multi_material' ) {
2017-05-17 14:53:40 +00:00
$ update_scheduled = 1 ;
2015-01-03 22:25:55 +00:00
} elsif ( $ opt_key eq 'serial_port' ) {
2017-05-31 15:05:11 +00:00
$ self - > { btn_print } - > Show ( $ config - > get ( 'serial_port' ) ) ;
2015-01-03 22:25:55 +00:00
$ self - > Layout ;
2018-07-08 12:32:48 +00:00
} elsif ( $ opt_key eq 'print_host' ) {
$ self - > { btn_send_gcode } - > Show ( $ config - > get ( 'print_host' ) ) ;
2014-12-28 00:30:05 +00:00
$ self - > Layout ;
2017-02-10 09:21:50 +00:00
} elsif ( $ opt_key eq 'variable_layer_height' ) {
if ( $ config - > get ( 'variable_layer_height' ) != 1 ) {
2018-08-15 11:19:58 +00:00
# if ($self->{htoolbar}) {
# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0);
# } else {
# $self->{"btn_layer_editing"}->Disable;
# $self->{"btn_layer_editing"}->SetValue(0);
# }
2018-07-23 11:49:48 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "layersediting" , 0 ) ;
2018-05-25 12:05:08 +00:00
Slic3r::GUI::_3DScene:: enable_layers_editing ( $ self - > { canvas3D } , 0 ) ;
2017-05-17 14:53:40 +00:00
$ self - > { canvas3D } - > Refresh ;
$ self - > { canvas3D } - > Update ;
2018-05-25 14:28:24 +00:00
} elsif ( Slic3r::GUI::_3DScene:: is_layers_editing_allowed ( $ self - > { canvas3D } ) ) {
2017-02-19 17:01:03 +00:00
# Want to allow the layer editing, but do it only if the OpenGL supports it.
2018-08-15 11:19:58 +00:00
# if ($self->{htoolbar}) {
# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
# } else {
# $self->{"btn_layer_editing"}->Enable;
# }
2018-07-23 11:49:48 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "layersediting" , 1 ) ;
2017-02-10 09:21:50 +00:00
}
2017-05-30 15:24:50 +00:00
} elsif ( $ opt_key eq 'extruder_colour' ) {
$ update_scheduled = 1 ;
my $ extruder_colors = $ config - > get ( 'extruder_colour' ) ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_number_extruders ( scalar ( @ { $ extruder_colors } ) ) ;
2018-09-18 14:13:18 +00:00
# $self->{preview3D}->set_number_extruders(scalar(@{$extruder_colors}));
2018-03-09 09:40:42 +00:00
} elsif ( $ opt_key eq 'max_print_height' ) {
$ update_scheduled = 1 ;
2018-06-21 08:43:01 +00:00
} elsif ( $ opt_key eq 'printer_model' ) {
# update to force bed selection (for texturing)
2018-06-26 10:19:19 +00:00
Slic3r::GUI::_3DScene:: set_bed_shape ( $ self - > { canvas3D } , $ self - > { config } - > bed_shape ) if $ self - > { canvas3D } ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_bed_shape ( $ self - > { config } - > bed_shape ) if ( $ self - > { preview_iface } ) ;
2018-09-18 14:13:18 +00:00
# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
2018-06-21 08:43:01 +00:00
$ update_scheduled = 1 ;
2012-07-24 22:15:32 +00:00
}
2012-04-30 12:56:01 +00:00
}
2017-05-17 14:53:40 +00:00
$ self - > update if $ update_scheduled ;
2014-06-13 09:19:53 +00:00
2014-06-14 17:54:18 +00:00
return if ! $ self - > GetFrame - > is_loaded ;
2014-06-13 13:54:13 +00:00
2014-06-13 17:23:51 +00:00
# (re)start timer
2014-06-13 18:36:45 +00:00
$ self - > schedule_background_process ;
2012-04-30 12:56:01 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: YS: WIP
2018-09-07 07:21:12 +00:00
sub item_changed_selection {
2018-06-07 09:12:09 +00:00
my ( $ self , $ obj_idx ) = @ _ ;
2012-04-30 12:56:01 +00:00
2018-09-07 07:21:12 +00:00
if ( ( $ obj_idx >= 0 ) && ( $ obj_idx < 1000 ) ) { # skip if wipe tower selected
if ( $ self - > { canvas3D } ) {
Slic3r::GUI::_3DScene:: deselect_volumes ( $ self - > { canvas3D } ) ;
if ( $ obj_idx >= 0 ) {
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: update_volumes_selection ( $ self - > { canvas3D } , \ @$ selections ) ;
}
# Slic3r::GUI::_3DScene::render($self->{canvas3D});
2018-06-26 11:34:25 +00:00
}
2012-04-30 12:56:01 +00:00
}
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2018-06-08 07:40:00 +00:00
sub collect_selections {
my ( $ self ) = @ _ ;
my $ selections = [] ;
foreach my $ o ( @ { $ self - > { objects } } ) {
push ( @$ selections , $ o - > selected ) ;
}
return $ selections ;
2012-04-30 12:56:01 +00:00
}
2018-10-11 08:03:38 +00:00
# XXX: YS: done, lambda on LEFT_DOWN
2017-05-24 13:20:20 +00:00
# Called when clicked on the filament preset combo box.
# When clicked on the icon, show the color picker.
sub filament_color_box_lmouse_down
{
my ( $ self , $ extruder_idx , $ combobox , $ event ) = @ _ ;
my $ pos = $ event - > GetLogicalPosition ( Wx::ClientDC - > new ( $ combobox ) ) ;
my ( $ x , $ y ) = ( $ pos - > x , $ pos - > y ) ;
if ( $ x > 24 ) {
# Let the combo box process the mouse click.
$ event - > Skip ;
} else {
# Swallow the mouse click and open the color picker.
my $ data = Wx::ColourData - > new ;
$ data - > SetChooseFull ( 1 ) ;
my $ dialog = Wx::ColourDialog - > new ( $ self - > GetFrame , $ data ) ;
if ( $ dialog - > ShowModal == wxID_OK ) {
my $ cfg = Slic3r::Config - > new ;
2017-10-25 10:53:31 +00:00
my $ colors = wxTheApp - > { preset_bundle } - > full_config - > get ( 'extruder_colour' ) ;
2017-05-24 13:20:20 +00:00
$ colors - > [ $ extruder_idx ] = $ dialog - > GetColourData - > GetColour - > GetAsString ( wxC2S_HTML_SYNTAX ) ;
$ cfg - > set ( 'extruder_colour' , $ colors ) ;
$ self - > GetFrame - > { options_tabs } { printer } - > load_config ( $ cfg ) ;
2017-11-10 16:27:05 +00:00
wxTheApp - > { preset_bundle } - > update_platter_filament_ui ( $ extruder_idx , $ combobox ) ;
2017-05-24 13:20:20 +00:00
}
$ dialog - > Destroy ( ) ;
}
}
2018-09-14 08:25:20 +00:00
#sub object_cut_dialog {
# my ($self, $obj_idx) = @_;
#
# if (!defined $obj_idx) {
# ($obj_idx, undef) = $self->selected_object;
# }
#
# if (!$Slic3r::GUI::have_OpenGL) {
# Slic3r::GUI::show_error($self, L("Please install the OpenGL modules to use this feature (see build instructions)."));
# return;
# }
#
# my $dlg = Slic3r::GUI::Plater::ObjectCutDialog->new($self,
# object => $self->{objects}[$obj_idx],
# model_object => $self->{model}->objects->[$obj_idx],
# );
# return unless $dlg->ShowModal == wxID_OK;
#
# if (my @new_objects = $dlg->NewModelObjects) {
# $self->remove($obj_idx);
# $self->load_model_objects(grep defined($_), @new_objects);
# $self->arrange;
# Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
# }
#}
2013-08-25 16:01:59 +00:00
2018-10-11 08:03:38 +00:00
# XXX: YS: done
2018-06-12 17:15:03 +00:00
sub changed_object_settings {
my ( $ self , $ obj_idx , $ parts_changed , $ part_settings_changed ) = @ _ ;
# update thumbnail since parts may have changed
if ( $ parts_changed ) {
# recenter and re-align to Z = 0
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
$ model_object - > center_around_origin ;
2018-08-28 13:51:53 +00:00
# $self->reset_thumbnail($obj_idx);
2018-06-12 17:15:03 +00:00
}
# update print
if ( $ parts_changed || $ part_settings_changed ) {
$ self - > stop_background_process ;
$ self - > { print } - > reload_object ( $ obj_idx ) ;
$ self - > schedule_background_process ;
2017-06-12 12:25:35 +00:00
$ self - > { canvas } - > reload_scene if $ self - > { canvas } ;
2018-06-26 11:34:25 +00:00
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 0 ) ;
2014-07-01 14:40:56 +00:00
} else {
2018-03-23 10:41:20 +00:00
$ self - > schedule_background_process ;
2014-03-23 15:45:55 +00:00
}
2014-07-03 07:24:19 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2016-10-25 11:24:42 +00:00
# Called to update various buttons depending on whether there are any objects or
# whether background processing (export of a G-code, sending to Octoprint, forced background re-slicing) is active.
2012-04-30 12:56:01 +00:00
sub object_list_changed {
my $ self = shift ;
2017-02-13 11:40:12 +00:00
2016-10-25 11:24:42 +00:00
# Enable/disable buttons depending on whether there are any objects on the platter.
2013-08-25 16:01:59 +00:00
my $ have_objects = @ { $ self - > { objects } } ? 1 : 0 ;
2018-08-15 11:19:58 +00:00
# if ($self->{htoolbar}) {
# # On OSX or Linux
# $self->{htoolbar}->EnableTool($_, $have_objects)
# for (TB_RESET, TB_ARRANGE);
# } else {
# # On MSW
# my $method = $have_objects ? 'Enable' : 'Disable';
# $self->{"btn_$_"}->$method
# for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode);
# }
2017-02-13 11:40:12 +00:00
2018-07-27 10:08:33 +00:00
for my $ toolbar_item ( qw( deleteall arrange ) ) {
2018-07-23 11:49:48 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , $ toolbar_item , $ have_objects ) ;
}
2017-02-17 14:00:01 +00:00
my $ export_in_progress = $ self - > { export_gcode_output_file } || $ self - > { send_gcode_file } ;
2018-06-11 11:48:02 +00:00
my $ model_fits = $ self - > { canvas3D } ? Slic3r::GUI::_3DScene:: check_volumes_outside_state ( $ self - > { canvas3D } , $ self - > { config } ) : 1 ;
2018-07-23 08:16:56 +00:00
# $model_fits == 1 -> ModelInstance::PVS_Partly_Outside
my $ method = ( $ have_objects && ! $ export_in_progress && ( $ model_fits != 1 ) ) ? 'Enable' : 'Disable' ;
2017-02-17 14:00:01 +00:00
$ self - > { "btn_$_" } - > $ method
for grep $ self - > { "btn_$_" } , qw( reslice export_gcode print send_gcode ) ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: WIP
2017-10-26 15:17:39 +00:00
# Selection of an active 3D object changed.
2012-04-30 12:56:01 +00:00
sub selection_changed {
2017-10-27 20:49:59 +00:00
my ( $ self ) = @ _ ;
2013-12-12 19:19:33 +00:00
my ( $ obj_idx , $ object ) = $ self - > selected_object ;
my $ have_sel = defined $ obj_idx ;
2018-07-27 10:08:33 +00:00
my $ layers_height_allowed = $ self - > { config } - > variable_layer_height && Slic3r::GUI::_3DScene:: is_layers_editing_allowed ( $ self - > { canvas3D } ) && $ have_sel ;
2018-04-27 13:39:00 +00:00
2018-05-18 11:56:51 +00:00
$ self - > { right_panel } - > Freeze ;
2018-08-15 11:19:58 +00:00
# if ($self->{htoolbar}) {
# # On OSX or Linux
# $self->{htoolbar}->EnableTool($_, $have_sel)
# for (TB_REMOVE, TB_MORE, TB_45CW, TB_45CCW, TB_SCALE, TB_SPLIT, TB_CUT, TB_SETTINGS);
#
# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, $layers_height_allowed);
#
# if ($have_sel) {
# my $model_object = $self->{model}->objects->[$obj_idx];
# $self->{htoolbar}->EnableTool(TB_FEWER, $model_object->instances_count > 1);
# } else {
# $self->{htoolbar}->EnableTool(TB_FEWER, 0);
# }
#
# } else {
# # On MSW
# my $method = $have_sel ? 'Enable' : 'Disable';
# $self->{"btn_$_"}->$method
# for grep $self->{"btn_$_"}, qw(remove increase rotate45cw rotate45ccw changescale split cut settings);
#
# if ($layers_height_allowed) {
# $self->{"btn_layer_editing"}->Enable;
# } else {
# $self->{"btn_layer_editing"}->Disable;
# }
#
# if ($have_sel) {
# my $model_object = $self->{model}->objects->[$obj_idx];
# if ($model_object->instances_count > 1) {
# $self->{"btn_decrease"}->Enable;
# } else {
# $self->{"btn_decrease"}->Disable;
# }
# } else {
# $self->{"btn_decrease"}->Disable;
# }
# }
2018-08-24 13:08:19 +00:00
for my $ toolbar_item ( qw( delete more fewer split cut settings ) ) {
2018-07-23 11:49:48 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , $ toolbar_item , $ have_sel ) ;
}
2012-04-30 12:56:01 +00:00
2018-07-27 10:08:33 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "layersediting" , $ layers_height_allowed ) ;
2018-09-06 14:10:31 +00:00
my $ can_select_by_parts = 0 ;
2018-07-27 12:38:19 +00:00
if ( $ have_sel ) {
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2018-09-06 14:10:31 +00:00
$ can_select_by_parts = ( $ obj_idx >= 0 ) && ( $ obj_idx < 1000 ) && ( $ model_object - > volumes_count > 1 ) ;
2018-07-27 12:38:19 +00:00
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "fewer" , $ model_object - > instances_count > 1 ) ;
2013-08-25 10:22:05 +00:00
}
2018-09-06 14:10:31 +00:00
if ( $ can_select_by_parts ) {
# first disable to let the item in the toolbar to switch to the unpressed state
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "selectbyparts" , 0 ) ;
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "selectbyparts" , 1 ) ;
} else {
Slic3r::GUI::_3DScene:: enable_toolbar_item ( $ self - > { canvas3D } , "selectbyparts" , 0 ) ;
Slic3r::GUI::_3DScene:: set_select_by ( $ self - > { canvas3D } , 'object' ) ;
}
2013-08-25 10:22:05 +00:00
if ( $ self - > { object_info_size } ) { # have we already loaded the info pane?
if ( $ have_sel ) {
2013-12-12 19:19:33 +00:00
my $ model_object = $ self - > { model } - > objects - > [ $ obj_idx ] ;
2017-09-14 07:06:14 +00:00
#FIXME print_info runs model fixing in two rounds, it is very slow, it should not be performed here!
# $model_object->print_info;
2013-12-12 19:19:33 +00:00
my $ model_instance = $ model_object - > instances - > [ 0 ] ;
$ self - > { object_info_size } - > SetLabel ( sprintf ( "%.2f x %.2f x %.2f" , @ { $ model_object - > instance_bounding_box ( 0 ) - > size } ) ) ;
$ self - > { object_info_materials } - > SetLabel ( $ model_object - > materials_count ) ;
2013-08-25 10:22:05 +00:00
2013-12-12 19:19:33 +00:00
if ( my $ stats = $ model_object - > mesh_stats ) {
$ self - > { object_info_volume } - > SetLabel ( sprintf ( '%.2f' , $ stats - > { volume } * ( $ model_instance - > scaling_factor ** 3 ) ) ) ;
2018-02-22 14:13:07 +00:00
$ self - > { object_info_facets } - > SetLabel ( sprintf ( L ( '%d (%d shells)' ) , $ model_object - > facets_count , $ stats - > { number_of_parts } ) ) ;
2013-08-25 15:26:55 +00:00
if ( my $ errors = sum ( @$ stats { qw( degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges ) } ) ) {
2018-02-22 14:13:07 +00:00
$ self - > { object_info_manifold } - > SetLabel ( sprintf ( L ( "Auto-repaired (%d errors)" ) , $ errors ) ) ;
2018-05-18 09:39:49 +00:00
#$self->{object_info_manifold_warning_icon}->Show;
$ self - > { "object_info_manifold_warning_icon_show" } - > ( 1 ) ;
2013-08-25 15:26:55 +00:00
2013-08-25 16:01:59 +00:00
# we don't show normals_fixed because we never provide normals
# to admesh, so it generates normals for all facets
2018-02-22 14:13:07 +00:00
my $ message = sprintf L ( '%d degenerate facets, %d edges fixed, %d facets removed, %d facets added, %d facets reversed, %d backwards edges' ) ,
2013-08-25 15:26:55 +00:00
@$ stats { qw( degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges ) } ;
$ self - > { object_info_manifold } - > SetToolTipString ( $ message ) ;
$ self - > { object_info_manifold_warning_icon } - > SetToolTipString ( $ message ) ;
} else {
2018-02-22 14:13:07 +00:00
$ self - > { object_info_manifold } - > SetLabel ( L ( "Yes" ) ) ;
2018-05-18 09:39:49 +00:00
#$self->{object_info_manifold_warning_icon}->Hide;
$ self - > { "object_info_manifold_warning_icon_show" } - > ( 0 ) ;
2018-05-17 07:26:50 +00:00
$ self - > { object_info_manifold } - > SetToolTipString ( "" ) ;
$ self - > { object_info_manifold_warning_icon } - > SetToolTipString ( "" ) ;
2013-08-25 15:26:55 +00:00
}
} else {
$ self - > { object_info_facets } - > SetLabel ( $ object - > facets ) ;
2013-08-25 10:22:05 +00:00
}
} else {
2013-08-25 15:26:55 +00:00
$ self - > { "object_info_$_" } - > SetLabel ( "" ) for qw( size volume facets materials manifold ) ;
2018-05-18 09:39:49 +00:00
#$self->{object_info_manifold_warning_icon}->Hide;
$ self - > { "object_info_manifold_warning_icon_show" } - > ( 0 ) ;
2013-08-25 15:26:55 +00:00
$ self - > { object_info_manifold } - > SetToolTipString ( "" ) ;
2018-05-17 07:26:50 +00:00
$ self - > { object_info_manifold_warning_icon } - > SetToolTipString ( "" ) ;
2013-08-25 10:22:05 +00:00
}
2013-08-25 15:26:55 +00:00
$ self - > Layout ;
2012-05-04 09:22:56 +00:00
}
2014-06-14 16:58:56 +00:00
# prepagate the event to the frame (a custom Wx event would be cleaner)
2014-06-14 17:11:04 +00:00
$ self - > GetFrame - > on_plater_selection_changed ( $ have_sel ) ;
2018-05-18 11:56:51 +00:00
$ self - > { right_panel } - > Thaw ;
2012-04-30 12:56:01 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2013-12-12 19:19:33 +00:00
sub select_object {
2018-06-16 01:04:59 +00:00
my ( $ self , $ obj_idx , $ child ) = @ _ ;
2018-05-02 11:55:04 +00:00
# remove current selection
foreach my $ o ( 0 .. $# { $ self - > { objects } } ) {
$ self - > { objects } - > [ $ o ] - > selected ( 0 ) ;
}
2018-06-05 11:17:24 +00:00
2013-12-12 19:19:33 +00:00
if ( defined $ obj_idx ) {
$ self - > { objects } - > [ $ obj_idx ] - > selected ( 1 ) ;
2018-06-16 01:04:59 +00:00
# Select current object in the list on c++ side, if item isn't child
2018-09-17 13:12:13 +00:00
# if (!defined $child){
# Slic3r::GUI::select_current_object($obj_idx);} # all selections in the object list is on c++ side
2013-12-12 19:19:33 +00:00
} else {
2018-06-07 09:12:09 +00:00
# Unselect all objects in the list on c++ side
2018-09-17 13:12:13 +00:00
# Slic3r::GUI::unselect_objects(); # all selections in the object list is on c++ side
}
$ self - > selection_changed ( 1 ) ;
}
2018-10-11 08:03:38 +00:00
# XXX: YS: WIP
2018-09-17 13:12:13 +00:00
sub select_object_from_cpp {
my ( $ self , $ obj_idx , $ vol_idx ) = @ _ ;
# remove current selection
foreach my $ o ( 0 .. $# { $ self - > { objects } } ) {
$ self - > { objects } - > [ $ o ] - > selected ( 0 ) ;
}
my $ curr = Slic3r::GUI::_3DScene:: get_select_by ( $ self - > { canvas3D } ) ;
if ( defined $ obj_idx ) {
if ( $ vol_idx == - 1 ) {
if ( $ curr eq 'object' ) {
$ self - > { objects } - > [ $ obj_idx ] - > selected ( 1 ) ;
}
elsif ( $ curr eq 'volume' ) {
Slic3r::GUI::_3DScene:: set_select_by ( $ self - > { canvas3D } , 'object' ) ;
}
my $ selections = $ self - > collect_selections ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 1 ) ;
}
else {
if ( $ curr eq 'object' ) {
Slic3r::GUI::_3DScene:: set_select_by ( $ self - > { canvas3D } , 'volume' ) ;
}
my $ selections = [] ;
Slic3r::GUI::_3DScene:: set_objects_selections ( $ self - > { canvas3D } , \ @$ selections ) ;
Slic3r::GUI::_3DScene:: deselect_volumes ( $ self - > { canvas3D } ) ;
Slic3r::GUI::_3DScene:: reload_scene ( $ self - > { canvas3D } , 1 ) ;
my $ volume_idx = Slic3r::GUI::_3DScene:: get_first_volume_id ( $ self - > { canvas3D } , $ obj_idx ) ;
my $ inst_cnt = $ self - > { model } - > objects - > [ $ obj_idx ] - > instances_count ;
for ( 0 .. $ inst_cnt - 1 ) {
Slic3r::GUI::_3DScene:: select_volume ( $ self - > { canvas3D } , $ vol_idx * $ inst_cnt + $ _ + $ volume_idx ) if ( $ volume_idx != - 1 ) ;
}
}
2013-12-12 19:19:33 +00:00
}
2018-09-17 13:12:13 +00:00
2013-12-12 19:19:33 +00:00
$ self - > selection_changed ( 1 ) ;
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2012-08-29 17:37:27 +00:00
sub selected_object {
2017-10-27 20:49:59 +00:00
my ( $ self ) = @ _ ;
2013-12-12 19:19:33 +00:00
my $ obj_idx = first { $ self - > { objects } [ $ _ ] - > selected } 0 .. $# { $ self - > { objects } } ;
2017-10-27 20:49:59 +00:00
return defined $ obj_idx ? ( $ obj_idx , $ self - > { objects } [ $ obj_idx ] ) : undef ;
2013-08-25 20:24:43 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done
2012-05-04 10:56:15 +00:00
sub statusbar {
2017-10-25 10:53:31 +00:00
return $ _ [ 0 ] - > GetFrame - > { statusbar } ;
2012-05-04 10:56:15 +00:00
}
2018-10-08 17:14:55 +00:00
# XXX: not done, to be removed (?)
2014-06-14 19:36:28 +00:00
sub object_menu {
my ( $ self ) = @ _ ;
my $ frame = $ self - > GetFrame ;
my $ menu = Wx::Menu - > new ;
2017-11-30 17:26:15 +00:00
my $ accel = ( $^O eq 'MSWin32' ) ? sub { $ _ [ 0 ] . "\t\xA0" . $ _ [ 1 ] } : sub { $ _ [ 0 ] } ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , $ accel - > ( L ( 'Delete' ) , 'Del' ) , L ( 'Remove the selected object' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > remove ;
2015-05-25 20:37:04 +00:00
} , undef , 'brick_delete.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , $ accel - > ( L ( 'Increase copies' ) , '+' ) , L ( 'Place one more copy of the selected object' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > increase ;
2015-05-25 20:37:04 +00:00
} , undef , 'add.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , $ accel - > ( L ( 'Decrease copies' ) , '-' ) , L ( 'Remove one copy of the selected object' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > decrease ;
2015-05-25 20:37:04 +00:00
} , undef , 'delete.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , L ( "Set number of copies…" ) , L ( 'Change the number of copies of the selected object' ) , sub {
2015-01-14 22:19:13 +00:00
$ self - > set_number_of_copies ;
2015-05-25 20:37:04 +00:00
} , undef , 'textfield.png' ) ;
2014-06-14 19:36:28 +00:00
$ menu - > AppendSeparator ( ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , $ accel - > ( L ( 'Rotate 45° clockwise' ) , 'l' ) , L ( 'Rotate the selected object by 45° clockwise' ) , sub {
2017-03-23 10:53:59 +00:00
$ self - > rotate ( - 45 , Z , 'relative' ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'arrow_rotate_clockwise.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , $ accel - > ( L ( 'Rotate 45° counter-clockwise' ) , 'r' ) , L ( 'Rotate the selected object by 45° counter-clockwise' ) , sub {
2017-03-23 10:53:59 +00:00
$ self - > rotate ( + 45 , Z , 'relative' ) ;
2015-05-25 20:37:04 +00:00
} , undef , 'arrow_rotate_anticlockwise.png' ) ;
2014-06-14 19:36:28 +00:00
my $ rotateMenu = Wx::Menu - > new ;
2018-02-22 14:13:07 +00:00
my $ rotateMenuItem = $ menu - > AppendSubMenu ( $ rotateMenu , L ( "Rotate" ) , L ( 'Rotate the selected object by an arbitrary angle' ) ) ;
2015-05-25 20:37:04 +00:00
$ frame - > _set_menu_item_icon ( $ rotateMenuItem , 'textfield.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ rotateMenu , L ( "Around X axis…" ) , L ( 'Rotate the selected object by an arbitrary angle around X axis' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > rotate ( undef , X ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_red.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ rotateMenu , L ( "Around Y axis…" ) , L ( 'Rotate the selected object by an arbitrary angle around Y axis' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > rotate ( undef , Y ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_green.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ rotateMenu , L ( "Around Z axis…" ) , L ( 'Rotate the selected object by an arbitrary angle around Z axis' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > rotate ( undef , Z ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_blue.png' ) ;
2014-06-14 19:36:28 +00:00
2015-11-04 22:11:30 +00:00
my $ mirrorMenu = Wx::Menu - > new ;
2018-02-22 14:13:07 +00:00
my $ mirrorMenuItem = $ menu - > AppendSubMenu ( $ mirrorMenu , L ( "Mirror" ) , L ( 'Mirror the selected object' ) ) ;
2015-11-04 22:11:30 +00:00
$ frame - > _set_menu_item_icon ( $ mirrorMenuItem , 'shape_flip_horizontal.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ mirrorMenu , L ( "Along X axis…" ) , L ( 'Mirror the selected object along the X axis' ) , sub {
2015-11-04 22:11:30 +00:00
$ self - > mirror ( X ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_red.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ mirrorMenu , L ( "Along Y axis…" ) , L ( 'Mirror the selected object along the Y axis' ) , sub {
2015-11-04 22:11:30 +00:00
$ self - > mirror ( Y ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_green.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ mirrorMenu , L ( "Along Z axis…" ) , L ( 'Mirror the selected object along the Z axis' ) , sub {
2015-11-04 22:11:30 +00:00
$ self - > mirror ( Z ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_blue.png' ) ;
2014-06-14 19:36:28 +00:00
2014-06-16 22:50:44 +00:00
my $ scaleMenu = Wx::Menu - > new ;
2018-02-22 14:13:07 +00:00
my $ scaleMenuItem = $ menu - > AppendSubMenu ( $ scaleMenu , L ( "Scale" ) , L ( 'Scale the selected object along a single axis' ) ) ;
2015-05-25 20:37:04 +00:00
$ frame - > _set_menu_item_icon ( $ scaleMenuItem , 'arrow_out.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleMenu , $ accel - > ( L ( 'Uniformly…' ) , 's' ) , L ( 'Scale the selected object along the XYZ axes' ) , sub {
2014-06-16 22:50:44 +00:00
$ self - > changescale ( undef ) ;
} ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleMenu , L ( "Along X axis…" ) , L ( 'Scale the selected object along the X axis' ) , sub {
2014-06-16 22:50:44 +00:00
$ self - > changescale ( X ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_red.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleMenu , L ( "Along Y axis…" ) , L ( 'Scale the selected object along the Y axis' ) , sub {
2014-06-16 22:50:44 +00:00
$ self - > changescale ( Y ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_green.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleMenu , L ( "Along Z axis…" ) , L ( 'Scale the selected object along the Z axis' ) , sub {
2014-06-16 22:50:44 +00:00
$ self - > changescale ( Z ) ;
2015-12-05 18:01:17 +00:00
} , undef , 'bullet_blue.png' ) ;
2014-06-16 22:50:44 +00:00
2015-12-05 18:37:57 +00:00
my $ scaleToSizeMenu = Wx::Menu - > new ;
2018-02-22 14:13:07 +00:00
my $ scaleToSizeMenuItem = $ menu - > AppendSubMenu ( $ scaleToSizeMenu , L ( "Scale to size" ) , L ( 'Scale the selected object along a single axis' ) ) ;
2015-12-05 18:37:57 +00:00
$ frame - > _set_menu_item_icon ( $ scaleToSizeMenuItem , 'arrow_out.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleToSizeMenu , L ( "Uniformly…" ) , L ( 'Scale the selected object along the XYZ axes' ) , sub {
2015-12-05 18:37:57 +00:00
$ self - > changescale ( undef , 1 ) ;
} ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleToSizeMenu , L ( "Along X axis…" ) , L ( 'Scale the selected object along the X axis' ) , sub {
2015-12-05 18:37:57 +00:00
$ self - > changescale ( X , 1 ) ;
} , undef , 'bullet_red.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleToSizeMenu , L ( "Along Y axis…" ) , L ( 'Scale the selected object along the Y axis' ) , sub {
2015-12-05 18:37:57 +00:00
$ self - > changescale ( Y , 1 ) ;
} , undef , 'bullet_green.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ scaleToSizeMenu , L ( "Along Z axis…" ) , L ( 'Scale the selected object along the Z axis' ) , sub {
2015-12-05 18:37:57 +00:00
$ self - > changescale ( Z , 1 ) ;
} , undef , 'bullet_blue.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , L ( "Split" ) , L ( 'Split the selected object into individual parts' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > split_object ;
2015-05-25 20:37:04 +00:00
} , undef , 'shape_ungroup.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , L ( "Cut…" ) , L ( 'Open the 3D cutting tool' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > object_cut_dialog ;
2015-05-25 20:37:04 +00:00
} , undef , 'package.png' ) ;
2014-06-14 19:36:28 +00:00
$ menu - > AppendSeparator ( ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , L ( "Settings…" ) , L ( 'Open the object editor dialog' ) , sub {
2014-06-14 19:36:28 +00:00
$ self - > object_settings_dialog ;
2015-05-25 20:37:04 +00:00
} , undef , 'cog.png' ) ;
2015-01-03 14:48:53 +00:00
$ menu - > AppendSeparator ( ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , L ( "Reload from Disk" ) , L ( 'Reload the selected file from Disk' ) , sub {
2016-12-17 20:47:45 +00:00
$ self - > reload_from_disk ;
} , undef , 'arrow_refresh.png' ) ;
2018-02-22 14:13:07 +00:00
$ frame - > _append_menu_item ( $ menu , L ( "Export object as STL…" ) , L ( 'Export this single object as STL file' ) , sub {
2015-01-03 14:48:53 +00:00
$ self - > export_object_stl ;
2015-05-25 20:37:04 +00:00
} , undef , 'brick_go.png' ) ;
2018-07-17 19:31:54 +00:00
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' ) ;
}
2014-06-14 19:36:28 +00:00
return $ menu ;
}
2018-10-08 17:14:55 +00:00
# XXX: not done
2016-10-05 12:13:07 +00:00
# Set a camera direction, zoom to all objects.
sub select_view {
my ( $ self , $ direction ) = @ _ ;
my $ idx_page = $ self - > { preview_notebook } - > GetSelection ;
2018-02-22 14:13:07 +00:00
my $ page = ( $ idx_page == & Wx:: wxNOT_FOUND ) ? L ( '3D' ) : $ self - > { preview_notebook } - > GetPageText ( $ idx_page ) ;
2018-09-18 14:13:18 +00:00
if ( $ page eq L ( 'Preview' ) ) {
$ self - > { preview_iface } - > select_view ( $ direction ) ;
$ self - > { preview_iface } - > set_viewport_into_scene ( $ self - > { canvas3D } ) ;
# Slic3r::GUI::_3DScene::select_view($self->{preview3D}->canvas, $direction);
# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas);
2016-10-05 12:13:07 +00:00
} else {
2018-05-24 14:11:34 +00:00
Slic3r::GUI::_3DScene:: select_view ( $ self - > { canvas3D } , $ direction ) ;
2018-09-18 11:35:05 +00:00
$ self - > { preview_iface } - > set_viewport_from_scene ( $ self - > { canvas3D } ) ;
2018-09-18 14:13:18 +00:00
# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D});
2016-10-05 12:13:07 +00:00
}
}
2018-10-08 17:14:55 +00:00
# XXX: VK: done, in PlaterDropTarget
2012-05-04 08:15:33 +00:00
package Slic3r::GUI::Plater::DropTarget ;
2012-04-30 12:56:01 +00:00
use Wx::DND ;
use base 'Wx::FileDropTarget' ;
sub new {
2017-10-27 20:49:59 +00:00
my ( $ class , $ window ) = @ _ ;
2012-04-30 12:56:01 +00:00
my $ self = $ class - > SUPER:: new ;
$ self - > { window } = $ window ;
return $ self ;
}
sub OnDropFiles {
2017-10-27 20:49:59 +00:00
my ( $ self , $ x , $ y , $ filenames ) = @ _ ;
2012-07-21 12:45:45 +00:00
# stop scalars leaking on older perl
# https://rt.perl.org/rt3/Public/Bug/Display.html?id=70602
@ _ = ( ) ;
2018-02-14 13:30:03 +00:00
# only accept STL, OBJ, AMF, 3MF and PRUSA files
return 0 if grep ! /\.(?:[sS][tT][lL]|[oO][bB][jJ]|[aA][mM][fF]|[3][mM][fF]|[aA][mM][fF].[xX][mM][lL]|[zZ][iI][pP].[aA][mM][lL]|[pP][rR][uU][sS][aA])$/ , @$ filenames ;
2017-07-11 11:55:55 +00:00
$ self - > { window } - > load_files ( $ filenames ) ;
2012-04-30 12:56:01 +00:00
}
2016-09-13 09:24:55 +00:00
# 2D preview of an object. Each object is previewed by its convex hull.
2012-08-29 17:37:27 +00:00
package Slic3r::GUI::Plater::Object ;
use Moo ;
has 'name' = > ( is = > 'rw' , required = > 1 ) ;
2013-12-12 19:19:33 +00:00
has 'selected' = > ( is = > 'rw' , default = > sub { 0 } ) ;
2012-08-29 17:37:27 +00:00
2012-04-30 12:56:01 +00:00
1 ;