/usr/local/CPAN/Qt/PiecesModel.pm
package PiecesModel;
use strict;
use warnings;
use List::Util qw( min max );
use QtCore4;
use QtGui4;
use QtCore4::isa qw( Qt::AbstractListModel );
use constant { RAND_MAX => 2147483647 };
sub locations() {
return this->{locations};
}
sub pixmaps() {
return this->{pixmaps};
}
sub NEW
{
my ($class, $parent) = @_;
$class->SUPER::NEW( $parent );
this->{locations} = [];
this->{pixmaps} = [];
}
sub data
{
my ($index, $role) = @_;
if (!$index->isValid()) {
return Qt::Variant();
}
if ($role == Qt::DecorationRole()) {
return Qt::qVariantFromValue(Qt::Icon(this->pixmaps->[$index->row()]->scaled(60, 60,
Qt::KeepAspectRatio(), Qt::SmoothTransformation())));
}
elsif ($role == Qt::UserRole()) {
return Qt::qVariantFromValue(this->pixmaps->[$index->row()]);
}
elsif ($role == Qt::UserRole() + 1) {
return Qt::Variant(this->locations->[$index->row()]);
}
return Qt::Variant();
}
sub addPiece
{
my ($pixmap, $location) = @_;
my $row;
if (int(2.0*rand(RAND_MAX)/(RAND_MAX+1.0)) == 1) {
$row = 0;
}
else {
$row = scalar @{this->pixmaps};
}
this->beginInsertRows(Qt::ModelIndex(), $row, $row);
splice @{this->pixmaps}, $row, 0, $pixmap;
splice @{this->locations}, $row, 0, $location;
this->endInsertRows();
}
sub flags
{
my ($index) = @_;
if ($index->isValid()) {
return (Qt::ItemIsEnabled() | Qt::ItemIsSelectable() | Qt::ItemIsDragEnabled());
}
return Qt::ItemIsDropEnabled();
}
sub removeRows
{
my ($row, $count, $parent) = @_;
if ($parent->isValid()) {
return 0;
}
if ($row >= scalar @{this->pixmaps} || $row + $count <= 0) {
return 0;
}
my $beginRow = max(0, $row);
my $endRow = min($row + $count - 1, scalar @{this->pixmaps} - 1);
this->beginRemoveRows($parent, $beginRow, $endRow);
while ($beginRow <= $endRow) {
splice @{this->pixmaps}, $beginRow, 1;
splice @{this->locations}, $beginRow, 1;
++$beginRow;
}
this->endRemoveRows();
return 1;
}
sub mimeTypes
{
return [ 'image/x-puzzle-piece' ];
}
sub mimeData
{
my ($indexes) = @_;
my $mimeData = Qt::MimeData();
my $encodedData = Qt::ByteArray();
my $stream = Qt::DataStream($encodedData, Qt::IODevice::WriteOnly());
foreach my $index ( @{$indexes} ) {
if ($index->isValid()) {
my $pixmap = Qt::qVariantValue( this->data($index, Qt::UserRole()), 'Qt::Pixmap' );
my $location = this->data($index, Qt::UserRole()+1)->toPoint();
no warnings qw(void); # Ignore bitshift warning
$stream << $pixmap << $location;
use warnings;
}
}
$mimeData->setData('image/x-puzzle-piece', $encodedData);
return $mimeData;
}
sub dropMimeData
{
my ($data, $action, $row, $column, $parent) = @_;
if (!$data->hasFormat('image/x-puzzle-piece')) {
return 0;
}
if ($action == Qt::IgnoreAction()) {
return 1;
}
if ($column > 0) {
return 0;
}
my $endRow;
if (!$parent->isValid()) {
if ($row < 0) {
$endRow = scalar @{this->pixmaps};
}
else {
$endRow = min($row, scalar @{this->pixmaps});
}
} else {
$endRow = $parent->row();
}
my $encodedData = $data->data('image/x-puzzle-piece');
my $stream = Qt::DataStream($encodedData, Qt::IODevice::ReadOnly());
while (!$stream->atEnd()) {
my $pixmap = Qt::Pixmap();
my $location = Qt::Point();
no warnings qw(void); # Ignore bitshift warning
$stream >> $pixmap >> $location;
use warnings;
this->beginInsertRows(Qt::ModelIndex(), $endRow, $endRow);
splice @{this->pixmaps}, $endRow, 0, $pixmap;
splice @{this->locations}, $endRow, 0, $location;
this->endInsertRows();
++$endRow;
}
return 1;
}
sub rowCount
{
my ($parent) = @_;
if ($parent->isValid()) {
return 0;
}
else {
return scalar @{this->pixmaps};
}
}
sub supportedDropActions
{
return Qt::CopyAction() | Qt::MoveAction();
}
sub addPieces
{
my ($pixmap) = @_;
this->beginRemoveRows(Qt::ModelIndex(), 0, 24);
this->{pixmaps} = [];
this->{locations} = [];
this->endRemoveRows();
foreach my $y (0..4) {
foreach my $x (0..4) {
my $pieceImage = $pixmap->copy($x*80, $y*80, 80, 80);
this->addPiece($pieceImage, Qt::Point($x, $y));
}
}
}
1;