Implements tab-movement, changing the order of tabs by dragging with mouse.

This commit is contained in:
mfreiholz 2016-02-02 08:24:12 +01:00
parent 863d3233ad
commit bc14d9255f
5 changed files with 118 additions and 31 deletions

View File

@ -42,6 +42,7 @@ static void deleteEmptySplitter(ContainerWidget* container)
SectionTitleWidget::SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent) :
QFrame(parent),
_content(content),
_tabMoving(false),
_activeTab(false)
{
auto l = new QBoxLayout(QBoxLayout::LeftToRight);
@ -83,10 +84,7 @@ void SectionTitleWidget::mousePressEvent(QMouseEvent* ev)
void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
{
// qDebug() << Q_FUNC_INFO << ev->pos();
if (!_dragStartPos.isNull())
{
emit clicked();
}
SectionWidget* section = NULL;
// Drop contents of FloatingWidget into SectionWidget.
if (_fw)
@ -153,9 +151,28 @@ void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
}
}
}
// End of tab moving, change order now
else if (_tabMoving
&& (section = findParentSectionWidget(this)) != NULL)
{
qDebug() << "Stop tab move";
// Find tab under mouse
QPoint pos = ev->globalPos();
pos = section->mapFromGlobal(pos);
const int fromIndex = section->indexOfContent(_content);
const int toIndex = section->indexOfContentByTitlePos(pos, this);
qDebug() << "from" << fromIndex << "to" << toIndex;
section->moveContent(fromIndex, toIndex);
section->layout()->update();
}
if (!_dragStartPos.isNull())
emit clicked();
// Reset
_dragStartPos = QPoint();
_tabMoving = false;
hideDropOverlay();
QFrame::mouseReleaseEvent(ev);
}
@ -207,15 +224,11 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
ev->accept();
return;
}
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
&& (section = findParentSectionWidget(this)) != NULL && section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
{
// qDebug() << "Move inside title area" << ev->pos();
}
// Begin to drag/float the SectionContent.
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton) && (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()
&& (section = findParentSectionWidget(this)) != NULL)
else if (!_fw && !_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
//&& (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()
&& (section = findParentSectionWidget(this)) != NULL
&& !section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
{
// Create floating widget.
auto data = section->take(_content->uid(), false);
@ -241,6 +254,27 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
ev->accept();
return;
}
// Handle movement of this tab
else if (_tabMoving
&& (section = findParentSectionWidget(this)) != NULL)
{
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QPoint moveToPos = mapToParent(ev->pos()) - _dragStartPos;
moveToPos.setY(0 + top);
move(moveToPos);
ev->accept();
}
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
&& (section = findParentSectionWidget(this)) != NULL
&& section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
{
// Raise current title-widget above other tabs
_tabMoving = true;
raise();
ev->accept();
}
QFrame::mouseMoveEvent(ev);
}

View File

@ -19,9 +19,15 @@ class SectionTitleWidget : public QFrame
friend class SectionWidget;
SectionContent::RefPtr _content;
// Drag & Drop (Floating)
QPointer<FloatingWidget> _fw;
QPoint _dragStartPos;
// Drag & Drop (Title/Tabs)
bool _tabMoving;
// Property values
bool _activeTab;
public:

View File

@ -189,9 +189,52 @@ InternalContentData SectionWidget::take(int uid, bool del)
return data;
}
int SectionWidget::indexOfContent(SectionContent::RefPtr c) const
{
return _contents.indexOf(c);
}
int SectionWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
{
int index = -1;
for (int i = 0; i < _sectionTitles.size(); ++i)
{
if (_sectionTitles[i]->geometry().contains(p) && (exclude == NULL || _sectionTitles[i] != exclude))
{
index = i;
break;
}
}
return index;
}
void SectionWidget::moveContent(int from, int to)
{
if (from >= _contents.size() || from < 0 || to >= _contents.size() || to < 0 || from == to)
{
qCritical() << "Invalid index for tab movement" << from << to;
return;
}
SectionContent::RefPtr sc = _contents.at(from);
_contents.move(from, to);
_sectionTitles.move(from, to);
_sectionContents.move(from, to);
QLayoutItem* liFrom = NULL;
liFrom = _tabsLayout->takeAt(from);
_tabsLayout->insertItem(to, liFrom);
liFrom = _contentsLayout->takeAt(from);
_contentsLayout->insertWidget(to, liFrom->widget());
delete liFrom;
}
void SectionWidget::setCurrentIndex(int index)
{
// Set active TAB.
qDebug() << Q_FUNC_INFO << index;
for (int i = 0; i < _tabsLayout->count(); ++i)
{
auto item = _tabsLayout->itemAt(i);

View File

@ -39,6 +39,10 @@ public:
void addContent(SectionContent::RefPtr c);
void addContent(const InternalContentData& data, bool autoActivate);
InternalContentData take(int uid, bool del = true);
int indexOfContent(SectionContent::RefPtr c) const;
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = NULL) const;
void moveContent(int from, int to);
public slots:
void setCurrentIndex(int index);

View File

@ -39,27 +39,27 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(ads);
// Development style.
// a.setStyleSheet(""
// " QSplitter::handle { border: 1px solid #000000; background: #000000; } "
// " ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; } "
// " ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; } "
// " ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; } "
// " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; } "
// " ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; } "
// );
a.setStyleSheet(""
" QSplitter::handle { border: 1px solid #000000; background: #000000; } "
" ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; padding: 6px; } "
" ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; padding: 6px; } "
" ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; padding: 6px; } "
" ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; padding: 6px; } "
" ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; padding: 6px; } "
);
// PARTsolutions style.
a.setStyleSheet(""
" QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } "
" QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } "
" ads--ContainerWidget { border: 0; background: #9ab6ca; } "
" ads--SectionWidget { border-width: 1px; border-color: #ffffff; border-style: solid; background: #7c9eb3; padding: 0; margin: 0; } "
" ads--SectionTitleWidget { border-right: 1px solid #E7F3F8; background: #7c9eb3; } "
" ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } "
" ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } "
" ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } "
" ads--FloatingWidget QPushButton { background: #E7F3F8; } "
);
// a.setStyleSheet(""
// " QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } "
// " QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } "
// " ads--ContainerWidget { border: 0; background: #9ab6ca; } "
// " ads--SectionWidget { border-width: 1px; border-color: #ffffff; border-style: solid; background: #7c9eb3; padding: 0; margin: 0; } "
// " ads--SectionTitleWidget { border-right: 1px solid #E7F3F8; background: #7c9eb3; } "
// " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } "
// " ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } "
// " ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } "
// " ads--FloatingWidget QPushButton { background: #E7F3F8; } "
// );
MainWindow mw;
resizeWidgetPerCent(&mw, 60, 80);