File: framelesswindow.cpp

package info (click to toggle)
pineapple-pictures 1.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,424 kB
  • sloc: cpp: 3,794; xml: 339; sh: 8; makefile: 2
file content (136 lines) | stat: -rw-r--r-- 3,924 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
// SPDX-FileCopyrightText: 2023 Tad Young <yyc12321@outlook.com>
//
// SPDX-License-Identifier: MIT

#include "framelesswindow.h"

#include <QMouseEvent>
#include <QHoverEvent>
#include <QApplication>
#include <QVBoxLayout>
#include <QWindow>

FramelessWindow::FramelessWindow(QWidget *parent)
    : QWidget(parent)
    , m_centralLayout(new QVBoxLayout(this))
    , m_oldCursorShape(Qt::ArrowCursor)
    , m_oldEdges()
{
    this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
    this->setMouseTracking(true);
    this->setAttribute(Qt::WA_Hover, true);
    this->installEventFilter(this);

    m_centralLayout->setContentsMargins(QMargins());
}

void FramelessWindow::setCentralWidget(QWidget *widget)
{
    if (m_centralWidget) {
        m_centralLayout->removeWidget(m_centralWidget);
        m_centralWidget->deleteLater();
    }

    m_centralLayout->addWidget(widget);
    m_centralWidget = widget;
}

void FramelessWindow::installResizeCapture(QObject* widget)
{
    widget->installEventFilter(this);
}

bool FramelessWindow::eventFilter(QObject* o, QEvent* e)
{
    switch (e->type()) {
    case QEvent::HoverMove:
    {
        QWidget* wg = qobject_cast<QWidget*>(o);
        if (wg != nullptr)
            return mouseHover(static_cast<QHoverEvent*>(e), wg);

        break;
    }
    case QEvent::MouseButtonPress:
        return mousePress(static_cast<QMouseEvent*>(e));
    }

    return QWidget::eventFilter(o, e);
}

bool FramelessWindow::mouseHover(QHoverEvent* event, QWidget* wg)
{
    if (!isMaximized() && !isFullScreen()) {
        QWindow* win = window()->windowHandle();
        Qt::Edges edges = this->getEdgesByPos(wg->mapToGlobal(event->oldPos()), win->frameGeometry());

        // backup & restore cursor shape
        if (edges && !m_oldEdges)
            // entering the edge. backup cursor shape
            m_oldCursorShape = win->cursor().shape();
        if (!edges && m_oldEdges)
            // leaving the edge. restore cursor shape
            win->setCursor(m_oldCursorShape);

        // save the latest edges status
        m_oldEdges = edges;

        // show resize cursor shape if cursor is within border
        if (edges) {
            win->setCursor(this->getCursorByEdge(edges, Qt::ArrowCursor));
            return true;
        }
    }

    return false;
}

bool FramelessWindow::mousePress(QMouseEvent* event)
{
    if (event->buttons() & Qt::LeftButton && !isMaximized() && !isFullScreen()) {
        QWindow* win = window()->windowHandle();
        Qt::Edges edges = this->getEdgesByPos(event->globalPosition().toPoint(), win->frameGeometry());
        if (edges) {
            win->startSystemResize(edges);
            return true;
        }
    }

    return false;
}

Qt::CursorShape FramelessWindow::getCursorByEdge(const Qt::Edges& edges, Qt::CursorShape default_cursor)
{
    if ((edges == (Qt::TopEdge | Qt::LeftEdge)) || (edges == (Qt::RightEdge | Qt::BottomEdge)))
        return Qt::SizeFDiagCursor;
    else if ((edges == (Qt::TopEdge | Qt::RightEdge)) || (edges == (Qt::LeftEdge | Qt::BottomEdge)))
        return Qt::SizeBDiagCursor;
    else if (edges & (Qt::TopEdge | Qt::BottomEdge))
        return Qt::SizeVerCursor;
    else if (edges & (Qt::LeftEdge | Qt::RightEdge))
        return Qt::SizeHorCursor;
    else
        return default_cursor;
}

Qt::Edges FramelessWindow::getEdgesByPos(const QPoint gpos, const QRect& winrect)
{
    const int borderWidth = 8;
    Qt::Edges edges;

    int x = gpos.x() - winrect.x();
    int y = gpos.y() - winrect.y();

    if (x < borderWidth)
        edges |= Qt::LeftEdge;
    if (x > (winrect.width() - borderWidth))
        edges |= Qt::RightEdge;
    if (y < borderWidth)
        edges |= Qt::TopEdge;
    if (y > (winrect.height() - borderWidth))
        edges |= Qt::BottomEdge;

    return edges;
}