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) { void BlockGrid::mousePressEvent(QMouseEvent* event) {
m_block_dnd.mouse_press_event(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() { void BlockGrid::advance_frame() {
for (auto& ico : m_icons) { for (auto& ico : m_icons) {
ico.advance_frame(); ico.advance_frame();

View file

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

View file

@ -22,9 +22,13 @@
#include <QMimeData> #include <QMimeData>
#include <QDrag> #include <QDrag>
#include <QApplication> #include <QApplication>
#include <QWidget>
#include <cassert> #include <cassert>
#include <ciso646> #include <ciso646>
#include <memory> #include <memory>
#if !defined(NDEBUG)
# include <iostream>
#endif
namespace duck::widget::detail { namespace duck::widget::detail {
namespace { namespace {
@ -32,38 +36,74 @@ constexpr char g_drag_mime[] = "application/x-dndblock";
} //unnamed namespace } //unnamed namespace
BlockDragAndDrop::BlockDragAndDrop ( BlockDragAndDrop::BlockDragAndDrop (
QObject* parent, QWidget* parent,
PointToIndexFunc&& func, 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 std::function<const QPixmap&(std::size_t)>&& get_pixmap
) : ) :
m_point_to_index(std::move(func)), 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_get_pixmap(std::move(get_pixmap)),
m_parent(parent) m_parent(parent)
{ {
assert(m_parent); assert(m_parent);
m_parent->setAcceptDrops(true);
} }
void BlockDragAndDrop::mouse_press_event (const QMouseEvent* event) { void BlockDragAndDrop::mouse_press_event (const QMouseEvent* event) {
const auto [icon_index, block_origin] = m_point_to_index(event->position().toPoint()); if (event->button() & Qt::LeftButton) {
if (icon_index < 0) assert(not m_dragging);
return;
const auto icon_index_uns = static_cast<std::size_t>(icon_index); const auto [block_index, block_origin] = m_point_to_index(event->position().toPoint());
if (icon_index_uns >= m_get_block_count()) 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; 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; QByteArray item_data;
QDataStream data_stream(&item_data, QIODevice::WriteOnly); 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); std::unique_ptr<QMimeData> mime_data(new QMimeData);
mime_data->setData(g_drag_mime, item_data); 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)); QDrag* const drag(new QDrag(m_parent));
drag->setMimeData(mime_data.release()); drag->setMimeData(mime_data.release());
drag->setPixmap(m_get_pixmap(icon_index_uns)); drag->setPixmap(m_get_pixmap(icon_index));
drag->setHotSpot(event->position().toPoint() - block_origin); drag->setHotSpot(m_hot_spot);
switch (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction)) { switch (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction)) {
case Qt::MoveAction: case Qt::MoveAction:
@ -73,5 +113,14 @@ void BlockDragAndDrop::mouse_press_event (const QMouseEvent* event) {
default: default:
break; 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 } //namespace duck::widget::detail

View file

@ -23,6 +23,9 @@
class QMouseEvent; class QMouseEvent;
class QPixmap; class QPixmap;
class QWidget;
class QDragEnterEvent;
class QDropEvent;
namespace duck::widget::detail { namespace duck::widget::detail {
class BlockDragAndDrop { class BlockDragAndDrop {
@ -30,19 +33,27 @@ public:
typedef std::function<std::pair<int,QPoint>(QPoint)> PointToIndexFunc; typedef std::function<std::pair<int,QPoint>(QPoint)> PointToIndexFunc;
BlockDragAndDrop ( BlockDragAndDrop (
QObject* parent, QWidget* parent,
PointToIndexFunc&& func, 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 std::function<const QPixmap&(std::size_t)>&& get_pixmap
); );
void mouse_press_event (const QMouseEvent* event); 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: private:
PointToIndexFunc m_point_to_index; 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; 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 } //namespace duck::widget::detail