123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- package Slic3r::GUI::Preset;
- use Moo;
- use Unicode::Normalize;
- use Wx qw(:dialog :icon :id wxTheApp);
- has 'group' => (is => 'ro', required => 1);
- has 'default' => (is => 'ro', default => sub { 0 });
- has 'external' => (is => 'ro', default => sub { 0 });
- has 'name' => (is => 'rw', required => 1);
- 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 {
- my ($self) = @_;
-
- $self->name(Unicode::Normalize::NFC($self->name));
- }
- sub _loaded {
- my ($self) = @_;
-
- return !$self->_config->empty;
- }
- 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->default ? $self->save_prompt($parent) : $self->save;
- } elsif ($res == wxID_NO) {
- $self->dismiss_changes;
- return 1;
- }
- }
-
- return 1;
- }
- sub save_prompt {
- my ($self, $parent) = @_;
-
- 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;
-
- $self->save_as($dlg->get_name);
- }
- sub save {
- my ($self, $opt_keys) = @_;
-
- return $self->save_as($self->name, $opt_keys);
- }
- sub save_as {
- my ($self, $name, $opt_keys) = @_;
-
- $self->rename($name);
-
- if (!$self->file) {
- die "Calling save() without setting filename";
- }
-
- if ($opt_keys) {
- $self->_config->apply_only($self->_dirty_config, $opt_keys);
- } else {
- $self->_config->clear;
- $self->_config->apply($self->_dirty_config);
- }
-
- # unlink the file first to avoid problems on case-insensitive file systems
- unlink Slic3r::encode_path($self->file);
- $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 {
- my ($self) = @_;
-
- return $self->_config if $self->_loaded;
-
- 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;
|