X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=lib%2FLaTeX%2FTikZ%2FSet.pm;h=cf2386d85f6c62abdfb67943f2a756ca7a728c3c;hb=58ac8fce7c7d1d825f90340434ca71b1b9da843b;hp=dcaab09494b69c2971e619e21a787f9e19c757da;hpb=e8f0879ade07eed4f58cd52c0771f4e1ecc90b09;p=perl%2Fmodules%2FLaTeX-TikZ.git diff --git a/lib/LaTeX/TikZ/Set.pm b/lib/LaTeX/TikZ/Set.pm index dcaab09..cf2386d 100644 --- a/lib/LaTeX/TikZ/Set.pm +++ b/lib/LaTeX/TikZ/Set.pm @@ -9,66 +9,179 @@ LaTeX::TikZ::Set - Base role for LaTeX::TikZ set objects. =head1 VERSION -Version 0.01 +Version 0.02 =cut -our $VERSION = '0.01'; +our $VERSION = '0.02'; -use LaTeX::TikZ::Set::Mod; +use Scope::Guard (); + +use LaTeX::TikZ::Scope; use LaTeX::TikZ::Tools; use Any::Moose 'Role'; +=head1 ATTRIBUTES + +=head2 C + +Returns the list of the L objects associated with the current set. + +=cut + +has '_mods' => ( + is => 'ro', + isa => 'Maybe[ArrayRef[LaTeX::TikZ::Mod]]', + init_arg => 'mods', + default => sub { [ ] }, + lazy => 1, +); + +sub mods { @{$_[0]->_mods} } + +=head1 METHODS + +This method is required by the interface : + +=over 4 + +=item * + +C + +Returns an array reference of TikZ code lines required to effectively draw the current set object, formatted by the L object C<$formatter>. + +=back + +=cut + requires qw( draw ); -sub mod { - my $set = $_[0]; +=head2 C - return $set unless @_ > 1; +Apply the given list of L objects to the current set. - # If $set is already a Tikz::Set::Mod object, the overridden method is - # called instead. This ensures that you can't have two T::S::M objects in a - # row. +=cut - # Prepend a new set with the mods - my $new = LaTeX::TikZ::Set::Mod->new( - set => $set, - mods => [ @_[1 .. $#_] ], - ); +my $ltm_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod'); +my $ltml_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Layer'); +my $ltmc_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Clip'); + +sub mod { + my $set = shift; + + my @mods = map $ltm_tc->coerce($_), @_; + $ltm_tc->assert_valid($_) for @mods; - $_[0] = $new unless defined wantarray; + push @{$set->_mods}, @mods; - $new; + $set; } -my $ltml_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Layer'); -my $ltmc_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Clip'); +{ + our %mods; + our $last_mod = 0; + + around 'draw' => sub { + my ($orig, $set, $tikz) = @_; + + local $last_mod = $last_mod; + + # Save a deep copy + my %saved_idx = map { $_ => $#{$mods{$_}} } keys %mods; + my $guard = Scope::Guard->new(sub { + for (keys %mods) { + if (exists $saved_idx{$_}) { + $#{$mods{$_}} = $saved_idx{$_}; + } else { + delete $mods{$_}; + } + } + }); + + my (@mods, $last_layer); +MOD: + for my $mod ($set->mods) { + my $is_layer = $ltml_tc->check($mod); + $last_layer = $mod if $is_layer; + my $tag = $mod->tag; + my $old = $mods{$tag} || []; + for (@$old) { + next MOD if $_->[0]->covers($mod); + } + push @{$mods{$tag}}, [ $mod, $last_mod++, $is_layer ]; + push @mods, $mod; + } + + if ($last_layer) { + # Clips and mods don't propagate through layers. Hence if a layer is set, + # force their reuse. + @mods = $last_layer; + push @mods, map $_->[0], + sort { $a->[1] <=> $b->[1] } + grep !$_->[2], + map @$_, + values %mods; + } + + my $body = $set->$orig($tikz); + + if (@mods) { + $body = LaTeX::TikZ::Scope->new + ->mod(map $_->apply($tikz), @mods) + ->body($body); + } + + $body; + }; +} + +=head2 C + +Puts the current set in the corresponding layer. +This is a shortcut for C<< $set->mod(Tikz->layer($layer)) >>. + +=cut sub layer { - return $_[0] unless @_ > 1; + my $set = shift; - my $layer = $_[1]; + return $set unless @_; - $_[0]->mod( + my $layer = $_[0]; + $set->mod( $ltml_tc->check($layer) ? $layer : LaTeX::TikZ::Mod::Layer->new(name => $layer) ) } +=head2 C + +Clips the current set by the path given by C<$path>. +This is a shortcut for C<< $set->mod(Tikz->clip($path)) >>. + +=cut + sub clip { - return $_[0] unless @_ > 1; + my $set = shift; + + return $set unless @_; - $_[0]->mod( + $set->mod( map { - $ltmc_tc->check($_) ? $_ : LaTeX::TikZ::Mod::Clip->new($_) - } @_[1 .. $#_] + $ltmc_tc->check($_) ? $_ : LaTeX::TikZ::Mod::Clip->new(clip => $_) + } @_ ) } +=head1 SEE ALSO + +L. + =head1 AUTHOR Vincent Pit, C<< >>, L.