The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w
#
# PerlQt Example Application: drawdemo
#
# Demonstrates the painter and the printer.
#

use Qt 2.0;
use POSIX 'math_h';  # No atan() in Perl.

#
# This function draws a color wheel.
# The coordinate system x=(0..500), y=(0..500) spans the paint device.
#

sub drawColorWheel {
    my $p = shift;
    my $f = Qt::Font->new('Times', 18, Qt::Font::Bold);
    $p->setFont($f);
    $p->setPen(Qt::black);
    $p->setWindow(0, 0, 500, 500);

    for(my $i = 0; $i < 36; $i++) {
	my $matrix = Qt::WMatrix->new;
	$matrix->translate(250.0, 250.0);
	$matrix->shear(0.0, 0.3);
	$matrix->rotate($i*10);
	$p->setWorldMatrix($matrix);

	$c = Qt::Color->new;
	$c->setHsv($i*10, 255, 255);
	$p->setBrush($c);
	$p->drawRect(70, -10, 80, 10);

	$p->drawText(80+70+5, 0, "H=" . $i*10);
    }
}

#
# This function draws a few lines of text using different fonts.
#

{
    my @fonts = ('Helvetica', 'Courier', 'Times');
    my @sizes = (10, 12, 18, 24);

    sub drawFonts {
	my $p = shift;
	my($y) = (0, 0, 0);
	for my $f (@fonts) {
	    for my $s (@sizes) {
		my $font = Qt::Font->new($f, $s);
		$p->setFont($font);
		my $fm = $p->fontMetrics();
		$y += $fm->ascent();
		$p->drawText(10, $y, "Quartz Glyph Job Vex'd Cwm Finks");
		$y += $fm->descent();
	    }
	}
    }
}

#
# This function draws some shapes
#

sub drawShapes {
    my $p = shift;
    my $b1 = Qt::Brush->new(Qt::blue);
    my $b2 = Qt::Brush->new(Qt::green, Qt::Dense6Pattern);
    my $b3 = Qt::Brush->new(Qt::NoBrush);
    my $b4 = Qt::Brush->new(Qt::CrossPattern);

    $p->setPen(Qt::red);
    $p->setBrush($b1);
    $p->drawRect(10, 10, 200, 100);
    $p->setBrush($b2);
    $p->drawRoundRect(10, 150, 200, 100, 20, 20);
    $p->setBrush($b3);
    $p->drawEllipse(250, 10, 200, 100);
    $p->setBrush($b4);
    $p->drawPie(250, 150, 200, 100, 45*16, 90*16);
}

#
# This function draws a text that follows a (Bezier) curve.
# Notice that this function does not support the general case.
# It should be rewritten to calculate the real dx/dy.
#

sub drawPathText {
    my $p = shift;
    my $a = Qt::PointArray->new(4);
    $a->setPoint(0, 100,200);
    $a->setPoint(1, 150,75);
    $a->setPoint(2, 250,75);
    $a->setPoint(3, 300,200);
    $a = $a->quadBezier();

    $p->setPen(Qt::lightGray);
    $p->drawPolyline($a);

    $p->setFont(Qt::Font->new('Times', 24));
    $p->setPen(Qt::black);

    my $text = "PerlQt rocks!";

    my $len = length($text);
    return unless $len;
    my $ipos = 2; # $a->size()/$len;     # ugly hack, fix me
    my $cpos = $ipos;

    for(my $i = 0; $i < $len; $i++) {
	my $p1 = $a->point($cpos-1);
	my $p2 = $a->point($cpos+1);
	my $pt = $a->point($cpos);
	my $dx = $p2->x() - $p1->x();
	my $dy = $p2->y() - $p1->y();
	my $angle = atan($dy/$dx);
	$angle *= 180.0/3.14;
	my $m = Qt::WMatrix->new;
	$m->translate($pt->x(), $pt->y());
	$m->rotate($angle);
	$p->setWorldMatrix($m);
	$p->drawText(0, 0, substr($text, $i, 1), 1);
	$cpos += $ipos;
    }
}

