]> git.vpit.fr Git - perl/modules/LaTeX-TikZ.git/blob - lib/LaTeX/TikZ/Mod/Layer.pm
6b3f73de0967e2e2e5149632370ac5832fb40b06
[perl/modules/LaTeX-TikZ.git] / lib / LaTeX / TikZ / Mod / Layer.pm
1 package LaTeX::TikZ::Mod::Layer;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 LaTeX::TikZ::Mod::Layer - A modifier that specifies a drawing layer.
9
10 =head1 VERSION
11
12 Version 0.01
13
14 =cut
15
16 our $VERSION = '0.01';
17
18 use List::Util ();
19
20 use LaTeX::TikZ::Mod::Formatted;
21
22 use Any::Moose;
23 use Any::Moose 'Util::TypeConstraints';
24
25 with 'LaTeX::TikZ::Mod';
26
27 has 'name' => (
28  is       => 'ro',
29  isa      => 'Str',
30  required => 1,
31 );
32
33 subtype 'LaTeX::TikZ::Mod::LevelList'
34      => as 'ArrayRef[LaTeX::TikZ::Mod::Layer]';
35
36 coerce 'LaTeX::TikZ::Mod::LevelList'
37     => from 'Str'
38     => via { [ __PACKAGE__->new(name => $_) ] };
39
40 coerce 'LaTeX::TikZ::Mod::LevelList'
41     => from 'ArrayRef[Str]'
42     => via { [ map __PACKAGE__->new(name => $_), @$_ ] };
43
44 has '_above' => (
45  is       => 'ro',
46  isa      => 'LaTeX::TikZ::Mod::LevelList',
47  init_arg => 'above',
48  default  => sub { [ ] },
49  coerce   => 1,
50 );
51
52 sub above { @{$_[0]->_above} }
53
54 has '_below' => (
55  is       => 'ro',
56  isa      => 'LaTeX::TikZ::Mod::LevelList',
57  init_arg => 'below',
58  default  => sub { [ ] },
59  coerce   => 1,
60 );
61
62 sub below { @{$_[0]->_below} }
63
64 has '_score' => (
65  is       => 'ro',
66  isa      => 'Int',
67  init_arg => undef,
68  lazy     => 1,
69  builder  => '_build_score',
70 );
71
72 my %layers;
73
74 around 'new' => sub {
75  my ($orig, $self, %args) = @_;
76
77  my $name = $args{name};
78  if (defined $name) {
79   $self->meta->find_attribute_by_name('name')
80              ->type_constraint->assert_valid($name);
81   my $layer = $layers{$name};
82   if (defined $layer) {
83    confess("Can't redefine layer '$name'") if keys(%args) > 1;
84    return $layer;
85   }
86  }
87
88  return $self->$orig(%args);
89 };
90
91 sub BUILD {
92  my ($self) = @_;
93
94  $layers{$self->name} = $self;
95 }
96
97 sub DEMOLISH {
98  my ($self) = @_;
99
100  delete $layers{$self->name};
101 }
102
103 sub tag {
104  my ($self) = @_;
105
106  ref($self) . '/' . $self->name;
107 }
108
109 sub cover { $_[0]->name eq $_[1]->name }
110
111 {
112  our %score;
113
114  sub score {
115   my $layer = $_[0];
116
117   my $name = $layer->name;
118
119   return $score{$name} if exists $score{$name};
120
121   my (@lower, $min);
122   for ($layer->above) {
123    my $cur = $_->score;
124    if (defined $cur) {
125     $min = $cur if not defined $min or $min < $cur;
126    } else {
127     push @lower, $_;
128    }
129   }
130
131   my (@higher, $max);
132   for ($layer->below) {
133    my $cur = $_->score;
134    if (defined $cur) {
135     $max = $cur if not defined $max or $max < $cur;
136    } else {
137     push @higher, $_;
138    }
139   }
140
141   if (defined $min) {
142    if (defined $max) {
143     confess("Order mismatch for $name") unless $min < $max;
144     $score{$name} = ($min + $max) / 2;
145    } else {
146     my $i = List::Util::max(values %score);
147     $score{$_} = ++$i for $name, @higher;
148    }
149   } elsif (defined $max) {
150    my $i = List::Util::min(values %score);
151    $score{$_} = --$i for @lower, $name;
152   } else {
153    my $i = 0;
154    $score{$_} = ++$i for @lower, $name, @higher;
155   }
156
157   $score{$name}
158  }
159
160  sub declare {
161   shift;
162
163   return unless @_;
164
165   local %score = (main => 0);
166
167   $_->score for @_;
168
169   my @layers = sort { $score{$a} <=> $score{$b} }
170                 map { ref() ? $_->name : $_ }
171                  keys %score;
172
173   my @intro = map "\\pgfdeclarelayer{$_}",
174                grep $_ ne 'main',
175                 @layers;
176
177   return (
178    @intro,
179    "\\pgfsetlayers{" . join(',', @layers) . "}",
180   );
181  }
182 }
183
184 sub apply {
185  my ($self) = @_;
186
187  LaTeX::TikZ::Mod::Formatted->new(
188   type    => 'layer',
189   content => $self->name,
190  )
191 }
192
193 use LaTeX::TikZ::Interface layer => sub {
194  shift;
195
196  my $name = shift;
197  __PACKAGE__->new(name => $name, @_);
198 };
199
200 __PACKAGE__->meta->make_immutable(
201  inline_constructor => 0,
202 );
203
204 =head1 AUTHOR
205
206 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
207
208 You can contact me by mail or on C<irc.perl.org> (vincent).
209
210 =head1 BUGS
211
212 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>.
213 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
214
215 =head1 SUPPORT
216
217 You can find documentation for this module with the perldoc command.
218
219     perldoc LaTeX::TikZ
220
221 =head1 COPYRIGHT & LICENSE
222
223 Copyright 2010 Vincent Pit, all rights reserved.
224
225 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
226
227 =cut
228
229 1; # End of LaTeX::TikZ::Mod::Layer