ADS: Integrate newest base repository commits

* Activate new ADS feature focus highlight
* Remove resources.qrc and related *.svg files
* Clean up new and existing source

Base repository was merged until commit
3de877fe5635ff51a6d1205ca98aad85d204427f

Merged changes from base repository include the following:

* Fix wrong current index when removing a widget from DockAreaLayout
* Fix invisible TabWidget for DockWidgets that are not part of a
  restored state
* Enable ClickFocus for DockWidget to support focussing in case the
  content does not support it
* Move focus related functionality into DockFocusController class
* Add new DockManger config flag FocusStyling
* Add support for focus styling of FloatingWidgetTitleBar
* Improve focus handling when dropping a DockWidget
* Improve highlighting focused DockWidget
* Improve setting of DockWidgetTab focus
* Add styling of focused DockWidget
* Fix docking of floating widgets for macOS
* Fix setting of DockingStateReader file version - use internal file
  version instead of user file version
* Fix saveState() and restoreState() version handling to work like the
  function from QMainWindow
* Fix escape key handling in native window event function if event
  WM_EXITSIZEMOVE occurs
* Implement windows drag handling with native WM_ nonclient area
  messages
* Fix showing DockArea when inserting a DockWidget in a hidden DockArea
* Fix setting DockAreaTabBar index to prevent showing of tab 0 when
  inserting a DockWidget into an area with no current index tab
* Fix wrong insertion order of DockWidget when dropping a floating
  widget to the left or top container drop area
* Fix tab changes position when redocking it to the same position
* Add nullptr check to fix potential nullptr access when closing a
  FloatingDockContainer
* Fix single DockArea cannot be split
* Fix visibility issue when adding dock widget after all other dock
  widgets have ben closed
* Fix FloatingDragPreview flashing of hidden overlay when dragging the
  last visible DockWidget in non opaque docking mode
* Fix FloatingDragPreview preventing dock widget from floating when
  dragging over another dock widget
* Fix DockWidget::setWidget function to test for QAbstractScrollArea
  instead of QScrollArea. Now setWidget properly supports ItemViews like
  QTreeView or QTableView
* Fix wrong display of center drop area when dragging over invisible
  dock area title bar
* Fix bug that drop overlay sometimes was not visible when moving the
  drag preview over a floating window
* Fix dropping of FloatingDragPreview into center of dock container with
  only one single visible dock area. If this happens the dropped dock
  widget needs to get tabified
* Fix crash when trying to make a DockWidget floating in non-opaque mode
  if the DockWidget is not floatable
* Fix DockWidgetTab to provide the right size when starting floating
* Add DockWidget functions setAsCurrentTab, raise, isCurrentTab,
  isTabbed
* Add new config flag HideSingleCentralWidgetTitleBar to enable a
  central single dock widget in the main dock container (dock manager)
  without titlebar
* Fix DockContainerWidget::hasTopLevelDockWidget() and
  DockContainerWidget::topLevelDockArea() to work properly also for the
  main non floating dock container
* Fix ElidingLabel to properly support Qt::ElideNone
* Add setElideMode function to DockWidgetTab
* Add setFullScreen(), setNormal() and isFullScreen() function to
  DockWidget
* Fix takeWidget() function and fixed setWidget() function to handle
  case when there is already a content widget

Task-number: QDS-2180
Change-Id: Ie30648ba329016c91fd19e9b4e12e31e47614b18
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-06-22 16:46:25 +02:00
committed by Henning Gründl
parent e5d9cb3779
commit a98c254c59
31 changed files with 1704 additions and 876 deletions

View File

@@ -7,6 +7,7 @@ add_qtc_library(AdvancedDockingSystem
dockareawidget.cpp dockareawidget.h
dockcomponentsfactory.cpp dockcomponentsfactory.h
dockcontainerwidget.cpp dockcontainerwidget.h
dockfocuscontroller.cpp dockfocuscontroller.h
dockingstatereader.cpp dockingstatereader.h
dockmanager.cpp dockmanager.h
dockoverlay.cpp dockoverlay.h
@@ -21,7 +22,6 @@ add_qtc_library(AdvancedDockingSystem
workspacemodel.cpp workspacemodel.h
workspaceview.cpp workspaceview.h
workspacedialog.ui
resources.qrc
)
extend_qtc_library(AdvancedDockingSystem

View File

@@ -41,6 +41,7 @@
#include <QAbstractButton>
#include <QPainter>
#include <QStyle>
#include <QVariant>
namespace ADS {
@@ -93,7 +94,7 @@ void hideEmptyParentSplitters(DockSplitter *splitter)
}
}
void setButtonIcon(QAbstractButton* button,
void setButtonIcon(QAbstractButton *button,
QStyle::StandardPixmap standarPixmap,
ADS::eIcon customIconId)
{
@@ -116,5 +117,25 @@ void setButtonIcon(QAbstractButton* button,
}
}
void repolishStyle(QWidget *widget, eRepolishChildOptions options)
{
if (!widget)
return;
widget->style()->unpolish(widget);
widget->style()->polish(widget);
if (RepolishIgnoreChildren == options)
return;
QList<QWidget*> children = widget->findChildren<QWidget *>(QString(),
(RepolishDirectChildren == options) ? Qt::FindDirectChildrenOnly : Qt::FindChildrenRecursively);
for (auto w : children)
{
w->style()->unpolish(w);
w->style()->polish(w);
}
}
} // namespace internal
} // namespace ADS

View File

@@ -72,8 +72,6 @@ QT_END_NAMESPACE
namespace ADS {
enum eStateFileVersion { InitialVerison = 0, Version1 = 1, CurrentVersion = Version1 };
class DockSplitter;
enum DockWidgetArea {
@@ -228,5 +226,18 @@ void setToolTip(QObjectPtr obj, const QString &tip)
void setButtonIcon(QAbstractButton *button, QStyle::StandardPixmap standarPixmap,
ADS::eIcon CustomIconId);
enum eRepolishChildOptions
{
RepolishIgnoreChildren,
RepolishDirectChildren,
RepolishChildrenRecursively
};
/**
* Calls unpolish() / polish for the style of the given widget to update
* stylesheet if a property changes
*/
void repolishStyle(QWidget *widget, eRepolishChildOptions options = RepolishIgnoreChildren);
} // namespace internal
} // namespace ADS

View File

@@ -5,9 +5,6 @@ shared {
}
## Input
RESOURCES += \
resources.qrc
HEADERS += \
ads_globals.h \
dockareatabbar.h \
@@ -15,6 +12,7 @@ HEADERS += \
dockareawidget.h \
dockcomponentsfactory.h \
dockcontainerwidget.h \
dockfocuscontroller.h \
dockingstatereader.h \
dockmanager.h \
dockoverlay.h \
@@ -36,6 +34,7 @@ SOURCES += \
dockareawidget.cpp \
dockcomponentsfactory.cpp \
dockcontainerwidget.cpp \
dockfocuscontroller.cpp \
dockingstatereader.cpp \
dockmanager.cpp \
dockoverlay.cpp \

View File

@@ -19,6 +19,7 @@ QtcLibrary {
"dockareawidget.cpp", "dockareawidget.h",
"dockcomponentsfactory.cpp", "dockcomponentsfactory.h",
"dockcontainerwidget.cpp", "dockcontainerwidget.h",
"dockfocuscontroller.cpp", "dockfocuscontroller.h",
"dockingstatereader.cpp", "dockingstatereader.h",
"dockmanager.cpp", "dockmanager.h",
"dockoverlay.cpp", "dockoverlay.h",
@@ -32,8 +33,7 @@ QtcLibrary {
"workspacedialog.cpp", "workspacedialog.h",
"workspacemodel.cpp", "workspacemodel.h",
"workspaceview.cpp", "workspaceview.h",
"workspacedialog.ui",
"resources.qrc"
"workspacedialog.ui"
]
}

View File

@@ -82,12 +82,12 @@ namespace ADS
/**
* Convenience function to access first tab
*/
DockWidgetTab *firstTab() const {return q->tab(0);}
DockWidgetTab *firstTab() const { return q->tab(0); }
/**
* Convenience function to access last tab
*/
DockWidgetTab *lastTab() const {return q->tab(q->count() - 1);}
DockWidgetTab *lastTab() const { return q->tab(q->count() - 1); }
}; // class DockAreaTabBarPrivate
DockAreaTabBarPrivate::DockAreaTabBarPrivate(DockAreaTabBar *parent)
@@ -140,11 +140,10 @@ namespace ADS
{
event->accept();
const int direction = event->angleDelta().y();
if (direction < 0) {
if (direction < 0)
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
} else {
else
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
}
}
void DockAreaTabBar::setCurrentIndex(int index)
@@ -189,9 +188,11 @@ namespace ADS
&DockAreaTabBar::elidedChanged);
dockWidgetTab->installEventFilter(this);
emit tabInserted(index);
if (index <= d->m_currentIndex || d->m_currentIndex == -1) {
if (index <= d->m_currentIndex)
setCurrentIndex(d->m_currentIndex + 1);
}
else if (d->m_currentIndex == -1)
setCurrentIndex(index);
updateGeometry();
}
@@ -235,11 +236,11 @@ namespace ADS
dockWidgetTab->disconnect(this);
dockWidgetTab->removeEventFilter(this);
qCInfo(adsLog) << "NewCurrentIndex " << newCurrentIndex;
if (newCurrentIndex != d->m_currentIndex) {
if (newCurrentIndex != d->m_currentIndex)
setCurrentIndex(newCurrentIndex);
} else {
else
d->updateTabs();
}
updateGeometry();
}
@@ -247,12 +248,11 @@ namespace ADS
DockWidgetTab *DockAreaTabBar::currentTab() const
{
if (d->m_currentIndex < 0) {
if (d->m_currentIndex < 0)
return nullptr;
} else {
else
return qobject_cast<DockWidgetTab *>(
d->m_tabsLayout->itemAt(d->m_currentIndex)->widget());
}
}
void DockAreaTabBar::onTabClicked()
@@ -292,9 +292,8 @@ namespace ADS
// If the the dock widget blocks closing, i.e. if the flag
// CustomCloseHandling is set, and the dock widget is still open,
// then we do not need to correct the index
if (currentTab->dockWidget()->isClosed()) {
if (currentTab->dockWidget()->isClosed())
i -= offset;
}
}
}
}

View File

@@ -103,10 +103,11 @@ namespace ADS
/**
* Returns true if the given config flag is set
* Convenience function to ease config flag testing
*/
static bool testConfigFlag(DockManager::eConfigFlag flag)
{
return DockManager::configFlags().testFlag(flag);
return DockManager::testConfigFlag(flag);
}
/**
@@ -159,7 +160,7 @@ namespace ADS
// Undock button
m_undockButton = new TitleBarButton(testConfigFlag(DockManager::DockAreaHasUndockButton));
m_undockButton->setObjectName("undockButton");
m_undockButton->setObjectName("detachGroupButton");
m_undockButton->setAutoRaise(true);
internal::setToolTip(m_undockButton, QObject::tr("Detach Group"));
internal::setButtonIcon(m_undockButton,
@@ -175,16 +176,16 @@ namespace ADS
// Close button
m_closeButton = new TitleBarButton(testConfigFlag(DockManager::DockAreaHasCloseButton));
m_closeButton->setObjectName("closeButton");
m_closeButton->setObjectName("dockAreaCloseButton");
m_closeButton->setAutoRaise(true);
internal::setButtonIcon(m_closeButton,
QStyle::SP_TitleBarCloseButton,
ADS::DockAreaCloseIcon);
if (testConfigFlag(DockManager::DockAreaCloseButtonClosesTab)) {
if (testConfigFlag(DockManager::DockAreaCloseButtonClosesTab))
internal::setToolTip(m_closeButton, QObject::tr("Close Active Tab"));
} else {
else
internal::setToolTip(m_closeButton, QObject::tr("Close Group"));
}
m_closeButton->setSizePolicy(sizePolicy);
m_closeButton->setIconSize(iconSize);
m_layout->addWidget(m_closeButton, 0);
@@ -238,7 +239,7 @@ namespace ADS
{
QSize size = m_dockArea->size();
m_dragState = dragState;
bool opaqueUndocking = DockManager::configFlags().testFlag(DockManager::OpaqueUndocking)
bool opaqueUndocking = DockManager::testConfigFlag(DockManager::OpaqueUndocking)
|| (DraggingFloatingWidget != dragState);
FloatingDockContainer *floatingDockContainer = nullptr;
AbstractFloatingWidget *floatingWidget;
@@ -269,9 +270,9 @@ namespace ADS
}
TitleBarButton::TitleBarButton(bool visible, QWidget *parent)
: TitleBarButtonType(parent),
m_visible(visible),
m_hideWhenDisabled(DockAreaTitleBarPrivate::testConfigFlag(DockManager::DockAreaHideDisabledButtons))
: TitleBarButtonType(parent)
, m_visible(visible)
, m_hideWhenDisabled(DockAreaTitleBarPrivate::testConfigFlag(DockManager::DockAreaHideDisabledButtons))
{}
void TitleBarButton::setVisible(bool visible)
@@ -281,9 +282,8 @@ namespace ADS
// 'visible' can stay 'true' unless: this button is configured to be invisible when it
// is disabled and it is currently disabled:
if (visible && m_hideWhenDisabled) {
if (visible && m_hideWhenDisabled)
visible = isEnabled();
}
Super::setVisible(visible);
}
@@ -360,9 +360,8 @@ namespace ADS
void DockAreaTitleBar::onTabsMenuAboutToShow()
{
if (!d->m_menuOutdated) {
if (!d->m_menuOutdated)
return;
}
QMenu *menu = d->m_tabsMenuButton->menu();
menu->clear();
@@ -382,18 +381,16 @@ namespace ADS
void DockAreaTitleBar::onCloseButtonClicked()
{
qCInfo(adsLog) << Q_FUNC_INFO;
if (d->testConfigFlag(DockManager::DockAreaCloseButtonClosesTab)) {
if (d->testConfigFlag(DockManager::DockAreaCloseButtonClosesTab))
d->m_tabBar->closeTab(d->m_tabBar->currentIndex());
} else {
else
d->m_dockArea->closeArea();
}
}
void DockAreaTitleBar::onUndockButtonClicked()
{
if (d->m_dockArea->features().testFlag(DockWidget::DockWidgetFloatable)) {
if (d->m_dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
}
}
void DockAreaTitleBar::onTabsMenuActionTriggered(QAction *action)
@@ -470,6 +467,9 @@ namespace ADS
event->accept();
d->m_dragStartMousePos = event->pos();
d->m_dragState = DraggingMousePressed;
if (DockManager::testConfigFlag(DockManager::FocusHighlighting))
d->m_tabBar->currentTab()->setFocus(Qt::OtherFocusReason);
return;
}
Super::mousePressEvent(event);
@@ -505,7 +505,7 @@ namespace ADS
return;
}
// If this is the last dock area in a dock container it does not make
// If this is the last dock area in a floating dock container it does not make
// sense to move it to a new floating widget and leave this one empty
if (d->m_dockArea->dockContainer()->isFloating()
&& d->m_dockArea->dockContainer()->visibleDockAreaCount() == 1) {
@@ -525,7 +525,7 @@ namespace ADS
int dragDistance = (d->m_dragStartMousePos - event->pos()).manhattanLength();
if (dragDistance >= DockManager::startDragDistance()) {
qCInfo(adsLog) << "TabsScrollArea::startFloating";
qCInfo(adsLog) << "DockAreaTitlBar::startFloating";
d->startFloating(d->m_dragStartMousePos);
auto overlay = d->m_dockArea->dockManager()->containerOverlay();
overlay->setAllowedAreas(OuterDockAreas);

View File

@@ -103,16 +103,15 @@ namespace ADS
void insertWidget(int index, QWidget *widget)
{
widget->setParent(nullptr);
if (index < 0) {
if (index < 0)
index = m_widgets.count();
}
m_widgets.insert(index, widget);
if (m_currentIndex < 0) {
setCurrentIndex(index);
} else {
if (index <= m_currentIndex) {
if (index <= m_currentIndex)
++m_currentIndex;
}
}
}
@@ -123,11 +122,13 @@ namespace ADS
{
if (currentWidget() == widget) {
auto layoutItem = m_parentLayout->takeAt(1);
if (layoutItem) {
if (layoutItem)
layoutItem->widget()->setParent(nullptr);
}
m_currentWidget = nullptr;
m_currentIndex = -1;
} else if (indexOf(widget) < m_currentIndex) {
--m_currentIndex;
}
m_widgets.removeOne(widget);
}
@@ -144,9 +145,8 @@ namespace ADS
{
QWidget *prev = currentWidget();
QWidget *next = widget(index);
if (!next || (next == prev && !m_currentWidget)) {
if (!next || (next == prev && !m_currentWidget))
return;
}
bool reenableUpdates = false;
QWidget *parent = m_parentLayout->parentWidget();
@@ -156,22 +156,18 @@ namespace ADS
parent->setUpdatesEnabled(false);
}
// TODO
auto layoutItem = m_parentLayout->takeAt(1);
if (layoutItem) {
if (auto layoutItem = m_parentLayout->takeAt(1))
layoutItem->widget()->setParent(nullptr);
}
m_parentLayout->addWidget(next);
if (prev) {
if (prev)
prev->hide();
}
m_currentIndex = index;
m_currentWidget = next;
if (reenableUpdates) {
if (reenableUpdates)
parent->setUpdatesEnabled(true);
}
}
/**
@@ -262,7 +258,7 @@ namespace ADS
DockAreaTabBar *tabBar() const { return m_titleBar->tabBar(); }
/**
* Udpates the enable state of the close and detach button
* Updates the enable state of the close and detach button
*/
void updateTitleBarButtonStates();
@@ -330,9 +326,8 @@ namespace ADS
d->createTitleBar();
d->m_contentsLayout = new DockAreaLayout(d->m_layout);
if (d->m_dockManager) {
if (d->m_dockManager)
emit d->m_dockManager->dockAreaCreated(this);
}
}
DockAreaWidget::~DockAreaWidget()
@@ -357,6 +352,7 @@ namespace ADS
void DockAreaWidget::insertDockWidget(int index, DockWidget *dockWidget, bool activate)
{
d->m_contentsLayout->insertWidget(index, dockWidget);
dockWidget->setDockArea(this);
dockWidget->tabWidget()->setDockAreaWidget(this);
auto tabWidget = dockWidget->tabWidget();
// Inserting the tab will change the current index which in turn will
@@ -370,10 +366,14 @@ namespace ADS
dockWidget->minimumSizeHint().height()));
d->m_minSizeHint.setWidth(qMax(d->m_minSizeHint.width(),
dockWidget->minimumSizeHint().width()));
if (activate) {
if (activate)
setCurrentIndex(index);
}
dockWidget->setDockArea(this);
// If this dock area is hidden, then we need to make it visible again
// by calling dockWidget->toggleViewInternal(true);
if (!this->isVisible() && d->m_contentsLayout->count() > 1 && !dockManager()->isRestoringState())
dockWidget->toggleViewInternal(true);
d->updateTitleBarButtonStates();
}
@@ -389,7 +389,7 @@ namespace ADS
DockContainerWidget *dockContainerWidget = dockContainer();
if (nextOpen) {
setCurrentDockWidget(nextOpen);
} else if (d->m_contentsLayout->isEmpty() && dockContainerWidget->dockAreaCount() > 1) {
} else if (d->m_contentsLayout->isEmpty() && dockContainerWidget->dockAreaCount() >= 1) {
qCInfo(adsLog) << "Dock Area empty";
dockContainerWidget->removeDockArea(this);
this->deleteLater();
@@ -404,9 +404,8 @@ namespace ADS
updateTitleBarVisibility();
d->updateMinimumSizeHint();
auto topLevelDockWidget = dockContainerWidget->topLevelDockWidget();
if (topLevelDockWidget) {
if (topLevelDockWidget)
topLevelDockWidget->emitTopLevelChanged(true);
}
#if (ADS_DEBUG_LEVEL > 0)
dockContainerWidget->dumpLayout();
@@ -423,17 +422,19 @@ namespace ADS
//Hide empty floating widget
DockContainerWidget *container = this->dockContainer();
if (!container->isFloating()) {
if (!container->isFloating()
&& DockManager::testConfigFlag(DockManager::HideSingleCentralWidgetTitleBar))
return;
}
updateTitleBarVisibility();
auto topLevelWidget = container->topLevelDockWidget();
auto floatingWidget = container->floatingWidget();
if (topLevelWidget) {
floatingWidget->updateWindowTitle();
if (floatingWidget)
floatingWidget->updateWindowTitle();
DockWidget::emitTopLevelEventForWidget(topLevelWidget, true);
} else if (container->openedDockAreas().isEmpty()) {
} else if (container->openedDockAreas().isEmpty() && floatingWidget) {
floatingWidget->hide();
}
}
@@ -442,28 +443,25 @@ namespace ADS
{
qCInfo(adsLog) << Q_FUNC_INFO << "index" << index;
auto *currentDockWidget = dockWidget(index);
if (currentDockWidget->features().testFlag(DockWidget::DockWidgetDeleteOnClose)) {
if (currentDockWidget->features().testFlag(DockWidget::DockWidgetDeleteOnClose))
currentDockWidget->closeDockWidgetInternal();
} else {
else
currentDockWidget->toggleView(false);
}
}
DockWidget *DockAreaWidget::currentDockWidget() const
{
int currentIdx = currentIndex();
if (currentIdx < 0) {
if (currentIdx < 0)
return nullptr;
}
return dockWidget(currentIdx);
}
void DockAreaWidget::setCurrentDockWidget(DockWidget *dockWidget)
{
if (dockManager()->isRestoringState()) {
if (dockManager()->isRestoringState())
return;
}
internalSetCurrentDockWidget(dockWidget);
}
@@ -471,9 +469,8 @@ namespace ADS
void DockAreaWidget::internalSetCurrentDockWidget(DockWidget *dockWidget)
{
int index = indexOf(dockWidget);
if (index < 0) {
if (index < 0)
return;
}
setCurrentIndex(index);
}
@@ -488,9 +485,8 @@ namespace ADS
auto cw = d->m_contentsLayout->currentWidget();
auto nw = d->m_contentsLayout->widget(index);
if (cw == nw && !nw->isHidden()) {
if (cw == nw && !nw->isHidden())
return;
}
emit currentChanging(index);
currentTabBar->setCurrentIndex(index);
@@ -513,9 +509,9 @@ namespace ADS
QList<DockWidget *> DockAreaWidget::dockWidgets() const
{
QList<DockWidget *> dockWidgetList;
for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
for (int i = 0; i < d->m_contentsLayout->count(); ++i)
dockWidgetList.append(dockWidget(i));
}
return dockWidgetList;
}
@@ -523,9 +519,8 @@ namespace ADS
{
int count = 0;
for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
if (!dockWidget(i)->isClosed()) {
if (!dockWidget(i)->isClosed())
++count;
}
}
return count;
}
@@ -535,9 +530,8 @@ namespace ADS
QList<DockWidget *> dockWidgetList;
for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
DockWidget *currentDockWidget = dockWidget(i);
if (!currentDockWidget->isClosed()) {
if (!currentDockWidget->isClosed())
dockWidgetList.append(dockWidget(i));
}
}
return dockWidgetList;
}
@@ -545,12 +539,11 @@ namespace ADS
int DockAreaWidget::indexOfFirstOpenDockWidget() const
{
for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
if (!dockWidget(i)->isClosed()) {
if (!dockWidget(i)->isClosed())
return i;
}
}
return -1;
return - 1;
}
int DockAreaWidget::dockWidgetsCount() const { return d->m_contentsLayout->count(); }
@@ -585,24 +578,23 @@ namespace ADS
void DockAreaWidget::updateTitleBarVisibility()
{
DockContainerWidget *container = dockContainer();
if (!container) {
if (!container)
return;
}
if (DockManager::configFlags().testFlag(DockManager::AlwaysShowTabs)) {
if (DockManager::testConfigFlag(DockManager::AlwaysShowTabs))
return;
}
if (d->m_titleBar) {
d->m_titleBar->setVisible(!container->isFloating() || !container->hasTopLevelDockWidget());
bool hidden = container->hasTopLevelDockWidget() && (container->isFloating()
|| DockManager::testConfigFlag(DockManager::HideSingleCentralWidgetTitleBar));
d->m_titleBar->setVisible(!hidden);
}
}
void DockAreaWidget::markTitleBarMenuOutdated()
{
if (d->m_titleBar) {
if (d->m_titleBar)
d->m_titleBar->markTabsMenuOutdated();
}
}
void DockAreaWidget::saveState(QXmlStreamWriter &stream) const
@@ -614,9 +606,9 @@ namespace ADS
stream.writeAttribute("current", name);
qCInfo(adsLog) << Q_FUNC_INFO << "TabCount: " << d->m_contentsLayout->count()
<< " Current: " << name;
for (int i = 0; i < d->m_contentsLayout->count(); ++i) {
for (int i = 0; i < d->m_contentsLayout->count(); ++i)
dockWidget(i)->saveState(stream);
}
stream.writeEndElement();
}
@@ -643,15 +635,15 @@ namespace ADS
{
if (BitwiseAnd == mode) {
DockWidget::DockWidgetFeatures features(DockWidget::AllDockWidgetFeatures);
for (const auto dockWidget : dockWidgets()) {
for (const auto dockWidget : dockWidgets())
features &= dockWidget->features();
}
return features;
} else {
DockWidget::DockWidgetFeatures features(DockWidget::NoDockWidgetFeatures);
for (const auto dockWidget : dockWidgets()) {
for (const auto dockWidget : dockWidgets())
features |= dockWidget->features();
}
return features;
}
}
@@ -666,9 +658,8 @@ namespace ADS
void DockAreaWidget::setVisible(bool visible)
{
Super::setVisible(visible);
if (d->m_updateTitleBarButtons) {
if (d->m_updateTitleBarButtons)
d->updateTitleBarButtonStates();
}
}
void DockAreaWidget::setAllowedAreas(DockWidgetAreas areas)
@@ -695,9 +686,8 @@ namespace ADS
&& openDockWidgets[0]->features().testFlag(DockWidget::DockWidgetDeleteOnClose)) {
openDockWidgets[0]->closeDockWidgetInternal();
} else {
for (auto dockWidget : openedDockWidgets()) {
for (auto dockWidget : openedDockWidgets())
dockWidget->toggleView(false);
}
}
}

View File

