Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2020-10-10 12:41:43 +08:00
parent 5087c473f6
commit 12253c8a50
1 changed files with 121 additions and 158 deletions

View File

@ -52,25 +52,25 @@ namespace {
QWindow *getWindowHandle(QObject *val) QWindow *getWindowHandle(QObject *val)
{ {
if (val) { Q_ASSERT(val);
const auto validWindow = [](QWindow *window) -> QWindow * { const auto validWindow = [](QWindow *window) -> QWindow * {
return (window && window->handle()) ? window : nullptr; Q_ASSERT(window);
}; return window->handle() ? window : nullptr;
if (val->isWindowType()) { };
return validWindow(qobject_cast<QWindow *>(val)); if (val->isWindowType()) {
} return validWindow(qobject_cast<QWindow *>(val));
}
#ifdef QT_WIDGETS_LIB #ifdef QT_WIDGETS_LIB
else if (val->isWidgetType()) { else if (val->isWidgetType()) {
const auto widget = qobject_cast<QWidget *>(val); const auto widget = qobject_cast<QWidget *>(val);
if (widget && widget->isTopLevel()) { if (widget && widget->isTopLevel()) {
return validWindow(widget->windowHandle()); return validWindow(widget->windowHandle());
}
} }
}
#endif #endif
else { else {
qWarning().noquote() << "Can't acquire the window handle: only " qWarning().noquote() << "Can't acquire the window handle: only "
"top level QWidget and QWindow are accepted."; "top level QWidget and QWindow are accepted.";
}
} }
return nullptr; return nullptr;
} }
@ -81,7 +81,8 @@ FramelessHelper::FramelessHelper(QObject *parent) : QObject(parent) {}
void FramelessHelper::updateQtFrame(QWindow *window, const int titleBarHeight) void FramelessHelper::updateQtFrame(QWindow *window, const int titleBarHeight)
{ {
if (window && (titleBarHeight > 0)) { Q_ASSERT(window);
if (titleBarHeight > 0) {
// Reduce top frame to zero since we paint it ourselves. Use // Reduce top frame to zero since we paint it ourselves. Use
// device pixel to avoid rounding errors. // device pixel to avoid rounding errors.
const QMargins margins = {0, -titleBarHeight, 0, 0}; const QMargins margins = {0, -titleBarHeight, 0, 0};
@ -110,9 +111,7 @@ void FramelessHelper::updateQtFrame(QWindow *window, const int titleBarHeight)
void FramelessHelper::moveWindowToDesktopCenter(QObject *obj) void FramelessHelper::moveWindowToDesktopCenter(QObject *obj)
{ {
if (!obj) { Q_ASSERT(obj);
return;
}
if (obj->isWindowType()) { if (obj->isWindowType()) {
const auto window = qobject_cast<QWindow *>(obj); const auto window = qobject_cast<QWindow *>(obj);
if (window) { if (window) {
@ -176,71 +175,59 @@ void FramelessHelper::setTitleBarHeight(const int val)
QList<QRect> FramelessHelper::getIgnoreAreas(QObject *obj) const QList<QRect> FramelessHelper::getIgnoreAreas(QObject *obj) const
{ {
if (!obj) { Q_ASSERT(obj);
return {};
}
return m_ignoreAreas.value(obj); return m_ignoreAreas.value(obj);
} }
void FramelessHelper::setIgnoreAreas(QObject *obj, const QList<QRect> &val) void FramelessHelper::setIgnoreAreas(QObject *obj, const QList<QRect> &val)
{ {
if (obj) { Q_ASSERT(obj);
m_ignoreAreas[obj] = val; m_ignoreAreas[obj] = val;
}
} }
void FramelessHelper::addIgnoreArea(QObject *obj, const QRect &val) void FramelessHelper::addIgnoreArea(QObject *obj, const QRect &val)
{ {
if (obj) { Q_ASSERT(obj);
QList<QRect> areas = m_ignoreAreas[obj]; QList<QRect> areas = m_ignoreAreas[obj];
areas.append(val); areas.append(val);
m_ignoreAreas[obj] = areas; m_ignoreAreas[obj] = areas;
}
} }
void FramelessHelper::clearIgnoreAreas(QObject *obj) void FramelessHelper::clearIgnoreAreas(QObject *obj)
{ {
if (obj) { Q_ASSERT(obj);
m_ignoreAreas[obj] = {}; m_ignoreAreas[obj] = {};
}
} }
QList<QRect> FramelessHelper::getDraggableAreas(QObject *obj) const QList<QRect> FramelessHelper::getDraggableAreas(QObject *obj) const
{ {
if (!obj) { Q_ASSERT(obj);
return {};
}
return m_draggableAreas.value(obj); return m_draggableAreas.value(obj);
} }
void FramelessHelper::setDraggableAreas(QObject *obj, const QList<QRect> &val) void FramelessHelper::setDraggableAreas(QObject *obj, const QList<QRect> &val)
{ {
if (obj) { Q_ASSERT(obj);
m_draggableAreas[obj] = val; m_draggableAreas[obj] = val;
}
} }
void FramelessHelper::addDraggableArea(QObject *obj, const QRect &val) void FramelessHelper::addDraggableArea(QObject *obj, const QRect &val)
{ {
if (obj) { Q_ASSERT(obj);
QList<QRect> areas = m_draggableAreas[obj]; QList<QRect> areas = m_draggableAreas[obj];
areas.append(val); areas.append(val);
m_draggableAreas[obj] = areas; m_draggableAreas[obj] = areas;
}
} }
void FramelessHelper::clearDraggableAreas(QObject *obj) void FramelessHelper::clearDraggableAreas(QObject *obj)
{ {
if (obj) { Q_ASSERT(obj);
m_draggableAreas[obj] = {}; m_draggableAreas[obj] = {};
}
} }
QList<QObject *> FramelessHelper::getIgnoreObjects(QObject *obj) const QList<QObject *> FramelessHelper::getIgnoreObjects(QObject *obj) const
{ {
if (!obj) { Q_ASSERT(obj);
return {};
}
QList<QObject *> ret{}; QList<QObject *> ret{};
const QList<QPointer<QObject>> objs = m_ignoreObjects.value(obj); const QList<QPointer<QObject>> objs = m_ignoreObjects.value(obj);
if (!objs.isEmpty()) { if (!objs.isEmpty()) {
@ -255,38 +242,33 @@ QList<QObject *> FramelessHelper::getIgnoreObjects(QObject *obj) const
void FramelessHelper::setIgnoreObjects(QObject *obj, const QList<QObject *> &val) void FramelessHelper::setIgnoreObjects(QObject *obj, const QList<QObject *> &val)
{ {
if (obj) { Q_ASSERT(obj);
QList<QPointer<QObject>> objs{}; QList<QPointer<QObject>> objs{};
if (!val.isEmpty()) { if (!val.isEmpty()) {
for (auto &&_obj : qAsConst(val)) { for (auto &&_obj : qAsConst(val)) {
objs.append(_obj); objs.append(_obj);
}
} }
m_ignoreObjects[obj] = objs;
} }
m_ignoreObjects[obj] = objs;
} }
void FramelessHelper::addIgnoreObject(QObject *obj, QObject *val) void FramelessHelper::addIgnoreObject(QObject *obj, QObject *val)
{ {
if (obj) { Q_ASSERT(obj);
QList<QPointer<QObject>> objs = m_ignoreObjects[obj]; QList<QPointer<QObject>> objs = m_ignoreObjects[obj];
objs.append(val); objs.append(val);
m_ignoreObjects[obj] = objs; m_ignoreObjects[obj] = objs;
}
} }
void FramelessHelper::clearIgnoreObjects(QObject *obj) void FramelessHelper::clearIgnoreObjects(QObject *obj)
{ {
if (obj) { Q_ASSERT(obj);
m_ignoreObjects[obj] = {}; m_ignoreObjects[obj] = {};
}
} }
QList<QObject *> FramelessHelper::getDraggableObjects(QObject *obj) const QList<QObject *> FramelessHelper::getDraggableObjects(QObject *obj) const
{ {
if (!obj) { Q_ASSERT(obj);
return {};
}
QList<QObject *> ret{}; QList<QObject *> ret{};
const QList<QPointer<QObject>> objs = m_draggableObjects.value(obj); const QList<QPointer<QObject>> objs = m_draggableObjects.value(obj);
if (!objs.isEmpty()) { if (!objs.isEmpty()) {
@ -301,112 +283,103 @@ QList<QObject *> FramelessHelper::getDraggableObjects(QObject *obj) const
void FramelessHelper::setDraggableObjects(QObject *obj, const QList<QObject *> &val) void FramelessHelper::setDraggableObjects(QObject *obj, const QList<QObject *> &val)
{ {
if (obj) { Q_ASSERT(obj);
QList<QPointer<QObject>> objs{}; QList<QPointer<QObject>> objs{};
if (!val.isEmpty()) { if (!val.isEmpty()) {
for (auto &&_obj : qAsConst(val)) { for (auto &&_obj : qAsConst(val)) {
objs.append(_obj); objs.append(_obj);
}
} }
m_draggableObjects[obj] = objs;
} }
m_draggableObjects[obj] = objs;
} }
void FramelessHelper::addDraggableObject(QObject *obj, QObject *val) void FramelessHelper::addDraggableObject(QObject *obj, QObject *val)
{ {
if (obj) { Q_ASSERT(obj);
QList<QPointer<QObject>> objs = m_draggableObjects[obj]; QList<QPointer<QObject>> objs = m_draggableObjects[obj];
objs.append(val); objs.append(val);
m_draggableObjects[obj] = objs; m_draggableObjects[obj] = objs;
}
} }
void FramelessHelper::clearDraggableObjects(QObject *obj) void FramelessHelper::clearDraggableObjects(QObject *obj)
{ {
if (obj) { Q_ASSERT(obj);
m_draggableObjects[obj] = {}; m_draggableObjects[obj] = {};
}
} }
bool FramelessHelper::getResizable(QObject *obj) const bool FramelessHelper::getResizable(QObject *obj) const
{ {
if (!obj) { Q_ASSERT(obj);
return true;
}
return !m_fixedSize.value(obj); return !m_fixedSize.value(obj);
} }
void FramelessHelper::setResizable(QObject *obj, const bool val) void FramelessHelper::setResizable(QObject *obj, const bool val)
{ {
if (obj) { Q_ASSERT(obj);
m_fixedSize[obj] = !val; m_fixedSize[obj] = !val;
}
} }
bool FramelessHelper::getTitleBarEnabled(QObject *obj) const bool FramelessHelper::getTitleBarEnabled(QObject *obj) const
{ {
if (!obj) { Q_ASSERT(obj);
return true;
}
return !m_disableTitleBar.value(obj); return !m_disableTitleBar.value(obj);
} }
void FramelessHelper::setTitleBarEnabled(QObject *obj, const bool val) void FramelessHelper::setTitleBarEnabled(QObject *obj, const bool val)
{ {
if (obj) { Q_ASSERT(obj);
m_disableTitleBar[obj] = !val; m_disableTitleBar[obj] = !val;
}
} }
void FramelessHelper::removeWindowFrame(QObject *obj) void FramelessHelper::removeWindowFrame(QObject *obj)
{ {
if (obj) { Q_ASSERT(obj);
// Don't miss the Qt::Window flag. // Don't miss the Qt::Window flag.
const Qt::WindowFlags flags = Qt::Window | Qt::FramelessWindowHint; const Qt::WindowFlags flags = Qt::Window | Qt::FramelessWindowHint;
const auto window = qobject_cast<QWindow *>(obj); const auto window = qobject_cast<QWindow *>(obj);
if (window) { if (window) {
window->setFlags(flags); window->setFlags(flags);
// MouseTracking is always enabled for QWindow. // MouseTracking is always enabled for QWindow.
window->installEventFilter(this); window->installEventFilter(this);
}
#ifdef QT_WIDGETS_LIB
else {
const auto widget = qobject_cast<QWidget *>(obj);
if (widget && widget->isTopLevel()) {
widget->setWindowFlags(flags);
// We can't get MouseMove events if MouseTracking is
// disabled.
widget->setMouseTracking(true);
widget->installEventFilter(this);
updateQtFrame(widget->windowHandle(), m_titleBarHeight);
}
}
#endif
} }
#ifdef QT_WIDGETS_LIB
else {
const auto widget = qobject_cast<QWidget *>(obj);
if (widget && widget->isTopLevel()) {
widget->setWindowFlags(flags);
// We can't get MouseMove events if MouseTracking is
// disabled.
widget->setMouseTracking(true);
widget->installEventFilter(this);
updateQtFrame(widget->windowHandle(), m_titleBarHeight);
}
}
#endif
} }
bool FramelessHelper::eventFilter(QObject *object, QEvent *event) bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
{ {
Q_ASSERT(object);
Q_ASSERT(event);
const auto isWindowTopLevel = [](QObject *window) -> bool { const auto isWindowTopLevel = [](QObject *window) -> bool {
if (window) { Q_ASSERT(window);
if (window->isWindowType()) { if (window->isWindowType()) {
const auto win = qobject_cast<QWindow *>(window); const auto win = qobject_cast<QWindow *>(window);
if (win) { if (win) {
return win->isTopLevel(); return win->isTopLevel();
}
} }
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
const auto widget = qobject_cast<QWidget *>(window);
if (widget) {
return widget->isTopLevel();
}
}
#endif
} }
#ifdef QT_WIDGETS_LIB
else if (window->isWidgetType()) {
const auto widget = qobject_cast<QWidget *>(window);
if (widget) {
return widget->isTopLevel();
}
}
#endif
return false; return false;
}; };
if (!object || !isWindowTopLevel(object)) { if (!isWindowTopLevel(object)) {
return false; return false;
} }
const auto getWindowEdges = const auto getWindowEdges =
@ -496,17 +469,13 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
}; };
const auto isInIgnoreAreas = [this, &isInSpecificAreas](const QPointF &point, const auto isInIgnoreAreas = [this, &isInSpecificAreas](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
if (!window) { Q_ASSERT(window);
return false;
}
return isInSpecificAreas(point.x(), point.y(), getIgnoreAreas(window)); return isInSpecificAreas(point.x(), point.y(), getIgnoreAreas(window));
}; };
const auto isInIgnoreObjects = [this, &isInSpecificObjects](const QPointF &point, const auto isInIgnoreObjects = [this, &isInSpecificObjects](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
Q_ASSERT(window);
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB) #if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
if (!window) {
return false;
}
return isInSpecificObjects(point.x(), point.y(), getIgnoreObjects(window)); return isInSpecificObjects(point.x(), point.y(), getIgnoreObjects(window));
#else #else
Q_UNUSED(point) Q_UNUSED(point)
@ -516,18 +485,14 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
}; };
const auto isInDraggableAreas = [this, &isInSpecificAreas](const QPointF &point, const auto isInDraggableAreas = [this, &isInSpecificAreas](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
if (!window) { Q_ASSERT(window);
return false;
}
const auto areas = getDraggableAreas(window); const auto areas = getDraggableAreas(window);
return (areas.isEmpty() ? true : isInSpecificAreas(point.x(), point.y(), areas)); return (areas.isEmpty() ? true : isInSpecificAreas(point.x(), point.y(), areas));
}; };
const auto isInDraggableObjects = [this, &isInSpecificObjects](const QPointF &point, const auto isInDraggableObjects = [this, &isInSpecificObjects](const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
Q_ASSERT(window);
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB) #if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
if (!window) {
return false;
}
const auto objs = getDraggableObjects(window); const auto objs = getDraggableObjects(window);
return (objs.isEmpty() ? true : isInSpecificObjects(point.x(), point.y(), objs)); return (objs.isEmpty() ? true : isInSpecificObjects(point.x(), point.y(), objs));
#else #else
@ -539,9 +504,7 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
const auto isResizePermitted = [&isInIgnoreAreas, &isInIgnoreObjects](const QPointF &globalPoint, const auto isResizePermitted = [&isInIgnoreAreas, &isInIgnoreObjects](const QPointF &globalPoint,
const QPointF &point, const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
if (!window) { Q_ASSERT(window);
return false;
}
return (!isInIgnoreAreas(point, window) && !isInIgnoreObjects(globalPoint, window)); return (!isInIgnoreAreas(point, window) && !isInIgnoreObjects(globalPoint, window));
}; };
const auto isInTitlebarArea = [this, const auto isInTitlebarArea = [this,
@ -550,25 +513,25 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event)
&isResizePermitted](const QPointF &globalPoint, &isResizePermitted](const QPointF &globalPoint,
const QPointF &point, const QPointF &point,
QObject *window) -> bool { QObject *window) -> bool {
if (window) { Q_ASSERT(window);
const bool customDragAreas = !getDraggableAreas(window).isEmpty(); const bool customDragAreas = !getDraggableAreas(window).isEmpty();
#if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB) #if defined(QT_WIDGETS_LIB) || defined(QT_QUICK_LIB)
const bool customDragObjects = !getDraggableObjects(window).isEmpty(); const bool customDragObjects = !getDraggableObjects(window).isEmpty();
#else #else
const bool customDragObjects = false; const bool customDragObjects = false;
#endif #endif
const bool customDrag = customDragAreas || customDragObjects; const bool customDrag = customDragAreas || customDragObjects;
return ((customDrag ? (isInDraggableAreas(point, window) return ((customDrag ? (isInDraggableAreas(point, window)
&& isInDraggableObjects(globalPoint, window)) && isInDraggableObjects(globalPoint, window))
: (point.y() <= m_titleBarHeight)) : (point.y() <= m_titleBarHeight))
&& isResizePermitted(globalPoint, point, window) && getTitleBarEnabled(window)); && isResizePermitted(globalPoint, point, window) && getTitleBarEnabled(window));
}
return false; return false;
}; };
const auto moveOrResize = const auto moveOrResize =
[this, &getWindowEdges, &isResizePermitted, &isInTitlebarArea](const QPointF &globalPoint, [this, &getWindowEdges, &isResizePermitted, &isInTitlebarArea](const QPointF &globalPoint,
const QPointF &point, const QPointF &point,
QObject *object) { QObject *object) {
Q_ASSERT(object);
QWindow *window = getWindowHandle(object); QWindow *window = getWindowHandle(object);
if (window) { if (window) {
const Qt::Edges edges = getWindowEdges(point, window->width(), window->height()); const Qt::Edges edges = getWindowEdges(point, window->width(), window->height());