internal refactor

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-04-29 18:03:39 +08:00
parent 16b7841bac
commit fbe241f29e
14 changed files with 435 additions and 587 deletions

View File

@ -71,6 +71,7 @@ void MainWindow::setupUi()
setTitleBarWidget(titleBarWidget); setTitleBarWidget(titleBarWidget);
setHitTestVisible(mb); // IMPORTANT!
setHitTestVisible(titleBar->iconButton); setHitTestVisible(titleBar->iconButton);
setHitTestVisible(titleBar->minimizeButton); setHitTestVisible(titleBar->minimizeButton);
setHitTestVisible(titleBar->maximizeButton); setHitTestVisible(titleBar->maximizeButton);

View File

@ -277,7 +277,8 @@ enum class ButtonState
{ {
Unspecified = -1, Unspecified = -1,
Hovered = 0, Hovered = 0,
Pressed = 1 Pressed = 1,
Clicked = 2
}; };
Q_ENUM_NS(ButtonState) Q_ENUM_NS(ButtonState)
@ -404,6 +405,10 @@ using SetSystemButtonStateCallback = std::function<void(const SystemButtonType,
using GetWindowIdCallback = std::function<WId()>; using GetWindowIdCallback = std::function<WId()>;
using ShouldIgnoreMouseEventsCallback = std::function<bool(const QPoint &)>;
using ShowSystemMenuCallback = std::function<void(const QPoint &)>;
struct UserSettings struct UserSettings
{ {
QPoint startupPosition = {}; QPoint startupPosition = {};
@ -451,6 +456,10 @@ struct SystemParameters
GetWindowIdCallback getWindowId = nullptr; GetWindowIdCallback getWindowId = nullptr;
ShouldIgnoreMouseEventsCallback shouldIgnoreMouseEvents = nullptr;
ShowSystemMenuCallback showSystemMenu = nullptr;
[[nodiscard]] inline bool isValid() const [[nodiscard]] inline bool isValid() const
{ {
Q_ASSERT(getWindowFlags); Q_ASSERT(getWindowFlags);
@ -472,13 +481,16 @@ struct SystemParameters
Q_ASSERT(getWindowDevicePixelRatio); Q_ASSERT(getWindowDevicePixelRatio);
Q_ASSERT(setSystemButtonState); Q_ASSERT(setSystemButtonState);
Q_ASSERT(getWindowId); Q_ASSERT(getWindowId);
Q_ASSERT(shouldIgnoreMouseEvents);
Q_ASSERT(showSystemMenu);
return (getWindowFlags && setWindowFlags && getWindowSize return (getWindowFlags && setWindowFlags && getWindowSize
&& setWindowSize && getWindowPosition && setWindowPosition && setWindowSize && getWindowPosition && setWindowPosition
&& getWindowScreen && isWindowFixedSize && setWindowFixedSize && getWindowScreen && isWindowFixedSize && setWindowFixedSize
&& getWindowState && setWindowState && getWindowHandle && getWindowState && setWindowState && getWindowHandle
&& windowToScreen && screenToWindow && isInsideSystemButtons && windowToScreen && screenToWindow && isInsideSystemButtons
&& isInsideTitleBarDraggableArea && getWindowDevicePixelRatio && isInsideTitleBarDraggableArea && getWindowDevicePixelRatio
&& setSystemButtonState && getWindowId); && setSystemButtonState && getWindowId && shouldIgnoreMouseEvents
&& showSystemMenu);
} }
}; };

View File

@ -161,6 +161,7 @@ struct FRAMELESSHELPER_QUICK_API QuickGlobal
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Unspecified) FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Unspecified)
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Hovered) FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Hovered)
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Pressed) FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Pressed)
FRAMELESSHELPER_QUICK_ENUM_VALUE(ButtonState, Clicked)
}; };
Q_ENUM(ButtonState) Q_ENUM(ButtonState)

View File

@ -31,6 +31,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQuickWindow; class QQuickWindow;
class QQuickItem;
QT_END_NAMESPACE QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -80,6 +81,19 @@ public:
Q_NODISCARD Q_INVOKABLE static QColor getSystemButtonBackgroundColor( Q_NODISCARD Q_INVOKABLE static QColor getSystemButtonBackgroundColor(
const QuickGlobal::SystemButtonType button, const QuickGlobal::ButtonState state); const QuickGlobal::SystemButtonType button, const QuickGlobal::ButtonState state);
#if 0
public Q_SLOTS:
static void removeWindowFrame(QQuickWindow *window);
static void setTitleBarItem(QQuickWindow *window, QQuickItem *item);
static void setHitTestVisible(QQuickWindow *window, QQuickItem *item);
static void setWindowFixedSize(QQuickWindow *window, const bool value);
static void moveWindowToDesktopCenter(QQuickWindow *window);
static void startSystemMove2(QQuickWindow *window, const QPoint &pos);
static void startSystemResize2(QQuickWindow *window, const Qt::Edges edges, const QPoint &pos);
static void bringWindowToFront(QQuickWindow *window);
static void showSystemMenu(QQuickWindow *window, const QPoint &pos);
#endif
Q_SIGNALS: Q_SIGNALS:
void darkModeEnabledChanged(); void darkModeEnabledChanged();
void systemAccentColorChanged(); void systemAccentColorChanged();

View File

@ -37,7 +37,8 @@ class FRAMELESSHELPER_WIDGETS_API StandardSystemButton : public QAbstractButton
Q_DECLARE_PRIVATE(StandardSystemButton) Q_DECLARE_PRIVATE(StandardSystemButton)
Q_DISABLE_COPY_MOVE(StandardSystemButton) Q_DISABLE_COPY_MOVE(StandardSystemButton)
Q_PROPERTY(Global::SystemButtonType buttonType READ buttonType WRITE setButtonType NOTIFY buttonTypeChanged FINAL) Q_PROPERTY(Global::SystemButtonType buttonType READ buttonType WRITE setButtonType NOTIFY buttonTypeChanged FINAL)
Q_PROPERTY(bool hover READ isHover WRITE setHover NOTIFY hoverChanged FINAL) Q_PROPERTY(bool hovered READ isHovered WRITE setHovered NOTIFY hoveredChanged FINAL)
Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL) Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor NOTIFY hoverColorChanged FINAL)
Q_PROPERTY(QColor pressColor READ pressColor WRITE setPressColor NOTIFY pressColorChanged FINAL) Q_PROPERTY(QColor pressColor READ pressColor WRITE setPressColor NOTIFY pressColorChanged FINAL)
@ -53,8 +54,11 @@ public:
Q_NODISCARD Global::SystemButtonType buttonType(); Q_NODISCARD Global::SystemButtonType buttonType();
void setButtonType(const Global::SystemButtonType value); void setButtonType(const Global::SystemButtonType value);
Q_NODISCARD bool isHover() const; Q_NODISCARD bool isHovered() const;
void setHover(const bool value); void setHovered(const bool value);
Q_NODISCARD bool isPressed() const;
void setPressed(const bool value);
Q_NODISCARD QColor hoverColor() const; Q_NODISCARD QColor hoverColor() const;
void setHoverColor(const QColor &value); void setHoverColor(const QColor &value);
@ -69,7 +73,8 @@ protected:
Q_SIGNALS: Q_SIGNALS:
void buttonTypeChanged(); void buttonTypeChanged();
void hoverChanged(); void hoveredChanged();
void pressedChanged();
void hoverColorChanged(); void hoverColorChanged();
void pressColorChanged(); void pressColorChanged();

View File

@ -40,6 +40,7 @@ struct QtHelperData
SystemParameters params = {}; SystemParameters params = {};
FramelessHelperQt *eventFilter = nullptr; FramelessHelperQt *eventFilter = nullptr;
bool cursorShapeChanged = false; bool cursorShapeChanged = false;
bool leftButtonPressed = false;
}; };
struct QtHelper struct QtHelper
@ -96,13 +97,14 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
managerPriv->notifySystemThemeHasChangedOrNot(); managerPriv->notifySystemThemeHasChangedOrNot();
return false; return false;
} }
// Only monitor window events. // We are only interested in events that are dispatched to top level windows.
if (!object->isWindowType()) { if (!object->isWindowType()) {
return false; return false;
} }
const QEvent::Type type = event->type(); const QEvent::Type type = event->type();
// We are only interested in mouse events. // We are only interested in some specific mouse events.
if ((type != QEvent::MouseButtonPress) && (type != QEvent::MouseMove)) { if ((type != QEvent::MouseButtonPress) && (type != QEvent::MouseButtonRelease)
&& (type != QEvent::MouseButtonDblClick) && (type != QEvent::MouseMove)) {
return false; return false;
} }
const auto window = qobject_cast<QWindow *>(object); const auto window = qobject_cast<QWindow *>(object);
@ -114,10 +116,8 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
} }
const QtHelperData data = g_qtHelper()->data.value(windowId); const QtHelperData data = g_qtHelper()->data.value(windowId);
g_qtHelper()->mutex.unlock(); g_qtHelper()->mutex.unlock();
if (data.params.isWindowFixedSize()) {
return false;
}
const auto mouseEvent = static_cast<QMouseEvent *>(event); const auto mouseEvent = static_cast<QMouseEvent *>(event);
const Qt::MouseButton button = mouseEvent->button();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = mouseEvent->scenePosition().toPoint(); const QPoint scenePos = mouseEvent->scenePosition().toPoint();
const QPoint globalPos = mouseEvent->globalPosition().toPoint(); const QPoint globalPos = mouseEvent->globalPosition().toPoint();
@ -125,37 +125,68 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
const QPoint scenePos = mouseEvent->windowPos().toPoint(); const QPoint scenePos = mouseEvent->windowPos().toPoint();
const QPoint globalPos = mouseEvent->screenPos().toPoint(); const QPoint globalPos = mouseEvent->screenPos().toPoint();
#endif #endif
const bool windowFixedSize = data.params.isWindowFixedSize();
const bool ignoreThisEvent = data.params.shouldIgnoreMouseEvents(scenePos);
const bool insideTitleBar = data.params.isInsideTitleBarDraggableArea(scenePos);
switch (type) { switch (type) {
case QEvent::MouseMove: { case QEvent::MouseButtonPress: {
if (data.settings.options & Option::DontTouchCursorShape) { if (button == Qt::LeftButton) {
return false; g_qtHelper()->mutex.lock();
} g_qtHelper()->data[windowId].leftButtonPressed = true;
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos); g_qtHelper()->mutex.unlock();
if (cs == Qt::ArrowCursor) { if (!windowFixedSize) {
if (data.cursorShapeChanged) { const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos);
window->unsetCursor(); if (edges != Qt::Edges{}) {
QMutexLocker locker(&g_qtHelper()->mutex); Utils::startSystemResize(window, edges, globalPos);
g_qtHelper()->data[windowId].cursorShapeChanged = false; return true;
} else { }
return false;
} }
} else {
window->setCursor(cs);
QMutexLocker locker(&g_qtHelper()->mutex);
g_qtHelper()->data[windowId].cursorShapeChanged = true;
} }
} break; } break;
case QEvent::MouseButtonPress: { case QEvent::MouseButtonRelease: {
if (mouseEvent->button() != Qt::LeftButton) { if (button == Qt::LeftButton) {
return false; QMutexLocker locker(&g_qtHelper()->mutex);
g_qtHelper()->data[windowId].leftButtonPressed = false;
} }
const Qt::Edges edges = Utils::calculateWindowEdges(window, scenePos); if ((button == Qt::RightButton) && !(data.settings.options & Option::DisableSystemMenu)) {
if (edges == Qt::Edges{}) { if (!ignoreThisEvent && insideTitleBar) {
return false; data.params.showSystemMenu(scenePos);
return true;
}
} }
Utils::startSystemResize(window, edges, globalPos); } break;
return true; case QEvent::MouseButtonDblClick: {
} if ((button == Qt::LeftButton) && !windowFixedSize && !ignoreThisEvent
&& insideTitleBar && !(data.settings.options & Option::NoDoubleClickMaximizeToggle)) {
Qt::WindowState newWindowState = Qt::WindowNoState;
if (data.params.getWindowState() != Qt::WindowMaximized) {
newWindowState = Qt::WindowMaximized;
}
data.params.setWindowState(newWindowState);
}
} break;
case QEvent::MouseMove: {
if (!windowFixedSize && !(data.settings.options & Option::DontTouchCursorShape)) {
const Qt::CursorShape cs = Utils::calculateCursorShape(window, scenePos);
if (cs == Qt::ArrowCursor) {
if (data.cursorShapeChanged) {
window->unsetCursor();
QMutexLocker locker(&g_qtHelper()->mutex);
g_qtHelper()->data[windowId].cursorShapeChanged = false;
}
} else {
window->setCursor(cs);
QMutexLocker locker(&g_qtHelper()->mutex);
g_qtHelper()->data[windowId].cursorShapeChanged = true;
}
}
if (data.leftButtonPressed && !(data.settings.options & Option::DisableDragging)) {
if (!ignoreThisEvent && insideTitleBar) {
Utils::startSystemMove(window, globalPos);
return true;
}
}
} break;
default: default:
break; break;
} }

View File

@ -42,7 +42,6 @@ struct Win32HelperData
{ {
UserSettings settings = {}; UserSettings settings = {};
SystemParameters params = {}; SystemParameters params = {};
WNDPROC originalWindowProc = nullptr;
}; };
struct Win32Helper struct Win32Helper
@ -73,142 +72,6 @@ FRAMELESSHELPER_STRING_CONSTANT(GetClientRect)
FRAMELESSHELPER_STRING_CONSTANT2(SetWindowLongPtrW, "SetWindowLongW") FRAMELESSHELPER_STRING_CONSTANT2(SetWindowLongPtrW, "SetWindowLongW")
#endif #endif
[[nodiscard]] static inline Qt::MouseButtons keyStateToMouseButtons(const WPARAM wParam)
{
if (wParam == 0) {
return {};
}
Qt::MouseButtons result = {};
if (wParam & MK_LBUTTON) {
result |= Qt::LeftButton;
}
if (wParam & MK_MBUTTON) {
result |= Qt::MiddleButton;
}
if (wParam & MK_RBUTTON) {
result |= Qt::RightButton;
}
if (wParam & MK_XBUTTON1) {
result |= Qt::XButton1;
}
if (wParam & MK_XBUTTON2) {
result |= Qt::XButton2;
}
return result;
}
[[nodiscard]] static inline Qt::MouseButtons queryMouseButtons()
{
Qt::MouseButtons result = {};
const bool mouseSwapped = (GetSystemMetrics(SM_SWAPBUTTON) != FALSE);
if (GetAsyncKeyState(VK_LBUTTON) < 0) {
result |= (mouseSwapped ? Qt::RightButton: Qt::LeftButton);
}
if (GetAsyncKeyState(VK_MBUTTON) < 0) {
result |= Qt::MiddleButton;
}
if (GetAsyncKeyState(VK_RBUTTON) < 0) {
result |= (mouseSwapped ? Qt::LeftButton : Qt::RightButton);
}
if (GetAsyncKeyState(VK_XBUTTON1) < 0) {
result |= Qt::XButton1;
}
if (GetAsyncKeyState(VK_XBUTTON2) < 0) {
result |= Qt::XButton2;
}
return result;
}
[[nodiscard]] static inline LRESULT CALLBACK MaximizeDockingHookWindowProc
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
{
Q_ASSERT(hWnd);
if (!hWnd) {
return 0;
}
const auto windowId = reinterpret_cast<WId>(hWnd);
g_win32Helper()->mutex.lock();
if (!g_win32Helper()->data.contains(windowId)) {
g_win32Helper()->mutex.unlock();
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
const Win32HelperData data = g_win32Helper()->data.value(windowId);
g_win32Helper()->mutex.unlock();
const bool isNonClientMouseEvent = (((uMsg >= WM_NCMOUSEMOVE) && (uMsg <= WM_NCMBUTTONDBLCLK))
|| (uMsg == WM_NCHITTEST));
const bool isClientMouseEvent = (((uMsg >= WM_MOUSEFIRST) && (uMsg <= WM_MOUSELAST))
|| ((uMsg >= WM_XBUTTONDOWN) && (uMsg <= WM_XBUTTONDBLCLK)));
if (isNonClientMouseEvent || isClientMouseEvent) {
const Qt::MouseButtons mouseButtons = (isNonClientMouseEvent ? queryMouseButtons() : keyStateToMouseButtons(wParam));
const POINT nativePosExtractedFromLParam = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
POINT nativeScreenPos = {};
POINT nativeWindowPos = {};
if (isNonClientMouseEvent) {
nativeScreenPos = nativePosExtractedFromLParam;
nativeWindowPos = nativeScreenPos;
if (ScreenToClient(hWnd, &nativeWindowPos) == FALSE) {
qWarning() << Utils::getSystemErrorMessage(kScreenToClient);
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
}
if (isClientMouseEvent) {
nativeWindowPos = nativePosExtractedFromLParam;
nativeScreenPos = nativeWindowPos;
if (ClientToScreen(hWnd, &nativeScreenPos) == FALSE) {
qWarning() << Utils::getSystemErrorMessage(kClientToScreen);
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
}
const qreal devicePixelRatio = data.params.getWindowDevicePixelRatio();
const QPoint qtScenePos = QPointF(QPointF(qreal(nativeWindowPos.x), qreal(nativeWindowPos.y)) / devicePixelRatio).toPoint();
SystemButtonType currentButtonType = SystemButtonType::Unknown;
static constexpr const auto defaultButtonState = ButtonState::Unspecified;
data.params.setSystemButtonState(SystemButtonType::WindowIcon, defaultButtonState);
data.params.setSystemButtonState(SystemButtonType::Help, defaultButtonState);
data.params.setSystemButtonState(SystemButtonType::Minimize, defaultButtonState);
data.params.setSystemButtonState(SystemButtonType::Maximize, defaultButtonState);
data.params.setSystemButtonState(SystemButtonType::Restore, defaultButtonState);
data.params.setSystemButtonState(SystemButtonType::Close, defaultButtonState);
if (data.params.isInsideSystemButtons(qtScenePos, &currentButtonType)) {
Q_ASSERT(currentButtonType != SystemButtonType::Unknown);
if (currentButtonType != SystemButtonType::Unknown) {
const ButtonState currentButtonState = ((mouseButtons & Qt::LeftButton) ? ButtonState::Pressed : ButtonState::Hovered);
data.params.setSystemButtonState(currentButtonType, currentButtonState);
}
}
if ((uMsg == WM_NCHITTEST) && (currentButtonType != SystemButtonType::Unknown)) {
const int hitTestResult = [currentButtonType]() -> int {
switch (currentButtonType) {
case SystemButtonType::WindowIcon:
return HTSYSMENU;
case SystemButtonType::Help:
return HTHELP;
case SystemButtonType::Minimize:
return HTREDUCE;
case SystemButtonType::Maximize:
case SystemButtonType::Restore:
return HTZOOM;
case SystemButtonType::Close:
return HTCLOSE;
default:
break;
}
return 0;
}();
Q_ASSERT(hitTestResult);
if (hitTestResult != 0) {
return hitTestResult;
}
}
}
Q_ASSERT(data.originalWindowProc);
if (data.originalWindowProc) {
return CallWindowProcW(data.originalWindowProc, hWnd, uMsg, wParam, lParam);
} else {
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
}
FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {} FramelessHelperWin::FramelessHelperWin() : QAbstractNativeEventFilter() {}
FramelessHelperWin::~FramelessHelperWin() = default; FramelessHelperWin::~FramelessHelperWin() = default;
@ -254,25 +117,6 @@ void FramelessHelperWin::addWindow(const UserSettings &settings, const SystemPar
if (settings.options & Option::SyncNativeControlsThemeWithSystem) { if (settings.options & Option::SyncNativeControlsThemeWithSystem) {
Utils::updateGlobalWin32ControlsTheme(windowId, dark); Utils::updateGlobalWin32ControlsTheme(windowId, dark);
} }
if (Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2)) {
if (settings.options & Option::MaximizeButtonDocking) {
const auto hwnd = reinterpret_cast<HWND>(windowId);
SetLastError(ERROR_SUCCESS);
const auto originalWindowProc = reinterpret_cast<WNDPROC>(GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
Q_ASSERT(originalWindowProc);
if (!originalWindowProc) {
qWarning() << Utils::getSystemErrorMessage(kGetWindowLongPtrW);
return;
}
g_win32Helper()->mutex.lock();
g_win32Helper()->data[windowId].originalWindowProc = originalWindowProc;
g_win32Helper()->mutex.unlock();
SetLastError(ERROR_SUCCESS);
if (SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(MaximizeDockingHookWindowProc)) == 0) {
qWarning() << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
}
}
}
} }
} }
} }
@ -622,17 +466,23 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
*result = HTCLIENT; *result = HTCLIENT;
return true; return true;
} }
const POINT globalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; const POINT nativeGlobalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
POINT localPos = globalPos; POINT nativeLocalPos = nativeGlobalPos;
if (ScreenToClient(hWnd, &localPos) == FALSE) { if (ScreenToClient(hWnd, &nativeLocalPos) == FALSE) {
qWarning() << Utils::getSystemErrorMessage(kScreenToClient); qWarning() << Utils::getSystemErrorMessage(kScreenToClient);
break; break;
} }
const qreal dpr = data.params.getWindowDevicePixelRatio();
const QPoint qtScenePos = QPointF(QPointF(qreal(nativeLocalPos.x), qreal(nativeLocalPos.y)) / dpr).toPoint();
const bool max = IsMaximized(hWnd); const bool max = IsMaximized(hWnd);
const bool full = Utils::isFullScreen(windowId); const bool full = Utils::isFullScreen(windowId);
const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true);
const bool isTop = (localPos.y < frameSizeY); const bool isTop = (nativeLocalPos.y < frameSizeY);
const bool isTitleBar = (false && !(data.settings.options & Option::DisableDragging)); const bool buttonSwapped = (GetSystemMetrics(SM_SWAPBUTTON) != FALSE);
const bool leftButtonPressed = (buttonSwapped ?
(GetAsyncKeyState(VK_RBUTTON) < 0) : (GetAsyncKeyState(VK_LBUTTON) < 0));
const bool isTitleBar = (data.params.isInsideTitleBarDraggableArea(qtScenePos) &&
leftButtonPressed && !(data.settings.options & Option::DisableDragging));
if (frameBorderVisible) { if (frameBorderVisible) {
// This will handle the left, right and bottom parts of the frame // This will handle the left, right and bottom parts of the frame
// because we didn't change them. // because we didn't change them.
@ -680,13 +530,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
} }
const LONG width = clientRect.right; const LONG width = clientRect.right;
const LONG height = clientRect.bottom; const LONG height = clientRect.bottom;
const bool isBottom = (localPos.y >= (height - frameSizeY)); const bool isBottom = (nativeLocalPos.y >= (height - frameSizeY));
// Make the border a little wider to let the user easy to resize on corners. // Make the border a little wider to let the user easy to resize on corners.
const qreal scaleFactor = ((isTop || isBottom) ? 2.0 : 1.0); const qreal scaleFactor = ((isTop || isBottom) ? 2.0 : 1.0);
const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true); const int frameSizeX = Utils::getResizeBorderThickness(windowId, true, true);
const auto scaledFrameSizeX = static_cast<int>(qRound(qreal(frameSizeX) * scaleFactor)); const auto scaledFrameSizeX = static_cast<int>(qRound(qreal(frameSizeX) * scaleFactor));
const bool isLeft = (localPos.x < scaledFrameSizeX); const bool isLeft = (nativeLocalPos.x < scaledFrameSizeX);
const bool isRight = (localPos.x >= (width - scaledFrameSizeX)); const bool isRight = (nativeLocalPos.x >= (width - scaledFrameSizeX));
if (isTop) { if (isTop) {
if (isLeft) { if (isLeft) {
*result = HTTOPLEFT; *result = HTTOPLEFT;

View File

@ -131,4 +131,54 @@ QColor FramelessQuickUtils::getSystemButtonBackgroundColor(const QuickGlobal::Sy
FRAMELESSHELPER_ENUM_QUICK_TO_CORE(ButtonState, state)); FRAMELESSHELPER_ENUM_QUICK_TO_CORE(ButtonState, state));
} }
#if 0
void FramelessQuickUtils::removeWindowFrame(QQuickWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
}
void FramelessQuickUtils::setTitleBarItem(QQuickWindow *window, QQuickItem *item)
{
}
void FramelessQuickUtils::setHitTestVisible(QQuickWindow *window, QQuickItem *item)
{
}
void FramelessQuickUtils::setWindowFixedSize(QQuickWindow *window, const bool value)
{
}
void FramelessQuickUtils::moveWindowToDesktopCenter(QQuickWindow *window)
{
}
void FramelessQuickUtils::startSystemMove2(QQuickWindow *window, const QPoint &pos)
{
}
void FramelessQuickUtils::startSystemResize2(QQuickWindow *window, const Qt::Edges edges, const QPoint &pos)
{
}
void FramelessQuickUtils::bringWindowToFront(QQuickWindow *window)
{
}
void FramelessQuickUtils::showSystemMenu(QQuickWindow *window, const QPoint &pos)
{
}
#endif
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -27,6 +27,7 @@
#include <QtQuick/private/qquickitem_p.h> #include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickanchors_p.h> #include <QtQuick/private/qquickanchors_p.h>
#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
#include <framelesswindowsmanager.h> #include <framelesswindowsmanager.h>
#include <utils.h> #include <utils.h>
@ -34,7 +35,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
static constexpr const char QT_QUICKITEM_CLASS_NAME[] = "QQuickItem"; static constexpr const char QTQUICK_ITEM_CLASS_NAME[] = "QQuickItem";
static constexpr const char QTQUICK_BUTTON_CLASS_NAME[] = "QQuickAbstractButton";
[[nodiscard]] static inline QuickGlobal::Options optionsCoreToQuick(const Options value) [[nodiscard]] static inline QuickGlobal::Options optionsCoreToQuick(const Options value)
{ {
@ -370,22 +372,6 @@ bool FramelessQuickWindowPrivate::eventFilter(QObject *object, QEvent *event)
const auto showEvent = static_cast<QShowEvent *>(event); const auto showEvent = static_cast<QShowEvent *>(event);
showEventHandler(showEvent); showEventHandler(showEvent);
} break; } break;
case QEvent::MouseMove: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mouseMoveEventHandler(mouseEvent);
} break;
case QEvent::MouseButtonPress: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mousePressEventHandler(mouseEvent);
} break;
case QEvent::MouseButtonRelease: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mouseReleaseEventHandler(mouseEvent);
} break;
case QEvent::MouseButtonDblClick: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mouseDoubleClickEventHandler(mouseEvent);
} break;
default: default:
break; break;
} }
@ -466,10 +452,6 @@ void FramelessQuickWindowPrivate::startSystemResize2(const Qt::Edges edges, cons
void FramelessQuickWindowPrivate::initialize() void FramelessQuickWindowPrivate::initialize()
{ {
if (m_initialized) {
return;
}
m_initialized = true;
Q_Q(FramelessQuickWindow); Q_Q(FramelessQuickWindow);
m_params.getWindowId = [q]() -> WId { return q->winId(); }; m_params.getWindowId = [q]() -> WId { return q->winId(); };
m_params.getWindowFlags = [q]() -> Qt::WindowFlags { return q->flags(); }; m_params.getWindowFlags = [q]() -> Qt::WindowFlags { return q->flags(); };
@ -494,14 +476,12 @@ void FramelessQuickWindowPrivate::initialize()
}; };
m_params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; m_params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
m_params.getWindowDevicePixelRatio = [q]() -> qreal { return q->effectiveDevicePixelRatio(); }; m_params.getWindowDevicePixelRatio = [q]() -> qreal { return q->effectiveDevicePixelRatio(); };
m_params.setSystemButtonState = [q](const SystemButtonType button, const ButtonState state) -> void { m_params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void {
Q_ASSERT(button != SystemButtonType::Unknown); setSystemButtonState(FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemButtonType, button),
if (button == SystemButtonType::Unknown) { FRAMELESSHELPER_ENUM_CORE_TO_QUICK(ButtonState, state));
return;
}
Q_EMIT q->systemButtonStateChanged(FRAMELESSHELPER_ENUM_CORE_TO_QUICK(SystemButtonType, button),
FRAMELESSHELPER_ENUM_CORE_TO_QUICK(ButtonState, state));
}; };
m_params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); };
m_params.showSystemMenu = [this](const QPoint &pos) -> void { showSystemMenu(pos); };
if (m_settings.options & Option::DisableResizing) { if (m_settings.options & Option::DisableResizing) {
setFixedSize(true, true); setFixedSize(true, true);
} }
@ -563,39 +543,35 @@ bool FramelessQuickWindowPrivate::isInSystemButtons(const QPoint &pos, QuickGlob
return false; return false;
} }
*button = QuickGlobal::SystemButtonType::Unknown; *button = QuickGlobal::SystemButtonType::Unknown;
if (!m_settings.windowIconButton && !m_settings.contextHelpButton if (m_settings.windowIconButton && m_settings.windowIconButton->inherits(QTQUICK_ITEM_CLASS_NAME)) {
&& !m_settings.minimizeButton && !m_settings.maximizeButton && !m_settings.closeButton) {
return false;
}
if (m_settings.windowIconButton && m_settings.windowIconButton->inherits(QT_QUICKITEM_CLASS_NAME)) {
const auto iconBtn = qobject_cast<QQuickItem *>(m_settings.windowIconButton); const auto iconBtn = qobject_cast<QQuickItem *>(m_settings.windowIconButton);
if (mapItemGeometryToScene(iconBtn).contains(pos)) { if (mapItemGeometryToScene(iconBtn).contains(pos)) {
*button = QuickGlobal::SystemButtonType::WindowIcon; *button = QuickGlobal::SystemButtonType::WindowIcon;
return true; return true;
} }
} }
if (m_settings.contextHelpButton && m_settings.contextHelpButton->inherits(QT_QUICKITEM_CLASS_NAME)) { if (m_settings.contextHelpButton && m_settings.contextHelpButton->inherits(QTQUICK_ITEM_CLASS_NAME)) {
const auto helpBtn = qobject_cast<QQuickItem *>(m_settings.contextHelpButton); const auto helpBtn = qobject_cast<QQuickItem *>(m_settings.contextHelpButton);
if (mapItemGeometryToScene(helpBtn).contains(pos)) { if (mapItemGeometryToScene(helpBtn).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Help; *button = QuickGlobal::SystemButtonType::Help;
return true; return true;
} }
} }
if (m_settings.minimizeButton && m_settings.minimizeButton->inherits(QT_QUICKITEM_CLASS_NAME)) { if (m_settings.minimizeButton && m_settings.minimizeButton->inherits(QTQUICK_ITEM_CLASS_NAME)) {
const auto minBtn = qobject_cast<QQuickItem *>(m_settings.minimizeButton); const auto minBtn = qobject_cast<QQuickItem *>(m_settings.minimizeButton);
if (mapItemGeometryToScene(minBtn).contains(pos)) { if (mapItemGeometryToScene(minBtn).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Minimize; *button = QuickGlobal::SystemButtonType::Minimize;
return true; return true;
} }
} }
if (m_settings.maximizeButton && m_settings.maximizeButton->inherits(QT_QUICKITEM_CLASS_NAME)) { if (m_settings.maximizeButton && m_settings.maximizeButton->inherits(QTQUICK_ITEM_CLASS_NAME)) {
const auto maxBtn = qobject_cast<QQuickItem *>(m_settings.maximizeButton); const auto maxBtn = qobject_cast<QQuickItem *>(m_settings.maximizeButton);
if (mapItemGeometryToScene(maxBtn).contains(pos)) { if (mapItemGeometryToScene(maxBtn).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Maximize; *button = QuickGlobal::SystemButtonType::Maximize;
return true; return true;
} }
} }
if (m_settings.closeButton && m_settings.closeButton->inherits(QT_QUICKITEM_CLASS_NAME)) { if (m_settings.closeButton && m_settings.closeButton->inherits(QTQUICK_ITEM_CLASS_NAME)) {
const auto closeBtn = qobject_cast<QQuickItem *>(m_settings.closeButton); const auto closeBtn = qobject_cast<QQuickItem *>(m_settings.closeButton);
if (mapItemGeometryToScene(closeBtn).contains(pos)) { if (mapItemGeometryToScene(closeBtn).contains(pos)) {
*button = QuickGlobal::SystemButtonType::Close; *button = QuickGlobal::SystemButtonType::Close;
@ -611,6 +587,14 @@ bool FramelessQuickWindowPrivate::isInTitleBarDraggableArea(const QPoint &pos) c
return false; return false;
} }
QRegion region = mapItemGeometryToScene(m_titleBarItem); QRegion region = mapItemGeometryToScene(m_titleBarItem);
const auto systemButtons = {m_settings.windowIconButton, m_settings.contextHelpButton,
m_settings.minimizeButton, m_settings.maximizeButton, m_settings.closeButton};
for (auto &&button : qAsConst(systemButtons)) {
if (button && button->inherits(QTQUICK_ITEM_CLASS_NAME)) {
const auto quickButton = qobject_cast<QQuickItem *>(button);
region -= mapItemGeometryToScene(quickButton);
}
}
if (!m_hitTestVisibleItems.isEmpty()) { if (!m_hitTestVisibleItems.isEmpty()) {
for (auto &&item : qAsConst(m_hitTestVisibleItems)) { for (auto &&item : qAsConst(m_hitTestVisibleItems)) {
Q_ASSERT(item); Q_ASSERT(item);
@ -650,6 +634,85 @@ bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const
#endif #endif
} }
void FramelessQuickWindowPrivate::setSystemButtonState(const QuickGlobal::SystemButtonType button,
const QuickGlobal::ButtonState state)
{
Q_ASSERT(button != QuickGlobal::SystemButtonType::Unknown);
if (button == QuickGlobal::SystemButtonType::Unknown) {
return;
}
QQuickAbstractButton *quickButton = nullptr;
switch (button) {
case QuickGlobal::SystemButtonType::Unknown: {
Q_ASSERT(false);
} break;
case QuickGlobal::SystemButtonType::WindowIcon: {
if (m_settings.windowIconButton && m_settings.windowIconButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
quickButton = qobject_cast<QQuickAbstractButton *>(m_settings.windowIconButton);
}
} break;
case QuickGlobal::SystemButtonType::Help: {
if (m_settings.contextHelpButton && m_settings.contextHelpButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
quickButton = qobject_cast<QQuickAbstractButton *>(m_settings.contextHelpButton);
}
} break;
case QuickGlobal::SystemButtonType::Minimize: {
if (m_settings.minimizeButton && m_settings.minimizeButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
quickButton = qobject_cast<QQuickAbstractButton *>(m_settings.minimizeButton);
}
} break;
case QuickGlobal::SystemButtonType::Maximize:
case QuickGlobal::SystemButtonType::Restore: {
if (m_settings.maximizeButton && m_settings.maximizeButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
quickButton = qobject_cast<QQuickAbstractButton *>(m_settings.maximizeButton);
}
} break;
case QuickGlobal::SystemButtonType::Close: {
if (m_settings.closeButton && m_settings.closeButton->inherits(QTQUICK_BUTTON_CLASS_NAME)) {
quickButton = qobject_cast<QQuickAbstractButton *>(m_settings.closeButton);
}
} break;
}
if (quickButton) {
const auto updateButtonState = [state](QQuickAbstractButton *btn) -> void {
Q_ASSERT(btn);
if (!btn) {
return;
}
switch (state) {
case QuickGlobal::ButtonState::Unspecified: {
btn->setDown(false);
btn->setPressed(false);
btn->setHovered(false);
} break;
case QuickGlobal::ButtonState::Hovered: {
btn->setDown(false);
btn->setPressed(false);
btn->setHovered(true);
} break;
case QuickGlobal::ButtonState::Pressed: {
btn->setHovered(true);
btn->setDown(true);
btn->setPressed(true);
} break;
case QuickGlobal::ButtonState::Clicked: {
// Clicked: pressed --> released, so behave like hovered.
btn->setDown(false);
btn->setPressed(false);
btn->setHovered(true);
// "QQuickAbstractButtonPrivate::click()"'s implementation is nothing but
// emits the "clicked" signal of the public interface, so we just emit
// the signal directly to avoid accessing the private implementation.
Q_EMIT btn->clicked();
} break;
}
};
updateButtonState(quickButton);
}
Q_Q(FramelessQuickWindow);
Q_EMIT q->systemButtonStateChanged(button, state);
}
void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event) void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event)
{ {
Q_ASSERT(event); Q_ASSERT(event);
@ -675,101 +738,6 @@ void FramelessQuickWindowPrivate::showEventHandler(QShowEvent *event)
} }
} }
void FramelessQuickWindowPrivate::mouseMoveEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
if (!m_mouseLeftButtonPressed) {
return;
}
if (m_settings.options & Option::DisableDragging) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = event->scenePosition().toPoint();
const QPoint globalPos = event->globalPosition().toPoint();
#else
const QPoint scenePos = event->windowPos().toPoint();
const QPoint globalPos = event->screenPos().toPoint();
#endif
if (shouldIgnoreMouseEvents(scenePos)) {
return;
}
if (!isInTitleBarDraggableArea(scenePos)) {
return;
}
startSystemMove2(globalPos);
}
void FramelessQuickWindowPrivate::mousePressEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
if (event->button() == Qt::LeftButton) {
m_mouseLeftButtonPressed = true;
}
}
void FramelessQuickWindowPrivate::mouseReleaseEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
const Qt::MouseButton button = event->button();
if (button == Qt::LeftButton) {
m_mouseLeftButtonPressed = false;
}
if (button != Qt::RightButton) {
return;
}
if (m_settings.options & Option::DisableSystemMenu) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = event->scenePosition().toPoint();
#else
const QPoint scenePos = event->windowPos().toPoint();
#endif
if (shouldIgnoreMouseEvents(scenePos)) {
return;
}
if (!isInTitleBarDraggableArea(scenePos)) {
return;
}
showSystemMenu(scenePos);
}
void FramelessQuickWindowPrivate::mouseDoubleClickEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
if ((m_settings.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize()) {
return;
}
if (event->button() != Qt::LeftButton) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = event->scenePosition().toPoint();
#else
const QPoint scenePos = event->windowPos().toPoint();
#endif
if (shouldIgnoreMouseEvents(scenePos)) {
return;
}
if (!isInTitleBarDraggableArea(scenePos)) {
return;
}
toggleMaximized();
}
QuickGlobal::Options FramelessQuickWindowPrivate::getOptions() const QuickGlobal::Options FramelessQuickWindowPrivate::getOptions() const
{ {
return m_quickOptions; return m_quickOptions;

View File

@ -66,10 +66,6 @@ public:
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderVerticalCenter() const; Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderVerticalCenter() const;
Q_INVOKABLE void showEventHandler(QShowEvent *event); Q_INVOKABLE void showEventHandler(QShowEvent *event);
Q_INVOKABLE void mouseMoveEventHandler(QMouseEvent *event);
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event);
Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event);
Q_INVOKABLE Q_NODISCARD QuickGlobal::Options getOptions() const; Q_INVOKABLE Q_NODISCARD QuickGlobal::Options getOptions() const;
@ -100,6 +96,7 @@ private:
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
Q_NODISCARD bool shouldDrawFrameBorder() const; Q_NODISCARD bool shouldDrawFrameBorder() const;
void setSystemButtonState(const QuickGlobal::SystemButtonType button, const QuickGlobal::ButtonState state);
private Q_SLOTS: private Q_SLOTS:
void updateTopBorderColor(); void updateTopBorderColor();
@ -107,7 +104,6 @@ private Q_SLOTS:
private: private:
FramelessQuickWindow *q_ptr = nullptr; FramelessQuickWindow *q_ptr = nullptr;
bool m_initialized = false;
QScopedPointer<QQuickRectangle> m_topBorderRectangle; QScopedPointer<QQuickRectangle> m_topBorderRectangle;
QScopedPointer<QQuickAnchors> m_topBorderAnchors; QScopedPointer<QQuickAnchors> m_topBorderAnchors;
QWindow::Visibility m_savedVisibility = QWindow::Windowed; QWindow::Visibility m_savedVisibility = QWindow::Windowed;
@ -117,7 +113,6 @@ private:
QPointer<QQuickItem> m_titleBarItem = nullptr; QPointer<QQuickItem> m_titleBarItem = nullptr;
QList<QQuickItem *> m_hitTestVisibleItems = {}; QList<QQuickItem *> m_hitTestVisibleItems = {};
QuickGlobal::Options m_quickOptions = {}; QuickGlobal::Options m_quickOptions = {};
bool m_mouseLeftButtonPressed = false;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -38,7 +38,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
using namespace Global; using namespace Global;
static constexpr const char FRAMELESSHELPER_PROP_NAME[] = "__wwx190_FramelessWidgetsHelper_instance"; static constexpr const char FRAMELESSHELPER_PROP_NAME[] = "__wwx190_FramelessWidgetsHelper_instance";
static constexpr const char QT_MAINWINDOW_CLASS_NAME[] = "QMainWindow"; static constexpr const char QTWIDGETS_MAINWINDOW_CLASS_NAME[] = "QMainWindow";
static constexpr const char FRAMELESSHELPER_SYSTEMBUTTON_CLASS_NAME[] = "StandardSystemButton";
FRAMELESSHELPER_STRING_CONSTANT2(StyleSheetColorTemplate, "color: %1;") FRAMELESSHELPER_STRING_CONSTANT2(StyleSheetColorTemplate, "color: %1;")
FRAMELESSHELPER_STRING_CONSTANT2(StyleSheetBackgroundColorTemplate, "background-color: %1;") FRAMELESSHELPER_STRING_CONSTANT2(StyleSheetBackgroundColorTemplate, "background-color: %1;")
@ -275,107 +276,8 @@ void FramelessWidgetsHelper::paintEventHandler(QPaintEvent *event)
#endif #endif
} }
void FramelessWidgetsHelper::mouseMoveEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
if (!m_mouseLeftButtonPressed) {
return;
}
if (m_settings.options & Option::DisableDragging) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = event->scenePosition().toPoint();
const QPoint globalPos = event->globalPosition().toPoint();
#else
const QPoint scenePos = event->windowPos().toPoint();
const QPoint globalPos = event->screenPos().toPoint();
#endif
if (shouldIgnoreMouseEvents(scenePos)) {
return;
}
if (!isInTitleBarDraggableArea(scenePos)) {
return;
}
startSystemMove2(globalPos);
}
void FramelessWidgetsHelper::mousePressEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
if (event->button() == Qt::LeftButton) {
m_mouseLeftButtonPressed = true;
}
}
void FramelessWidgetsHelper::mouseReleaseEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
const Qt::MouseButton button = event->button();
if (button == Qt::LeftButton) {
m_mouseLeftButtonPressed = false;
}
if (button != Qt::RightButton) {
return;
}
if (m_settings.options & Option::DisableSystemMenu) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = event->scenePosition().toPoint();
#else
const QPoint scenePos = event->windowPos().toPoint();
#endif
if (shouldIgnoreMouseEvents(scenePos)) {
return;
}
if (!isInTitleBarDraggableArea(scenePos)) {
return;
}
showSystemMenu(scenePos);
}
void FramelessWidgetsHelper::mouseDoubleClickEventHandler(QMouseEvent *event)
{
Q_ASSERT(event);
if (!event) {
return;
}
if ((m_settings.options & Option::NoDoubleClickMaximizeToggle) || isFixedSize()) {
return;
}
if (event->button() != Qt::LeftButton) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
const QPoint scenePos = event->scenePosition().toPoint();
#else
const QPoint scenePos = event->windowPos().toPoint();
#endif
if (shouldIgnoreMouseEvents(scenePos)) {
return;
}
if (!isInTitleBarDraggableArea(scenePos)) {
return;
}
toggleMaximized();
}
void FramelessWidgetsHelper::initialize() void FramelessWidgetsHelper::initialize()
{ {
if (m_initialized) {
return;
}
m_initialized = true;
// Let the user be able to get the helper class instance from outside. // Let the user be able to get the helper class instance from outside.
q->setProperty(FRAMELESSHELPER_PROP_NAME, QVariant::fromValue(this)); q->setProperty(FRAMELESSHELPER_PROP_NAME, QVariant::fromValue(this));
// Without this flag, Qt will always create an invisible native parent window // Without this flag, Qt will always create an invisible native parent window
@ -410,57 +312,11 @@ void FramelessWidgetsHelper::initialize()
m_params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); }; m_params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
m_params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); }; m_params.isInsideTitleBarDraggableArea = [this](const QPoint &pos) -> bool { return isInTitleBarDraggableArea(pos); };
m_params.getWindowDevicePixelRatio = [this]() -> qreal { return q->devicePixelRatioF(); }; m_params.getWindowDevicePixelRatio = [this]() -> qreal { return q->devicePixelRatioF(); };
m_params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { m_params.setSystemButtonState = [this](const SystemButtonType button, const ButtonState state) -> void { setSystemButtonState(button, state); };
Q_ASSERT(button != SystemButtonType::Unknown); m_params.shouldIgnoreMouseEvents = [this](const QPoint &pos) -> bool { return shouldIgnoreMouseEvents(pos); };
if (button == SystemButtonType::Unknown) { m_params.showSystemMenu = [this](const QPoint &pos) -> void { showSystemMenu(pos); };
return;
}
if (m_settings.options & Option::CreateStandardWindowLayout) {
const auto updateSystemButtonState = [state](StandardSystemButton *sysButton) -> void {
Q_ASSERT(sysButton);
if (!sysButton) {
return;
}
switch (state) {
case ButtonState::Unspecified: {
sysButton->setDown(false);
sysButton->setHover(false);
} break;
case ButtonState::Hovered: {
sysButton->setDown(false);
sysButton->setHover(true);
} break;
case ButtonState::Pressed: {
sysButton->setHover(true);
sysButton->setDown(true);
} break;
}
};
switch (button) {
case SystemButtonType::Minimize: {
if (m_systemMinimizeButton) {
updateSystemButtonState(m_systemMinimizeButton.data());
}
} break;
case SystemButtonType::Maximize:
case SystemButtonType::Restore: {
if (m_systemMaximizeButton) {
updateSystemButtonState(m_systemMaximizeButton.data());
}
} break;
case SystemButtonType::Close: {
if (m_systemCloseButton) {
updateSystemButtonState(m_systemCloseButton.data());
}
} break;
default:
break;
}
}
QMetaObject::invokeMethod(q, "systemButtonStateChanged", Q_ARG(Global::SystemButtonType, button), Q_ARG(Global::ButtonState, state));
};
if (m_settings.options & Option::CreateStandardWindowLayout) { if (m_settings.options & Option::CreateStandardWindowLayout) {
if (q->inherits(QT_MAINWINDOW_CLASS_NAME)) { if (q->inherits(QTWIDGETS_MAINWINDOW_CLASS_NAME)) {
m_settings.options &= ~Options(Option::CreateStandardWindowLayout); m_settings.options &= ~Options(Option::CreateStandardWindowLayout);
qWarning() << "\"Option::CreateStandardWindowLayout\" is not compatible with QMainWindow and it's subclasses." qWarning() << "\"Option::CreateStandardWindowLayout\" is not compatible with QMainWindow and it's subclasses."
" Enabling this option will mess up with your main window's layout."; " Enabling this option will mess up with your main window's layout.";
@ -495,11 +351,6 @@ void FramelessWidgetsHelper::initialize()
QMetaObject::invokeMethod(q, "systemThemeChanged"); QMetaObject::invokeMethod(q, "systemThemeChanged");
}); });
setupInitialUi(); setupInitialUi();
if (m_settings.options & Option::CreateStandardWindowLayout) {
m_settings.minimizeButton = m_systemMinimizeButton.data();
m_settings.maximizeButton = m_systemMaximizeButton.data();
m_settings.closeButton = m_systemCloseButton.data();
}
} }
void FramelessWidgetsHelper::createSystemTitleBar() void FramelessWidgetsHelper::createSystemTitleBar()
@ -517,30 +368,33 @@ void FramelessWidgetsHelper::createSystemTitleBar()
m_systemWindowTitleLabel->setFont(windowTitleFont); m_systemWindowTitleLabel->setFont(windowTitleFont);
m_systemWindowTitleLabel->setText(q->windowTitle()); m_systemWindowTitleLabel->setText(q->windowTitle());
connect(q, &QWidget::windowTitleChanged, m_systemWindowTitleLabel.data(), &QLabel::setText); connect(q, &QWidget::windowTitleChanged, m_systemWindowTitleLabel.data(), &QLabel::setText);
m_systemMinimizeButton.reset(new StandardSystemButton(SystemButtonType::Minimize, m_systemTitleBarWidget.data())); const auto minBtn = new StandardSystemButton(SystemButtonType::Minimize, m_systemTitleBarWidget.data());
m_systemMinimizeButton->setFixedSize(kDefaultSystemButtonSize); minBtn->setFixedSize(kDefaultSystemButtonSize);
m_systemMinimizeButton->setIconSize(kDefaultSystemButtonIconSize); minBtn->setIconSize(kDefaultSystemButtonIconSize);
m_systemMinimizeButton->setToolTip(tr("Minimize")); minBtn->setToolTip(tr("Minimize"));
connect(m_systemMinimizeButton.data(), &StandardSystemButton::clicked, q, &QWidget::showMinimized); connect(minBtn, &StandardSystemButton::clicked, q, &QWidget::showMinimized);
m_systemMaximizeButton.reset(new StandardSystemButton(SystemButtonType::Maximize, m_systemTitleBarWidget.data())); m_settings.minimizeButton = minBtn;
m_systemMaximizeButton->setFixedSize(kDefaultSystemButtonSize); const auto maxBtn = new StandardSystemButton(SystemButtonType::Maximize, m_systemTitleBarWidget.data());
m_systemMaximizeButton->setIconSize(kDefaultSystemButtonIconSize); maxBtn->setFixedSize(kDefaultSystemButtonSize);
connect(m_systemMaximizeButton.data(), &StandardSystemButton::clicked, this, &FramelessWidgetsHelper::toggleMaximized); maxBtn->setIconSize(kDefaultSystemButtonIconSize);
m_systemCloseButton.reset(new StandardSystemButton(SystemButtonType::Close, m_systemTitleBarWidget.data()));
m_systemCloseButton->setFixedSize(kDefaultSystemButtonSize);
m_systemCloseButton->setIconSize(kDefaultSystemButtonIconSize);
m_systemCloseButton->setToolTip(tr("Close"));
connect(m_systemCloseButton.data(), &StandardSystemButton::clicked, q, &QWidget::close);
updateSystemMaximizeButton(); updateSystemMaximizeButton();
connect(maxBtn, &StandardSystemButton::clicked, this, &FramelessWidgetsHelper::toggleMaximized);
m_settings.maximizeButton = maxBtn;
const auto closeBtn = new StandardSystemButton(SystemButtonType::Close, m_systemTitleBarWidget.data());
closeBtn->setFixedSize(kDefaultSystemButtonSize);
closeBtn->setIconSize(kDefaultSystemButtonIconSize);
closeBtn->setToolTip(tr("Close"));
connect(closeBtn, &StandardSystemButton::clicked, q, &QWidget::close);
m_settings.closeButton = closeBtn;
const auto systemTitleBarLayout = new QHBoxLayout(m_systemTitleBarWidget.data()); const auto systemTitleBarLayout = new QHBoxLayout(m_systemTitleBarWidget.data());
systemTitleBarLayout->setContentsMargins(0, 0, 0, 0); systemTitleBarLayout->setContentsMargins(0, 0, 0, 0);
systemTitleBarLayout->setSpacing(0); systemTitleBarLayout->setSpacing(0);
systemTitleBarLayout->addSpacerItem(new QSpacerItem(kDefaultTitleBarTitleLabelMargin, kDefaultTitleBarTitleLabelMargin)); systemTitleBarLayout->addSpacerItem(new QSpacerItem(kDefaultTitleBarTitleLabelMargin, kDefaultTitleBarTitleLabelMargin));
systemTitleBarLayout->addWidget(m_systemWindowTitleLabel.data()); systemTitleBarLayout->addWidget(m_systemWindowTitleLabel.data());
systemTitleBarLayout->addStretch(); systemTitleBarLayout->addStretch();
systemTitleBarLayout->addWidget(m_systemMinimizeButton.data()); systemTitleBarLayout->addWidget(minBtn);
systemTitleBarLayout->addWidget(m_systemMaximizeButton.data()); systemTitleBarLayout->addWidget(maxBtn);
systemTitleBarLayout->addWidget(m_systemCloseButton.data()); systemTitleBarLayout->addWidget(closeBtn);
m_systemTitleBarWidget->setLayout(systemTitleBarLayout); m_systemTitleBarWidget->setLayout(systemTitleBarLayout);
} }
@ -632,29 +486,25 @@ bool FramelessWidgetsHelper::isInSystemButtons(const QPoint &pos, SystemButtonTy
bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const bool FramelessWidgetsHelper::isInTitleBarDraggableArea(const QPoint &pos) const
{ {
const QRegion draggableRegion = [this]() -> QRegion { QRegion region = (m_userTitleBarWidget ? mapWidgetGeometryToScene(m_userTitleBarWidget) :
if (m_userTitleBarWidget) { (m_systemTitleBarWidget ? mapWidgetGeometryToScene(m_systemTitleBarWidget.data()) : QRegion{}));
QRegion region = mapWidgetGeometryToScene(m_userTitleBarWidget); const auto systemButtons = {m_settings.windowIconButton, m_settings.contextHelpButton,
if (!m_hitTestVisibleWidgets.isEmpty()) { m_settings.minimizeButton, m_settings.maximizeButton, m_settings.closeButton};
for (auto &&widget : qAsConst(m_hitTestVisibleWidgets)) { for (auto &&button : qAsConst(systemButtons)) {
Q_ASSERT(widget); if (button && button->isWidgetType()) {
if (widget) { const auto widgetButton = qobject_cast<QWidget *>(button);
region -= mapWidgetGeometryToScene(widget); region -= mapWidgetGeometryToScene(widgetButton);
} }
} }
if (!m_hitTestVisibleWidgets.isEmpty()) {
for (auto &&widget : qAsConst(m_hitTestVisibleWidgets)) {
Q_ASSERT(widget);
if (widget) {
region -= mapWidgetGeometryToScene(widget);
} }
return region;
} }
if (m_settings.options & Option::CreateStandardWindowLayout) { }
QRegion region = mapWidgetGeometryToScene(m_systemTitleBarWidget.data()); return region.contains(pos);
region -= mapWidgetGeometryToScene(m_systemMinimizeButton.data());
region -= mapWidgetGeometryToScene(m_systemMaximizeButton.data());
region -= mapWidgetGeometryToScene(m_systemCloseButton.data());
return region;
}
return {};
}();
return draggableRegion.contains(pos);
} }
bool FramelessWidgetsHelper::shouldDrawFrameBorder() const bool FramelessWidgetsHelper::shouldDrawFrameBorder() const
@ -684,6 +534,78 @@ bool FramelessWidgetsHelper::shouldIgnoreMouseEvents(const QPoint &pos) const
return (isNormal() && withinFrameBorder); return (isNormal() && withinFrameBorder);
} }
void FramelessWidgetsHelper::setSystemButtonState(const SystemButtonType button, const ButtonState state)
{
Q_ASSERT(button != SystemButtonType::Unknown);
if (button == SystemButtonType::Unknown) {
return;
}
QWidget *widgetButton = nullptr;
switch (button) {
case SystemButtonType::Unknown: {
Q_ASSERT(false);
} break;
case SystemButtonType::WindowIcon: {
if (m_settings.windowIconButton && m_settings.windowIconButton->isWidgetType()) {
widgetButton = qobject_cast<QWidget *>(m_settings.windowIconButton);
}
} break;
case SystemButtonType::Help: {
if (m_settings.contextHelpButton && m_settings.contextHelpButton->isWidgetType()) {
widgetButton = qobject_cast<QWidget *>(m_settings.contextHelpButton);
}
} break;
case SystemButtonType::Minimize: {
if (m_settings.minimizeButton && m_settings.minimizeButton->isWidgetType()) {
widgetButton = qobject_cast<QWidget *>(m_settings.minimizeButton);
}
} break;
case SystemButtonType::Maximize:
case SystemButtonType::Restore: {
if (m_settings.maximizeButton && m_settings.maximizeButton->isWidgetType()) {
widgetButton = qobject_cast<QWidget *>(m_settings.maximizeButton);
}
} break;
case SystemButtonType::Close: {
if (m_settings.closeButton && m_settings.closeButton->isWidgetType()) {
widgetButton = qobject_cast<QWidget *>(m_settings.closeButton);
}
} break;
}
if (widgetButton) {
const auto updateButtonState = [state](QWidget *btn) -> void {
Q_ASSERT(btn);
if (!btn) {
return;
}
switch (state) {
case ButtonState::Unspecified: {
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, false));
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, false));
} break;
case ButtonState::Hovered: {
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, false));
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, true));
} break;
case ButtonState::Pressed: {
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, true));
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, true));
} break;
case ButtonState::Clicked: {
// Clicked: pressed --> released, so behave like hovered.
QMetaObject::invokeMethod(btn, "setPressed", Q_ARG(bool, false));
QMetaObject::invokeMethod(btn, "setHovered", Q_ARG(bool, true));
// Trigger the clicked signal.
QMetaObject::invokeMethod(btn, "clicked");
} break;
}
};
updateButtonState(widgetButton);
}
QMetaObject::invokeMethod(q, "systemButtonStateChanged",
Q_ARG(Global::SystemButtonType, button), Q_ARG(Global::ButtonState, state));
}
void FramelessWidgetsHelper::updateContentsMargins() void FramelessWidgetsHelper::updateContentsMargins()
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -733,12 +655,11 @@ void FramelessWidgetsHelper::updateSystemTitleBarStyleSheet()
void FramelessWidgetsHelper::updateSystemMaximizeButton() void FramelessWidgetsHelper::updateSystemMaximizeButton()
{ {
if (!(m_settings.options & Option::CreateStandardWindowLayout)) { if (const auto button = qobject_cast<StandardSystemButton *>(m_settings.maximizeButton)) {
return; const bool zoomed = isZoomed();
button->setToolTip(zoomed ? tr("Restore") : tr("Maximize"));
button->setButtonType(zoomed ? SystemButtonType::Restore : SystemButtonType::Maximize);
} }
const bool zoomed = isZoomed();
m_systemMaximizeButton->setToolTip(zoomed ? tr("Restore") : tr("Maximize"));
m_systemMaximizeButton->setButtonType(zoomed ? SystemButtonType::Restore : SystemButtonType::Maximize);
} }
void FramelessWidgetsHelper::toggleMaximized() void FramelessWidgetsHelper::toggleMaximized()
@ -830,22 +751,6 @@ bool FramelessWidgetsHelper::eventFilter(QObject *object, QEvent *event)
const auto paintEvent = static_cast<QPaintEvent *>(event); const auto paintEvent = static_cast<QPaintEvent *>(event);
paintEventHandler(paintEvent); paintEventHandler(paintEvent);
} break; } break;
case QEvent::MouseMove: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mouseMoveEventHandler(mouseEvent);
} break;
case QEvent::MouseButtonPress: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mousePressEventHandler(mouseEvent);
} break;
case QEvent::MouseButtonRelease: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mouseReleaseEventHandler(mouseEvent);
} break;
case QEvent::MouseButtonDblClick: {
const auto mouseEvent = static_cast<QMouseEvent *>(event);
mouseDoubleClickEventHandler(mouseEvent);
} break;
case QEvent::ActivationChange: case QEvent::ActivationChange:
case QEvent::WindowStateChange: { case QEvent::WindowStateChange: {
changeEventHandler(event); changeEventHandler(event);

View File

@ -66,10 +66,6 @@ public:
Q_INVOKABLE void showEventHandler(QShowEvent *event); Q_INVOKABLE void showEventHandler(QShowEvent *event);
Q_INVOKABLE void changeEventHandler(QEvent *event); Q_INVOKABLE void changeEventHandler(QEvent *event);
Q_INVOKABLE void paintEventHandler(QPaintEvent *event); Q_INVOKABLE void paintEventHandler(QPaintEvent *event);
Q_INVOKABLE void mouseMoveEventHandler(QMouseEvent *event);
Q_INVOKABLE void mousePressEventHandler(QMouseEvent *event);
Q_INVOKABLE void mouseReleaseEventHandler(QMouseEvent *event);
Q_INVOKABLE void mouseDoubleClickEventHandler(QMouseEvent *event);
public Q_SLOTS: public Q_SLOTS:
void setHitTestVisible(QWidget *widget); void setHitTestVisible(QWidget *widget);
@ -94,6 +90,7 @@ private:
Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const; Q_NODISCARD bool isInTitleBarDraggableArea(const QPoint &pos) const;
Q_NODISCARD bool shouldDrawFrameBorder() const; Q_NODISCARD bool shouldDrawFrameBorder() const;
Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const; Q_NODISCARD bool shouldIgnoreMouseEvents(const QPoint &pos) const;
void setSystemButtonState(const Global::SystemButtonType button, const Global::ButtonState state);
private Q_SLOTS: private Q_SLOTS:
void updateContentsMargins(); void updateContentsMargins();
@ -102,12 +99,8 @@ private Q_SLOTS:
private: private:
QPointer<QWidget> q = nullptr; QPointer<QWidget> q = nullptr;
bool m_initialized = false;
QScopedPointer<QWidget> m_systemTitleBarWidget; QScopedPointer<QWidget> m_systemTitleBarWidget;
QScopedPointer<QLabel> m_systemWindowTitleLabel; QScopedPointer<QLabel> m_systemWindowTitleLabel;
QScopedPointer<StandardSystemButton> m_systemMinimizeButton;
QScopedPointer<StandardSystemButton> m_systemMaximizeButton;
QScopedPointer<StandardSystemButton> m_systemCloseButton;
QPointer<QWidget> m_userTitleBarWidget = nullptr; QPointer<QWidget> m_userTitleBarWidget = nullptr;
QPointer<QWidget> m_userContentWidget = nullptr; QPointer<QWidget> m_userContentWidget = nullptr;
QScopedPointer<QVBoxLayout> m_mainLayout; QScopedPointer<QVBoxLayout> m_mainLayout;
@ -118,7 +111,6 @@ private:
Global::UserSettings m_settings = {}; Global::UserSettings m_settings = {};
Global::SystemParameters m_params = {}; Global::SystemParameters m_params = {};
bool m_windowExposed = false; bool m_windowExposed = false;
bool m_mouseLeftButtonPressed = false;
}; };
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -172,11 +172,16 @@ QSize StandardSystemButtonPrivate::getRecommendedButtonSize() const
return kDefaultSystemButtonSize; return kDefaultSystemButtonSize;
} }
bool StandardSystemButtonPrivate::isHover() const bool StandardSystemButtonPrivate::isHovered() const
{ {
return m_hovered; return m_hovered;
} }
bool StandardSystemButtonPrivate::isPressed() const
{
return m_pressed;
}
QColor StandardSystemButtonPrivate::getHoverColor() const QColor StandardSystemButtonPrivate::getHoverColor() const
{ {
return m_hoverColor; return m_hoverColor;
@ -187,7 +192,7 @@ QColor StandardSystemButtonPrivate::getPressColor() const
return m_pressColor; return m_pressColor;
} }
void StandardSystemButtonPrivate::setHover(const bool value) void StandardSystemButtonPrivate::setHovered(const bool value)
{ {
if (m_hovered == value) { if (m_hovered == value) {
return; return;
@ -195,7 +200,24 @@ void StandardSystemButtonPrivate::setHover(const bool value)
m_hovered = value; m_hovered = value;
Q_Q(StandardSystemButton); Q_Q(StandardSystemButton);
q->update(); q->update();
Q_EMIT q->hoverChanged(); Q_EMIT q->hoveredChanged();
}
void StandardSystemButtonPrivate::setPressed(const bool value)
{
if (m_pressed == value) {
return;
}
m_pressed = value;
Q_Q(StandardSystemButton);
q->setDown(m_pressed);
q->update();
Q_EMIT q->pressedChanged();
if (m_pressed) {
Q_EMIT q->pressed();
} else {
Q_EMIT q->released();
}
} }
void StandardSystemButtonPrivate::setHoverColor(const QColor &value) void StandardSystemButtonPrivate::setHoverColor(const QColor &value)
@ -234,7 +256,7 @@ void StandardSystemButtonPrivate::enterEventHandler(QT_ENTER_EVENT_TYPE *event)
if (!event) { if (!event) {
return; return;
} }
setHover(true); setHovered(true);
} }
void StandardSystemButtonPrivate::leaveEventHandler(QEvent *event) void StandardSystemButtonPrivate::leaveEventHandler(QEvent *event)
@ -243,7 +265,7 @@ void StandardSystemButtonPrivate::leaveEventHandler(QEvent *event)
if (!event) { if (!event) {
return; return;
} }
setHover(false); setHovered(false);
} }
void StandardSystemButtonPrivate::paintEventHandler(QPaintEvent *event) void StandardSystemButtonPrivate::paintEventHandler(QPaintEvent *event)
@ -282,20 +304,8 @@ void StandardSystemButtonPrivate::initialize()
Q_Q(StandardSystemButton); Q_Q(StandardSystemButton);
q->setFixedSize(kDefaultSystemButtonSize); q->setFixedSize(kDefaultSystemButtonSize);
q->setIconSize(kDefaultSystemButtonIconSize); q->setIconSize(kDefaultSystemButtonIconSize);
connect(q, &StandardSystemButton::pressed, this, [this, q](){ connect(q, &StandardSystemButton::pressed, this, [this](){ setPressed(true); });
if (m_pressed) { connect(q, &StandardSystemButton::released, this, [this](){ setPressed(false); });
return;
}
m_pressed = true;
q->update();
});
connect(q, &StandardSystemButton::released, this, [this, q](){
if (!m_pressed) {
return;
}
m_pressed = false;
q->update();
});
connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged, connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::systemThemeChanged,
this, [this](){ refreshButtonTheme(false); }); this, [this](){ refreshButtonTheme(false); });
} }
@ -336,16 +346,28 @@ void StandardSystemButton::setButtonType(const Global::SystemButtonType value)
d->setButtonType(value); d->setButtonType(value);
} }
bool StandardSystemButton::isHover() const bool StandardSystemButton::isHovered() const
{ {
Q_D(const StandardSystemButton); Q_D(const StandardSystemButton);
return d->isHover(); return d->isHovered();
} }
void StandardSystemButton::setHover(const bool value) void StandardSystemButton::setHovered(const bool value)
{ {
Q_D(StandardSystemButton); Q_D(StandardSystemButton);
d->setHover(value); d->setHovered(value);
}
bool StandardSystemButton::isPressed() const
{
Q_D(const StandardSystemButton);
return d->isPressed();
}
void StandardSystemButton::setPressed(const bool value)
{
Q_D(StandardSystemButton);
d->setPressed(value);
} }
QColor StandardSystemButton::hoverColor() const QColor StandardSystemButton::hoverColor() const

View File

@ -61,11 +61,13 @@ public:
Q_NODISCARD QSize getRecommendedButtonSize() const; Q_NODISCARD QSize getRecommendedButtonSize() const;
Q_NODISCARD bool isHover() const; Q_NODISCARD bool isHovered() const;
Q_NODISCARD bool isPressed() const;
Q_NODISCARD QColor getHoverColor() const; Q_NODISCARD QColor getHoverColor() const;
Q_NODISCARD QColor getPressColor() const; Q_NODISCARD QColor getPressColor() const;
void setHover(const bool value); void setHovered(const bool value);
void setPressed(const bool value);
void setHoverColor(const QColor &value); void setHoverColor(const QColor &value);
void setPressColor(const QColor &value); void setPressColor(const QColor &value);