Skip to content

Commit

Permalink
feat: support drag tab to other for DTabBar
Browse files Browse the repository at this point in the history
Change-Id: I0b5a315537fe822dfb70587775804dca4da93966
  • Loading branch information
zccrs committed Jan 24, 2018
1 parent c4d3f48 commit f674947
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 18 deletions.
167 changes: 150 additions & 17 deletions src/widgets/dtabbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ class DTabBarPrivate : public QTabBar, public DObjectPrivate
explicit DTabBarPrivate(DTabBar* qq)
: QTabBar(qq)
, DObjectPrivate(qq) {
startDragDistance = qApp->startDragDistance();

addButton = new DTabBarAddButton(qq);
addButton->setObjectName("AddButton");
addButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
Expand Down Expand Up @@ -206,6 +208,7 @@ class DTabBarPrivate : public QTabBar, public DObjectPrivate
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void dragEnterEvent(QDragEnterEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
void dropEvent(QDropEvent *e) override;
void showEvent(QShowEvent *e) override;
Expand All @@ -222,18 +225,28 @@ class DTabBarPrivate : public QTabBar, public DObjectPrivate
Q_SLOT void startDrag(int tabIndex);

void setupMovableTab();
void stopMoveingTab();
void setupDragableTab();
void slide(int from, int to);
void layoutTab(int index);
void moveTabFinished(int index);
void layoutWidgets(int start = 0);

void updateTabSize();

void setDragingFromOther(bool v);

QList<QSize> tabMinimumSize;
QList<QSize> tabMaximumSize;
bool visibleAddButton = true;
DTabBarAddButton *addButton;
QPointer<QDrag> drag;
bool dragable = false;
int startDragDistance;
// 有从其它地方drag过来的标签页需要处理
bool dragingFromOther = false;
// 记录当前drag过来的对象是否可以当做新标签页插入
bool canInsertFromDrag = false;

QToolButton *leftScrollButton;
QToolButton *rightScrollButton;
Expand Down Expand Up @@ -262,14 +275,13 @@ void DTabBarPrivate::setupMovableTab()
QPixmap grabImage(grabRect.size() * devicePixelRatioF());
grabImage.setDevicePixelRatio(devicePixelRatioF());
grabImage.fill(Qt::transparent);
QStylePainter p(&grabImage, this);
QPainter p(&grabImage);
p.initFrom(this);

QStyleOptionTab tab;
initStyleOption(&tab, d->pressedIndex);
tab.rect.moveTopLeft(QPoint(taboverlap, 0));
p.drawControl(QStyle::CE_TabBarTab, tab);
p.end();
q_func()->paintTab(&p, d->pressedIndex, tab);

reinterpret_cast<DMovableTabWidget*>(d->movingTab)->setPixmap(grabImage);
d->movingTab->setGeometry(grabRect);
Expand All @@ -285,12 +297,32 @@ void DTabBarPrivate::setupMovableTab()
if (d->rightB)
d->rightB->raise();
d->movingTab->setVisible(true);
}

void DTabBarPrivate::setupDragableTab()
{
if (!dragable)
return;

D_Q(DTabBar);

QTabBarPrivate *d = reinterpret_cast<QTabBarPrivate *>(qGetPtrHelper(d_ptr));
QStyleOptionTab opt;
initStyleOption(&opt, d->pressedIndex);

QMimeData *mime_data = q->createMimeDataFromTab(d->pressedIndex, opt);

if (!mime_data)
return;

drag = new QDrag(this);
QMimeData *mime_data = new QMimeData();

QPoint hotspot = drag->hotSpot();
const QPixmap &grabImage = q->createDragPixmapFramTab(d->pressedIndex, opt, &hotspot);

drag->setPixmap(grabImage);
drag->setMimeData(mime_data);
drag->setHotSpot(hotspot);

QMetaObject::invokeMethod(this, "startDrag", Qt::QueuedConnection, Q_ARG(int, d->pressedIndex));
}
Expand Down Expand Up @@ -426,6 +458,15 @@ void DTabBarPrivate::updateTabSize()
}
}

void DTabBarPrivate::setDragingFromOther(bool v)
{
if (v == dragingFromOther)
return;

dragingFromOther = v;
update();
}

bool DTabBarPrivate::eventFilter(QObject *watched, QEvent *event)
{
QTabBarPrivate *d = reinterpret_cast<QTabBarPrivate *>(qGetPtrHelper(d_ptr));
Expand Down Expand Up @@ -537,8 +578,7 @@ void DTabBarPrivate::paintEvent(QPaintEvent *e)
if (i == selected)
continue;

if (!q->paintTab(&p, i, tab))
p.drawControl(QStyle::CE_TabBarTab, tab);
q->paintTab(&p, i, tab);
}

