The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Copyright 2010, 2011, 2012 Kevin Ryde

# This file is part of Image-Base-Other.
#
# Image-Base-Other is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any later
# version.
#
# Image-Base-Other is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with Image-Base-Other.  If not, see <http://www.gnu.org/licenses/>.


package Image::Base::Multiplex;
use 5.004;
use strict;
use Carp;
use vars '$VERSION', '@ISA';

$VERSION = 9;

use Image::Base;
@ISA = ('Image::Base');

# uncomment this to run the ### lines
#use Smart::Comments;


sub new {
  my $class = shift;

  if (ref $class) {
    # clone by copying fields, don't think need to copy images array
    return bless { %$class }, $class;
  }

  return bless { -images => [],
                 @_ }, $class;
}

sub _get {
  my ($self, $key) = @_;
  # ### Image-Base-Multiplex _get(): $key
  if ($key eq '-images') {
    return $self->SUPER::_get($key);
  } else {
    my $image = $self->{'-images'}->[0] || return undef;
    return $image->get($key);
  }
}
sub set {
  my $self = shift;
  # ### Image-Base-Multiplex set()

  my $set_file;
  for (my $i = 0; $i < @_; ) {
    my $key = $_[$i];
    $set_file = ($key eq '-file');
    if ($key eq '-images') {
      $self->{$key} = $_[$i+1];
      splice @_, $i, 2;
    } else {
      $i += 2
    }
  }

  my $images = $self->{'-images'};
  if ($set_file && @$images > 1) {
    croak 'Refusing to set multiple images to same -file';
  }

  foreach my $image (@$images) {
    $image->set(@_);
  }
}

sub load {
  my $self = shift;
  my $images = $self->{'-images'};
  if (@_ && @$images > 1) {
    croak 'Refusing to load multiple images from one file';
  }
  foreach my $image (@$images) { $image->load; }
}
sub save {
  my $self = shift;
  my $images = $self->{'-images'};
  if (@_ && @$images > 1) {
    croak 'Refusing to save multiple images to one file';
  }
  foreach my $image (@$images) { $image->save; }
}

sub xy {
  my $self = shift;
  ### Image-Base-Multiplex xy(): @_[1..$#_]
  my $images = $self->{'-images'};
  if (@_ > 2) {
    foreach my $image (@$images) { $image->xy(@_); }
  } else {
    my ($x, $y) = @_;
    my $image = $images->[0] || return undef;
    return $image->xy($x,$y);
  }
}
sub line {
  foreach my $image (@{shift->{'-images'}}) { $image->line(@_); }
}
sub rectangle {
  foreach my $image (@{shift->{'-images'}}) { $image->rectangle(@_); }
}
sub ellipse {
  foreach my $image (@{shift->{'-images'}}) { $image->ellipse(@_); }
}
sub diamond {
  foreach my $image (@{shift->{'-images'}}) { $image->diamond(@_); }
}

sub add_colours {
  foreach my $image (@{shift->{'-images'}}) {
    if (my $coderef = $image->can('add_colours')) {
      $image->$coderef(@_);
    }
  }
}

sub Image_Base_Other_xy_points {
  ### Multiplex xy_points
  foreach my $image (@{shift->{'-images'}}) {
    if (my $coderef = $image->can('Image_Base_Other_xy_points')) {
      $image->$coderef(@_);
    } else {
      for (my $i = 1; $i < @_; $i += 2) {
        $image->xy ($_[$i], $_[$i+1],
                    $_[0]);  # colour
      }
    }
  }
}
sub Image_Base_Other_rectangles {
  ### Multiplex rectangles
  foreach my $image (@{shift->{'-images'}}) {
    if (my $coderef = $image->can('Image_Base_Other_rectangles')) {
      $image->$coderef(@_);
    } else {
      for (my $i = 2; $i < @_; $i += 4) {
        ### rect: @_[$i .. $i+3], $_[0], $_[1]
        $image->rectangle (@_[$i .. $i+3],
                           $_[0],   # colour
                           $_[1]);  # fill
      }
    }
  }
}

1;
__END__

=for stopwords filename Ryde arrayref multi-output

=head1 NAME

Image::Base::Multiplex -- draw to multiple Image::Base objects simultaneously

=for test_synopsis my ($image1, $image2)

=head1 SYNOPSIS

 use Image::Base::Multiplex;
 my $multiplex_image = Image::Base::Multiplex->new
                           (-images => [$image1,$image2]);
 $multiplex_image->rectangle (0,0, 99,99, 'white');
 $multiplex_image->line (50,50, 70,70, '#FF00FF');

=head1 CLASS HIERARCHY

C<Image::Base::Multiplex> is a subclass of C<Image::Base>,

    Image::Base
      Image::Base::Multiplex

=head1 DESCRIPTION

C<Image::Base::Multiplex> operates on multiple C<Image::Base> objects
simultaneously so that one drawing call draws to a set of images.

=head1 FUNCTIONS

=over 4

=item C<$image = Image::Base::Multiplex-E<gt>new (key=E<gt>value,...)>

Create and return a new multiplex image object.  An initial list of target
images can be supplied,

    my $image = Image::Base::Multiplex->new
                   (-images => [ $image1, $image2 ]);

Or start empty and set some C<-images> later

    my $image = Image::Base::Multiplex->new ();

=item C<$image-E<gt>xy (...)>

=item C<$image-E<gt>line (...)>

=item C<$image-E<gt>rectangle (...)>

=item C<$image-E<gt>ellipse (...)>

=item C<$image-E<gt>diamond (...)>

These calls are passed through to each target image.

=item C<$image-E<gt>add_colours ($colour, $colour, ...)>

Call C<add_colours> on each target image which supports that method, and
skip those which don't.

=back

=head1 ATTRIBUTES

=over

=item C<-images> (arrayref of C<Image::Base> objects)

The target images to draw on.

=back

=head1 SEE ALSO

L<Image::Base>

L<G2> has a similar multi-output to its devices.

=head1 HOME PAGE

http://user42.tuxfamily.org/image-base-other/index.html

=head1 LICENSE

Image-Base-Other is Copyright 2010, 2011, 2012 Kevin Ryde

Image-Base-Other is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option) any
later version.

Image-Base-Other is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with
Image-Base-Other.  If not, see <http://www.gnu.org/licenses/>.

=cut