The Perl Advent Calendar needs more articles for 2022. Submit your idea today!
=pod

=head1 NAME

examples/blend.pl - Prima alpha blending

=head1 FEATURES

Demonstrates use of Prima image alpha blending with C<rop::blend($ALPHA)>.

=cut


use strict;
use warnings;
use Prima qw(Application Label Sliders ImageViewer);

my ($rop_name, $rop_val);
my $w = Prima::MainWindow->new(
	size => [ 600, 500 ],
	designScale => [7, 16],
	text => 'Blending example',
	menuItems => [
		[ '~Binary' => [ map { [$_, $_, \&bin, {group => 1}] } qw(
			CopyPut XorPut AndPut OrPut NotPut Invert Blackness
			NotDestAnd NotDestOr Whiteness NotSrcAnd NotSrcOr NotXor
			NotAnd NotOr NoOper
		)]],
		[ 'Porter-~Duff' => [ map { [$_, $_, \&pd, {group => 1}] } qw(
			SrcOver Xor DstOver SrcCopy DstCopy Clear
			SrcIn DstIn SrcOut DstOut SrcAtop DstAtop
		)]],
		[ '~Photoshop' => [ map { [$_, $_, \&pd, {group => 1}] } qw(
			Add Multiply Screen Overlay Darken
			Lighten ColorDodge ColorBurn HardLight
			SoftLight Difference Exclusion
		)]],
	]
);

my $a = Prima::Image->new(
	size => [200,200],
	type => im::RGB,
);
$a->begin_paint;
$a->new_gradient( palette => [cl::LightGreen, cl::Blue ])->bar(0, 0, $a->size);
$a->end_paint;
my $ia = Prima::Icon->new(
	size => [200,200],
	type => im::RGB,
	maskType => im::bpp8,
	autoMasking => am::MaskColor,
	maskColor => cl::Black,
);
$ia->put_image(0,0,$a);
$ia->color(cl::Black);
$ia->bar(0,0,30,200);
$ia->bar(170,0,200,200);

my $b = $a->dup;
$b->begin_paint;
$b->bar(0,0,$b->size);
$b->new_gradient( palette => [cl::LightRed, cl::Yellow ])-> ellipse($b->width/2,$b->height/2, $b->size);
$b->end_paint;

my $ib = Prima::Icon->new(
	size => [200,200],
	type => im::RGB,
	maskType => im::bpp8,
	autoMasking => am::MaskColor,
	maskColor => cl::Black,
);
$ib->put_image( 0,0,$b);

my $base = $a->dup;
$base->set( backColor => cl::White, color => cl::Black, fillPattern => [(0xF0)x4, (0xF)x4], rop2 => rop::CopyPut);
$base->bar(0,0,$base->size);

my $canvas = $a->dup;
my $precanvas = Prima::Icon->new(
	size => [200,200],
	type => im::RGB,
	maskType => im::bpp8,
	autoMasking => am::None,
);
$ia->autoMasking(am::None);

my $mask = Prima::Image->new(
	size => [200,200],
	type => im::Byte,
);

sub repaint
{
	my $sa = $w->SliderA;
	my $sb = $w->SliderB;
	if ( $sa->enabled ) {
		$precanvas->put_image(0,0,$ia, rop::alpha( rop::SrcCopy | rop::Premultiply, $sa->value));
		$precanvas->put_image(0,0,$ib, rop::alpha( $rop_val     | rop::Premultiply, $sb->value));
		$canvas->put_image(0,0,$base);
		$canvas->put_image(0,0,$precanvas);
	} else {
		$canvas->put_image(0,0,$a);
		$canvas->put_image(0,0,$b,$rop_val);
	}

	my $fader = $w->Fader;
	$canvas->put_image(2, 2, $fader->{banner}, rop::alpha( rop::SrcOver | rop::Premultiply, $fader->{alpha} ))
		if $fader->{banner};
	$w-> ImageViewer1->repaint;
}

sub select_rop
{
	my ($newrop, $with_slider) = @_;
	$rop_name = $newrop;
	$rop_val = &{${rop::}{$rop_name}}();
	$w->SliderA->enabled( $with_slider );
	$w->SliderA->readOnly( !$with_slider );
	$w->SliderB->enabled( $with_slider );
	$w->SliderB->readOnly( !$with_slider );
	$w->Fader->{text} = $rop_name;
	delete $w->Fader->{left};
	$w->Fader->{steps} = 30;
	$w->Fader->start;
	repaint();
}

sub set_slider
{
	$w->Fader->{text} = shift->value;
	$w->Fader->{steps} = 15;
	delete $w->Fader->{left};
	$w->Fader->start;
	repaint();
}
sub bin { select_rop($_[1], 0) }
sub pd  { select_rop($_[1], 1) } 


$w-> insert( ImageViewer =>
	pack => {side => 'top', fill => 'both', pad => 10, expand => 1},
	image => $canvas,
	stretch => 1,
);

$w->insert( Label => 
	text => '~Green transparency',
	focusLink => 'SliderA',
	pack => {side => 'top', fill => 'x', padx => 15},
);

$w->insert( Slider =>
	min => 0,
	max => 255,
	value => 200,
	scheme => ss::Axis,
	increment => 16,
	name => 'SliderA',
	pack => {side => 'top', fill => 'x'},
	onChange => \&set_slider,
);

$w->insert( Label => 
	text => '~Red transparency',
	focusLink => 'SliderB',
	pack => {side => 'top', fill => 'x', padx => 15},
);

$w->insert( Slider =>
	min => 0,
	max => 255,
	scheme => ss::Axis,
	increment => 16,
	value => 200,
	name => 'SliderB',
	pack => {side => 'top', fill => 'x'},
	onChange => \&set_slider,
);

$w-> insert( Timer => 
	timeout => 50,
	name => 'Fader',
	onTick => sub {
		my $self = shift;
		if ( !defined $self->{left}) {
			$self->{left} = $self->{steps};
			$canvas-> begin_paint_info;
			$canvas->font->set( size => 18, style => fs::Bold );
			my $f = $canvas->font;
			my $b = Prima::Icon->new(
				type        => im::RGB,
				size        => [ $canvas->get_text_width( $self->{text}, 1 ) + 4, $f-> height + 4 ],
				color       => cl::Yellow,
				backColor   => cl::Black,
				lineWidth   => 5,
				maskType    => 8,
				autoMasking => 0,
				font        => { vector => 1 },
			);
			$canvas-> end_paint_info;
			$b->begin_paint;
			$b->clear;
			$b->font->set( size => 18, style => fs::Bold );
			$b->color(0x010101); # black but not zero
			my $path = $b->new_path;
			$path->translate(2,2);
			$path->text( $self->{text});
			$path->stroke;
			$b->color(cl::Yellow);
			$b->text_out($self->{text}, 2, 2);
			$b->end_paint;

			my $bb = $b->clone( type => im::Byte, rop2 => rop::CopyPut );
			$bb->map(0x000000); # black and zero
			$b->mask( $bb->data );

			$self->{banner} = $b;
			$self->{alpha} = 255;
		} elsif ( --$self->{left} <= 0 ) {
			delete $self->{banner};
			delete $self->{left};
			$self->stop;
		} else {
			$self->{alpha} -= 256 / $self->{steps};
		}
		repaint;
	},
);
$w->Fader->{steps} = 30;

select_rop('SrcOver', 1);

run Prima;