2012-01-29 02:25:37 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Eliot
|
|
|
|
* Copyright (C) 2012 Olivier Teulière
|
|
|
|
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include <QtGui/QHBoxLayout>
|
2012-12-23 18:40:40 +01:00
|
|
|
#include <QtGui/QDragEnterEvent>
|
|
|
|
#include <QtGui/QDragLeaveEvent>
|
|
|
|
#include <QtGui/QDragMoveEvent>
|
|
|
|
#include <QtGui/QDropEvent>
|
2012-01-29 02:25:37 +01:00
|
|
|
|
|
|
|
#include "rack_widget.h"
|
|
|
|
#include "tile_widget.h"
|
|
|
|
#include "tile_layout.h"
|
2012-12-25 16:30:37 +01:00
|
|
|
#include "play_model.h"
|
2012-01-29 02:25:37 +01:00
|
|
|
#include "qtcommon.h"
|
|
|
|
|
|
|
|
#include "public_game.h"
|
|
|
|
#include "pldrack.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
INIT_LOGGER(qt, RackWidget);
|
|
|
|
|
|
|
|
|
2012-12-23 18:40:40 +01:00
|
|
|
#define MIME_TYPE "text/x-tile"
|
|
|
|
|
|
|
|
|
2012-01-29 02:25:37 +01:00
|
|
|
RackWidget::RackWidget(QWidget *parent)
|
2012-12-25 16:30:37 +01:00
|
|
|
: QFrame(parent), m_game(NULL),
|
2012-12-29 19:18:12 +01:00
|
|
|
m_playModel(NULL), m_showOnlyLastTurn(false),
|
|
|
|
m_dragOrigin(-1)
|
2012-01-29 02:25:37 +01:00
|
|
|
{
|
|
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
|
2012-01-29 20:03:45 +01:00
|
|
|
TileLayout *layout = new TileLayout(1);
|
|
|
|
layout->setSpacing(5);
|
2012-12-17 22:53:24 +01:00
|
|
|
layout->setAlignment(Qt::AlignCenter);
|
2012-01-29 20:03:45 +01:00
|
|
|
setLayout(layout);
|
2012-12-23 18:40:40 +01:00
|
|
|
|
|
|
|
setAcceptDrops(true);
|
2012-01-29 02:25:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-25 16:30:37 +01:00
|
|
|
void RackWidget::setPlayModel(PlayModel *iPlayModel)
|
|
|
|
{
|
|
|
|
if (m_playModel != NULL)
|
|
|
|
m_playModel->disconnect(this, SLOT(refresh()));
|
|
|
|
if (iPlayModel != NULL)
|
|
|
|
{
|
|
|
|
QObject::connect(iPlayModel, SIGNAL(moveChanged(const Move &, const Move&)),
|
|
|
|
this, SLOT(refresh()));
|
|
|
|
}
|
|
|
|
m_playModel = iPlayModel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-29 02:25:37 +01:00
|
|
|
void RackWidget::setGame(const PublicGame *iGame)
|
|
|
|
{
|
|
|
|
m_game = iGame;
|
|
|
|
if (m_game == NULL)
|
|
|
|
{
|
|
|
|
// Delete the widgets
|
|
|
|
TileLayout *layout = (TileLayout*) this->layout();
|
|
|
|
layout->clear();
|
|
|
|
m_tilesVect.clear();
|
|
|
|
}
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::refresh()
|
|
|
|
{
|
|
|
|
if (m_game == NULL)
|
|
|
|
return;
|
|
|
|
|
2012-04-10 20:29:52 +02:00
|
|
|
if (m_showOnlyLastTurn && !m_game->isLastTurn())
|
|
|
|
return;
|
|
|
|
|
2012-12-18 09:56:07 +01:00
|
|
|
// Get the tiles
|
2012-01-29 02:25:37 +01:00
|
|
|
vector<Tile> tiles;
|
2012-03-26 07:48:33 +02:00
|
|
|
m_game->getCurrentRack().getAllTiles(tiles);
|
2012-01-29 02:25:37 +01:00
|
|
|
|
2012-12-18 09:56:07 +01:00
|
|
|
// Update the rack
|
|
|
|
setRack(tiles);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::setRack(const vector<Tile> &iTiles)
|
|
|
|
{
|
2012-12-29 19:18:12 +01:00
|
|
|
m_tiles = filterRack(iTiles);
|
2012-12-25 16:30:37 +01:00
|
|
|
|
2012-12-29 19:18:12 +01:00
|
|
|
unsigned tilesCount = m_tiles.size();
|
2012-12-18 09:56:07 +01:00
|
|
|
|
2012-01-29 02:25:37 +01:00
|
|
|
// Make sure we have as many widgets as there are letters in the rack
|
2012-12-18 09:56:07 +01:00
|
|
|
while (m_tilesVect.size() > tilesCount)
|
2012-01-29 02:25:37 +01:00
|
|
|
{
|
|
|
|
QtCommon::DestroyObject(m_tilesVect.back());
|
|
|
|
m_tilesVect.pop_back();
|
|
|
|
}
|
2012-12-18 09:56:07 +01:00
|
|
|
while (m_tilesVect.size() < tilesCount)
|
2012-01-29 02:25:37 +01:00
|
|
|
{
|
2012-12-23 18:40:40 +01:00
|
|
|
TileWidget *tileWidget =
|
|
|
|
new TileWidget(0, TileWidget::NONE, 0, m_tilesVect.size());
|
|
|
|
QObject::connect(tileWidget, SIGNAL(mousePressed(int, int, QMouseEvent*)),
|
|
|
|
this, SLOT(tilePressed(int, int, QMouseEvent*)));
|
2012-01-29 02:25:37 +01:00
|
|
|
tileWidget->setBorder(2);
|
|
|
|
layout()->addWidget(tileWidget);
|
|
|
|
m_tilesVect.push_back(tileWidget);
|
|
|
|
}
|
2012-12-18 09:56:07 +01:00
|
|
|
ASSERT(m_tilesVect.size() == tilesCount, "Invalid number of tiles");
|
2012-01-29 02:25:37 +01:00
|
|
|
|
|
|
|
// Update the widgets
|
2012-12-18 09:56:07 +01:00
|
|
|
for (unsigned int i = 0; i < tilesCount; ++i)
|
2012-01-29 02:25:37 +01:00
|
|
|
{
|
|
|
|
TileWidget *tileWidget = m_tilesVect[i];
|
2012-12-29 19:18:12 +01:00
|
|
|
tileWidget->tileChanged(TileWidget::NORMAL, m_tiles[i]);
|
2012-01-29 02:25:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-25 16:30:37 +01:00
|
|
|
vector<Tile> RackWidget::filterRack(const vector<Tile> &iTiles) const
|
|
|
|
{
|
|
|
|
if (m_playModel == NULL || !m_playModel->getMove().isValid())
|
|
|
|
return iTiles;
|
|
|
|
|
|
|
|
vector<Tile> result = iTiles;
|
|
|
|
const Round &round = m_playModel->getMove().getRound();
|
|
|
|
for (unsigned i = 0; i < round.getWordLen(); ++i)
|
|
|
|
{
|
|
|
|
if (round.isPlayedFromRack(i))
|
|
|
|
{
|
|
|
|
const Tile &t = round.getTile(i);
|
|
|
|
vector<Tile>::iterator it;
|
|
|
|
for (it = result.begin(); it != result.end(); ++it)
|
|
|
|
{
|
|
|
|
if (*it == t)
|
|
|
|
{
|
|
|
|
result.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-23 18:40:40 +01:00
|
|
|
// Drag & drop handling
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::tilePressed(int row, int col, QMouseEvent *event)
|
|
|
|
{
|
|
|
|
ASSERT(row == 0, "Multi-line racks are not supported");
|
|
|
|
ASSERT(col >= 0 && (unsigned)col < m_tilesVect.size(),
|
|
|
|
"Invalid tile index: " << col);
|
|
|
|
|
|
|
|
LOG_DEBUG("Starting drag for tile " << col);
|
|
|
|
|
|
|
|
TileWidget *tileWidget = m_tilesVect[col];
|
|
|
|
|
|
|
|
// Save the initial column of the moved tile
|
|
|
|
QMimeData *mimeData = new QMimeData;
|
2012-12-29 19:18:12 +01:00
|
|
|
mimeData->setData(MIME_TYPE, QByteArray());
|
|
|
|
m_dragOrigin = col;
|
2012-12-23 18:40:40 +01:00
|
|
|
|
|
|
|
// Create an image of the tile
|
|
|
|
QPixmap pixmap(tileWidget->size());
|
|
|
|
tileWidget->render(&pixmap);
|
|
|
|
|
|
|
|
// Initiate the drag
|
|
|
|
QDrag *drag = new QDrag(this);
|
|
|
|
drag->setMimeData(mimeData);
|
|
|
|
drag->setHotSpot(event->pos());
|
|
|
|
drag->setPixmap(pixmap);
|
|
|
|
|
|
|
|
if (!(drag->exec(Qt::MoveAction) == Qt::MoveAction))
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::dragEnterEvent(QDragEnterEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasFormat(MIME_TYPE))
|
|
|
|
event->accept();
|
|
|
|
else
|
|
|
|
event->ignore();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::dragLeaveEvent(QDragLeaveEvent *event)
|
|
|
|
{
|
|
|
|
event->accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::dragMoveEvent(QDragMoveEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasFormat(MIME_TYPE))
|
|
|
|
{
|
|
|
|
event->setDropAction(Qt::MoveAction);
|
2012-12-29 19:18:12 +01:00
|
|
|
|
|
|
|
int closestCol = findClosestTile(event->pos());
|
|
|
|
moveTile(m_dragOrigin, closestCol, true);
|
|
|
|
// We have a new drag origin, since we just moved the tile
|
|
|
|
m_dragOrigin = closestCol;
|
|
|
|
|
2012-12-23 18:40:40 +01:00
|
|
|
event->accept();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
event->ignore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RackWidget::dropEvent(QDropEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasFormat(MIME_TYPE))
|
|
|
|
{
|
2012-12-29 19:18:12 +01:00
|
|
|
int closestCol = findClosestTile(event->pos());
|
|
|
|
LOG_DEBUG("Dropping tile " << m_dragOrigin << " closest to tile " << closestCol);
|
2012-12-23 18:40:40 +01:00
|
|
|
|
2012-12-29 19:18:12 +01:00
|
|
|
moveTile(m_dragOrigin, closestCol);
|
2012-12-23 18:40:40 +01:00
|
|
|
|
|
|
|
event->setDropAction(Qt::MoveAction);
|
|
|
|
event->accept();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
event->ignore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RackWidget::findTile(const QPoint &iPos) const
|
|
|
|
{
|
|
|
|
for (unsigned i = 0; i < m_tilesVect.size(); ++i)
|
|
|
|
{
|
|
|
|
if (m_tilesVect[i]->geometry().contains(iPos))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RackWidget::findClosestTile(const QPoint &iPos) const
|
|
|
|
{
|
|
|
|
int minDist = geometry().bottomRight().manhattanLength();
|
|
|
|
int minIdx = -1;
|
|
|
|
for (unsigned i = 0; i < m_tilesVect.size(); ++i)
|
|
|
|
{
|
|
|
|
QPoint distPoint = iPos - m_tilesVect[i]->geometry().center();
|
|
|
|
int dist = distPoint.manhattanLength();
|
|
|
|
if (dist < minDist)
|
|
|
|
{
|
|
|
|
minDist = dist;
|
|
|
|
minIdx = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return minIdx;
|
|
|
|
}
|
|
|
|
|
2012-12-29 19:18:12 +01:00
|
|
|
|
|
|
|
void RackWidget::moveTile(int fromPos, int toPos, bool shaded)
|
|
|
|
{
|
|
|
|
if (fromPos != toPos)
|
|
|
|
{
|
|
|
|
// Change the order
|
|
|
|
Tile moved = m_tiles[fromPos];
|
|
|
|
m_tiles.erase(m_tiles.begin() + fromPos);
|
|
|
|
m_tiles.insert(m_tiles.begin() + toPos, moved);
|
|
|
|
// Update the rack
|
|
|
|
setRack(m_tiles);
|
|
|
|
}
|
|
|
|
// Change the look of the moved tile
|
2012-12-30 01:53:14 +01:00
|
|
|
m_tilesVect[toPos]->tileChanged(shaded ? TileWidget::SHADED : TileWidget::NORMAL,
|
2012-12-29 19:18:12 +01:00
|
|
|
m_tiles[toPos]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|