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;