Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Reload from disk" - UI function overhaul #4388

Merged
merged 14 commits into from
Apr 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/Slic3r/GUI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use Slic3r::GUI::Preset;
use Slic3r::GUI::PresetEditor;
use Slic3r::GUI::PresetEditorDialog;
use Slic3r::GUI::SLAPrintOptions;
use Slic3r::GUI::ReloadDialog;

our $have_OpenGL = eval "use Slic3r::GUI::3DScene; 1";
our $have_LWP = eval "use LWP::UserAgent; 1";
Expand Down Expand Up @@ -91,7 +92,9 @@ our $Settings = {
color_toolpaths_by => 'role',
tabbed_preset_editors => 1,
show_host => 0,
nudge_val => 1
nudge_val => 1,
reload_hide_dialog => 0,
reload_behavior => 0
},
};

Expand Down
171 changes: 154 additions & 17 deletions lib/Slic3r/GUI/Plater.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ sub add_tin {

sub load_file {
my $self = shift;
my ($input_file, $obj_idx) = @_;
my ($input_file, $obj_idx_to_load) = @_;

$Slic3r::GUI::Settings->{recent}{skein_directory} = dirname($input_file);
wxTheApp->save_settings;
Expand All @@ -1203,14 +1203,27 @@ sub load_file {
}
}

if (defined $obj_idx) {
return () if $obj_idx >= $model->objects_count;
@obj_idx = $self->load_model_objects($model->get_object($obj_idx));
for my $obj_idx (0..($model->objects_count-1)) {
my $object = $model->objects->[$obj_idx];
$object->set_input_file($input_file);
for my $vol_idx (0..($object->volumes_count-1)) {
my $volume = $object->get_volume($vol_idx);
$volume->set_input_file($input_file);
$volume->set_input_file_obj_idx($obj_idx);
$volume->set_input_file_obj_idx($vol_idx);
}
}

my $i = 0;

if (defined $obj_idx_to_load) {
return () if $obj_idx_to_load >= $model->objects_count;
@obj_idx = $self->load_model_objects($model->get_object($obj_idx_to_load));
$i = $obj_idx_to_load;
} else {
@obj_idx = $self->load_model_objects(@{$model->objects});
}

my $i = 0;
foreach my $obj_idx (@obj_idx) {
$self->{objects}[$obj_idx]->input_file($input_file);
$self->{objects}[$obj_idx]->input_file_obj_idx($i++);
Expand Down Expand Up @@ -2306,26 +2319,141 @@ sub reload_from_disk {
my ($obj_idx, $object) = $self->selected_object;
return if !defined $obj_idx;

return if !$object->input_file
|| !-e $object->input_file;
if (!$object->input_file) {
Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because it isn't referenced to its input file any more. This is the case after performing operations like cut or split.");
return;
}
if (!-e $object->input_file) {
Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because the file doesn't exist anymore on the disk.");
return;
}

# Only reload the selected object and not all objects from the input file.
my @new_obj_idx = $self->load_file($object->input_file, $object->input_file_obj_idx);
return if !@new_obj_idx;

my $model_object = $self->{model}->objects->[$obj_idx];
if (!@new_obj_idx) {
Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be reloaded because the new file doesn't contain the object.");
return;
}

my $org_obj = $self->{model}->objects->[$obj_idx];

# check if the object is dependant of more than one file
my $org_obj_has_modifiers=0;
for my $i (0..($org_obj->volumes_count-1)) {
if ($org_obj->input_file ne $org_obj->get_volume($i)->input_file) {
$org_obj_has_modifiers=1;
last;
}
}

my $reload_behavior = $Slic3r::GUI::Settings->{_}{reload_behavior};

# ask the user how to proceed, if option is selected in preferences
if ($org_obj_has_modifiers && !$Slic3r::GUI::Settings->{_}{reload_hide_dialog}) {
my $dlg = Slic3r::GUI::ReloadDialog->new(undef,$reload_behavior);
my $res = $dlg->ShowModal;
if ($res==wxID_CANCEL) {
$self->remove($_) for @new_obj_idx;
$dlg->Destroy;
return;
}
$reload_behavior = $dlg->GetSelection;
my $save = 0;
if ($reload_behavior != $Slic3r::GUI::Settings->{_}{reload_behavior}) {
$Slic3r::GUI::Settings->{_}{reload_behavior} = $reload_behavior;
$save = 1;
}
if ($dlg->GetHideOnNext) {
$Slic3r::GUI::Settings->{_}{reload_hide_dialog} = 1;
$save = 1;
}
Slic3r::GUI->save_settings if $save;
$dlg->Destroy;
}

my $volume_unmatched=0;

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};
my $new_obj = $self->{model}->objects->[$new_obj_idx];
$new_obj->clear_instances;
$new_obj->add_instance($_) for @{$org_obj->instances};
$new_obj->config->apply($org_obj->config);

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);
my $new_vol_idx = 0;
my $org_vol_idx = 0;
my $new_vol_count=$new_obj->volumes_count;
my $org_vol_count=$org_obj->volumes_count;

while ($new_vol_idx<=$new_vol_count-1) {
if (($org_vol_idx<=$org_vol_count-1) && ($org_obj->get_volume($org_vol_idx)->input_file eq $new_obj->input_file)) {
# apply config from the matching volumes
$new_obj->get_volume($new_vol_idx++)->config->apply($org_obj->get_volume($org_vol_idx++)->config);
} else {
# reload has more volumes than original (first file), apply config from the first volume
$new_obj->get_volume($new_vol_idx++)->config->apply($org_obj->get_volume(0)->config);
$volume_unmatched=1;
}
}
$org_vol_idx=$org_vol_count if $reload_behavior==2; # Reload behavior: discard
while (($org_vol_idx<=$org_vol_count-1) && ($org_obj->get_volume($org_vol_idx)->input_file eq $new_obj->input_file)) {
# original has more volumes (first file), skip those
$org_vol_idx++;
$volume_unmatched=1;
}
while ($org_vol_idx<=$org_vol_count-1) {
if ($reload_behavior==1) { # Reload behavior: copy
my $new_volume = $new_obj->add_volume($org_obj->get_volume($org_vol_idx));
$new_volume->mesh->translate(@{$org_obj->origin_translation->negative});
$new_volume->mesh->translate(@{$new_obj->origin_translation});
if ($new_volume->name =~ m/link to path\z/) {
my $new_name = $new_volume->name;
$new_name =~ s/ - no link to path$/ - copied/;
$new_volume->set_name($new_name);
}elsif(!($new_volume->name =~ m/copied\z/)) {
$new_volume->set_name($new_volume->name . " - copied");
}
}else{ # Reload behavior: Reload all, also fallback solution if ini was manually edited to a wrong value
if ($org_obj->get_volume($org_vol_idx)->input_file) {
my $model = eval { Slic3r::Model->read_from_file($org_obj->get_volume($org_vol_idx)->input_file) };
if ($@) {
$org_obj->get_volume($org_vol_idx)->set_input_file("");
}elsif ($org_obj->get_volume($org_vol_idx)->input_file_obj_idx > ($model->objects_count-1)) {
# Object Index for that part / modifier not found in current version of the file
$org_obj->get_volume($org_vol_idx)->set_input_file("");
}else{
my $prt_mod_obj = $model->objects->[$org_obj->get_volume($org_vol_idx)->input_file_obj_idx];
if ($org_obj->get_volume($org_vol_idx)->input_file_vol_idx > ($prt_mod_obj->volumes_count-1)) {
# Volume Index for that part / modifier not found in current version of the file
$org_obj->get_volume($org_vol_idx)->set_input_file("");
}else{
# all checks passed, load new mesh and copy metadata
my $new_volume = $new_obj->add_volume($prt_mod_obj->get_volume($org_obj->get_volume($org_vol_idx)->input_file_vol_idx));
$new_volume->set_input_file($org_obj->get_volume($org_vol_idx)->input_file);
$new_volume->set_input_file_obj_idx($org_obj->get_volume($org_vol_idx)->input_file_obj_idx);
$new_volume->set_input_file_vol_idx($org_obj->get_volume($org_vol_idx)->input_file_vol_idx);
$new_volume->config->apply($org_obj->get_volume($org_vol_idx)->config);
$new_volume->set_modifier($org_obj->get_volume($org_vol_idx)->modifier);
$new_volume->mesh->translate(@{$new_obj->origin_translation});
}
}
}
if (!$org_obj->get_volume($org_vol_idx)->input_file) {
my $new_volume = $new_obj->add_volume($org_obj->get_volume($org_vol_idx)); # error -> copy old mesh
$new_volume->mesh->translate(@{$org_obj->origin_translation->negative});
$new_volume->mesh->translate(@{$new_obj->origin_translation});
if ($new_volume->name =~ m/copied\z/) {
my $new_name = $new_volume->name;
$new_name =~ s/ - copied$/ - no link to path/;
$new_volume->set_name($new_name);
}elsif(!($new_volume->name =~ m/link to path\z/)) {
$new_volume->set_name($new_volume->name . " - no link to path");
}
$volume_unmatched=1;
}
}
$org_vol_idx++;
}
}

$self->remove($obj_idx);

# TODO: refresh object list which contains wrong count and scale
Expand All @@ -2336,8 +2464,17 @@ sub reload_from_disk {
# When porting to C++ we'll probably have cleaner ways to do this.
$self->make_thumbnail($_-1) for @new_obj_idx;

# update print
$self->stop_background_process;
$self->{print}->reload_object($_-1) for @new_obj_idx;
$self->on_model_change;

# Empty the redo stack
$self->{redo_stack} = [];

if ($volume_unmatched) {
Slic3r::GUI::warning_catcher($self)->("At least 1 volume couldn't be matched between the original object and the reloaded one.");
}
}

sub export_object_stl {
Expand Down
12 changes: 9 additions & 3 deletions lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,17 @@ sub on_btn_load {
next;
}

foreach my $object (@{$model->objects}) {
foreach my $volume (@{$object->volumes}) {
my $new_volume = $self->{model_object}->add_volume($volume);
for my $obj_idx (0..($model->objects_count-1)) {
my $object = $model->objects->[$obj_idx];
for my $vol_idx (0..($object->volumes_count-1)) {
my $new_volume = $self->{model_object}->add_volume($object->get_volume($vol_idx));
$new_volume->set_modifier($is_modifier);
$new_volume->set_name(basename($input_file));

# input_file needed to reload / update modifiers' volumes
$new_volume->set_input_file($input_file);
$new_volume->set_input_file_obj_idx($obj_idx);
$new_volume->set_input_file_vol_idx($vol_idx);

# apply the same translation we applied to the object
$new_volume->mesh->translate(@{$self->{model_object}->origin_translation});
Expand Down
19 changes: 18 additions & 1 deletion lib/Slic3r/GUI/Preferences.pm
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ sub new {
tooltip => 'In 2D plater, Move objects using keyboard by nudge value of',
default => $Slic3r::GUI::Settings->{_}{nudge_val},
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( # reload hide dialog
opt_id => 'reload_hide_dialog',
type => 'bool',
label => 'Hide Dialog on Reload',
tooltip => 'When checked, the dialog on reloading files with added parts & modifiers is suppressed. The reload is performed according to the option given in \'Default Reload Behavior\'',
default => $Slic3r::GUI::Settings->{_}{reload_hide_dialog},
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( # default reload behavior
opt_id => 'reload_behavior',
type => 'select',
label => 'Default Reload Behavior',
tooltip => 'Choose the default behavior of the \'Reload from disk\' function regarding additional parts and modifiers.',
labels => ['Reload all','Reload main, copy added','Reload main, discard added'],
values => [0, 1, 2],
default => $Slic3r::GUI::Settings->{_}{reload_behavior},
width => 180,
));
$optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( # colorscheme
opt_id => 'colorscheme',
type => 'select',
Expand All @@ -100,7 +117,7 @@ sub new {
labels => ['Default','Solarized'], # add more schemes, if you want in ColorScheme.pm.
values => ['getDefault','getSolarized'], # add more schemes, if you want - those are the names of the corresponding function in ColorScheme.pm.
default => $Slic3r::GUI::Settings->{_}{colorscheme} // 'getDefault',
width => 130,
width => 180,
));

my $sizer = Wx::BoxSizer->new(wxVERTICAL);
Expand Down
60 changes: 60 additions & 0 deletions lib/Slic3r/GUI/ReloadDialog.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# A tiny dialog to select how to reload an object that has additional parts or modifiers.

package Slic3r::GUI::ReloadDialog;
use strict;
use warnings;
use utf8;

use Wx qw(:button :dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE);
use base 'Wx::Dialog';

sub new {
my $class = shift;
my ($parent,$default_selection) = @_;
my $self = $class->SUPER::new($parent, -1, "Additional parts and modifiers detected", wxDefaultPosition, [350,100], wxDEFAULT_DIALOG_STYLE);

# label
my $text = Wx::StaticText->new($self, -1, "Additional parts and modifiers are loaded in the current model. \n\nHow do you want to proceed?", wxDefaultPosition, wxDefaultSize);

# selector
$self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, []);
$choice->Append("Reload all linked files");
$choice->Append("Reload main file, copy added parts & modifiers");
$choice->Append("Reload main file, discard added parts & modifiers");
$choice->SetSelection($default_selection);

# checkbox
$self->{checkbox} = my $checkbox = Wx::CheckBox->new($self, -1, "Don't ask again");

my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
$vsizer->Add($text, 0, wxEXPAND | wxALL, 10);
$vsizer->Add($choice, 0, wxEXPAND | wxALL, 10);
$hsizer->Add($checkbox, 1, wxEXPAND | wxALL, 10);
$hsizer->Add($self->CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 10);
$vsizer->Add($hsizer, 0, wxEXPAND | wxALL, 0);

$self->SetSizer($vsizer);
$self->SetMinSize($self->GetSize);
$vsizer->SetSizeHints($self);

# needed to actually free memory
EVT_CLOSE($self, sub {
$self->EndModal(wxID_CANCEL);
$self->Destroy;
});

return $self;
}

sub GetSelection {
my ($self) = @_;
return $self->{choice}->GetSelection;
}
sub GetHideOnNext {
my ($self) = @_;
return $self->{checkbox}->GetValue;
}

1;
16 changes: 13 additions & 3 deletions xs/src/libslic3r/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,12 +936,18 @@ ModelObject::print_info() const


ModelVolume::ModelVolume(ModelObject* object, const TriangleMesh &mesh)
: mesh(mesh), modifier(false), object(object)
: mesh(mesh), modifier(false), input_file(""), object(object)
{}

ModelVolume::ModelVolume(ModelObject* object, const ModelVolume &other)
: name(other.name), mesh(other.mesh), config(other.config),
modifier(other.modifier), object(object)
: name(other.name),
mesh(other.mesh),
config(other.config),
modifier(other.modifier),
input_file(other.input_file),
input_file_obj_idx(other.input_file_obj_idx),
input_file_vol_idx(other.input_file_vol_idx),
object(object)
{
this->material_id(other.material_id());
}
Expand All @@ -959,6 +965,10 @@ ModelVolume::swap(ModelVolume &other)
std::swap(this->mesh, other.mesh);
std::swap(this->config, other.config);
std::swap(this->modifier, other.modifier);

std::swap(this->input_file, other.input_file);
std::swap(this->input_file_obj_idx, other.input_file_obj_idx);
std::swap(this->input_file_vol_idx, other.input_file_vol_idx);
}

t_model_material_id
Expand Down
7 changes: 6 additions & 1 deletion xs/src/libslic3r/Model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,12 @@ class ModelVolume
DynamicPrintConfig config;
///< Configuration parameters specific to an object model geometry or a modifier volume,
///< overriding the global Slic3r settings and the ModelObject settings.


/// Input file path needed for reloading the volume from disk
std::string input_file; ///< Input file path
int input_file_obj_idx; ///< Input file object index
int input_file_vol_idx; ///< Input file volume index

bool modifier; ///< Is it an object to be printed, or a modifier volume?

/// Get the parent object owning this modifier volume.
Expand Down
Loading