Implemented proper drag&drop
This commit is contained in:
162
stripsgrid.cpp
162
stripsgrid.cpp
@@ -9,15 +9,12 @@
|
|||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "stripwidget.h"
|
#include "stripwidget.h"
|
||||||
#include "flowlayout.h"
|
#include "flowlayout.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
QDebug &operator<<(QDebug &debug, const QMouseEvent &event)
|
|
||||||
{
|
|
||||||
return debug << "QMouseEvent(" << event.pos() << event.source() << event.flags() << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void call_n_times(int count, T func)
|
void call_n_times(int count, T func)
|
||||||
{
|
{
|
||||||
@@ -40,6 +37,14 @@ StripsGrid::StripsGrid(QWidget *parent) :
|
|||||||
int column{0};
|
int column{0};
|
||||||
for (const auto text : {"Story", "To Do:", "In Progress:", "In Review:", "Done:"})
|
for (const auto text : {"Story", "To Do:", "In Progress:", "In Review:", "Done:"})
|
||||||
{
|
{
|
||||||
|
if (column)
|
||||||
|
{
|
||||||
|
auto line = new QFrame;
|
||||||
|
line->setFrameShape(QFrame::VLine);
|
||||||
|
line->setFrameShadow(QFrame::Sunken);
|
||||||
|
m_layout->addWidget(line, row, column++, (stories*2)+1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
auto label = new QLabel{text};
|
auto label = new QLabel{text};
|
||||||
{
|
{
|
||||||
auto font = label->font();
|
auto font = label->font();
|
||||||
@@ -48,13 +53,6 @@ StripsGrid::StripsGrid(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
label->setFixedHeight(40);
|
label->setFixedHeight(40);
|
||||||
m_layout->addWidget(label, row, column++);
|
m_layout->addWidget(label, row, column++);
|
||||||
|
|
||||||
{
|
|
||||||
auto line = new QFrame;
|
|
||||||
line->setFrameShape(QFrame::VLine);
|
|
||||||
line->setFrameShadow(QFrame::Sunken);
|
|
||||||
m_layout->addWidget(line, row, column++, (stories*2)+1, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,9 +71,10 @@ StripsGrid::StripsGrid(QWidget *parent) :
|
|||||||
|
|
||||||
int storyPoints{0};
|
int storyPoints{0};
|
||||||
|
|
||||||
auto storyWidget = new StripWidget;
|
Story story;
|
||||||
storyWidget->setTitle(QString("ATC-%0").arg(random.bounded(1000, 5000)));
|
story.widget = new StripWidget;
|
||||||
storyWidget->setStyleSheet("StripWidget { background-color: #AFA; }");
|
story.widget->setTitle(QString("ATC-%0").arg(random.bounded(1000, 5000)));
|
||||||
|
story.widget->setStyleSheet("StripWidget { background-color: #AFA; }");
|
||||||
|
|
||||||
for (int column = 0; column < 5; column++)
|
for (int column = 0; column < 5; column++)
|
||||||
{
|
{
|
||||||
@@ -83,19 +82,16 @@ StripsGrid::StripsGrid(QWidget *parent) :
|
|||||||
{
|
{
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
layout->addSpacing(0);
|
layout->addSpacing(0);
|
||||||
layout->addWidget(storyWidget);
|
layout->addWidget(story.widget);
|
||||||
layout->addStretch(1);
|
layout->addStretch(1);
|
||||||
m_layout->addLayout(layout, row, column*2);
|
m_layout->addLayout(layout, row, column*2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int count = random.bounded(0, 5);
|
auto &test = story.columns[column-1];
|
||||||
if (!count)
|
test.layout = new FlowLayout;
|
||||||
continue;
|
|
||||||
|
|
||||||
auto layout = new FlowLayout;
|
call_n_times(random.bounded(6), [&]()
|
||||||
|
|
||||||
call_n_times(count, [&]()
|
|
||||||
{
|
{
|
||||||
auto widget = new StripWidget;
|
auto widget = new StripWidget;
|
||||||
widget->setTitle(QString("ATC-%0").arg(random.bounded(1000, 5000)));
|
widget->setTitle(QString("ATC-%0").arg(random.bounded(1000, 5000)));
|
||||||
@@ -106,71 +102,71 @@ StripsGrid::StripsGrid(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
widget->setOwner(std::array<const char *, 5>{"DB", "KW", "BK", "MS", "AS"}[random.bounded(5)]);
|
widget->setOwner(std::array<const char *, 5>{"DB", "KW", "BK", "MS", "AS"}[random.bounded(5)]);
|
||||||
widget->setStyleSheet("StripWidget { background-color: #FCC; }");
|
widget->setStyleSheet("StripWidget { background-color: #FCC; }");
|
||||||
layout->addWidget(widget);
|
test.layout->addWidget(widget);
|
||||||
|
test.widgets.push_back(widget);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_layout->addLayout(layout, row, column*2);
|
m_layout->addLayout(test.layout, row, column*2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storyWidget->setPoints(storyPoints);
|
story.widget->setPoints(storyPoints);
|
||||||
|
m_stories.push_back(story);
|
||||||
|
|
||||||
row++;
|
row++;
|
||||||
});
|
});
|
||||||
|
|
||||||
m_layout->addItem(new QSpacerItem{0, 40, QSizePolicy::Minimum, QSizePolicy::Expanding}, ++row, 0, 1, 5);
|
m_layout->addItem(new QSpacerItem{0, 40, QSizePolicy::Minimum, QSizePolicy::Expanding}, ++row, 0, 1, 5);
|
||||||
|
|
||||||
m_widget = new StripWidget{this};
|
|
||||||
m_widget->setStyleSheet("StripWidget { background-color: #88FFFF; }");
|
|
||||||
m_widget->move(100, 100);
|
|
||||||
|
|
||||||
// auto widget = new QWidget;
|
|
||||||
// setCentralWidget(widget);
|
|
||||||
|
|
||||||
// m_layout = new QGridLayout{widget};
|
|
||||||
// const auto addColumn = [&](const QString &name)
|
|
||||||
// {
|
|
||||||
// auto label = new QLabel{name};
|
|
||||||
// {
|
|
||||||
// auto font = label->font();
|
|
||||||
// font.setPointSize(30);
|
|
||||||
// label->setFont(font);
|
|
||||||
// }
|
|
||||||
// m_layout->addWidget(label, 0, m_layout->columnCount());
|
|
||||||
// };
|
|
||||||
// addColumn("To Do");
|
|
||||||
// addColumn("In Progress");
|
|
||||||
// addColumn("In Review");
|
|
||||||
// addColumn("Done");
|
|
||||||
|
|
||||||
// m_layout->addWidget(new QWidget, 1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StripsGrid::mousePressEvent(QMouseEvent *event)
|
void StripsGrid::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
qDebug() << "mousePressEvent" << *event;
|
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton &&
|
if (event->button() == Qt::LeftButton &&
|
||||||
!m_isDragging &&
|
!m_dragWidget)
|
||||||
m_widget->startDragging(event->pos() - m_widget->pos()))
|
|
||||||
{
|
{
|
||||||
m_widget->setGraphicsEffect(new QGraphicsOpacityEffect);
|
for (const auto &story : m_stories)
|
||||||
m_isDragging = true;
|
{
|
||||||
m_dragOffset = event->pos() - m_widget->pos();
|
for (const auto &column : story.columns)
|
||||||
|
{
|
||||||
|
for (auto *subtaskWidget : column.widgets)
|
||||||
|
{
|
||||||
|
if (subtaskWidget->startDragging(event->pos() - subtaskWidget->pos()))
|
||||||
|
{
|
||||||
|
m_draggedWidget = subtaskWidget;
|
||||||
|
m_draggedWidget->setGraphicsEffect(new QGraphicsBlurEffect);
|
||||||
|
|
||||||
|
m_dragWidget = new StripWidget{this};
|
||||||
|
m_dragWidget->setTitle(m_draggedWidget->title());
|
||||||
|
m_dragWidget->setDescription(m_draggedWidget->description());
|
||||||
|
m_dragWidget->setPoints(m_draggedWidget->points());
|
||||||
|
m_dragWidget->setOwner(m_draggedWidget->owner());
|
||||||
|
m_dragWidget->setStyleSheet(m_draggedWidget->styleSheet());
|
||||||
|
m_dragWidget->move(m_draggedWidget->pos());
|
||||||
|
m_dragWidget->setGraphicsEffect(new QGraphicsDropShadowEffect);
|
||||||
|
m_dragWidget->show();
|
||||||
|
|
||||||
|
m_dragOffset = event->pos() - m_draggedWidget->pos();
|
||||||
|
goto after;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
after:
|
||||||
|
|
||||||
QWidget::mousePressEvent(event);
|
QWidget::mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StripsGrid::mouseReleaseEvent(QMouseEvent *event)
|
void StripsGrid::mouseReleaseEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
qDebug() << "mouseReleaseEvent" << *event;
|
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton &&
|
if (event->button() == Qt::LeftButton &&
|
||||||
m_isDragging)
|
m_dragWidget)
|
||||||
{
|
{
|
||||||
m_widget->setGraphicsEffect(nullptr);
|
m_draggedWidget->setGraphicsEffect(nullptr);
|
||||||
m_isDragging = false;
|
m_draggedWidget = nullptr;
|
||||||
|
m_dragWidget->deleteLater();
|
||||||
|
m_dragWidget = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget::mouseReleaseEvent(event);
|
QWidget::mouseReleaseEvent(event);
|
||||||
@@ -178,10 +174,46 @@ void StripsGrid::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
void StripsGrid::mouseMoveEvent(QMouseEvent *event)
|
void StripsGrid::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
qDebug() << "mouseMoveEvent" << *event;
|
if (m_dragWidget)
|
||||||
|
{
|
||||||
|
Story::Column *currentColumn{};
|
||||||
|
|
||||||
if (m_isDragging)
|
for (auto &story : m_stories)
|
||||||
m_widget->move(event->pos() - m_dragOffset);
|
{
|
||||||
|
for (auto &column : story.columns)
|
||||||
|
{
|
||||||
|
if (std::find(column.widgets.begin(), column.widgets.end(), m_draggedWidget) != column.widgets.end())
|
||||||
|
currentColumn = &column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Story::Column *newColumn{};
|
||||||
|
for (auto &story : m_stories)
|
||||||
|
{
|
||||||
|
for (auto &column : story.columns)
|
||||||
|
{
|
||||||
|
if (column.layout->geometry().contains(event->pos()))
|
||||||
|
newColumn = &column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentColumn != newColumn && newColumn != nullptr)
|
||||||
|
{
|
||||||
|
if (currentColumn)
|
||||||
|
{
|
||||||
|
currentColumn->layout->removeWidget(m_draggedWidget);
|
||||||
|
currentColumn->widgets.erase(std::remove(currentColumn->widgets.begin(), currentColumn->widgets.end(), m_draggedWidget), currentColumn->widgets.end());
|
||||||
|
|
||||||
|
currentColumn->layout->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
newColumn->layout->addWidget(m_draggedWidget);
|
||||||
|
newColumn->widgets.push_back(m_draggedWidget);
|
||||||
|
newColumn->layout->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dragWidget->move(event->pos() - m_dragOffset);
|
||||||
|
}
|
||||||
|
|
||||||
QWidget::mouseMoveEvent(event);
|
QWidget::mouseMoveEvent(event);
|
||||||
}
|
}
|
||||||
|
21
stripsgrid.h
21
stripsgrid.h
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class QGridLayout;
|
class QGridLayout;
|
||||||
|
|
||||||
class StripWidget;
|
class StripWidget;
|
||||||
|
class FlowLayout;
|
||||||
|
|
||||||
class StripsGrid : public QWidget
|
class StripsGrid : public QWidget
|
||||||
{
|
{
|
||||||
@@ -21,7 +24,21 @@ protected:
|
|||||||
private:
|
private:
|
||||||
QGridLayout *m_layout;
|
QGridLayout *m_layout;
|
||||||
|
|
||||||
bool m_isDragging{false};
|
StripWidget *m_draggedWidget{};
|
||||||
|
StripWidget *m_dragWidget{};
|
||||||
QPoint m_dragOffset;
|
QPoint m_dragOffset;
|
||||||
StripWidget *m_widget;
|
|
||||||
|
struct Story {
|
||||||
|
StripWidget *widget;
|
||||||
|
|
||||||
|
struct Column {
|
||||||
|
FlowLayout *layout;
|
||||||
|
|
||||||
|
std::vector<StripWidget*> widgets;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<Column, 4> columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Story> m_stories;
|
||||||
};
|
};
|
||||||
|
@@ -19,21 +19,41 @@ bool StripWidget::startDragging(const QPoint &pos) const
|
|||||||
return m_ui->title->geometry().contains(pos);
|
return m_ui->title->geometry().contains(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString StripWidget::title() const
|
||||||
|
{
|
||||||
|
return m_ui->title->text();
|
||||||
|
}
|
||||||
|
|
||||||
void StripWidget::setTitle(const QString &title)
|
void StripWidget::setTitle(const QString &title)
|
||||||
{
|
{
|
||||||
m_ui->title->setText(title);
|
m_ui->title->setText(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString StripWidget::description() const
|
||||||
|
{
|
||||||
|
return m_ui->description->text();
|
||||||
|
}
|
||||||
|
|
||||||
void StripWidget::setDescription(const QString &description)
|
void StripWidget::setDescription(const QString &description)
|
||||||
{
|
{
|
||||||
m_ui->description->setText(description);
|
m_ui->description->setText(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int StripWidget::points() const
|
||||||
|
{
|
||||||
|
return m_ui->points->text().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
void StripWidget::setPoints(int points)
|
void StripWidget::setPoints(int points)
|
||||||
{
|
{
|
||||||
m_ui->points->setText(QString::number(points));
|
m_ui->points->setText(QString::number(points));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString StripWidget::owner() const
|
||||||
|
{
|
||||||
|
return m_ui->owner->text();
|
||||||
|
}
|
||||||
|
|
||||||
void StripWidget::setOwner(const QString &owner)
|
void StripWidget::setOwner(const QString &owner)
|
||||||
{
|
{
|
||||||
m_ui->owner->setText(owner);
|
m_ui->owner->setText(owner);
|
||||||
|
@@ -16,9 +16,16 @@ public:
|
|||||||
|
|
||||||
bool startDragging(const QPoint &pos) const;
|
bool startDragging(const QPoint &pos) const;
|
||||||
|
|
||||||
|
QString title() const;
|
||||||
void setTitle(const QString &title);
|
void setTitle(const QString &title);
|
||||||
|
|
||||||
|
QString description() const;
|
||||||
void setDescription(const QString &description);
|
void setDescription(const QString &description);
|
||||||
|
|
||||||
|
int points() const;
|
||||||
void setPoints(int points);
|
void setPoints(int points);
|
||||||
|
|
||||||
|
QString owner() const;
|
||||||
void setOwner(const QString &owner);
|
void setOwner(const QString &owner);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>195</width>
|
<width>183</width>
|
||||||
<height>105</height>
|
<height>105</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -26,14 +26,14 @@
|
|||||||
<widget class="QLabel" name="title">
|
<widget class="QLabel" name="title">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<pointsize>15</pointsize>
|
<pointsize>13</pointsize>
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
<enum>QFrame::Panel</enum>
|
<enum>QFrame::Panel</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow">
|
<property name="frameShadow">
|
||||||
<enum>QFrame::Sunken</enum>
|
<enum>QFrame::Plain</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">ATC-1234</string>
|
<string notr="true">ATC-1234</string>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<enum>QFrame::Sunken</enum>
|
<enum>QFrame::Sunken</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>1</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
<enum>QFrame::Sunken</enum>
|
<enum>QFrame::Sunken</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>OW</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
Reference in New Issue
Block a user