// Draw the selected tab last to get it "on top"
Expand All @@ -553,8 +593,7 @@ void DTabBarPrivate::paintEvent(QPaintEvent *e)
}
}
if (!d->dragInProgress) {
if (!q->paintTab(&p, selected, tab))
p.drawControl(QStyle::CE_TabBarTab, tab);
q->paintTab(&p, selected, tab);
} else {
int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this);
d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0));
Expand All @@ -567,6 +606,10 @@ void DTabBarPrivate::paintEvent(QPaintEvent *e)
cutTab.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicator, &cutTab, this);
p.drawPrimitive(QStyle::PE_IndicatorTabTear, cutTab);
}

if (dragingFromOther) {
p.fillRect(rect(), QColor(0, 0, 255, 128));
}
}

void DTabBarPrivate::mouseMoveEvent(QMouseEvent *event)
Expand All @@ -581,19 +624,28 @@ void DTabBarPrivate::mouseMoveEvent(QMouseEvent *event)
&& event->buttons() == Qt::NoButton)
moveTabFinished(d->pressedIndex);

int offset_x = qAbs(event->x() - d->dragStartPosition.x());
int offset_y = qAbs(event->y() - d->dragStartPosition.y());
bool valid_pressed_index = d->validIndex(d->pressedIndex);

// Start drag
if (!d->dragInProgress && d->pressedIndex != -1) {
if ((event->pos() - d->dragStartPosition).manhattanLength() > QApplication::startDragDistance()) {
if (!drag && valid_pressed_index) {
if (offset_y > startDragDistance) {
setupDragableTab();
}
}

// Start move
if (!d->dragInProgress && valid_pressed_index) {
if (offset_x > startDragDistance) {
d->dragInProgress = true;
setupMovableTab();
}
}

int offset = (event->pos() - d->dragStartPosition).manhattanLength();

if (event->buttons() == Qt::LeftButton
&& offset > QApplication::startDragDistance()
&& d->validIndex(d->pressedIndex)) {
&& offset_x > startDragDistance
&& valid_pressed_index) {

bool vertical = verticalTabs(d->shape);
int dragDistance;
Expand Down Expand Up @@ -658,9 +710,21 @@ void DTabBarPrivate::dragEnterEvent(QDragEnterEvent *e)
e->keyboardModifiers());

mouseMoveEvent(&event);
} else {
if (q_func()->canInsertFromMimeData(e->mimeData())) {
setDragingFromOther(true);
e->acceptProposedAction();
}
}
}

void DTabBarPrivate::dragLeaveEvent(QDragLeaveEvent *e)
{
setDragingFromOther(false);

QTabBar::dragLeaveEvent(e);
}

void DTabBarPrivate::dragMoveEvent(QDragMoveEvent *e)
{
if (e->source() == this) {
Expand All @@ -671,6 +735,11 @@ void DTabBarPrivate::dragMoveEvent(QDragMoveEvent *e)
e->keyboardModifiers());

mouseMoveEvent(&event);
} else {
if (q_func()->canInsertFromMimeData(e->mimeData())) {
setDragingFromOther(true);
e->acceptProposedAction();
}
}
}

Expand All @@ -684,6 +753,8 @@ void DTabBarPrivate::dropEvent(QDropEvent *e)
e->keyboardModifiers());

mouseReleaseEvent(&event);
} else {
setDragingFromOther(false);
}
}

Expand Down Expand Up @@ -1019,6 +1090,16 @@ void DTabBar::setMovable(bool movable)
d_func()->setMovable(movable);
}

bool DTabBar::isDragable() const
{
return d_func()->dragable;
}

void DTabBar::setDragable(bool dragable)
{
d_func()->dragable = dragable;
}

bool DTabBar::documentMode() const
{
return d_func()->documentMode();
Expand Down Expand Up @@ -1049,6 +1130,11 @@ void DTabBar::setChangeCurrentOnDrag(bool change)
d_func()->setChangeCurrentOnDrag(change);
}

int DTabBar::startDragDistance() const
{
return d_func()->startDragDistance;
}

void DTabBar::setCurrentIndex(int index)
{
d_func()->setCurrentIndex(index);
Expand All @@ -1062,13 +1148,60 @@ void DTabBar::setVisibleAddButton(bool visibleAddButton)
d->addButton->setVisible(visibleAddButton);
}