@@ -95,11 +95,10 @@ namespace ADS
*/
static void insertWidgetIntoSplitter(QSplitter *splitter, QWidget *widget, bool append)
{
if (append) {
if (append)
splitter->addWidget(widget);
} else {
else
splitter->insertWidget(0, widget);
}
}
/**
@@ -128,14 +127,14 @@ namespace ADS
* Adds dock widget to container and returns the dock area that contains
* the inserted dock widget
*/
DockAreaWidget *dockWidgetIntoContainer(DockWidgetArea area, DockWidget *dockWidget);
DockAreaWidget *addDockWidgetToContainer(DockWidgetArea area, DockWidget *dockWidget);
/**
* Adds dock widget to a existing DockWidgetArea
*/
DockAreaWidget *dockWidgetIntoDockArea(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget *targetDockArea);
DockAreaWidget *addDockWidgetToDockArea(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget *targetDockArea);
/**
* Add dock area to this container
@@ -233,14 +232,12 @@ namespace ADS
*/
void initVisibleDockAreaCount()
{
if (m_visibleDockAreaCount > -1) {
if (m_visibleDockAreaCount > -1)
return;
}
m_visibleDockAreaCount = 0;
for (auto dockArea : m_dockAreas) {
for (auto dockArea : m_dockAreas)
m_visibleDockAreaCount += dockArea->isHidden() ? 0 : 1;
}
}
/**
@@ -248,7 +245,7 @@ namespace ADS
*/
int visibleDockAreaCount()
{
// Lazy initialization - we initialize the VisibleDockAreaCount variable
// Lazy initialization - we initialize the m_visibleDockAreaCount variable
// on first use
initVisibleDockAreaCount();
return m_visibleDockAreaCount;
@@ -278,12 +275,29 @@ namespace ADS
DockSplitter *createSplitter(Qt::Orientation orientation, QWidget *parent = nullptr)
{
auto *splitter = new DockSplitter(orientation, parent);
splitter->setOpaqueResize(
DockManager::configFlags().testFlag(DockManager::OpaqueSplitterResize));
splitter->setOpaqueResize(DockManager::testConfigFlag(DockManager::OpaqueSplitterResize));
splitter->setChildrenCollapsible(false);
return splitter;
}
/**
* Ensures equal distribution of the sizes of a splitter if an dock widget
* is inserted from code
*/
void adjustSplitterSizesOnInsertion(QSplitter *splitter, qreal lastRatio = 1.0)
{
const int areaSize = (splitter->orientation() == Qt::Horizontal) ? splitter->width()
: splitter->height();
auto splitterSizes = splitter->sizes();
const qreal totalRatio = splitterSizes.size() - 1.0 + lastRatio;
for (int i = 0; i < splitterSizes.size() - 1; ++i)
splitterSizes[i] = areaSize / totalRatio;
splitterSizes.back() = areaSize * lastRatio / totalRatio;
splitter->setSizes(splitterSizes);
}
void onDockAreaViewToggled(bool visible)
{
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(q->sender());
@@ -309,9 +323,8 @@ namespace ADS
auto dropOverlay = m_dockManager->dockAreaOverlay();
dropOverlay->setAllowedAreas(dockArea->allowedAreas());
dropArea = dropOverlay->showOverlay(dockArea);
if (containerDropArea != InvalidDockWidgetArea && containerDropArea != dropArea) {
if (containerDropArea != InvalidDockWidgetArea && containerDropArea != dropArea)
dropArea = InvalidDockWidgetArea;
}
if (dropArea != InvalidDockWidgetArea) {
qCInfo(adsLog) << "Dock Area Drop Content: " << dropArea;
@@ -323,9 +336,8 @@ namespace ADS
if (InvalidDockWidgetArea == dropArea) {
dropArea = containerDropArea;
qCInfo(adsLog) << "Container Drop Content: " << dropArea;
if (dropArea != InvalidDockWidgetArea) {
if (dropArea != InvalidDockWidgetArea)
return DropModeIntoContainer;
}
}
return DropModeInvalid;
@@ -373,11 +385,9 @@ namespace ADS
if (floatingSplitter->count() == 1) {
insertWidgetIntoSplitter(splitter, floatingSplitter->widget(0), insertParam.append());
} else if (floatingSplitter->orientation() == insertParam.orientation()) {
while (floatingSplitter->count()) {
insertWidgetIntoSplitter(splitter,
floatingSplitter->widget(0),
insertParam.append());
}
int insertIndex = insertParam.append() ? splitter->count() : 0;
while (floatingSplitter->count())
splitter->insertWidget(insertIndex++, floatingSplitter->widget(0));
} else {
insertWidgetIntoSplitter(splitter, floatingSplitter, insertParam.append());
}
@@ -388,9 +398,9 @@ namespace ADS
// If we dropped the floating widget into the main dock container that does
// not contain any dock widgets, then splitter is invisible and we need to
// show it to display the docked widgets
if (!splitter->isVisible()) {
if (!splitter->isVisible())
splitter->show();
}
q->dumpLayout();
}
@@ -405,9 +415,8 @@ namespace ADS
// If the floating widget contains only one single dock are, then the
// current dock widget of the dock area will also be the future current
// dock widget in the drop area.
if (topLevelDockArea) {
if (topLevelDockArea)
newCurrentIndex = topLevelDockArea->currentIndex();
}
for (int i = 0; i < newDockWidgets.count(); ++i) {
DockWidget *dockWidget = newDockWidgets[i];
@@ -415,9 +424,8 @@ namespace ADS
// If the floating widget contains multiple visible dock areas, then we
// simply pick the first visible open dock widget and make it
// the current one.
if (newCurrentIndex < 0 && !dockWidget->isClosed()) {
if (newCurrentIndex < 0 && !dockWidget->isClosed())
newCurrentIndex = i;
}
}
targetArea->setCurrentIndex(newCurrentIndex);
targetArea->updateTitleBarVisibility();
@@ -464,9 +472,8 @@ namespace ADS
} else {
adjustSplitterSizes = (floatingSplitter->count() == 1);
int insertIndex = areaIndex + insertParam.insertOffset();
while (floatingSplitter->count()) {
while (floatingSplitter->count())
targetAreaSplitter->insertWidget(insertIndex++, floatingSplitter->widget(0));
}
}
if (adjustSplitterSizes) {
@@ -516,9 +523,12 @@ namespace ADS
if (droppedDockWidget) {
DockAreaWidget *oldDockArea = droppedDockWidget->dockAreaWidget();
if (oldDockArea) {
if (oldDockArea == targetArea)
return;
if (oldDockArea)
oldDockArea->removeDockWidget(droppedDockWidget);
}
targetArea->insertDockWidget(0, droppedDockWidget, true);
} else {
QList<DockWidget *> newDockWidgets = droppedArea->dockWidgets();
@@ -553,9 +563,9 @@ namespace ADS
if (droppedDockWidget) {
newDockArea = new DockAreaWidget(m_dockManager, q);
DockAreaWidget *oldDockArea = droppedDockWidget->dockAreaWidget();
if (oldDockArea) {
if (oldDockArea)
oldDockArea->removeDockWidget(droppedDockWidget);
}
newDockArea->addDockWidget(droppedDockWidget);
} else {
droppedDockArea->dockContainer()->removeDockArea(droppedDockArea);
@@ -564,25 +574,25 @@ namespace ADS
auto insertParam = internal::dockAreaInsertParameters(area);
QSplitter *targetAreaSplitter = internal::findParent<QSplitter *>(targetArea);
int areaIndex = targetAreaSplitter->indexOf(targetArea);
const int areaIndex = targetAreaSplitter->indexOf(targetArea);
auto sizes = targetAreaSplitter->sizes();
if (targetAreaSplitter->orientation() == insertParam.orientation()) {
int targetAreaSize = (insertParam.orientation() == Qt::Horizontal)
? targetArea->width()
: targetArea->height();
const int targetAreaSize = (insertParam.orientation() == Qt::Horizontal)
? targetArea->width()
: targetArea->height();
targetAreaSplitter->insertWidget(areaIndex + insertParam.insertOffset(), newDockArea);
int size = (targetAreaSize - targetAreaSplitter->handleWidth()) / 2;
const int size = (targetAreaSize - targetAreaSplitter->handleWidth()) / 2;
sizes[areaIndex] = size;
sizes.insert(areaIndex, size);
} else {
auto sizes = targetAreaSplitter->sizes();
int targetAreaSize = (insertParam.orientation() == Qt::Horizontal)
? targetArea->width()
: targetArea->height();
const int targetAreaSize = (insertParam.orientation() == Qt::Horizontal)
? targetArea->width()
: targetArea->height();
QSplitter *newSplitter = createSplitter(insertParam.orientation());
newSplitter->addWidget(targetArea);
insertWidgetIntoSplitter(newSplitter, newDockArea, insertParam.append());
int size = targetAreaSize / 2;
const int size = targetAreaSize / 2;
newSplitter->setSizes({size, size});
targetAreaSplitter->insertWidget(areaIndex, newSplitter);
}
@@ -600,9 +610,9 @@ namespace ADS
if (droppedDockWidget) {
newDockArea = new DockAreaWidget(m_dockManager, q);
DockAreaWidget *oldDockArea = droppedDockWidget->dockAreaWidget();
if (oldDockArea) {
if (oldDockArea)
oldDockArea->removeDockWidget(droppedDockWidget);
}
newDockArea->addDockWidget(droppedDockWidget);
} else {
// We check, if we insert the dropped widget into the same place that
@@ -627,8 +637,8 @@ namespace ADS
void DockContainerWidgetPrivate::addDockAreasToList(const QList<DockAreaWidget *> newDockAreas)
{
int countBefore = m_dockAreas.count();
int newAreaCount = newDockAreas.count();
const int countBefore = m_dockAreas.count();
const int newAreaCount = newDockAreas.count();
appendDockAreas(newDockAreas);
// If the user dropped a floating widget that contains only one single
// visible dock area, then its title bar button TitleBarButtonUndock is
@@ -640,13 +650,11 @@ namespace ADS
// We need to ensure, that the dock area title bar is visible. The title bar
// is invisible, if the dock are is a single dock area in a floating widget.
if (1 == countBefore) {
if (1 == countBefore)
m_dockAreas.at(0)->updateTitleBarVisibility();
}
if (1 == newAreaCount) {
if (1 == newAreaCount)
m_dockAreas.last()->updateTitleBarVisibility();
}
emitDockAreasAdded();
}
@@ -674,23 +682,21 @@ namespace ADS
stream.writeAttribute("count", QString::number(splitter->count()));
qCInfo(adsLog) << "NodeSplitter orient: " << splitter->orientation()
<< " WidgetCont: " << splitter->count();
for (int i = 0; i < splitter->count(); ++i) {
for (int i = 0; i < splitter->count(); ++i)
saveChildNodesState(stream, splitter->widget(i));
}
stream.writeStartElement("sizes");
QStringList sizes;
for (auto size : splitter->sizes()) {
for (auto size : splitter->sizes())
sizes.append(QString::number(size));
}
stream.writeCharacters(sizes.join(" "));
stream.writeEndElement();
stream.writeEndElement();
stream.writeEndElement(); // sizes
stream.writeEndElement(); // splitter
} else {
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(widget);
if (dockArea) {
if (dockArea)
dockArea->saveState(stream);
}
}
}
@@ -701,22 +707,22 @@ namespace ADS
QVariant orientationVar = QVariant(stateReader.attributes().value("orientation").toString());
// Check if the orientation string is convertable
if (!orientationVar.canConvert<Qt::Orientation>()) {
if (!orientationVar.canConvert<Qt::Orientation>())
return false;
}
Qt::Orientation orientation = orientationVar.value<Qt::Orientation>();
bool ok;
int widgetCount = stateReader.attributes().value("count").toInt(&ok);
if (!ok) {
if (!ok)
return false;
}
qCInfo(adsLog) << "Restore NodeSplitter Orientation: " << orientation
<< " WidgetCount: " << widgetCount;
QSplitter *splitter = nullptr;
if (!testing) {
if (!testing)
splitter = createSplitter(orientation);
}
bool visible = false;
QList<int> sizes;
while (stateReader.readNextStartElement()) {
@@ -739,13 +745,11 @@ namespace ADS
stateReader.skipCurrentElement();
}
if (!result) {
if (!result)
return false;
}
if (testing || !childNode) {
if (testing || !childNode)
continue;
}
qCInfo(adsLog) << "ChildNode isVisible " << childNode->isVisible() << " isVisibleTo "
<< childNode->isVisibleTo(splitter);
@@ -753,9 +757,8 @@ namespace ADS
visible |= childNode->isVisibleTo(splitter);
}
if (sizes.count() != widgetCount) {
if (sizes.count() != widgetCount)
return false;
}
if (!testing) {
if (!splitter->count()) {
@@ -782,22 +785,20 @@ namespace ADS
#ifdef ADS_DEBUG_PRINT
bool ok;
int tabs = stateReader.attributes().value("tabs").toInt(&ok);
if (!ok) {
if (!ok)
return false;
}
qCInfo(adsLog) << "Restore NodeDockArea Tabs: " << tabs
<< " Current: " << currentDockWidget;
#endif
DockAreaWidget *dockArea = nullptr;
if (!testing) {
if (!testing)
dockArea = new DockAreaWidget(m_dockManager, q);
}
while (stateReader.readNextStartElement()) {
if (stateReader.name() != "widget") {
if (stateReader.name() != "widget")
continue;
}
auto objectName = stateReader.attributes().value("name");
if (objectName.isEmpty()) {
@@ -806,16 +807,15 @@ namespace ADS
}
QVariant closedVar = QVariant(stateReader.attributes().value("closed").toString());
if (!closedVar.canConvert<bool>()) {
if (!closedVar.canConvert<bool>())
return false;
}
bool closed = closedVar.value<bool>();
stateReader.skipCurrentElement();
DockWidget *dockWidget = m_dockManager->findDockWidget(objectName.toString());
if (!dockWidget || testing) {
if (!dockWidget || testing)
continue;
}
qCInfo(adsLog) << "Dock Widget found - parent " << dockWidget->parent();
// We hide the DockArea here to prevent the short display (the flashing)
@@ -828,9 +828,8 @@ namespace ADS
dockWidget->setProperty(internal::dirtyProperty, false);
}
if (testing) {
if (testing)
return true;
}
if (!dockArea->dockWidgetsCount()) {
delete dockArea;
@@ -865,8 +864,8 @@ namespace ADS
return result;
}
DockAreaWidget *DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetArea area,
DockWidget *dockWidget)
DockAreaWidget *DockContainerWidgetPrivate::addDockWidgetToContainer(DockWidgetArea area,
DockWidget *dockWidget)
{
DockAreaWidget *newDockArea = new DockAreaWidget(m_dockManager, q);
newDockArea->addDockWidget(dockWidget);
@@ -880,13 +879,15 @@ namespace ADS
{
auto insertParam = internal::dockAreaInsertParameters(area);
// As long as we have only one dock area in the splitter we can adjust its orientation
if (m_dockAreas.count() <= 1) {
if (m_dockAreas.count() <= 1)
m_rootSplitter->setOrientation(insertParam.orientation());
}
QSplitter *splitter = m_rootSplitter;
if (splitter->orientation() == insertParam.orientation()) {
insertWidgetIntoSplitter(splitter, newDockArea, insertParam.append());
if (splitter->isHidden())
splitter->show();
} else {
QSplitter *newSplitter = createSplitter(insertParam.orientation());
if (insertParam.append()) {
@@ -924,14 +925,13 @@ namespace ADS
<< (splitter->isHidden() ? " " : "v") << " "
<< QString::number(splitter->count()).toStdString() << std::endl;
#endif
for (int i = 0; i < splitter->count(); ++i) {
for (int i = 0; i < splitter->count(); ++i)
dumpRecursive(level + 1, splitter->widget(i));
}
} else {
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(widget);
if (!dockArea) {
if (!dockArea)
return;
}
#ifdef ADS_DEBUG_PRINT
qDebug("%sDockArea", buf.data());
std::cout << buf.data() << (dockArea->isHidden() ? " " : "v")
@@ -953,10 +953,9 @@ namespace ADS
#endif
}
DockAreaWidget *DockContainerWidgetPrivate::dockWidgetIntoDockArea(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget
*targetDockArea)
DockAreaWidget *DockContainerWidgetPrivate::addDockWidgetToDockArea(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget *targetDockArea)
{
if (CenterDockWidgetArea == area) {
targetDockArea->addDockWidget(dockWidget);
@@ -973,12 +972,20 @@ namespace ADS
if (targetAreaSplitter->orientation() == insertParam.orientation()) {
qCInfo(adsLog) << "TargetAreaSplitter->orientation() == InsertParam.orientation()";
targetAreaSplitter->insertWidget(index + insertParam.insertOffset(), newDockArea);
// do nothing, if flag is not enabled
if (DockManager::testConfigFlag(DockManager::EqualSplitOnInsertion))
adjustSplitterSizesOnInsertion(targetAreaSplitter);
} else {
qCInfo(adsLog) << "TargetAreaSplitter->orientation() != InsertParam.orientation()";
auto targetAreaSizes = targetAreaSplitter->sizes();
QSplitter *newSplitter = createSplitter(insertParam.orientation());
newSplitter->addWidget(targetDockArea);
insertWidgetIntoSplitter(newSplitter, newDockArea, insertParam.append());
targetAreaSplitter->insertWidget(index, newSplitter);
if (DockManager::testConfigFlag(DockManager::EqualSplitOnInsertion)) {
targetAreaSplitter->setSizes(targetAreaSizes);
adjustSplitterSizesOnInsertion(newSplitter);
}
}
appendDockAreas({newDockArea});
@@ -1011,9 +1018,9 @@ namespace ADS
DockContainerWidget::~DockContainerWidget()
{
if (d->m_dockManager) {
if (d->m_dockManager)
d->m_dockManager->removeDockContainer(this);
}
delete d;
}
@@ -1022,24 +1029,21 @@ namespace ADS
DockAreaWidget *dockAreaWidget)
{
DockAreaWidget *oldDockArea = dockWidget->dockAreaWidget();
if (oldDockArea) {
if (oldDockArea)
oldDockArea->removeDockWidget(dockWidget);
}
dockWidget->setDockManager(d->m_dockManager);
if (dockAreaWidget) {
return d->dockWidgetIntoDockArea(area, dockWidget, dockAreaWidget);
} else {
return d->dockWidgetIntoContainer(area, dockWidget);
}
if (dockAreaWidget)
return d->addDockWidgetToDockArea(area, dockWidget, dockAreaWidget);
else
return d->addDockWidgetToContainer(area, dockWidget);
}
void DockContainerWidget::removeDockWidget(DockWidget * dockWidget)
{
DockAreaWidget *area = dockWidget->dockAreaWidget();
if (area) {
if (area)
area->removeDockWidget(dockWidget);
}
}
unsigned int DockContainerWidget::zOrderIndex() const { return d->m_zOrderIndex; }
@@ -1052,11 +1056,10 @@ namespace ADS
bool DockContainerWidget::event(QEvent *event)
{
bool result = QWidget::event(event);
if (event->type() == QEvent::WindowActivate) {
if (event->type() == QEvent::WindowActivate)
d->m_zOrderIndex = ++zOrderCounter;
} else if (event->type() == QEvent::Show && !d->m_zOrderIndex) {
else if (event->type() == QEvent::Show && !d->m_zOrderIndex)
d->m_zOrderIndex = ++zOrderCounter;
}
return result;
}
@@ -1064,9 +1067,8 @@ namespace ADS
void DockContainerWidget::addDockArea(DockAreaWidget *dockAreaWidget, DockWidgetArea area)
{
DockContainerWidget *container = dockAreaWidget->dockContainer();
if (container && container != this) {
if (container && container != this)
container->removeDockArea(dockAreaWidget);
}
d->addDockArea(dockAreaWidget, area);
}
@@ -1085,9 +1087,8 @@ namespace ADS
// Remove this area from cached areas
const auto &cache = d->m_lastAddedAreaCache;
if (auto p = std::find(cache, cache + sizeof(cache) / sizeof(cache[0]), area)) {
if (auto p = std::find(cache, cache + sizeof(cache) / sizeof(cache[0]), area))
d->m_lastAddedAreaCache[std::distance(cache, p)] = nullptr;
}
// If splitter has more than 1 widgets, we are finished and can leave
if (splitter->count() > 1) {
@@ -1149,9 +1150,8 @@ namespace ADS
{
for (auto dockArea : d->m_dockAreas) {
if (dockArea->isVisible()
&& dockArea->rect().contains(dockArea->mapFromGlobal(globalPosition))) {
&& dockArea->rect().contains(dockArea->mapFromGlobal(globalPosition)))
return dockArea;
}
}
return nullptr;
@@ -1169,9 +1169,8 @@ namespace ADS
int DockContainerWidget::visibleDockAreaCount() const
{
int result = 0;
for (auto dockArea : d->m_dockAreas) {
for (auto dockArea : d->m_dockAreas)
result += dockArea->isHidden() ? 0 : 1;
}
return result;
@@ -1195,9 +1194,8 @@ namespace ADS
auto dropOverlay = d->m_dockManager->dockAreaOverlay();
dropOverlay->setAllowedAreas(dockArea->allowedAreas());
dropArea = dropOverlay->showOverlay(dockArea);
if (containerDropArea != InvalidDockWidgetArea && containerDropArea != dropArea) {
if (containerDropArea != InvalidDockWidgetArea && containerDropArea != dropArea)
dropArea = InvalidDockWidgetArea;
}
if (dropArea != InvalidDockWidgetArea) {
qCInfo(adsLog) << "Dock Area Drop Content: " << dropArea;
@@ -1227,6 +1225,11 @@ namespace ADS
// level widget anymore
DockWidget::emitTopLevelEventForWidget(singleDockWidget, false);
}
window()->activateWindow();
if (singleDroppedDockWidget)
d->m_dockManager->notifyWidgetOrAreaRelocation(singleDroppedDockWidget);
d->m_dockManager->notifyFloatingWidgetDrop(floatingWidget);
}
void DockContainerWidget::dropWidget(QWidget *widget, DockWidgetArea dropArea, DockAreaWidget *targetAreaWidget)
@@ -1240,15 +1243,25 @@ namespace ADS
// If there was a top level widget before the drop, then it is not top
// level widget anymore
DockWidget::emitTopLevelEventForWidget(singleDockWidget, false);
DockWidget *dockWidget = qobject_cast<DockWidget *>(widget);
if (!dockWidget)
{
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(widget);
auto openDockWidgets = dockArea->openedDockWidgets();
if (openDockWidgets.count() == 1)
dockWidget = openDockWidgets[0];
}
window()->activateWindow();
d->m_dockManager->notifyWidgetOrAreaRelocation(widget);
}
QList<DockAreaWidget *> DockContainerWidget::openedDockAreas() const
{
QList<DockAreaWidget *> result;
for (auto dockArea : d->m_dockAreas) {
if (!dockArea->isHidden()) {
if (!dockArea->isHidden())
result.append(dockArea);
}
}
return result;
@@ -1272,9 +1285,9 @@ namespace ADS
bool DockContainerWidget::restoreState(DockingStateReader &stateReader, bool testing)
{
QVariant floatingVar = QVariant(stateReader.attributes().value("floating").toString());
if (!floatingVar.canConvert<bool>()) {
if (!floatingVar.canConvert<bool>())
return false;
}
bool isFloating = floatingVar.value<bool>();
qCInfo(adsLog) << "Restore DockContainerWidget Floating" << isFloating;
@@ -1289,18 +1302,16 @@ namespace ADS
if (isFloating) {
qCInfo(adsLog) << "Restore floating widget";
if (!stateReader.readNextStartElement() || stateReader.name() != "geometry") {
if (!stateReader.readNextStartElement() || stateReader.name() != "geometry")
return false;
}
QByteArray geometryString = stateReader
.readElementText(
DockingStateReader::ErrorOnUnexpectedElement)
.toLocal8Bit();
QByteArray geometry = QByteArray::fromBase64(geometryString);
if (geometry.isEmpty()) {
if (geometry.isEmpty())
return false;
}
if (!testing) {
FloatingDockContainer *floatingDockContainer = floatingWidget();
@@ -1308,19 +1319,16 @@ namespace ADS
}
}
if (!d->restoreChildNodes(stateReader, newRootSplitter, testing)) {
if (!d->restoreChildNodes(stateReader, newRootSplitter, testing))
return false;
}
if (testing) {
if (testing)
return true;
}
// If the root splitter is empty, rostoreChildNodes returns a 0 pointer
// and we need to create a new empty root splitter
if (!newRootSplitter) {
if (!newRootSplitter)
newRootSplitter = d->createSplitter(Qt::Horizontal);
}
d->m_layout->replaceWidget(d->m_rootSplitter, newRootSplitter);
QSplitter *oldRoot = d->m_rootSplitter;
@@ -1334,9 +1342,9 @@ namespace ADS
void DockContainerWidget::createRootSplitter()
{
if (d->m_rootSplitter) {
if (d->m_rootSplitter)
return;
}
d->m_rootSplitter = d->createSplitter(Qt::Horizontal);
d->m_layout->addWidget(d->m_rootSplitter);
}
@@ -1359,14 +1367,9 @@ namespace ADS
bool DockContainerWidget::hasTopLevelDockWidget() const
{
if (!isFloating()) {
return false;
}
auto dockAreas = openedDockAreas();
if (dockAreas.count() != 1) {
if (dockAreas.count() != 1)
return false;
}
return dockAreas[0]->openDockWidgetsCount() == 1;
}
@@ -1374,28 +1377,21 @@ namespace ADS
DockWidget *DockContainerWidget::topLevelDockWidget() const
{
auto dockArea = topLevelDockArea();
if (!dockArea) {
if (!dockArea)
return nullptr;
}
auto dockWidgets = dockArea->openedDockWidgets();
if (dockWidgets.count() != 1) {
if (dockWidgets.count() != 1)
return nullptr;
}
return dockWidgets[0];
}
DockAreaWidget *DockContainerWidget::topLevelDockArea() const
{
if (!isFloating()) {
return nullptr;
}
auto dockAreas = openedDockAreas();
if (dockAreas.count() != 1) {
if (dockAreas.count() != 1)
return nullptr;
}
return dockAreas[0];
}
@@ -1403,9 +1399,8 @@ namespace ADS
QList<DockWidget *> DockContainerWidget::dockWidgets() const
{
QList<DockWidget *> result;
for (const auto dockArea : d->m_dockAreas) {
for (const auto dockArea : d->m_dockAreas)
result.append(dockArea->dockWidgets());
}
return result;
}
@@ -1413,9 +1408,8 @@ namespace ADS
DockWidget::DockWidgetFeatures DockContainerWidget::features() const
{
DockWidget::DockWidgetFeatures features(DockWidget::AllDockWidgetFeatures);
for (const auto dockArea : d->m_dockAreas) {
for (const auto dockArea : d->m_dockAreas)
features &= dockArea->features();
}
return features;
}
@@ -1428,18 +1422,15 @@ namespace ADS
void DockContainerWidget::closeOtherAreas(DockAreaWidget *keepOpenArea)
{
for (const auto dockArea : d->m_dockAreas) {
if (dockArea == keepOpenArea) {
if (dockArea == keepOpenArea)
continue;
}
if (!dockArea->features(BitwiseAnd).testFlag(DockWidget::DockWidgetClosable)) {
if (!dockArea->features(BitwiseAnd).testFlag(DockWidget::DockWidgetClosable))
continue;
}
// We do not close areas with widgets with custom close handling
if (dockArea->features(BitwiseOr).testFlag(DockWidget::CustomCloseHandling)) {
if (dockArea->features(BitwiseOr).testFlag(DockWidget::CustomCloseHandling))
continue;
}
dockArea->closeArea();
}

View File

@@ -59,10 +59,10 @@ class FloatingDragPreviewPrivate;
/**
* Container that manages a number of dock areas with single dock widgets
* or tabyfied dock widgets in each area.
* or tabified dock widgets in each area.
* Each window that support docking has a DockContainerWidget. That means
* the main application window and all floating windows contain
* a DockContainerWidget.
* the main application window and all floating windows contain a
* DockContainerWidget instance.
*/
class ADS_EXPORT DockContainerWidget : public QFrame
{
@@ -86,13 +86,11 @@ protected:
*/
bool event(QEvent *event) override;
public: // TODO temporary
/**
* Access function for the internal root splitter
*/
QSplitter *rootSplitter() const;
protected:
/**
* Helper function for creation of the root splitter
*/

View File

@@ -0,0 +1,273 @@
/****************************************************************************
**
** Copyright (C) 2020 Uwe Kindler
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or (at your option) any later version.
** The licenses are as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPLv21 included in the packaging
** of this file. Please review the following information to ensure
** the GNU Lesser General Public License version 2.1 requirements
** will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "dockfocuscontroller.h"
#include "dockareawidget.h"
#include "dockareatitlebar.h"
#include "dockcontainerwidget.h"
#include "dockmanager.h"
#include "dockwidget.h"
#include "dockwidgettab.h"
#include "floatingdockcontainer.h"
#ifdef Q_OS_LINUX
#include "linux/floatingwidgettitlebar.h"
#endif
#include <QApplication>
#include <QPointer>
#include <algorithm>
#include <iostream>
namespace ADS
{
/**
* Private data class of CDockFocusController class (pimpl)
*/
class DockFocusControllerPrivate
{
public:
DockFocusController *q;
QPointer<DockWidget> m_focusedDockWidget = nullptr;
QPointer<DockAreaWidget> m_focusedArea = nullptr;
#ifdef Q_OS_LINUX
QPointer<FloatingDockContainer> m_floatingWidget = nullptr;
#endif
DockManager *m_dockManager;
/**
* Private data constructor
*/
DockFocusControllerPrivate(DockFocusController *parent);
/**
* This function updates the focus style of the given dock widget and
* the dock area that it belongs to
*/
void updateDockWidgetFocus(DockWidget *dockWidget);
}; // class DockFocusControllerPrivate
static void updateDockWidgetFocusStyle(DockWidget *dockWidget, bool focused)
{
dockWidget->setProperty("focused", focused);
dockWidget->tabWidget()->setProperty("focused", focused);
dockWidget->tabWidget()->updateStyle();
internal::repolishStyle(dockWidget);
}
static void updateDockAreaFocusStyle(DockAreaWidget *dockArea, bool focused)
{
dockArea->setProperty("focused", focused);
internal::repolishStyle(dockArea);
internal::repolishStyle(dockArea->titleBar());
}
#ifdef Q_OS_LINUX
static void updateFloatingWidgetFocusStyle(FloatingDockContainer *floatingWidget, bool focused)
{
auto titleBar = qobject_cast<FloatingWidgetTitleBar *>(floatingWidget->titleBarWidget());
if (!titleBar)
return;
titleBar->setProperty("focused", focused);
titleBar->updateStyle();
}
#endif
DockFocusControllerPrivate::DockFocusControllerPrivate(DockFocusController *parent)
: q(parent)
{}
void DockFocusControllerPrivate::updateDockWidgetFocus(DockWidget *dockWidget)
{
DockAreaWidget *newFocusedDockArea = nullptr;
if (m_focusedDockWidget)
updateDockWidgetFocusStyle(m_focusedDockWidget, false);
DockWidget *old = m_focusedDockWidget;
m_focusedDockWidget = dockWidget;
updateDockWidgetFocusStyle(m_focusedDockWidget, true);
newFocusedDockArea = m_focusedDockWidget->dockAreaWidget();
if (newFocusedDockArea && (m_focusedArea != newFocusedDockArea))
{
if (m_focusedArea)
{
QObject::disconnect(m_focusedArea, &DockAreaWidget::viewToggled,
q, &DockFocusController::onFocusedDockAreaViewToggled);
updateDockAreaFocusStyle(m_focusedArea, false);
}
m_focusedArea = newFocusedDockArea;
updateDockAreaFocusStyle(m_focusedArea, true);
QObject::connect(m_focusedArea, &DockAreaWidget::viewToggled,
q, &DockFocusController::onFocusedDockAreaViewToggled);
}
auto newFloatingWidget = m_focusedDockWidget->dockContainer()->floatingWidget();
if (newFloatingWidget)
newFloatingWidget->setProperty("FocusedDockWidget", QVariant::fromValue(dockWidget));
#ifdef Q_OS_LINUX
// This code is required for styling the floating widget titlebar for linux
// depending on the current focus state
if (m_floatingWidget == newFloatingWidget)
return;
if (m_floatingWidget)
updateFloatingWidgetFocusStyle(m_floatingWidget, false);
m_floatingWidget = newFloatingWidget;
if (m_floatingWidget)
updateFloatingWidgetFocusStyle(m_floatingWidget, true);
#endif
if (old != dockWidget)
emit m_dockManager->focusedDockWidgetChanged(old, dockWidget);
}
DockFocusController::DockFocusController(DockManager *dockManager)
: QObject(dockManager)
, d(new DockFocusControllerPrivate(this))
{
d->m_dockManager = dockManager;
connect(qApp, &QApplication::focusChanged,
this, &DockFocusController::onApplicationFocusChanged);
connect(d->m_dockManager, &DockManager::stateRestored,
this, &DockFocusController::onStateRestored);
}
DockFocusController::~DockFocusController()
{
delete d;
}
void DockFocusController::onApplicationFocusChanged(QWidget *focusedOld, QWidget *focusedNow)
{
if (d->m_dockManager->isRestoringState())
return;
if (!focusedNow)
return;
DockWidget *dockWidget = nullptr;
auto dockWidgetTab = qobject_cast<DockWidgetTab *>(focusedNow);
if (dockWidgetTab)
dockWidget = dockWidgetTab->dockWidget();
if (!dockWidget)
dockWidget = qobject_cast<DockWidget *>(focusedNow);
if (!dockWidget)
dockWidget = internal::findParent<DockWidget *>(focusedNow);
#ifdef Q_OS_LINUX
if (!dockWidget)
return;
#else
if (!dockWidget || dockWidget->tabWidget()->isHidden())
return;
#endif
d->updateDockWidgetFocus(dockWidget);
}
void DockFocusController::setDockWidgetFocused(DockWidget *focusedNow)
{
d->updateDockWidgetFocus(focusedNow);
}
void DockFocusController::onFocusedDockAreaViewToggled(bool open)
{
if (d->m_dockManager->isRestoringState())
return;
DockAreaWidget* dockArea = qobject_cast<DockAreaWidget *>(sender());
if (!dockArea || open)
return;
auto container = dockArea->dockContainer();
auto openedDockAreas = container->openedDockAreas();
if (openedDockAreas.isEmpty())
return;
DockManager::setWidgetFocus(openedDockAreas[0]->currentDockWidget()->tabWidget());
}
void DockFocusController::notifyWidgetOrAreaRelocation(QWidget *droppedWidget)
{
if (d->m_dockManager->isRestoringState())
return;
DockWidget *dockWidget = qobject_cast<DockWidget *>(droppedWidget);
if (dockWidget)
{
DockManager::setWidgetFocus(dockWidget->tabWidget());
return;
}
DockAreaWidget* dockArea = qobject_cast<DockAreaWidget*>(droppedWidget);
if (!dockArea)
return;
dockWidget = dockArea->currentDockWidget();
DockManager::setWidgetFocus(dockWidget->tabWidget());
}
void DockFocusController::notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget)
{
if (!floatingWidget || d->m_dockManager->isRestoringState())
return;
auto vDockWidget = floatingWidget->property("FocusedDockWidget");
if (!vDockWidget.isValid())
return;
auto dockWidget = vDockWidget.value<DockWidget *>();
if (dockWidget) {
dockWidget->dockAreaWidget()->setCurrentDockWidget(dockWidget);
DockManager::setWidgetFocus(dockWidget->tabWidget());
}
}
void DockFocusController::onStateRestored()
{
if (d->m_focusedDockWidget)
updateDockWidgetFocusStyle(d->m_focusedDockWidget, false);
}
} // namespace ADS

View File

@@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2020 Uwe Kindler
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or (at your option) any later version.
** The licenses are as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPLv21 included in the packaging
** of this file. Please review the following information to ensure
** the GNU Lesser General Public License version 2.1 requirements
** will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "ads_globals.h"
#include "dockmanager.h"
#include <QObject>
namespace ADS {
class DockFocusControllerPrivate;
class DockManager;
class FloatingDockContainer;
/**
* Manages focus styling of dock widgets and handling of focus changes
*/
class ADS_EXPORT DockFocusController : public QObject
{
Q_OBJECT
private:
DockFocusControllerPrivate* d; ///< private data (pimpl)
friend class DockFocusControllerPrivate;
private:
void onApplicationFocusChanged(QWidget *old, QWidget *now);
void onFocusedDockAreaViewToggled(bool open);
void onStateRestored();
public:
/**
* Default Constructor
*/
DockFocusController(DockManager *dockManager);
/**
* Virtual Destructor
*/
~DockFocusController() override;
/**
* Helper function to set focus depending on the configuration of the
* FocusStyling flag
*/
template <class QWidgetPtr>
static void setWidgetFocus(QWidgetPtr widget)
{
if (!DockManager::testConfigFlag(DockManager::FocusHighlighting))
return;
widget->setFocus(Qt::OtherFocusReason);
}
/**
* A container needs to call this function if a widget has been dropped
* into it
*/
void notifyWidgetOrAreaRelocation(QWidget *relocatedWidget);
/**
* This function is called, if a floating widget has been dropped into
* an new position.
* When this function is called, all dock widgets of the FloatingWidget
* are already inserted into its new position
*/
void notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget);
/**
* Request a focus change to the given dock widget
*/
void setDockWidgetFocused(DockWidget *focusedNow);
}; // class DockFocusController
} // namespace ADS

View File

@@ -36,7 +36,9 @@
#include "dockmanager.h"
#include "ads_globals.h"
#include "dockareatitlebar.h"
#include "dockareawidget.h"
#include "dockfocuscontroller.h"
#include "dockingstatereader.h"
#include "dockoverlay.h"
#include "dockwidget.h"
@@ -72,6 +74,15 @@ static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWar
namespace ADS
{
/**
* Internal file version in case the structure changes internally
*/
enum eStateFileVersion {
InitialVersion = 0, //!< InitialVersion
Version1 = 1, //!< Version1
CurrentVersion = Version1 //!< CurrentVersion
};
static DockManager::ConfigFlags g_staticConfigFlags = DockManager::DefaultNonOpaqueConfig;
/**
@@ -88,6 +99,7 @@ namespace ADS
QMap<QString, DockWidget *> m_dockWidgetsMap;
bool m_restoringState = false;
QVector<FloatingDockContainer *> m_uninitializedFloatingWidgets;
DockFocusController *m_focusController = nullptr;
QString m_workspaceName;
bool m_workspaceListDirty = true;
@@ -159,11 +171,10 @@ namespace ADS
} else {
qCInfo(adsLog) << "d->m_containers[i]->restoreState ";
auto container = m_containers[index];
if (container->isFloating()) {
if (container->isFloating())
result = container->floatingWidget()->restoreState(stream, testing);
} else {
else
result = container->restoreState(stream, testing);
}
}
return result;
@@ -190,6 +201,17 @@ namespace ADS
return false;
stateReader.setFileVersion(v);
qCInfo(adsLog) << stateReader.attributes().value("userVersion");
// Older files do not support UserVersion but we still want to load them so
// we first test if the attribute exists
if (!stateReader.attributes().value("userVersion").isEmpty())
{
v = stateReader.attributes().value("userVersion").toInt(&ok);
if (!ok || v != version)
return false;
}
bool result = true;
#ifdef ADS_DEBUG_PRINT
int dockContainers = stateReader.attributes().value("containers").toInt();
@@ -248,9 +270,8 @@ namespace ADS
DockAreaWidget *dockArea = dockContainer->dockArea(i);
QString dockWidgetName = dockArea->property("currentDockWidget").toString();
DockWidget *dockWidget = nullptr;
if (!dockWidgetName.isEmpty()) {
if (!dockWidgetName.isEmpty())
dockWidget = q->findDockWidget(dockWidgetName);
}
if (!dockWidget || dockWidget->isClosed()) {
int index = dockArea->indexOfFirstOpenDockWidget();
@@ -276,9 +297,8 @@ namespace ADS
} else {
for (int i = 0; i < dockContainer->dockAreaCount(); ++i) {
auto dockArea = dockContainer->dockArea(i);
for (auto dockWidget : dockArea->dockWidgets()) {
for (auto dockWidget : dockArea->dockWidgets())
dockWidget->emitTopLevelChanged(false);
}
}
}
}
@@ -326,6 +346,9 @@ namespace ADS
d->m_dockAreaOverlay = new DockOverlay(this, DockOverlay::ModeDockAreaOverlay);
d->m_containerOverlay = new DockOverlay(this, DockOverlay::ModeContainerOverlay);
d->m_containers.append(this);
if (DockManager::configFlags().testFlag(DockManager::FocusHighlighting))
d->m_focusController = new DockFocusController(this);
}
DockManager::~DockManager()
@@ -398,13 +421,12 @@ namespace ADS
DockAreaWidget *DockManager::addDockWidgetTab(DockWidgetArea area, DockWidget *dockWidget)
{
DockAreaWidget *areaWidget = lastAddedDockAreaWidget(area);
if (areaWidget) {
if (areaWidget)
return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, areaWidget);
} else if (!openedDockAreas().isEmpty()) {
else if (!openedDockAreas().isEmpty())
return addDockWidget(area, dockWidget, openedDockAreas().last());
} else {
else
return addDockWidget(area, dockWidget, nullptr);
}
}
DockAreaWidget *DockManager::addDockWidgetTabToArea(DockWidget *dockWidget,
@@ -423,11 +445,11 @@ namespace ADS
dockWidget->setDockManager(this);
FloatingDockContainer *floatingWidget = new FloatingDockContainer(dockWidget);
floatingWidget->resize(dockWidget->size());
if (isVisible()) {
if (isVisible())
floatingWidget->show();
} else {
else
d->m_uninitializedFloatingWidgets.append(floatingWidget);
}
return floatingWidget;
}
@@ -450,9 +472,8 @@ namespace ADS
void DockManager::removeDockContainer(DockContainerWidget *dockContainer)
{
if (this != dockContainer) {
if (this != dockContainer)
d->m_containers.removeAll(dockContainer);
}
}
DockOverlay *DockManager::containerOverlay() const { return d->m_containerOverlay; }
@@ -479,7 +500,8 @@ namespace ADS
stream.setAutoFormatting(configFlags.testFlag(XmlAutoFormattingEnabled));
stream.writeStartDocument();
stream.writeStartElement("QtAdvancedDockingSystem");
stream.writeAttribute("version", QString::number(version));
stream.writeAttribute("version", QString::number(CurrentVersion));
stream.writeAttribute("userVersion", QString::number(version));
stream.writeAttribute("containers", QString::number(d->m_containers.count()));
for (auto container : d->m_containers)
container->saveState(stream);
@@ -512,10 +534,10 @@ namespace ADS
emit restoringState();
bool result = d->restoreState(state, version);
d->m_restoringState = false;
emit stateRestored();
if (!isHidden)
show();
emit stateRestored();
return result;
}
@@ -574,15 +596,14 @@ namespace ADS
emit aboutToSaveWorkspace();
bool result = write(activeWorkspace(), saveState(), parentWidget());
if (result) {
if (result)
d->m_workspaceDateTimes.insert(activeWorkspace(), QDateTime::currentDateTime());
} else {
else
QMessageBox::warning(parentWidget(),
tr("Cannot Save Workspace"),
tr("Could not save workspace to file %1")
.arg(workspaceNameToFilePath(d->m_workspaceName)
.toUserOutput()));
}
return result;
}
@@ -638,9 +659,8 @@ namespace ADS
= workspacePresetsDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt,
QDir::NoFilter,
QDir::Time);
for (const QFileInfo &fileInfo : workspacePresetsFiles) {
for (const QFileInfo &fileInfo : workspacePresetsFiles)
d->m_workspacePresets.insert(fileNameToWorkspaceName(fileInfo.completeBaseName()));
}
}
return d->m_workspacePresets;
}
@@ -819,8 +839,10 @@ namespace ADS
{
if (!cloneWorkspace(original, newName))
return false;
if (original == activeWorkspace())
openWorkspace(newName);
return deleteWorkspace(original);
}
@@ -1002,10 +1024,10 @@ namespace ADS
QFile file(filePath);
if (file.exists()) {
if (!file.copy(workspaceDir.filePath(fileName))) {
if (!file.copy(workspaceDir.filePath(fileName)))
qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg(
filePath, workspaceDir.filePath(fileName), file.errorString());
}
d->m_workspaceListDirty = true;
}
}
@@ -1020,4 +1042,22 @@ namespace ADS
d->m_settings->setValue(Constants::STARTUP_WORKSPACE_SETTINGS_KEY, activeWorkspace());
}
void DockManager::notifyWidgetOrAreaRelocation(QWidget *droppedWidget)
{
if (d->m_focusController)
d->m_focusController->notifyWidgetOrAreaRelocation(droppedWidget);
}
void DockManager::notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget)
{
if (d->m_focusController)
d->m_focusController->notifyFloatingWidgetDrop(floatingWidget);
}
void DockManager::setDockWidgetFocused(DockWidget *dockWidget)
{
if (d->m_focusController)
d->m_focusController->setDockWidgetFocused(dockWidget);
}
} // namespace ADS

View File

@@ -142,6 +142,32 @@ protected:
*/
DockOverlay *dockAreaOverlay() const;
/**
* A container needs to call this function if a widget has been dropped
* into it
*/
void notifyWidgetOrAreaRelocation(QWidget *droppedWidget);
/**
* This function is called, if a floating widget has been dropped into
* an new position.
* When this function is called, all dock widgets of the FloatingWidget
* are already inserted into its new position
*/
void notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget);
/**
* This function is called, if the given DockWidget has been relocated from
* the old container ContainerOld to the new container DockWidget->dockContainer()
*/
void notifyDockWidgetRelocation(DockWidget *dockWidget, DockContainerWidget *containerOld);
/**
* This function is called, if the given DockAreahas been relocated from
* the old container ContainerOld to the new container DockArea->dockContainer()
*/
void notifyDockAreaRelocation(DockAreaWidget *dockArea, DockContainerWidget *containerOld);
/**
* Show the floating widgets that has been created floating
*/
@@ -190,11 +216,18 @@ public:
DockAreaHideDisabledButtons
= 0x10000, //!< If the flag is set disabled dock area buttons will not appear on the tollbar at all (enabling them will bring them back)
DockAreaDynamicTabsMenuButtonVisibility
= 0x20000, //!< If the flag is set dock area will disable a tabs menu button when there is only one tab in the area
= 0x20000, //!< If the flag is set, the tabs menu button will be shown only when it is required - that means, if the tabs are elided. If the tabs are not elided, it is hidden
FloatingContainerHasWidgetTitle
= 0x40000,
= 0x40000, //!< If set, the Floating Widget window title reflects the title of the current dock widget otherwise it displays application name as window title
FloatingContainerHasWidgetIcon
= 0x80000,
= 0x80000, //!< If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays application icon
HideSingleCentralWidgetTitleBar
= 0x100000, //!< If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden
//!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget
FocusHighlighting
= 0x200000, //!< enables styling of focused dock widget tabs or floating widget titlebar
EqualSplitOnInsertion
= 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter
DefaultDockAreaButtons = DockAreaHasCloseButton
| DockAreaHasUndockButton
@@ -267,6 +300,19 @@ public:
*/
static int startDragDistance();
/**
* Helper function to set focus depending on the configuration of the
* FocusStyling flag
*/
template <class QWidgetPtr>
static void setWidgetFocus(QWidgetPtr widget)
{
if (!DockManager::testConfigFlag(DockManager::FocusHighlighting))
return;
widget->setFocus(Qt::OtherFocusReason);
}
/**
* Set the QtCreator settings.
*/
@@ -358,8 +404,12 @@ public:
* If auto formatting is enabled, the output is intended and line wrapped.
* The XmlMode XmlAutoFormattingDisabled is better if you would like to have
* a more compact XML output - i.e. for storage in ini files.
* The version number is stored as part of the data.
* To restore the saved state, pass the return value and version number
* to restoreState().
* \see restoreState()
*/
QByteArray saveState(int version = Version1) const;
QByteArray saveState(int version = 0) const;
/**
* Restores the state of this dockmanagers dockwidgets.
@@ -367,8 +417,9 @@ public:
* not match, the dockmanager's state is left unchanged, and this function
* returns false; otherwise, the state is restored, and this function
* returns true.
* \see saveState()
*/
bool restoreState(const QByteArray &state, int version = Version1);
bool restoreState(const QByteArray &state, int version = 0);
/**
* This function returns true between the restoringState() and
@@ -376,6 +427,13 @@ public:
*/
bool isRestoringState() const;
/**
* Request a focus change to the given dock widget.
* This function only has an effect, if the flag CDockManager::FocusStyling
* is enabled
*/
void setDockWidgetFocused(DockWidget *dockWidget);
signals:
/**
* This signal is emitted if the list of workspaces changed.
@@ -444,6 +502,13 @@ signals:
*/
void dockWidgetRemoved(DockWidget *dockWidget);
/**
* This signal is emitted if the focused dock widget changed.
* Both old and now can be nullptr.
* The focused dock widget is the one that is highlighted in the GUI
*/
void focusedDockWidgetChanged(DockWidget *old, DockWidget *now);
public:
void showWorkspaceMananger();

View File

@@ -36,6 +36,7 @@
#include "dockoverlay.h"
#include "dockareawidget.h"
#include "dockareatitlebar.h"
#include <utils/hostosinfo.h>
@@ -151,12 +152,10 @@ namespace ADS {
*/
qreal dropIndicatiorWidth(QLabel *label) const
{
#ifdef Q_OS_LINUX
Q_UNUSED(label)
return 40;
#else
return static_cast<qreal>(label->fontMetrics().height()) * 3.f;
#endif
if (Utils::HostOsInfo::isLinuxHost())
return 40;
else
return static_cast<qreal>(label->fontMetrics().height()) * 3.f;
}
QWidget *createDropIndicatorWidget(DockWidgetArea dockWidgetArea, DockOverlay::eMode mode)
@@ -190,10 +189,10 @@ namespace ADS {
DockWidgetArea dockWidgetArea,
DockOverlay::eMode mode)
{
QColor borderColor = iconColor(DockOverlayCross::FrameColor);
QColor backgroundColor = iconColor(DockOverlayCross::WindowBackgroundColor);
double devicePixelRatio = q->window()->devicePixelRatioF();
QSizeF pixmapSize = size * devicePixelRatio;
const QColor borderColor = iconColor(DockOverlayCross::FrameColor);
const QColor backgroundColor = iconColor(DockOverlayCross::WindowBackgroundColor);
const double devicePixelRatio = q->window()->devicePixelRatioF();
const QSizeF pixmapSize = size * devicePixelRatio;
QPixmap pixmap(pixmapSize.toSize());
pixmap.fill(QColor(0, 0, 0, 0));
@@ -259,7 +258,7 @@ namespace ADS {
break;
}
QSizeF baseSize = baseRect.size();
const QSizeF baseSize = baseRect.size();
if (DockOverlay::ModeContainerOverlay == mode && dockWidgetArea != CenterDockWidgetArea) {
baseRect = areaRect;
}
@@ -296,7 +295,7 @@ namespace ADS {
// draw window title bar
painter.setBrush(borderColor);
QRectF frameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10));
const QRectF frameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10));
painter.drawRect(frameRect);
painter.restore();
@@ -370,6 +369,7 @@ namespace ADS {
{
if (areas == d->m_allowedAreas)
return;
d->m_allowedAreas = areas;
d->m_cross->reset();
}
@@ -382,19 +382,17 @@ namespace ADS {
DockWidgetArea DockOverlay::dropAreaUnderCursor() const
{
DockWidgetArea result = d->m_cross->cursorLocation();
if (result != InvalidDockWidgetArea) {
if (result != InvalidDockWidgetArea)
return result;
}
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(d->m_targetWidget.data());
if (!dockArea) {
if (!dockArea)
return result;
}
if (dockArea->allowedAreas().testFlag(CenterDockWidgetArea)
&& dockArea->titleBarGeometry().contains(dockArea->mapFromGlobal(QCursor::pos()))) {
&& !dockArea->titleBar()->isHidden()
&& dockArea->titleBarGeometry().contains(dockArea->mapFromGlobal(QCursor::pos())))
return CenterDockWidgetArea;
}
return result;
}
@@ -518,9 +516,9 @@ namespace ADS {
bool DockOverlay::event(QEvent *event)
{
bool result = Super::event(event);
if (event->type() == QEvent::Polish) {
if (event->type() == QEvent::Polish)
d->m_cross->setupOverlayCross(d->m_mode);
}
return result;
}
@@ -622,13 +620,12 @@ namespace ADS {
void DockOverlayCross::updateOverlayIcons()
{
if (windowHandle()->devicePixelRatio() == d->m_lastDevicePixelRatio) { // TODO
if (windowHandle()->devicePixelRatio() == d->m_lastDevicePixelRatio) // TODO
return;
}
for (auto Widget : d->m_dropIndicatorWidgets) {
d->updateDropIndicatorIcon(Widget);
}
for (auto widget : d->m_dropIndicatorWidgets)
d->updateDropIndicatorIcon(widget);
d->m_lastDevicePixelRatio = devicePixelRatioF();
}
@@ -661,7 +658,7 @@ namespace ADS {
for (constIt = areas.begin(); constIt != areas.end(); ++constIt) {
const DockWidgetArea area = constIt.key();
QWidget *widget = constIt.value();
QPoint position = d->areaGridPosition(area);
const QPoint position = d->areaGridPosition(area);
d->m_gridLayout->addWidget(widget,
position.x(),
position.y(),
@@ -717,9 +714,9 @@ namespace ADS {
void DockOverlayCross::showEvent(QShowEvent *)
{
if (d->m_updateRequired) {
if (d->m_updateRequired)
setupOverlayCross(d->m_mode);
}
this->updatePosition();
}
@@ -744,12 +741,11 @@ namespace ADS {
// Update visibility of area widgets based on allowedAreas.
for (auto area : allAreas) {
QPoint position = d->areaGridPosition(area);
const QPoint position = d->areaGridPosition(area);
QLayoutItem *item = d->m_gridLayout->itemAtPosition(position.x(), position.y());
QWidget *widget = nullptr;
if (item && (widget = item->widget()) != nullptr) {
if (item && (widget = item->widget()) != nullptr)
widget->setVisible(allowedAreas.testFlag(area));
}
}
}
@@ -766,9 +762,9 @@ namespace ADS {
for (const auto &colorListEntry : colorList) {
auto componentColor = colorListEntry.split('=', QString::SkipEmptyParts);
int component = colorCompenentStringMap.value(componentColor[0], -1);
if (component < 0) {
if (component < 0)
continue;
}
d->m_iconColors[component] = QColor(componentColor[1]);
}

View File

@@ -55,6 +55,7 @@
#include <QTextStream>
#include <QToolBar>
#include <QXmlStreamWriter>
#include <QWindow>
static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg)
@@ -127,6 +128,7 @@ namespace ADS
if (!m_dockArea) {
FloatingDockContainer *floatingWidget = new FloatingDockContainer(q);
floatingWidget->resize(q->size());
m_tabWidget->show();
floatingWidget->show();
} else {
m_dockArea->setCurrentDockWidget(q);
@@ -204,6 +206,9 @@ namespace ADS
d->m_toggleViewAction->setCheckable(true);
connect(d->m_toggleViewAction, &QAction::triggered, this, &DockWidget::toggleView);
setToolbarFloatingStyle(false);
if (DockManager::testConfigFlag(DockManager::FocusHighlighting))
setFocusPolicy(Qt::ClickFocus);
}
DockWidget::~DockWidget()
@@ -222,7 +227,10 @@ namespace ADS
void DockWidget::setWidget(QWidget *widget, eInsertMode insertMode)
{
QScrollArea *scrollAreaWidget = qobject_cast<QScrollArea *>(widget);
if (d->m_widget)
takeWidget();
auto scrollAreaWidget = qobject_cast<QAbstractScrollArea *>(widget);
if (scrollAreaWidget || ForceNoScrollArea == insertMode) {
d->m_layout->addWidget(widget);
if (scrollAreaWidget && scrollAreaWidget->viewport())
@@ -238,11 +246,23 @@ namespace ADS
QWidget *DockWidget::takeWidget()
{
// TODO Shouldn't m_widget being set to nullptr?!
d->m_scrollArea->takeWidget();
d->m_layout->removeWidget(d->m_widget);
d->m_widget->setParent(nullptr);
return d->m_widget;
QWidget *w = nullptr;
if (d->m_scrollArea) {
d->m_layout->removeWidget(d->m_scrollArea);
w = d->m_scrollArea->takeWidget();
delete d->m_scrollArea;
d->m_scrollArea = nullptr;
d->m_widget = nullptr;
} else if (d->m_widget) {
d->m_layout->removeWidget(d->m_widget);
w = d->m_widget;
d->m_widget = nullptr;
}
if (w)
w->setParent(nullptr);
return w;
}
QWidget *DockWidget::widget() const { return d->m_widget; }
@@ -251,9 +271,9 @@ namespace ADS
void DockWidget::setFeatures(DockWidgetFeatures features)
{
if (d->m_features == features) {
if (d->m_features == features)
return;
}
d->m_features = features;
emit featuresChanged(d->m_features);
d->m_tabWidget->onDockWidgetFeaturesChanged();
@@ -274,11 +294,10 @@ namespace ADS
DockContainerWidget *DockWidget::dockContainer() const
{
if (d->m_dockArea) {
if (d->m_dockArea)
return d->m_dockArea->dockContainer();
} else {
else
return nullptr;
}
}
DockAreaWidget *DockWidget::dockAreaWidget() const { return d->m_dockArea; }
@@ -347,11 +366,11 @@ namespace ADS
? beforeDockContainerWidget->topLevelDockWidget()
: nullptr;
if (open) {
if (open)
d->showDockWidget();
} else {
else
d->hideDockWidget();
}
d->m_closed = !open;
//d->m_toggleViewAction->blockSignals(true);
d->m_toggleViewAction->setChecked(open);
@@ -449,7 +468,7 @@ namespace ADS
d->m_toggleViewAction->setToolTip(text);
if (d->m_dockArea)
d->m_dockArea->markTitleBarMenuOutdated(); //update tabs menu
d->m_dockArea->markTitleBarMenuOutdated(); // update tabs menu
}
#endif
@@ -617,4 +636,58 @@ namespace ADS
return d->m_titleBarActions;
}
void DockWidget::showFullScreen()
{
if (isFloating())
dockContainer()->floatingWidget()->showFullScreen();
else
Super::showFullScreen();
}
void DockWidget::showNormal()
{
if (isFloating())
dockContainer()->floatingWidget()->showNormal();
else
Super::showNormal();
}
bool DockWidget::isFullScreen() const
{
if (isFloating())
return dockContainer()->floatingWidget()->isFullScreen();
else
return Super::isFullScreen();
}
void DockWidget::setAsCurrentTab()
{
if (d->m_dockArea && !isClosed())
d->m_dockArea->setCurrentDockWidget(this);
}
bool DockWidget::isTabbed() const
{
return d->m_dockArea && (d->m_dockArea->openDockWidgetsCount() > 1);
}
bool DockWidget::isCurrentTab() const
{
return d->m_dockArea && (d->m_dockArea->currentDockWidget() == this);
}
void DockWidget::raise()
{
if (isClosed())
return;
setAsCurrentTab();
if (isInFloatingContainer())
{
auto floatingWindow = window();
floatingWindow->raise();
floatingWindow->activateWindow();
}
}
} // namespace ADS

View File

@@ -152,8 +152,8 @@ public:
using Super = QFrame;
enum DockWidgetFeature {
DockWidgetClosable = 0x01,
DockWidgetMovable = 0x02,///< this feature is not properly implemented yet and is ignored
DockWidgetClosable = 0x01,///< dock widget has a close button
DockWidgetMovable = 0x02,///< dock widget is movable and can be moved to a new position in the current dock container
DockWidgetFloatable = 0x04,
DockWidgetDeleteOnClose = 0x08, ///< deletes the dock widget when it is closed
CustomCloseHandling = 0x10,
@@ -435,6 +435,26 @@ public:
void setTabToolTip(const QString &text);
#endif
/**
* Returns true if the dock widget is floating and if the floating dock
* container is full screen
*/
bool isFullScreen() const;
/**
* Returns true if this dock widget is in a dock area, that contains at
* least 2 opened dock widgets
*/
bool isTabbed() const;
/**
* Returns true if this dock widget is the current one in the dock
* area widget that contains it.
* If the dock widget is the only opened dock widget in a dock area,
* the true is returned
*/
bool isCurrentTab() const;
public: // reimplements QFrame
/**
* Emits titleChanged signal if title change event occurs
@@ -447,6 +467,23 @@ public: // reimplements QFrame
*/
void toggleView(bool open = true);
/**
* Makes this dock widget the current tab in its dock area.
* The function only has an effect, if the dock widget is open. A call
* to this function will not toggle the view, so if it is closed,
* nothing will happen
*/
void setAsCurrentTab();
/**
* Brings the dock widget to the front
* This means:
* - If the dock widget is tabbed with other dock widgets but its tab is not current, it's made current.
* - If the dock widget is floating, QWindow::raise() is called.
* This only applies if the dock widget is already open. If closed, does nothing.
*/
void raise();
/**
* This function will make a docked widget floating
*/
@@ -463,6 +500,26 @@ public: // reimplements QFrame
*/
void closeDockWidget();
/**
* Shows the widget in full-screen mode.
* Normally this function only affects windows. To make the interface
* compatible to QDockWidget, this function also maximizes a floating
* dock widget.
*
* \note Full-screen mode works fine under Windows, but has certain
* problems (doe not work) under X (Linux). These problems are due to
* limitations of the ICCCM protocol that specifies the communication
* between X11 clients and the window manager. ICCCM simply does not
* understand the concept of non-decorated full-screen windows.
*/
void showFullScreen();
/**
* This function complements showFullScreen() to restore the widget
* after it has been in full screen mode.
*/
void showNormal();
signals:
/**
* This signal is emitted if the dock widget is opened or closed

View File

@@ -116,7 +116,7 @@ namespace ADS
*/
bool testConfigFlag(DockManager::eConfigFlag flag) const
{
return DockManager::configFlags().testFlag(flag);
return DockManager::testConfigFlag(flag);
}
/**
@@ -232,18 +232,20 @@ namespace ADS
qCInfo(adsLog) << "startFloating";
m_dragState = draggingState;
QSize size = m_dockArea->size();
AbstractFloatingWidget *floatingWidget = nullptr;
bool opaqueUndocking = DockManager::configFlags().testFlag(DockManager::OpaqueUndocking)
bool opaqueUndocking = DockManager::testConfigFlag(DockManager::OpaqueUndocking)
|| (DraggingFloatingWidget != draggingState);
// If section widget has multiple tabs, we take only one tab
// If it has only one single tab, we can move the complete
// dock area into floating widget
QSize size;
if (m_dockArea->dockWidgetsCount() > 1) {
floatingWidget = createFloatingWidget(m_dockWidget, opaqueUndocking);
size = m_dockWidget->size();
} else {
floatingWidget = createFloatingWidget(m_dockArea, opaqueUndocking);
size = m_dockArea->size();
}
if (DraggingFloatingWidget == draggingState) {
@@ -265,6 +267,8 @@ namespace ADS
setAttribute(Qt::WA_NoMousePropagation, true);
d->m_dockWidget = dockWidget;
d->createLayout();
if (DockManager::testConfigFlag(DockManager::FocusHighlighting))
setFocusPolicy(Qt::ClickFocus);
}
DockWidgetTab::~DockWidgetTab()
@@ -358,9 +362,9 @@ namespace ADS
// If we undock, we need to restore the initial position of this
// tab because it looks strange if it remains on its dragged position
if (d->isDraggingState(DraggingTab)
&& !DockManager::configFlags().testFlag(DockManager::OpaqueUndocking)) {
&& !DockManager::testConfigFlag(DockManager::OpaqueUndocking))
parentWidget()->layout()->update();
}
d->startFloating();
}
return;
@@ -370,9 +374,9 @@ namespace ADS
{
// If we start dragging the tab, we save its initial position to
// restore it later
if (DraggingTab != d->m_dragState) {
if (DraggingTab != d->m_dragState)
d->m_tabDragStartPosition = this->pos();
}
d->m_dragState = DraggingTab;
return;
}
@@ -383,9 +387,8 @@ namespace ADS
void DockWidgetTab::contextMenuEvent(QContextMenuEvent *event)
{
event->accept();
if (d->isDraggingState(DraggingFloatingWidget)) {
if (d->isDraggingState(DraggingFloatingWidget))
return;
}
d->saveDragStartMousePosition(event->globalPos());
QMenu menu(this);
@@ -413,16 +416,27 @@ namespace ADS
bool allTabsHaveCloseButton = d->testConfigFlag(DockManager::AllTabsHaveCloseButton);
bool tabHasCloseButton = (activeTabHasCloseButton && active) | allTabsHaveCloseButton;
d->m_closeButton->setVisible(dockWidgetClosable && tabHasCloseButton);
if (d->m_isActiveTab == active) {
// Focus related stuff
if (DockManager::testConfigFlag(DockManager::FocusHighlighting)
&& !d->m_dockWidget->dockManager()->isRestoringState()) {
bool updateFocusStyle = false;
if (active && !hasFocus()) {
setFocus(Qt::OtherFocusReason);
updateFocusStyle = true;
}
if (d->m_isActiveTab == active) {
if (updateFocusStyle)
updateStyle();
return;
}
} else if (d->m_isActiveTab == active) {
return;
}
d->m_isActiveTab = active;
style()->unpolish(this);
style()->polish(this);
d->m_titleLabel->style()->unpolish(d->m_titleLabel);
d->m_titleLabel->style()->polish(d->m_titleLabel);
updateStyle();
update();
updateGeometry();
@@ -438,9 +452,8 @@ namespace ADS
void DockWidgetTab::setIcon(const QIcon &icon)
{
QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(layout());
if (!d->m_iconLabel && icon.isNull()) {
if (!d->m_iconLabel && icon.isNull())
return;
}
if (!d->m_iconLabel) {
d->m_iconLabel = new QLabel();
@@ -499,9 +512,9 @@ namespace ADS
void DockWidgetTab::detachDockWidget()
{
if (!d->m_dockWidget->features().testFlag(DockWidget::DockWidgetFloatable)) {
if (!d->m_dockWidget->features().testFlag(DockWidget::DockWidgetFloatable))
return;
}
d->saveDragStartMousePosition(QCursor::pos());
d->startFloating(DraggingInactive);
}
@@ -527,4 +540,14 @@ namespace ADS
d->m_closeButton->setSizePolicy(sizePolicy);
}
void DockWidgetTab::setElideMode(Qt::TextElideMode mode)
{
d->m_titleLabel->setElideMode(mode);
}
void DockWidgetTab::updateStyle()
{
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
} // namespace ADS

View File

@@ -59,6 +59,7 @@ private:
DockWidgetTabPrivate *d; ///< private data (pimpl)
friend class DockWidgetTabPrivate;
friend class DockWidget;
friend class DockManager;
void onDockWidgetFeaturesChanged();
void detachDockWidget();
@@ -150,6 +151,16 @@ public:
*/
bool event(QEvent *event) override;
/**
* Sets the text elide mode
*/
void setElideMode(Qt::TextElideMode mode);
/**
* Update stylesheet style if a property changes
*/
void updateStyle();
void setVisible(bool visible) override;
signals:

View File

@@ -115,9 +115,8 @@ namespace ADS {
void ElidingLabel::mouseReleaseEvent(QMouseEvent *event)
{
Super::mouseReleaseEvent(event);
if (event->button() != Qt::LeftButton) {
if (event->button() != Qt::LeftButton)
return;
}
emit clicked();
}
@@ -131,17 +130,17 @@ namespace ADS {
void ElidingLabel::resizeEvent(QResizeEvent *event)
{
if (!d->isModeElideNone()) {
if (!d->isModeElideNone())
d->elideText(event->size().width());
}
Super::resizeEvent(event);
}
QSize ElidingLabel::minimumSizeHint() const
{
if (pixmap() != nullptr || d->isModeElideNone()) {
if (pixmap() != nullptr || d->isModeElideNone())
return QLabel::minimumSizeHint();
}
const QFontMetrics &fm = fontMetrics();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
QSize size(fm.horizontalAdvance(d->m_text.left(2) + ""), fm.height());
@@ -153,9 +152,9 @@ namespace ADS {
QSize ElidingLabel::sizeHint() const
{
if (pixmap() != nullptr || d->isModeElideNone()) {
if (pixmap() != nullptr || d->isModeElideNone())
return QLabel::sizeHint();
}
const QFontMetrics &fm = fontMetrics();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
QSize size(fm.horizontalAdvance(d->m_text), QLabel::sizeHint().height());
@@ -167,10 +166,10 @@ namespace ADS {
void ElidingLabel::setText(const QString &text)
{
d->m_text = text;
if (d->isModeElideNone()) {
Super::setText(text);
} else {
d->m_text = text;
internal::setToolTip(this, text);
d->elideText(this->size().width());
}

View File

@@ -41,6 +41,12 @@
#include "dockoverlay.h"
#include "dockwidget.h"
#include "linux/floatingwidgettitlebar.h"
#ifdef Q_OS_WIN
#include <windows.h>
#ifdef _MSC_VER
#pragma comment(lib, "User32.lib")
#endif
#endif
#include <QAbstractButton>
#include <QAction>
@@ -56,6 +62,303 @@ static Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWar
namespace ADS
{
#ifdef Q_OS_WIN
#if 0 // set to 1 if you need this function for debugging
/**
* Just for debugging to convert windows message identifiers to strings
*/
static const char* windowsMessageString(int messageId)
{
switch (messageId)
{
case 0: return "WM_NULL";
case 1: return "WM_CREATE";
case 2: return "WM_DESTROY";
case 3: return "WM_MOVE";
case 5: return "WM_SIZE";
case 6: return "WM_ACTIVATE";
case 7: return "WM_SETFOCUS";
case 8: return "WM_KILLFOCUS";
case 10: return "WM_ENABLE";
case 11: return "WM_SETREDRAW";
case 12: return "WM_SETTEXT";
case 13: return "WM_GETTEXT";
case 14: return "WM_GETTEXTLENGTH";
case 15: return "WM_PAINT";
case 16: return "WM_CLOSE";
case 17: return "WM_QUERYENDSESSION";
case 18: return "WM_QUIT";
case 19: return "WM_QUERYOPEN";
case 20: return "WM_ERASEBKGND";
case 21: return "WM_SYSCOLORCHANGE";
case 22: return "WM_ENDSESSION";
case 24: return "WM_SHOWWINDOW";
case 25: return "WM_CTLCOLOR";
case 26: return "WM_WININICHANGE";
case 27: return "WM_DEVMODECHANGE";
case 28: return "WM_ACTIVATEAPP";
case 29: return "WM_FONTCHANGE";
case 30: return "WM_TIMECHANGE";
case 31: return "WM_CANCELMODE";
case 32: return "WM_SETCURSOR";
case 33: return "WM_MOUSEACTIVATE";
case 34: return "WM_CHILDACTIVATE";
case 35: return "WM_QUEUESYNC";
case 36: return "WM_GETMINMAXINFO";
case 38: return "WM_PAINTICON";
case 39: return "WM_ICONERASEBKGND";
case 40: return "WM_NEXTDLGCTL";
case 42: return "WM_SPOOLERSTATUS";
case 43: return "WM_DRAWITEM";
case 44: return "WM_MEASUREITEM";
case 45: return "WM_DELETEITEM";
case 46: return "WM_VKEYTOITEM";
case 47: return "WM_CHARTOITEM";
case 48: return "WM_SETFONT";
case 49: return "WM_GETFONT";
case 50: return "WM_SETHOTKEY";
case 51: return "WM_GETHOTKEY";
case 55: return "WM_QUERYDRAGICON";
case 57: return "WM_COMPAREITEM";
case 61: return "WM_GETOBJECT";
case 65: return "WM_COMPACTING";
case 68: return "WM_COMMNOTIFY";
case 70: return "WM_WINDOWPOSCHANGING";
case 71: return "WM_WINDOWPOSCHANGED";
case 72: return "WM_POWER";
case 73: return "WM_COPYGLOBALDATA";
case 74: return "WM_COPYDATA";
case 75: return "WM_CANCELJOURNAL";
case 78: return "WM_NOTIFY";
case 80: return "WM_INPUTLANGCHANGEREQUEST";
case 81: return "WM_INPUTLANGCHANGE";
case 82: return "WM_TCARD";
case 83: return "WM_HELP";
case 84: return "WM_USERCHANGED";
case 85: return "WM_NOTIFYFORMAT";
case 123: return "WM_CONTEXTMENU";
case 124: return "WM_STYLECHANGING";
case 125: return "WM_STYLECHANGED";
case 126: return "WM_DISPLAYCHANGE";
case 127: return "WM_GETICON";
case 128: return "WM_SETICON";
case 129: return "WM_NCCREATE";
case 130: return "WM_NCDESTROY";
case 131: return "WM_NCCALCSIZE";
case 132: return "WM_NCHITTEST";
case 133: return "WM_NCPAINT";
case 134: return "WM_NCACTIVATE";
case 135: return "WM_GETDLGCODE";
case 136: return "WM_SYNCPAINT";
case 160: return "WM_NCMOUSEMOVE";
case 161: return "WM_NCLBUTTONDOWN";
case 162: return "WM_NCLBUTTONUP";
case 163: return "WM_NCLBUTTONDBLCLK";
case 164: return "WM_NCRBUTTONDOWN";
case 165: return "WM_NCRBUTTONUP";
case 166: return "WM_NCRBUTTONDBLCLK";
case 167: return "WM_NCMBUTTONDOWN";
case 168: return "WM_NCMBUTTONUP";
case 169: return "WM_NCMBUTTONDBLCLK";
case 171: return "WM_NCXBUTTONDOWN";
case 172: return "WM_NCXBUTTONUP";
case 173: return "WM_NCXBUTTONDBLCLK";
case 176: return "EM_GETSEL";
case 177: return "EM_SETSEL";
case 178: return "EM_GETRECT";
case 179: return "EM_SETRECT";
case 180: return "EM_SETRECTNP";
case 181: return "EM_SCROLL";
case 182: return "EM_LINESCROLL";
case 183: return "EM_SCROLLCARET";
case 185: return "EM_GETMODIFY";
case 187: return "EM_SETMODIFY";
case 188: return "EM_GETLINECOUNT";
case 189: return "EM_LINEINDEX";
case 190: return "EM_SETHANDLE";
case 191: return "EM_GETHANDLE";
case 192: return "EM_GETTHUMB";
case 193: return "EM_LINELENGTH";
case 194: return "EM_REPLACESEL";
case 195: return "EM_SETFONT";
case 196: return "EM_GETLINE";
case 197: return "EM_LIMITTEXT / EM_SETLIMITTEXT";
case 198: return "EM_CANUNDO";
case 199: return "EM_UNDO";
case 200: return "EM_FMTLINES";
case 201: return "EM_LINEFROMCHAR";
case 202: return "EM_SETWORDBREAK";
case 203: return "EM_SETTABSTOPS";
case 204: return "EM_SETPASSWORDCHAR";
case 205: return "EM_EMPTYUNDOBUFFER";
case 206: return "EM_GETFIRSTVISIBLELINE";
case 207: return "EM_SETREADONLY";
case 209: return "EM_SETWORDBREAKPROC / EM_GETWORDBREAKPROC";
case 210: return "EM_GETPASSWORDCHAR";
case 211: return "EM_SETMARGINS";
case 212: return "EM_GETMARGINS";
case 213: return "EM_GETLIMITTEXT";
case 214: return "EM_POSFROMCHAR";
case 215: return "EM_CHARFROMPOS";
case 216: return "EM_SETIMESTATUS";
case 217: return "EM_GETIMESTATUS";
case 224: return "SBM_SETPOS";
case 225: return "SBM_GETPOS";
case 226: return "SBM_SETRANGE";
case 227: return "SBM_GETRANGE";
case 228: return "SBM_ENABLE_ARROWS";
case 230: return "SBM_SETRANGEREDRAW";
case 233: return "SBM_SETSCROLLINFO";
case 234: return "SBM_GETSCROLLINFO";
case 235: return "SBM_GETSCROLLBARINFO";
case 240: return "BM_GETCHECK";
case 241: return "BM_SETCHECK";
case 242: return "BM_GETSTATE";
case 243: return "BM_SETSTATE";
case 244: return "BM_SETSTYLE";
case 245: return "BM_CLICK";
case 246: return "BM_GETIMAGE";
case 247: return "BM_SETIMAGE";
case 248: return "BM_SETDONTCLICK";
case 255: return "WM_INPUT";
case 256: return "WM_KEYDOWN";
case 257: return "WM_KEYUP";
case 258: return "WM_CHAR";
case 259: return "WM_DEADCHAR";
case 260: return "WM_SYSKEYDOWN";
case 261: return "WM_SYSKEYUP";
case 262: return "WM_SYSCHAR";
case 263: return "WM_SYSDEADCHAR";
case 265: return "WM_UNICHAR / WM_WNT_CONVERTREQUESTEX";
case 266: return "WM_CONVERTREQUEST";
case 267: return "WM_CONVERTRESULT";
case 268: return "WM_INTERIM";
case 269: return "WM_IME_STARTCOMPOSITION";
case 270: return "WM_IME_ENDCOMPOSITION";
case 272: return "WM_INITDIALOG";
case 273: return "WM_COMMAND";
case 274: return "WM_SYSCOMMAND";
case 275: return "WM_TIMER";
case 276: return "WM_HSCROLL";
case 277: return "WM_VSCROLL";
case 278: return "WM_INITMENU";
case 279: return "WM_INITMENUPOPUP";
case 280: return "WM_SYSTIMER";
case 287: return "WM_MENUSELECT";
case 288: return "WM_MENUCHAR";
case 289: return "WM_ENTERIDLE";
case 290: return "WM_MENURBUTTONUP";
case 291: return "WM_MENUDRAG";
case 292: return "WM_MENUGETOBJECT";
case 293: return "WM_UNINITMENUPOPUP";
case 294: return "WM_MENUCOMMAND";
case 295: return "WM_CHANGEUISTATE";
case 296: return "WM_UPDATEUISTATE";
case 297: return "WM_QUERYUISTATE";
case 306: return "WM_CTLCOLORMSGBOX";
case 307: return "WM_CTLCOLOREDIT";
case 308: return "WM_CTLCOLORLISTBOX";
case 309: return "WM_CTLCOLORBTN";
case 310: return "WM_CTLCOLORDLG";
case 311: return "WM_CTLCOLORSCROLLBAR";
case 312: return "WM_CTLCOLORSTATIC";
case 512: return "WM_MOUSEMOVE";
case 513: return "WM_LBUTTONDOWN";
case 514: return "WM_LBUTTONUP";
case 515: return "WM_LBUTTONDBLCLK";
case 516: return "WM_RBUTTONDOWN";
case 517: return "WM_RBUTTONUP";
case 518: return "WM_RBUTTONDBLCLK";
case 519: return "WM_MBUTTONDOWN";
case 520: return "WM_MBUTTONUP";
case 521: return "WM_MBUTTONDBLCLK";
case 522: return "WM_MOUSEWHEEL";
case 523: return "WM_XBUTTONDOWN";
case 524: return "WM_XBUTTONUP";
case 525: return "WM_XBUTTONDBLCLK";
case 528: return "WM_PARENTNOTIFY";
case 529: return "WM_ENTERMENULOOP";
case 530: return "WM_EXITMENULOOP";
case 531: return "WM_NEXTMENU";
case 532: return "WM_SIZING";
case 533: return "WM_CAPTURECHANGED";
case 534: return "WM_MOVING";
case 536: return "WM_POWERBROADCAST";
case 537: return "WM_DEVICECHANGE";
case 544: return "WM_MDICREATE";
case 545: return "WM_MDIDESTROY";
case 546: return "WM_MDIACTIVATE";
case 547: return "WM_MDIRESTORE";
case 548: return "WM_MDINEXT";
case 549: return "WM_MDIMAXIMIZE";
case 550: return "WM_MDITILE";
case 551: return "WM_MDICASCADE";
case 552: return "WM_MDIICONARRANGE";
case 553: return "WM_MDIGETACTIVE";
case 560: return "WM_MDISETMENU";
case 561: return "WM_ENTERSIZEMOVE";
case 562: return "WM_EXITSIZEMOVE";
case 563: return "WM_DROPFILES";
case 564: return "WM_MDIREFRESHMENU";
case 640: return "WM_IME_REPORT";
case 641: return "WM_IME_SETCONTEXT";
case 642: return "WM_IME_NOTIFY";
case 643: return "WM_IME_CONTROL";
case 644: return "WM_IME_COMPOSITIONFULL";
case 645: return "WM_IME_SELECT";
case 646: return "WM_IME_CHAR";
case 648: return "WM_IME_REQUEST";
case 656: return "WM_IME_KEYDOWN";
case 657: return "WM_IME_KEYUP";
case 672: return "WM_NCMOUSEHOVER";
case 673: return "WM_MOUSEHOVER";
case 674: return "WM_NCMOUSELEAVE";
case 675: return "WM_MOUSELEAVE";
case 768: return "WM_CUT";
case 769: return "WM_COPY";
case 770: return "WM_PASTE";
case 771: return "WM_CLEAR";
case 772: return "WM_UNDO";
case 773: return "WM_RENDERFORMAT";
case 774: return "WM_RENDERALLFORMATS";
case 775: return "WM_DESTROYCLIPBOARD";
case 776: return "WM_DRAWCLIPBOARD";
case 777: return "WM_PAINTCLIPBOARD";
case 778: return "WM_VSCROLLCLIPBOARD";
case 779: return "WM_SIZECLIPBOARD";
case 780: return "WM_ASKCBFORMATNAME";
case 781: return "WM_CHANGECBCHAIN";
case 782: return "WM_HSCROLLCLIPBOARD";
case 783: return "WM_QUERYNEWPALETTE";
case 784: return "WM_PALETTEISCHANGING";
case 785: return "WM_PALETTECHANGED";
case 786: return "WM_HOTKEY";
case 791: return "WM_PRINT";
case 792: return "WM_PRINTCLIENT";
case 793: return "WM_APPCOMMAND";
case 856: return "WM_HANDHELDFIRST";
case 863: return "WM_HANDHELDLAST";
case 864: return "WM_AFXFIRST";
case 895: return "WM_AFXLAST";
case 896: return "WM_PENWINFIRST";
case 897: return "WM_RCRESULT";
case 898: return "WM_HOOKRCRESULT";
case 899: return "WM_GLOBALRCCHANGE / WM_PENMISCINFO";
case 900: return "WM_SKB";
case 901: return "WM_HEDITCTL / WM_PENCTL";
case 902: return "WM_PENMISC";
case 903: return "WM_CTLINIT";
case 904: return "WM_PENEVENT";
case 911: return "WM_PENWINLAST";
default:
return "unknown WM_ message";
}
return "unknown WM_ message";
}
#endif
#endif
AbstractFloatingWidget::~AbstractFloatingWidget() = default;
static unsigned int zOrderCounter = 0;
@@ -74,8 +377,9 @@ namespace ADS
DockContainerWidget *m_dropContainer = nullptr;
DockAreaWidget *m_singleDockArea = nullptr;
QPoint m_dragStartPos;
QWidget *m_mouseEventHandler = nullptr;
FloatingWidgetTitleBar *m_titleBar = nullptr;
bool m_hiding = false;
QWidget *m_mouseEventHandler = nullptr; // linux only
FloatingWidgetTitleBar *m_titleBar = nullptr; // linux only
/**
* Private data constructor
@@ -90,7 +394,7 @@ namespace ADS
*/
static bool testConfigFlag(DockManager::eConfigFlag flag)
{
return DockManager::configFlags().testFlag(flag);
return DockManager::testConfigFlag(flag);
}
/**
@@ -146,11 +450,11 @@ namespace ADS
if (m_dockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
|| m_dockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea) {
// Resize the floating widget to the size of the highlighted drop area rectangle
DockOverlay *overlay = m_dockManager->containerOverlay();
if (!overlay->dropOverlayRect().isValid())
overlay = m_dockManager->dockAreaOverlay();
// Resize the floating widget to the size of the highlighted drop area rectangle
QRect rect = overlay->dropOverlayRect();
int frameWidth = (q->frameSize().width() - q->rect().width()) / 2;
int titleBarHeight = q->frameSize().height() - q->rect().height() - frameWidth;
@@ -246,7 +550,7 @@ namespace ADS
this,
&FloatingDockContainer::onDockAreasAddedOrRemoved);
#ifdef Q_OS_LINUX
#ifdef Q_OS_LINUX
d->m_titleBar = new FloatingWidgetTitleBar(this);
setWindowFlags(windowFlags() | Qt::Tool);
QDockWidget::setWidget(d->m_dockContainer);
@@ -257,14 +561,14 @@ namespace ADS
&FloatingWidgetTitleBar::closeRequested,
this,
&FloatingDockContainer::close);
#else
#else
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
QBoxLayout *boxLayout = new QBoxLayout(QBoxLayout::TopToBottom);
boxLayout->setContentsMargins(0, 0, 0, 0);
boxLayout->setSpacing(0);
setLayout(boxLayout);
boxLayout->addWidget(d->m_dockContainer);
#endif
#endif
dockManager->registerFloatingWidget(this);
}
@@ -272,24 +576,26 @@ namespace ADS
: FloatingDockContainer(dockArea->dockManager())
{
d->m_dockContainer->addDockArea(dockArea);
if (Utils::HostOsInfo::isLinuxHost())
d->m_titleBar->enableCloseButton(isClosable());
auto dw = topLevelDockWidget();
if (dw)
#ifdef Q_OS_LINUX
d->m_titleBar->enableCloseButton(isClosable());
#endif
if (auto dw = topLevelDockWidget())
dw->emitTopLevelChanged(true);
d->m_dockManager->notifyWidgetOrAreaRelocation(dockArea);
}
FloatingDockContainer::FloatingDockContainer(DockWidget *dockWidget)
: FloatingDockContainer(dockWidget->dockManager())
{
d->m_dockContainer->addDockWidget(CenterDockWidgetArea, dockWidget);
if (Utils::HostOsInfo::isLinuxHost())
d->m_titleBar->enableCloseButton(isClosable());
auto dw = topLevelDockWidget();
if (dw)
#ifdef Q_OS_LINUX
d->m_titleBar->enableCloseButton(isClosable());
#endif
if (auto dw = topLevelDockWidget())
dw->emitTopLevelChanged(true);
d->m_dockManager->notifyWidgetOrAreaRelocation(dockWidget);
}
FloatingDockContainer::~FloatingDockContainer()
@@ -313,33 +619,56 @@ namespace ADS
}
}
void FloatingDockContainer::moveEvent(QMoveEvent *event)
#ifdef Q_OS_WIN
bool FloatingDockContainer::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
QWidget::nativeEvent(eventType, message, result);
MSG *msg = static_cast<MSG *>(message);
switch (msg->message)
{
QWidget::moveEvent(event);
switch (d->m_draggingState) {
case DraggingMousePressed:
// TODO Is checking for windows only sufficient or has macOS also problems?
if (Utils::HostOsInfo::isWindowsHost())
QApplication::instance()->installEventFilter(this);
d->setState(DraggingFloatingWidget);
d->updateDropOverlays(QCursor::pos());
break;
case DraggingFloatingWidget:
d->updateDropOverlays(QCursor::pos());
if (Utils::HostOsInfo::isMacHost()) {
// In macOS when hiding the DockAreaOverlay the application would set
// the main window as the active window for some reason. This fixes
// that by resetting the active window to the floating widget after
// updating the overlays.
QApplication::setActiveWindow(this);
}
break;
default:
break;
case WM_MOVING:
{
if (d->isState(DraggingFloatingWidget))
d->updateDropOverlays(QCursor::pos());
}
break;
case WM_NCLBUTTONDOWN:
if (msg->wParam == HTCAPTION && d->isState(DraggingInactive))
{
qCInfo(adsLog) << Q_FUNC_INFO << "WM_NCLBUTTONDOWN" << eventType;
d->m_dragStartPos = pos();
d->setState(DraggingMousePressed);
}
break;
case WM_NCLBUTTONDBLCLK:
d->setState(DraggingInactive);
break;
case WM_ENTERSIZEMOVE:
if (d->isState(DraggingMousePressed))
{
qCInfo(adsLog) << Q_FUNC_INFO << "WM_ENTERSIZEMOVE" << eventType;
d->setState(DraggingFloatingWidget);
d->updateDropOverlays(QCursor::pos());
}
break;
case WM_EXITSIZEMOVE:
if (d->isState(DraggingFloatingWidget))
{
qCInfo(adsLog) << Q_FUNC_INFO << "WM_EXITSIZEMOVE" << eventType;
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
d->handleEscapeKey();
else
d->titleMouseReleaseEvent();
}
break;
}
return false;
}
#endif
void FloatingDockContainer::closeEvent(QCloseEvent *event)
{
@@ -368,112 +697,21 @@ namespace ADS
if (d->m_dockManager->isRestoringState())
return;
d->m_hiding = true;
for (auto dockArea : d->m_dockContainer->openedDockAreas()) {
for (auto dockWidget : dockArea->openedDockWidgets())
dockWidget->toggleView(false);
}
d->m_hiding = false;
}
void FloatingDockContainer::showEvent(QShowEvent *event) { Super::showEvent(event); }
bool FloatingDockContainer::event(QEvent *event)
void FloatingDockContainer::showEvent(QShowEvent *event)
{
switch (d->m_draggingState) {
case DraggingInactive: {
// Normally we would check here, if the left mouse button is pressed.
// But from QT version 5.12.2 on the mouse events from
// QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
// The event always returns Qt::RightButton even if the left button is clicked.
// It is really great to work around the whole NonClientMouseArea bugs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
if (event->type() == QEvent::NonClientAreaMouseButtonPress
/*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
#else
if (event->type() == QEvent::NonClientAreaMouseButtonPress
&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
#endif
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonPress"
<< event->type();
d->m_dragStartPos = pos();
d->setState(DraggingMousePressed);
}
} break;
case DraggingMousePressed:
switch (event->type()) {
case QEvent::NonClientAreaMouseButtonDblClick:
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonDblClick";
d->setState(DraggingInactive);
break;
case QEvent::Resize:
// If the first event after the mouse press is a resize event, then
// the user resizes the window instead of dragging it around.
// But there is one exception. If the window is maximized,
// then dragging the window via title bar will cause the widget to
// leave the maximized state. This in turn will trigger a resize event.
// To know, if the resize event was triggered by user via moving a
// corner of the window frame or if it was caused by a windows state
// change, we check, if we are not in maximized state.
if (!isMaximized()) {
d->setState(DraggingInactive);
}
break;
default:
break;
}
break;
case DraggingFloatingWidget:
if (event->type() == QEvent::NonClientAreaMouseButtonRelease) {
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonRelease";
d->titleMouseReleaseEvent();
}
break;
default:
break;
}
#if (ADS_DEBUG_LEVEL > 0)
qDebug() << "FloatingDockContainer::event " << event->type();
#endif
return QWidget::event(event);
}
bool FloatingDockContainer::eventFilter(QObject *watched, QEvent *event)
{
Q_UNUSED(watched);
// I have not found a way to detect non client area key press events to
// handle escape key presses. On Windows, if the escape key is pressed while
// dragging around a widget, the widget position is reset to its start position
// which in turn generates a QEvent::NonClientAreaMouseButtonRelease event
// if the mouse is outside of the widget after the move to its initial position
// or a QEvent::MouseButtonRelease event, if the mouse is inside of the widget
// after the position has been reset.
// So we can install an event filter on the application to get these events
// here to properly cancel dragging and hide the overlays.
// If we are in DraggingFloatingWidget state, it means the widget
// has been dragged already but if the position is the same like
// the start position, then this is an indication that the escape
// key has been pressed.
if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::NonClientAreaMouseButtonRelease)
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::MouseButtonRelease or QEvent::NonClientAreaMouseButtonRelease"
<< "d->m_draggingState " << d->m_draggingState;
QApplication::instance()->removeEventFilter(this);
if (d->m_dragStartPos == pos())
{
d->handleEscapeKey();
return true;
}
return false;
}
return false;
Super::showEvent(event);
#ifdef Q_OS_LINUX
if (DockManager::testConfigFlag(DockManager::FocusHighlighting))
window()->activateWindow();
#endif
}
void FloatingDockContainer::startFloating(const QPoint &dragStartMousePos,
@@ -481,29 +719,52 @@ namespace ADS
eDragState dragState,
QWidget *mouseEventHandler)
{
#ifndef Q_OS_LINUX
Q_UNUSED(mouseEventHandler)
#endif
resize(size);
d->setState(dragState);
d->m_dragStartMousePosition = dragStartMousePos;
if (Utils::HostOsInfo::isLinuxHost()) {
if (DraggingFloatingWidget == dragState) {
setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
d->m_mouseEventHandler = mouseEventHandler;
if (d->m_mouseEventHandler) {
d->m_mouseEventHandler->grabMouse();
}
}
#ifdef Q_OS_LINUX
if (DraggingFloatingWidget == dragState) {
setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
d->m_mouseEventHandler = mouseEventHandler;
if (d->m_mouseEventHandler)
d->m_mouseEventHandler->grabMouse();
}
#endif
moveFloating();
show();
}
void FloatingDockContainer::moveFloating()
{
int borderSize = (frameSize().width() - size().width()) / 2;
const int borderSize = (frameSize().width() - size().width()) / 2;
const QPoint moveToPos = QCursor::pos() - d->m_dragStartMousePosition
- QPoint(borderSize, 0);
move(moveToPos);
switch (d->m_draggingState)
{
case DraggingMousePressed:
d->setState(DraggingFloatingWidget);
d->updateDropOverlays(QCursor::pos());
break;
case DraggingFloatingWidget:
d->updateDropOverlays(QCursor::pos());
// On macOS when hiding the DockAreaOverlay the application would set
// the main window as the active window for some reason. This fixes
// that by resetting the active window to the floating widget after
// updating the overlays.
if (Utils::HostOsInfo::isMacHost())
QApplication::setActiveWindow(this);
break;
default:
break;
}
}
bool FloatingDockContainer::isClosable() const
@@ -538,10 +799,14 @@ namespace ADS
void FloatingDockContainer::updateWindowTitle()
{
auto topLevelDockArea = d->m_dockContainer->topLevelDockArea();
if (topLevelDockArea) {
DockWidget *currentWidget = topLevelDockArea->currentDockWidget();
d->reflectCurrentWidget(currentWidget);
// If this floating container will be hidden, then updating the window
// title is not required anymore
if (d->m_hiding)
return;
if (auto topLevelDockArea = d->m_dockContainer->topLevelDockArea()) {
if (DockWidget *currentWidget = topLevelDockArea->currentDockWidget())
d->reflectCurrentWidget(currentWidget);
} else {
d->setWindowTitle(QApplication::applicationDisplayName());
setWindowIcon(QApplication::windowIcon());
@@ -557,9 +822,8 @@ namespace ADS
bool FloatingDockContainer::restoreState(DockingStateReader &stream, bool testing)
{
if (!d->m_dockContainer->restoreState(stream, testing)) {
if (!d->m_dockContainer->restoreState(stream, testing))
return false;
}
onDockAreasAddedOrRemoved();
return true;
@@ -584,16 +848,113 @@ namespace ADS
{
qCInfo(adsLog) << Q_FUNC_INFO;
if (Utils::HostOsInfo::isLinuxHost()) {
setAttribute(Qt::WA_X11NetWmWindowTypeDock, false);
setWindowOpacity(1);
activateWindow();
if (d->m_mouseEventHandler) {
d->m_mouseEventHandler->releaseMouse();
d->m_mouseEventHandler = nullptr;
}
#ifdef Q_OS_LINUX
setAttribute(Qt::WA_X11NetWmWindowTypeDock, false);
setWindowOpacity(1);
activateWindow();
if (d->m_mouseEventHandler) {
d->m_mouseEventHandler->releaseMouse();
d->m_mouseEventHandler = nullptr;
}
#endif
d->titleMouseReleaseEvent();
}
#ifdef Q_OS_MACOS
bool FloatingDockContainer::event(QEvent *event)
{
switch (d->m_draggingState)
{
case DraggingInactive:
{
// Normally we would check here, if the left mouse button is pressed.
// But from QT version 5.12.2 on the mouse events from
// QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
// The event always returns Qt::RightButton even if the left button
// is clicked.
// It is really great to work around the whole NonClientMouseArea
// bugs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
if (event->type() == QEvent::NonClientAreaMouseButtonPress
/*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
#else
if (event->type() == QEvent::NonClientAreaMouseButtonPress
&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
#endif
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonPress"
<< event->type();
d->m_dragStartPos = pos();
d->setState(DraggingMousePressed);
}
}
break;
case DraggingMousePressed:
switch (event->type())
{
case QEvent::NonClientAreaMouseButtonDblClick:
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonDblClick";
d->setState(DraggingInactive);
break;
case QEvent::Resize:
// If the first event after the mouse press is a resize event, then
// the user resizes the window instead of dragging it around.
// But there is one exception. If the window is maximized,
// then dragging the window via title bar will cause the widget to
// leave the maximized state. This in turn will trigger a resize event.
// To know, if the resize event was triggered by user via moving a
// corner of the window frame or if it was caused by a windows state
// change, we check, if we are not in maximized state.
if (!isMaximized())
d->setState(DraggingInactive);
break;
default:
break;
}
break;
case DraggingFloatingWidget:
if (event->type() == QEvent::NonClientAreaMouseButtonRelease)
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonRelease";
d->titleMouseReleaseEvent();
}
break;
default:
break;
}
#if (ADS_DEBUG_LEVEL > 0)
qDebug() << Q_FUNC_INFO << event->type();
#endif
return QWidget::event(event);
}
void FloatingDockContainer::moveEvent(QMoveEvent *event)
{
QWidget::moveEvent(event);
switch (d->m_draggingState)
{
case DraggingMousePressed:
d->setState(DraggingFloatingWidget);
d->updateDropOverlays(QCursor::pos());
break;
case DraggingFloatingWidget:
d->updateDropOverlays(QCursor::pos());
// On macOS when hiding the DockAreaOverlay the application would set
// the main window as the active window for some reason. This fixes
// that by resetting the active window to the floating widget after
// updating the overlays.
QApplication::setActiveWindow(this);
break;
default:
break;
}
}
#endif
} // namespace ADS

View File

@@ -183,12 +183,21 @@ protected:
protected: // reimplements QWidget
void changeEvent(QEvent *event) override;
void moveEvent(QMoveEvent *event) override;
bool event(QEvent *event) override;
void closeEvent(QCloseEvent *event) override;
void hideEvent(QHideEvent *event) override;
void showEvent(QShowEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
#ifdef Q_OS_MACOS
virtual bool event(QEvent *event) override;
virtual void moveEvent(QMoveEvent *event) override;
#endif
#ifdef Q_OS_WIN
/**
* Native event filter for handling WM_MOVING messages on Windows
*/
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
#endif
public:
using Super = QWidget;

View File

@@ -62,7 +62,6 @@ namespace ADS
FloatingDragPreview *q;
QWidget *m_content = nullptr;
DockAreaWidget *m_contentSourceArea = nullptr;
DockContainerWidget *m_contenSourceContainer = nullptr;
QPoint m_dragStartMousePosition;
DockManager *m_dockManager = nullptr;
DockContainerWidget *m_dropContainer = nullptr;
@@ -93,6 +92,12 @@ namespace ADS
m_dockManager->dockAreaOverlay()->hideOverlay();
q->close();
}
/**
* Creates the real floating widget in case the mouse is released outside
* outside of any drop area
*/
void createFloatingWidget();
}; // class FloatingDragPreviewPrivate
void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition)
@@ -106,7 +111,7 @@ namespace ADS
if (!containerWidget->isVisible())
continue;
QPoint mappedPosition = containerWidget->mapFromGlobal(globalPosition);
const QPoint mappedPosition = containerWidget->mapFromGlobal(globalPosition);
if (containerWidget->rect().contains(mappedPosition)) {
if (!topContainer || containerWidget->isInFrontOf(topContainer))
topContainer = containerWidget;
@@ -122,18 +127,16 @@ namespace ADS
if (!topContainer) {
containerOverlay->hideOverlay();
dockAreaOverlay->hideOverlay();
if (DockManager::configFlags().testFlag(DockManager::DragPreviewIsDynamic))
if (DockManager::testConfigFlag(DockManager::DragPreviewIsDynamic))
setHidden(false);
return;
}
int visibleDockAreas = topContainer->visibleDockAreaCount();
const int visibleDockAreas = topContainer->visibleDockAreaCount();
containerOverlay->setAllowedAreas(visibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
DockWidgetArea containerArea = containerOverlay->showOverlay(topContainer);
containerOverlay->enableDropPreview(containerArea != InvalidDockWidgetArea);
auto dockArea = topContainer->dockAreaAt(globalPosition);
if (dockArea && dockArea->isVisible() && visibleDockAreas > 0
if (dockArea && dockArea->isVisible() && visibleDockAreas >= 0
&& dockArea != m_contentSourceArea) {
dockAreaOverlay->enableDropPreview(true);
dockAreaOverlay->setAllowedAreas((visibleDockAreas == 1) ? NoDockWidgetArea
@@ -143,25 +146,28 @@ namespace ADS
// A CenterDockWidgetArea for the dockAreaOverlay() indicates that the mouse is in the
// title bar. If the ContainerArea is valid then we ignore the dock area of the
// dockAreaOverlay() and disable the drop preview
if ((area == CenterDockWidgetArea) && (containerArea != InvalidDockWidgetArea)) {
if ((area == CenterDockWidgetArea) && (containerDropArea != InvalidDockWidgetArea)) {
dockAreaOverlay->enableDropPreview(false);
containerOverlay->enableDropPreview(true);
} else {
containerOverlay->enableDropPreview(InvalidDockWidgetArea == area);
}
containerOverlay->showOverlay(topContainer);
} else {
dockAreaOverlay->hideOverlay();
// If there is only one single visible dock area in a container, then
// it does not make sense to show a dock overlay because the dock area
// would be removed and inserted at the same position
if (visibleDockAreas <= 1)
containerOverlay->hide();
containerOverlay->hideOverlay();
else
containerOverlay->showOverlay(topContainer);
if (dockArea == m_contentSourceArea && InvalidDockWidgetArea == containerDropArea)
m_dropContainer = nullptr;
}
if (DockManager::configFlags().testFlag(DockManager::DragPreviewIsDynamic)) {
if (DockManager::testConfigFlag(DockManager::DragPreviewIsDynamic)) {
setHidden(dockDropArea != InvalidDockWidgetArea
|| containerDropArea != InvalidDockWidgetArea);
}
@@ -171,13 +177,38 @@ namespace ADS
: q(parent)
{}
void FloatingDragPreviewPrivate::createFloatingWidget()
{
DockWidget *dockWidget = qobject_cast<DockWidget *>(m_content);
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(m_content);
FloatingDockContainer *floatingWidget = nullptr;
if (dockWidget && dockWidget->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockWidget);
else if (dockArea && dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockArea);
if (floatingWidget) {
floatingWidget->setGeometry(q->geometry());
floatingWidget->show();
if (!DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
QApplication::processEvents();
int frameHeight = floatingWidget->frameGeometry().height() - floatingWidget->geometry().height();
QRect fixedGeometry = q->geometry();
fixedGeometry.adjust(0, frameHeight, 0, 0);
floatingWidget->setGeometry(fixedGeometry);
}
}
}
FloatingDragPreview::FloatingDragPreview(QWidget *content, QWidget *parent)
: QWidget(parent)
, d(new FloatingDragPreviewPrivate(this))
{
d->m_content = content;
setAttribute(Qt::WA_DeleteOnClose);
if (DockManager::configFlags().testFlag(DockManager::DragPreviewHasWindowFrame)) {
if (DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
} else {
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
@@ -195,7 +226,7 @@ namespace ADS
// Create a static image of the widget that should get undocked
// This is like some kind preview image like it is uses in drag and drop operations
if (DockManager::configFlags().testFlag(DockManager::DragPreviewShowsContentPixmap)) {
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap)) {
d->m_contentPreviewPixmap = QPixmap(content->size());
content->render(&d->m_contentPreviewPixmap);
}
@@ -213,10 +244,9 @@ namespace ADS
content->dockManager()) // TODO static_cast?
{
d->m_dockManager = content->dockManager();
if (content->dockAreaWidget()->openDockWidgetsCount() == 1) {
if (content->dockAreaWidget()->openDockWidgetsCount() == 1)
d->m_contentSourceArea = content->dockAreaWidget();
d->m_contenSourceContainer = content->dockContainer();
}
setWindowTitle(content->windowTitle());
}
@@ -226,7 +256,6 @@ namespace ADS
{
d->m_dockManager = content->dockManager();
d->m_contentSourceArea = content;
d->m_contenSourceContainer = content->dockContainer();
setWindowTitle(content->currentDockWidget()->windowTitle());
}
@@ -234,10 +263,11 @@ namespace ADS
void FloatingDragPreview::moveFloating()
{
int borderSize = (frameSize().width() - size().width()) / 2;
const int borderSize = (frameSize().width() - size().width()) / 2;
const QPoint moveToPos = QCursor::pos() - d->m_dragStartMousePosition
- QPoint(borderSize, 0);
move(moveToPos);
d->updateDropOverlays(QCursor::pos());
}
void FloatingDragPreview::startFloating(const QPoint &dragStartMousePos,
@@ -253,46 +283,24 @@ namespace ADS
show();
}
void FloatingDragPreview::moveEvent(QMoveEvent *event)
{
QWidget::moveEvent(event);
d->updateDropOverlays(QCursor::pos());
}
void FloatingDragPreview::finishDragging()
{
qCInfo(adsLog) << Q_FUNC_INFO;
auto dockDropArea = d->m_dockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
auto containerDropArea = d->m_dockManager->containerOverlay()->visibleDropAreaUnderCursor();
if (d->m_dropContainer && (dockDropArea != InvalidDockWidgetArea)) {
d->m_dropContainer->dropWidget(d->m_content,
dockDropArea,
d->m_dropContainer->dockAreaAt(QCursor::pos()));
} else if (d->m_dropContainer && (containerDropArea != InvalidDockWidgetArea)) {
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr);
if (!d->m_dropContainer) {
d->createFloatingWidget();
} else if (dockDropArea != InvalidDockWidgetArea) {
d->m_dropContainer->dropWidget(d->m_content, dockDropArea, d->m_dropContainer->dockAreaAt(QCursor::pos()));
} else if (containerDropArea != InvalidDockWidgetArea) {
// If there is only one single dock area, and we drop into the center
// then we tabify the dropped widget into the only visible dock area
if (d->m_dropContainer->visibleDockAreaCount() <= 1 && CenterDockWidgetArea == containerDropArea)
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, d->m_dropContainer->dockAreaAt(QCursor::pos()));
else
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr);
} else {
DockWidget *dockWidget = qobject_cast<DockWidget *>(d->m_content);
FloatingDockContainer *floatingWidget = nullptr;
if (dockWidget && dockWidget->features().testFlag(DockWidget::DockWidgetFloatable)) {
floatingWidget = new FloatingDockContainer(dockWidget);
} else {
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(d->m_content);
if (dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockArea);
}
if (floatingWidget) {
floatingWidget->setGeometry(this->geometry());
floatingWidget->show();
if (!DockManager::configFlags().testFlag(DockManager::DragPreviewHasWindowFrame)) {
QApplication::processEvents();
int frameHeight = floatingWidget->frameGeometry().height() - floatingWidget->geometry().height();
QRect fixedGeometry = this->geometry();
fixedGeometry.adjust(0, frameHeight, 0, 0);
floatingWidget->setGeometry(fixedGeometry);
}
}
d->createFloatingWidget();
}
this->close();
@@ -307,11 +315,11 @@ namespace ADS
return;
QPainter painter(this);
if (DockManager::configFlags().testFlag(DockManager::DragPreviewShowsContentPixmap))
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap))
painter.drawPixmap(QPoint(0, 0), d->m_contentPreviewPixmap);
// If we do not have a window frame then we paint a QRubberBand like frameless window
if (!DockManager::configFlags().testFlag(DockManager::DragPreviewHasWindowFrame)) {
if (!DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
QColor color = palette().color(QPalette::Active, QPalette::Highlight);
QPen pen = painter.pen();
pen.setColor(color.darker(120));

View File

@@ -64,11 +64,6 @@ private:
void onApplicationStateChanged(Qt::ApplicationState state);
protected:
/**
* Updates the drop overlays
*/
void moveEvent(QMoveEvent *event) override;
/**
* Cares about painting the
*/

View File

@@ -1,122 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="512"
height="512"
viewBox="0 0 512 512"
xml:space="preserve"
sodipodi:docname="close-button-disabled.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata897"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs895" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview893"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.85862966"
inkscape:cx="345.29142"
inkscape:cy="32.731258"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g860"
transform="matrix(0.71708683,0,0,0.71708683,128,128)"
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081">
<g
id="close"
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081">
<polygon
points="357,321.3 214.2,178.5 357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 "
id="polygon857"
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081" />
</g>
</g>
<g
id="g862"
transform="translate(0,155)">
</g>
<g
id="g864"
transform="translate(0,155)">
</g>
<g
id="g866"
transform="translate(0,155)">
</g>
<g
id="g868"
transform="translate(0,155)">
</g>
<g
id="g870"
transform="translate(0,155)">
</g>
<g
id="g872"
transform="translate(0,155)">
</g>
<g
id="g874"
transform="translate(0,155)">
</g>
<g
id="g876"
transform="translate(0,155)">
</g>
<g
id="g878"
transform="translate(0,155)">
</g>
<g
id="g880"
transform="translate(0,155)">
</g>
<g
id="g882"
transform="translate(0,155)">
</g>
<g
id="g884"
transform="translate(0,155)">
</g>
<g
id="g886"
transform="translate(0,155)">
</g>
<g
id="g888"
transform="translate(0,155)">
</g>
<g
id="g890"
transform="translate(0,155)">
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1,119 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="512"
height="512"
viewBox="0 0 512 512"
xml:space="preserve"
sodipodi:docname="close-button.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata897"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs895" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview893"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.85862966"
inkscape:cx="345.29142"
inkscape:cy="32.731258"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g860"
transform="matrix(0.71708683,0,0,0.71708683,128,128)">
<g
id="close">
<polygon
points="357,321.3 214.2,178.5 357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 "
id="polygon857" />
</g>
</g>
<g
id="g862"
transform="translate(0,155)">
</g>
<g
id="g864"
transform="translate(0,155)">
</g>
<g
id="g866"
transform="translate(0,155)">
</g>
<g
id="g868"
transform="translate(0,155)">
</g>
<g
id="g870"
transform="translate(0,155)">
</g>
<g
id="g872"
transform="translate(0,155)">
</g>
<g
id="g874"
transform="translate(0,155)">
</g>
<g
id="g876"
transform="translate(0,155)">
</g>
<g
id="g878"
transform="translate(0,155)">
</g>
<g
id="g880"
transform="translate(0,155)">
</g>
<g
id="g882"
transform="translate(0,155)">
</g>
<g
id="g884"
transform="translate(0,155)">
</g>
<g
id="g886"
transform="translate(0,155)">
</g>
<g
id="g888"
transform="translate(0,155)">
</g>
<g
id="g890"
transform="translate(0,155)">
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -41,7 +41,7 @@
namespace ADS {
using TabLabelType = ElidingLabel;
using CloseButtonType = QPushButton;
using CloseButtonType = QToolButton;
/**
* @brief Private data class of public interface CFloatingWidgetTitleBar
@@ -76,7 +76,7 @@ void FloatingWidgetTitleBarPrivate::createLayout()
m_closeButton = new CloseButtonType();
m_closeButton->setObjectName("floatingTitleCloseButton");
m_closeButton->setFlat(true);
m_closeButton->setAutoRaise(true);
internal::setButtonIcon(m_closeButton,
QStyle::SP_TitleBarCloseButton,
ADS::FloatingWidgetCloseIcon);
@@ -106,7 +106,7 @@ void FloatingWidgetTitleBarPrivate::createLayout()
}
FloatingWidgetTitleBar::FloatingWidgetTitleBar(FloatingDockContainer *parent)
: QWidget(parent)
: QFrame(parent)
, d(new FloatingWidgetTitleBarPrivate(this))
{
d->m_floatingWidget = parent;
@@ -131,9 +131,9 @@ void FloatingWidgetTitleBar::mousePressEvent(QMouseEvent *event)
void FloatingWidgetTitleBar::mouseReleaseEvent(QMouseEvent *event)
{
d->m_dragState = DraggingInactive;
if (d->m_floatingWidget) {
if (d->m_floatingWidget)
d->m_floatingWidget->finishDragging();
}
Super::mouseReleaseEvent(event);
}
@@ -164,4 +164,9 @@ void FloatingWidgetTitleBar::setTitle(const QString &text)
d->m_titleLabel->setText(text);
}
void FloatingWidgetTitleBar::updateStyle()
{
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
} // namespace ADS

View File

@@ -25,7 +25,7 @@
#pragma once
#include <QWidget>
#include <QFrame>
namespace ADS {
@@ -34,12 +34,12 @@ class FloatingWidgetTitleBarPrivate;
/**
* Titlebar for floating widgets to capture non client are mouse events.
* Linux does not support NonClieantArea mouse events like
* Linux does not support NonClientArea mouse events like
* QEvent::NonClientAreaMouseButtonPress. Because these events are required
* for the docking system to work properly, we use our own titlebar here to
* capture the required mouse events.
*/
class FloatingWidgetTitleBar : public QWidget
class FloatingWidgetTitleBar : public QFrame
{
Q_OBJECT
private:
@@ -55,24 +55,29 @@ public:
explicit FloatingWidgetTitleBar(FloatingDockContainer *parent = nullptr);
/**
* Virtual Destructor
*/
* Virtual Destructor
*/
~FloatingWidgetTitleBar() override;
/**
* Enables / disables the window close button.
*/
* Enables / disables the window close button.
*/
void enableCloseButton(bool enable);
/**
* Sets the window title, that means, the text of the internal tile label.
*/
* Sets the window title, that means, the text of the internal tile label.
*/
void setTitle(const QString &text);
/**
* Update stylesheet style if a property changes
*/
void updateStyle();
signals:
/**
* This signal is emitted, if the close button is clicked.
*/
* This signal is emitted, if the close button is clicked.
*/
void closeRequested();
};

View File

@@ -1,6 +0,0 @@
<RCC>
<qresource prefix="/ads">
<file>images/close-button.svg</file>
<file>images/close-button-disabled.svg</file>
</qresource>
</RCC>

View File

@@ -59,9 +59,15 @@ ADS--DockWidget
border-width: 0;
}
ADS--DockAreaTitleBar{ background-color: creatorTheme.BackgroundColorDark; }
ADS--DockAreaTitleBar
{
background-color: creatorTheme.BackgroundColorDark;
}
QWidget#tabsContainerWidget { background-color: creatorTheme.BackgroundColorDark; }
QWidget#tabsContainerWidget
{
background-color: creatorTheme.BackgroundColorDark;
}
ADS--TitleBarButton
{
@@ -126,3 +132,33 @@ QScrollBar::sub-page {
height: 0px;
width: 0px;
}
/* Focus related styling */
ADS--DockWidgetTab[focused="true"] {
background: creatorTheme.DSinteraction;
border-color: creatorTheme.DSinteraction;
}
ADS--DockWidgetTab[focused="true"] > #tabCloseButton:hover {
background: rgba(255, 255, 255, 48);
}
ADS--DockWidgetTab[focused="true"] > #tabCloseButton:pressed {
background: rgba(255, 255, 255, 92);
}
ADS--DockWidgetTab[focused="true"] QLabel {
color: palette(creatorTheme.QmlDesigner_TabDark);
}
ADS--DockAreaTitleBar {
background: transparent;
border-bottom: 2px solid creatorTheme.QmlDesigner_TabLight;
padding-bottom: 0px;
}
ADS--DockAreaWidget[focused="true"] ADS--DockAreaTitleBar {
background: transparent;
border-bottom: 2px solid creatorTheme.DSinteraction;
padding-bottom: 0px;
}

View File

@@ -228,8 +228,9 @@ void DesignModeWidget::setup()
auto settings = Core::ICore::settings(QSettings::UserScope);
ADS::DockManager::setConfigFlags(ADS::DockManager::DefaultNonOpaqueConfig);
ADS::DockManager::setConfigFlag(ADS::DockManager::FocusHighlighting, true);
m_dockManager = new ADS::DockManager(this);
m_dockManager->setConfigFlags(ADS::DockManager::DefaultNonOpaqueConfig);
m_dockManager->setSettings(settings);
m_dockManager->setWorkspacePresetsPath(Core::ICore::resourcePath() + QLatin1String("/qmldesigner/workspacePresets/"));