From 9836e963a5bc197dc09b6496e408ddbe00e93a9b Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 21 Dec 2013 21:06:45 +0100 Subject: [PATCH] Incomplete work for adapting the application to the new XS-based Config --- lib/Slic3r/Config.pm | 113 ++++++++++++----------------------------- slic3r.pl | 4 +- xs/src/Config.cpp | 25 ++++++--- xs/src/Config.hpp | 28 ++++++++-- xs/src/PrintConfig.hpp | 2 +- xs/t/15_config.t | 13 ++++- xs/xsp/Config.xsp | 112 +++++++++++++++++++++++++++++++++++++++- xs/xsp/typemap.xspt | 1 + 8 files changed, 200 insertions(+), 98 deletions(-) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index adf83bec2..ba45bfa92 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -1151,35 +1151,22 @@ END }, }; +$Options = print_config_def(); + # generate accessors -if (eval "use Class::XSAccessor; 1") { - Class::XSAccessor->import( - getters => { map { $_ => $_ } keys %$Options }, - ); -} else { +{ no strict 'refs'; for my $opt_key (keys %$Options) { - *{$opt_key} = sub { $_[0]{$opt_key} }; + *{$opt_key} = sub { $_[0]->get($opt_key) }; } } -sub new { - my $class = shift; - my %args = @_; - - my $self = bless {}, $class; - $self->apply(%args); - return $self; -} - sub new_from_defaults { my $class = shift; - return $class->new( - map { $_ => $Options->{$_}{default} } - grep !$Options->{$_}{shortcut}, - (@_ ? @_ : keys %$Options) - ); + my $self = $class->new; + $self->apply_static(Slic3r::Config::Print->new); + return $self; } sub new_from_cli { @@ -1201,10 +1188,14 @@ sub new_from_cli { } } - $args{$_} = $Options->{$_}{deserialize}->($args{$_}) - for grep exists $args{$_}, qw(print_center bed_size duplicate_grid extruder_offset retract_layer_change wipe); - - return $class->new(%args); + my $self = $class->new; + foreach my $opt_key (keys %args) { + if ($opt_key =~ /^(?:print_center|bed_size|duplicate_grid|extruder_offset|retract_layer_change|wipe)$/) { + $self->set_deserialize($opt_key, $args{$opt_key}); + } else { + $self->set($opt_key, $args{$opt_key}); + } + } } sub merge { @@ -1220,21 +1211,15 @@ sub load { my $ini = __PACKAGE__->read_ini($file); my $config = __PACKAGE__->new; - $config->set($_, $ini->{_}{$_}, 1) for keys %{$ini->{_}}; + $config->set_deserialize(handle_legacy($_, $ini->{_}{$_})) for keys %{$ini->{_}}; return $config; } -sub apply { - my $self = shift; - my %args = @_ == 1 ? %{$_[0]} : @_; # accept a single Config object too - - $self->set($_, $args{$_}) for keys %args; -} - sub clone { my $self = shift; - my $new = __PACKAGE__->new(%$self); - $new->{$_} = [@{$new->{$_}}] for grep { ref $new->{$_} eq 'ARRAY' } keys %$new; + + my $new = __PACKAGE__->new; + $new->apply($self); return $new; } @@ -1242,23 +1227,14 @@ sub get_value { my $self = shift; my ($opt_key) = @_; - no strict 'refs'; - my $value = $self->get($opt_key); - $value = $self->get_value($Options->{$opt_key}{ratio_over}) * $1/100 - if $Options->{$opt_key}{ratio_over} && $value =~ /^(\d+(?:\.\d+)?)%$/; - return $value; + return $Options->{$opt_key}{ratio_over} + ? $self->get_abs_value($opt_key) + : $self->get($opt_key); } -sub get { +sub handle_legacy { my $self = shift; - my ($opt_key) = @_; - - return $self->{$opt_key}; -} - -sub set { - my $self = shift; - my ($opt_key, $value, $deserialize) = @_; + my ($opt_key, $value) = @_; # handle legacy options return if first { $_ eq $opt_key } @Ignore; @@ -1294,41 +1270,20 @@ sub set { $opt_key = $keys[0]; } - # clone arrayrefs - $value = [@$value] if ref $value eq 'ARRAY'; - - # deserialize if requested - $value = $Options->{$opt_key}{deserialize}->($value) - if $deserialize && $Options->{$opt_key}{deserialize}; - - $self->{$opt_key} = $value; - - if ($Options->{$opt_key}{shortcut}) { - $self->set($_, $value, $deserialize) for @{$Options->{$opt_key}{shortcut}}; - } + return ($opt_key, $value); } sub set_ifndef { my $self = shift; my ($opt_key, $value, $deserialize) = @_; - $self->set($opt_key, $value, $deserialize) - if !defined $self->get($opt_key); -} - -sub has { - my $self = shift; - my ($opt_key) = @_; - return exists $self->{$opt_key}; -} - -sub serialize { - my $self = shift; - my ($opt_key) = @_; - - my $value = $self->get($opt_key); - $value = $Options->{$opt_key}{serialize}->($value) if $Options->{$opt_key}{serialize}; - return $value; + if (!$self->has($opt_key)) { + if ($deserialize) { + $self->set_deserialize($opt_key, $value); + } else { + $self->set($opt_key, $value); + } + } } sub save { @@ -1336,9 +1291,8 @@ sub save { my ($file) = @_; my $ini = { _ => {} }; - foreach my $opt_key (sort keys %$self) { + foreach my $opt_key (sort @{$self->get_keys}) { next if $Options->{$opt_key}{shortcut}; - next if $Options->{$opt_key}{gui_only}; $ini->{_}{$opt_key} = $self->serialize($opt_key); } __PACKAGE__->write_ini($file, $ini); @@ -1348,7 +1302,6 @@ sub setenv { my $self = shift; foreach my $opt_key (sort keys %$Options) { - next if $Options->{$opt_key}{gui_only}; $ENV{"SLIC3R_" . uc $opt_key} = $self->serialize($opt_key); } } diff --git a/slic3r.pl b/slic3r.pl index d573a4735..1503412a7 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -151,8 +151,8 @@ if (@ARGV) { # slicing from command line sub usage { my ($exit_code) = @_; - my $config = Slic3r::Config->new_from_defaults; - + my $config = Slic3r::Config->new_from_defaults->as_hash; + use Devel::Peek; Dump($config->{layer_height});exit; my $j = ''; if ($Slic3r::have_threads) { $j = <<"EOF"; diff --git a/xs/src/Config.cpp b/xs/src/Config.cpp index 5c63a8c5c..67abd2eac 100644 --- a/xs/src/Config.cpp +++ b/xs/src/Config.cpp @@ -2,6 +2,11 @@ namespace Slic3r { +bool +ConfigBase::has(const t_config_option_key opt_key) { + return (this->option(opt_key, false) != NULL); +} + void ConfigBase::apply(ConfigBase &other, bool ignore_nonexistent) { // get list of option keys to apply @@ -10,7 +15,7 @@ ConfigBase::apply(ConfigBase &other, bool ignore_nonexistent) { // loop through options and apply them for (t_config_option_keys::const_iterator it = opt_keys.begin(); it != opt_keys.end(); ++it) { - ConfigOption* my_opt = this->option(*it); + ConfigOption* my_opt = this->option(*it, true); if (my_opt == NULL) { if (ignore_nonexistent == false) throw "Attempt to apply non-existent option"; continue; @@ -57,6 +62,19 @@ ConfigBase::get_abs_value(const t_config_option_key opt_key) { } #ifdef SLIC3RXS +SV* +ConfigBase::as_hash() { + HV* hv = newHV(); + + t_config_option_keys opt_keys; + this->keys(&opt_keys); + + for (t_config_option_keys::const_iterator it = opt_keys.begin(); it != opt_keys.end(); ++it) + (void)hv_store( hv, it->c_str(), it->length(), this->get(*it), 0 ); + + return newRV_noinc((SV*)hv); +} + SV* ConfigBase::get(t_config_option_key opt_key) { ConfigOption* opt = this->option(opt_key); @@ -212,11 +230,6 @@ DynamicConfig::keys(t_config_option_keys *keys) { keys->push_back(it->first); } -bool -DynamicConfig::has(const t_config_option_key opt_key) const { - return (this->options.count(opt_key) != 0); -} - void StaticConfig::keys(t_config_option_keys *keys) { for (t_optiondef_map::const_iterator it = this->def->begin(); it != this->def->end(); ++it) { diff --git a/xs/src/Config.hpp b/xs/src/Config.hpp index 1374347d2..b8023df4a 100644 --- a/xs/src/Config.hpp +++ b/xs/src/Config.hpp @@ -327,21 +327,39 @@ class ConfigOptionDef public: ConfigOptionType type; std::string label; + std::string category; std::string tooltip; - std::string ratio_over; + std::string sidetext; + std::string cli; + std::string scope; + t_config_option_key ratio_over; + bool multiline; + bool full_label; + bool full_width; + bool readonly; + int height; + int width; + int min; + int max; + std::vector aliases; + std::vector shortcut; + std::vector enum_values; + std::vector enum_labels; t_config_enum_values enum_keys_map; + + ConfigOptionDef() : multiline(false), full_label(false), full_width(false), readonly(false), + height(0), width(0), min(0), max(0) {}; }; typedef std::map t_optiondef_map; -ConfigOptionDef* get_config_option_def(const t_config_option_key opt_key); - class ConfigBase { public: t_optiondef_map* def; ConfigBase() : def(NULL) {}; + bool has(const t_config_option_key opt_key); virtual ConfigOption* option(const t_config_option_key opt_key, bool create = false) = 0; virtual void keys(t_config_option_keys *keys) = 0; void apply(ConfigBase &other, bool ignore_nonexistent = false); @@ -350,6 +368,7 @@ class ConfigBase float get_abs_value(const t_config_option_key opt_key); #ifdef SLIC3RXS + SV* as_hash(); SV* get(t_config_option_key opt_key); void set(t_config_option_key opt_key, SV* value); #endif @@ -358,11 +377,10 @@ class ConfigBase class DynamicConfig : public ConfigBase { public: - DynamicConfig(){}; + DynamicConfig() {}; ~DynamicConfig(); ConfigOption* option(const t_config_option_key opt_key, bool create = false); void keys(t_config_option_keys *keys); - bool has(const t_config_option_key opt_key) const; private: DynamicConfig(const DynamicConfig& other); // we disable this by making it private and unimplemented diff --git a/xs/src/PrintConfig.hpp b/xs/src/PrintConfig.hpp index c2d86dac5..10fd61285 100644 --- a/xs/src/PrintConfig.hpp +++ b/xs/src/PrintConfig.hpp @@ -57,7 +57,6 @@ class PrintConfig : public StaticConfig }; ConfigOption* option(const t_config_option_key opt_key, bool create = false) { - assert(!create); // can't create options in StaticConfig if (opt_key == "layer_height") return &this->layer_height; if (opt_key == "first_layer_height") return &this->first_layer_height; if (opt_key == "perimeters") return &this->perimeters; @@ -70,6 +69,7 @@ class PrintConfig : public StaticConfig if (opt_key == "nozzle_diameter") return &this->nozzle_diameter; if (opt_key == "temperature") return &this->temperature; if (opt_key == "wipe") return &this->wipe; + if (create) throw "Attempt to create non-existing option in StaticConfig object"; return NULL; }; diff --git a/xs/t/15_config.t b/xs/t/15_config.t index 5e4719824..7a823700d 100644 --- a/xs/t/15_config.t +++ b/xs/t/15_config.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 67; +use Test::More tests => 70; foreach my $config (Slic3r::Config->new, Slic3r::Config::Print->new) { $config->set('layer_height', 0.3); @@ -73,6 +73,8 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Print->new) { is $config->serialize('wipe'), '1,0', 'serialize bools'; $config->set_deserialize('wipe', '0,1,1'); is_deeply $config->get('wipe'), [0,1,1], 'deserialize bools'; + + is_deeply [ sort @{$config->get_keys} ], [ sort keys %{$config->as_hash} ], 'get_keys and as_hash'; } { @@ -81,7 +83,14 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Print->new) { my $config2 = Slic3r::Config::Print->new; $config2->apply_dynamic($config); - is $config2->get('perimeters'), 2, 'apply (dynamic -> static)'; + is $config2->get('perimeters'), 2, 'apply_dynamic'; +} + +{ + my $config = Slic3r::Config::Print->new; + my $config2 = Slic3r::Config->new; + $config2->apply_static($config); + is $config2->get('perimeters'), Slic3r::Config::print_config_def()->{perimeters}{default}, 'apply_static and print_config_def'; } __END__ diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp index da8925cfd..6c93c9249 100644 --- a/xs/xsp/Config.xsp +++ b/xs/xsp/Config.xsp @@ -8,11 +8,19 @@ %name{Slic3r::Config} class DynamicPrintConfig { DynamicPrintConfig(); ~DynamicPrintConfig(); + bool has(t_config_option_key opt_key); + SV* as_hash(); SV* get(t_config_option_key opt_key); void set(t_config_option_key opt_key, SV* value); void set_deserialize(t_config_option_key opt_key, std::string str); std::string serialize(t_config_option_key opt_key); float get_abs_value(t_config_option_key opt_key); + void apply(DynamicPrintConfig* other) + %code{% THIS->apply(*other, true); %}; + void apply_static(PrintConfig* other) + %code{% THIS->apply(*other, true); %}; + std::vector get_keys() + %code{% THIS->keys(&RETVAL); %}; %{ %} @@ -21,14 +29,114 @@ %name{Slic3r::Config::Print} class PrintConfig { PrintConfig(); ~PrintConfig(); + bool has(t_config_option_key opt_key); + SV* as_hash(); SV* get(t_config_option_key opt_key); void set(t_config_option_key opt_key, SV* value); void set_deserialize(t_config_option_key opt_key, std::string str); std::string serialize(t_config_option_key opt_key); float get_abs_value(t_config_option_key opt_key); - void apply_dynamic(DynamicPrintConfig* other, bool ignore_nonexistent = false) - %code{% THIS->apply(*other, ignore_nonexistent); %}; + void apply_dynamic(DynamicPrintConfig* other) + %code{% THIS->apply(*other, true); %}; + std::vector get_keys() + %code{% THIS->keys(&RETVAL); %}; %{ %} }; + +%package{Slic3r::Config}; + +%{ +PROTOTYPES: DISABLE + +SV* +print_config_def() + CODE: + PrintConfig config; + t_optiondef_map* def = config.def; + + HV* options_hv = newHV(); + for (t_optiondef_map::iterator oit = def->begin(); oit != def->end(); ++oit) { + HV* hv = newHV(); + + t_config_option_key opt_key = oit->first; + ConfigOptionDef* optdef = &oit->second; + + const char* opt_type; + if (optdef->type == coFloat || optdef->type == coFloats || optdef->type == coFloatOrPercent) { + opt_type = "f"; + } else if (optdef->type == coInt || optdef->type == coInts) { + opt_type = "i"; + } else if (optdef->type == coString) { + opt_type = "s"; + } else if (optdef->type == coPoint || optdef->type == coPoints) { + opt_type = "point"; + } else if (optdef->type == coBool || optdef->type == coBools) { + opt_type = "bool"; + } else if (optdef->type == coEnum) { + opt_type = "select"; + } else { + throw "Unknown option type"; + } + (void)hv_stores( hv, "type", newSVpv(opt_type, 0) ); + (void)hv_stores( hv, "label", newSVpvn(optdef->label.c_str(), optdef->label.length()) ); + (void)hv_stores( hv, "category", newSVpvn(optdef->category.c_str(), optdef->category.length()) ); + (void)hv_stores( hv, "tooltip", newSVpvn(optdef->tooltip.c_str(), optdef->tooltip.length()) ); + (void)hv_stores( hv, "sidetext", newSVpvn(optdef->sidetext.c_str(), optdef->sidetext.length()) ); + (void)hv_stores( hv, "cli", newSVpvn(optdef->cli.c_str(), optdef->cli.length()) ); + (void)hv_stores( hv, "scope", newSVpvn(optdef->scope.c_str(), optdef->scope.length()) ); + (void)hv_stores( hv, "ratio_over", newSVpvn(optdef->ratio_over.c_str(), optdef->ratio_over.length()) ); + (void)hv_stores( hv, "multiline", newSViv(optdef->multiline ? 1 : 0) ); + (void)hv_stores( hv, "full_label", newSViv(optdef->full_label ? 1 : 0) ); + (void)hv_stores( hv, "full_width", newSViv(optdef->full_width ? 1 : 0) ); + (void)hv_stores( hv, "readonly", newSViv(optdef->readonly ? 1 : 0) ); + (void)hv_stores( hv, "height", newSViv(optdef->height) ); + (void)hv_stores( hv, "width", newSViv(optdef->width) ); + (void)hv_stores( hv, "min", newSViv(optdef->min) ); + (void)hv_stores( hv, "max", newSViv(optdef->max) ); + + // aliases + { + AV* av = newAV(); + av_fill(av, optdef->aliases.size()-1); + for (std::vector::iterator it = optdef->aliases.begin(); it != optdef->aliases.end(); ++it) + av_store(av, it - optdef->aliases.begin(), newSVpvn(it->c_str(), it->length())); + (void)hv_stores( hv, "aliases", newRV_noinc((SV*)av) ); + } + + // shortcut + { + AV* av = newAV(); + av_fill(av, optdef->shortcut.size()-1); + for (std::vector::iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) + av_store(av, it - optdef->shortcut.begin(), newSVpvn(it->c_str(), it->length())); + (void)hv_stores( hv, "shortcut", newRV_noinc((SV*)av) ); + } + + // enum_values + { + AV* av = newAV(); + av_fill(av, optdef->enum_values.size()-1); + for (std::vector::iterator it = optdef->enum_values.begin(); it != optdef->enum_values.end(); ++it) + av_store(av, it - optdef->enum_values.begin(), newSVpvn(it->c_str(), it->length())); + (void)hv_stores( hv, "enum_values", newRV_noinc((SV*)av) ); + } + + // enum_labels + { + AV* av = newAV(); + av_fill(av, optdef->enum_labels.size()-1); + for (std::vector::iterator it = optdef->enum_labels.begin(); it != optdef->enum_labels.end(); ++it) + av_store(av, it - optdef->enum_labels.begin(), newSVpvn(it->c_str(), it->length())); + (void)hv_stores( hv, "enum_labels", newRV_noinc((SV*)av) ); + } + + (void)hv_stores( hv, "default", config.get(opt_key) ); + (void)hv_store( options_hv, opt_key.c_str(), opt_key.length(), newRV_noinc((SV*)hv), 0 ); + } + + RETVAL = newRV_noinc((SV*)options_hv); + OUTPUT: + RETVAL +%} diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 67a16b654..a503a984a 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -4,6 +4,7 @@ %typemap{std::vector*}; %typemap{std::vector}; %typemap{std::vector*}; +%typemap{std::vector}; %typemap{SV*}; %typemap{AV*}; %typemap{Point*};