1 package Reaction::UI::LayoutSet;
6 class LayoutSet which {
8 has 'layouts' => (is => 'ro', default => sub { {} });
10 has 'name' => (is => 'ro', required => 1);
12 has 'source_file' => (is => 'ro', required => 1);
14 has 'widget_class' => (
15 is => 'rw', lazy_fail => 1, predicate => 'has_widget_class'
18 has 'widget_type' => (is => 'rw', lazy_build => 1);
20 has 'super' => (is => 'rw', predicate => 'has_super');
22 implements 'BUILD' => as {
23 my ($self, $args) = @_;
24 my @path = @{$args->{search_path}||[]};
25 confess "No skin object provided" unless $args->{skin};
26 $self->_load_file($self->source_file, $args);
27 unless ($self->has_widget_class) {
28 $self->widget_class($args->{skin}->widget_class_for($self));
32 implements 'widget_order_for' => as {
33 my ($self, $name) = @_;
35 ($self->has_layout($name)
36 ? ([ $self->widget_class, $self ]) #;
39 ? ($self->super->widget_order_for($name))
44 implements 'layout_names' => as {
49 keys %{shift->layouts},
51 ? (@{$self->super->layout_names})
56 implements 'has_layout' => as { exists $_[0]->layouts->{$_[1]} };
58 implements '_load_file' => as {
59 my ($self, $file, $build_args) = @_;
60 my $data = $file->slurp;
61 my $layouts = $self->layouts;
62 # cheesy match for "=for layout name ... =something"
63 # final split group also handles last in file, (?==) is lookahead
64 # assertion for '=' so "=for layout name1 ... =for layout name2"
65 # doesn't have the match pos go past the latter = and lose name2
66 while ($data =~ m/=(.*?)\n(.*?)(?:\n(?==)|$)/sg) {
67 my ($data, $text) = ($1, $2);
68 if ($data =~ /^for layout (\S+)/) {
70 $text =~ s/^(?:\s*\r?\n)+//; #remove leading empty lines
71 $text =~ s/[\s\r\n]+$//; #remove trailing whitespace
72 $layouts->{$fname} = $text;
73 } elsif ($data =~ /^extends (\S+)/) {
76 if ($super_name eq 'NEXT') {
77 confess "No next skin and layout extends NEXT"
78 unless $build_args->{next_skin};
79 $skin = $build_args->{next_skin};
80 $super_name = $self->name;
82 $skin = $build_args->{skin};
84 $self->super($skin->create_layout_set($super_name));
85 } elsif ($data =~ /^widget (\S+)/) {
87 $self->widget_type($1);
88 } elsif ($data =~ /^cut/) {
91 confess "Unparseable directive ${data}";
96 implements '_build_widget_type' => as {
98 my $widget = join('', map { ucfirst($_) } split('_', $self->name));
99 $widget = join('::', map { ucfirst($_) } split('/', $widget));
101 #print STDERR "--- ", $self->name, " maps to widget $widget \n";