bool DTabBar::paintTab(QPainter *painter, int index, const QStyleOptionTab &option)
void DTabBar::setStartDragDistance(int startDragDistance)
{
d_func()->startDragDistance = startDragDistance;
}

void DTabBar::paintTab(QPainter *painter, int index, const QStyleOptionTab &option) const
{
Q_UNUSED(index)

style()->drawControl(QStyle::CE_TabBarTab, &option, painter, this);
}

QPixmap DTabBar::createDragPixmapFramTab(int index, const QStyleOptionTab &option, QPoint *hotspot) const
{
Q_UNUSED(hotspot)

QPixmap grabImage(option.rect.size() * devicePixelRatioF());
grabImage.setDevicePixelRatio(devicePixelRatioF());
grabImage.fill(Qt::transparent);

QStyleOptionTab tab = option;

int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this);

tab.rect.moveTopLeft(QPoint(taboverlap, 0));

QPainter p(&grabImage);
p.initFrom(d_func());
paintTab(&p, index, tab);

return grabImage;
}

QMimeData *DTabBar::createMimeDataFromTab(int index, const QStyleOptionTab &option) const
{
Q_UNUSED(painter)
Q_UNUSED(index)
Q_UNUSED(option)

return false;
QMimeData *data = new QMimeData();

data->setText(tabText(index));
data->setData("deepin/dtkwidget-DTabBar-data", QByteArray());

return data;
}

bool DTabBar::canInsertFromMimeData(const QMimeData *source) const
{
return source->hasFormat("deepin/dtkwidget-DTabBar-data");
}

void DTabBar::insertFromMimeData(const QMimeData *source)
{
insertTab(0, source->text());
}

DTabBarPrivate *DTabBar::d_func()
Expand Down
19 changes: 18 additions & 1 deletion src/widgets/dtabbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include <dtkwidget_global.h>
#include <dobject.h>

QT_BEGIN_NAMESPACE
class QMimeData;
QT_END_NAMESPACE

DCORE_USE_NAMESPACE
DWIDGET_BEGIN_NAMESPACE

Expand All @@ -46,9 +50,11 @@ class DTabBar : public QWidget, public DObject
Q_PROPERTY(QTabBar::SelectionBehavior selectionBehaviorOnRemove READ selectionBehaviorOnRemove WRITE setSelectionBehaviorOnRemove)
Q_PROPERTY(bool expanding READ expanding WRITE setExpanding)
Q_PROPERTY(bool movable READ isMovable WRITE setMovable)
Q_PROPERTY(bool dragable READ isDragable WRITE setDragable)
Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode)
Q_PROPERTY(bool autoHide READ autoHide WRITE setAutoHide)
Q_PROPERTY(bool changeCurrentOnDrag READ changeCurrentOnDrag WRITE setChangeCurrentOnDrag)
Q_PROPERTY(int startDragDistance READ startDragDistance WRITE setStartDragDistance)

public:
explicit DTabBar(QWidget *parent = 0);
Expand Down Expand Up @@ -128,6 +134,9 @@ class DTabBar : public QWidget, public DObject
bool isMovable() const;
void setMovable(bool movable);

bool isDragable() const;
void setDragable(bool dragable);

bool documentMode() const;
void setDocumentMode(bool set);

Expand All @@ -137,6 +146,8 @@ class DTabBar : public QWidget, public DObject
bool changeCurrentOnDrag() const;
void setChangeCurrentOnDrag(bool change);

int startDragDistance() const;

Q_SIGNALS:
void currentChanged(int index);
void tabCloseRequested(int index);
Expand All @@ -149,9 +160,15 @@ class DTabBar : public QWidget, public DObject
public Q_SLOTS:
void setCurrentIndex(int index);
void setVisibleAddButton(bool visibleAddButton);
void setStartDragDistance(int startDragDistance);

protected:
virtual bool paintTab(QPainter *painter, int index, const QStyleOptionTab &option);
virtual void paintTab(QPainter *painter, int index, const QStyleOptionTab &option) const;

virtual QPixmap createDragPixmapFramTab(int index, const QStyleOptionTab &option, QPoint *hotspot) const;
virtual QMimeData *createMimeDataFromTab(int index, const QStyleOptionTab &option) const;
virtual bool canInsertFromMimeData(const QMimeData *source) const;
virtual void insertFromMimeData(const QMimeData *source);

private:
DTabBarPrivate* d_func();
Expand Down

0 comments on commit f674947

Please sign in to comment.