Compare commits
68 Commits
fix-python
...
fix-python
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c76540b86 | ||
|
|
6cf527403e | ||
|
|
92843b4972 | ||
|
|
b2df16dcb0 | ||
|
|
8bb15f5447 | ||
|
|
2977f0b8c6 | ||
|
|
251423116f | ||
|
|
04e2a71b66 | ||
|
|
a06fec51c8 | ||
|
|
83eda81263 | ||
|
|
1bb476ca95 | ||
|
|
f0ac455ec1 | ||
|
|
44b2fc6944 | ||
|
|
113e6453ea | ||
|
|
283d814dc6 | ||
|
|
034dc25483 | ||
|
|
b1333b2c4c | ||
|
|
ff58ff72f9 | ||
|
|
00b4dbc821 | ||
|
|
35076bbdb6 | ||
|
|
2dc98804f4 | ||
|
|
961600fe74 | ||
|
|
7fdca76a4c | ||
|
|
32592f6ad1 | ||
|
|
1545e98e6d | ||
|
|
85b3feb10b | ||
|
|
d9fdd20caa | ||
|
|
9e2d001ac5 | ||
|
|
750f9b6142 | ||
|
|
1c3cf8cf2d | ||
|
|
db19cb40d7 | ||
|
|
037fa76fff | ||
|
|
caa2ece751 | ||
|
|
22f2975f3c | ||
|
|
d3323d824a | ||
|
|
41d1ea8f61 | ||
|
|
1e85b1e7fb | ||
|
|
75464708af | ||
|
|
f007451442 | ||
|
|
f591270d46 | ||
|
|
390423d0c1 | ||
|
|
1aed8c7429 | ||
|
|
0aee56114b | ||
|
|
b3ec7423e8 | ||
|
|
179cd4cf45 | ||
|
|
75d26c3cce | ||
|
|
9071664ef2 | ||
|
|
1980f9c42c | ||
|
|
2c917dcd7c | ||
|
|
5ccf15b9ed | ||
|
|
7eaac87640 | ||
|
|
5b9f08c754 | ||
|
|
02c165163a | ||
|
|
4bbc0f1d4f | ||
|
|
cf692797b6 | ||
|
|
0e4ec055b2 | ||
|
|
cf7c25cd88 | ||
|
|
60b5eb00a3 | ||
|
|
0705b4da72 | ||
|
|
09b3e685a9 | ||
|
|
64791eec82 | ||
|
|
dc3aa354ec | ||
|
|
890784ba5a | ||
|
|
c9468bef8a | ||
|
|
0b4c017f22 | ||
|
|
6de558773f | ||
|
|
94258abf43 | ||
|
|
10026ba191 |
@@ -61,11 +61,11 @@ else()
|
||||
LANGUAGES CXX)
|
||||
endif()
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 0)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 9)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 99)
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 0)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 95)
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(${PROJECT_NAME}_SOVERSION "1.0")
|
||||
set(${PROJECT_NAME}_SOVERSION "1.1")
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
@@ -83,6 +83,8 @@ if(OPTION_DEVELOPER_MODE)
|
||||
set(${PROJECT_NAME}_TESTS ON)
|
||||
endif()
|
||||
|
||||
# option(OPTION_QTQUICK "Build for QtQuick instead of QtWidgets" OFF)
|
||||
|
||||
find_package(Qt5Widgets 5.9 REQUIRED)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
@@ -26,3 +26,12 @@
|
||||
- Static build support
|
||||
- Namespaced Qt support
|
||||
- Dozens of crash fixes, bugs and much more...
|
||||
|
||||
* v1.1.0 (, 2020)
|
||||
- New drop indicator style type: Segmented Indicators
|
||||
- Added FocusScope support
|
||||
- Added DockWidget::isFocused() and DockWidgetBase::isFocusedChanged()
|
||||
- Added Config::Flag_AlwaysTitleBarWhenFloating, which complements Flag_HideTitleBarWhenTabsVisible
|
||||
|
||||
* Roadmap
|
||||
- QtQuick support
|
||||
|
||||
@@ -23,6 +23,19 @@ endif()
|
||||
if (NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
|
||||
# On macOS, check if Qt is a framework build. This affects how include paths should be handled.
|
||||
get_target_property(QtCore_is_framework Qt5::Core FRAMEWORK)
|
||||
if (QtCore_is_framework)
|
||||
# Get the path to the framework dir.
|
||||
get_filename_component(QT_FRAMEWORK_INCLUDE_DIR "${QT_INCLUDE_DIR}/../" ABSOLUTE)
|
||||
|
||||
list(GET Qt5Core_INCLUDE_DIRS 0 QT_INCLUDE_DIR)
|
||||
# QT_INCLUDE_DIR points to the QtCore.framework directory, so we need to adjust this to point
|
||||
# to the actual include directory, which has include files for non-framework parts of Qt.
|
||||
get_filename_component(QT_INCLUDE_DIR "${QT_INCLUDE_DIR}/../../include" ABSOLUTE)
|
||||
endif()
|
||||
|
||||
# Flags that we will pass to shiboken-generator
|
||||
# --generator-set=shiboken: tells the generator that we want to use shiboken to generate code,
|
||||
# a doc generator is also available
|
||||
|
||||
@@ -41,7 +41,9 @@ public:
|
||||
{
|
||||
QPainter p(this);
|
||||
QPen pen(Qt::black);
|
||||
QBrush brush(Qt::yellow);
|
||||
const QColor focusedBackgroundColor = Qt::yellow;
|
||||
const QColor backgroundColor = focusedBackgroundColor.darker(115);
|
||||
QBrush brush(isFocused() ? focusedBackgroundColor : backgroundColor);
|
||||
pen.setWidth(4);
|
||||
p.setPen(pen);
|
||||
p.setBrush(brush);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLineEdit>
|
||||
|
||||
static QHash<QString, QImage> s_images; /// clazy:exclude=non-pod-global-static
|
||||
|
||||
@@ -33,6 +34,15 @@ MyWidget::MyWidget(const QString &backgroundFile, const QString &logoFile, QWidg
|
||||
it = s_images.insert(logoFile, QImage(logoFile));
|
||||
m_logo = it.value();
|
||||
}
|
||||
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
#if 0
|
||||
// Uncomment to show focus propagation working
|
||||
new QLineEdit(this);
|
||||
auto l2 = new QLineEdit(this);
|
||||
l2->move(0, 100);
|
||||
setFocusProxy(l2);
|
||||
#endif
|
||||
}
|
||||
|
||||
MyWidget::~MyWidget()
|
||||
|
||||
@@ -48,6 +48,9 @@ int main(int argc, char **argv)
|
||||
QCommandLineOption noTitleBars("t", QCoreApplication::translate("main", "Hide titlebars when tabs are visible"));
|
||||
parser.addOption(noTitleBars);
|
||||
|
||||
QCommandLineOption alwaysTitleBarWhenFloating("q", QCoreApplication::translate("main", "Don't hide title bars if floating, even if Flag_HideTitleBarWhenTabsVisible is specified."));
|
||||
parser.addOption(alwaysTitleBarWhenFloating);
|
||||
|
||||
QCommandLineOption alwaysTabs("z", QCoreApplication::translate("main", "Show tabs even if there's only one"));
|
||||
parser.addOption(alwaysTabs);
|
||||
|
||||
@@ -78,6 +81,9 @@ int main(int argc, char **argv)
|
||||
QCommandLineOption maximizeButton("b", QCoreApplication::translate("main", "DockWidgets have maximize/restore buttons instead of float/dock button"));
|
||||
parser.addOption(maximizeButton);
|
||||
|
||||
QCommandLineOption segmentedIndicators("y", QCoreApplication::translate("main", "Use segmented indicators instead of classical"));
|
||||
parser.addOption(segmentedIndicators);
|
||||
|
||||
parser.addPositionalArgument("savedlayout", QCoreApplication::translate("main", "loads the specified json file at startup"));
|
||||
|
||||
#ifdef KDDOCKWIDGETS_SUPPORTS_NESTED_MAINWINDOWS
|
||||
@@ -104,6 +110,9 @@ int main(int argc, char **argv)
|
||||
Config::self().setSeparatorThickness(10);
|
||||
}
|
||||
|
||||
if (parser.isSet(segmentedIndicators))
|
||||
KDDockWidgets::DefaultWidgetFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::Segmented;
|
||||
|
||||
MainWindowOptions options = MainWindowOption_None;
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
options = parser.isSet(centralFrame) ? MainWindowOption_HasCentralFrame
|
||||
@@ -117,6 +126,17 @@ int main(int argc, char **argv)
|
||||
if (parser.isSet(alwaysTabs))
|
||||
flags |= KDDockWidgets::Config::Flag_AlwaysShowTabs;
|
||||
|
||||
if (parser.isSet(alwaysTitleBarWhenFloating)) {
|
||||
flags |= KDDockWidgets::Config::Flag_AlwaysTitleBarWhenFloating;
|
||||
if (!(flags & KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible)) {
|
||||
qWarning() << "Flag_AlwaysTitleBarWhenFloating is unneeded if Flag_HideTitleBarWhenTabsVisible isn't used."
|
||||
<< "As floating windows already have title bars by default.";
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet(customStyle))
|
||||
flags |= KDDockWidgets::Config::Flag_TitleBarIsFocusable; // also showing title bar focus with -p, just to not introduce another switch
|
||||
|
||||
if (parser.isSet(reorderTabsOption))
|
||||
flags |= KDDockWidgets::Config::Flag_AllowReorderTabs;
|
||||
|
||||
|
||||
34
examples/qtquick/CMakeLists.txt
Normal file
34
examples/qtquick/CMakeLists.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_example_quick)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIRS ON)
|
||||
|
||||
if(NOT TARGET kddockwidgets)
|
||||
# This will look for Qt, do find_package yourself manually before
|
||||
# if you want to look for a specific Qt version for instance.
|
||||
find_package(KDDockWidgets REQUIRED)
|
||||
endif()
|
||||
|
||||
qt5_add_resources(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_example_quick
|
||||
main.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_example_quick
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
20
examples/qtquick/Guest.qml
Normal file
20
examples/qtquick/Guest.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "blue"
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget!"
|
||||
}
|
||||
}
|
||||
20
examples/qtquick/Guest1.qml
Normal file
20
examples/qtquick/Guest1.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "lightblue"
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget #1 !"
|
||||
}
|
||||
}
|
||||
20
examples/qtquick/Guest2.qml
Normal file
20
examples/qtquick/Guest2.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "pink"
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget #2!"
|
||||
}
|
||||
}
|
||||
20
examples/qtquick/Guest3.qml
Normal file
20
examples/qtquick/Guest3.qml
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "gray"
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget #3!"
|
||||
}
|
||||
}
|
||||
53
examples/qtquick/main.cpp
Normal file
53
examples/qtquick/main.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
|
||||
#include "private/DockRegistry_p.h"
|
||||
#include "private/quick/DockWidgetQuick.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QGuiApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QQuickView view;
|
||||
KDDockWidgets::Config::self().setQmlEngine(view.engine());
|
||||
view.resize(1000, 800);
|
||||
view.show();
|
||||
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
|
||||
auto dw1 = new KDDockWidgets::DockWidgetQuick("Dock #1");
|
||||
dw1->setWidget(QStringLiteral("qrc:/Guest1.qml"));
|
||||
dw1->resize(QSize(800, 800));
|
||||
dw1->show();
|
||||
|
||||
auto dw2 = new KDDockWidgets::DockWidgetQuick("Dock #2");
|
||||
dw2->setWidget(QStringLiteral("qrc:/Guest2.qml"));
|
||||
dw2->resize(QSize(800, 800));
|
||||
dw2->show();
|
||||
|
||||
auto dw3 = new KDDockWidgets::DockWidgetQuick("Dock #3");
|
||||
dw3->setWidget(QStringLiteral("qrc:/Guest3.qml"));
|
||||
dw3->resize(QSize(800, 800));
|
||||
dw3->show();
|
||||
|
||||
view.setSource(QUrl("qrc:/main.qml"));
|
||||
|
||||
dw1->addDockWidgetToContainingWindow(dw3, KDDockWidgets::Location_OnRight);
|
||||
|
||||
KDDockWidgets::MainWindowBase *mainWindow = KDDockWidgets::DockRegistry::self()->mainwindows().constFirst();
|
||||
mainWindow->addDockWidget(dw2, KDDockWidgets::Location_OnTop);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
23
examples/qtquick/main.qml
Normal file
23
examples/qtquick/main.qml
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
import com.kdab.dockwidgets 1.0 as KDDW
|
||||
|
||||
KDDW.MainWindow {
|
||||
id: root
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
root.init("MyWindowName-1");
|
||||
}
|
||||
}
|
||||
|
||||
8
examples/qtquick/resources_example.qrc
Normal file
8
examples/qtquick/resources_example.qrc
Normal file
@@ -0,0 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
<file>Guest1.qml</file>
|
||||
<file>Guest2.qml</file>
|
||||
<file>Guest3.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -24,6 +24,7 @@ add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS
|
||||
set(DOCKSLIBS_SRCS
|
||||
Config.cpp
|
||||
Qt5Qt6Compat_p.h
|
||||
FocusScope.cpp
|
||||
FrameworkWidgetFactory.cpp
|
||||
DockWidgetBase.cpp
|
||||
MainWindowBase.cpp
|
||||
@@ -43,6 +44,8 @@ set(DOCKSLIBS_SRCS
|
||||
private/Frame.cpp
|
||||
private/DropAreaWithCentralFrame.cpp
|
||||
private/WidgetResizeHandler.cpp
|
||||
private/indicators/ClassicIndicators.cpp
|
||||
private/indicators/ClassicIndicatorsWindow.cpp
|
||||
)
|
||||
|
||||
set(DOCKS_INSTALLABLE_INCLUDES
|
||||
@@ -51,6 +54,7 @@ set(DOCKS_INSTALLABLE_INCLUDES
|
||||
FrameworkWidgetFactory.h
|
||||
DockWidgetBase.h
|
||||
KDDockWidgets.h
|
||||
FocusScope.h
|
||||
QWidgetAdapter.h
|
||||
LayoutSaver.h
|
||||
LayoutSaver_p.h
|
||||
@@ -99,7 +103,7 @@ else()
|
||||
private/widgets/TitleBarWidget.cpp
|
||||
private/widgets/DockWidget.cpp
|
||||
private/widgets/QWidgetAdapter_widgets.cpp
|
||||
private/indicators/ClassicIndicators.cpp
|
||||
private/indicators/SegmentedIndicators.cpp
|
||||
# private/indicators/AnimatedIndicators.cpp
|
||||
)
|
||||
|
||||
@@ -199,6 +203,9 @@ install(FILES private/multisplitter/Separator_qwidget.h DESTINATION include/kddo
|
||||
install(FILES private/multisplitter/multisplitter_export.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES} DESTINATION include/kddockwidgets/private/widgets)
|
||||
|
||||
install(FILES private/indicators/ClassicIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
install(FILES private/indicators/SegmentedIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
KDDockWidgetsConfigVersion.cmake
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
MainWindowFactoryFunc m_mainWindowFactoryFunc = nullptr;
|
||||
FrameworkWidgetFactory *m_frameworkWidgetFactory;
|
||||
Flags m_flags = Flag_Default;
|
||||
qreal m_draggedWindowOpacity = Q_QNAN;
|
||||
};
|
||||
|
||||
Config::Config()
|
||||
@@ -142,6 +143,16 @@ void Config::setSeparatorThickness(int value)
|
||||
Layouting::Config::self().setSeparatorThickness(value);
|
||||
}
|
||||
|
||||
void Config::setDraggedWindowOpacity(qreal opacity)
|
||||
{
|
||||
d->m_draggedWindowOpacity = opacity;
|
||||
}
|
||||
|
||||
qreal Config::draggedWindowOpacity() const
|
||||
{
|
||||
return d->m_draggedWindowOpacity;
|
||||
}
|
||||
|
||||
void Config::setQmlEngine(QQmlEngine *qmlEngine)
|
||||
{
|
||||
if (d->m_qmlEngine) {
|
||||
|
||||
10
src/Config.h
10
src/Config.h
@@ -56,12 +56,14 @@ public:
|
||||
Flag_None = 0, ///> No option set
|
||||
Flag_NativeTitleBar = 1, ///> Enables the Native OS title bar on OSes that support it (Windows 10, macOS), ignored otherwise. This is mutually exclusive with Flag_AeroSnap
|
||||
Flag_AeroSnapWithClientDecos = 2, ///> Enables AeroSnap even if we're not using the native title bar. Only supported on Windows 10.
|
||||
Flag_AlwaysTitleBarWhenFloating = 4, ///> Floating windows will have a title bar even if Flag_HideTitleBarWhenTabsVisible is specified. Unneeded if Flag_HideTitleBarWhenTabsVisible isn't specified, as that's the default already.
|
||||
Flag_HideTitleBarWhenTabsVisible = 8, ///> Hides the title bar if there's tabs visible. The empty space in the tab bar becomes draggable.
|
||||
Flag_AlwaysShowTabs = 16, ///> Always show tabs, even if there's only one,
|
||||
Flag_AllowReorderTabs = 32, /// Allows user to re-order tabs by dragging them
|
||||
Flag_TabsHaveCloseButton = 64, /// Tabs will have a close button. Equivalent to QTabWidget::setTabsClosable(true).
|
||||
Flag_DoubleClickMaximizes = 128, /// Double clicking the titlebar will maximize a floating window instead of re-docking it
|
||||
Flag_TitleBarHasMaximizeButton = 256, /// The title bar will have a maximize/restore button when floating. This is mutually-exclusive with the floating button (since many apps behave that way).
|
||||
Flag_TitleBarIsFocusable = 512, /// You can click the title bar and it will focus the last focused widget in the focus scope. If no previously focused widget then it focuses the user's dock widget guest, which should accept focus or use a focus proxy.
|
||||
Flag_LazyResize = 1024, /// The dock widgets are resized in a lazy manner. The actual resize only happens when you release the mouse button.
|
||||
Flag_Default = Flag_AeroSnapWithClientDecos ///> The defaults
|
||||
};
|
||||
@@ -130,6 +132,14 @@ public:
|
||||
///Note: Only use this function at startup before creating any DockWidget or MainWindow.
|
||||
void setSeparatorThickness(int value);
|
||||
|
||||
///@brief sets the dragged window opacity
|
||||
///1.0 is fully opaque while 0.0 is fully transparent
|
||||
void setDraggedWindowOpacity(qreal opacity);
|
||||
|
||||
///@brief returns the opacity to use when dragging dock widgets
|
||||
///By default it's 1.0, fully opaque
|
||||
qreal draggedWindowOpacity() const;
|
||||
|
||||
///@brief Sets the QQmlEngine to use. Applicable only when using QtQuick.
|
||||
void setQmlEngine(QQmlEngine *);
|
||||
QQmlEngine* qmlEngine() const;
|
||||
|
||||
@@ -80,7 +80,6 @@ public:
|
||||
QPoint defaultCenterPosForFloating();
|
||||
|
||||
void updateTitle();
|
||||
void updateIcon();
|
||||
void toggle(bool enabled);
|
||||
void updateToggleAction();
|
||||
void updateFloatAction();
|
||||
@@ -101,7 +100,8 @@ public:
|
||||
const QString name;
|
||||
QStringList affinities;
|
||||
QString title;
|
||||
QIcon icon;
|
||||
QIcon titleBarIcon;
|
||||
QIcon tabBarIcon;
|
||||
QWidgetOrQuick *widget = nullptr;
|
||||
DockWidgetBase *const q;
|
||||
DockWidgetBase::Options options;
|
||||
@@ -355,16 +355,26 @@ void DockWidgetBase::setAsCurrentTab()
|
||||
frame->setCurrentDockWidget(this);
|
||||
}
|
||||
|
||||
void DockWidgetBase::setIcon(const QIcon &icon)
|
||||
void DockWidgetBase::setIcon(const QIcon &icon, IconPlaces places)
|
||||
{
|
||||
d->icon = icon;
|
||||
d->updateIcon();
|
||||
if (places & IconPlace::TitleBar)
|
||||
d->titleBarIcon = icon;
|
||||
|
||||
if (places & IconPlace::TabBar)
|
||||
d->tabBarIcon = icon;
|
||||
|
||||
Q_EMIT iconChanged();
|
||||
}
|
||||
|
||||
QIcon DockWidgetBase::icon() const
|
||||
QIcon DockWidgetBase::icon(IconPlace place) const
|
||||
{
|
||||
return d->icon;
|
||||
if (place == IconPlace::TitleBar)
|
||||
return d->titleBarIcon;
|
||||
|
||||
if (place == IconPlace::TabBar)
|
||||
return d->tabBarIcon;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void DockWidgetBase::forceClose()
|
||||
@@ -420,6 +430,12 @@ bool DockWidgetBase::isMainWindow() const
|
||||
return qobject_cast<MainWindowBase*>(widget());
|
||||
}
|
||||
|
||||
bool DockWidgetBase::isFocused() const
|
||||
{
|
||||
auto f = this->frame();
|
||||
return f && f->isFocused() && isCurrentTab();
|
||||
}
|
||||
|
||||
void DockWidgetBase::setAffinityName(const QString &affinity)
|
||||
{
|
||||
setAffinities({ affinity });
|
||||
@@ -514,6 +530,11 @@ void DockWidgetBase::saveLastFloatingGeometry()
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::updateFloatAction()
|
||||
{
|
||||
d->updateFloatAction();
|
||||
}
|
||||
|
||||
QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
|
||||
{
|
||||
MainWindowBase::List mainWindows = DockRegistry::self()->mainwindows();
|
||||
@@ -534,10 +555,6 @@ void DockWidgetBase::Private::updateTitle()
|
||||
toggleAction->setText(title);
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::updateIcon()
|
||||
{
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::toggle(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
|
||||
@@ -72,6 +72,14 @@ public:
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
|
||||
enum class IconPlace {
|
||||
TitleBar = 1,
|
||||
TabBar = 2,
|
||||
All = TitleBar | TabBar
|
||||
};
|
||||
Q_ENUM(IconPlace)
|
||||
Q_DECLARE_FLAGS(IconPlaces, IconPlace)
|
||||
|
||||
/**
|
||||
* @brief constructs a new DockWidget
|
||||
* @param uniqueName the name of the dockwidget, should be unique. Use title for user visible text.
|
||||
@@ -223,14 +231,22 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Sets an icon to show on title bars and tab bars.
|
||||
* By default none is shown.
|
||||
* @param places Specifies where the icon will be shown (TitleBar, TabBar or both)
|
||||
*
|
||||
* By default there's no icon set.
|
||||
*
|
||||
* @sa icon()
|
||||
*/
|
||||
void setIcon(const QIcon &icon);
|
||||
void setIcon(const QIcon &icon, IconPlaces places = IconPlace::All);
|
||||
|
||||
/**
|
||||
* @brief Returns the dock widget's icon.
|
||||
* @brief Returns the dock widget's titlebar or tabbar icon (depending on the passed @p place)
|
||||
*
|
||||
* By default it's null.
|
||||
*
|
||||
* @sa setIcon()
|
||||
*/
|
||||
QIcon icon() const;
|
||||
QIcon icon(IconPlace place = IconPlace::TitleBar) const;
|
||||
|
||||
/**
|
||||
* @brief Like QWidget::close() but the hosted widget won't be asked if we
|
||||
@@ -304,6 +320,12 @@ public:
|
||||
*/
|
||||
bool isMainWindow() const;
|
||||
|
||||
///@brief Returns whether This or any child of this dock widget is focused
|
||||
///Not to be confused with QWidget::hasFocus(), which just refers to 1 widget. This includes
|
||||
///variant includes children.
|
||||
///@sa isFocusedChanged()
|
||||
bool isFocused() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
///@brief signal emitted when the parent changed
|
||||
void parentChanged();
|
||||
@@ -327,6 +349,10 @@ Q_SIGNALS:
|
||||
///@sa setOptions(), options()
|
||||
void optionsChanged(KDDockWidgets::DockWidgetBase::Options);
|
||||
|
||||
///@brief emitted when isFocused changes
|
||||
///@sa isFocused
|
||||
void isFocusedChanged(bool);
|
||||
|
||||
protected:
|
||||
void onParentChanged();
|
||||
void onShown(bool spontaneous);
|
||||
@@ -392,6 +418,9 @@ private:
|
||||
///@brief If this dock widget is floating, then it saves its geometry
|
||||
void saveLastFloatingGeometry();
|
||||
|
||||
///@brief Updates the floatAction state
|
||||
void updateFloatAction();
|
||||
|
||||
class Private;
|
||||
Private *const d;
|
||||
};
|
||||
|
||||
130
src/FocusScope.cpp
Normal file
130
src/FocusScope.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief FocusScope
|
||||
*
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
#include "FocusScope.h"
|
||||
#include "TitleBar_p.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QApplication>
|
||||
#include <QPointer>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
// Our Private inherits from QObject since FocusScope can't (Since Frame is already QObject)
|
||||
class FocusScope::Private : public QObject
|
||||
{
|
||||
public:
|
||||
Private(FocusScope *qq, QWidgetAdapter *thisWidget)
|
||||
: q(qq)
|
||||
, m_thisWidget(thisWidget)
|
||||
{
|
||||
connect(qApp, &QGuiApplication::focusObjectChanged,
|
||||
this, &Private::onFocusObjectChanged);
|
||||
|
||||
onFocusObjectChanged(qApp->focusObject());
|
||||
m_inCtor = false;
|
||||
}
|
||||
|
||||
void setIsFocused(bool);
|
||||
void onFocusObjectChanged(QObject *);
|
||||
bool isInFocusScope(WidgetType *) const;
|
||||
|
||||
FocusScope *const q;
|
||||
QWidgetAdapter *const m_thisWidget;
|
||||
bool m_isFocused = false;
|
||||
bool m_inCtor = true;
|
||||
QPointer<WidgetType> m_lastFocusedInScope;
|
||||
};
|
||||
|
||||
|
||||
FocusScope::FocusScope(QWidgetAdapter *thisWidget)
|
||||
: d(new Private(this, thisWidget))
|
||||
{
|
||||
}
|
||||
|
||||
FocusScope::~FocusScope()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool FocusScope::isFocused() const
|
||||
{
|
||||
return d->m_isFocused;
|
||||
}
|
||||
|
||||
WidgetType *FocusScope::focusedWidget() const
|
||||
{
|
||||
return d->m_lastFocusedInScope;
|
||||
}
|
||||
|
||||
void FocusScope::focus(Qt::FocusReason reason)
|
||||
{
|
||||
if (d->m_lastFocusedInScope) {
|
||||
d->m_lastFocusedInScope->setFocus(reason);
|
||||
} else {
|
||||
if (auto frame = qobject_cast<Frame*>(d->m_thisWidget)) {
|
||||
if (DockWidgetBase *dw = frame->currentDockWidget()) {
|
||||
if (auto guest = dw->widget()) {
|
||||
if (guest->focusPolicy() != Qt::NoFocus)
|
||||
guest->setFocus(reason);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not a use case right now
|
||||
d->m_thisWidget->setFocus(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FocusScope::Private::setIsFocused(bool is)
|
||||
{
|
||||
if (is != m_isFocused) {
|
||||
m_isFocused = is;
|
||||
|
||||
if (!m_inCtor) // Hack so we don't call pure-virtual
|
||||
Q_EMIT q->isFocusedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void FocusScope::Private::onFocusObjectChanged(QObject *obj)
|
||||
{
|
||||
auto widget = qobject_cast<WidgetType*>(obj);
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
const bool is = isInFocusScope(widget);
|
||||
if (is && m_lastFocusedInScope != widget && !qobject_cast<TitleBar*>(obj)) {
|
||||
m_lastFocusedInScope = widget;
|
||||
Q_EMIT q->focusedWidgetChanged();
|
||||
}
|
||||
|
||||
setIsFocused(is);
|
||||
}
|
||||
|
||||
bool FocusScope::Private::isInFocusScope(WidgetType *widget) const
|
||||
{
|
||||
WidgetType *p = widget;
|
||||
while (p) {
|
||||
if (p == m_thisWidget)
|
||||
return true;
|
||||
|
||||
p = KDDockWidgets::Private::parentWidget(p);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
61
src/FocusScope.h
Normal file
61
src/FocusScope.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief FocusScope
|
||||
*
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
#ifndef KD_DOCKWIDGETS_FOCUSSCOPE_H
|
||||
#define KD_DOCKWIDGETS_FOCUSSCOPE_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
///@brief Allows to implement a similar functionality to QtQuick's FocusScope item, in QtWidgets
|
||||
class FocusScope
|
||||
{
|
||||
public:
|
||||
///@brief constructor
|
||||
explicit FocusScope(QWidgetAdapter *thisWidget);
|
||||
~FocusScope();
|
||||
|
||||
///@brief Returns true if this FocusScope is focused.
|
||||
///This is similar to the QWidget::hasFocus(), except that it counts with the children being focused too.
|
||||
///i.e: If any child is focused then this FocusScope has focus too.
|
||||
bool isFocused() const;
|
||||
|
||||
///@brief Returns the widget that's focused in this scope
|
||||
///The widget itself might not have focus as in QWidget::hasFocus(), but will get actual focus
|
||||
///as soon as this scope is focused.
|
||||
WidgetType* focusedWidget() const;
|
||||
|
||||
///@brief Sets focus on this scope.
|
||||
///
|
||||
/// This will call QWidget::focus() on the last QWidget that was focused in this scope.
|
||||
void focus(Qt::FocusReason = Qt::OtherFocusReason);
|
||||
|
||||
/*Q_SIGNALS:*/
|
||||
///@brief reimplement in the 1st QObject derived class
|
||||
virtual void isFocusedChanged() = 0;
|
||||
virtual void focusedWidgetChanged() = 0;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *const d;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "multisplitter/Separator_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Config.h"
|
||||
#include "indicators/ClassicIndicators_p.h"
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include "indicators/ClassicIndicators_p.h"
|
||||
@@ -25,6 +26,8 @@
|
||||
# include "widgets/TabWidgetWidget_p.h"
|
||||
# include "multisplitter/Separator_qwidget.h"
|
||||
# include "widgets/FloatingWindowWidget_p.h"
|
||||
# include "indicators/SegmentedIndicators_p.h"
|
||||
# include <QRubberBand>
|
||||
#else
|
||||
# include "quick/FrameQuick_p.h"
|
||||
# include "quick/DockWidgetQuick.h"
|
||||
@@ -35,6 +38,8 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
DropIndicatorType DefaultWidgetFactory::s_dropIndicatorType = DropIndicatorType::Classic;
|
||||
|
||||
FrameworkWidgetFactory::~FrameworkWidgetFactory()
|
||||
{
|
||||
}
|
||||
@@ -82,8 +87,21 @@ FloatingWindow *DefaultWidgetFactory::createFloatingWindow(Frame *frame, MainWin
|
||||
|
||||
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *dropArea) const
|
||||
{
|
||||
switch (s_dropIndicatorType) {
|
||||
case DropIndicatorType::Classic:
|
||||
return new ClassicIndicators(dropArea);
|
||||
case DropIndicatorType::Segmented:
|
||||
return new SegmentedIndicators(dropArea);
|
||||
}
|
||||
|
||||
return new ClassicIndicators(dropArea);
|
||||
}
|
||||
|
||||
QWidgetOrQuick *DefaultWidgetFactory::createRubberBand(QWidgetOrQuick *parent) const
|
||||
{
|
||||
return new QRubberBand(QRubberBand::Rectangle, parent);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Frame *DefaultWidgetFactory::createFrame(QWidgetOrQuick *parent, FrameOptions options) const
|
||||
@@ -116,9 +134,9 @@ FloatingWindow *DefaultWidgetFactory::createFloatingWindow(Frame *frame, MainWin
|
||||
return new FloatingWindowQuick(frame, parent);
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *) const
|
||||
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *dropArea) const
|
||||
{
|
||||
return nullptr;
|
||||
return new ClassicIndicators(dropArea);
|
||||
}
|
||||
|
||||
TabBar *DefaultWidgetFactory::createTabBar(TabWidget *parent) const
|
||||
@@ -140,4 +158,9 @@ Layouting::Separator *DefaultWidgetFactory::createSeparator(Layouting::Widget *p
|
||||
return new Layouting::SeparatorQuick(parent);
|
||||
}
|
||||
|
||||
QWidgetOrQuick *DefaultWidgetFactory::createRubberBand(QWidgetOrQuick *parent) const
|
||||
{
|
||||
return new QWidgetOrQuick(parent);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -117,6 +117,10 @@ public:
|
||||
/// Override to provide your own DropIndicatorOverlayInterface sub-class.
|
||||
///@param dropArea Just forward to DropIndicatorOverlayInterface's constructor.
|
||||
virtual DropIndicatorOverlayInterface *createDropIndicatorOverlay(DropArea *dropArea) const = 0;
|
||||
|
||||
///@brief Called internally by the framework to create a RubberBand to show as drop zone
|
||||
///Returns a rubber band
|
||||
virtual QWidgetOrQuick *createRubberBand(QWidgetOrQuick *parent) const = 0;
|
||||
private:
|
||||
Q_DISABLE_COPY(FrameworkWidgetFactory)
|
||||
};
|
||||
@@ -137,6 +141,9 @@ public:
|
||||
FloatingWindow *createFloatingWindow(MainWindowBase *parent = nullptr) const override;
|
||||
FloatingWindow *createFloatingWindow(Frame *frame, MainWindowBase *parent = nullptr) const override;
|
||||
DropIndicatorOverlayInterface *createDropIndicatorOverlay(DropArea*) const override;
|
||||
QWidgetOrQuick *createRubberBand(QWidgetOrQuick *parent) const override;
|
||||
|
||||
static DropIndicatorType s_dropIndicatorType;
|
||||
private:
|
||||
Q_DISABLE_COPY(DefaultWidgetFactory)
|
||||
};
|
||||
|
||||
@@ -73,6 +73,11 @@ namespace KDDockWidgets
|
||||
SizePolicy, ///< Uses the item's sizeHint() and sizePolicy()
|
||||
};
|
||||
|
||||
enum class DropIndicatorType {
|
||||
Classic, ///< The default
|
||||
Segmented
|
||||
};
|
||||
|
||||
///@internal
|
||||
inline QString locationStr(Location loc)
|
||||
{
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../../../private/indicators/ClassicIndicators_p.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../../../private/indicators/SegmentedIndicators_p.h"
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Logging_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QDebug>
|
||||
@@ -52,6 +53,9 @@ DockRegistry::DockRegistry(QObject *parent)
|
||||
KDDockWidgets::registerQmlTypes();
|
||||
#endif
|
||||
|
||||
connect(qApp, &QGuiApplication::focusObjectChanged,
|
||||
this, &DockRegistry::onFocusObjectChanged);
|
||||
|
||||
initKDDockWidgetResources();
|
||||
}
|
||||
|
||||
@@ -65,6 +69,35 @@ void DockRegistry::maybeDelete()
|
||||
delete this;
|
||||
}
|
||||
|
||||
void DockRegistry::onFocusObjectChanged(QObject *obj)
|
||||
{
|
||||
DockWidgetBase *const unfocusedDW = m_focusedDockWidget.data();
|
||||
DockWidgetBase *newFocusedDockWidget = nullptr;
|
||||
|
||||
// Check if it's inside a dock widget:
|
||||
auto p = qobject_cast<WidgetType*>(obj);
|
||||
while (p) {
|
||||
if (auto dw = qobject_cast<DockWidgetBase*>(p)) {
|
||||
newFocusedDockWidget = dw;
|
||||
break;
|
||||
}
|
||||
|
||||
p = KDDockWidgets::Private::parentWidget(p);
|
||||
}
|
||||
|
||||
// Nothing changed
|
||||
if (m_focusedDockWidget.data() == newFocusedDockWidget)
|
||||
return;
|
||||
|
||||
m_focusedDockWidget = newFocusedDockWidget;
|
||||
|
||||
if (unfocusedDW)
|
||||
Q_EMIT unfocusedDW->isFocusedChanged(false);
|
||||
|
||||
if (m_focusedDockWidget)
|
||||
Q_EMIT m_focusedDockWidget->isFocusedChanged(true);
|
||||
}
|
||||
|
||||
bool DockRegistry::isEmpty() const
|
||||
{
|
||||
return m_dockWidgets.isEmpty() && m_mainWindows.isEmpty() && m_nestedWindows.isEmpty();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <QVector>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
/**
|
||||
* DockRegistry is a singleton that knows about all DockWidgets.
|
||||
@@ -48,6 +49,8 @@ public:
|
||||
void registerFrame(Frame *);
|
||||
void unregisterFrame(Frame *);
|
||||
|
||||
DockWidgetBase *focusedDockWidget() const;
|
||||
|
||||
DockWidgetBase *dockByName(const QString &) const;
|
||||
MainWindowBase *mainWindowByName(const QString &) const;
|
||||
|
||||
@@ -167,12 +170,14 @@ protected:
|
||||
private:
|
||||
explicit DockRegistry(QObject *parent = nullptr);
|
||||
void maybeDelete();
|
||||
void onFocusObjectChanged(QObject *);
|
||||
bool m_isProcessingAppQuitEvent = false;
|
||||
DockWidgetBase::List m_dockWidgets;
|
||||
MainWindowBase::List m_mainWindows;
|
||||
Frame::List m_frames;
|
||||
QVector<FloatingWindow*> m_nestedWindows;
|
||||
QVector<MultiSplitter*> m_layouts;
|
||||
QPointer<DockWidgetBase> m_focusedDockWidget;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -427,14 +427,16 @@ template <typename T>
|
||||
static WidgetType* qtTopLevelUnderCursor_impl(QPoint globalPos, const QVector<QWindow*> &windows, T windowBeingDragged)
|
||||
{
|
||||
for (int i = windows.size() -1; i >= 0; --i) {
|
||||
auto tl = KDDockWidgets::Private::widgetForWindow(windows.at(i));
|
||||
QWindow *window = windows.at(i);
|
||||
auto tl = KDDockWidgets::Private::widgetForWindow(window);
|
||||
|
||||
if (!tl->isVisible() || tl == windowBeingDragged || KDDockWidgets::Private::isMinimized(tl))
|
||||
continue;
|
||||
|
||||
if (windowBeingDragged && KDDockWidgets::Private::windowForWidget(windowBeingDragged) == KDDockWidgets::Private::windowForWidget(tl))
|
||||
continue;
|
||||
|
||||
if (KDDockWidgets::Private::geometry(tl).contains(globalPos)) {
|
||||
if (window->geometry().contains(globalPos)) {
|
||||
qCDebug(toplevels) << Q_FUNC_INFO << "Found top-level" << tl;
|
||||
return tl;
|
||||
}
|
||||
|
||||
@@ -27,33 +27,45 @@ DropIndicatorOverlayInterface::DropIndicatorOverlayInterface(DropArea *dropArea)
|
||||
|
||||
void DropIndicatorOverlayInterface::setWindowBeingDragged(const FloatingWindow *window)
|
||||
{
|
||||
if (window != m_windowBeingDragged) {
|
||||
m_windowBeingDragged = window;
|
||||
if (m_windowBeingDragged) {
|
||||
setGeometry(m_dropArea->QWidgetAdapter::rect());
|
||||
raise();
|
||||
} else {
|
||||
setHoveredFrame(nullptr);
|
||||
}
|
||||
if (window == m_windowBeingDragged)
|
||||
return;
|
||||
|
||||
updateVisibility();
|
||||
m_windowBeingDragged = window;
|
||||
if (m_windowBeingDragged) {
|
||||
setGeometry(m_dropArea->QWidgetAdapter::rect());
|
||||
raise();
|
||||
} else {
|
||||
setHoveredFrame(nullptr);
|
||||
}
|
||||
|
||||
setVisible(m_windowBeingDragged != nullptr);
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
QRect DropIndicatorOverlayInterface::hoveredFrameRect() const
|
||||
{
|
||||
return m_hoveredFrameRect;
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::setHoveredFrame(Frame *frame)
|
||||
{
|
||||
if (frame != m_hoveredFrame) {
|
||||
if (m_hoveredFrame)
|
||||
disconnect(m_hoveredFrame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
|
||||
if (frame == m_hoveredFrame)
|
||||
return;
|
||||
|
||||
m_hoveredFrame = frame;
|
||||
if (m_hoveredFrame)
|
||||
connect(frame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
|
||||
if (m_hoveredFrame)
|
||||
disconnect(m_hoveredFrame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
|
||||
|
||||
updateVisibility();
|
||||
Q_EMIT hoveredFrameChanged(m_hoveredFrame);
|
||||
onHoveredFrameChanged(m_hoveredFrame);
|
||||
m_hoveredFrame = frame;
|
||||
if (m_hoveredFrame) {
|
||||
connect(frame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
|
||||
setHoveredFrameRect(m_hoveredFrame->QWidgetAdapter::geometry());
|
||||
} else {
|
||||
setHoveredFrameRect(QRect());
|
||||
}
|
||||
|
||||
updateVisibility();
|
||||
Q_EMIT hoveredFrameChanged(m_hoveredFrame);
|
||||
onHoveredFrameChanged(m_hoveredFrame);
|
||||
}
|
||||
|
||||
bool DropIndicatorOverlayInterface::isHovered() const
|
||||
@@ -61,6 +73,11 @@ bool DropIndicatorOverlayInterface::isHovered() const
|
||||
return m_windowBeingDragged != nullptr;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation DropIndicatorOverlayInterface::currentDropLocation() const
|
||||
{
|
||||
return m_currentDropLocation;
|
||||
}
|
||||
|
||||
KDDockWidgets::Location DropIndicatorOverlayInterface::multisplitterLocationFor(DropIndicatorOverlayInterface::DropLocation dropLoc)
|
||||
{
|
||||
switch (dropLoc) {
|
||||
@@ -92,10 +109,25 @@ void DropIndicatorOverlayInterface::onFrameDestroyed()
|
||||
|
||||
void DropIndicatorOverlayInterface::onHoveredFrameChanged(Frame *)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location)
|
||||
{
|
||||
m_currentDropLocation = location;
|
||||
if (m_currentDropLocation != location) {
|
||||
m_currentDropLocation = location;
|
||||
Q_EMIT currentDropLocationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::hover(QPoint globalPos)
|
||||
{
|
||||
hover_impl(globalPos);
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::setHoveredFrameRect(QRect rect)
|
||||
{
|
||||
if (m_hoveredFrameRect != rect) {
|
||||
m_hoveredFrameRect = rect;
|
||||
Q_EMIT hoveredFrameRectChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,12 @@ namespace KDDockWidgets {
|
||||
class FloatingWindow;
|
||||
class DropArea;
|
||||
|
||||
class DOCKS_EXPORT_FOR_UNIT_TESTS DropIndicatorOverlayInterface : public QWidgetAdapter
|
||||
class DOCKS_EXPORT DropIndicatorOverlayInterface : public QWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QRect hoveredFrameRect READ hoveredFrameRect NOTIFY hoveredFrameRectChanged)
|
||||
Q_PROPERTY(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation currentDropLocation READ currentDropLocation NOTIFY currentDropLocationChanged)
|
||||
public:
|
||||
enum Type {
|
||||
TypeNone = 0,
|
||||
TypeClassic = 1,
|
||||
TypeAnimated = 2
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
enum DropLocation {
|
||||
DropLocation_None = 0,
|
||||
DropLocation_Left,
|
||||
@@ -43,36 +38,45 @@ public:
|
||||
DropLocation_OutterLeft,
|
||||
DropLocation_OutterTop,
|
||||
DropLocation_OutterRight,
|
||||
DropLocation_OutterBottom
|
||||
DropLocation_OutterBottom,
|
||||
|
||||
DropLocation_First = DropLocation_Left,
|
||||
DropLocation_Last = DropLocation_OutterBottom,
|
||||
};
|
||||
Q_ENUM(DropLocation)
|
||||
|
||||
explicit DropIndicatorOverlayInterface(DropArea *dropArea);
|
||||
void setHoveredFrame(Frame *);
|
||||
void setWindowBeingDragged(const FloatingWindow *);
|
||||
QRect hoveredFrameRect() const;
|
||||
bool isHovered() const;
|
||||
DropLocation currentDropLocation() const { return m_currentDropLocation; }
|
||||
DropLocation currentDropLocation() const;
|
||||
Frame *hoveredFrame() const { return m_hoveredFrame; }
|
||||
void setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location);
|
||||
|
||||
virtual Type indicatorType() const = 0;
|
||||
virtual void hover(QPoint globalPos) = 0;
|
||||
void hover(QPoint globalPos);
|
||||
|
||||
virtual QPoint posForIndicator(DropLocation) const = 0; // Used by unit-tests only
|
||||
virtual QPoint posForIndicator(DropLocation) const { return {}; }; // Used by unit-tests only
|
||||
|
||||
static KDDockWidgets::Location multisplitterLocationFor(DropLocation);
|
||||
|
||||
Q_SIGNALS:
|
||||
void hoveredFrameChanged(KDDockWidgets::Frame *);
|
||||
void hoveredFrameRectChanged();
|
||||
void currentDropLocationChanged();
|
||||
|
||||
private:
|
||||
void onFrameDestroyed();
|
||||
void setHoveredFrameRect(QRect);
|
||||
QRect m_hoveredFrameRect;
|
||||
DropLocation m_currentDropLocation = DropLocation_None;
|
||||
|
||||
protected:
|
||||
virtual void hover_impl(QPoint globalPos) = 0;
|
||||
virtual void onHoveredFrameChanged(Frame *);
|
||||
virtual void updateVisibility() = 0;
|
||||
virtual void updateVisibility() {};
|
||||
|
||||
Frame *m_hoveredFrame = nullptr;
|
||||
DropLocation m_currentDropLocation = DropLocation_None;
|
||||
QPointer<const FloatingWindow> m_windowBeingDragged;
|
||||
DropArea *const m_dropArea;
|
||||
};
|
||||
|
||||
@@ -316,7 +316,8 @@ void FloatingWindow::updateTitleBarVisibility()
|
||||
if (KDDockWidgets::usesNativeTitleBar()) {
|
||||
visible = false;
|
||||
} else {
|
||||
if (Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible) {
|
||||
const auto flags = Config::self().flags();
|
||||
if ((flags & Config::Flag_HideTitleBarWhenTabsVisible) && !(flags & Config::Flag_AlwaysTitleBarWhenFloating)) {
|
||||
if (hasSingleFrame()) {
|
||||
visible = !frames().first()->hasTabsVisible();
|
||||
}
|
||||
@@ -417,3 +418,14 @@ QRect FloatingWindow::dragRect() const
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
bool FloatingWindow::event(QEvent *ev)
|
||||
{
|
||||
if (ev->type() == QEvent::ActivationChange) {
|
||||
// Since QWidget is missing a signal for window activation
|
||||
Q_EMIT activatedChanged();
|
||||
}
|
||||
|
||||
return QWidgetAdapter::event(ev);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ public:
|
||||
QRect dragRect() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void activatedChanged();
|
||||
void numFramesChanged();
|
||||
void windowStateChanged(QWindowStateChangeEvent *);
|
||||
protected:
|
||||
@@ -131,6 +132,7 @@ protected:
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
|
||||
#endif
|
||||
|
||||
bool event(QEvent *ev) override;
|
||||
void onCloseEvent(QCloseEvent *) override;
|
||||
|
||||
DropArea *const m_dropArea;
|
||||
|
||||
@@ -48,6 +48,7 @@ static FrameOptions actualOptions(FrameOptions options)
|
||||
|
||||
Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
|
||||
: LayoutGuestWidget(parent)
|
||||
, FocusScope(this)
|
||||
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
|
||||
, m_options(actualOptions(options))
|
||||
{
|
||||
@@ -233,6 +234,10 @@ void Frame::onDockWidgetCountChanged()
|
||||
// We don't really keep track of the state, so emit even if the visibility didn't change. No biggie.
|
||||
if (!(m_options & FrameOption_AlwaysShowsTabs))
|
||||
Q_EMIT hasTabsVisibleChanged();
|
||||
|
||||
const DockWidgetBase::List docks = dockWidgets();
|
||||
for (DockWidgetBase *dock : docks)
|
||||
dock->updateFloatAction();
|
||||
}
|
||||
|
||||
Q_EMIT numDockWidgetsChanged();
|
||||
@@ -280,7 +285,7 @@ void Frame::updateTitleBarVisibility()
|
||||
|
||||
bool Frame::containsMouse(QPoint globalPos) const
|
||||
{
|
||||
return QWidgetAdapter::rect().contains(LayoutGuestWidgetBase::mapFromGlobal(globalPos));
|
||||
return QWidgetAdapter::rect().contains(KDDockWidgets::QWidgetAdapter::mapFromGlobal(globalPos));
|
||||
}
|
||||
|
||||
TitleBar *Frame::titleBar() const
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "multisplitter/Widget_qwidget.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "FocusScope.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
@@ -47,7 +48,9 @@ class FloatingWindow;
|
||||
* inside a MultiSplitter (DropArea). Be it a MultiSplitter belonging to a MainWindow or belonging
|
||||
* to a FloatingWindow.
|
||||
*/
|
||||
class DOCKS_EXPORT Frame : public LayoutGuestWidget
|
||||
class DOCKS_EXPORT Frame
|
||||
: public LayoutGuestWidget
|
||||
, public FocusScope
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(KDDockWidgets::TitleBar* titleBar READ titleBar CONSTANT)
|
||||
@@ -223,6 +226,8 @@ Q_SIGNALS:
|
||||
void hasTabsVisibleChanged();
|
||||
void layoutInvalidated();
|
||||
void isInMainWindowChanged();
|
||||
void isFocusedChanged() override; // override from non-QObject
|
||||
void focusedWidgetChanged() override;
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
||||
@@ -220,11 +220,10 @@ void MultiSplitter::addMultiSplitter(MultiSplitter *sourceMultiSplitter, Locatio
|
||||
|
||||
void MultiSplitter::removeItem(Layouting::Item *item)
|
||||
{
|
||||
if (!item)
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "nullptr item";
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
}
|
||||
|
||||
item->parentContainer()->removeItem(item);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,12 @@ TitleBar::TitleBar(Frame *parent)
|
||||
, m_floatingWindow(nullptr)
|
||||
{
|
||||
connect(m_frame, &Frame::numDockWidgetsChanged, this, &TitleBar::updateCloseButton);
|
||||
connect(m_frame, &Frame::isFocusedChanged, this, &TitleBar::isFocusedChanged);
|
||||
|
||||
init();
|
||||
|
||||
if (Config::self().flags() & Config::Flag_TitleBarIsFocusable)
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
|
||||
TitleBar::TitleBar(FloatingWindow *parent)
|
||||
@@ -41,6 +46,7 @@ TitleBar::TitleBar(FloatingWindow *parent)
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateFloatButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateMaximizeButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::windowStateChanged, this, &TitleBar::updateMaximizeButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::activatedChanged , this, &TitleBar::isFocusedChanged);
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -48,6 +54,10 @@ void TitleBar::init()
|
||||
{
|
||||
qCDebug(creation) << "TitleBar" << this;
|
||||
setFixedHeight(30);
|
||||
connect(this, &TitleBar::isFocusedChanged, this, [this] {
|
||||
// repaint
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
TitleBar::~TitleBar()
|
||||
@@ -79,6 +89,17 @@ void TitleBar::toggleMaximized()
|
||||
m_floatingWindow->showMaximized();
|
||||
}
|
||||
|
||||
void TitleBar::focusInEvent(QFocusEvent *ev)
|
||||
{
|
||||
QWidgetAdapter::focusInEvent(ev);
|
||||
|
||||
if (!m_frame || !(Config::self().flags() & Config::Flag_TitleBarIsFocusable))
|
||||
return;
|
||||
|
||||
// For some reason QWidget::setFocusProxy() isn't working, so forward manually
|
||||
m_frame->FocusScope::focus(ev->reason());
|
||||
}
|
||||
|
||||
void TitleBar::setTitle(const QString &title)
|
||||
{
|
||||
if (title != m_title) {
|
||||
@@ -129,7 +150,7 @@ std::unique_ptr<WindowBeingDragged> TitleBar::makeWindow()
|
||||
|
||||
QRect r = m_frame->QWidgetAdapter::geometry();
|
||||
qCDebug(hovering) << "TitleBar::makeWindow original geometry" << r;
|
||||
r.moveTopLeft(static_cast<Layouting::Widget*>(m_frame)->mapToGlobal(QPoint(0, 0))); // TODO: Remove static_cast if it compiles. Ambiguous base for now
|
||||
r.moveTopLeft(m_frame->mapToGlobal(QPoint(0, 0))); // TODO: Remove static_cast if it compiles. Ambiguous base for now
|
||||
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(m_frame);
|
||||
floatingWindow->setSuggestedGeometry(r);
|
||||
@@ -174,6 +195,16 @@ bool TitleBar::hasIcon() const
|
||||
return !m_icon.isNull();
|
||||
}
|
||||
|
||||
bool TitleBar::isFocused() const
|
||||
{
|
||||
if (m_frame)
|
||||
return m_frame->isFocused();
|
||||
else if (m_floatingWindow)
|
||||
return m_floatingWindow->isActiveWindow();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QIcon TitleBar::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
|
||||
@@ -69,6 +69,11 @@ public:
|
||||
///@brief returns whether this title bar has an icon
|
||||
bool hasIcon() const;
|
||||
|
||||
///@brief returns whether any of the DockWidgets this TitleBar controls has a child focus
|
||||
///Not to be confused with QWidget::hasFocus(), which just refers to 1 widget. This works more
|
||||
/// like QtQuick's FocusScope
|
||||
bool isFocused() const;
|
||||
|
||||
///@brief the icon
|
||||
QIcon icon() const;
|
||||
|
||||
@@ -86,6 +91,7 @@ public:
|
||||
Q_SIGNALS:
|
||||
void titleChanged();
|
||||
void iconChanged();
|
||||
void isFocusedChanged();
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void onCloseClicked();
|
||||
@@ -102,6 +108,8 @@ protected:
|
||||
virtual bool isFloatButtonVisible() const { return true; }
|
||||
virtual bool isFloatButtonEnabled() const { return true; }
|
||||
|
||||
void focusInEvent(QFocusEvent *event) override;
|
||||
|
||||
private:
|
||||
friend class TestDocks;
|
||||
|
||||
|
||||
@@ -47,11 +47,21 @@ WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw, Draggable *draggable)
|
||||
, m_draggable(bestDraggable(draggable)->asWidget())
|
||||
{
|
||||
init();
|
||||
|
||||
// Set opacity while dragging, if needed
|
||||
const qreal opacity = Config::self().draggedWindowOpacity();
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
fw->setWindowOpacity(opacity);
|
||||
}
|
||||
|
||||
WindowBeingDragged::~WindowBeingDragged()
|
||||
{
|
||||
grabMouse(false);
|
||||
|
||||
// Restore opacity to fully opaque if needed
|
||||
const qreal opacity = Config::self().draggedWindowOpacity();
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
m_floatingWindow->setWindowOpacity(1);
|
||||
}
|
||||
|
||||
void WindowBeingDragged::init()
|
||||
|
||||
@@ -14,245 +14,24 @@
|
||||
#include "DragController_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QRubberBand>
|
||||
|
||||
#define INDICATOR_WIDTH 40
|
||||
#define OUTTER_INDICATOR_MARGIN 10
|
||||
//#define KDDOCKWIDGETS_RUBBERBAND_IS_TOPLEVEL 1
|
||||
#include "Config.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "ClassicIndicatorsWindow_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
class IndicatorWindow;
|
||||
}
|
||||
|
||||
void Indicator::paintEvent(QPaintEvent *)
|
||||
static IndicatorWindow* createIndicatorWindow(ClassicIndicators *classicIndicators)
|
||||
{
|
||||
QPainter p(this);
|
||||
if (m_hovered)
|
||||
p.drawImage(rect(), m_imageActive, rect());
|
||||
else
|
||||
p.drawImage(rect(), m_image, rect());
|
||||
|
||||
}
|
||||
|
||||
void Indicator::setHovered(bool hovered)
|
||||
{
|
||||
if (hovered != m_hovered) {
|
||||
m_hovered = hovered;
|
||||
update();
|
||||
if (hovered) {
|
||||
q->setDropLocation(m_dropLocation);
|
||||
} else if (q->currentDropLocation() == m_dropLocation) {
|
||||
q->setDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString Indicator::iconName(bool active) const
|
||||
{
|
||||
QString suffix = active ? QStringLiteral("_active")
|
||||
: QString();
|
||||
|
||||
QString name;
|
||||
switch (m_dropLocation) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
name = QStringLiteral("center");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
name = QStringLiteral("inner_left");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
name = QStringLiteral("inner_right");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
name = QStringLiteral("inner_bottom");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
name = QStringLiteral("inner_top");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
name = QStringLiteral("outter_left");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
name = QStringLiteral("outter_bottom");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
name = QStringLiteral("outter_right");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
name = QStringLiteral("outter_top");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_None:
|
||||
return QString();
|
||||
}
|
||||
|
||||
return name + suffix;
|
||||
}
|
||||
|
||||
QString Indicator::iconFileName(bool active) const
|
||||
{
|
||||
const QString name = iconName(active);
|
||||
return KDDockWidgets::windowManagerHasTranslucency() ? QStringLiteral(":/img/classic_indicators/%1.png").arg(name)
|
||||
: QStringLiteral(":/img/classic_indicators/opaque/%1.png").arg(name);
|
||||
}
|
||||
|
||||
IndicatorWindow::IndicatorWindow(ClassicIndicators *classicIndicators_, QWidget *)
|
||||
: QWidget(nullptr, Qt::Tool | Qt::BypassWindowManagerHint)
|
||||
, classicIndicators(classicIndicators_)
|
||||
, m_center(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Center)) // Each indicator is not a top-level. Otherwise there's noticeable delay.
|
||||
, m_left(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Left))
|
||||
, m_right(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Right))
|
||||
, m_bottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Bottom))
|
||||
, m_top(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Top))
|
||||
, m_outterLeft(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterLeft))
|
||||
, m_outterRight(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterRight))
|
||||
, m_outterBottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterBottom))
|
||||
, m_outterTop(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterTop))
|
||||
{
|
||||
setWindowFlag(Qt::FramelessWindowHint, true);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
updatePosition();
|
||||
|
||||
m_indicators << m_center << m_left << m_right << m_top << m_bottom
|
||||
<< m_outterBottom << m_outterTop << m_outterLeft << m_outterRight;
|
||||
|
||||
setObjectName(QStringLiteral("_docks_IndicatorWindow_Overlay"));
|
||||
}
|
||||
|
||||
bool IndicatorWindow::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::Show) {
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
Indicator *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
{
|
||||
switch (loc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
return m_center;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
return m_left;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
return m_right;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
return m_bottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
return m_top;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
return m_outterLeft;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
return m_outterBottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
return m_outterRight;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
return m_outterTop;
|
||||
case DropIndicatorOverlayInterface::DropLocation_None:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IndicatorWindow::updateMask()
|
||||
{
|
||||
QRegion region;
|
||||
|
||||
if (!KDDockWidgets::windowManagerHasTranslucency()) {
|
||||
for (Indicator *indicator : qAsConst(m_indicators)) {
|
||||
if (indicator->isVisible())
|
||||
region = region.united(QRegion(indicator->geometry(), QRegion::Rectangle));
|
||||
}
|
||||
}
|
||||
|
||||
setMask(region);
|
||||
}
|
||||
|
||||
void IndicatorWindow::resizeEvent(QResizeEvent *ev)
|
||||
{
|
||||
QWidget::resizeEvent(ev);
|
||||
updatePositions();
|
||||
}
|
||||
|
||||
void IndicatorWindow::updateIndicatorVisibility(bool visible)
|
||||
{
|
||||
Frame *hoveredFrame = classicIndicators->m_hoveredFrame;
|
||||
const bool isTheOnlyFrame = hoveredFrame && hoveredFrame->isTheOnlyFrame();
|
||||
|
||||
const bool innerShouldBeVisible = visible && hoveredFrame;
|
||||
const bool outterShouldBeVisible = visible && !isTheOnlyFrame;
|
||||
|
||||
for (Indicator *indicator : { m_center, m_left, m_right, m_bottom, m_top })
|
||||
indicator->setVisible(innerShouldBeVisible);
|
||||
|
||||
for (Indicator *indicator : { m_outterTop, m_outterLeft, m_outterRight, m_outterBottom })
|
||||
indicator->setVisible(outterShouldBeVisible);
|
||||
|
||||
updateMask();
|
||||
}
|
||||
|
||||
void IndicatorWindow::hover(QPoint globalPos)
|
||||
{
|
||||
for (Indicator *indicator : qAsConst(m_indicators)) {
|
||||
if (indicator->isVisible())
|
||||
indicator->setHovered(indicator->rect().contains(indicator->mapFromGlobal(globalPos)));
|
||||
}
|
||||
}
|
||||
|
||||
void IndicatorWindow::updatePosition()
|
||||
{
|
||||
QRect rect = classicIndicators->rect();
|
||||
QPoint pos = classicIndicators->mapToGlobal(QPoint(0, 0));
|
||||
rect.moveTo(pos);
|
||||
setGeometry(rect);
|
||||
}
|
||||
|
||||
void IndicatorWindow::updatePositions()
|
||||
{
|
||||
QRect r = rect();
|
||||
const int indicatorWidth = m_outterBottom->width();
|
||||
const int halfIndicatorWidth = m_outterBottom->width() / 2;
|
||||
|
||||
m_outterLeft->move(r.x() + OUTTER_INDICATOR_MARGIN, r.center().y() - halfIndicatorWidth);
|
||||
m_outterBottom->move(r.center().x() - halfIndicatorWidth, r.y() + height() - indicatorWidth - OUTTER_INDICATOR_MARGIN);
|
||||
m_outterTop->move(r.center().x() - halfIndicatorWidth, r.y() + OUTTER_INDICATOR_MARGIN);
|
||||
m_outterRight->move(r.x() + width() - indicatorWidth - OUTTER_INDICATOR_MARGIN, r.center().y() - halfIndicatorWidth);
|
||||
Frame *hoveredFrame = classicIndicators->m_hoveredFrame;
|
||||
if (hoveredFrame) {
|
||||
QRect hoveredRect = hoveredFrame->QWidget::geometry();
|
||||
m_center->move(r.topLeft() + hoveredRect.center() - QPoint(halfIndicatorWidth, halfIndicatorWidth));
|
||||
m_top->move(m_center->pos() - QPoint(0, indicatorWidth + OUTTER_INDICATOR_MARGIN));
|
||||
m_right->move(m_center->pos() + QPoint(indicatorWidth + OUTTER_INDICATOR_MARGIN, 0));
|
||||
m_bottom->move(m_center->pos() + QPoint(0, indicatorWidth + OUTTER_INDICATOR_MARGIN));
|
||||
m_left->move(m_center->pos() - QPoint(indicatorWidth + OUTTER_INDICATOR_MARGIN, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Indicator::Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent, ClassicIndicators::DropLocation location)
|
||||
: QWidget(parent)
|
||||
, q(classicIndicators)
|
||||
, m_dropLocation(location)
|
||||
{
|
||||
m_image = QImage(iconFileName(/*active=*/ false)).scaled(INDICATOR_WIDTH, INDICATOR_WIDTH);
|
||||
m_imageActive = QImage(iconFileName(/*active=*/ true)).scaled(INDICATOR_WIDTH, INDICATOR_WIDTH);
|
||||
setFixedSize(m_image.size());
|
||||
setVisible(true);
|
||||
auto window = new IndicatorWindow(classicIndicators);
|
||||
window->setObjectName(QStringLiteral("_docks_IndicatorWindow_Overlay"));
|
||||
return window;
|
||||
}
|
||||
|
||||
ClassicIndicators::ClassicIndicators(DropArea *dropArea)
|
||||
: DropIndicatorOverlayInterface(dropArea) // Is parented on the drop-area, not a toplevel.
|
||||
, m_rubberBand(new QRubberBand(QRubberBand::Rectangle, rubberBandIsTopLevel() ? nullptr : dropArea))
|
||||
, m_indicatorWindow(new IndicatorWindow(this, /*parent=*/ nullptr)) // Top-level so the indicators can appear above the window being dragged.
|
||||
, m_rubberBand(Config::self().frameworkWidgetFactory()->createRubberBand(dropArea))
|
||||
, m_indicatorWindow(createIndicatorWindow(this))
|
||||
{
|
||||
setVisible(false);
|
||||
if (rubberBandIsTopLevel())
|
||||
m_rubberBand->setWindowOpacity(0.5);
|
||||
}
|
||||
|
||||
ClassicIndicators::~ClassicIndicators()
|
||||
@@ -260,20 +39,30 @@ ClassicIndicators::~ClassicIndicators()
|
||||
delete m_indicatorWindow;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::Type ClassicIndicators::indicatorType() const
|
||||
{
|
||||
return TypeClassic;
|
||||
}
|
||||
|
||||
void ClassicIndicators::hover(QPoint globalPos)
|
||||
void ClassicIndicators::hover_impl(QPoint globalPos)
|
||||
{
|
||||
m_indicatorWindow->hover(globalPos);
|
||||
}
|
||||
|
||||
QPoint ClassicIndicators::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
{
|
||||
Indicator *indicator = m_indicatorWindow->indicatorForLocation(loc);
|
||||
return indicator->mapToGlobal(indicator->rect().center());
|
||||
return m_indicatorWindow->posForIndicator(loc);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::innerIndicatorsVisible() const
|
||||
{
|
||||
return m_innerIndicatorsVisible;
|
||||
}
|
||||
|
||||
bool ClassicIndicators::outterIndicatorsVisible() const
|
||||
{
|
||||
return m_outterIndicatorsVisible;
|
||||
}
|
||||
|
||||
bool ClassicIndicators::onResize(QSize)
|
||||
{
|
||||
m_indicatorWindow->resize(window()->size());
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClassicIndicators::updateVisibility()
|
||||
@@ -281,29 +70,26 @@ void ClassicIndicators::updateVisibility()
|
||||
if (isHovered()) {
|
||||
m_indicatorWindow->updatePositions();
|
||||
m_indicatorWindow->setVisible(true);
|
||||
m_indicatorWindow->updateIndicatorVisibility(true);
|
||||
updateWindowPosition();
|
||||
updateIndicatorsVisibility(true);
|
||||
raiseIndicators();
|
||||
} else {
|
||||
m_rubberBand->setVisible(false);
|
||||
m_indicatorWindow->setVisible(false);
|
||||
m_indicatorWindow->updateIndicatorVisibility(false);
|
||||
updateIndicatorsVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicIndicators::showEvent(QShowEvent *e)
|
||||
void ClassicIndicators::updateIndicatorsVisibility(bool visible)
|
||||
{
|
||||
QWidget::showEvent(e);
|
||||
}
|
||||
Frame *hoveredFrame = m_hoveredFrame;
|
||||
const bool isTheOnlyFrame = hoveredFrame && hoveredFrame->isTheOnlyFrame();
|
||||
|
||||
void ClassicIndicators::hideEvent(QHideEvent *e)
|
||||
{
|
||||
QWidget::hideEvent(e);
|
||||
}
|
||||
m_innerIndicatorsVisible = visible && hoveredFrame;
|
||||
m_outterIndicatorsVisible = visible && !isTheOnlyFrame;
|
||||
|
||||
void ClassicIndicators::resizeEvent(QResizeEvent *ev)
|
||||
{
|
||||
QWidget::resizeEvent(ev);
|
||||
m_indicatorWindow->resize(window()->size());
|
||||
Q_EMIT innerIndicatorsVisibleChanged();
|
||||
Q_EMIT outterIndicatorsVisibleChanged();
|
||||
}
|
||||
|
||||
void ClassicIndicators::raiseIndicators()
|
||||
@@ -346,12 +132,8 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
|
||||
}
|
||||
|
||||
if (location == DropLocation_Center) {
|
||||
m_rubberBand->setGeometry(geometryForRubberband(m_hoveredFrame ? m_hoveredFrame->QWidget::geometry() : rect()));
|
||||
m_rubberBand->setGeometry(m_hoveredFrame ? m_hoveredFrame->QWidgetAdapter::geometry() : rect());
|
||||
m_rubberBand->setVisible(true);
|
||||
if (rubberBandIsTopLevel()) {
|
||||
m_rubberBand->raise();
|
||||
raiseIndicators();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -384,32 +166,14 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
|
||||
QRect rect = m_dropArea->rectForDrop(m_windowBeingDragged, multisplitterLocation,
|
||||
m_dropArea->itemForFrame(relativeToFrame));
|
||||
|
||||
m_rubberBand->setGeometry(geometryForRubberband(rect));
|
||||
m_rubberBand->setGeometry(rect);
|
||||
m_rubberBand->setVisible(true);
|
||||
if (rubberBandIsTopLevel()) {
|
||||
m_rubberBand->raise();
|
||||
raiseIndicators();
|
||||
}
|
||||
}
|
||||
|
||||
QRect ClassicIndicators::geometryForRubberband(QRect localRect) const
|
||||
void ClassicIndicators::updateWindowPosition()
|
||||
{
|
||||
if (!rubberBandIsTopLevel())
|
||||
return localRect;
|
||||
|
||||
QPoint topLeftLocal = localRect.topLeft();
|
||||
QPoint topLeftGlobal = m_dropArea->QWidget::mapToGlobal(topLeftLocal);
|
||||
|
||||
localRect.moveTopLeft(topLeftGlobal);
|
||||
|
||||
return localRect;
|
||||
}
|
||||
|
||||
bool ClassicIndicators::rubberBandIsTopLevel() const
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_RUBBERBAND_IS_TOPLEVEL
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
QRect rect = this->rect();
|
||||
QPoint pos = mapToGlobal(QPoint(0, 0));
|
||||
rect.moveTo(pos);
|
||||
m_indicatorWindow->setGeometry(rect);
|
||||
}
|
||||
|
||||
318
src/private/indicators/ClassicIndicatorsWindow.cpp
Normal file
318
src/private/indicators/ClassicIndicatorsWindow.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "ClassicIndicatorsWindow_p.h"
|
||||
#include "ClassicIndicators_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
|
||||
static QString iconName(DropIndicatorOverlayInterface::DropLocation loc, bool active)
|
||||
{
|
||||
QString suffix = active ? QStringLiteral("_active")
|
||||
: QString();
|
||||
|
||||
QString name;
|
||||
switch (loc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
name = QStringLiteral("center");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
name = QStringLiteral("inner_left");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
name = QStringLiteral("inner_right");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
name = QStringLiteral("inner_bottom");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
name = QStringLiteral("inner_top");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
name = QStringLiteral("outter_left");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
name = QStringLiteral("outter_bottom");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
name = QStringLiteral("outter_right");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
name = QStringLiteral("outter_top");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_None:
|
||||
return QString();
|
||||
}
|
||||
|
||||
return name + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#define INDICATOR_WIDTH 40
|
||||
#define OUTTER_INDICATOR_MARGIN 10
|
||||
|
||||
void Indicator::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
if (m_hovered)
|
||||
p.drawImage(rect(), m_imageActive, rect());
|
||||
else
|
||||
p.drawImage(rect(), m_image, rect());
|
||||
}
|
||||
|
||||
void Indicator::setHovered(bool hovered)
|
||||
{
|
||||
if (hovered != m_hovered) {
|
||||
m_hovered = hovered;
|
||||
update();
|
||||
if (hovered) {
|
||||
q->setDropLocation(m_dropLocation);
|
||||
} else if (q->currentDropLocation() == m_dropLocation) {
|
||||
q->setDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString Indicator::iconName(bool active) const
|
||||
{
|
||||
return KDDockWidgets::iconName(m_dropLocation, active);
|
||||
}
|
||||
|
||||
QString Indicator::iconFileName(bool active) const
|
||||
{
|
||||
const QString name = iconName(active);
|
||||
return KDDockWidgets::windowManagerHasTranslucency() ? QStringLiteral(":/img/classic_indicators/%1.png").arg(name)
|
||||
: QStringLiteral(":/img/classic_indicators/opaque/%1.png").arg(name);
|
||||
}
|
||||
|
||||
IndicatorWindow::IndicatorWindow(ClassicIndicators *classicIndicators_)
|
||||
: QWidget(nullptr, Qt::Tool | Qt::BypassWindowManagerHint)
|
||||
, classicIndicators(classicIndicators_)
|
||||
, m_center(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Center)) // Each indicator is not a top-level. Otherwise there's noticeable delay.
|
||||
, m_left(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Left))
|
||||
, m_right(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Right))
|
||||
, m_bottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Bottom))
|
||||
, m_top(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Top))
|
||||
, m_outterLeft(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterLeft))
|
||||
, m_outterRight(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterRight))
|
||||
, m_outterBottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterBottom))
|
||||
, m_outterTop(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterTop))
|
||||
{
|
||||
setWindowFlag(Qt::FramelessWindowHint, true);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
connect(classicIndicators, &ClassicIndicators::innerIndicatorsVisibleChanged,
|
||||
this, &IndicatorWindow::updateIndicatorVisibility);
|
||||
connect(classicIndicators, &ClassicIndicators::outterIndicatorsVisibleChanged,
|
||||
this, &IndicatorWindow::updateIndicatorVisibility);
|
||||
|
||||
m_indicators << m_center << m_left << m_right << m_top << m_bottom
|
||||
<< m_outterBottom << m_outterTop << m_outterLeft << m_outterRight;
|
||||
}
|
||||
|
||||
Indicator *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
{
|
||||
switch (loc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
return m_center;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
return m_left;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
return m_right;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
return m_bottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
return m_top;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
return m_outterLeft;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
return m_outterBottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
return m_outterRight;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
return m_outterTop;
|
||||
case DropIndicatorOverlayInterface::DropLocation_None:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IndicatorWindow::updateMask()
|
||||
{
|
||||
QRegion region;
|
||||
|
||||
if (!KDDockWidgets::windowManagerHasTranslucency()) {
|
||||
for (Indicator *indicator : qAsConst(m_indicators)) {
|
||||
if (indicator->isVisible())
|
||||
region = region.united(QRegion(indicator->geometry(), QRegion::Rectangle));
|
||||
}
|
||||
}
|
||||
|
||||
setMask(region);
|
||||
}
|
||||
|
||||
void IndicatorWindow::resizeEvent(QResizeEvent *ev)
|
||||
{
|
||||
QWidget::resizeEvent(ev);
|
||||
updatePositions();
|
||||
}
|
||||
|
||||
void IndicatorWindow::updateIndicatorVisibility()
|
||||
{
|
||||
for (Indicator *indicator : { m_center, m_left, m_right, m_bottom, m_top })
|
||||
indicator->setVisible(classicIndicators->innerIndicatorsVisible());
|
||||
|
||||
for (Indicator *indicator : { m_outterTop, m_outterLeft, m_outterRight, m_outterBottom })
|
||||
indicator->setVisible(classicIndicators->outterIndicatorsVisible());
|
||||
|
||||
updateMask();
|
||||
}
|
||||
|
||||
QPoint IndicatorWindow::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
{
|
||||
Indicator *indicator = indicatorForLocation(loc);
|
||||
return indicator->mapToGlobal(indicator->rect().center());
|
||||
}
|
||||
|
||||
void IndicatorWindow::hover(QPoint globalPos)
|
||||
{
|
||||
for (Indicator *indicator : qAsConst(m_indicators)) {
|
||||
if (indicator->isVisible())
|
||||
indicator->setHovered(indicator->rect().contains(indicator->mapFromGlobal(globalPos)));
|
||||
}
|
||||
}
|
||||
|
||||
void IndicatorWindow::updatePositions()
|
||||
{
|
||||
QRect r = rect();
|
||||
const int indicatorWidth = m_outterBottom->width();
|
||||
const int halfIndicatorWidth = m_outterBottom->width() / 2;
|
||||
|
||||
m_outterLeft->move(r.x() + OUTTER_INDICATOR_MARGIN, r.center().y() - halfIndicatorWidth);
|
||||
m_outterBottom->move(r.center().x() - halfIndicatorWidth, r.y() + height() - indicatorWidth - OUTTER_INDICATOR_MARGIN);
|
||||
m_outterTop->move(r.center().x() - halfIndicatorWidth, r.y() + OUTTER_INDICATOR_MARGIN);
|
||||
m_outterRight->move(r.x() + width() - indicatorWidth - OUTTER_INDICATOR_MARGIN, r.center().y() - halfIndicatorWidth);
|
||||
Frame *hoveredFrame = classicIndicators->m_hoveredFrame;
|
||||
if (hoveredFrame) {
|
||||
QRect hoveredRect = hoveredFrame->QWidget::geometry();
|
||||
m_center->move(r.topLeft() + hoveredRect.center() - QPoint(halfIndicatorWidth, halfIndicatorWidth));
|
||||
m_top->move(m_center->pos() - QPoint(0, indicatorWidth + OUTTER_INDICATOR_MARGIN));
|
||||
m_right->move(m_center->pos() + QPoint(indicatorWidth + OUTTER_INDICATOR_MARGIN, 0));
|
||||
m_bottom->move(m_center->pos() + QPoint(0, indicatorWidth + OUTTER_INDICATOR_MARGIN));
|
||||
m_left->move(m_center->pos() - QPoint(indicatorWidth + OUTTER_INDICATOR_MARGIN, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Indicator::Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent, ClassicIndicators::DropLocation location)
|
||||
: QWidget(parent)
|
||||
, q(classicIndicators)
|
||||
, m_dropLocation(location)
|
||||
{
|
||||
m_image = QImage(iconFileName(/*active=*/ false)).scaled(INDICATOR_WIDTH, INDICATOR_WIDTH);
|
||||
m_imageActive = QImage(iconFileName(/*active=*/ true)).scaled(INDICATOR_WIDTH, INDICATOR_WIDTH);
|
||||
setFixedSize(m_image.size());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <QQmlContext>
|
||||
|
||||
IndicatorWindow::IndicatorWindow(KDDockWidgets::ClassicIndicators *classicIndicators)
|
||||
: QQuickView()
|
||||
, m_classicIndicators(classicIndicators)
|
||||
{
|
||||
setColor(Qt::transparent);
|
||||
setFlags(flags() | Qt::FramelessWindowHint);
|
||||
rootContext()->setContextProperty(QStringLiteral("_window"), QVariant::fromValue<QObject*>(this));
|
||||
setSource(QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/ClassicIndicatorsOverlay.qml")));
|
||||
}
|
||||
|
||||
void IndicatorWindow::hover(QPoint pt)
|
||||
{
|
||||
QQuickItem *item = indicatorForPos(pt);
|
||||
if (item) {
|
||||
const auto loc = DropIndicatorOverlayInterface::DropLocation(item->property("indicatorType").toInt());
|
||||
classicIndicators()->setDropLocation(loc);
|
||||
} else {
|
||||
classicIndicators()->setDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
}
|
||||
}
|
||||
|
||||
QQuickItem *IndicatorWindow::indicatorForPos(QPoint pt) const
|
||||
{
|
||||
const QVector<QQuickItem *> indicators = indicatorItems();
|
||||
Q_ASSERT(indicators.size() == 9);
|
||||
|
||||
for (QQuickItem *item : indicators) {
|
||||
QRect rect(0, 0, int(item->width()), int(item->height()));
|
||||
rect.moveTopLeft(item->mapToGlobal(QPointF(0, 0)).toPoint());
|
||||
if (rect.contains(pt))
|
||||
return item;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IndicatorWindow::updatePositions()
|
||||
{
|
||||
// Not needed to implement, the Indicators use QML anchors
|
||||
}
|
||||
|
||||
QPoint IndicatorWindow::posForIndicator(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation) const
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
return {};
|
||||
}
|
||||
|
||||
QString IndicatorWindow::iconName(int loc, bool active) const
|
||||
{
|
||||
return KDDockWidgets::iconName(DropIndicatorOverlayInterface::DropLocation(loc), active);
|
||||
}
|
||||
|
||||
ClassicIndicators *IndicatorWindow::classicIndicators() const
|
||||
{
|
||||
return m_classicIndicators;
|
||||
}
|
||||
|
||||
QVector<QQuickItem *> IndicatorWindow::indicatorItems() const
|
||||
{
|
||||
QVector<QQuickItem *> indicators;
|
||||
indicators.reserve(9);
|
||||
|
||||
QQuickItem *root = rootObject();
|
||||
const QList<QQuickItem*> items = root->childItems();
|
||||
for (QQuickItem *item : items) {
|
||||
if (QString::fromLatin1(item->metaObject()->className()).startsWith(QLatin1String("ClassicIndicator_QMLTYPE"))) {
|
||||
indicators.push_back(item);
|
||||
} else if (item->objectName() == QLatin1String("innerIndicators")) {
|
||||
const QList<QQuickItem*> innerIndicators = item->childItems();
|
||||
for (QQuickItem *innerItem : innerIndicators) {
|
||||
if (QString::fromLatin1(innerItem->metaObject()->className()).startsWith(QLatin1String("ClassicIndicator_QMLTYPE"))) {
|
||||
indicators.push_back(innerItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return indicators;
|
||||
}
|
||||
|
||||
#endif // QtQuick
|
||||
108
src/private/indicators/ClassicIndicatorsWindow_p.h
Normal file
108
src/private/indicators/ClassicIndicatorsWindow_p.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef KD_INDICATORS_CLASSICINDICATORS_WINDOW_P_H
|
||||
#define KD_INDICATORS_CLASSICINDICATORS_WINDOW_P_H
|
||||
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
|
||||
#include <QImage>
|
||||
#include <QWidget>
|
||||
#include <QResizeEvent>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class Indicator;
|
||||
class ClassicIndicators;
|
||||
|
||||
class IndicatorWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *classicIndicators);
|
||||
void hover(QPoint globalPos);
|
||||
void updatePositions();
|
||||
QPoint posForIndicator(DropIndicatorOverlayInterface::DropLocation) const;
|
||||
private:
|
||||
void updateIndicatorVisibility();
|
||||
void resizeEvent(QResizeEvent *ev) override;
|
||||
|
||||
// When the compositor doesn't support translucency, we use a mask instead
|
||||
// Only happens on Linux
|
||||
void updateMask();
|
||||
|
||||
Indicator *indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const;
|
||||
|
||||
ClassicIndicators *const classicIndicators;
|
||||
Indicator *const m_center;
|
||||
Indicator *const m_left;
|
||||
Indicator *const m_right;
|
||||
Indicator *const m_bottom;
|
||||
Indicator *const m_top;
|
||||
Indicator *const m_outterLeft;
|
||||
Indicator *const m_outterRight;
|
||||
Indicator *const m_outterBottom;
|
||||
Indicator *const m_outterTop;
|
||||
QVector<Indicator *> m_indicators;
|
||||
};
|
||||
|
||||
class Indicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QList<Indicator *> List;
|
||||
explicit Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent,
|
||||
DropIndicatorOverlayInterface::DropLocation location);
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
void setHovered(bool hovered);
|
||||
QString iconName(bool active) const;
|
||||
QString iconFileName(bool active) const;
|
||||
|
||||
QImage m_image;
|
||||
QImage m_imageActive;
|
||||
ClassicIndicators *const q;
|
||||
bool m_hovered = false;
|
||||
const DropIndicatorOverlayInterface::DropLocation m_dropLocation;
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <QQuickView>
|
||||
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
class ClassicIndicators;
|
||||
|
||||
class IndicatorWindow : public QQuickView
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(KDDockWidgets::ClassicIndicators* classicIndicators READ classicIndicators CONSTANT)
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *);
|
||||
void hover(QPoint);
|
||||
void updatePositions();
|
||||
QPoint posForIndicator(DropIndicatorOverlayInterface::DropLocation) const;
|
||||
Q_INVOKABLE QString iconName(int loc, bool active) const;
|
||||
KDDockWidgets::ClassicIndicators* classicIndicators() const;
|
||||
private:
|
||||
QQuickItem *indicatorForPos(QPoint) const;
|
||||
QVector<QQuickItem*> indicatorItems() const;
|
||||
ClassicIndicators *const m_classicIndicators;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -12,92 +12,47 @@
|
||||
#ifndef KD_INDICATORS_CLASSICINDICATORS_P_H
|
||||
#define KD_INDICATORS_CLASSICINDICATORS_P_H
|
||||
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QRubberBand;
|
||||
QT_END_NAMESPACE
|
||||
#include "../DropIndicatorOverlayInterface_p.h"
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class IndicatorWindow;
|
||||
class Indicator;
|
||||
|
||||
class ClassicIndicators : public DropIndicatorOverlayInterface
|
||||
class DOCKS_EXPORT ClassicIndicators : public DropIndicatorOverlayInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool innerIndicatorsVisible READ innerIndicatorsVisible NOTIFY innerIndicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool outterIndicatorsVisible READ outterIndicatorsVisible NOTIFY outterIndicatorsVisibleChanged)
|
||||
|
||||
public:
|
||||
explicit ClassicIndicators(DropArea *dropArea);
|
||||
~ClassicIndicators() override;
|
||||
Type indicatorType() const override;
|
||||
void hover(QPoint globalPos) override;
|
||||
void hover_impl(QPoint globalPos) override;
|
||||
QPoint posForIndicator(DropLocation) const override;
|
||||
|
||||
bool innerIndicatorsVisible() const;
|
||||
bool outterIndicatorsVisible() const;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *) override;
|
||||
void hideEvent(QHideEvent *) override;
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
bool onResize(QSize newSize) override;
|
||||
void updateVisibility() override;
|
||||
Q_SIGNALS:
|
||||
void innerIndicatorsVisibleChanged();
|
||||
void outterIndicatorsVisibleChanged();
|
||||
private:
|
||||
friend class KDDockWidgets::Indicator;
|
||||
friend class KDDockWidgets::IndicatorWindow;
|
||||
void updateIndicatorsVisibility(bool visible);
|
||||
void raiseIndicators();
|
||||
void setDropLocation(DropLocation);
|
||||
QRect geometryForRubberband(QRect localRect) const;
|
||||
bool rubberBandIsTopLevel() const;
|
||||
void updateWindowPosition();
|
||||
|
||||
QRubberBand *const m_rubberBand;
|
||||
QWidgetOrQuick *const m_rubberBand;
|
||||
IndicatorWindow *const m_indicatorWindow;
|
||||
};
|
||||
|
||||
class IndicatorWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *classicIndicators, QWidget * = nullptr);
|
||||
void hover(QPoint globalPos);
|
||||
|
||||
void updatePosition();
|
||||
void updatePositions();
|
||||
void updateIndicatorVisibility(bool visible);
|
||||
void resizeEvent(QResizeEvent *ev) override;
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
Indicator *indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const;
|
||||
|
||||
// When the compositor doesn't support translucency, we use a mask instead
|
||||
// Only happens on Linux
|
||||
void updateMask();
|
||||
|
||||
ClassicIndicators *const classicIndicators;
|
||||
Indicator *const m_center;
|
||||
Indicator *const m_left;
|
||||
Indicator *const m_right;
|
||||
Indicator *const m_bottom;
|
||||
Indicator *const m_top;
|
||||
Indicator *const m_outterLeft;
|
||||
Indicator *const m_outterRight;
|
||||
Indicator *const m_outterBottom;
|
||||
Indicator *const m_outterTop;
|
||||
QVector<Indicator *> m_indicators;
|
||||
};
|
||||
|
||||
class Indicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QList<Indicator *> List;
|
||||
explicit Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent, ClassicIndicators::DropLocation location);
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
void setHovered(bool hovered);
|
||||
QString iconName(bool active) const;
|
||||
QString iconFileName(bool active) const;
|
||||
|
||||
QImage m_image;
|
||||
QImage m_imageActive;
|
||||
ClassicIndicators *const q;
|
||||
bool m_hovered = false;
|
||||
const ClassicIndicators::DropLocation m_dropLocation;
|
||||
bool m_innerIndicatorsVisible = false;
|
||||
bool m_outterIndicatorsVisible = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
182
src/private/indicators/SegmentedIndicators.cpp
Normal file
182
src/private/indicators/SegmentedIndicators.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "SegmentedIndicators_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
#define SEGMENT_GIRTH 50
|
||||
#define SEGMENT_PEN_WIDTH 4
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
|
||||
SegmentedIndicators::SegmentedIndicators(DropArea *dropArea)
|
||||
: DropIndicatorOverlayInterface(dropArea)
|
||||
{
|
||||
// If the app didn't choose opacity then we choose a suitable default value.
|
||||
// ClassicIndicators works fine with an opaque dragged window because the indicators have higher Z,
|
||||
// However for SegmentedIndicators the indicators are in the main window, so lower Z. Make the
|
||||
// dragged window translucent a bit, so we can see the indicators
|
||||
const bool userChoseOpacity = !qIsNaN(Config::self().draggedWindowOpacity());
|
||||
if (!userChoseOpacity)
|
||||
Config::self().setDraggedWindowOpacity(0.7);
|
||||
}
|
||||
|
||||
SegmentedIndicators::~SegmentedIndicators()
|
||||
{
|
||||
}
|
||||
|
||||
void SegmentedIndicators::hover_impl(QPoint pt)
|
||||
{
|
||||
m_hoveredPt = mapFromGlobal(pt);
|
||||
updateSegments();
|
||||
setCurrentDropLocation(dropLocationForPos(m_hoveredPt));
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation SegmentedIndicators::dropLocationForPos(QPoint pos) const
|
||||
{
|
||||
for (auto it = m_segments.cbegin(), end = m_segments.cend(); it != end; ++it) {
|
||||
if (it.value().containsPoint(pos, Qt::OddEvenFill)) {
|
||||
return it.key();
|
||||
}
|
||||
}
|
||||
|
||||
return DropLocation_None;
|
||||
}
|
||||
|
||||
void SegmentedIndicators::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
drawSegments(&p);
|
||||
}
|
||||
|
||||
QVector<QPolygon> SegmentedIndicators::segmentsForRect(QRect r, QPolygon ¢er, bool useOffset) const
|
||||
{
|
||||
const int penWidth = SEGMENT_PEN_WIDTH;
|
||||
const int halfPenWidth = penWidth / 2;
|
||||
|
||||
const int l = SEGMENT_GIRTH;
|
||||
const int top = (r.y() == 0 && useOffset) ? l : r.y();
|
||||
const int left = (r.x() == 0 && useOffset) ? l : r.x();
|
||||
const int right = (rect().right() == r.right() && useOffset) ? r.right() - l : r.right();
|
||||
const int bottom = (rect().bottom() == r.bottom() && useOffset) ? r.bottom() - l : r.bottom();
|
||||
const QPoint topLeft = { left + halfPenWidth, top + halfPenWidth };
|
||||
const QPoint topRight = { right, top + halfPenWidth };
|
||||
const QPoint bottomLeft = { left + halfPenWidth, bottom };
|
||||
const QPoint bottomRight = { right, bottom };
|
||||
|
||||
const QVector<QPoint> leftPoints = { topLeft, bottomLeft,
|
||||
QPoint(left, bottom) + QPoint(l, -l),
|
||||
topLeft + QPoint(l, l), topLeft
|
||||
};
|
||||
|
||||
const QVector<QPoint> rightPoints = { topRight, bottomRight,
|
||||
bottomRight + QPoint(-l, -l),
|
||||
topRight + QPoint(-l, l)
|
||||
};
|
||||
|
||||
const QVector<QPoint> topPoints = { topLeft, topRight,
|
||||
topRight + QPoint(-l, l),
|
||||
topLeft + QPoint(l, l)
|
||||
};
|
||||
|
||||
const QVector<QPoint> bottomPoints = { bottomLeft, bottomRight,
|
||||
bottomRight + QPoint(-l, -l),
|
||||
bottomLeft + QPoint(l, -l)
|
||||
};
|
||||
|
||||
{
|
||||
|
||||
QPolygon bounds = QVector<QPoint> { topLeft + QPoint(l, l),
|
||||
topRight + QPoint(-l, l),
|
||||
bottomRight + QPoint(-l, -l),
|
||||
bottomLeft + QPoint(l, -l)
|
||||
};
|
||||
const int maxWidth = bounds.boundingRect().width();
|
||||
const QPoint centerPos = bounds.boundingRect().center();
|
||||
|
||||
// Build the center
|
||||
const int indicatorWidth = qMin(300, maxWidth - 100);
|
||||
const int indicatorHeight = qMin(160, int(indicatorWidth * 0.60));
|
||||
const int tabWidth = int(indicatorWidth * 0.267);
|
||||
const int tabHeight = int(indicatorHeight * 0.187);
|
||||
const int centerRectLeft = centerPos.x() - indicatorWidth / 2;
|
||||
const int centerRectRight = centerPos.x() + indicatorWidth / 2;
|
||||
const int centerRectBottom = centerPos.y() + indicatorHeight / 2;
|
||||
const int centerRectTop = centerPos.y() - indicatorHeight / 2;
|
||||
|
||||
|
||||
center = QVector<QPoint> { { centerRectLeft, centerRectTop },
|
||||
{ centerRectLeft + tabWidth, centerRectTop },
|
||||
{ centerRectLeft + tabWidth, centerRectTop + tabHeight },
|
||||
{ centerRectRight, centerRectTop + tabHeight },
|
||||
{ centerRectRight, centerRectBottom },
|
||||
{ centerRectLeft, centerRectBottom },
|
||||
};
|
||||
}
|
||||
|
||||
return { leftPoints, topPoints, rightPoints, bottomPoints };
|
||||
}
|
||||
|
||||
void SegmentedIndicators::updateSegments()
|
||||
{
|
||||
m_segments.clear();
|
||||
|
||||
const bool hasMultipleFrames = m_dropArea->count() > 1;
|
||||
const bool needsInnerIndicators = hoveredFrameRect().isValid();
|
||||
const bool needsOutterIndicators = hasMultipleFrames || !needsInnerIndicators;
|
||||
QPolygon center;
|
||||
|
||||
if (needsInnerIndicators) {
|
||||
const bool useOffset = needsOutterIndicators;
|
||||
auto segments = segmentsForRect(hoveredFrameRect(), /*by-ref*/center, useOffset);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
m_segments.insert(DropLocation(DropLocation_Left + i), segments[i]);
|
||||
|
||||
m_segments.insert(DropLocation_Center, center);
|
||||
}
|
||||
|
||||
if (needsOutterIndicators) {
|
||||
auto segments = segmentsForRect(rect(), /*unused*/center);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
m_segments.insert(DropLocation(DropLocation_OutterLeft + i), segments[i]);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void SegmentedIndicators::drawSegments(QPainter *p)
|
||||
{
|
||||
for (int i = DropLocation_First; i <= DropLocation_Last; ++i)
|
||||
drawSegment(p, m_segments.value(DropLocation(i)));
|
||||
}
|
||||
|
||||
void SegmentedIndicators::drawSegment(QPainter *p, const QPolygon &segment)
|
||||
{
|
||||
if (segment.isEmpty())
|
||||
return;
|
||||
|
||||
QPen pen(Qt::black);
|
||||
pen.setWidth(SEGMENT_PEN_WIDTH);
|
||||
p->setPen(pen);
|
||||
QColor brush(0xbb, 0xd5, 0xee, 200);
|
||||
|
||||
if (segment.containsPoint(m_hoveredPt, Qt::OddEvenFill))
|
||||
brush = QColor(0x3574c5);
|
||||
|
||||
p->setBrush(brush);
|
||||
p->drawPolygon(segment);
|
||||
}
|
||||
46
src/private/indicators/SegmentedIndicators_p.h
Normal file
46
src/private/indicators/SegmentedIndicators_p.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef KD_SEGMENTED_INDICATORS_P_H
|
||||
#define KD_SEGMENTED_INDICATORS_P_H
|
||||
|
||||
#include "../DropIndicatorOverlayInterface_p.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QPolygon>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class DOCKS_EXPORT SegmentedIndicators : public DropIndicatorOverlayInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SegmentedIndicators(DropArea *dropArea);
|
||||
~SegmentedIndicators() override;
|
||||
void hover_impl(QPoint globalPos) override;
|
||||
|
||||
DropLocation dropLocationForPos(QPoint pos) const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
private:
|
||||
QVector<QPolygon> segmentsForRect(QRect, QPolygon ¢er, bool useOffset = false) const;
|
||||
void updateSegments();
|
||||
void drawSegments(QPainter *p);
|
||||
void drawSegment(QPainter *p, const QPolygon &segment);
|
||||
QPoint m_hoveredPt = {};
|
||||
QHash<DropLocation, QPolygon> m_segments;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -70,8 +70,6 @@ public:
|
||||
virtual void show() = 0;
|
||||
virtual void hide() = 0;
|
||||
virtual void update() = 0;
|
||||
virtual QPoint mapFromGlobal(QPoint) const = 0;
|
||||
virtual QPoint mapToGlobal(QPoint) const = 0;
|
||||
|
||||
QSize size() const {
|
||||
return geometry().size();
|
||||
|
||||
@@ -121,18 +121,6 @@ void Widget_quick::update()
|
||||
m_thisWidget->update();
|
||||
}
|
||||
|
||||
QPoint Widget_quick::mapFromGlobal(QPoint p) const
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "Implement me!";
|
||||
return p;
|
||||
}
|
||||
|
||||
QPoint Widget_quick::mapToGlobal(QPoint p) const
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "Implement me!";
|
||||
return p;
|
||||
}
|
||||
|
||||
QQuickItem *Widget_quick::createQQuickItem(const QString &filename, QQuickItem *parent) const
|
||||
{
|
||||
auto p = parent;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
#include <QQuickItem>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQuickItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
///@file
|
||||
///@brief A Layouting::Widget that's deals in QQuickItem
|
||||
@@ -52,8 +54,6 @@ public:
|
||||
void setWidth(int width) override;
|
||||
void setHeight(int height) override;
|
||||
void update() override;
|
||||
QPoint mapFromGlobal(QPoint p) const override;
|
||||
QPoint mapToGlobal(QPoint p) const override;
|
||||
|
||||
static QSize widgetMinSize(const QWidget *w);
|
||||
|
||||
|
||||
@@ -121,13 +121,3 @@ void Widget_qwidget::update()
|
||||
{
|
||||
m_thisWidget->update();
|
||||
}
|
||||
|
||||
QPoint Widget_qwidget::mapFromGlobal(QPoint p) const
|
||||
{
|
||||
return m_thisWidget->mapFromGlobal(p);
|
||||
}
|
||||
|
||||
QPoint Widget_qwidget::mapToGlobal(QPoint p) const
|
||||
{
|
||||
return m_thisWidget->mapToGlobal(p);
|
||||
}
|
||||
|
||||
@@ -55,8 +55,6 @@ public:
|
||||
void setWidth(int width) override;
|
||||
void setHeight(int height) override;
|
||||
void update() override;
|
||||
QPoint mapFromGlobal(QPoint p) const override;
|
||||
QPoint mapToGlobal(QPoint p) const override;
|
||||
|
||||
private:
|
||||
QWidget *const m_thisWidget;
|
||||
|
||||
@@ -22,17 +22,36 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class QuickView : public QQuickView
|
||||
{
|
||||
using QQuickView::QQuickView;
|
||||
|
||||
bool event(QEvent *ev) override
|
||||
{
|
||||
if (ev->type() == QEvent::FocusAboutToChange) {
|
||||
// qquickwindow.cpp::event(FocusAboutToChange) removes the item grabber. Inibit that
|
||||
return true;
|
||||
}
|
||||
|
||||
return QQuickView::event(ev);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
FloatingWindowQuick::FloatingWindowQuick(MainWindowBase *parent)
|
||||
: FloatingWindow(parent)
|
||||
, m_quickWindow(new QQuickView(Config::self().qmlEngine(), nullptr))
|
||||
, m_quickWindow(new QuickView(Config::self().qmlEngine(), nullptr))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
FloatingWindowQuick::FloatingWindowQuick(Frame *frame, MainWindowBase *parent)
|
||||
: FloatingWindow(frame, parent)
|
||||
, m_quickWindow(new QQuickView(Config::self().qmlEngine(), nullptr))
|
||||
, m_quickWindow(new QuickView(Config::self().qmlEngine(), nullptr))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
MainWindowQuick::MainWindowQuick(const QString &uniqueName, QWidgetAdapter *parent)
|
||||
: MainWindowBase(uniqueName, MainWindowOption_None, parent)
|
||||
MainWindowQuick::MainWindowQuick(const QString &uniqueName, MainWindowOptions options,
|
||||
QWidgetAdapter *parent)
|
||||
: MainWindowBase(uniqueName, options, parent)
|
||||
{
|
||||
QWidgetAdapter::makeItemFillParent(this);
|
||||
QWidgetAdapter::makeItemFillParent(dropArea());
|
||||
|
||||
@@ -24,7 +24,9 @@ class DOCKS_EXPORT MainWindowQuick : public MainWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindowQuick(const QString &uniqueName, QWidgetAdapter *parent);
|
||||
explicit MainWindowQuick(const QString &uniqueName,
|
||||
MainWindowOptions options = MainWindowOption_HasCentralFrame,
|
||||
QWidgetAdapter *parent = nullptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -31,5 +31,5 @@ void MainWindowWrapper::init(const QString &uniqueName)
|
||||
return;
|
||||
}
|
||||
|
||||
m_mainWindow = new MainWindowQuick(uniqueName, this);
|
||||
m_mainWindow = new MainWindowQuick(uniqueName, MainWindowOption_None, this);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,12 @@ void QWidgetAdapter::raiseAndActivate()
|
||||
}
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setWindowOpacity(qreal level)
|
||||
{
|
||||
if (QWindow *w = windowHandle())
|
||||
w->setOpacity(level);
|
||||
}
|
||||
|
||||
bool QWidgetAdapter::onResize(QSize) { return false; }
|
||||
void QWidgetAdapter::onLayoutRequest() {}
|
||||
void QWidgetAdapter::onMousePress() {}
|
||||
@@ -176,6 +182,14 @@ bool QWidgetAdapter::isMaximized() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KDDockWidgets::QWidgetAdapter::isActiveWindow() const
|
||||
{
|
||||
if (QWindow *w = windowHandle())
|
||||
return w->isActive();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QWidgetAdapter::showMaximized()
|
||||
{
|
||||
if (QWindow *w = windowHandle())
|
||||
@@ -216,6 +230,28 @@ QWidgetAdapter *QWidgetAdapter::parentWidget() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QPoint QWidgetAdapter::mapToGlobal(QPoint pt) const
|
||||
{
|
||||
return QQuickItem::mapToGlobal(pt).toPoint();
|
||||
}
|
||||
|
||||
QPoint QWidgetAdapter::mapFromGlobal(QPoint pt) const
|
||||
{
|
||||
return QQuickItem::mapFromGlobal(pt).toPoint();
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setWindowTitle(const QString &title)
|
||||
{
|
||||
if (QWindow *window = windowHandle())
|
||||
window->setTitle(title);
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setWindowIcon(const QIcon &icon)
|
||||
{
|
||||
if (QWindow *window = windowHandle())
|
||||
window->setIcon(icon);
|
||||
}
|
||||
|
||||
void QWidgetAdapter::close()
|
||||
{
|
||||
QCloseEvent ev;
|
||||
@@ -323,6 +359,16 @@ void QWidgetAdapter::setFlag(Qt::WindowType f, bool on)
|
||||
}
|
||||
}
|
||||
|
||||
Qt::FocusPolicy QWidgetAdapter::focusPolicy() const
|
||||
{
|
||||
return Qt::NoFocus;
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setFocusProxy(QQuickItem *)
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "Implement me";
|
||||
}
|
||||
|
||||
QQuickItem* KDDockWidgets::Private::widgetForWindow(QWindow *window)
|
||||
{
|
||||
if (!window)
|
||||
|
||||
@@ -89,7 +89,6 @@ public:
|
||||
QRect geometry() const;
|
||||
QRect rect() const;
|
||||
void show();
|
||||
void setEnabled(bool) {}
|
||||
void setFixedHeight(int);
|
||||
void setFixedWidth(int);
|
||||
void raise();
|
||||
@@ -114,18 +113,19 @@ public:
|
||||
void resize(QSize);
|
||||
bool isWindow() const { return parentItem() == nullptr; }
|
||||
bool isMaximized() const;
|
||||
bool isActiveWindow() const;
|
||||
void showMaximized();
|
||||
void showNormal();
|
||||
|
||||
QWindow *windowHandle() const;
|
||||
QWidgetAdapter *window() const;
|
||||
QWidgetAdapter *parentWidget() const;
|
||||
QPoint mapToGlobal(QPoint) const { return {}; }
|
||||
QPoint mapFromGlobal(QPoint) const { return {}; }
|
||||
QPoint mapToGlobal(QPoint pt) const;
|
||||
QPoint mapFromGlobal(QPoint) const;
|
||||
bool testAttribute(Qt::WidgetAttribute) { return false; }
|
||||
|
||||
void setWindowTitle(const QString &) {}
|
||||
void setWindowIcon(const QIcon &) {}
|
||||
void setWindowTitle(const QString &);
|
||||
void setWindowIcon(const QIcon &);
|
||||
void close();
|
||||
QQuickItem *childAt(QPoint) const;
|
||||
void move(int x, int y);
|
||||
@@ -134,9 +134,13 @@ public:
|
||||
void activateWindow();
|
||||
void setSizePolicy(QSizePolicy);
|
||||
QSizePolicy sizePolicy() const;
|
||||
Qt::FocusPolicy focusPolicy() const;
|
||||
void setFocusPolicy(Qt::FocusPolicy) {}
|
||||
void setFocusProxy(QQuickItem*);
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
Qt::WindowFlags windowFlags() const;
|
||||
void setWindowOpacity(qreal);
|
||||
|
||||
static QQuickItem *createItem(QQmlEngine *, const QString &filename);
|
||||
static void makeItemFillParent(QQuickItem *item);
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#include "QmlTypes.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "quick/MainWindowWrapper_p.h"
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "indicators/ClassicIndicators_p.h"
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QDebug>
|
||||
@@ -24,5 +26,8 @@ void KDDockWidgets::registerQmlTypes()
|
||||
qmlRegisterType<MainWindowWrapper>("com.kdab.dockwidgets", 1, 0, "MainWindow");
|
||||
|
||||
qmlRegisterUncreatableType<TitleBar>("com.kdab.dockwidgets", 1, 0, "TitleBar", QStringLiteral("Enum access only"));
|
||||
qmlRegisterUncreatableType<DropIndicatorOverlayInterface>("com.kdab.dockwidgets", 1, 0, "DropIndicatorOverlayInterface", QStringLiteral("Enum access only"));
|
||||
|
||||
qRegisterMetaType<DropArea*>();
|
||||
qRegisterMetaType<KDDockWidgets::ClassicIndicators*>();
|
||||
}
|
||||
|
||||
13
src/private/quick/qml/ClassicIndicator.qml
Normal file
13
src/private/quick/qml/ClassicIndicator.qml
Normal file
@@ -0,0 +1,13 @@
|
||||
import QtQuick 2.9
|
||||
import com.kdab.dockwidgets 1.0
|
||||
|
||||
Image {
|
||||
id: root
|
||||
|
||||
property int indicatorType: DropIndicatorOverlayInterface.DropLocation_None
|
||||
readonly property bool isHovered: _window.classicIndicators.currentDropLocation === indicatorType
|
||||
|
||||
source: "qrc:/img/classic_indicators/" + _window.iconName(indicatorType, isHovered) + ".png";
|
||||
width: 64
|
||||
height: 64
|
||||
}
|
||||
115
src/private/quick/qml/ClassicIndicatorsOverlay.qml
Normal file
115
src/private/quick/qml/ClassicIndicatorsOverlay.qml
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
import com.kdab.dockwidgets 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
readonly property int outterMargin: 10
|
||||
readonly property int innerMargin: 10
|
||||
readonly property QtObject innerIndicators: innerIndicators
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterLeft
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: outterMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterRight
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: outterMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterTop
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: outterMargin
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterBottom
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: outterMargin
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: innerIndicators
|
||||
objectName: "innerIndicators"
|
||||
|
||||
x: _window.classicIndicators.hoveredFrameRect.x + (_window.classicIndicators.hoveredFrameRect.width / 2)
|
||||
y: _window.classicIndicators.hoveredFrameRect.y + (_window.classicIndicators.hoveredFrameRect.height / 2)
|
||||
|
||||
width: (centerIndicator * 3) + (2 * innerMargin)
|
||||
height: width
|
||||
visible: _window.classicIndicators.innerIndicatorsVisible
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Left
|
||||
anchors {
|
||||
right: centerIndicator.left
|
||||
rightMargin: innerMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
id: centerIndicator
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Center
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Right
|
||||
anchors {
|
||||
left: centerIndicator.right
|
||||
leftMargin: innerMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Top
|
||||
anchors {
|
||||
bottom: centerIndicator.top
|
||||
bottomMargin: innerMargin
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Bottom
|
||||
anchors {
|
||||
top: centerIndicator.bottom
|
||||
topMargin: innerMargin
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ void TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
|
||||
}
|
||||
|
||||
QPointer<Frame> oldFrame = dock->frame();
|
||||
insertDockWidget(index, dock, dock->icon(), dock->title());
|
||||
insertDockWidget(index, dock, dock->icon(DockWidgetBase::IconPlace::TabBar), dock->title());
|
||||
setCurrentDockWidget(index);
|
||||
|
||||
if (oldFrame && oldFrame->beingDeletedLater()) {
|
||||
|
||||
@@ -7,5 +7,7 @@
|
||||
<file>private/quick/qml/Separator.qml</file>
|
||||
<file>private/quick/qml/TitleBarBase.qml</file>
|
||||
<file>private/quick/qml/TitleBar.qml</file>
|
||||
<file>private/quick/qml/ClassicIndicatorsOverlay.qml</file>
|
||||
<file>private/quick/qml/ClassicIndicator.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*/
|
||||
|
||||
#include "Testing.h"
|
||||
#include "MainWindow.h"
|
||||
#include "DockRegistry_p.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
|
||||
#include "Testing.h"
|
||||
#include "utils.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "private/MultiSplitter_p.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QObject>
|
||||
#include <QApplication>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
using namespace KDDockWidgets::Tests;
|
||||
|
||||
class TestCommon : public QObject
|
||||
{
|
||||
@@ -43,7 +46,10 @@ private Q_SLOTS:
|
||||
|
||||
void TestCommon::tst_simple1()
|
||||
{
|
||||
// TODO
|
||||
// Simply create a MainWindow
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
m->multiSplitter()->checkSanity();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <QMenuBar>
|
||||
#include <QStyleFactory>
|
||||
#include <QCursor>
|
||||
#include <QLineEdit>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <Windows.h>
|
||||
@@ -266,42 +267,6 @@ static QWidget *createWidget(int minLength, const QString &objname = QString())
|
||||
return w;
|
||||
}
|
||||
|
||||
struct EnsureTopLevelsDeleted
|
||||
{
|
||||
EnsureTopLevelsDeleted()
|
||||
: m_originalFlags(Config::self().flags())
|
||||
, m_originalSeparatorThickness(Config::self().separatorThickness())
|
||||
{
|
||||
}
|
||||
|
||||
~EnsureTopLevelsDeleted()
|
||||
{
|
||||
if (topLevels().size() != 0) {
|
||||
qWarning() << "There's still top-level widgets present!" << topLevels();
|
||||
}
|
||||
|
||||
// Other cleanup, since we use this class everywhere
|
||||
Config::self().setDockWidgetFactoryFunc(nullptr);
|
||||
Config::self().setFlags(m_originalFlags);
|
||||
Config::self().setSeparatorThickness(m_originalSeparatorThickness);
|
||||
}
|
||||
|
||||
QWidgetList topLevels() const
|
||||
{
|
||||
QWidgetList result;
|
||||
|
||||
for (QWidget *w : qApp->topLevelWidgets()) {
|
||||
if (!qobject_cast<QToolButton*>(w))
|
||||
result << w;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const Config::Flags m_originalFlags;
|
||||
const int m_originalSeparatorThickness;
|
||||
};
|
||||
|
||||
class TestDocks : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -323,7 +288,6 @@ public:
|
||||
static void nestDockWidget(DockWidgetBase *dock, DropArea *dropArea, Frame *relativeTo, KDDockWidgets::Location location);
|
||||
|
||||
private Q_SLOTS:
|
||||
void tst_simple1();
|
||||
void tst_simple2();
|
||||
void tst_shutdown();
|
||||
void tst_mainWindowAlwaysHasCentralWidget();
|
||||
@@ -463,7 +427,8 @@ private Q_SLOTS:
|
||||
void tst_maximumSizePolicy();
|
||||
void tst_tabsNotClickable();
|
||||
void tst_stuckSeparator();
|
||||
void setWidget();
|
||||
void tst_isFocused();
|
||||
void tst_setWidget();
|
||||
|
||||
private:
|
||||
std::unique_ptr<MultiSplitter> createMultiSplitterFromSetup(MultiSplitterSetup setup, QHash<QWidget *, Frame *> &frameMap) const;
|
||||
@@ -584,7 +549,7 @@ DockWidgetBase *createAndNestDockWidget(DropArea *dropArea, Frame *relativeTo, K
|
||||
return dock;
|
||||
}
|
||||
|
||||
std::unique_ptr<MainWindow> createSimpleNestedMainWindow(DockWidgetBase * *centralDock, DockWidgetBase * *leftDock, DockWidgetBase * *rightDock)
|
||||
std::unique_ptr<MainWindowBase> createSimpleNestedMainWindow(DockWidgetBase * *centralDock, DockWidgetBase * *leftDock, DockWidgetBase * *rightDock)
|
||||
{
|
||||
auto window = createMainWindow({900, 500});
|
||||
*centralDock = createDockWidget("centralDock", Qt::green);
|
||||
@@ -661,7 +626,7 @@ void TestDocks::tst_dock2FloatingWidgetsTabbed()
|
||||
QTest::qWait(1000); // Test is flaky otherwise
|
||||
|
||||
auto fw2 = dock2->floatingWindow();
|
||||
drag(fw2->titleBar(), static_cast<Layouting::Widget*>(frame2)->mapToGlobal(QPoint(10, 10)), dock3->window()->geometry().center());
|
||||
drag(fw2->titleBar(), frame2->mapToGlobal(QPoint(10, 10)), dock3->window()->geometry().center());
|
||||
|
||||
QVERIFY(Testing::waitForDeleted(frame1));
|
||||
QVERIFY(Testing::waitForDeleted(frame2));
|
||||
@@ -810,7 +775,7 @@ void TestDocks::tst_close()
|
||||
// 2. Test that closing the single frame of a main window doesn't close the main window itself
|
||||
{
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None); // Remove central frame
|
||||
QPointer<MainWindow> mainWindowPtr = m.get();
|
||||
QPointer<MainWindowBase> mainWindowPtr = m.get();
|
||||
dock1 = createDockWidget("hello", Qt::green);
|
||||
m->addDockWidget(dock1, Location_OnLeft);
|
||||
|
||||
@@ -823,7 +788,7 @@ void TestDocks::tst_close()
|
||||
// 2.1 Test closing the frame instead
|
||||
{
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None); // Remove central frame
|
||||
QPointer<MainWindow> mainWindowPtr = m.get();
|
||||
QPointer<MainWindowBase> mainWindowPtr = m.get();
|
||||
dock1 = createDockWidget("hello", Qt::green);
|
||||
m->addDockWidget(dock1, Location_OnLeft);
|
||||
|
||||
@@ -837,7 +802,7 @@ void TestDocks::tst_close()
|
||||
// 2.2 Repeat, but with a central frame
|
||||
{
|
||||
auto m = createMainWindow(QSize(800, 500));
|
||||
QPointer<MainWindow> mainWindowPtr = m.get();
|
||||
QPointer<MainWindowBase> mainWindowPtr = m.get();
|
||||
dock1 = createDockWidget("hello", Qt::green);
|
||||
m->addDockWidget(dock1, Location_OnLeft);
|
||||
|
||||
@@ -2579,14 +2544,6 @@ void TestDocks::tst_setVisibleFalseWhenSideBySide()
|
||||
Testing::waitForDeleted(window);
|
||||
}
|
||||
|
||||
void TestDocks::tst_simple1()
|
||||
{
|
||||
// Simply create a MainWindow
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
m->multiSplitter()->checkSanity();
|
||||
}
|
||||
|
||||
void TestDocks::tst_simple2()
|
||||
{
|
||||
// Simply create a MainWindow, and dock something on top
|
||||
@@ -5259,6 +5216,50 @@ void TestDocks::tst_floatingAction()
|
||||
|
||||
Testing::waitForDeleted(fw);
|
||||
}
|
||||
{
|
||||
// 3. A floating window with two tabs
|
||||
auto dock1 = createDockWidget("dock1", new QPushButton("one"));
|
||||
auto dock2 = createDockWidget("dock2", new QPushButton("two"));
|
||||
|
||||
bool dock1IsFloating = dock1->floatAction()->isChecked();
|
||||
bool dock2IsFloating = dock2->floatAction()->isChecked();
|
||||
|
||||
connect(dock1->floatAction(), &QAction::toggled, [&dock1IsFloating] (bool t) {
|
||||
Q_ASSERT(dock1IsFloating != t);
|
||||
dock1IsFloating = t;
|
||||
});
|
||||
|
||||
connect(dock2->floatAction(), &QAction::toggled, [&dock2IsFloating] (bool t) {
|
||||
Q_ASSERT(dock2IsFloating != t);
|
||||
dock2IsFloating = t;
|
||||
});
|
||||
|
||||
auto fw2 = dock2->floatingWindow();
|
||||
QVERIFY(dock1->isFloating());
|
||||
QVERIFY(dock2->isFloating());
|
||||
QVERIFY(dock1->floatAction()->isChecked());
|
||||
QVERIFY(dock2->floatAction()->isChecked());
|
||||
|
||||
dock1->addDockWidgetAsTab(dock2);
|
||||
QVERIFY(!dock1->isFloating());
|
||||
QVERIFY(!dock2->isFloating());
|
||||
QVERIFY(!dock1->floatAction()->isChecked());
|
||||
QVERIFY(!dock2->floatAction()->isChecked());
|
||||
|
||||
dock2->setFloating(true);
|
||||
|
||||
QVERIFY(dock1->isFloating());
|
||||
QVERIFY(dock1->floatAction()->isChecked());
|
||||
QVERIFY(dock2->isFloating());
|
||||
QVERIFY(dock2->floatAction()->isChecked());
|
||||
|
||||
QVERIFY(dock1IsFloating);
|
||||
QVERIFY(dock2IsFloating);
|
||||
|
||||
delete fw2;
|
||||
delete dock1->window();
|
||||
delete dock2->window();
|
||||
}
|
||||
}
|
||||
|
||||
void TestDocks::tst_dockableMainWindows()
|
||||
@@ -5751,7 +5752,65 @@ void TestDocks::tst_stuckSeparator()
|
||||
}
|
||||
}
|
||||
|
||||
void TestDocks::setWidget()
|
||||
void TestDocks::tst_isFocused()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
|
||||
// 1. Create 2 floating windows
|
||||
auto dock1 = createDockWidget(QStringLiteral("dock1"), new QLineEdit());
|
||||
auto dock2 = createDockWidget(QStringLiteral("dock2"), new QLineEdit());
|
||||
dock1->window()->move(400, 200);
|
||||
|
||||
// 2. Raise dock1 and focus its line edit
|
||||
dock1->raise();
|
||||
dock1->widget()->setFocus(Qt::OtherFocusReason);
|
||||
Testing::waitForEvent(dock1->widget(), QEvent::FocusIn);
|
||||
|
||||
QVERIFY(dock1->isFocused());
|
||||
QVERIFY(!dock2->isFocused());
|
||||
|
||||
// 3. Raise dock3 and focus its line edit
|
||||
dock2->raise();
|
||||
dock2->widget()->setFocus(Qt::OtherFocusReason);
|
||||
Testing::waitForEvent(dock2->widget(), QEvent::FocusIn);
|
||||
QVERIFY(!dock1->isFocused());
|
||||
QVERIFY(dock2->isFocused());
|
||||
|
||||
// 4. Tab dock1, it's current tab now
|
||||
auto oldFw1 = dock1->window();
|
||||
dock2->addDockWidgetAsTab(dock1);
|
||||
delete oldFw1;
|
||||
QVERIFY(dock1->isFocused());
|
||||
QVERIFY(!dock2->isFocused());
|
||||
|
||||
// 5. Set dock2 as current tab again
|
||||
dock2->raise();
|
||||
QVERIFY(!dock1->isFocused());
|
||||
QVERIFY(dock2->isFocused());
|
||||
|
||||
// 6. Create dock3, focus it
|
||||
auto dock3 = createDockWidget(QStringLiteral("dock3"), new QLineEdit());
|
||||
auto oldFw3 = dock3->window();
|
||||
dock3->raise();
|
||||
dock3->widget()->setFocus(Qt::OtherFocusReason);
|
||||
Testing::waitForEvent(dock2->widget(), QEvent::FocusIn);
|
||||
QVERIFY(!dock1->isFocused());
|
||||
QVERIFY(!dock2->isFocused());
|
||||
QVERIFY(dock3->isFocused());
|
||||
|
||||
// 4. Add dock3 to the 1st window, nested, focus 2 again
|
||||
dock2->addDockWidgetToContainingWindow(dock3, Location_OnLeft);
|
||||
delete oldFw3;
|
||||
dock2->raise();
|
||||
dock2->widget()->setFocus(Qt::OtherFocusReason);
|
||||
Testing::waitForEvent(dock2->widget(), QEvent::FocusIn);
|
||||
QVERIFY(!dock1->isFocused());
|
||||
QVERIFY(dock2->isFocused());
|
||||
QVERIFY(!dock3->isFocused());
|
||||
delete dock2->window();
|
||||
}
|
||||
|
||||
void TestDocks::tst_setWidget()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto dw = new DockWidget(QStringLiteral("FOO"));
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
# include "private/quick/DockWidgetQuick.h"
|
||||
# include "private/quick/MainWindowQuick_p.h"
|
||||
#else
|
||||
# include "DockWidget.h"
|
||||
# include "MainWindow.h"
|
||||
#endif
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
@@ -46,8 +48,7 @@ void NonClosableWidget::closeEvent(QCloseEvent *ev)
|
||||
ev->ignore(); // don't allow to close
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
std::unique_ptr<KDDockWidgets::MainWindow> KDDockWidgets::Tests::createMainWindow(QSize sz, KDDockWidgets::MainWindowOptions options, const QString &name)
|
||||
std::unique_ptr<KDDockWidgets::MainWindowBase> KDDockWidgets::Tests::createMainWindow(QSize sz, KDDockWidgets::MainWindowOptions options, const QString &name)
|
||||
{
|
||||
static int count = 0;
|
||||
count++;
|
||||
@@ -55,17 +56,17 @@ std::unique_ptr<KDDockWidgets::MainWindow> KDDockWidgets::Tests::createMainWindo
|
||||
const QString mainWindowName = name.isEmpty() ? QStringLiteral("MyMainWindow%1").arg(count)
|
||||
: name;
|
||||
|
||||
auto ptr = std::unique_ptr<MainWindow>(new MainWindow(mainWindowName, options));
|
||||
auto ptr = std::unique_ptr<MainWindowType>(new MainWindowType(mainWindowName, options));
|
||||
ptr->show();
|
||||
ptr->resize(sz);
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
DockWidgetBase *KDDockWidgets::Tests::createDockWidget(const QString &name, QWidgetOrQuick *w,
|
||||
DockWidgetBase::Options options, bool show,
|
||||
const QString &affinityName)
|
||||
{
|
||||
w->setFocusPolicy(Qt::StrongFocus);
|
||||
auto dock = new DockWidgetType(name, options);
|
||||
dock->setAffinityName(affinityName);
|
||||
dock->DockWidgetBase::setWidget(w);
|
||||
@@ -90,32 +91,41 @@ DockWidgetBase *KDDockWidgets::Tests::createDockWidget(const QString &name, QCol
|
||||
return createDockWidget(name, new MyWidget(name, color));
|
||||
};
|
||||
|
||||
static QWidgetOrQuick *createGuestWidget(int i)
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
std::unique_ptr<MainWindow> KDDockWidgets::Tests::createMainWindow(QVector<DockDescriptor> &docks)
|
||||
return new QPushButton(QStringLiteral("%1").arg(i));
|
||||
#else
|
||||
Q_UNUSED(i);
|
||||
return new QWidgetAdapter();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<MainWindowBase> KDDockWidgets::Tests::createMainWindow(QVector<DockDescriptor> &docks)
|
||||
{
|
||||
static int count = 0;
|
||||
count++;
|
||||
auto m = std::unique_ptr<MainWindow>(new MainWindow(QStringLiteral("MyMainWindow%1").arg(count), MainWindowOption_None));
|
||||
auto m = std::unique_ptr<MainWindowType>(new MainWindowType(QStringLiteral("MyMainWindow%1").arg(count), MainWindowOption_None));
|
||||
auto layout = m->multiSplitter();
|
||||
m->show();
|
||||
m->resize(QSize(700, 700));
|
||||
|
||||
int i = 0;
|
||||
for (DockDescriptor &desc : docks) {
|
||||
desc.createdDock = createDockWidget(QStringLiteral("%1-%2").arg(i).arg(count), new QPushButton(QStringLiteral("%1").arg(i)), {}, false);
|
||||
desc.createdDock = createDockWidget(QStringLiteral("%1-%2").arg(i).arg(count), createGuestWidget(i), {}, false);
|
||||
DockWidgetBase *relativeTo = nullptr;
|
||||
if (desc.relativeToIndex != -1)
|
||||
relativeTo = docks.at(desc.relativeToIndex).createdDock;
|
||||
|
||||
m->addDockWidget(desc.createdDock, desc.loc, relativeTo, desc.option);
|
||||
qDebug() << "Added" <<i;
|
||||
|
||||
layout->checkSanity();
|
||||
++i;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
#endif
|
||||
|
||||
MyWidget::MyWidget(const QString &, QColor c)
|
||||
: QWidgetOrQuick()
|
||||
, c(c)
|
||||
|
||||
@@ -12,12 +12,16 @@
|
||||
#ifndef KDDOCKWIDGETS_TESTS_UTILS_H
|
||||
#define KDDOCKWIDGETS_TESTS_UTILS_H
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "KDDockWidgets.h"
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "Config.h"
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include <QWidget>
|
||||
# include <QToolButton>
|
||||
#endif
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
|
||||
@@ -45,16 +49,51 @@ struct DockDescriptor {
|
||||
KDDockWidgets::AddingOption option;
|
||||
};
|
||||
|
||||
struct EnsureTopLevelsDeleted
|
||||
{
|
||||
EnsureTopLevelsDeleted()
|
||||
: m_originalFlags(Config::self().flags())
|
||||
, m_originalSeparatorThickness(Config::self().separatorThickness())
|
||||
{
|
||||
}
|
||||
|
||||
~EnsureTopLevelsDeleted()
|
||||
{
|
||||
if (topLevels().size() != 0) {
|
||||
qWarning() << "There's still top-level widgets present!" << topLevels();
|
||||
}
|
||||
|
||||
// Other cleanup, since we use this class everywhere
|
||||
Config::self().setDockWidgetFactoryFunc(nullptr);
|
||||
Config::self().setFlags(m_originalFlags);
|
||||
Config::self().setSeparatorThickness(m_originalSeparatorThickness);
|
||||
}
|
||||
|
||||
QWidgetList topLevels() const
|
||||
{
|
||||
QWidgetList result;
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
for (QWidget *w : qApp->topLevelWidgets()) {
|
||||
if (!qobject_cast<QToolButton*>(w))
|
||||
result << w;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
const Config::Flags m_originalFlags;
|
||||
const int m_originalSeparatorThickness;
|
||||
};
|
||||
|
||||
bool shouldBlacklistWarning(const QString &msg, const QString &category = {});
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
std::unique_ptr<KDDockWidgets::MainWindow> createMainWindow(QSize sz = {600, 600},
|
||||
std::unique_ptr<MainWindowBase> createMainWindow(QSize sz = {600, 600},
|
||||
KDDockWidgets::MainWindowOptions options = MainWindowOption_HasCentralFrame, const QString &name = {});
|
||||
|
||||
|
||||
|
||||
std::unique_ptr<KDDockWidgets::MainWindow> createMainWindow(QVector<DockDescriptor> &docks);
|
||||
#endif
|
||||
std::unique_ptr<KDDockWidgets::MainWindowBase> createMainWindow(QVector<DockDescriptor> &docks);
|
||||
|
||||
KDDockWidgets::DockWidgetBase *createDockWidget(const QString &name, QWidgetOrQuick *w,
|
||||
DockWidgetBase::Options options = {}, bool show = true,
|
||||
const QString &affinityName = {});
|
||||
|
||||
Reference in New Issue
Block a user