diff options
Diffstat (limited to 'Swift/QtUI/Trellis')
-rw-r--r-- | Swift/QtUI/Trellis/QtDNDTabBar.cpp | 220 | ||||
-rw-r--r-- | Swift/QtUI/Trellis/QtDNDTabBar.h | 55 | ||||
-rw-r--r-- | Swift/QtUI/Trellis/QtDynamicGridLayout.cpp | 786 | ||||
-rw-r--r-- | Swift/QtUI/Trellis/QtDynamicGridLayout.h | 98 | ||||
-rw-r--r-- | Swift/QtUI/Trellis/QtGridSelectionDialog.cpp | 222 | ||||
-rw-r--r-- | Swift/QtUI/Trellis/QtGridSelectionDialog.h | 91 |
6 files changed, 766 insertions, 706 deletions
diff --git a/Swift/QtUI/Trellis/QtDNDTabBar.cpp b/Swift/QtUI/Trellis/QtDNDTabBar.cpp index dbe397b..9a6c436 100644 --- a/Swift/QtUI/Trellis/QtDNDTabBar.cpp +++ b/Swift/QtUI/Trellis/QtDNDTabBar.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -18,12 +18,12 @@ namespace Swift { QtDNDTabBar::QtDNDTabBar(QWidget* parent) : QTabBar(parent) { - setAcceptDrops(true); + setAcceptDrops(true); - // detect the default tab bar height; - insertTab(0, ""); - defaultTabHeight = QTabBar::sizeHint().height(); - removeTab(0); + // detect the default tab bar height; + insertTab(0, ""); + defaultTabHeight = QTabBar::sizeHint().height(); + removeTab(0); } QtDNDTabBar::~QtDNDTabBar() { @@ -31,136 +31,136 @@ QtDNDTabBar::~QtDNDTabBar() { } int QtDNDTabBar::getDragIndex() const { - return dragIndex; + return dragIndex; } QString QtDNDTabBar::getDragText() const { - return dragText; + return dragText; } QWidget* QtDNDTabBar::getDragWidget() const { - return dragWidget; + return dragWidget; } QSize QtDNDTabBar::sizeHint() const { - QSize hint = QTabBar::sizeHint(); - if (hint.isEmpty()) { - hint = QSize(parentWidget()->width(), defaultTabHeight); - } - return hint; + QSize hint = QTabBar::sizeHint(); + if (hint.isEmpty()) { + hint = QSize(parentWidget()->width(), defaultTabHeight); + } + return hint; } QSize QtDNDTabBar::tabSizeHint(int index) const { - QSize tabSize = QTabBar::tabSizeHint(index); + QSize tabSize = QTabBar::tabSizeHint(index); #if defined(Q_OS_MAC) - // With multiple tabs having the same label in a QTabBar, the size hint computed by - // Qt on OS X is too small and it is elided even though there is enough horizontal - // space available. We work around this issue by adding the width of a letter to the - // size hint. - tabSize += QSize(QFontMetrics(font()).width("I"), 0); + // With multiple tabs having the same label in a QTabBar, the size hint computed by + // Qt on OS X is too small and it is elided even though there is enough horizontal + // space available. We work around this issue by adding the width of a letter to the + // size hint. + tabSize += QSize(QFontMetrics(font()).width("I"), 0); #endif - return tabSize; + return tabSize; } void QtDNDTabBar::dragEnterEvent(QDragEnterEvent* dragEnterEvent) { - QtDNDTabBar* sourceTabBar = dynamic_cast<QtDNDTabBar*>(dragEnterEvent->source()); - if (sourceTabBar) { - dragEnterEvent->acceptProposedAction(); - } + QtDNDTabBar* sourceTabBar = dynamic_cast<QtDNDTabBar*>(dragEnterEvent->source()); + if (sourceTabBar) { + dragEnterEvent->acceptProposedAction(); + } } void QtDNDTabBar::dropEvent(QDropEvent* dropEvent) { - QtDNDTabBar* sourceTabBar = dynamic_cast<QtDNDTabBar*>(dropEvent->source()); - if (sourceTabBar && dropEvent->mimeData() && dropEvent->mimeData()->data("action") == QByteArray("application/tab-detach")) { - QtDNDTabBar* source = dynamic_cast<QtDNDTabBar*>(dropEvent->source()); - - int targetTabIndex = tabAt(dropEvent->pos()); - QRect rect = tabRect(targetTabIndex); - if (targetTabIndex >= 0 && (dropEvent->pos().x() - rect.left() - rect.width()/2 > 0)) { - targetTabIndex++; - } - - QWidget* tab = source->getDragWidget(); - assert(tab); - QTabWidget* targetTabWidget = dynamic_cast<QTabWidget*>(parentWidget()); - - QString tabText = source->getDragText(); - - /* - * When you add a widget to an empty QTabWidget, it's automatically made the current widget. - * Making the widget the current widget, widget->show() is called for the widget. Directly reacting - * to that event, and adding the widget again to the QTabWidget results in undefined behavior. For - * example the tab label is shown but the widget is neither has the old nor in the new QTabWidget as - * parent. Blocking signals on the QWidget to be added to a QTabWidget prevents this behavior. - */ - targetTabWidget->setUpdatesEnabled(false); - tab->blockSignals(true); - targetTabWidget->insertTab(targetTabIndex, tab, tabText); - dropEvent->acceptProposedAction(); - tab->blockSignals(false); - targetTabWidget->setUpdatesEnabled(true); - onDropSucceeded(); - } + QtDNDTabBar* sourceTabBar = dynamic_cast<QtDNDTabBar*>(dropEvent->source()); + if (sourceTabBar && dropEvent->mimeData() && dropEvent->mimeData()->data("action") == QByteArray("application/tab-detach")) { + QtDNDTabBar* source = dynamic_cast<QtDNDTabBar*>(dropEvent->source()); + + int targetTabIndex = tabAt(dropEvent->pos()); + QRect rect = tabRect(targetTabIndex); + if (targetTabIndex >= 0 && (dropEvent->pos().x() - rect.left() - rect.width()/2 > 0)) { + targetTabIndex++; + } + + QWidget* tab = source->getDragWidget(); + assert(tab); + QTabWidget* targetTabWidget = dynamic_cast<QTabWidget*>(parentWidget()); + + QString tabText = source->getDragText(); + + /* + * When you add a widget to an empty QTabWidget, it's automatically made the current widget. + * Making the widget the current widget, widget->show() is called for the widget. Directly reacting + * to that event, and adding the widget again to the QTabWidget results in undefined behavior. For + * example the tab label is shown but the widget is neither has the old nor in the new QTabWidget as + * parent. Blocking signals on the QWidget to be added to a QTabWidget prevents this behavior. + */ + targetTabWidget->setUpdatesEnabled(false); + tab->blockSignals(true); + targetTabWidget->insertTab(targetTabIndex, tab, tabText); + dropEvent->acceptProposedAction(); + tab->blockSignals(false); + targetTabWidget->setUpdatesEnabled(true); + onDropSucceeded(); + } } bool QtDNDTabBar::event(QEvent* event) { - QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event); - if (mouseEvent) { - QWidget* childAtPoint = window()->childAt(mapTo(window(), mouseEvent->pos())); - QtDNDTabBar* underMouse = dynamic_cast<QtDNDTabBar*>(childAtPoint); - if (!underMouse && childAtPoint) { - underMouse = dynamic_cast<QtDNDTabBar*>(childAtPoint->parent()); - } - if (!underMouse && currentIndex() >= 0) { - // detach and drag - - // stop move event - QMouseEvent* finishMoveEvent = new QMouseEvent (QEvent::MouseMove, mouseEvent->pos (), Qt::NoButton, Qt::NoButton, Qt::NoModifier); - QTabBar::event(finishMoveEvent); - delete finishMoveEvent; - finishMoveEvent = NULL; - - // start drag - QDrag* drag = new QDrag(this); - QMimeData* mimeData = new QMimeData; - - // distinguish tab-reordering drops from other ones - mimeData->setData("action", "application/tab-detach") ; - drag->setMimeData(mimeData); - - // set drag image - QRect rect = tabRect( currentIndex() ); + QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event); + if (mouseEvent) { + QWidget* childAtPoint = window()->childAt(mapTo(window(), mouseEvent->pos())); + QtDNDTabBar* underMouse = dynamic_cast<QtDNDTabBar*>(childAtPoint); + if (!underMouse && childAtPoint) { + underMouse = dynamic_cast<QtDNDTabBar*>(childAtPoint->parent()); + } + if (!underMouse && currentIndex() >= 0) { + // detach and drag + + // stop move event + QMouseEvent* finishMoveEvent = new QMouseEvent (QEvent::MouseMove, mouseEvent->pos (), Qt::NoButton, Qt::NoButton, Qt::NoModifier); + QTabBar::event(finishMoveEvent); + delete finishMoveEvent; + finishMoveEvent = nullptr; + + // start drag + QDrag* drag = new QDrag(this); + QMimeData* mimeData = new QMimeData; + + // distinguish tab-reordering drops from other ones + mimeData->setData("action", "application/tab-detach") ; + drag->setMimeData(mimeData); + + // set drag image + QRect rect = tabRect( currentIndex() ); #if QT_VERSION >= 0x050000 - QPixmap pixmap = grab(rect); + QPixmap pixmap = grab(rect); #else - QPixmap pixmap = QPixmap::grabWidget(this, rect); + QPixmap pixmap = QPixmap::grabWidget(this, rect); #endif - QPixmap targetPixmap (pixmap.size ()); - QPainter painter (&targetPixmap); - painter.setOpacity(0.9); - painter.drawPixmap(0,0, pixmap); - painter.end (); - drag->setPixmap (targetPixmap); - - drag->setHotSpot(QPoint(drag->pixmap().width()/2, drag->pixmap().height())); - - dragIndex = currentIndex(); - dragText = tabText(dragIndex); - dragWidget = dynamic_cast<QTabWidget*>(parent())->widget(dragIndex); - assert(dragWidget); - dynamic_cast<QTabWidget*>(parent())->removeTab(currentIndex()); - Qt::DropAction dropAction = drag->exec(); - if (dropAction == Qt::IgnoreAction) { - // aborted drag, put tab back in place - // disable event handling during the insert for the tab to prevent infinite recursion (stack overflow) - dragWidget->blockSignals(true); - dynamic_cast<QTabWidget*>(parent())->insertTab(dragIndex, dragWidget, dragText); - dragWidget->blockSignals(false); - } - return true; - } - } - return QTabBar::event(event); + QPixmap targetPixmap (pixmap.size ()); + QPainter painter (&targetPixmap); + painter.setOpacity(0.9); + painter.drawPixmap(0,0, pixmap); + painter.end (); + drag->setPixmap (targetPixmap); + + drag->setHotSpot(QPoint(drag->pixmap().width()/2, drag->pixmap().height())); + + dragIndex = currentIndex(); + dragText = tabText(dragIndex); + dragWidget = dynamic_cast<QTabWidget*>(parent())->widget(dragIndex); + assert(dragWidget); + dynamic_cast<QTabWidget*>(parent())->removeTab(currentIndex()); + Qt::DropAction dropAction = drag->exec(); + if (dropAction == Qt::IgnoreAction) { + // aborted drag, put tab back in place + // disable event handling during the insert for the tab to prevent infinite recursion (stack overflow) + dragWidget->blockSignals(true); + dynamic_cast<QTabWidget*>(parent())->insertTab(dragIndex, dragWidget, dragText); + dragWidget->blockSignals(false); + } + return true; + } + } + return QTabBar::event(event); } } diff --git a/Swift/QtUI/Trellis/QtDNDTabBar.h b/Swift/QtUI/Trellis/QtDNDTabBar.h index 71ca94b..6de04d5 100644 --- a/Swift/QtUI/Trellis/QtDNDTabBar.h +++ b/Swift/QtUI/Trellis/QtDNDTabBar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -8,34 +8,37 @@ #include <QTabBar> +#include <Swift/QtUI/QtTabWidget.h> + namespace Swift { class QtDNDTabBar : public QTabBar { - Q_OBJECT - public: - explicit QtDNDTabBar(QWidget* parent = 0); - virtual ~QtDNDTabBar(); - - int getDragIndex() const; - QString getDragText() const; - QWidget* getDragWidget() const; - - virtual QSize sizeHint() const; - - signals: - void onDropSucceeded(); - - protected: - virtual void dragEnterEvent(QDragEnterEvent* dragEnterEvent); - virtual void dropEvent(QDropEvent* dropEvent); - virtual bool event(QEvent* event); - virtual QSize tabSizeHint(int index) const; - - private: - int defaultTabHeight; - int dragIndex; - QString dragText; - QWidget* dragWidget; + Q_OBJECT + public: + explicit QtDNDTabBar(QWidget* parent = nullptr); + virtual ~QtDNDTabBar(); + + int getDragIndex() const; + QString getDragText() const; + QWidget* getDragWidget() const; + + virtual QSize sizeHint() const; + + friend class QtTabWidget; + signals: + void onDropSucceeded(); + + protected: + virtual void dragEnterEvent(QDragEnterEvent* dragEnterEvent); + virtual void dropEvent(QDropEvent* dropEvent); + virtual bool event(QEvent* event); + virtual QSize tabSizeHint(int index) const; + + private: + int defaultTabHeight; + int dragIndex = -1; + QString dragText; + QWidget* dragWidget = nullptr; }; } diff --git a/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp b/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp index 3b8adf8..5600cc8 100644 --- a/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp +++ b/Swift/QtUI/Trellis/QtDynamicGridLayout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -23,128 +23,129 @@ namespace Swift { -QtDynamicGridLayout::QtDynamicGridLayout(QWidget* parent, bool enableDND) : QWidget(parent), dndEnabled_(enableDND), movingTab_(NULL) { - gridLayout_ = new QGridLayout(this); - setContentsMargins(0,0,0,0); - setDimensions(QSize(1,1)); - connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(handleApplicationFocusChanged(QWidget*,QWidget*))); +QtDynamicGridLayout::QtDynamicGridLayout(QWidget* parent, bool enableDND) : QWidget(parent), dndEnabled_(enableDND), movingTab_(nullptr) { + gridLayout_ = new QGridLayout(this); + setContentsMargins(0,0,0,0); + setDimensions(QSize(1,1)); + connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(handleApplicationFocusChanged(QWidget*,QWidget*))); } QtDynamicGridLayout::~QtDynamicGridLayout() { } int QtDynamicGridLayout::addTab(QtTabbable* tab, const QString& title) { - assert(gridLayout_->rowCount() > 0 && gridLayout_->columnCount() > 0); - - QPoint lastPos(0,0); - if (tabPositions_.contains(P2QSTRING(tab->getID()))) { - lastPos = tabPositions_[P2QSTRING(tab->getID())]; - } - - lastPos = QPoint(qMin(lastPos.x(), gridLayout_->columnCount() - 1), qMin(lastPos.y(), gridLayout_->rowCount() - 1)); - - QLayoutItem* item = gridLayout_->itemAtPosition(lastPos.y(), lastPos.x()); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(item ? item->widget() : 0); - if (tabWidget) { - tabWidget->addTab(tab, title); - } - return tabWidget ? indexOf(tab) : -1; + assert(gridLayout_->rowCount() > 0 && gridLayout_->columnCount() > 0); + + QPoint lastPos(0,0); + if (tabPositions_.contains(P2QSTRING(tab->getID()))) { + lastPos = tabPositions_[P2QSTRING(tab->getID())]; + } + + lastPos = QPoint(qMin(lastPos.x(), gridLayout_->columnCount() - 1), qMin(lastPos.y(), gridLayout_->rowCount() - 1)); + + QLayoutItem* item = gridLayout_->itemAtPosition(lastPos.y(), lastPos.x()); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(item ? item->widget() : nullptr); + if (tabWidget) { + tabWidget->addTab(tab, title); + } + tab->setEmphasiseFocus(getDimension().width() > 1 || getDimension().height() > 1); + return tabWidget ? indexOf(tab) : -1; } int QtDynamicGridLayout::count() const { - int count = 0; - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - if (tabWidget) { - count += tabWidget->count(); - } - } - } - return count; + int count = 0; + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + if (tabWidget) { + count += tabWidget->count(); + } + } + } + return count; } QWidget* QtDynamicGridLayout::widget(int index) const { - QWidget* widgetAtIndex = NULL; - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - if (tabWidget) { - if (index < tabWidget->count()) { - widgetAtIndex = tabWidget->widget(index); - return widgetAtIndex; - } - else { - index -= tabWidget->count(); - } - } - } - } - return widgetAtIndex; + QWidget* widgetAtIndex = nullptr; + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem ? layoutItem->widget() : nullptr); + if (tabWidget) { + if (index < tabWidget->count()) { + widgetAtIndex = tabWidget->widget(index); + return widgetAtIndex; + } + else { + index -= tabWidget->count(); + } + } + } + } + return widgetAtIndex; } int QtDynamicGridLayout::indexOf(const QWidget* widget) const { - int index = 0; - if (widget) { - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - if (tabWidget) { - for (int n = 0; n < tabWidget->count(); n++) { - QWidget* nthWidget = tabWidget->widget(n); - if (nthWidget == widget) { - return index; - } - index++; - } - } - } - } - } - return -1; + int index = 0; + if (widget) { + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + if (tabWidget) { + for (int n = 0; n < tabWidget->count(); n++) { + QWidget* nthWidget = tabWidget->widget(n); + if (nthWidget == widget) { + return index; + } + index++; + } + } + } + } + } + return -1; } void QtDynamicGridLayout::handleApplicationFocusChanged(QWidget*, QWidget* newFocus) { - if (movingTab_) { - return; - } - - if (newFocus) { - if (isAncestorOf(newFocus)) { - QtTabbable *newTab = dynamic_cast<QtTabbable*>(newFocus->parentWidget()); - if (newTab) { - onCurrentIndexChanged(currentIndex()); - } - } - } + if (movingTab_ || resizing_) { + return; + } + + if (newFocus) { + if (isAncestorOf(newFocus)) { + QtTabbable *newTab = dynamic_cast<QtTabbable*>(newFocus->parentWidget()); + if (newTab) { + onCurrentIndexChanged(currentIndex()); + } + } + } } int QtDynamicGridLayout::currentIndex() const { - return indexOf(currentWidget()); + return indexOf(currentWidget()); } void QtDynamicGridLayout::setCurrentIndex(int index) { - int tabIndex = -1; - QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); - if (tabIndex >= 0) { - tabWidget->setCurrentIndex(tabIndex); - if (!tabWidget->hasFocus()) { - tabWidget->widget(tabIndex)->setFocus(Qt::TabFocusReason); - } - } else { - assert(false); - } + int tabIndex = -1; + QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); + if (tabIndex >= 0) { + tabWidget->setCurrentIndex(tabIndex); + if (!tabWidget->hasFocus()) { + tabWidget->widget(tabIndex)->setFocus(Qt::TabFocusReason); + } + } else { + assert(false); + } } void QtDynamicGridLayout::removeTab(int index) { - int tabIndex = -1; - QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); - if (tabWidget) { - tabWidget->removeTab(tabIndex); - } + int tabIndex = -1; + QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); + if (tabWidget) { + tabWidget->removeTab(tabIndex); + } } /** @@ -158,348 +159,375 @@ void QtDynamicGridLayout::removeTab(int index) { * being out of sync in an inconsistent state. */ bool QtDynamicGridLayout::eventFilter(QObject* object, QEvent* event) { - QtTabbable* tab = qobject_cast<QtTabbable*>(object); - if (!tab) { - return false; - } - if (tab && (tab != movingTab_)) { - if (event->type() == QEvent::Show) { - return true; - } - } - return false; + QtTabbable* tab = qobject_cast<QtTabbable*>(object); + if (!tab) { + return false; + } + if (tab && (tab != movingTab_)) { + if (event->type() == QEvent::Show) { + return true; + } + } + return false; } QWidget* QtDynamicGridLayout::currentWidget() const { - QWidget* current = NULL; - current = focusWidget(); - while (current && !dynamic_cast<QtTabbable*>(current)) { - if (current->parentWidget()) { - current = current->parentWidget(); - } else { - current = NULL; - break; - } - } - if (!current) { - current = widget(0); - } - return current; + QWidget* current = nullptr; + current = focusWidget(); + while (current && !dynamic_cast<QtTabbable*>(current)) { + if (current->parentWidget()) { + current = current->parentWidget(); + } else { + current = nullptr; + break; + } + } + if (!current) { + current = widget(0); + } + return current; } void QtDynamicGridLayout::setCurrentWidget(QWidget* widget) { - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - if (tabWidget) { - for (int n = 0; n < tabWidget->count(); n++) { - if (tabWidget->widget(n) == widget) { - tabWidget->setCurrentWidget(widget); - } - } - } - } - } + if (widget) { + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + if (tabWidget) { + for (int n = 0; n < tabWidget->count(); n++) { + if (tabWidget->widget(n) == widget) { + tabWidget->setCurrentWidget(widget); + } + } + } + } + } + } } QtTabWidget* QtDynamicGridLayout::indexToTabWidget(int index, int& tabIndex) { - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - if (tabWidget) { - if (index < tabWidget->count()) { - tabIndex = index; - return tabWidget; - } - else { - index -= tabWidget->count(); - if (index < 0) { - qWarning() << "Called QtDynamicGridLayout::setCurrentIndex with index out of bounds: index = " << index; - tabIndex = -1; - return NULL; - } - } - } - } - } - tabIndex = -1; - return NULL; + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + if (tabWidget) { + if (index < tabWidget->count()) { + tabIndex = index; + return tabWidget; + } + else { + index -= tabWidget->count(); + if (index < 0) { + qWarning() << "Called QtDynamicGridLayout::setCurrentIndex with index out of bounds: index = " << index; + tabIndex = -1; + return nullptr; + } + } + } + } + } + tabIndex = -1; + return nullptr; } bool QtDynamicGridLayout::isDNDEnabled() const { - return dndEnabled_; + return dndEnabled_; } QHash<QString, QPoint> QtDynamicGridLayout::getTabPositions() const { - return tabPositions_; + return tabPositions_; } void QtDynamicGridLayout::setTabPositions(const QHash<QString, QPoint> positions) { - tabPositions_ = positions; + tabPositions_ = positions; } QSize QtDynamicGridLayout::getDimension() const { - return QSize(gridLayout_->columnCount(), gridLayout_->rowCount()); + return QSize(gridLayout_->columnCount(), gridLayout_->rowCount()); } void QtDynamicGridLayout::setDimensions(const QSize& dim) { - assert(dim.width() > 0 && dim.height() > 0); - setUpdatesEnabled(false); - - QGridLayout* oldLayout = dynamic_cast<QGridLayout*>(layout()); - QGridLayout* newLayout = new QGridLayout; - newLayout->setSpacing(4); - newLayout->setContentsMargins(0,0,0,0); - - int oldWidth = oldLayout->columnCount(); - int oldHeight = oldLayout->rowCount(); - int maxCol = qMax(oldWidth, dim.width()); - int minCol = qMin(oldWidth, dim.width()); - int maxRow = qMax(oldHeight, dim.height()); - int minRow = qMin(oldHeight, dim.height()); - - for (int row = 0; row < maxRow; row++) { - for (int col = 0; col < maxCol; col++) { - QLayoutItem* oldItem = oldLayout->itemAtPosition(row, col); - QLayoutItem* newItem = newLayout->itemAtPosition(row, col); - bool removeRow = !(row < dim.height()); - bool removeCol = !(col < dim.width()); - - if (removeCol || removeRow) { - if (oldItem) { - int squeezeRow = removeRow ? (minRow - 1) : row; - int squeezeCol = removeCol ? (minCol - 1) : col; - newItem = newLayout->itemAtPosition(squeezeRow, squeezeCol); - if (!newItem) { - newLayout->addWidget(createDNDTabWidget(this), squeezeRow, squeezeCol); - newItem = newLayout->itemAtPosition(squeezeRow, squeezeCol); - } - QtTabWidget* oldTabWidget = dynamic_cast<QtTabWidget*>(oldItem->widget()); - QtTabWidget* newTabWidget = dynamic_cast<QtTabWidget*>(newItem->widget()); - assert(oldTabWidget && newTabWidget); - - oldTabWidget->hide(); - while(oldTabWidget->count()) { - QIcon icon = oldTabWidget->tabIcon(0); - QString text = oldTabWidget->tabText(0); - newTabWidget->addTab(oldTabWidget->widget(0), icon, text); - } - delete oldTabWidget; - } - } else { - if (oldItem) { - newLayout->addWidget(oldItem->widget(), row, col); - newItem = newLayout->itemAtPosition(row, col); - } else { - newLayout->addWidget(createDNDTabWidget(this), row, col); - } - } - } - } - - for (int col = 0; col < dim.width(); col++) { - newLayout->setColumnStretch(col, 1); - } - for (int row = 0; row < dim.height(); row++) { - newLayout->setRowStretch(row, 1); - } - - setUpdatesEnabled(true); - delete layout(); - setLayout(newLayout); - gridLayout_ = newLayout; + resizing_ = true; + assert(dim.width() > 0 && dim.height() > 0); + setUpdatesEnabled(false); + + QWidget* restoredWidget = currentWidget(); + + QGridLayout* oldLayout = dynamic_cast<QGridLayout*>(layout()); + QGridLayout* newLayout = new QGridLayout(this); + newLayout->setSpacing(4); + newLayout->setContentsMargins(0,0,0,0); + + int oldWidth = oldLayout->columnCount(); + int oldHeight = oldLayout->rowCount(); + int maxCol = qMax(oldWidth, dim.width()); + int minCol = qMin(oldWidth, dim.width()); + int maxRow = qMax(oldHeight, dim.height()); + int minRow = qMin(oldHeight, dim.height()); + + for (int row = 0; row < maxRow; row++) { + for (int col = 0; col < maxCol; col++) { + QLayoutItem* oldItem = oldLayout->itemAtPosition(row, col); + QLayoutItem* newItem = newLayout->itemAtPosition(row, col); + bool removeRow = !(row < dim.height()); + bool removeCol = !(col < dim.width()); + + if (removeCol || removeRow) { + if (oldItem) { + int squeezeRow = removeRow ? (minRow - 1) : row; + int squeezeCol = removeCol ? (minCol - 1) : col; + newItem = newLayout->itemAtPosition(squeezeRow, squeezeCol); + if (!newItem) { + newLayout->addWidget(createDNDTabWidget(this), squeezeRow, squeezeCol); + newItem = newLayout->itemAtPosition(squeezeRow, squeezeCol); + } + QtTabWidget* oldTabWidget = dynamic_cast<QtTabWidget*>(oldItem->widget()); + QtTabWidget* newTabWidget = dynamic_cast<QtTabWidget*>(newItem->widget()); + assert(oldTabWidget && newTabWidget); + + oldTabWidget->hide(); + while(oldTabWidget->count()) { + QIcon icon = oldTabWidget->tabIcon(0); + QString text = oldTabWidget->tabText(0); + newTabWidget->addTab(oldTabWidget->widget(0), icon, text); + } + delete oldTabWidget; + } + } else { + if (oldItem) { + newLayout->addWidget(oldItem->widget(), row, col); + newItem = newLayout->itemAtPosition(row, col); + } else { + newLayout->addWidget(createDNDTabWidget(this), row, col); + } + } + } + } + + for (int col = 0; col < dim.width(); col++) { + newLayout->setColumnStretch(col, 1); + } + for (int row = 0; row < dim.height(); row++) { + newLayout->setRowStretch(row, 1); + } + + setUpdatesEnabled(true); + delete layout(); + setLayout(newLayout); + gridLayout_ = newLayout; + + resizing_ = false; + setCurrentWidget(restoredWidget); + + updateEmphasiseFocusOnTabs(); +} + +void QtDynamicGridLayout::updateEmphasiseFocusOnTabs() { + const auto currentDimensions = getDimension(); + + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + assert(tabWidget); + for (int index = 0; index < tabWidget->count(); index++) { + QtTabbable* tab = dynamic_cast<QtTabbable*>(tabWidget->widget(index)); + assert(tab); + tab->setEmphasiseFocus(currentDimensions.height() > 1 || currentDimensions.width() > 1); + } + } + } } void QtDynamicGridLayout::moveCurrentTabRight() { - int index = currentIndex(); - if (index >= 0) { - int tabIndex = -1; - QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); - assert(tabWidget); - int newTabIndex = (tabIndex + 1) % tabWidget->count(); - moveTab(tabWidget, tabIndex, newTabIndex); - } + int index = currentIndex(); + if (index >= 0) { + int tabIndex = -1; + QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); + assert(tabWidget); + int newTabIndex = (tabIndex + 1) % tabWidget->count(); + moveTab(tabWidget, tabIndex, newTabIndex); + } } void QtDynamicGridLayout::moveCurrentTabLeft() { - int index = currentIndex(); - if (index >= 0) { - int tabIndex = -1; - QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); - assert(tabWidget); - int newTabIndex = (tabWidget->count() + tabIndex - 1) % tabWidget->count(); - moveTab(tabWidget, tabIndex, newTabIndex); - } + int index = currentIndex(); + if (index >= 0) { + int tabIndex = -1; + QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); + assert(tabWidget); + int newTabIndex = (tabWidget->count() + tabIndex - 1) % tabWidget->count(); + moveTab(tabWidget, tabIndex, newTabIndex); + } } void QtDynamicGridLayout::moveCurrentTabToNextGroup() { - int index = currentIndex(); - if (index >= 0) { - int tabIndex = -1; - QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); - - int row = -1; - int col = -1; - int tmp; - gridLayout_->getItemPosition(gridLayout_->indexOf(tabWidget), &row, &col, &tmp, &tmp); - - // calculate next cell - col++; - if (!(col < gridLayout_->columnCount())) { - col = 0; - row++; - if (!(row < gridLayout_->rowCount())) { - row = 0; - } - } - - QtTabWidget* targetTabWidget = dynamic_cast<QtTabWidget*>(gridLayout_->itemAtPosition(row, col)->widget()); - assert(tabWidget); - assert(targetTabWidget); - - // fetch tab information - QWidget* tab = tabWidget->widget(tabIndex); - QString tabText = tabWidget->tabText(tabIndex); - - // move tab - tab->blockSignals(true); - targetTabWidget->addTab(tab, tabText); - tab->blockSignals(false); - tab->setFocus(Qt::TabFocusReason); - - updateTabPositions(); - } + int index = currentIndex(); + if (index >= 0) { + int tabIndex = -1; + QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); + + int row = -1; + int col = -1; + int tmp; + gridLayout_->getItemPosition(gridLayout_->indexOf(tabWidget), &row, &col, &tmp, &tmp); + + // calculate next cell + col++; + if (!(col < gridLayout_->columnCount())) { + col = 0; + row++; + if (!(row < gridLayout_->rowCount())) { + row = 0; + } + } + + QtTabWidget* targetTabWidget = dynamic_cast<QtTabWidget*>(gridLayout_->itemAtPosition(row, col)->widget()); + assert(tabWidget); + assert(targetTabWidget); + + // fetch tab information + QWidget* tab = tabWidget->widget(tabIndex); + QString tabText = tabWidget->tabText(tabIndex); + + // move tab + tab->blockSignals(true); + targetTabWidget->addTab(tab, tabText); + tab->blockSignals(false); + tab->setFocus(Qt::TabFocusReason); + + updateTabPositions(); + } } void QtDynamicGridLayout::moveCurrentTabToPreviousGroup() { - int index = currentIndex(); - if (index >= 0) { - int tabIndex = -1; - QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); - - int row = -1; - int col = -1; - int tmp; - gridLayout_->getItemPosition(gridLayout_->indexOf(tabWidget), &row, &col, &tmp, &tmp); - - // calculate next cell - col--; - if (col < 0) { - col = gridLayout_->columnCount() - 1; - row--; - if (row < 0) { - row = gridLayout_->rowCount() - 1; - } - } - - QtTabWidget* targetTabWidget = dynamic_cast<QtTabWidget*>(gridLayout_->itemAtPosition(row, col)->widget()); - assert(tabWidget); - assert(targetTabWidget); - - // fetch tab information - QWidget* tab = tabWidget->widget(tabIndex); - QString tabText = tabWidget->tabText(tabIndex); - - // move tab - tab->blockSignals(true); - targetTabWidget->addTab(tab, tabText); - tab->blockSignals(false); - tab->setFocus(Qt::TabFocusReason); - - updateTabPositions(); - } + int index = currentIndex(); + if (index >= 0) { + int tabIndex = -1; + QtTabWidget* tabWidget = indexToTabWidget(index, tabIndex); + + int row = -1; + int col = -1; + int tmp; + gridLayout_->getItemPosition(gridLayout_->indexOf(tabWidget), &row, &col, &tmp, &tmp); + + // calculate next cell + col--; + if (col < 0) { + col = gridLayout_->columnCount() - 1; + row--; + if (row < 0) { + row = gridLayout_->rowCount() - 1; + } + } + + QtTabWidget* targetTabWidget = dynamic_cast<QtTabWidget*>(gridLayout_->itemAtPosition(row, col)->widget()); + assert(tabWidget); + assert(targetTabWidget); + + // fetch tab information + QWidget* tab = tabWidget->widget(tabIndex); + QString tabText = tabWidget->tabText(tabIndex); + + // move tab + tab->blockSignals(true); + targetTabWidget->addTab(tab, tabText); + tab->blockSignals(false); + tab->setFocus(Qt::TabFocusReason); + + updateTabPositions(); + } } void QtDynamicGridLayout::handleTabCloseRequested(int index) { - updateTabPositions(); - QtTabWidget* tabWidgetSender = dynamic_cast<QtTabWidget*>(sender()); - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - if (tabWidget == tabWidgetSender) { - tabCloseRequested(index); - } - else { - index += tabWidget->count(); - } - } - } + updateTabPositions(); + QtTabWidget* tabWidgetSender = dynamic_cast<QtTabWidget*>(sender()); + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + if (tabWidget == tabWidgetSender) { + tabCloseRequested(index); + } + else { + index += tabWidget->count(); + } + } + } } void QtDynamicGridLayout::handleTabCurrentChanged(int index) { - if (movingTab_) { - return; - } - - if (index >= 0) { - QTabWidget* sendingTabWidget = dynamic_cast<QTabWidget*>(sender()); - assert(sendingTabWidget); - sendingTabWidget->widget(index)->setFocus(); - } + if (movingTab_) { + return; + } + + if (index >= 0) { + QTabWidget* sendingTabWidget = dynamic_cast<QTabWidget*>(sender()); + assert(sendingTabWidget); + sendingTabWidget->widget(index)->setFocus(); + } } void QtDynamicGridLayout::updateTabPositions() { - for (int y = 0; y < gridLayout_->rowCount(); y++) { - for (int x = 0; x < gridLayout_->columnCount(); x++) { - QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); - QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); - assert(tabWidget); - for (int index = 0; index < tabWidget->count(); index++) { - QtTabbable* tab = dynamic_cast<QtTabbable*>(tabWidget->widget(index)); - assert(tab); - tabPositions_.insert(P2QSTRING(tab->getID()), QPoint(x, y)); - } - } - } + for (int y = 0; y < gridLayout_->rowCount(); y++) { + for (int x = 0; x < gridLayout_->columnCount(); x++) { + QLayoutItem* layoutItem = gridLayout_->itemAtPosition(y, x); + QtTabWidget* tabWidget = dynamic_cast<QtTabWidget*>(layoutItem->widget()); + assert(tabWidget); + for (int index = 0; index < tabWidget->count(); index++) { + QtTabbable* tab = dynamic_cast<QtTabbable*>(tabWidget->widget(index)); + assert(tab); + tabPositions_.insert(P2QSTRING(tab->getID()), QPoint(x, y)); + } + } + } } void QtDynamicGridLayout::moveTab(QtTabWidget* tabWidget, int oldIndex, int newIndex) { #if QT_VERSION >= 0x040500 - SWIFT_LOG_ASSERT(movingTab_ == NULL, error) << std::endl; - movingTab_ = qobject_cast<QtTabbable*>(tabWidget->widget(oldIndex)); - SWIFT_LOG_ASSERT(movingTab_ != NULL, error) << std::endl; - - if (movingTab_) { - // Install event filter that filters out events issued during the internal movement of the - // tab but not targeted at the moving tab. - qApp->installEventFilter(this); - - tabWidget->tabBar()->moveTab(oldIndex, newIndex); - - qApp->removeEventFilter(this); - SWIFT_LOG_ASSERT(movingTab_ == tabWidget->widget(newIndex), error) << std::endl; - } - movingTab_ = NULL; - tabWidget->widget(newIndex)->setFocus(); + SWIFT_LOG_ASSERT(movingTab_ == nullptr, error) << std::endl; + movingTab_ = qobject_cast<QtTabbable*>(tabWidget->widget(oldIndex)); + SWIFT_LOG_ASSERT(movingTab_ != nullptr, error) << std::endl; + + if (movingTab_) { + // Install event filter that filters out events issued during the internal movement of the + // tab but not targeted at the moving tab. + qApp->installEventFilter(this); + + tabWidget->tabBar()->moveTab(oldIndex, newIndex); + + qApp->removeEventFilter(this); + SWIFT_LOG_ASSERT(movingTab_ == tabWidget->widget(newIndex), error) << std::endl; + } + movingTab_ = nullptr; + tabWidget->widget(newIndex)->setFocus(); #else #warning Qt 4.5 or later is needed. Trying anyway, some things will be disabled. #endif } QtTabWidget* QtDynamicGridLayout::createDNDTabWidget(QWidget* parent) { - QtTabWidget* tab = new QtTabWidget(parent); - if (dndEnabled_) { - QtDNDTabBar* tabBar = new QtDNDTabBar(tab); - connect(tabBar, SIGNAL(onDropSucceeded()), this, SLOT(updateTabPositions())); - tab->setTabBar(tabBar); - } - tab->setUsesScrollButtons(true); - tab->setElideMode(Qt::ElideRight); + QtTabWidget* tab = new QtTabWidget(parent); + if (dndEnabled_) { + QtDNDTabBar* tabBar = new QtDNDTabBar(tab); + connect(tabBar, SIGNAL(onDropSucceeded()), this, SLOT(updateTabPositions())); + tab->setTabBar(tabBar); + } + tab->setUsesScrollButtons(true); + tab->setElideMode(Qt::ElideRight); #if QT_VERSION >= 0x040500 - /*For Macs, change the tab rendering.*/ - tab->setDocumentMode(true); - /*Closable tabs are only in Qt4.5 and later*/ - tab->setTabsClosable(true); - tab->setMovable(true); - connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabCloseRequested(int))); - connect(tab, SIGNAL(currentChanged(int)), this, SLOT(handleTabCurrentChanged(int))); + /*For Macs, change the tab rendering.*/ + tab->setDocumentMode(true); + /*Closable tabs are only in Qt4.5 and later*/ + tab->setTabsClosable(true); + tab->setMovable(true); + connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabCloseRequested(int))); + connect(tab, SIGNAL(currentChanged(int)), this, SLOT(handleTabCurrentChanged(int))); #else #warning Qt 4.5 or later is needed. Trying anyway, some things will be disabled. #endif - return tab; + return tab; } } diff --git a/Swift/QtUI/Trellis/QtDynamicGridLayout.h b/Swift/QtUI/Trellis/QtDynamicGridLayout.h index ed8a9fc..682ae41 100644 --- a/Swift/QtUI/Trellis/QtDynamicGridLayout.h +++ b/Swift/QtUI/Trellis/QtDynamicGridLayout.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -14,67 +14,69 @@ #include <QWidget> namespace Swift { - class QtTabbable; - class QtTabWidget; + class QtTabbable; + class QtTabWidget; - class QtDynamicGridLayout : public QWidget { - Q_OBJECT - public: - explicit QtDynamicGridLayout(QWidget* parent = 0, bool enableDND = false); - virtual ~QtDynamicGridLayout(); + class QtDynamicGridLayout : public QWidget { + Q_OBJECT + public: + explicit QtDynamicGridLayout(QWidget* parent = nullptr, bool enableDND = false); + virtual ~QtDynamicGridLayout(); - QSize getDimension() const; + QSize getDimension() const; - // emulate QtTabWidget API - int addTab(QtTabbable* tab, const QString& title); - void removeTab(int index); - int count() const; + // emulate QtTabWidget API + int addTab(QtTabbable* tab, const QString& title); + void removeTab(int index); + int count() const; - QWidget* widget(int index) const; - QWidget* currentWidget() const; - void setCurrentWidget(QWidget* widget); + QWidget* widget(int index) const; + QWidget* currentWidget() const; + void setCurrentWidget(QWidget* widget); - QtTabWidget* indexToTabWidget(int index, int& tabIndex); + QtTabWidget* indexToTabWidget(int index, int& tabIndex); - int indexOf(const QWidget* widget) const; - int currentIndex() const; - void setCurrentIndex(int index); + int indexOf(const QWidget* widget) const; + int currentIndex() const; + void setCurrentIndex(int index); - bool isDNDEnabled() const; + bool isDNDEnabled() const; - QHash<QString, QPoint> getTabPositions() const; - void setTabPositions(const QHash<QString, QPoint> positions); + QHash<QString, QPoint> getTabPositions() const; + void setTabPositions(const QHash<QString, QPoint> positions); - bool eventFilter(QObject* object, QEvent* event); + bool eventFilter(QObject* object, QEvent* event); - signals: - void tabCloseRequested(int index); - void onCurrentIndexChanged(int newIndex); + signals: + void tabCloseRequested(int index); + void onCurrentIndexChanged(int newIndex); - public slots: - void setDimensions(const QSize& dim); + public slots: + void setDimensions(const QSize& dim); - // Tab Management - void moveCurrentTabRight(); - void moveCurrentTabLeft(); - void moveCurrentTabToNextGroup(); - void moveCurrentTabToPreviousGroup(); + // Tab Management + void moveCurrentTabRight(); + void moveCurrentTabLeft(); + void moveCurrentTabToNextGroup(); + void moveCurrentTabToPreviousGroup(); - void updateTabPositions(); + void updateTabPositions(); - private slots: - void handleTabCloseRequested(int index); - void handleTabCurrentChanged(int index); - void handleApplicationFocusChanged(QWidget* oldFocus, QWidget* newFocus); + private slots: + void handleTabCloseRequested(int index); + void handleTabCurrentChanged(int index); + void handleApplicationFocusChanged(QWidget* oldFocus, QWidget* newFocus); - private: - void moveTab(QtTabWidget* tabWidget, int oldIndex, int newIndex); - QtTabWidget* createDNDTabWidget(QWidget* parent); + private: + void moveTab(QtTabWidget* tabWidget, int oldIndex, int newIndex); + QtTabWidget* createDNDTabWidget(QWidget* parent); + void updateEmphasiseFocusOnTabs(); - private: - QGridLayout *gridLayout_; - bool dndEnabled_; - QHash<QString, QPoint> tabPositions_; - QtTabbable* movingTab_; - }; + private: + QGridLayout *gridLayout_; + bool dndEnabled_; + QHash<QString, QPoint> tabPositions_; + QtTabbable* movingTab_; + bool resizing_ = false; + }; } diff --git a/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp b/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp index a3a1bf8..f03d0ec 100644 --- a/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp +++ b/Swift/QtUI/Trellis/QtGridSelectionDialog.cpp @@ -1,157 +1,181 @@ /* - * Copyright (c) 2014-2015 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swift/QtUI/Trellis/QtGridSelectionDialog.h> +#include <QApplication> +#include <QCursor> #include <QPaintEvent> #include <QPainter> #include <QStyle> -#include <QStyleOptionFrame> -#include <QStyleOptionMenuItem> -#include <QStyleOptionSizeGrip> +#include <QStyleOption> namespace Swift { -QtGridSelectionDialog::QtGridSelectionDialog(QWidget* parent) : QWidget(parent) { - frameSize = QSize(23,23) * 2; - maxGridSize = QSize(7,7); - minGridSize = QSize(1,1); - currentGridSize = QSize(1,1); - padding = 4; - setWindowFlags(Qt::FramelessWindowHint); - setCursor(Qt::SizeAllCursor); - horizontalMargin = style()->pixelMetric(QStyle::PM_MenuVMargin) * 2; - verticalMargin = style()->pixelMetric(QStyle::PM_MenuVMargin) * 2; +QtGridSelectionDialog::QtGridSelectionDialog(QWidget* parent) : QWidget(parent), descriptionText(tr("Select the number of rows and columns for your layout. You can change the size by moving the mouse or cursor keys.")) { + frameSize = QSize(28,28) * 2; + maxGridSize = QSize(7,7); + minGridSize = QSize(1,1); + currentGridSize = QSize(1,1); + padding = 4; + setWindowFlags(Qt::FramelessWindowHint); + setCursor(Qt::SizeAllCursor); + horizontalMargin = style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + verticalMargin = style()->pixelMetric(QStyle::PM_LayoutBottomMargin); } QSize QtGridSelectionDialog::sizeHint() const { - // PM_MenuVMargin | frameSize | ( padding | frameSize ) * | PM_MenuVMargin - int width = horizontalMargin + frameSize.width() + (padding + frameSize.width()) * (currentGridSize.width() - 1) + horizontalMargin; - int height = verticalMargin + frameSize.height() + (padding + frameSize.height()) * (currentGridSize.height() - 1) + verticalMargin; - return QSize(width, height); + // PM_MenuVMargin | frameSize | ( padding | frameSize ) * | PM_MenuVMargin + int width = horizontalMargin + frameSize.width() + (padding + frameSize.width()) * (currentGridSize.width() - 1) + horizontalMargin; + int height = verticalMargin + frameSize.height() + (padding + frameSize.height()) * (currentGridSize.height() - 1) + verticalMargin; + + // Add space for descriptive centered text below. + auto fontMetrics = QFontMetrics(QApplication::font()); + auto descriptionBB = fontMetrics.boundingRect(QRect(0,0,width - 2*horizontalMargin,1000), Qt::TextWordWrap, descriptionText, 0, 0); + + height += descriptionBB.height() + descriptionBB.y(); + + return QSize(width, height); } void QtGridSelectionDialog::setCurrentGridSize(const QSize& size) { - currentGridSize = size; - emit currentGridSizeChanged(size); + currentGridSize = size; + emit currentGridSizeChanged(size); } QSize QtGridSelectionDialog::getCurrentGridSize() const { - return currentGridSize; + return currentGridSize; } void QtGridSelectionDialog::setMinGridSize(const QSize& size) { - minGridSize = size; - emit minGridSizeChanged(size); + minGridSize = size; + emit minGridSizeChanged(size); } QSize QtGridSelectionDialog::getMinGridSize() const { - return minGridSize; + return minGridSize; } void QtGridSelectionDialog::setMaxGridSize(const QSize& size) { - maxGridSize = size; - emit maxGridSizeChanged(size); + maxGridSize = size; + emit maxGridSizeChanged(size); } QSize QtGridSelectionDialog::getMaxGridSize() const { - return maxGridSize; + return maxGridSize; } void QtGridSelectionDialog::keyReleaseEvent(QKeyEvent* event) { - if (event) { - QSize newGridSize = currentGridSize; - if (event->key() == Qt::Key_Up) { - newGridSize += QSize(0, -1); - } - else if (event->key() == Qt::Key_Down) { - newGridSize += QSize(0, 1); - } - else if (event->key() == Qt::Key_Left) { - newGridSize += QSize(-1, 0); - } - else if (event->key() == Qt::Key_Right) { - newGridSize += QSize(1, 0); - } - else if (event->key() == Qt::Key_Return) { - hide(); - setCurrentGridSize(currentGridSize); - } - if (minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize) != currentGridSize) { - currentGridSize = minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize); - resize(sizeHint()); - } - } + if (event) { + QSize newGridSize = currentGridSize; + if (event->key() == Qt::Key_Up) { + newGridSize += QSize(0, -1); + } + else if (event->key() == Qt::Key_Down) { + newGridSize += QSize(0, 1); + } + else if (event->key() == Qt::Key_Left) { + newGridSize += QSize(-1, 0); + } + else if (event->key() == Qt::Key_Right) { + newGridSize += QSize(1, 0); + } + else if (event->key() == Qt::Key_Return) { + hide(); + setCurrentGridSize(currentGridSize); + } + if (minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize) != currentGridSize) { + currentGridSize = minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize); + + QSize newSizeHint = sizeHint(); + resize(newSizeHint); + QCursor::setPos(mapToGlobal(QPoint(newSizeHint.width(), newSizeHint.height()) - QPoint(frameSize.width() / 2, frameSize.height() / 2))); + } + } } void QtGridSelectionDialog::mousePressEvent(QMouseEvent*) { - hide(); - setCurrentGridSize(currentGridSize); + hide(); + setCurrentGridSize(currentGridSize); } void QtGridSelectionDialog::paintEvent(QPaintEvent*) { - QPainter painter(this); - QStyleOptionMenuItem option; - option.state = QStyle::State_Enabled | QStyle::State_Selected; - option.menuRect = QRect(QPoint(0,0), frameSize); - for (int x = 0; x < currentGridSize.width(); x++) { - for (int y = 0; y < currentGridSize.height(); y++) { - int xPos = horizontalMargin + (x * (frameSize.width() + padding)); - int yPos = verticalMargin + (y * (frameSize.height() + padding)); - option.menuRect.moveTo(QPoint(xPos, yPos)); - option.rect = option.menuRect; - style()->drawControl(QStyle::CE_MenuItem, &option, &painter, 0); - } - } - - QStyleOptionSizeGrip sizeGripOption; - sizeGripOption.init(this); - sizeGripOption.corner = Qt::BottomRightCorner; - style()->drawControl(QStyle::CE_SizeGrip, &sizeGripOption, &painter, this); + QPainter painter(this); + // draw grid + QRect gridCell = QRect(QPoint(0,0), frameSize); + painter.setBrush(palette().highlight()); + painter.setPen(Qt::NoPen); + for (int x = 0; x < currentGridSize.width(); x++) { + for (int y = 0; y < currentGridSize.height(); y++) { + int xPos = horizontalMargin + (x * (frameSize.width() + padding)); + int yPos = verticalMargin + (y * (frameSize.height() + padding)); + gridCell.moveTo(QPoint(xPos, yPos)); + painter.drawRect(gridCell); + } + } + + // draw description text + auto fontMetrics = QFontMetrics(QApplication::font()); + auto descriptionBB = fontMetrics.boundingRect(QRect(0,0, width() - 2 * horizontalMargin,0), Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, descriptionText, 0, 0); + + QStyleOption opt; + opt.initFrom(this); + int textY = verticalMargin + (currentGridSize.height() * (frameSize.height() + padding)); + int textX = (size().width() - descriptionBB.width()) / 2; + style()->drawItemText(&painter, QRect(textX, textY, descriptionBB.width(), descriptionBB.height()), Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, opt.palette, true, descriptionText, foregroundRole()); } void QtGridSelectionDialog::showEvent(QShowEvent*) { - int xPos = horizontalMargin + frameSize.width() + (padding + frameSize.width()) * (currentGridSize.width() - 1) - frameSize.width()/2; - int yPos = verticalMargin + frameSize.height() + (padding + frameSize.height()) * (currentGridSize.height() - 1) - frameSize.height()/2; - QCursor::setPos(mapToGlobal(QPoint(xPos, yPos))); - setMouseTracking(true); + int xPos = horizontalMargin + frameSize.width() + (padding + frameSize.width()) * (currentGridSize.width() - 1) - frameSize.width()/2; + int yPos = verticalMargin + frameSize.height() + (padding + frameSize.height()) * (currentGridSize.height() - 1) - frameSize.height()/2; + QCursor::setPos(mapToGlobal(QPoint(xPos, yPos))); + setMouseTracking(true); } void QtGridSelectionDialog::hideEvent(QHideEvent*) { - setMouseTracking(false); + setMouseTracking(false); } void QtGridSelectionDialog::mouseMoveEvent(QMouseEvent*) { - QPoint diff = (frameGeometry().bottomRight() - QCursor::pos()); - QSize newDimensions = currentGridSize; - if (diff.x() > frameSize.width() * 1.5) { - newDimensions -= QSize(diff.x() / (frameSize.width() * 1.5), 0); - } - if (diff.y() > frameSize.height() * 1.5) { - newDimensions -= QSize(0, diff.y() / (frameSize.height() * 1.5)); - } - if (minGridSize.expandedTo(newDimensions).boundedTo(maxGridSize) != currentGridSize) { - currentGridSize = minGridSize.expandedTo(newDimensions).boundedTo(maxGridSize); - resize(sizeHint()); - } + QPoint diff = (frameGeometry().bottomRight() - QCursor::pos()); + QSize newDimensions = currentGridSize; + if (diff.x() > frameSize.width() * 1.5) { + newDimensions -= QSize(diff.x() / (frameSize.width() * 1.5), 0); + } + if (diff.y() > frameSize.height() * 1.5) { + newDimensions -= QSize(0, diff.y() / (frameSize.height() * 1.5)); + } + if (minGridSize.expandedTo(newDimensions).boundedTo(maxGridSize) != currentGridSize) { + currentGridSize = minGridSize.expandedTo(newDimensions).boundedTo(maxGridSize); + resize(sizeHint()); + } } void QtGridSelectionDialog::leaveEvent(QEvent *) { - QPoint diff = (frameGeometry().bottomRight() - QCursor::pos()); - QSize newGridSize = currentGridSize; - if (diff.x() < 0) { - newGridSize += QSize(1,0); - } - if (diff.y() < 0) { - newGridSize += QSize(0,1); - } - if (minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize) != currentGridSize) { - currentGridSize = minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize); - resize(sizeHint()); - } + QPoint diff = (frameGeometry().bottomRight() - QCursor::pos()); + QSize newGridSize = currentGridSize; + if (diff.x() < 0) { + newGridSize += QSize(1,0); + } + if (diff.y() < 0) { + newGridSize += QSize(0,1); + } + if (minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize) != currentGridSize) { + currentGridSize = minGridSize.expandedTo(newGridSize).boundedTo(maxGridSize); + resize(sizeHint()); + } +} + +bool QtGridSelectionDialog::event(QEvent* event) { + // Hide the window when it becomes a non-top-level window. + if (event->type() == QEvent::WindowDeactivate) { + hide(); + return true; + } + return QWidget::event(event); } } diff --git a/Swift/QtUI/Trellis/QtGridSelectionDialog.h b/Swift/QtUI/Trellis/QtGridSelectionDialog.h index abcc8b1..557963d 100644 --- a/Swift/QtUI/Trellis/QtGridSelectionDialog.h +++ b/Swift/QtUI/Trellis/QtGridSelectionDialog.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Isode Limited. + * Copyright (c) 2014-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -11,47 +11,50 @@ namespace Swift { - class QtGridSelectionDialog : public QWidget { - Q_OBJECT - - Q_PROPERTY(QSize currentGridSize READ getCurrentGridSize WRITE setCurrentGridSize NOTIFY currentGridSizeChanged) - Q_PROPERTY(QSize minGridSize READ getMinGridSize WRITE setMinGridSize NOTIFY minGridSizeChanged) - Q_PROPERTY(QSize maxGridSize READ getMaxGridSize WRITE setMaxGridSize NOTIFY maxGridSizeChanged) - public: - explicit QtGridSelectionDialog(QWidget* parent = 0); - - virtual QSize sizeHint() const; - - void setCurrentGridSize(const QSize& size); - QSize getCurrentGridSize() const; - void setMinGridSize(const QSize& size); - QSize getMinGridSize() const; - void setMaxGridSize(const QSize& size); - QSize getMaxGridSize() const; - - signals: - void currentGridSizeChanged(QSize); - void minGridSizeChanged(QSize); - void maxGridSizeChanged(QSize); - - protected: - void keyReleaseEvent(QKeyEvent* event); - void mousePressEvent(QMouseEvent* event); - void mouseMoveEvent(QMouseEvent* event); - void paintEvent(QPaintEvent* event); - void showEvent(QShowEvent* event); - void hideEvent(QHideEvent* event); - void leaveEvent(QEvent *event); - - private: - int padding; - int horizontalMargin; - int verticalMargin; - - QSize frameSize; - - QSize currentGridSize; - QSize minGridSize; - QSize maxGridSize; - }; + class QtGridSelectionDialog : public QWidget { + Q_OBJECT + + Q_PROPERTY(QSize currentGridSize READ getCurrentGridSize WRITE setCurrentGridSize NOTIFY currentGridSizeChanged) + Q_PROPERTY(QSize minGridSize READ getMinGridSize WRITE setMinGridSize NOTIFY minGridSizeChanged) + Q_PROPERTY(QSize maxGridSize READ getMaxGridSize WRITE setMaxGridSize NOTIFY maxGridSizeChanged) + public: + explicit QtGridSelectionDialog(QWidget* parent = nullptr); + + virtual QSize sizeHint() const; + + void setCurrentGridSize(const QSize& size); + QSize getCurrentGridSize() const; + void setMinGridSize(const QSize& size); + QSize getMinGridSize() const; + void setMaxGridSize(const QSize& size); + QSize getMaxGridSize() const; + + signals: + void currentGridSizeChanged(QSize); + void minGridSizeChanged(QSize); + void maxGridSizeChanged(QSize); + + protected: + void keyReleaseEvent(QKeyEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void paintEvent(QPaintEvent* event); + void showEvent(QShowEvent* event); + void hideEvent(QHideEvent* event); + void leaveEvent(QEvent *event); + bool event(QEvent* event); + + private: + int padding; + int horizontalMargin; + int verticalMargin; + + QSize frameSize; + + QSize currentGridSize; + QSize minGridSize; + QSize maxGridSize; + + const QString descriptionText; + }; } |