Drag&drop, working towards making it accept drop events

Still work in progress
This commit is contained in:
King_DuckZ 2025-02-14 12:33:28 +00:00
parent f933d66e55
commit b427f9e094
4 changed files with 95 additions and 15 deletions

View file

@ -126,10 +126,26 @@ void BlockGrid::paintEvent (QPaintEvent* event) {
}
}
void BlockGrid::dragEnterEvent(QDragEnterEvent* event) {
m_block_dnd.drag_enter_event(event);
}
void BlockGrid::dropEvent(QDropEvent* event) {
m_block_dnd.drop_event(event);
}
void BlockGrid::mousePressEvent(QMouseEvent* event) {
m_block_dnd.mouse_press_event(event);
}
void BlockGrid::mouseReleaseEvent(QMouseEvent* event) {
m_block_dnd.mouse_release_event(event);
}
void BlockGrid::mouseMoveEvent(QMouseEvent* event) {
m_block_dnd.mouse_move_event(event);
}
void BlockGrid::advance_frame() {
for (auto& ico : m_icons) {
ico.advance_frame();

View file

@ -46,7 +46,11 @@ public:
protected:
void paintEvent (QPaintEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
private slots:
void advance_frame();

View file

@ -22,9 +22,13 @@
#include <QMimeData>
#include <QDrag>
#include <QApplication>
#include <QWidget>
#include <cassert>
#include <ciso646>
#include <memory>
#if !defined(NDEBUG)
# include <iostream>
#endif
namespace duck::widget::detail {
namespace {
@ -32,38 +36,74 @@ constexpr char g_drag_mime[] = "application/x-dndblock";
} //unnamed namespace
BlockDragAndDrop::BlockDragAndDrop (
QObject* parent,
QWidget* parent,
PointToIndexFunc&& func,
std::function<std::size_t()>&& get_block_count,
std::function<std::size_t()>&& get_icon_count,
std::function<const QPixmap&(std::size_t)>&& get_pixmap
) :
m_point_to_index(std::move(func)),
m_get_block_count(std::move(get_block_count)),
m_get_icon_count(std::move(get_icon_count)),
m_get_pixmap(std::move(get_pixmap)),
m_parent(parent)
{
assert(m_parent);
m_parent->setAcceptDrops(true);
}
void BlockDragAndDrop::mouse_press_event (const QMouseEvent* event) {
const auto [icon_index, block_origin] = m_point_to_index(event->position().toPoint());
if (icon_index < 0)
return;
const auto icon_index_uns = static_cast<std::size_t>(icon_index);
if (icon_index_uns >= m_get_block_count())
if (event->button() & Qt::LeftButton) {
assert(not m_dragging);
const auto [block_index, block_origin] = m_point_to_index(event->position().toPoint());
if (block_index < 0)
return;
const auto icon_index = static_cast<std::size_t>(block_index);
if (icon_index >= m_get_icon_count())
return;
m_start_pos = event->position().toPoint();
m_dragging = true;
m_block_index = block_index;
m_hot_spot = m_start_pos - block_origin;
}
}
void BlockDragAndDrop::mouse_release_event(const QMouseEvent* event) {
if (event->button() & Qt::LeftButton) {
m_dragging = false;
#if !defined(NDEBUG)
std::cout << "Mouse button released before block's drag&drop\n";
#endif
}
}
void BlockDragAndDrop::mouse_move_event (const QMouseEvent* event) {
if (not m_dragging)
return;
if (not (event->buttons() & Qt::LeftButton))
return;
if ((event->position().toPoint() - m_start_pos).manhattanLength() < QApplication::startDragDistance())
return;
#if !defined(NDEBUG)
std::cout << "mouse_move_event() drag&drop started\n";
#endif
QByteArray item_data;
QDataStream data_stream(&item_data, QIODevice::WriteOnly);
data_stream << m_get_pixmap(icon_index_uns);
data_stream << m_get_pixmap(m_block_index);
std::unique_ptr<QMimeData> mime_data(new QMimeData);
mime_data->setData(g_drag_mime, item_data);
assert(m_block_index >= 0);
const auto icon_index = static_cast<unsigned int>(m_block_index);
QDrag* const drag(new QDrag(m_parent));
drag->setMimeData(mime_data.release());
drag->setPixmap(m_get_pixmap(icon_index_uns));
drag->setHotSpot(event->position().toPoint() - block_origin);
drag->setPixmap(m_get_pixmap(icon_index));
drag->setHotSpot(m_hot_spot);
switch (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction)) {
case Qt::MoveAction:
@ -73,5 +113,14 @@ void BlockDragAndDrop::mouse_press_event (const QMouseEvent* event) {
default:
break;
}
m_dragging = false;
}
void BlockDragAndDrop::drag_enter_event(QDragEnterEvent* event) {
if (not m_dragging and event->mimeData()->hasFormat(g_drag_mime))
event->acceptProposedAction();
}
void BlockDragAndDrop::drop_event(QDropEvent* event) {
}
} //namespace duck::widget::detail

View file

@ -23,6 +23,9 @@
class QMouseEvent;
class QPixmap;
class QWidget;
class QDragEnterEvent;
class QDropEvent;
namespace duck::widget::detail {
class BlockDragAndDrop {
@ -30,19 +33,27 @@ public:
typedef std::function<std::pair<int,QPoint>(QPoint)> PointToIndexFunc;
BlockDragAndDrop (
QObject* parent,
QWidget* parent,
PointToIndexFunc&& func,
std::function<std::size_t()>&& get_block_count,
std::function<std::size_t()>&& get_icon_count,
std::function<const QPixmap&(std::size_t)>&& get_pixmap
);
void mouse_press_event (const QMouseEvent* event);
void mouse_release_event (const QMouseEvent* event);
void mouse_move_event (const QMouseEvent* event);
void drag_enter_event(QDragEnterEvent* event);
void drop_event(QDropEvent* event);
private:
PointToIndexFunc m_point_to_index;
std::function<std::size_t()> m_get_block_count;
std::function<std::size_t()> m_get_icon_count;
std::function<const QPixmap&(std::size_t)> m_get_pixmap;
QObject* m_parent;
QWidget* m_parent;
QPoint m_start_pos;
QPoint m_hot_spot;
int m_block_index;
bool m_dragging {false};
};
} //namespace duck::widget::detail