Commit e3b7103a authored by Yann Boucher's avatar Yann Boucher
Browse files

Added support for dragging and dropping structures

parent ed9c113c
Pipeline #78341 passed with stages
in 17 seconds
......@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<height>370</height>
</rect>
</property>
<property name="windowTitle">
......@@ -145,6 +145,13 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Double clic pour faire un glisser-déposer de la structure.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_copy">
<property name="enabled">
......
......@@ -33,7 +33,9 @@ class GridGraphicsView : public QGraphicsView
public:
GridGraphicsView(GridView& gridview, QWidget* parent)
: QGraphicsView(parent), m_gridview(gridview)
{}
{
setAcceptDrops(true);
}
protected:
void mousePressEvent(QMouseEvent* event);
......@@ -54,6 +56,8 @@ public:
void set_current_pen(unsigned state);
unsigned current_pen() const;
void paste_structure_at(Coord origin, const Structure& s);
void set_clipboard(const Structure& s);
void copy_grid(const Grid& grid);
......
......@@ -30,8 +30,10 @@ signals:
private:
void load_structures();
QTreeWidgetItem *add_directory_contents(const QDir& dir);
bool load_structure(const QString& filename, Structure& s);
bool try_load_structure(const QString& filename, Structure& s);
void update_preview(const Structure& s);
QImage create_preview_image(const Structure &s, QColor background);
void create_drag(QTreeWidgetItem* item, int column);
private slots:
void update_info(QTreeWidgetItem* item, int column);
......
......@@ -98,5 +98,8 @@ public:
virtual Structure read_structure();
};
//! Lit une structure à partir d'un chemin de fichier, en déterminant automatiquement le type de format de structure
//! \exception StructureReaderException en cas de problème
Structure load_structure(const std::string& path);
#endif // STRUCTUREREADER_HPP
......@@ -18,6 +18,7 @@ Cette classe représente le widget utilisé pour l'affichage et l'interaction av
#include <QGridLayout>
#include <QToolTip>
#include <QLabel>
#include <QMimeData>
#include <QDebug>
......@@ -25,17 +26,22 @@ Cette classe représente le widget utilisé pour l'affichage et l'interaction av
#include <qmath.h>
#include "structurereader.hpp"
class GridItem : public QGraphicsRectItem
{
public:
GridItem(QColor color, const QString& state_name, QGraphicsItem *parent = nullptr)
: QGraphicsRectItem(0, 0, GridItem::width(), GridItem::height(), parent), m_state_name(state_name)
GridItem(GridView& in_gridview, QColor color, const QString& state_name, QGraphicsItem *parent = nullptr)
: QGraphicsRectItem(0, 0, GridItem::width(), GridItem::height(), parent), grid_view(in_gridview), m_state_name(state_name)
{
setAcceptHoverEvents(true);
setPen(QPen(QBrush(color), 0));
setBrush(QBrush(color));
setToolTip(m_state_name);
setFlag(QGraphicsItem::ItemIsSelectable);
setAcceptDrops(true);
view = nullptr;
}
static int width()
......@@ -44,13 +50,17 @@ public:
{ return 20; }
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
{
assert(scene()->views().size() != 0);
QGraphicsView* view = scene()->views().first();
if (!view)
{
assert(scene()->views().size() != 0);
view = scene()->views().first();
}
QSizeF screen_size = view->transform().mapRect(sceneBoundingRect()).size();
QRectF rect = boundingRect();
QRectF rect = QRectF(0, 0, width(), height());
if (screen_size.width() < 7.5)
painter->setPen(Qt::NoPen); // if the cell is too small, don't draw its outline
......@@ -69,10 +79,42 @@ protected:
painter->drawRect(rect);
}
void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override
{
if (event->mimeData()->hasText())
{
event->acceptProposedAction();
update();
}
}
void dropEvent(QGraphicsSceneDragDropEvent *event) override
{
event->acceptProposedAction();
QString file_path = event->mimeData()->text();
Structure s;
try
{
s = load_structure(file_path.toStdString());
}
catch (const StructureReaderException& e)
{
//qDebug() << "StructureReaderException : " << e.what() << "\n";
return;
}
grid_view.paste_structure_at(cell_pos, s);
}
// infos associées à la cellule affichée
public:
unsigned cell_state;
Coord cell_pos;
QGraphicsView* view;
GridView& grid_view;
private:
QString m_state_name;
......@@ -122,6 +164,7 @@ GridView::GridView(QWidget *parent)
m_view->setScene(m_scene);
m_view->viewport()->setCursor(Qt::ArrowCursor);
m_view->setBackgroundBrush(QBrush(Qt::gray));
m_view->setRubberBandSelectionMode(Qt::IntersectsItemBoundingRect); // provides better performance
detail::Graphics_view_zoom* z = new detail::Graphics_view_zoom(m_view);
(void)z;
......@@ -183,7 +226,7 @@ void GridView::copy_grid(const Grid &grid)
Coord pos = {static_cast<int>(i), static_cast<int>(j)};
unsigned state = grid.get_state(pos);
GridItem *item = new GridItem(stateColor_to_QColor(m_alph.getState(state).getColor()), QString::fromStdString(m_alph.getState(state).getStateLabel()));
GridItem *item = new GridItem(*this, stateColor_to_QColor(m_alph.getState(state).getColor()), QString::fromStdString(m_alph.getState(state).getStateLabel()));
//GridItem *item = new GridItem((i ^ j) % 2 ? Qt::blue : Qt::white, (i ^ j) % 2 ? "Alive" : "Dead");
item->setPos(QPointF(i*GridItem::width(), j*GridItem::height()));
item->cell_pos = Coord{(int)i, (int)j};
......@@ -260,18 +303,7 @@ void GridView::paste_clipboard()
Coord origin = top_left_of_selection();
for (const auto& cell : m_copy_paste_buffer)
{
Coord corrected = wrap_coords(cell.first + origin, m_width, m_height);
GridItem* item = item_at(corrected);
assert(item != nullptr);
item->cell_state = cell.second;
item->setBrush(QBrush(stateColor_to_QColor(m_alph.getState(cell.second).getColor())));
item->update();
}
paste_structure_at(origin, m_copy_paste_buffer);
}
void GridView::fill_selection(unsigned state)
......@@ -291,6 +323,21 @@ void GridView::delete_selection()
clear_selection();
}
void GridView::paste_structure_at(Coord origin, const Structure &s)
{
for (const auto& cell : s)
{
Coord corrected = wrap_coords(cell.first + origin, m_width, m_height);
GridItem* item = item_at(corrected);
assert(item != nullptr);
item->cell_state = cell.second;
item->setBrush(QBrush(stateColor_to_QColor(m_alph.getState(cell.second).getColor())));
item->update();
}
}
Coord GridView::top_left_of_selection() const
{
// on calcule la position du coin supérieur gauche de la sélection
......
......@@ -4,8 +4,6 @@
#include "structuresavingdialog.hpp"
#include "structurewriter.hpp"
#include <QDate>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
......
......@@ -2,7 +2,7 @@ QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++14
CONFIG += c++14
TEMPLATE = app
# You can make your code fail to compile if it uses deprecated APIs.
......
......@@ -10,6 +10,9 @@
#include <QTextStream>
#include <QPixmap>
#include <QImage>
#include <QDrag>
#include <QMimeData>
#include <QDebug>
StructureLibraryView::StructureLibraryView(QWidget *parent) :
......@@ -21,6 +24,7 @@ StructureLibraryView::StructureLibraryView(QWidget *parent) :
load_structures();
connect(ui->tree, &QTreeWidget::itemClicked, this, &StructureLibraryView::update_info);
connect(ui->tree, &QTreeWidget::itemDoubleClicked, this, &StructureLibraryView::create_drag);
connect(ui->button_copy, &QPushButton::pressed, this, &StructureLibraryView::copy_button_clicked);
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, [this](const QString&)
{
......@@ -65,7 +69,7 @@ QTreeWidgetItem *StructureLibraryView::add_directory_contents(const QDir &dir)
Q_FOREACH (QFileInfo file, files)
{
Structure s;
bool valid = load_structure(file.absoluteFilePath(), s);
bool valid = try_load_structure(file.absoluteFilePath(), s);
if (!valid)
continue;
......@@ -83,70 +87,48 @@ QTreeWidgetItem *StructureLibraryView::add_directory_contents(const QDir &dir)
return root;
}
bool StructureLibraryView::load_structure(const QString &filename, Structure &s)
bool StructureLibraryView::try_load_structure(const QString &filename, Structure &s)
{
QFile f(filename);
if (!f.open(QFile::ReadOnly | QFile::Text))
return false;
QTextStream in(&f);
std::string data = in.readAll().toStdString();
if (QFileInfo(filename).suffix() == "json")
try
{
JSONStructureReader json(data);
try
{
s = json.read_structure();
return true;
}
catch (const StructureReaderException& e)
{
qDebug() << "StructureReaderException : " << e.what() << "\n";
return false;
}
s = load_structure(filename.toStdString());
return true;
}
else if (QFileInfo(filename).suffix() == "rle")
catch (const StructureReaderException& e)
{
RLEStructureReader rle(data);
try
{
s = rle.read_structure();
return true;
}
catch (const StructureReaderException& e)
{
qDebug() << "StructureReaderException : " << e.what() << "\n";
return false;
}
}
else
//qDebug() << "StructureReaderException : " << e.what() << "\n";
return false;
}
}
void StructureLibraryView::update_preview(const Structure &s)
{
QPixmap pix;
QImage img(s.width(), s.height(), QImage::Format_RGB32);
img.fill(Qt::white);
for (const auto& cell : s)
img.setPixel(cell.first.x, cell.first.y, Qt::black);
/** to check wether load ok */
if(pix.convertFromImage(img)){
if(pix.convertFromImage(create_preview_image(s, Qt::white))){
/** scale pixmap to fit in label'size and keep ratio of pixmap */
pix = pix.scaled(ui->preview->size() - 2*QSize(ui->preview->lineWidth(), ui->preview->lineWidth()),Qt::KeepAspectRatio);
ui->preview->setPixmap(pix);
}
}
QImage StructureLibraryView::create_preview_image(const Structure &s, QColor background)
{
QImage img(s.width(), s.height(), QImage::Format_ARGB32);
img.fill(background);
for (const auto& cell : s)
img.setPixelColor(cell.first.x, cell.first.y, QColor(Qt::black));
return img;
}
void StructureLibraryView::update_info(QTreeWidgetItem *item, int column)
{
(void)column;
Structure s;
if (!load_structure(item->data(0, Qt::UserRole).toString(), s))
if (!try_load_structure(item->data(0, Qt::UserRole).toString(), s))
{
ui->button_copy->setEnabled(false);
return;
......@@ -178,8 +160,35 @@ void StructureLibraryView::copy_button_clicked()
QTreeWidgetItem* item = ui->tree->selectedItems()[0];
Structure s;
if (!load_structure(item->data(0, Qt::UserRole).toString(), s))
if (!try_load_structure(item->data(0, Qt::UserRole).toString(), s))
return;
emit structure_copied(s);
}
void StructureLibraryView::create_drag(QTreeWidgetItem *item, int column)
{
(void)column;
Structure s;
if (!try_load_structure(item->data(0, Qt::UserRole).toString(), s))
{
ui->button_copy->setEnabled(false);
return;
}
QDrag* drag = new QDrag(this);
QMimeData* mimeData = new QMimeData;
QString filename = QFileInfo(item->data(0, Qt::UserRole).toString()).absoluteFilePath();
QPixmap pix;
QImage img = create_preview_image(s, Qt::transparent);
pix.convertFromImage(img);
pix = pix.scaled(QSize(100, 100), Qt::KeepAspectRatio);
mimeData->setText(filename);
drag->setMimeData(mimeData);
drag->setPixmap(pix);
drag->exec(Qt::CopyAction);
}
......@@ -12,6 +12,8 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QFileInfo>
#include "structure.hpp"
#include <vector>
......@@ -270,3 +272,27 @@ Structure JSONStructureReader::read_structure()
s.load(data.begin(), data.end());
return s;
}
Structure load_structure(const std::string &path)
{
QString filename = QString::fromStdString(path);
QFile f(filename);
if (!f.open(QFile::ReadOnly | QFile::Text))
throw StructureReaderException("Impossible de lire le fichier");
QTextStream in(&f);
std::string data = in.readAll().toStdString();
if (QFileInfo(filename).suffix() == "json")
{
JSONStructureReader json(data);
return json.read_structure();
}
else if (QFileInfo(filename).suffix() == "rle")
{
RLEStructureReader rle(data);
return rle.read_structure();
}
else
throw StructureReaderException("Format de fichier de structure invalide");
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment