mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-03 05:40:38 +08:00
Allow dirty presets, and many more improvements including remembering the preset dialog position and closing it with the Esc key
This commit is contained in:
parent
9a9597df83
commit
4ca5f9ee16
@ -5,7 +5,9 @@ use utf8;
|
|||||||
|
|
||||||
use File::Basename qw(basename);
|
use File::Basename qw(basename);
|
||||||
use FindBin;
|
use FindBin;
|
||||||
use List::Util qw(first);
|
use List::Util qw(first any);
|
||||||
|
use Slic3r::Geometry qw(X Y);
|
||||||
|
|
||||||
use Slic3r::GUI::2DBed;
|
use Slic3r::GUI::2DBed;
|
||||||
use Slic3r::GUI::AboutDialog;
|
use Slic3r::GUI::AboutDialog;
|
||||||
use Slic3r::GUI::BedShapeDialog;
|
use Slic3r::GUI::BedShapeDialog;
|
||||||
@ -98,7 +100,7 @@ sub OnInit {
|
|||||||
Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
|
Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
|
||||||
|
|
||||||
$self->{notifier} = Slic3r::GUI::Notifier->new;
|
$self->{notifier} = Slic3r::GUI::Notifier->new;
|
||||||
$self->{external_presets} = [];
|
$self->{presets} = { print => [], filament => [], printer => [] };
|
||||||
|
|
||||||
# locate or create data directory
|
# locate or create data directory
|
||||||
# Unix: ~/.Slic3r
|
# Unix: ~/.Slic3r
|
||||||
@ -142,6 +144,8 @@ sub OnInit {
|
|||||||
unlink "$enc_datadir/simple.ini";
|
unlink "$enc_datadir/simple.ini";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$self->load_presets;
|
||||||
|
|
||||||
# application frame
|
# application frame
|
||||||
Wx::Image::AddHandler(Wx::PNGHandler->new);
|
Wx::Image::AddHandler(Wx::PNGHandler->new);
|
||||||
$self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
|
$self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
|
||||||
@ -283,47 +287,64 @@ sub save_settings {
|
|||||||
Slic3r::Config->write_ini("$datadir/slic3r.ini", $Settings);
|
Slic3r::Config->write_ini("$datadir/slic3r.ini", $Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub presets {
|
sub presets { return $_[0]->{presets}; }
|
||||||
my ($self, $section, $force_default) = @_;
|
|
||||||
|
|
||||||
my @presets = ();
|
sub load_presets {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
opendir my $dh, Slic3r::encode_path("$Slic3r::GUI::datadir/$section")
|
for my $group (qw(printer filament print)) {
|
||||||
or die "Failed to read directory $Slic3r::GUI::datadir/$section (errno: $!)\n";
|
my $presets = $self->{presets}{$group};
|
||||||
|
|
||||||
|
# keep external or dirty presets
|
||||||
|
@$presets = grep { ($_->external && $_->file_exists) || $_->dirty } @$presets;
|
||||||
|
|
||||||
|
my $dir = "$Slic3r::GUI::datadir/$group";
|
||||||
|
opendir my $dh, Slic3r::encode_path($dir)
|
||||||
|
or die "Failed to read directory $dir (errno: $!)\n";
|
||||||
foreach my $file (grep /\.ini$/i, readdir $dh) {
|
foreach my $file (grep /\.ini$/i, readdir $dh) {
|
||||||
$file = Slic3r::decode_path($file);
|
$file = Slic3r::decode_path($file);
|
||||||
my $name = basename($file);
|
my $name = basename($file);
|
||||||
$name =~ s/\.ini$//i;
|
$name =~ s/\.ini$//i;
|
||||||
push @presets, Slic3r::GUI::Preset->new(
|
|
||||||
|
# skip if we already have it
|
||||||
|
next if any { $_->name eq $name } @$presets;
|
||||||
|
|
||||||
|
push @$presets, Slic3r::GUI::Preset->new(
|
||||||
|
group => $group,
|
||||||
name => $name,
|
name => $name,
|
||||||
file => "$Slic3r::GUI::datadir/$section/$file",
|
file => "$dir/$file",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
closedir $dh;
|
closedir $dh;
|
||||||
|
|
||||||
@presets = sort { $a->name cmp $b->name }
|
@$presets = sort { $a->name cmp $b->name } @$presets;
|
||||||
@presets,
|
|
||||||
(grep -e $_->file, @{$self->{external_presets}});
|
|
||||||
|
|
||||||
if ($force_default || !@presets) {
|
unshift @$presets, Slic3r::GUI::Preset->new(
|
||||||
unshift @presets, Slic3r::GUI::Preset->new(
|
group => $group,
|
||||||
default => 1,
|
default => 1,
|
||||||
name => '- default -',
|
name => '- default -',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return @presets;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub add_external_preset {
|
sub add_external_preset {
|
||||||
my ($self, $file) = @_;
|
my ($self, $file) = @_;
|
||||||
|
|
||||||
push @{$self->{external_presets}}, my $preset = Slic3r::GUI::Preset->new(
|
my $name = basename($file); # keep .ini suffix
|
||||||
name => basename($file), # keep .ini suffix
|
for my $group (qw(printer filament print)) {
|
||||||
|
my $presets = $self->{presets}{$group};
|
||||||
|
|
||||||
|
# remove any existing preset with the same name
|
||||||
|
@$presets = grep { $_->name ne $name } @$presets;
|
||||||
|
|
||||||
|
push @$presets, Slic3r::GUI::Preset->new(
|
||||||
|
group => $group,
|
||||||
|
name => $name,
|
||||||
file => $file,
|
file => $file,
|
||||||
external => 1,
|
external => 1,
|
||||||
);
|
);
|
||||||
return $preset;
|
}
|
||||||
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub have_version_check {
|
sub have_version_check {
|
||||||
@ -416,4 +437,29 @@ sub set_menu_item_icon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub save_window_pos {
|
||||||
|
my ($self, $window, $name) = @_;
|
||||||
|
|
||||||
|
$Settings->{_}{"${name}_pos"} = join ',', $window->GetScreenPositionXY;
|
||||||
|
$Settings->{_}{"${name}_size"} = join ',', $window->GetSizeWH;
|
||||||
|
$Settings->{_}{"${name}_maximized"} = $window->IsMaximized;
|
||||||
|
$self->save_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub restore_window_pos {
|
||||||
|
my ($self, $window, $name) = @_;
|
||||||
|
|
||||||
|
if (defined $Settings->{_}{"${name}_pos"}) {
|
||||||
|
my $size = [ split ',', $Settings->{_}{"${name}_size"}, 2 ];
|
||||||
|
$window->SetSize($size);
|
||||||
|
|
||||||
|
my $display = Wx::Display->new->GetClientArea();
|
||||||
|
my $pos = [ split ',', $Settings->{_}{"${name}_pos"}, 2 ];
|
||||||
|
if (($pos->[X] + $size->[X]/2) < $display->GetRight && ($pos->[Y] + $size->[Y]/2) < $display->GetBottom) {
|
||||||
|
$window->Move($pos);
|
||||||
|
}
|
||||||
|
$window->Maximize(1) if $Settings->{_}{"${name}_maximized"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -47,7 +47,7 @@ sub new {
|
|||||||
delete $presets{$_} for map $_->printer_name, @panels;
|
delete $presets{$_} for map $_->printer_name, @panels;
|
||||||
|
|
||||||
foreach my $preset_name (sort keys %presets) {
|
foreach my $preset_name (sort keys %presets) {
|
||||||
my $config = $presets{$preset_name}->load_config;
|
my $config = $presets{$preset_name}->dirty_config;
|
||||||
next if !$config->serial_port;
|
next if !$config->serial_port;
|
||||||
|
|
||||||
my $id = &Wx::NewId();
|
my $id = &Wx::NewId();
|
||||||
@ -101,7 +101,7 @@ sub OnActivate {
|
|||||||
# get all available presets
|
# get all available presets
|
||||||
my %presets = ();
|
my %presets = ();
|
||||||
{
|
{
|
||||||
my %all = map { $_->name => $_ } wxTheApp->presets('printer');
|
my %all = map { $_->name => $_ } @{wxTheApp->presets->{printer}};
|
||||||
my %configs = map { my $name = $_; $name => $all{$name}->load_config } keys %all;
|
my %configs = map { my $name = $_; $name => $all{$name}->load_config } keys %all;
|
||||||
%presets = map { $_ => $configs{$_} } grep $configs{$_}->serial_port, keys %all;
|
%presets = map { $_ => $configs{$_} } grep $configs{$_}->serial_port, keys %all;
|
||||||
}
|
}
|
||||||
|
@ -56,19 +56,8 @@ sub new {
|
|||||||
$self->SetSizer($sizer);
|
$self->SetSizer($sizer);
|
||||||
$self->Fit;
|
$self->Fit;
|
||||||
$self->SetMinSize([760, 490]);
|
$self->SetMinSize([760, 490]);
|
||||||
if (defined $Slic3r::GUI::Settings->{_}{main_frame_size}) {
|
|
||||||
my $size = [ split ',', $Slic3r::GUI::Settings->{_}{main_frame_size}, 2 ];
|
|
||||||
$self->SetSize($size);
|
|
||||||
|
|
||||||
my $display = Wx::Display->new->GetClientArea();
|
|
||||||
my $pos = [ split ',', $Slic3r::GUI::Settings->{_}{main_frame_pos}, 2 ];
|
|
||||||
if (($pos->[X] + $size->[X]/2) < $display->GetRight && ($pos->[Y] + $size->[Y]/2) < $display->GetBottom) {
|
|
||||||
$self->Move($pos);
|
|
||||||
}
|
|
||||||
$self->Maximize(1) if $Slic3r::GUI::Settings->{_}{main_frame_maximized};
|
|
||||||
} else {
|
|
||||||
$self->SetSize($self->GetMinSize);
|
$self->SetSize($self->GetMinSize);
|
||||||
}
|
wxTheApp->restore_window_pos($self, "main_frame");
|
||||||
$self->Show;
|
$self->Show;
|
||||||
$self->Layout;
|
$self->Layout;
|
||||||
}
|
}
|
||||||
@ -78,23 +67,23 @@ sub new {
|
|||||||
my (undef, $event) = @_;
|
my (undef, $event) = @_;
|
||||||
|
|
||||||
if ($event->CanVeto) {
|
if ($event->CanVeto) {
|
||||||
my $veto = 0;
|
if (!$self->{plater}->prompt_unsaved_changes) {
|
||||||
|
$event->Veto;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ($self->{controller} && $self->{controller}->printing) {
|
if ($self->{controller} && $self->{controller}->printing) {
|
||||||
my $confirm = Wx::MessageDialog->new($self, "You are currently printing. Do you want to stop printing and continue anyway?",
|
my $confirm = Wx::MessageDialog->new($self, "You are currently printing. Do you want to stop printing and continue anyway?",
|
||||||
'Unfinished Print', wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
|
'Unfinished Print', wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
|
||||||
$veto = 1 if $confirm->ShowModal == wxID_YES;
|
if ($confirm->ShowModal == wxID_NO) {
|
||||||
}
|
|
||||||
if ($veto) {
|
|
||||||
$event->Veto;
|
$event->Veto;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# save window size
|
# save window size
|
||||||
$Slic3r::GUI::Settings->{_}{main_frame_pos} = join ',', $self->GetScreenPositionXY;
|
wxTheApp->save_window_pos($self, "main_frame");
|
||||||
$Slic3r::GUI::Settings->{_}{main_frame_size} = join ',', $self->GetSizeWH;
|
|
||||||
$Slic3r::GUI::Settings->{_}{main_frame_maximized} = $self->IsMaximized;
|
|
||||||
wxTheApp->save_settings;
|
|
||||||
|
|
||||||
# propagate event
|
# propagate event
|
||||||
$event->Skip;
|
$event->Skip;
|
||||||
@ -507,9 +496,9 @@ sub load_config_file {
|
|||||||
wxTheApp->save_settings;
|
wxTheApp->save_settings;
|
||||||
$last_config = $file;
|
$last_config = $file;
|
||||||
|
|
||||||
my $preset = wxTheApp->add_external_preset($file);
|
my $name = wxTheApp->add_external_preset($file);
|
||||||
$self->{plater}->load_presets;
|
$self->{plater}->load_presets;
|
||||||
$self->{plater}->select_preset_by_name($preset->name, $_) for qw(print filament printer);
|
$self->{plater}->select_preset_by_name($name, $_) for qw(print filament printer);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub export_configbundle {
|
sub export_configbundle {
|
||||||
@ -536,8 +525,9 @@ sub export_configbundle {
|
|||||||
$ini->{presets} = $Slic3r::GUI::Settings->{presets};
|
$ini->{presets} = $Slic3r::GUI::Settings->{presets};
|
||||||
|
|
||||||
foreach my $section (qw(print filament printer)) {
|
foreach my $section (qw(print filament printer)) {
|
||||||
my @presets = wxTheApp->presets($section);
|
my @presets = @{wxTheApp->presets->{$section}};
|
||||||
foreach my $preset (@presets) {
|
foreach my $preset (@presets) {
|
||||||
|
next if $preset->default || $preset->external;
|
||||||
$ini->{"$section:" . $preset->name} = $preset->load_config->as_ini->{_};
|
$ini->{"$section:" . $preset->name} = $preset->load_config->as_ini->{_};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -581,10 +571,10 @@ sub load_configbundle {
|
|||||||
next if $skip_no_id && !$config->get($section . "_settings_id");
|
next if $skip_no_id && !$config->get($section . "_settings_id");
|
||||||
|
|
||||||
{
|
{
|
||||||
my @current_presets = Slic3r::GUI->presets($section);
|
my @current_presets = @{wxTheApp->presets->{$section}};
|
||||||
my %current_ids = map { $_ => 1 }
|
my %current_ids = map { $_ => 1 }
|
||||||
grep $_,
|
grep $_,
|
||||||
map $_->load_config->get($section . "_settings_id"),
|
map $_->dirty_config->get($section . "_settings_id"),
|
||||||
@current_presets;
|
@current_presets;
|
||||||
next INI_BLOCK if exists $current_ids{$config->get($section . "_settings_id")};
|
next INI_BLOCK if exists $current_ids{$config->get($section . "_settings_id")};
|
||||||
}
|
}
|
||||||
|
@ -368,6 +368,7 @@ sub new {
|
|||||||
printer => 'Printer',
|
printer => 'Printer',
|
||||||
);
|
);
|
||||||
$self->{preset_choosers} = {};
|
$self->{preset_choosers} = {};
|
||||||
|
$self->{preset_choosers_names} = {}; # wxChoice* => []
|
||||||
for my $group (qw(print filament printer)) {
|
for my $group (qw(print filament printer)) {
|
||||||
# label
|
# label
|
||||||
my $text = Wx::StaticText->new($self, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
|
my $text = Wx::StaticText->new($self, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
|
||||||
@ -380,7 +381,7 @@ sub new {
|
|||||||
EVT_COMBOBOX($choice, $choice, sub {
|
EVT_COMBOBOX($choice, $choice, sub {
|
||||||
my ($choice) = @_;
|
my ($choice) = @_;
|
||||||
wxTheApp->CallAfter(sub {
|
wxTheApp->CallAfter(sub {
|
||||||
$self->_on_select_preset($group);
|
$self->_on_change_combobox($group, $choice);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -512,11 +513,52 @@ sub new {
|
|||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub prompt_unsaved_changes {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
foreach my $group (qw(printer filament print)) {
|
||||||
|
foreach my $choice (@{$self->{preset_choosers}{$group}}) {
|
||||||
|
my $pp = $self->{preset_choosers_names}{$choice};
|
||||||
|
for my $i (0..$#$pp) {
|
||||||
|
my $preset = first { $_->name eq $pp->[$i] } @{wxTheApp->presets->{$group}};
|
||||||
|
if (!$preset->prompt_unsaved_changes($self)) {
|
||||||
|
# Restore the previous one
|
||||||
|
$choice->SetSelection($i);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _on_change_combobox {
|
||||||
|
my ($self, $group, $choice) = @_;
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
# This code is disabled because wxPerl doesn't provide GetCurrentSelection
|
||||||
|
my $current_name = $self->{preset_choosers_names}{$choice}[$choice->GetCurrentSelection];
|
||||||
|
my $current = first { $_->name eq $current_name } @{wxTheApp->presets->{$group}};
|
||||||
|
if (!$current->prompt_unsaved_changes($self)) {
|
||||||
|
# Restore the previous one
|
||||||
|
$choice->SetSelection($choice->GetCurrentSelection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0 if !$self->prompt_unsaved_changes;
|
||||||
|
}
|
||||||
|
wxTheApp->CallAfter(sub {
|
||||||
|
$self->_on_select_preset($group);
|
||||||
|
|
||||||
|
# This will remove the "(modified)" mark from any dirty preset handled here.
|
||||||
|
$self->load_presets;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
sub _on_select_preset {
|
sub _on_select_preset {
|
||||||
my ($self, $group) = @_;
|
my ($self, $group) = @_;
|
||||||
|
|
||||||
my @presets = map $self->presets->{$group}[scalar $_->GetSelection],
|
my @presets = $self->selected_presets($group);
|
||||||
@{$self->{preset_choosers}{$group}};
|
|
||||||
|
|
||||||
$Slic3r::GUI::Settings->{presets}{$group} = $presets[0]->name;
|
$Slic3r::GUI::Settings->{presets}{$group} = $presets[0]->name;
|
||||||
$Slic3r::GUI::Settings->{presets}{"${group}_${_}"} = $presets[$_]->name
|
$Slic3r::GUI::Settings->{presets}{"${group}_${_}"} = $presets[$_]->name
|
||||||
@ -565,17 +607,16 @@ sub GetFrame {
|
|||||||
sub load_presets {
|
sub load_presets {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
$self->presets({});
|
|
||||||
|
|
||||||
my $selected_printer_name;
|
my $selected_printer_name;
|
||||||
foreach my $group (qw(printer filament print)) {
|
foreach my $group (qw(printer filament print)) {
|
||||||
my @presets = wxTheApp->presets($group);
|
my @presets = @{wxTheApp->presets->{$group}};
|
||||||
if ($group eq 'filament' || $group eq 'print') {
|
|
||||||
my %printer_names = map { $_->name => 1 } @{ $self->presets->{printer} };
|
|
||||||
# Skip presets not compatible with the selected printer, if they
|
# Skip presets not compatible with the selected printer, if they
|
||||||
# have other compatible printers configured (and at least one of them exists).
|
# have other compatible printers configured (and at least one of them exists).
|
||||||
|
if ($group eq 'filament' || $group eq 'print') {
|
||||||
|
my %printer_names = map { $_->name => 1 } @{ wxTheApp->presets->{printer} };
|
||||||
for (my $i = 0; $i <= $#presets; ++$i) {
|
for (my $i = 0; $i <= $#presets; ++$i) {
|
||||||
my $config = $presets[$i]->config;
|
my $config = $presets[$i]->dirty_config;
|
||||||
next if !$config->has('compatible_printers');
|
next if !$config->has('compatible_printers');
|
||||||
my @compat = @{$config->compatible_printers};
|
my @compat = @{$config->compatible_printers};
|
||||||
if (@compat
|
if (@compat
|
||||||
@ -586,14 +627,11 @@ sub load_presets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!@presets) {
|
|
||||||
unshift @presets, Slic3r::GUI::Preset->new(
|
|
||||||
default => 1,
|
|
||||||
name => '- default -',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->presets->{$group} = [@presets];
|
# Only show the default presets if we have no other presets.
|
||||||
|
if (@presets > 1) {
|
||||||
|
@presets = grep { !$_->default } @presets;
|
||||||
|
}
|
||||||
|
|
||||||
# get the wxChoice objects for this group
|
# get the wxChoice objects for this group
|
||||||
my @choosers = @{ $self->{preset_choosers}{$group} };
|
my @choosers = @{ $self->{preset_choosers}{$group} };
|
||||||
@ -613,11 +651,12 @@ sub load_presets {
|
|||||||
# populate the wxChoice objects
|
# populate the wxChoice objects
|
||||||
foreach my $choice (@choosers) {
|
foreach my $choice (@choosers) {
|
||||||
$choice->Clear;
|
$choice->Clear;
|
||||||
|
$self->{preset_choosers_names}{$choice} = [];
|
||||||
foreach my $preset (@presets) {
|
foreach my $preset (@presets) {
|
||||||
# load/generate the proper icon
|
# load/generate the proper icon
|
||||||
my $bitmap;
|
my $bitmap;
|
||||||
if ($group eq 'filament') {
|
if ($group eq 'filament') {
|
||||||
my $config = $preset->config;
|
my $config = $preset->dirty_config;
|
||||||
if ($preset->default || !$config->has('filament_colour')) {
|
if ($preset->default || !$config->has('filament_colour')) {
|
||||||
$bitmap = Wx::Bitmap->new($Slic3r::var->("spool.png"), wxBITMAP_TYPE_PNG);
|
$bitmap = Wx::Bitmap->new($Slic3r::var->("spool.png"), wxBITMAP_TYPE_PNG);
|
||||||
} else {
|
} else {
|
||||||
@ -634,7 +673,8 @@ sub load_presets {
|
|||||||
} elsif ($group eq 'printer') {
|
} elsif ($group eq 'printer') {
|
||||||
$bitmap = Wx::Bitmap->new($Slic3r::var->("printer_empty.png"), wxBITMAP_TYPE_PNG);
|
$bitmap = Wx::Bitmap->new($Slic3r::var->("printer_empty.png"), wxBITMAP_TYPE_PNG);
|
||||||
}
|
}
|
||||||
$choice->AppendString($preset->name, $bitmap);
|
$choice->AppendString($preset->dropdown_name, $bitmap);
|
||||||
|
push @{$self->{preset_choosers_names}{$choice}}, $preset->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $selected = shift @sel;
|
my $selected = shift @sel;
|
||||||
@ -643,14 +683,13 @@ sub load_presets {
|
|||||||
# won't be picked up as the visible string
|
# won't be picked up as the visible string
|
||||||
$choice->SetSelection($selected);
|
$choice->SetSelection($selected);
|
||||||
|
|
||||||
my $preset_name = $choice->GetString($selected);
|
my $preset_name = $self->{preset_choosers_names}{$choice}[$selected];
|
||||||
$self->{print}->placeholder_parser->set("${group}_preset", $preset_name);
|
$self->{print}->placeholder_parser->set("${group}_preset", $preset_name);
|
||||||
|
# TODO: populate other filament preset placeholders
|
||||||
$selected_printer_name = $preset_name if $group eq 'printer';
|
$selected_printer_name = $preset_name if $group eq 'printer';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#$self->_on_select_preset($_) for qw(printer filament print);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub select_preset_by_name {
|
sub select_preset_by_name {
|
||||||
@ -658,11 +697,12 @@ sub select_preset_by_name {
|
|||||||
|
|
||||||
# $n is optional
|
# $n is optional
|
||||||
|
|
||||||
my $presets = $self->presets->{$group};
|
my $presets = wxTheApp->presets->{$group};
|
||||||
my $i = first { $presets->[$_]->name eq $name } 0..$#$presets;
|
my $choosers = $self->{preset_choosers}{$group};
|
||||||
|
my $names = $self->{preset_choosers_names}{$choosers->[0]};
|
||||||
|
my $i = first { $names->[$_] eq $name } 0..$#$names;
|
||||||
return if !defined $i;
|
return if !defined $i;
|
||||||
|
|
||||||
my $choosers = $self->{preset_choosers}{$group};
|
|
||||||
if (defined $n && $n <= $#$choosers) {
|
if (defined $n && $n <= $#$choosers) {
|
||||||
$choosers->[$n]->SetSelection($i);
|
$choosers->[$n]->SetSelection($i);
|
||||||
} else {
|
} else {
|
||||||
@ -674,10 +714,16 @@ sub select_preset_by_name {
|
|||||||
sub selected_presets {
|
sub selected_presets {
|
||||||
my ($self, $group) = @_;
|
my ($self, $group) = @_;
|
||||||
|
|
||||||
my %presets;
|
my %presets = ();
|
||||||
foreach my $group (qw(printer filament print)) {
|
foreach my $group (qw(printer filament print)) {
|
||||||
my @i = map scalar($_->GetSelection), @{ $self->{preset_choosers}{$group} };
|
$presets{$group} = [];
|
||||||
$presets{$group} = [ @{$self->presets->{$group}}[@i] ];
|
foreach my $choice (@{$self->{preset_choosers}{$group}}) {
|
||||||
|
my $sel = $choice->GetSelection;
|
||||||
|
$sel = 0 if $sel == -1;
|
||||||
|
push @{ $presets{$group} },
|
||||||
|
grep { $_->name eq $self->{preset_choosers_names}{$choice}[$sel] }
|
||||||
|
@{wxTheApp->presets->{$group}};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $group ? @{$presets{$group}} : %presets;
|
return $group ? @{$presets{$group}} : %presets;
|
||||||
}
|
}
|
||||||
@ -697,7 +743,7 @@ sub show_preset_editor {
|
|||||||
|
|
||||||
# Select the preset that was last selected in the editor.
|
# Select the preset that was last selected in the editor.
|
||||||
$self->select_preset_by_name
|
$self->select_preset_by_name
|
||||||
($dlg->preset_editor->get_current_preset->name, $group, $i, 1);
|
($dlg->preset_editor->current_preset->name, $group, $i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Returns the current config by merging the selected presets and the overrides.
|
# Returns the current config by merging the selected presets and the overrides.
|
||||||
@ -715,16 +761,13 @@ sub config {
|
|||||||
qw(print filament printer);
|
qw(print filament printer);
|
||||||
|
|
||||||
my %presets = $self->selected_presets;
|
my %presets = $self->selected_presets;
|
||||||
$config->apply($_->config([ $classes{printer}->options ]))
|
$config->apply($_->dirty_config) for @{ $presets{printer} };
|
||||||
for @{ $presets{printer} };
|
|
||||||
if (@{ $presets{filament} }) {
|
if (@{ $presets{filament} }) {
|
||||||
my @opt_keys = ($classes{filament}->options, $classes{filament}->overriding_options);
|
my $filament_config = $presets{filament}[0]->dirty_config;
|
||||||
my $filament_config = shift(@{ $presets{filament} })
|
|
||||||
->config(\@opt_keys);
|
|
||||||
|
|
||||||
my $i = 1;
|
for my $i (1..$#{ $presets{filament} }) {
|
||||||
for my $preset (@{ $presets{filament} }) {
|
my $preset = $presets{filament}[$i];
|
||||||
my $config = $preset->config(\@opt_keys);
|
my $config = $preset->dirty_config;
|
||||||
foreach my $opt_key (@{$config->get_keys}) {
|
foreach my $opt_key (@{$config->get_keys}) {
|
||||||
if ($filament_config->has($opt_key)) {
|
if ($filament_config->has($opt_key)) {
|
||||||
my $value = $filament_config->get($opt_key);
|
my $value = $filament_config->get($opt_key);
|
||||||
@ -733,14 +776,11 @@ sub config {
|
|||||||
$filament_config->set($opt_key, $value);
|
$filament_config->set($opt_key, $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++$i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$config->apply($filament_config);
|
$config->apply($filament_config);
|
||||||
}
|
}
|
||||||
$config->apply($_->config([ $classes{print}->options ]))
|
$config->apply($_->dirty_config) for @{ $presets{print} };
|
||||||
for @{ $presets{print} };
|
|
||||||
|
|
||||||
$config->apply($self->{settings_override_config});
|
$config->apply($self->{settings_override_config});
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
@ -1896,7 +1936,7 @@ sub on_extruders_change {
|
|||||||
EVT_COMBOBOX($choice, $choice, sub {
|
EVT_COMBOBOX($choice, $choice, sub {
|
||||||
my ($choice) = @_;
|
my ($choice) = @_;
|
||||||
wxTheApp->CallAfter(sub {
|
wxTheApp->CallAfter(sub {
|
||||||
$self->_on_select_preset('filament');
|
$self->_on_change_combobox('filament', $choice);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ sub new {
|
|||||||
EVT_MENU($menu, $id, sub {
|
EVT_MENU($menu, $id, sub {
|
||||||
$self->{config}->set($opt_key, $self->{default_config}->get($opt_key));
|
$self->{config}->set($opt_key, $self->{default_config}->get($opt_key));
|
||||||
$self->update_optgroup;
|
$self->update_optgroup;
|
||||||
$self->{on_change}->() if $self->{on_change};
|
$self->{on_change}->($opt_key) if $self->{on_change};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$self->PopupMenu($menu, $btn->GetPosition);
|
$self->PopupMenu($menu, $btn->GetPosition);
|
||||||
@ -155,7 +155,10 @@ sub update_optgroup {
|
|||||||
label_font => $Slic3r::GUI::small_font,
|
label_font => $Slic3r::GUI::small_font,
|
||||||
sidetext_font => $Slic3r::GUI::small_font,
|
sidetext_font => $Slic3r::GUI::small_font,
|
||||||
label_width => 120,
|
label_width => 120,
|
||||||
on_change => sub { $self->{on_change}->() if $self->{on_change} },
|
on_change => sub {
|
||||||
|
my ($opt_key) = @_;
|
||||||
|
$self->{on_change}->($opt_key) if $self->{on_change};
|
||||||
|
},
|
||||||
extra_column => sub {
|
extra_column => sub {
|
||||||
my ($line) = @_;
|
my ($line) = @_;
|
||||||
|
|
||||||
@ -169,7 +172,7 @@ sub update_optgroup {
|
|||||||
wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE);
|
wxDefaultPosition, wxDefaultSize, Wx::wxBORDER_NONE);
|
||||||
EVT_BUTTON($self, $btn, sub {
|
EVT_BUTTON($self, $btn, sub {
|
||||||
$self->{config}->erase($opt_key);
|
$self->{config}->erase($opt_key);
|
||||||
$self->{on_change}->() if $self->{on_change};
|
$self->{on_change}->($opt_key) if $self->{on_change};
|
||||||
wxTheApp->CallAfter(sub { $self->update_optgroup });
|
wxTheApp->CallAfter(sub { $self->update_optgroup });
|
||||||
});
|
});
|
||||||
return $btn;
|
return $btn;
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package Slic3r::GUI::Preset;
|
package Slic3r::GUI::Preset;
|
||||||
use Moo;
|
use Moo;
|
||||||
use Unicode::Normalize;
|
|
||||||
|
|
||||||
|
use Unicode::Normalize;
|
||||||
|
use Wx qw(:dialog :icon :id wxTheApp);
|
||||||
|
|
||||||
|
has 'group' => (is => 'ro', required => 1);
|
||||||
has 'default' => (is => 'ro', default => sub { 0 });
|
has 'default' => (is => 'ro', default => sub { 0 });
|
||||||
has 'external' => (is => 'ro', default => sub { 0 });
|
has 'external' => (is => 'ro', default => sub { 0 });
|
||||||
has 'name' => (is => 'rw', required => 1);
|
has 'name' => (is => 'rw', required => 1);
|
||||||
has 'file' => (is => 'rw');
|
has 'file' => (is => 'rw');
|
||||||
|
has '_config' => (is => 'rw', default => sub { Slic3r::Config->new });
|
||||||
|
has '_dirty_config' => (is => 'ro', default => sub { Slic3r::Config->new });
|
||||||
|
|
||||||
sub BUILD {
|
sub BUILD {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
@ -13,40 +18,193 @@ sub BUILD {
|
|||||||
$self->name(Unicode::Normalize::NFC($self->name));
|
$self->name(Unicode::Normalize::NFC($self->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
sub config {
|
sub _loaded {
|
||||||
my ($self, $keys, $extra_keys) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
if ($self->default) {
|
return !$self->_config->empty;
|
||||||
return Slic3r::Config->new_from_defaults(@$keys);
|
|
||||||
} else {
|
|
||||||
if (!-e Slic3r::encode_path($self->file)) {
|
|
||||||
Slic3r::GUI::show_error(undef, "The selected preset does not exist anymore (" . $self->file . ").");
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
my $external_config = $self->load_config;
|
|
||||||
if (!$keys) {
|
|
||||||
return $external_config;
|
|
||||||
} else {
|
|
||||||
# apply preset values on top of defaults
|
|
||||||
my $config = Slic3r::Config->new_from_defaults(@$keys);
|
|
||||||
$config->set($_, $external_config->get($_))
|
|
||||||
for grep $external_config->has($_), @$keys;
|
|
||||||
|
|
||||||
# For extra_keys we don't populate defaults.
|
|
||||||
if ($extra_keys && !$self->external) {
|
|
||||||
$config->set($_, $external_config->get($_))
|
|
||||||
for grep $external_config->has($_), @$extra_keys;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $config;
|
sub dirty_options {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my @dirty = ();
|
||||||
|
|
||||||
|
# Options present in both configs with different values:
|
||||||
|
push @dirty, @{$self->_config->diff($self->_dirty_config)};
|
||||||
|
|
||||||
|
# Overrides added to the dirty config:
|
||||||
|
my @extra = $self->_group_class->overriding_options;
|
||||||
|
push @dirty, grep { !$self->_config->has($_) && $self->_dirty_config->has($_) } @extra;
|
||||||
|
# Overrides removed from the dirty config:
|
||||||
|
push @dirty, grep { $self->_config->has($_) && !$self->_dirty_config->has($_) } @extra;
|
||||||
|
|
||||||
|
return @dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dirty {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
return !!$self->dirty_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dropdown_name {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my $name = $self->name;
|
||||||
|
$name .= " (modified)" if $self->dirty;
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub file_exists {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
die "Can't call file_exists() on a non-file preset" if !$self->file;
|
||||||
|
return -e Slic3r::encode_path($self->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub rename {
|
||||||
|
my ($self, $name) = @_;
|
||||||
|
|
||||||
|
$self->name($name);
|
||||||
|
$self->file(sprintf "$Slic3r::GUI::datadir/%s/%s.ini", $self->group, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prompt_unsaved_changes {
|
||||||
|
my ($self, $parent) = @_;
|
||||||
|
|
||||||
|
if ($self->dirty) {
|
||||||
|
my $name = $self->default ? 'Default preset' : "Preset \"" . $self->name . "\"";
|
||||||
|
|
||||||
|
my $opts = '';
|
||||||
|
foreach my $opt_key ($self->dirty_options) {
|
||||||
|
my $opt = $Slic3r::Config::Options->{$opt_key};
|
||||||
|
my $name = $opt->{full_label} // $opt->{label};
|
||||||
|
if ($opt->{category}) {
|
||||||
|
$name = $opt->{category} . " > $name";
|
||||||
|
}
|
||||||
|
$opts .= "- $name\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $msg = sprintf "%s has unsaved changes:\n%s\nDo you want to save them?", $name, $opts;
|
||||||
|
my $confirm = Wx::MessageDialog->new($parent, $msg,
|
||||||
|
'Unsaved Changes', wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_QUESTION);
|
||||||
|
$confirm->SetYesNoCancelLabels('Save', 'Discard', 'Cancel');
|
||||||
|
my $res = $confirm->ShowModal;
|
||||||
|
|
||||||
|
if ($res == wxID_CANCEL) {
|
||||||
|
return 0;
|
||||||
|
} elsif ($res == wxID_YES) {
|
||||||
|
return $self->save($self->default ? undef : $self->name);
|
||||||
|
} elsif ($res == wxID_NO) {
|
||||||
|
$self->dismiss_changes;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub save {
|
||||||
|
my ($self, $name, $parent) = @_;
|
||||||
|
|
||||||
|
if (!$name) {
|
||||||
|
my $default_name = $self->default ? 'Untitled' : $self->name;
|
||||||
|
$default_name =~ s/\.ini$//i;
|
||||||
|
|
||||||
|
my $dlg = Slic3r::GUI::SavePresetWindow->new($parent,
|
||||||
|
default => $default_name,
|
||||||
|
values => [ map $_->name, grep !$_->default && !$_->external, @{wxTheApp->presets->{$self->name}} ],
|
||||||
|
);
|
||||||
|
return 0 unless $dlg->ShowModal == wxID_OK;
|
||||||
|
$name = $dlg->get_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->rename($name);
|
||||||
|
|
||||||
|
if (!$self->file) {
|
||||||
|
die "Calling save() without setting filename";
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->_config->clear;
|
||||||
|
$self->_config->apply($self->_dirty_config);
|
||||||
|
$self->_config->save($self->file);
|
||||||
|
wxTheApp->load_presets;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dismiss_changes {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
$self->_dirty_config->clear;
|
||||||
|
$self->_dirty_config->apply($self->_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub delete {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
die "Default config can't be deleted" if $self->default;
|
||||||
|
die "External configs can't be deleted" if $self->external;
|
||||||
|
|
||||||
|
# Otherwise wxTheApp->load_presets() will keep it
|
||||||
|
$self->dismiss_changes;
|
||||||
|
|
||||||
|
if ($self->file) {
|
||||||
|
unlink Slic3r::encode_path($self->file) if $self->file_exists;
|
||||||
|
$self->file(undef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# This returns the loaded config with the dirty options applied.
|
||||||
|
sub dirty_config {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
$self->load_config if !$self->_loaded;
|
||||||
|
|
||||||
|
return $self->_dirty_config->clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_config {
|
sub load_config {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
return Slic3r::Config->load($self->file);
|
my @keys = $self->_group_class->options;
|
||||||
|
my @extra_keys = $self->_group_class->overriding_options;
|
||||||
|
|
||||||
|
if ($self->default) {
|
||||||
|
$self->_config(Slic3r::Config->new_from_defaults(@keys));
|
||||||
|
} elsif ($self->file) {
|
||||||
|
if (!$self->file_exists) {
|
||||||
|
Slic3r::GUI::show_error(undef, "The selected preset does not exist anymore (" . $self->file . ").");
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
my $external_config = Slic3r::Config->load($self->file);
|
||||||
|
if (!@keys) {
|
||||||
|
$self->_config($external_config);
|
||||||
|
} else {
|
||||||
|
# apply preset values on top of defaults
|
||||||
|
my $config = Slic3r::Config->new_from_defaults(@keys);
|
||||||
|
$config->set($_, $external_config->get($_))
|
||||||
|
for grep $external_config->has($_), @keys;
|
||||||
|
|
||||||
|
# For extra_keys we don't populate defaults.
|
||||||
|
if (@extra_keys && !$self->external) {
|
||||||
|
$config->set($_, $external_config->get($_))
|
||||||
|
for grep $external_config->has($_), @extra_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->_config($config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->_dirty_config->apply($self->_config);
|
||||||
|
|
||||||
|
return $self->_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _group_class {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
return "Slic3r::GUI::PresetEditor::".ucfirst $self->group;
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -10,13 +10,15 @@ use Wx qw(:bookctrl :dialog :keycode :icon :id :misc :panel :sizer :treectrl :wi
|
|||||||
use Wx::Event qw(EVT_BUTTON EVT_CHOICE EVT_KEY_DOWN EVT_TREE_SEL_CHANGED);
|
use Wx::Event qw(EVT_BUTTON EVT_CHOICE EVT_KEY_DOWN EVT_TREE_SEL_CHANGED);
|
||||||
use base qw(Wx::Panel Class::Accessor);
|
use base qw(Wx::Panel Class::Accessor);
|
||||||
|
|
||||||
__PACKAGE__->mk_accessors(qw(current_preset));
|
__PACKAGE__->mk_accessors(qw(current_preset config));
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my ($parent, %params) = @_;
|
my ($parent, %params) = @_;
|
||||||
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
|
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
|
||||||
|
|
||||||
|
$self->{presets} = wxTheApp->presets->{$self->name};
|
||||||
|
|
||||||
# horizontal sizer
|
# horizontal sizer
|
||||||
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
|
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
|
||||||
#$self->{sizer}->SetSizeHints($self);
|
#$self->{sizer}->SetSizeHints($self);
|
||||||
@ -91,78 +93,39 @@ sub new {
|
|||||||
EVT_BUTTON($self, $self->{btn_save_preset}, sub { $self->save_preset });
|
EVT_BUTTON($self, $self->{btn_save_preset}, sub { $self->save_preset });
|
||||||
|
|
||||||
EVT_BUTTON($self, $self->{btn_delete_preset}, sub {
|
EVT_BUTTON($self, $self->{btn_delete_preset}, sub {
|
||||||
my $i = $self->current_preset;
|
|
||||||
return if $i == 0; # this shouldn't happen but let's trap it anyway
|
|
||||||
my $res = Wx::MessageDialog->new($self, "Are you sure you want to delete the selected preset?", 'Delete Preset', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION)->ShowModal;
|
my $res = Wx::MessageDialog->new($self, "Are you sure you want to delete the selected preset?", 'Delete Preset', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION)->ShowModal;
|
||||||
return unless $res == wxID_YES;
|
return unless $res == wxID_YES;
|
||||||
if (-e $self->{presets}[$i]->file) {
|
|
||||||
unlink $self->{presets}[$i]->file;
|
$self->current_preset->delete;
|
||||||
}
|
|
||||||
splice @{$self->{presets}}, $i, 1;
|
|
||||||
$self->{presets_choice}->Delete($i);
|
|
||||||
$self->current_preset(undef);
|
$self->current_preset(undef);
|
||||||
$self->select_preset(0);
|
wxTheApp->load_presets;
|
||||||
|
$self->load_presets;
|
||||||
|
$self->select_preset(0, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
# C++ instance DynamicPrintConfig
|
$self->config(Slic3r::Config->new_from_defaults($self->options));
|
||||||
$self->{config} = Slic3r::Config->new;
|
|
||||||
# Initialize the DynamicPrintConfig by default keys/values.
|
|
||||||
$self->{config}->apply(Slic3r::Config->new_from_defaults($self->options));
|
|
||||||
|
|
||||||
|
$self->build;
|
||||||
|
|
||||||
# Possible %params keys: no_controller
|
|
||||||
$self->build(%params);
|
|
||||||
$self->update_tree;
|
$self->update_tree;
|
||||||
|
$self->load_presets;
|
||||||
$self->_update;
|
$self->_update;
|
||||||
if ($self->hidden_options) {
|
|
||||||
$self->{config}->apply(Slic3r::Config->new_from_defaults($self->hidden_options));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_current_preset {
|
# This is called by the save button.
|
||||||
my $self = shift;
|
|
||||||
return $self->get_preset($self->current_preset);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_current_preset_config {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
return $self->get_preset_config($self->get_current_preset);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_preset {
|
|
||||||
my ($self, $i) = @_;
|
|
||||||
return $self->{presets}[$i];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub save_preset {
|
sub save_preset {
|
||||||
my ($self, $name) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
# since buttons (and choices too) don't get focus on Mac, we set focus manually
|
# since buttons (and choices too) don't get focus on Mac, we set focus manually
|
||||||
# to the treectrl so that the EVT_* events are fired for the input field having
|
# to the treectrl so that the EVT_* events are fired for the input field having
|
||||||
# focus currently. is there anything better than this?
|
# focus currently. is there anything better than this?
|
||||||
$self->{treectrl}->SetFocus;
|
$self->{treectrl}->SetFocus;
|
||||||
|
|
||||||
if (!defined $name) {
|
my $preset = $self->current_preset;
|
||||||
my $preset = $self->get_current_preset;
|
$preset->save(undef, $self);
|
||||||
my $default_name = $preset->default ? 'Untitled' : $preset->name;
|
|
||||||
$default_name =~ s/\.ini$//i;
|
|
||||||
|
|
||||||
my $dlg = Slic3r::GUI::SavePresetWindow->new($self,
|
|
||||||
title => lc($self->title),
|
|
||||||
default => $default_name,
|
|
||||||
values => [ map $_->name, grep !$_->default && !$_->external, @{$self->{presets}} ],
|
|
||||||
);
|
|
||||||
return 0 unless $dlg->ShowModal == wxID_OK;
|
|
||||||
$name = $dlg->get_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->config->save(sprintf "$Slic3r::GUI::datadir/%s/%s.ini", $self->name, $name);
|
|
||||||
$self->load_presets;
|
$self->load_presets;
|
||||||
$self->select_preset_by_name($name);
|
$self->select_preset_by_name($preset->name);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -176,17 +139,17 @@ sub on_value_change {
|
|||||||
# or changed by user (so also when a preset is loaded).
|
# or changed by user (so also when a preset is loaded).
|
||||||
# propagate event to the parent
|
# propagate event to the parent
|
||||||
sub _on_value_change {
|
sub _on_value_change {
|
||||||
my $self = shift;
|
my ($self, $opt_key) = @_;
|
||||||
|
|
||||||
$self->{on_value_change}->(@_) if $self->{on_value_change};
|
$self->current_preset->_dirty_config->apply($self->config);
|
||||||
|
$self->{on_value_change}->($opt_key) if $self->{on_value_change};
|
||||||
|
$self->load_presets;
|
||||||
$self->_update;
|
$self->_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _update {}
|
sub _update {}
|
||||||
|
|
||||||
sub on_preset_loaded {}
|
sub on_preset_loaded {}
|
||||||
sub hidden_options {}
|
|
||||||
sub config { $_[0]->{config}->clone }
|
|
||||||
|
|
||||||
sub select_preset {
|
sub select_preset {
|
||||||
my ($self, $i, $force) = @_;
|
my ($self, $i, $force) = @_;
|
||||||
@ -198,62 +161,54 @@ sub select_preset {
|
|||||||
sub select_preset_by_name {
|
sub select_preset_by_name {
|
||||||
my ($self, $name, $force) = @_;
|
my ($self, $name, $force) = @_;
|
||||||
|
|
||||||
my $i = first { $self->{presets}[$_]->name eq $name } 0 .. $#{$self->{presets}};
|
my $presets = wxTheApp->presets->{$self->name};
|
||||||
return if !defined $i;
|
my $i = first { $presets->[$_]->name eq $name } 0..$#$presets;
|
||||||
$self->select_preset($i, $force);
|
$self->{presets_choice}->SetSelection($i);
|
||||||
|
$self->on_select_preset($force);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub prompt_unsaved_changes {
|
sub prompt_unsaved_changes {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
if ($self->is_dirty) {
|
return 1 if !$self->current_preset;
|
||||||
my $old_preset = $self->get_current_preset;
|
return $self->current_preset->prompt_unsaved_changes($self);
|
||||||
my $name = $old_preset->default ? 'Default preset' : "Preset \"" . $old_preset->name . "\"";
|
|
||||||
|
|
||||||
my @option_names = ();
|
|
||||||
foreach my $opt_key (@{$self->dirty_options}) {
|
|
||||||
my $opt = $Slic3r::Config::Options->{$opt_key};
|
|
||||||
my $name = $opt->{full_label} // $opt->{label};
|
|
||||||
if ($opt->{category}) {
|
|
||||||
$name = $opt->{category} . " > $name";
|
|
||||||
}
|
|
||||||
push @option_names, $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $changes = join "\n", map "- $_", @option_names;
|
|
||||||
my $confirm = Wx::MessageDialog->new($self, "$name has unsaved changes:\n$changes\n\nDo you want to save them?",
|
|
||||||
'Unsaved Changes', wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_QUESTION);
|
|
||||||
$confirm->SetYesNoCancelLabels('Save', 'Discard', 'Cancel');
|
|
||||||
my $res = $confirm->ShowModal;
|
|
||||||
|
|
||||||
if ($res == wxID_CANCEL) {
|
|
||||||
return 0;
|
|
||||||
} elsif ($res == wxID_YES) {
|
|
||||||
return $self->save_preset($old_preset->default ? undef : $old_preset->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub on_select_preset {
|
sub on_select_preset {
|
||||||
my ($self, $force) = @_;
|
my ($self, $force) = @_;
|
||||||
|
|
||||||
my $i = $self->{presets_choice}->GetSelection;
|
# This method is called:
|
||||||
return if defined $self->current_preset && $i == $self->current_preset;
|
# - upon first initialization;
|
||||||
|
# - whenever user selects a preset from the dropdown;
|
||||||
|
# - whenever select_preset() or select_preset_by_name() are called.
|
||||||
|
|
||||||
if (!$force && defined $self->current_preset && !$self->prompt_unsaved_changes) {
|
# Get the selected name.
|
||||||
$self->{presets_choice}->SetSelection($self->current_preset);
|
my $preset = wxTheApp->presets->{$self->name}->[$self->{presets_choice}->GetSelection];
|
||||||
|
|
||||||
|
# If selection didn't change, do nothing.
|
||||||
|
return if defined $self->current_preset && $preset->name eq $self->current_preset->name;
|
||||||
|
|
||||||
|
# If we have unsaved changes, prompt user.
|
||||||
|
if (!$force && !$self->prompt_unsaved_changes) {
|
||||||
|
# User decided not to save the current changes, so we restore the previous selection.
|
||||||
|
my $presets = wxTheApp->presets->{$self->name};
|
||||||
|
my $i = first { $presets->[$_]->name eq $self->current_preset->name } 0..$#$presets;
|
||||||
|
$self->{presets_choice}->SetSelection($i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->current_preset($i);
|
$self->current_preset($preset);
|
||||||
my $preset = $self->get_current_preset;
|
|
||||||
my $preset_config = $self->get_preset_config($preset);
|
# We reload presets in order to remove the "(modified)" suffix in case user was
|
||||||
|
# prompted and chose to discard changes.
|
||||||
|
$self->load_presets;
|
||||||
|
|
||||||
|
$preset->load_config if !$preset->_loaded;
|
||||||
|
$self->config->clear;
|
||||||
|
$self->config->apply($preset->dirty_config);
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
|
local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
|
||||||
$self->{config}->clear;
|
|
||||||
$self->{config}->apply($preset_config);
|
|
||||||
($preset->default || $preset->external)
|
($preset->default || $preset->external)
|
||||||
? $self->{btn_delete_preset}->Disable
|
? $self->{btn_delete_preset}->Disable
|
||||||
: $self->{btn_delete_preset}->Enable;
|
: $self->{btn_delete_preset}->Enable;
|
||||||
@ -266,14 +221,6 @@ sub on_select_preset {
|
|||||||
$@ = "I was unable to load the selected config file: $@";
|
$@ = "I was unable to load the selected config file: $@";
|
||||||
Slic3r::GUI::catch_error($self);
|
Slic3r::GUI::catch_error($self);
|
||||||
}
|
}
|
||||||
|
|
||||||
# use CallAfter because some field triggers schedule on_change calls using CallAfter,
|
|
||||||
# and we don't want them to be called after this update_dirty() as they would mark the
|
|
||||||
# preset dirty again
|
|
||||||
# (not sure this is true anymore now that update_dirty is idempotent)
|
|
||||||
wxTheApp->CallAfter(sub {
|
|
||||||
$self->update_dirty;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub add_options_page {
|
sub add_options_page {
|
||||||
@ -323,89 +270,35 @@ sub update_tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub update_dirty {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
foreach my $i (0..$#{$self->{presets}}) {
|
|
||||||
my $preset = $self->get_preset($i);
|
|
||||||
if ($i == $self->current_preset && $self->is_dirty) {
|
|
||||||
$self->{presets_choice}->SetString($i, $preset->name . " (modified)");
|
|
||||||
} else {
|
|
||||||
$self->{presets_choice}->SetString($i, $preset->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$self->{presets_choice}->SetSelection($self->current_preset); # http://trac.wxwidgets.org/ticket/13769
|
|
||||||
}
|
|
||||||
|
|
||||||
sub is_dirty {
|
|
||||||
my $self = shift;
|
|
||||||
return @{$self->dirty_options} > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub dirty_options {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
return [] if !defined $self->current_preset; # happens during initialization
|
|
||||||
|
|
||||||
my $preset_config = $self->get_current_preset_config;
|
|
||||||
return [
|
|
||||||
(grep !$preset_config->has($_), @{$self->{config}->get_keys}),
|
|
||||||
(grep !$self->{config}->has($_), @{$preset_config->get_keys}),
|
|
||||||
@{ $self->{config}->diff($self->get_current_preset_config) },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
sub load_presets {
|
sub load_presets {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->{presets} = [ wxTheApp->presets($self->name, 1) ];
|
my $presets = wxTheApp->presets->{$self->name};
|
||||||
$self->current_preset(undef);
|
|
||||||
$self->{presets_choice}->Clear;
|
$self->{presets_choice}->Clear;
|
||||||
$self->{presets_choice}->Append($_->name) for @{$self->{presets}};
|
foreach my $preset (@$presets) {
|
||||||
$self->select_preset(0);
|
$self->{presets_choice}->Append($preset->dropdown_name);
|
||||||
|
|
||||||
|
# Preserve selection.
|
||||||
|
if ($self->current_preset && $self->current_preset->name eq $preset->name) {
|
||||||
|
$self->{presets_choice}->SetSelection($self->{presets_choice}->GetCount-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_config_file {
|
# This is called internally whenever we make automatic adjustments to configuration
|
||||||
my $self = shift;
|
# based on user actions.
|
||||||
my ($file) = @_;
|
sub _load_config {
|
||||||
|
|
||||||
# look for the loaded config among the existing menu items
|
|
||||||
my $i = first { $self->{presets}[$_]{file} eq $file && $self->{presets}[$_]{external} } 1..$#{$self->{presets}};
|
|
||||||
if (!$i) {
|
|
||||||
my $preset_name = basename($file); # keep the .ini suffix
|
|
||||||
push @{$self->{presets}}, Slic3r::GUI::Preset->new(
|
|
||||||
file => $file,
|
|
||||||
name => $preset_name,
|
|
||||||
external => 1,
|
|
||||||
);
|
|
||||||
$self->{presets_choice}->Append($preset_name);
|
|
||||||
$i = $#{$self->{presets}};
|
|
||||||
}
|
|
||||||
$self->{presets_choice}->SetSelection($i);
|
|
||||||
$self->on_select_preset;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub load_config {
|
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($config) = @_;
|
my ($config) = @_;
|
||||||
|
|
||||||
foreach my $opt_key (@{$self->{config}->diff($config)}) {
|
my $diff = $self->config->diff($config);
|
||||||
$self->{config}->set($opt_key, $config->get($opt_key));
|
$self->config->set($_, $config->get($_)) for @$diff;
|
||||||
$self->update_dirty;
|
# First apply all changes, then call all the _on_value_change triggers.
|
||||||
}
|
$self->_on_value_change($_) for @$diff;
|
||||||
$self->reload_config;
|
$self->reload_config;
|
||||||
$self->_update;
|
$self->_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_preset_config {
|
|
||||||
my ($self, $preset) = @_;
|
|
||||||
|
|
||||||
return $preset->config(
|
|
||||||
[ $self->options ],
|
|
||||||
[ $self->overriding_options ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_field {
|
sub get_field {
|
||||||
my ($self, $opt_key, $opt_index) = @_;
|
my ($self, $opt_key, $opt_index) = @_;
|
||||||
|
|
||||||
@ -452,16 +345,15 @@ sub _compatible_printers_widget {
|
|||||||
"Compatible printers", \@presets);
|
"Compatible printers", \@presets);
|
||||||
|
|
||||||
my @selections = ();
|
my @selections = ();
|
||||||
foreach my $preset_name (@{ $self->{config}->get('compatible_printers') }) {
|
foreach my $preset_name (@{ $self->config->get('compatible_printers') }) {
|
||||||
push @selections, first { $presets[$_] eq $preset_name } 0..$#presets;
|
push @selections, first { $presets[$_] eq $preset_name } 0..$#presets;
|
||||||
}
|
}
|
||||||
$dlg->SetSelections(@selections);
|
$dlg->SetSelections(@selections);
|
||||||
|
|
||||||
if ($dlg->ShowModal == wxID_OK) {
|
if ($dlg->ShowModal == wxID_OK) {
|
||||||
my $value = [ @presets[$dlg->GetSelections] ];
|
my $value = [ @presets[$dlg->GetSelections] ];
|
||||||
$self->{config}->set('compatible_printers', $value);
|
$self->config->set('compatible_printers', $value);
|
||||||
$self->update_dirty;
|
$self->_on_value_change('compatible_printers');
|
||||||
$self->_on_value_change('compatible_printers', $value);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -554,16 +446,15 @@ sub build {
|
|||||||
[ map $options{$_}, @opt_keys ]);
|
[ map $options{$_}, @opt_keys ]);
|
||||||
|
|
||||||
my @selections = ();
|
my @selections = ();
|
||||||
foreach my $opt_key (@{ $self->{config}->get('overridable') }) {
|
foreach my $opt_key (@{ $self->config->get('overridable') }) {
|
||||||
push @selections, first { $opt_keys[$_] eq $opt_key } 0..$#opt_keys;
|
push @selections, first { $opt_keys[$_] eq $opt_key } 0..$#opt_keys;
|
||||||
}
|
}
|
||||||
$dlg->SetSelections(@selections);
|
$dlg->SetSelections(@selections);
|
||||||
|
|
||||||
if ($dlg->ShowModal == wxID_OK) {
|
if ($dlg->ShowModal == wxID_OK) {
|
||||||
my $value = [ @opt_keys[$dlg->GetSelections] ];
|
my $value = [ @opt_keys[$dlg->GetSelections] ];
|
||||||
$self->{config}->set('overridable', $value);
|
$self->config->set('overridable', $value);
|
||||||
$self->update_dirty;
|
$self->_on_value_change('overridable');
|
||||||
$self->_on_value_change('overridable', $value);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -850,11 +741,11 @@ sub _update {
|
|||||||
$new_conf->set("top_solid_layers", 0);
|
$new_conf->set("top_solid_layers", 0);
|
||||||
$new_conf->set("fill_density", 0);
|
$new_conf->set("fill_density", 0);
|
||||||
$new_conf->set("support_material", 0);
|
$new_conf->set("support_material", 0);
|
||||||
$self->load_config($new_conf);
|
$self->_load_config($new_conf);
|
||||||
} else {
|
} else {
|
||||||
my $new_conf = Slic3r::Config->new;
|
my $new_conf = Slic3r::Config->new;
|
||||||
$new_conf->set("spiral_vase", 0);
|
$new_conf->set("spiral_vase", 0);
|
||||||
$self->load_config($new_conf);
|
$self->_load_config($new_conf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,7 +771,7 @@ sub _update {
|
|||||||
$new_conf->set("support_material", 0);
|
$new_conf->set("support_material", 0);
|
||||||
$self->{support_material_overhangs_queried} = 0;
|
$self->{support_material_overhangs_queried} = 0;
|
||||||
}
|
}
|
||||||
$self->load_config($new_conf);
|
$self->_load_config($new_conf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -900,7 +791,7 @@ sub _update {
|
|||||||
} else {
|
} else {
|
||||||
$new_conf->set("fill_density", 40);
|
$new_conf->set("fill_density", 40);
|
||||||
}
|
}
|
||||||
$self->load_config($new_conf);
|
$self->_load_config($new_conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $have_perimeters = $config->perimeters > 0;
|
my $have_perimeters = $config->perimeters > 0;
|
||||||
@ -975,8 +866,6 @@ sub _update {
|
|||||||
for qw(standby_temperature_delta);
|
for qw(standby_temperature_delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hidden_options { !$Slic3r::have_threads ? qw(threads) : () }
|
|
||||||
|
|
||||||
package Slic3r::GUI::PresetEditor::Filament;
|
package Slic3r::GUI::PresetEditor::Filament;
|
||||||
use base 'Slic3r::GUI::PresetEditor';
|
use base 'Slic3r::GUI::PresetEditor';
|
||||||
|
|
||||||
@ -1150,9 +1039,11 @@ sub build {
|
|||||||
$self->{overrides_panel} = my $panel = Slic3r::GUI::Plater::OverrideSettingsPanel->new($parent,
|
$self->{overrides_panel} = my $panel = Slic3r::GUI::Plater::OverrideSettingsPanel->new($parent,
|
||||||
size => [-1, 300],
|
size => [-1, 300],
|
||||||
on_change => sub {
|
on_change => sub {
|
||||||
$self->{config}->erase($_) for @overridable;
|
my ($opt_key) = @_;
|
||||||
$self->{config}->apply($self->{overrides_config});
|
$self->config->erase($_) for @overridable;
|
||||||
$self->update_dirty;
|
$self->current_preset->_dirty_config->erase($_) for @overridable;
|
||||||
|
$self->config->apply($self->{overrides_config});
|
||||||
|
$self->_on_value_change($opt_key);
|
||||||
});
|
});
|
||||||
$panel->set_editable(1);
|
$panel->set_editable(1);
|
||||||
$panel->set_default_config($self->{overrides_default_config});
|
$panel->set_default_config($self->{overrides_default_config});
|
||||||
@ -1172,8 +1063,8 @@ sub reload_config {
|
|||||||
|
|
||||||
$self->{overrides_config}->clear;
|
$self->{overrides_config}->clear;
|
||||||
foreach my $opt_key (@{$self->{overrides_default_config}->get_keys}) {
|
foreach my $opt_key (@{$self->{overrides_default_config}->get_keys}) {
|
||||||
if ($self->{config}->has($opt_key)) {
|
if ($self->config->has($opt_key)) {
|
||||||
$self->{overrides_config}->set($opt_key, $self->{config}->get($opt_key));
|
$self->{overrides_config}->set($opt_key, $self->config->get($opt_key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$self->{overrides_panel}->update_optgroup;
|
$self->{overrides_panel}->update_optgroup;
|
||||||
@ -1186,10 +1077,10 @@ sub _update {
|
|||||||
|
|
||||||
$self->_update_description;
|
$self->_update_description;
|
||||||
|
|
||||||
my $cooling = $self->{config}->cooling;
|
my $cooling = $self->config->cooling;
|
||||||
$self->get_field($_)->toggle($cooling)
|
$self->get_field($_)->toggle($cooling)
|
||||||
for qw(max_fan_speed fan_below_layer_time slowdown_below_layer_time min_print_speed);
|
for qw(max_fan_speed fan_below_layer_time slowdown_below_layer_time min_print_speed);
|
||||||
$self->get_field($_)->toggle($cooling || $self->{config}->fan_always_on)
|
$self->get_field($_)->toggle($cooling || $self->config->fan_always_on)
|
||||||
for qw(min_fan_speed disable_fan_first_layers);
|
for qw(min_fan_speed disable_fan_first_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1269,12 +1160,11 @@ sub build {
|
|||||||
label => 'Bed shape',
|
label => 'Bed shape',
|
||||||
);
|
);
|
||||||
$line->append_button("Set…", "cog.png", sub {
|
$line->append_button("Set…", "cog.png", sub {
|
||||||
my $dlg = Slic3r::GUI::BedShapeDialog->new($self, $self->{config}->bed_shape);
|
my $dlg = Slic3r::GUI::BedShapeDialog->new($self, $self->config->bed_shape);
|
||||||
if ($dlg->ShowModal == wxID_OK) {
|
if ($dlg->ShowModal == wxID_OK) {
|
||||||
my $value = $dlg->GetValue;
|
my $value = $dlg->GetValue;
|
||||||
$self->{config}->set('bed_shape', $value);
|
$self->config->set('bed_shape', $value);
|
||||||
$self->update_dirty;
|
$self->_on_value_change('bed_shape');
|
||||||
$self->_on_value_change('bed_shape', $value);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$optgroup->append_line($line);
|
$optgroup->append_line($line);
|
||||||
@ -1301,7 +1191,6 @@ sub build {
|
|||||||
wxTheApp->CallAfter(sub {
|
wxTheApp->CallAfter(sub {
|
||||||
$self->_extruders_count_changed($optgroup->get_value('extruders_count'));
|
$self->_extruders_count_changed($optgroup->get_value('extruders_count'));
|
||||||
});
|
});
|
||||||
$self->update_dirty;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1328,8 +1217,8 @@ sub build {
|
|||||||
$line->append_button("Test", "wrench.png", sub {
|
$line->append_button("Test", "wrench.png", sub {
|
||||||
my $sender = Slic3r::GCode::Sender->new;
|
my $sender = Slic3r::GCode::Sender->new;
|
||||||
my $res = $sender->connect(
|
my $res = $sender->connect(
|
||||||
$self->{config}->serial_port,
|
$self->config->serial_port,
|
||||||
$self->{config}->serial_speed,
|
$self->config->serial_speed,
|
||||||
);
|
);
|
||||||
if ($res && $sender->wait_connected) {
|
if ($res && $sender->wait_connected) {
|
||||||
Slic3r::GUI::show_info($self, "Connection to printer works correctly.", "Success!");
|
Slic3r::GUI::show_info($self, "Connection to printer works correctly.", "Success!");
|
||||||
@ -1355,10 +1244,8 @@ sub build {
|
|||||||
my $dlg = Slic3r::GUI::BonjourBrowser->new($self, $entries);
|
my $dlg = Slic3r::GUI::BonjourBrowser->new($self, $entries);
|
||||||
if ($dlg->ShowModal == wxID_OK) {
|
if ($dlg->ShowModal == wxID_OK) {
|
||||||
my $value = $dlg->GetValue . ":" . $dlg->GetPort;
|
my $value = $dlg->GetValue . ":" . $dlg->GetPort;
|
||||||
$self->{config}->set('octoprint_host', $value);
|
$self->config->set('octoprint_host', $value);
|
||||||
$self->update_dirty;
|
$self->_on_value_change('octoprint_host');
|
||||||
$self->_on_value_change('octoprint_host', $value);
|
|
||||||
$self->reload_config;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Wx::MessageDialog->new($self, 'No Bonjour device found', 'Device Browser', wxOK | wxICON_INFORMATION)->ShowModal;
|
Wx::MessageDialog->new($self, 'No Bonjour device found', 'Device Browser', wxOK | wxICON_INFORMATION)->ShowModal;
|
||||||
@ -1369,8 +1256,8 @@ sub build {
|
|||||||
$ua->timeout(10);
|
$ua->timeout(10);
|
||||||
|
|
||||||
my $res = $ua->get(
|
my $res = $ua->get(
|
||||||
"http://" . $self->{config}->octoprint_host . "/api/version",
|
"http://" . $self->config->octoprint_host . "/api/version",
|
||||||
'X-Api-Key' => $self->{config}->octoprint_apikey,
|
'X-Api-Key' => $self->config->octoprint_apikey,
|
||||||
);
|
);
|
||||||
if ($res->is_success) {
|
if ($res->is_success) {
|
||||||
Slic3r::GUI::show_info($self, "Connection to OctoPrint works correctly.", "Success!");
|
Slic3r::GUI::show_info($self, "Connection to OctoPrint works correctly.", "Success!");
|
||||||
@ -1462,7 +1349,7 @@ sub _extruders_count_changed {
|
|||||||
|
|
||||||
$self->{extruders_count} = $extruders_count;
|
$self->{extruders_count} = $extruders_count;
|
||||||
$self->_build_extruder_pages;
|
$self->_build_extruder_pages;
|
||||||
$self->_on_value_change('extruders_count', $extruders_count);
|
$self->_on_value_change('extruders_count');
|
||||||
$self->_update;
|
$self->_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1477,7 +1364,7 @@ sub _build_extruder_pages {
|
|||||||
foreach my $extruder_idx (@{$self->{extruder_pages}} .. $self->{extruders_count}-1) {
|
foreach my $extruder_idx (@{$self->{extruder_pages}} .. $self->{extruders_count}-1) {
|
||||||
# extend options
|
# extend options
|
||||||
foreach my $opt_key ($self->_extruder_options) {
|
foreach my $opt_key ($self->_extruder_options) {
|
||||||
my $values = $self->{config}->get($opt_key);
|
my $values = $self->config->get($opt_key);
|
||||||
if (!defined $values) {
|
if (!defined $values) {
|
||||||
$values = [ $default_config->get_at($opt_key, 0) ];
|
$values = [ $default_config->get_at($opt_key, 0) ];
|
||||||
} else {
|
} else {
|
||||||
@ -1485,7 +1372,7 @@ sub _build_extruder_pages {
|
|||||||
my $last_value = $values->[-1];
|
my $last_value = $values->[-1];
|
||||||
$values->[$extruder_idx] //= $last_value;
|
$values->[$extruder_idx] //= $last_value;
|
||||||
}
|
}
|
||||||
$self->{config}->set($opt_key, $values)
|
$self->config->set($opt_key, $values)
|
||||||
or die "Unable to extend $opt_key";
|
or die "Unable to extend $opt_key";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1531,9 +1418,9 @@ sub _build_extruder_pages {
|
|||||||
|
|
||||||
# remove extra config values
|
# remove extra config values
|
||||||
foreach my $opt_key ($self->_extruder_options) {
|
foreach my $opt_key ($self->_extruder_options) {
|
||||||
my $values = $self->{config}->get($opt_key);
|
my $values = $self->config->get($opt_key);
|
||||||
splice @$values, $self->{extruders_count} if $self->{extruders_count} <= $#$values;
|
splice @$values, $self->{extruders_count} if $self->{extruders_count} <= $#$values;
|
||||||
$self->{config}->set($opt_key, $values)
|
$self->config->set($opt_key, $values)
|
||||||
or die "Unable to truncate $opt_key";
|
or die "Unable to truncate $opt_key";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1610,7 +1497,7 @@ sub _update {
|
|||||||
} else {
|
} else {
|
||||||
$new_conf->set("use_firmware_retraction", 0);
|
$new_conf->set("use_firmware_retraction", 0);
|
||||||
}
|
}
|
||||||
$self->load_config($new_conf);
|
$self->_load_config($new_conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->get_field('retract_length_toolchange', $i)->toggle($have_multiple_extruders);
|
$self->get_field('retract_length_toolchange', $i)->toggle($have_multiple_extruders);
|
||||||
@ -1628,7 +1515,7 @@ sub on_preset_loaded {
|
|||||||
# update the extruders count field
|
# update the extruders count field
|
||||||
{
|
{
|
||||||
# update the GUI field according to the number of nozzle diameters supplied
|
# update the GUI field according to the number of nozzle diameters supplied
|
||||||
my $extruders_count = scalar @{ $self->{config}->nozzle_diameter };
|
my $extruders_count = scalar @{ $self->config->nozzle_diameter };
|
||||||
$self->set_value('extruders_count', $extruders_count);
|
$self->set_value('extruders_count', $extruders_count);
|
||||||
$self->_extruders_count_changed($extruders_count);
|
$self->_extruders_count_changed($extruders_count);
|
||||||
}
|
}
|
||||||
@ -1642,7 +1529,7 @@ sub load_config_file {
|
|||||||
"Your configuration was imported. However, Slic3r is currently only able to import settings "
|
"Your configuration was imported. However, Slic3r is currently only able to import settings "
|
||||||
. "for the first defined filament. We recommend you don't use exported configuration files "
|
. "for the first defined filament. We recommend you don't use exported configuration files "
|
||||||
. "for multi-extruder setups and rely on the built-in preset management system instead.")
|
. "for multi-extruder setups and rely on the built-in preset management system instead.")
|
||||||
if @{ $self->{config}->nozzle_diameter } > 1;
|
if @{ $self->config->nozzle_diameter } > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
package Slic3r::GUI::PresetEditor::Page;
|
package Slic3r::GUI::PresetEditor::Page;
|
||||||
@ -1676,8 +1563,7 @@ sub new_optgroup {
|
|||||||
on_change => sub {
|
on_change => sub {
|
||||||
my ($opt_key, $value) = @_;
|
my ($opt_key, $value) = @_;
|
||||||
wxTheApp->CallAfter(sub {
|
wxTheApp->CallAfter(sub {
|
||||||
$self->GetParent->update_dirty;
|
$self->GetParent->_on_value_change($opt_key);
|
||||||
$self->GetParent->_on_value_change($opt_key, $value);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1726,7 +1612,7 @@ sub new {
|
|||||||
|
|
||||||
my @values = @{$params{values}};
|
my @values = @{$params{values}};
|
||||||
|
|
||||||
my $text = Wx::StaticText->new($self, -1, "Save " . lc($params{title}) . " as:", wxDefaultPosition, wxDefaultSize);
|
my $text = Wx::StaticText->new($self, -1, "Save profile as:", wxDefaultPosition, wxDefaultSize);
|
||||||
$self->{combo} = Wx::ComboBox->new($self, -1, $params{default}, wxDefaultPosition, wxDefaultSize, \@values,
|
$self->{combo} = Wx::ComboBox->new($self, -1, $params{default}, wxDefaultPosition, wxDefaultSize, \@values,
|
||||||
wxTE_PROCESS_ENTER);
|
wxTE_PROCESS_ENTER);
|
||||||
my $buttons = $self->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
my $buttons = $self->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package Slic3r::GUI::PresetEditorDialog;
|
package Slic3r::GUI::PresetEditorDialog;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Wx qw(:dialog :id :misc :sizer :button :icon wxTheApp);
|
use Wx qw(:dialog :id :misc :sizer :button :icon wxTheApp WXK_ESCAPE);
|
||||||
use Wx::Event qw(EVT_CLOSE);
|
use Wx::Event qw(EVT_CLOSE EVT_CHAR_HOOK);
|
||||||
use base qw(Wx::Dialog Class::Accessor);
|
use base qw(Wx::Dialog Class::Accessor);
|
||||||
use utf8;
|
use utf8;
|
||||||
|
|
||||||
@ -15,7 +15,6 @@ sub new {
|
|||||||
|
|
||||||
$self->preset_editor($self->preset_editor_class->new($self));
|
$self->preset_editor($self->preset_editor_class->new($self));
|
||||||
$self->SetTitle($self->preset_editor->title);
|
$self->SetTitle($self->preset_editor->title);
|
||||||
$self->preset_editor->load_presets;
|
|
||||||
|
|
||||||
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
|
||||||
$sizer->Add($self->preset_editor, 1, wxEXPAND);
|
$sizer->Add($self->preset_editor, 1, wxEXPAND);
|
||||||
@ -24,23 +23,32 @@ sub new {
|
|||||||
#$sizer->SetSizeHints($self);
|
#$sizer->SetSizeHints($self);
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
# This does not call the EVT_CLOSE below
|
|
||||||
my $buttons = $self->CreateStdDialogButtonSizer(wxCLOSE);
|
my $buttons = $self->CreateStdDialogButtonSizer(wxCLOSE);
|
||||||
$sizer->Add($buttons, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
$sizer->Add($buttons, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxTheApp->restore_window_pos($self, "preset_editor");
|
||||||
|
|
||||||
EVT_CLOSE($self, sub {
|
EVT_CLOSE($self, sub {
|
||||||
my (undef, $event) = @_;
|
my (undef, $event) = @_;
|
||||||
|
|
||||||
if ($event->CanVeto && !$self->preset_editor->prompt_unsaved_changes) {
|
# save window size
|
||||||
$event->Veto;
|
wxTheApp->save_window_pos($self, "preset_editor");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# propagate event
|
# propagate event
|
||||||
$event->Skip;
|
$event->Skip;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EVT_CHAR_HOOK($self, sub {
|
||||||
|
my (undef, $event) = @_;
|
||||||
|
|
||||||
|
if ($event->GetKeyCode == WXK_ESCAPE) {
|
||||||
|
$self->Close;
|
||||||
|
} else {
|
||||||
|
$event->Skip;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,6 +532,11 @@ DynamicConfig::clear() {
|
|||||||
this->options.clear();
|
this->options.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicConfig::empty() const {
|
||||||
|
return this->options.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra)
|
DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra)
|
||||||
{
|
{
|
||||||
|
@ -678,6 +678,7 @@ class DynamicConfig : public virtual ConfigBase
|
|||||||
t_config_option_keys keys() const;
|
t_config_option_keys keys() const;
|
||||||
void erase(const t_config_option_key &opt_key);
|
void erase(const t_config_option_key &opt_key);
|
||||||
void clear();
|
void clear();
|
||||||
|
bool empty() const;
|
||||||
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra);
|
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra);
|
||||||
void read_cli(const int argc, const char **argv, t_config_option_keys* extra);
|
void read_cli(const int argc, const char **argv, t_config_option_keys* extra);
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
%name{get_keys} std::vector<std::string> keys();
|
%name{get_keys} std::vector<std::string> keys();
|
||||||
void erase(t_config_option_key opt_key);
|
void erase(t_config_option_key opt_key);
|
||||||
void clear();
|
void clear();
|
||||||
|
bool empty();
|
||||||
void normalize();
|
void normalize();
|
||||||
%name{setenv} void setenv_();
|
%name{setenv} void setenv_();
|
||||||
double min_object_distance();
|
double min_object_distance();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user