Skip to content

Commit

Permalink
HotcueButton: move drag info and dnd verification to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
ronso0 committed Jan 29, 2025
1 parent 278806d commit 6b8f516
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 64 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1510,6 +1510,7 @@ add_library(
src/widget/findonwebmenuservices/findonwebmenulastfm.cpp
src/widget/findonwebmenuservices/findonwebmenusoundcloud.cpp
src/widget/hexspinbox.cpp
src/widget/hotcuedrag.cpp
src/widget/paintable.cpp
src/widget/wanalysislibrarytableview.cpp
src/widget/wbasewidget.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/skin/legacy/legacyskinparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1917,7 +1917,7 @@ QString LegacySkinParser::getSharedGroupString(const QString& channelStr) {

QWidget* LegacySkinParser::parseHotcueButton(const QDomElement& element) {
QString group = lookupNodeGroup(element);
WHotcueButton* pWidget = new WHotcueButton(group, m_pParent);
WHotcueButton* pWidget = new WHotcueButton(m_pParent, group);
commonWidgetSetup(element, pWidget);
pWidget->setup(element, *m_pContext);
pWidget->installEventFilter(m_pKeyboard);
Expand Down
60 changes: 60 additions & 0 deletions src/widget/hotcuedrag.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <widget/hotcuedrag.h>

#include <QDragEnterEvent>
#include <QMimeData>
#include <QMouseEvent>
#include <QString>

#include "mixer/playerinfo.h"
#include "track/track.h"

namespace mixxx {

namespace hotcuedrag {

/// Check if the event is a valid hotcue drag or drop event.
/// Event must be a QDragEnterEvent or a QDropEvent.
/// In case of QDropEvent, the HotcueDragInfo is extracted and the pointer
/// data is used by the caller (WHotcueButton) to swap hotuces.
template<typename T>
bool isValidHotcueDragOrDropEvent(T* pEvent,
QObject* pTarget,
const QString& group,
int ignoreHotcueIndex,
HotcueDragInfo* pDragData) {
bool isDrag = std::same_as<QDragEnterEvent, T>;
// Allow source == target in the drag case so we get the drag cursor
// (i.e. not the 'drop rejected' cursor) when starting the drag and when
// dragging over the source later on.
// Same exception for hotcue index check below.
if (!isDrag && pEvent->source() == pTarget) {
return false;
}
TrackPointer pTrack = PlayerInfo::instance().getTrackInfo(group);
if (!pTrack) {
return false;
}
const QByteArray mimeDataBytes = pEvent->mimeData()->data(kDragDataType);
if (mimeDataBytes.isEmpty()) {
return false;
}
const HotcueDragInfo dragData = HotcueDragInfo::fromByteArray(mimeDataBytes);
if (dragData.isValid() &&
(isDrag || dragData.hotcue != ignoreHotcueIndex) &&
dragData.trackId == pTrack->getId()) {
if (pDragData != nullptr) {
*pDragData = dragData;
}
return true;
}
return false;
};

} // namespace hotcuedrag

} // namespace mixxx

template bool mixxx::hotcuedrag::isValidHotcueDragOrDropEvent<QDropEvent>(
QDropEvent*, QObject*, const QString&, int, HotcueDragInfo*);
template bool mixxx::hotcuedrag::isValidHotcueDragOrDropEvent<QDragEnterEvent>(
QDragEnterEvent*, QObject*, const QString&, int, HotcueDragInfo*);
60 changes: 60 additions & 0 deletions src/widget/hotcuedrag.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#include <QBuffer>
#include <QMimeData>
#include <QString>

#include "track/cue.h"
#include "track/trackid.h"

const QString kDragDataType = QStringLiteral("hotcueDragInfo");

class TrackId;

struct HotcueDragInfo {
HotcueDragInfo() {};
HotcueDragInfo(TrackId id, int cue)
: trackId(id),
hotcue(cue) {};

static HotcueDragInfo fromByteArray(const QByteArray& bytes) {
QDataStream stream(bytes);
TrackId trackId;
int hotcue;
stream >> trackId >> hotcue;
return HotcueDragInfo(trackId, hotcue);
};

QByteArray toByteArray() {
QByteArray bytes;
QDataStream dataStream(&bytes, QIODevice::WriteOnly);
dataStream << trackId << hotcue;
return bytes;
};

bool isValid() const {
return trackId.isValid() && hotcue != Cue::kNoHotCue;
}

TrackId trackId = TrackId();
int hotcue = Cue::kNoHotCue;
};

namespace mixxx {

namespace hotcuedrag {

/// Check if the event is a valid hotcue drag or drop event.
/// Event must be a QDragEnterEvent or a QDropEvent.
/// In case of QDropEvent, the HotcueDragInfo is extracted and the pointer
/// data is used by the caller (WHotcueButton) to swap hotuces.
template<typename T>
bool isValidHotcueDragOrDropEvent(T* pEvent,
QObject* pTarget,
const QString& group,
int ignoreHotcueIndex,
HotcueDragInfo* pDragData = nullptr);

} // namespace hotcuedrag

} // namespace mixxx
53 changes: 23 additions & 30 deletions src/widget/whotcuebutton.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "widget/whotcuebutton.h"

#include <widget/hotcuedrag.h>

#include <QApplication>
#include <QDrag>
#include <QDragEnterEvent>
Expand All @@ -18,10 +20,9 @@

namespace {
constexpr int kDefaultDimBrightThreshold = 127;
const QString kDragDataType = QStringLiteral("hotcueDragInfo");
} // anonymous namespace

WHotcueButton::WHotcueButton(const QString& group, QWidget* pParent)
WHotcueButton::WHotcueButton(QWidget* pParent, const QString& group)
: WPushButton(pParent),
m_group(group),
m_hotcue(Cue::kNoHotCue),
Expand Down Expand Up @@ -190,8 +191,9 @@ void WHotcueButton::mouseMoveEvent(QMouseEvent* pEvent) {

// Use the currently rendered button as dnd cursor
// (incl. hover and pressed style).
// Note: for some reason, both grab() and render() render with sharp corners,
// ie. qss 'border-radius' is not applied to the drag image.
// Note: both grab() and render() use the pure rect(),
// i.e. these render with sharp corners and qss 'border-radius'
// is not visible in the drag image.
const QPixmap currLook = grab(rect().marginsRemoved(m_dndRectMargins));
pDrag->setDragCursor(currLook, Qt::MoveAction);

Expand All @@ -207,39 +209,30 @@ void WHotcueButton::mouseMoveEvent(QMouseEvent* pEvent) {
}

void WHotcueButton::dragEnterEvent(QDragEnterEvent* pEvent) {
TrackPointer pTrack = PlayerInfo::instance().getTrackInfo(m_group);
if (!pTrack) {
return;
}
QByteArray mimeDataBytes = pEvent->mimeData()->data(kDragDataType);
if (mimeDataBytes.isEmpty()) {
return;
}
HotcueDragInfo dragData = HotcueDragInfo::fromByteArray(mimeDataBytes);
if (dragData.isValid() &&
dragData.trackId == pTrack->getId()) {
if (mixxx::hotcuedrag::isValidHotcueDragOrDropEvent<QDragEnterEvent>(
pEvent,
this,
m_group,
m_hotcue)) {
pEvent->acceptProposedAction();
} else {
pEvent->ignore();
}
}

void WHotcueButton::dropEvent(QDropEvent* pEvent) {
if (pEvent->source() == this) {
pEvent->ignore();
return;
}
TrackPointer pTrack = PlayerInfo::instance().getTrackInfo(m_group);
if (!pTrack) {
return;
}
QByteArray mimeDataBytes = pEvent->mimeData()->data(kDragDataType);
if (mimeDataBytes.isEmpty()) {
return;
}
HotcueDragInfo dragData = HotcueDragInfo::fromByteArray(mimeDataBytes);
if (dragData.isValid() &&
dragData.trackId == pTrack->getId() &&
dragData.hotcue != m_hotcue) {
HotcueDragInfo dragData = HotcueDragInfo();
if (pTrack &&
mixxx::hotcuedrag::isValidHotcueDragOrDropEvent<QDropEvent>(
pEvent,
this,
m_group,
m_hotcue,
&dragData)) {
pTrack->swapHotcues(dragData.hotcue, m_hotcue);
} else {
pEvent->ignore();
}
}

Expand Down
33 changes: 1 addition & 32 deletions src/widget/whotcuebutton.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,14 @@

#include <QString>

#include "track/trackid.h"
#include "util/parented_ptr.h"
#include "widget/wcuemenupopup.h"
#include "widget/wpushbutton.h"

class WHotcueButton : public WPushButton {
Q_OBJECT

struct HotcueDragInfo {
HotcueDragInfo(TrackId id, int cue)
: trackId(id),
hotcue(cue) {};

static HotcueDragInfo fromByteArray(const QByteArray& bytes) {
QDataStream stream(bytes);
TrackId trackId;
int hotcue;
stream >> trackId >> hotcue;
return HotcueDragInfo(trackId, hotcue);
};

QByteArray toByteArray() {
QByteArray bytes;
QDataStream dataStream(&bytes, QIODevice::WriteOnly);
dataStream << trackId << hotcue;
return bytes;
};

bool isValid() {
return trackId.isValid() && hotcue != Cue::kNoHotCue;
}

TrackId trackId = TrackId();
int hotcue = Cue::kNoHotCue;
};

public:
WHotcueButton(const QString& group, QWidget* pParent);
WHotcueButton(QWidget* pParent, const QString& group);

void setup(const QDomNode& node, const SkinContext& context) override;

Expand All @@ -60,7 +30,6 @@ class WHotcueButton : public WPushButton {
void mouseMoveEvent(QMouseEvent* pEvent) override;
void dragEnterEvent(QDragEnterEvent* pEvent) override;
void dropEvent(QDropEvent* pEvent) override;

void restyleAndRepaint() override;

private slots:
Expand Down
1 change: 0 additions & 1 deletion src/widget/wpushbutton.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ class WPushButton : public WWidget {
void focusOutEvent(QFocusEvent* e) override;
void fillDebugTooltip(QStringList* debug) override;

protected:
virtual void restyleAndRepaint();

// Associates a pixmap of a given state of the button with the widget
Expand Down

0 comments on commit 6b8f516

Please sign in to comment.