package DrawView;

use Qt 2.0;

use Qt::slots 'updateIt(int)', 'printIt()';

@ISA = qw(Qt::Window);

@ourDrawFunctions = (
    { f => \&main::drawColorWheel, name => 'Draw color wheel' },
    { f => \&main::drawFonts,      name => 'Draw fonts'       },
    { f => \&main::drawShapes,     name => 'Draw shapes'      },
    { f => \&main::drawPathText,   name => 'Draw path text'   }
);

#
# Construct the DrawView with buttons.
#

sub new {
    my $self = shift->SUPER::new;

    $self->setCaption("PerlQt Draw Demo Application");
    $self->setBackgroundColor(Qt::white);

    my $printer = Qt::Printer->new;

    # Create a button group to contain all buttons
    my $bgroup = Qt::ButtonGroup->new($self);
    $bgroup->resize(200, 200);
    $self->connect($bgroup, 'clicked(int)', 'updateIt(int)');

    # Calculate the size for the radio buttons
    my $maxwidth = 80;
    my $i;
    my $n;
    my $fm = $bgroup->fontMetrics();
    for($i = 0; $i < @ourDrawFunctions; $i++) {#$i (0 .. $#ourDrawFunctions) {
	$n = $ourDrawFunctions[$i]{'name'};
	my $w = $fm->width($n);
	$maxwidth = $w > $maxwidth ? $w : $maxwidth;
    }
    $maxwidth += 20;

    for($i = 0; $i < @ourDrawFunctions; $i++) {
	$n = $ourDrawFunctions[$i]{'name'};
	my $rb = Qt::RadioButton->new($n, $bgroup);
	$rb->setGeometry(10, $i*30+10, $maxwidth, 30);
	$rb->setChecked(1) if $i == 0;
    }

    my $drawindex = 0;
    my $maxindex = $i;

    $maxwidth += 40;

    # Create and setup the print button
    my $print = Qt::PushButton->new('Print', $bgroup);
    $print->resize(80, 30);
    $print->move($maxwidth/2 - $print->width()/2, $maxindex*30+20);
    $self->connect($print, 'clicked()', 'printIt()');

    $bgroup->resize($maxwidth, $print->y()+$print->height()+10);

    $self->resize(640, 300);

    @$self{'printer', 'bgroup', 'print', 'drawindex', 'maxindex'} =
	($printer, $bgroup, $print, $drawindex, $maxindex);
    return $self;
}

#
# Called when a radio button is clicked.
#

sub updateIt {
    my $self = shift;
    my $index = shift;

    if($index < $self->{'maxindex'}) {
	$self->{'drawindex'} = $index;
	$self->update();
    }
}

#
# Calls the drawing function as specified by the radio buttons.
#

sub drawIt {
    my $self = shift;
    my $p = shift;
    my $drawindex = $self->{'drawindex'};

    &{$ourDrawFunctions[$drawindex]{'f'}}($p);
}

#
# Called when the print button is clicked.
#

sub printIt {
    my $self = shift;
    my $printer = $self->{'printer'};

    if($printer->setup($self)) {
	my $paint = Qt::Painter->new;
	$paint->begin($printer);
	$self->drawIt($paint);
	$paint->end();
    }
}

sub paintEvent {
    my $self = shift;
    my $paint = Qt::Painter->new;
    $paint->begin($self);
    $self->drawIt($paint);
    $paint->end();
}

#
# Called when the widget has been resized.
# Moves the button group to the upper right corner
# of the widget.
#

sub resizeEvent {
    my $self = shift;
    my $bgroup = $self->{'bgroup'};

    $bgroup->move($self->width()-$bgroup->width(), 0);
}


package main;

use Qt 2.0;
import Qt::app;

$draw = new DrawView;
$app->setMainWidget($draw);
$draw->show();
exit $app->exec();