/usr/local/CPAN/Qt/SortingBox.pm
package SortingBox;
use strict;
use warnings;
use QtCore4;
use QtGui4;
use QtCore4::isa qw( Qt::Widget );
use ShapeItem;
# [0]
use QtCore4::slots
createNewCircle => [],
createNewSquare => [],
createNewTriangle => [];
# [0]
# [2]
sub shapeItems() {
return this->{shapeItems};
}
sub circlePath() {
return this->{circlePath};
}
sub squarePath() {
return this->{squarePath};
}
sub trianglePath() {
return this->{trianglePath};
}
sub previousPosition() {
return this->{previousPosition};
}
sub itemInMotion() {
return this->{itemInMotion};
}
sub newCircleButton() {
return this->{newCircleButton};
}
sub newSquareButton() {
return this->{newSquareButton};
}
sub newTriangleButton() {
return this->{newTriangleButton};
}
# [2]
# [0]
sub NEW {
my ( $class ) = @_;
$class->SUPER::NEW();
# [0] //! [1]
this->setMouseTracking(1);
# [1] //! [2]
this->setBackgroundRole(Qt::Palette::Base());
# [2]
this->{itemInMotion} = 0;
this->{circlePath} = Qt::PainterPath();
this->{squarePath} = Qt::PainterPath();
this->{trianglePath} = Qt::PainterPath();
this->{shapeItems} = [];
# [3]
this->{newCircleButton} = createToolButton(this->tr('New Circle'),
Qt::Icon('images/circle.png'),
SLOT 'createNewCircle()');
this->{newSquareButton} = createToolButton(this->tr('New Square'),
Qt::Icon('images/square.png'),
SLOT 'createNewSquare()');
this->{newTriangleButton} = createToolButton(this->tr('New Triangle'),
Qt::Icon('images/triangle.png'),
SLOT 'createNewTriangle()');
this->circlePath->addEllipse(Qt::RectF(0, 0, 100, 100));
this->squarePath->addRect(Qt::RectF(0, 0, 100, 100));
my $x = this->trianglePath->currentPosition()->x();
my $y = this->trianglePath->currentPosition()->y();
this->trianglePath->moveTo($x + 120 / 2, $y);
this->trianglePath->lineTo(0, 100);
this->trianglePath->lineTo(120, 100);
this->trianglePath->lineTo($x + 120 / 2, $y);
# [3] //! [4]
this->setWindowTitle(this->tr('Tool Tips'));
this->resize(500, 300);
this->createShapeItem(circlePath, this->tr('Circle'), this->initialItemPosition(this->circlePath),
this->initialItemColor());
this->createShapeItem(squarePath, this->tr('Square'), this->initialItemPosition(this->squarePath),
this->initialItemColor());
this->createShapeItem(trianglePath, this->tr('Triangle'),
this->initialItemPosition(this->trianglePath), this->initialItemColor());
}
# [4]
# [5]
sub event {
# [5] //! [6]
my ($event) = @_;
if ($event->type() == Qt::Event::ToolTip()) {
my $helpEvent = CAST $event, 'Qt::HelpEvent';
my $index = this->itemAt($helpEvent->pos());
if ($index != -1) {
Qt::ToolTip::showText($helpEvent->globalPos(), this->shapeItems->[$index]->toolTip());
} else {
Qt::ToolTip::hideText();
$event->ignore();
}
return 1;
}
return this->SUPER::event($event);
}
# [6]
# [7]
sub resizeEvent {
# TODO figure out why the 1 and 2 argument form aren't correct in smoke.
my $margin = this->style()->pixelMetric(Qt::Style::PM_DefaultTopLevelMargin(), undef, undef);
my $x = this->width() - $margin;
my $y = this->height() - $margin;
$y = this->updateButtonGeometry(this->newCircleButton, $x, $y);
$y = this->updateButtonGeometry(this->newSquareButton, $x, $y);
this->updateButtonGeometry(this->newTriangleButton, $x, $y);
}
# [7]
# [8]
sub paintEvent {
my $painter = Qt::Painter(this);
$painter->setRenderHint(Qt::Painter::Antialiasing());
foreach my $shapeItem (@{this->{shapeItems}}) {
# [8] //! [9]
$painter->translate($shapeItem->position());
# [9] //! [10]
$painter->setBrush(Qt::Brush($shapeItem->color()));
$painter->drawPath($shapeItem->path());
$painter->translate(-$shapeItem->position());
}
$painter->end();
}
# [10]
# [11]
sub mousePressEvent {
my ($event) = @_;
CAST $event, 'Qt::MouseEvent';
if ($event->button() == Qt::LeftButton()) {
my $index = this->itemAt($event->pos());
if ($index != -1) {
this->{itemInMotion} = this->shapeItems->[$index];
this->{previousPosition} = $event->pos();
push @{this->shapeItems}, splice @{this->shapeItems}, $index, 1;
this->update();
}
}
}
# [11]
# [12]
sub mouseMoveEvent {
my ($event) = @_;
CAST $event, 'Qt::MouseEvent';
if (($event->buttons() & ${Qt::LeftButton()}) && this->itemInMotion) {
this->moveItemTo($event->pos());
}
}
# [12]
# [13]
sub mouseReleaseEvent {
my ($event) = @_;
CAST $event, 'Qt::MouseEvent';
if ($event->button() == ${Qt::LeftButton()} && this->itemInMotion) {
this->moveItemTo($event->pos());
this->{itemInMotion} = 0;
}
}
# [13]
# [14]
my $circleCount = 1;
sub createNewCircle {
this->createShapeItem(this->circlePath,
sprintf( this->tr('Circle <%d>'), ++$circleCount ),
this->randomItemPosition(), this->randomItemColor());
}
# [14]
# [15]
my $squareCount = 1;
sub createNewSquare {
this->createShapeItem(this->squarePath,
sprintf( this->tr('Square <%d>'), ++$squareCount ),
this->randomItemPosition(), this->randomItemColor());
}
# [15]
# [16]
my $triangleCount = 1;
sub createNewTriangle {
this->createShapeItem(trianglePath,
sprintf( this->tr('Triangle <%d>'), ++$triangleCount ),
this->randomItemPosition(), this->randomItemColor());
}
# [16]
# [17]
sub itemAt {
my ($pos) = @_;
foreach my $i ( reverse 0..$#{this->shapeItems} ) {
my $item = this->shapeItems->[$i];
if ($item->path()->contains(Qt::PointF($pos - $item->position()))) {
return $i;
}
}
return -1;
}
# [17]
# [18]
sub moveItemTo {
my ($pos) = @_;
my $offset = $pos - this->previousPosition;
this->itemInMotion->setPosition(this->itemInMotion->position() + $offset);
# [18] //! [19]
this->{previousPosition} = $pos;
this->update();
}
# [19]
# [20]
sub updateButtonGeometry {
my ($button, $x, $y) = @_;
my $size = $button->sizeHint();
$button->setGeometry($x - $size->rwidth(), $y - $size->rheight(),
$size->rwidth(), $size->rheight());
# TODO figure out why the 1 and 2 argument form aren't correct in smoke.
return $y - $size->rheight() -
this->style()->pixelMetric(Qt::Style::PM_DefaultLayoutSpacing(), undef, undef);
}
# [20]
# [21]
sub createShapeItem {
my ($path, $toolTip, $pos, $color) = @_;
my $shapeItem = ShapeItem();
$shapeItem->setPath($path);
$shapeItem->setToolTip($toolTip);
$shapeItem->setPosition($pos);
$shapeItem->setColor($color);
push @{this->shapeItems}, $shapeItem;
this->update();
}
# [21]
# [22]
sub createToolButton {
my ($toolTip, $icon, $member) = @_;
my $button = Qt::ToolButton(this);
$button->setToolTip($toolTip);
$button->setIcon($icon);
$button->setIconSize(Qt::Size(32, 32));
this->connect($button, SIGNAL 'clicked()', this, $member);
return $button;
}
# [22]
# [23]
sub initialItemPosition {
my ($path) = @_;
my $x;
my $y = (this->height() - int($path->controlPointRect()->height())) / 2;
if (scalar @{this->shapeItems} == 0) {
$x = ((3 * this->width()) / 2 - int($path->controlPointRect()->width())) / 2;
}
else {
$x = (this->width() / scalar( @{this->shapeItems} )
- int($path->controlPointRect()->width())) / 2;
}
return Qt::Point($x, $y);
}
# [23]
# [24]
sub randomItemPosition {
# 2147483647 is the value of RAND_MAX, defined in stdlib.h, at least on
# my machine.
# See the Qt4 documentation on qrand() for more details.
return Qt::Point(rand(2147483647) % (this->width() - 120), rand(2147483647) % (this->height() - 120));
}
# [24]
# [25]
sub initialItemColor {
return Qt::Color::fromHsv(((scalar @{this->shapeItems} + 1) * 85) % 256, 255, 190);
}
# [25]
# [26]
sub randomItemColor {
return Qt::Color::fromHsv(rand(2147483647) % 256, 255, 190);
}
# [26]
1;