1 package LaTeX::TikZ::Scope;
8 LaTeX::TikZ::Scope - An object modeling a TikZ scope or layer.
16 our $VERSION = '0.01';
20 use LaTeX::TikZ::Tools;
26 isa => 'Maybe[ArrayRef[LaTeX::TikZ::Mod::Formatted]]',
28 default => sub { [ ] },
31 sub mods { @{$_[0]->_mods} }
33 has '_mods_cache' => (
35 isa => 'Maybe[HashRef[LaTeX::TikZ::Mod::Formatted]]',
37 default => sub { +{ } },
42 isa => 'LaTeX::TikZ::Scope|ArrayRef[Str]',
46 my $my_tc = LaTeX::TikZ::Tools::type_constraint(__PACKAGE__);
47 my $ltmf_tc = LaTeX::TikZ::Tools::type_constraint('LaTeX::TikZ::Mod::Formatted');
48 my $_body_tc = __PACKAGE__->meta->find_attribute_by_name('_body')
54 my $cache = $scope->_mods_cache;
57 my $mod = $ltmf_tc->coerce($_);
58 $ltmf_tc->assert_valid($mod);
60 next if exists $cache->{$tag};
61 $cache->{$tag} = $mod;
62 push @{$scope->_mods}, $mod;
80 '@{}' => 'dereference',
87 my $body = $scope->_body;
88 return $scope unless $my_tc->check($body);
90 ->mod ($scope->mods, $body->mods)
95 my $inter = Sub::Name::subname('inter' => sub {
98 my (@left, @common, @right);
101 --$where{$_} for keys %$lh;
102 ++$where{$_} for keys %$rh;
104 while (my ($key, $where) = each %where) {
106 push @left, $lh->{$key};
107 } elsif ($where > 0) {
108 push @right, $rh->{$key};
110 push @common, $rh->{$key};
114 return \@left, \@common, \@right;
120 $scope = $scope->flatten;
122 my ($layer, @clips, @raw_mods);
125 if ($type eq 'clip') {
126 unshift @clips, $_->content;
127 } elsif ($type eq 'layer') {
128 confess("Can't apply two layers in a row") if defined $layer;
129 $layer = $_->content;
131 push @raw_mods, $_->content;
135 my @body = $scope->body;
137 my $mods_string = @raw_mods ? ' [' . join(',', @raw_mods) . ']' : undef;
139 if (@raw_mods and @body == 1 and $body[0] =~ /^\s*\\draw\b\s*([^\[].*)\s*$/) {
140 $body[0] = "\\draw$mods_string $1"; # Has trailing semicolon
141 $mods_string = undef; # Done with mods
145 my $clip = $clips[$_];
146 my $clip_string = "\\clip $clip ;";
147 my $mods_string = ($_ == $#clips and defined $mods_string)
149 unshift @body, "\\begin{scope}$mods_string",
151 push @body, "\\end{scope}",
154 if (not @clips and defined $mods_string) {
155 unshift @body, "\\begin{scope}$mods_string";
156 push @body, "\\end{scope}";
159 if (defined $layer) {
160 unshift @body, "\\begin{pgfonlayer}{$layer}";
161 push @body, "\\end{pgfonlayer}";
167 sub dereference { [ $_[0]->instantiate ] }
170 my ($left, $right, $rev) = @_;
174 if ($my_tc->check($left)) {
175 $left = $left->flatten;
177 if ($my_tc->check($right)) {
178 $right = $right->flatten;
180 my ($only_left, $common, $only_right) = $inter->(
185 my $has_different_layers;
187 if ($_->type eq 'layer') {
188 $has_different_layers = 1;
192 unless ($has_different_layers) {
194 if ($_->type eq 'layer') {
195 $has_different_layers = 1;
201 if (!$has_different_layers and @$common) {
204 ->body($left->_body);
207 ->body($right->_body);
210 ->body(fold($x, $y, $rev));
212 @right = $right->instantiate;
215 $_body_tc->assert_valid($right);
219 @left = $left->instantiate;
221 if ($my_tc->check($right)) {
222 return fold($right, $left, 1);
224 $_body_tc->assert_valid($_) for $left, $right;
230 $rev ? [ @right, @left ] : [ @left, @right ];
233 __PACKAGE__->meta->make_immutable;
237 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
239 You can contact me by mail or on C<irc.perl.org> (vincent).
243 Please report any bugs or feature requests to C<bug-latex-tikz at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=LaTeX-TikZ>.
244 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
248 You can find documentation for this module with the perldoc command.
252 =head1 COPYRIGHT & LICENSE
254 Copyright 2010 Vincent Pit, all rights reserved.
256 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
260 1; # End of LaTeX::TikZ::Scope