# Extends C++ class Slic3r::DynamicPrintConfig # This perl class does not keep any perl class variables, # all the storage is handled by the underlying C++ code. package Slic3r::Config; use strict; use warnings; use utf8; use List::Util qw(first max); # C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes. # The C++ counterpart is a constant singleton. our $Options = print_config_def(); # overwrite the hard-coded readonly value (this information is not available in XS) $Options->{threads}{readonly} = !$Slic3r::have_threads; # generate accessors { no strict 'refs'; for my $opt_key (keys %$Options) { *{$opt_key} = sub { $_[0]->get($opt_key) }; } } # From command line parameters, used by slic3r.pl sub new_from_cli { my $class = shift; my %args = @_; # Delete hash keys with undefined value. delete $args{$_} for grep !defined $args{$_}, keys %args; # Replace the start_gcode, end_gcode ... hash values # with the content of the files they reference. for (qw(start end layer toolchange)) { my $opt_key = "${_}_gcode"; if ($args{$opt_key}) { if (-e $args{$opt_key}) { Slic3r::open(\my $fh, "<", $args{$opt_key}) or die "Failed to open $args{$opt_key}\n"; binmode $fh, ':utf8'; $args{$opt_key} = do { local $/; <$fh> }; close $fh; } } } my $self = $class->new; foreach my $opt_key (keys %args) { my $opt_def = $Options->{$opt_key}; # we use set_deserialize() for bool options since GetOpt::Long doesn't handle # arrays of boolean values if ($opt_key =~ /^(?:bed_shape|duplicate_grid|extruder_offset)$/ || $opt_def->{type} eq 'bool') { $self->set_deserialize($opt_key, $args{$opt_key}); } elsif (my $shortcut = $opt_def->{shortcut}) { $self->set($_, $args{$opt_key}) for @$shortcut; } else { $self->set($opt_key, $args{$opt_key}); } } return $self; } # CLASS METHODS: # Write a "Windows" style ini file with categories enclosed in squre brackets. # Used by config-bundle-to-config.pl and to save slic3r.ini. sub write_ini { my $class = shift; my ($file, $ini) = @_; Slic3r::open(\my $fh, '>', $file); binmode $fh, ':utf8'; my $localtime = localtime; printf $fh "# generated by Slic3r $Slic3r::VERSION on %s\n", "$localtime"; # make sure the _ category is the first one written foreach my $category (sort { ($a eq '_') ? -1 : ($a cmp $b) } keys %$ini) { printf $fh "\n[%s]\n", $category if $category ne '_'; foreach my $key (sort keys %{$ini->{$category}}) { printf $fh "%s = %s\n", $key, $ini->{$category}{$key}; } } close $fh; } # Parse a "Windows" style ini file with categories enclosed in squre brackets. # Returns a hash of hashes over strings. # {category}{name}=value # Non-categorized entries are stored under a category '_'. # Used by config-bundle-to-config.pl and to read slic3r.ini. sub read_ini { my $class = shift; my ($file) = @_; local $/ = "\n"; Slic3r::open(\my $fh, '<', $file) or die "Unable to open $file: $!\n"; binmode $fh, ':utf8'; my $ini = { _ => {} }; my $category = '_'; while (<$fh>) { s/\R+$//; next if /^\s+/; next if /^$/; next if /^\s*#/; if (/^\[(.+?)\]$/) { $category = $1; next; } /^(\w+) *= *(.*)/ or die "Unreadable configuration file (invalid data at line $.)\n"; $ini->{$category}{$1} = $2; } close $fh; return $ini; } package Slic3r::Config::Static; use parent 'Slic3r::Config'; sub Slic3r::Config::GCode::new { Slic3r::Config::Static::new_GCodeConfig } sub Slic3r::Config::Print::new { Slic3r::Config::Static::new_PrintConfig } sub Slic3r::Config::PrintObject::new { Slic3r::Config::Static::new_PrintObjectConfig } sub Slic3r::Config::PrintRegion::new { Slic3r::Config::Static::new_PrintRegionConfig } sub Slic3r::Config::Full::new { Slic3r::Config::Static::new_FullPrintConfig } 1;