Skip to content

Commit

Permalink
使用简易的无边框窗口,能改变大小和拖动即可。比较麻烦的细节问题不在这里处理了。
Browse files Browse the repository at this point in the history
  • Loading branch information
jared2020 committed Dec 11, 2024
1 parent 0599d5b commit feeeb75
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 589 deletions.
217 changes: 217 additions & 0 deletions 3rdparty/TaoCommon/src/TaoCommon/Frameless/TaoFrameLessView.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#include "Frameless/TaoFrameLessView.h"
#include <QGuiApplication>
#include <QQuickItem>
#include <QScreen>
#include <QWindow>

struct TaoFrameLessViewPrivate
{
uint32_t mPressedEdge;
QRect mPressedGeometry;
};
TaoFrameLessView::TaoFrameLessView(QWindow* parent)
: Super(parent)
, d(std::make_unique<TaoFrameLessViewPrivate>())
{
setFlags(flags() | Qt::FramelessWindowHint | Qt::Window);
setResizeMode(SizeRootObjectToView);
}
TaoFrameLessView::~TaoFrameLessView() { }
QRect TaoFrameLessView::calcCenterGeo(const QRect& screenGeo, const QSize& normalSize)
{
int w = normalSize.width();
int h = normalSize.height();
int x = screenGeo.x() + (screenGeo.width() - w) / 2;
int y = screenGeo.y() + (screenGeo.height() - h) / 2;
if (screenGeo.width() < w)
{
x = screenGeo.x();
w = screenGeo.width();
}
if (screenGeo.height() < h)
{
y = screenGeo.y();
h = screenGeo.height();
}

return { x, y, w, h };
}
void TaoFrameLessView::moveToScreenCenter()
{
auto geo = calcCenterGeo(screen()->availableGeometry(), size());
if (minimumWidth() > geo.width() || minimumHeight() > geo.height())
{
setMinimumSize(geo.size());
}
setGeometry(geo);
update();
}

void TaoFrameLessView::move(int x, int y)
{
setPosition(x, y);
}

QPoint TaoFrameLessView::mousePosition() const
{
return QCursor::pos();
}

QPoint TaoFrameLessView::globalPosToWindowPos(const QPoint& pos) const
{
return mapFromGlobal(pos);
}

void TaoFrameLessView::mousePressEvent(QMouseEvent* event)
{
auto mousePos = event->pos();
emit mousePressed(mousePos.x(), mousePos.y(), event->button());
d->mPressedEdge = getPosEdges(mousePos);
if (d->mPressedEdge)
{
d->mPressedGeometry = geometry();
}
Super::mousePressEvent(event);
}

void TaoFrameLessView::mouseReleaseEvent(QMouseEvent* event)
{
d->mPressedEdge = 0;
d->mPressedGeometry = {};
Super::mouseReleaseEvent(event);
}

void TaoFrameLessView::mouseMoveEvent(QMouseEvent* event)
{
{
// 实时计算光标
auto edges = getPosEdges(event->pos());
auto shape = getCursorShapeByEdge(edges);
setCursor(shape);
}
{
// 根据按下时位置执行move
if (d->mPressedEdge)
{
doMoveTo(event->pos());
}
}
Super::mouseMoveEvent(event);
}
Qt::CursorShape TaoFrameLessView::getCursorShapeByEdge(const Qt::Edges& edges)
{
switch (edges)
{
case Qt::Edge::TopEdge:
case Qt::Edge::BottomEdge: {
return Qt::CursorShape::SizeVerCursor;
break;
}
case Qt::Edge::LeftEdge:
case Qt::Edge::RightEdge: {
return Qt::CursorShape::SizeHorCursor;
break;
}
case (Qt::Edge::TopEdge | Qt::Edge::LeftEdge):
case (Qt::Edge::BottomEdge | Qt::Edge::RightEdge): {
return Qt::CursorShape::SizeFDiagCursor;
break;
}
case (Qt::Edge::TopEdge | Qt::Edge::RightEdge):
case (Qt::Edge::BottomEdge | Qt::Edge::LeftEdge): {
return Qt::CursorShape::SizeBDiagCursor;
break;
}
default:
break;
}
return Qt::CursorShape::ArrowCursor;
}

void TaoFrameLessView::doMoveTo(const QPoint& nowPos)
{
switch (d->mPressedEdge)
{
case Qt::Edge::TopEdge: {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(0, gPos.y() - d->mPressedGeometry.top(), 0, 0);
// setGeometry(newGeo);
setY(newGeo.y());
setHeight(newGeo.height());
break;
}
case Qt::Edge::BottomEdge: {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(0, 0, 0, gPos.y() - d->mPressedGeometry.bottom());
setGeometry(newGeo);
break;
}
case Qt::Edge::LeftEdge: {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(gPos.x() - d->mPressedGeometry.left(), 0, 0, 0);
setGeometry(newGeo);
break;
}
case Qt::Edge::RightEdge: {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(0, 0, gPos.x() - d->mPressedGeometry.right(), 0);
setGeometry(newGeo);
break;
}
case (Qt::Edge::TopEdge | Qt::Edge::LeftEdge): {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(gPos.x() - d->mPressedGeometry.left(), gPos.y() - d->mPressedGeometry.top(), 0, 0);
setGeometry(newGeo);
break;
}
case (Qt::Edge::BottomEdge | Qt::Edge::RightEdge): {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(0, 0, gPos.x() - d->mPressedGeometry.right(), gPos.y() - d->mPressedGeometry.bottom());
setGeometry(newGeo);
break;
}
case (Qt::Edge::TopEdge | Qt::Edge::RightEdge): {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(0, gPos.y() - d->mPressedGeometry.top(), gPos.x() - d->mPressedGeometry.right(), 0);
setGeometry(newGeo);
break;
}
case (Qt::Edge::BottomEdge | Qt::Edge::LeftEdge): {
auto gPos = mapToGlobal(nowPos);
auto newGeo = d->mPressedGeometry.adjusted(gPos.x() - d->mPressedGeometry.left(), 0, 0, gPos.y() - d->mPressedGeometry.bottom());
setGeometry(newGeo);
break;
}
default:
break;
}
}
Qt::Edges TaoFrameLessView::getPosEdges(const QPoint& pos) const
{
uint32_t edges = 0;
if (pos.x() < 0 || pos.x() > width())
{
return (Qt::Edges)edges;
}
if (pos.y() < 0 || pos.y() > height())
{
return (Qt::Edges)edges;
}
if (pos.x() <= borderWidth())
{
edges |= Qt::Edge::LeftEdge;
}
else if (width() - borderWidth() <= pos.x())
{
edges |= Qt::Edge::RightEdge;
}
if (pos.y() <= borderWidth())
{
edges |= Qt::Edge::TopEdge;
}
else if (height() - borderWidth() <= pos.y())
{
edges |= Qt::Edge::BottomEdge;
}
return (Qt::Edges)edges;
}
51 changes: 19 additions & 32 deletions 3rdparty/TaoCommon/src/TaoCommon/Frameless/TaoFrameLessView.h
Original file line number Diff line number Diff line change
@@ -1,56 +1,43 @@
#pragma once
#include "Common/PropertyHelper.h"
#include "TaoCommonGlobal.h"
#include <QMouseEvent>
#include <QQuickView>
#include <QRegion>

// 无边框窗口,主要用来实现自定义标题栏。
// Windows平台支持拖动和改变大小,支持Aero效果
// 非Windows平台,去掉边框,不做其它处理。由Qml模拟resize和拖动。
class TaoFrameLessViewPrivate;
// 简易的无边框窗口,主要用来实现自定义标题栏。
// 支持标题栏拖动和边缘改变大小,不做深度处理
struct TaoFrameLessViewPrivate;
class TAO_API TaoFrameLessView : public QQuickView
{
Q_OBJECT
using Super = QQuickView;
Q_PROPERTY(bool isMax READ isMax NOTIFY isMaxChanged)
Q_PROPERTY(bool isFull READ isFull NOTIFY isFullChanged)
AUTO_PROPERTY(int, borderWidth, 4)
public:
explicit TaoFrameLessView(QWindow* parent = nullptr);
~TaoFrameLessView();
void moveToScreenCenter();
bool isMax() const;
bool isFull() const;
QQuickItem* titleItem() const;

static QRect calcCenterGeo(const QRect& screenGeo, const QSize& normalSize);
public slots:
void setIsMax(bool isMax);
void setIsFull(bool isFull);
void setTitleItem(QQuickItem* item);
void moveToScreenCenter();
void move(int x, int y);

QPoint mousePosition() const;

QPoint globalPosToWindowPos(const QPoint& pos) const;
signals:
void isMaxChanged(bool isMax);
void isFullChanged(bool isFull);
void mousePressed(int xPos, int yPos, int button);

protected:
void showEvent(QShowEvent* e) override;
void resizeEvent(QResizeEvent* e) override;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
#else
bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
#endif
void mousePressEvent(QMouseEvent* event) override
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
emit mousePressed(event->position().x(), event->position().y(), event->button());
#else
emit mousePressed(event->x(), event->y(), event->button());
#endif
Super::mousePressEvent(event);
}
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;

Qt::Edges getPosEdges(const QPoint& pos) const;
Qt::CursorShape getCursorShapeByEdge(const Qt::Edges& edges);

void doMoveTo(const QPoint& nowPos);

private:
TaoFrameLessViewPrivate* d;
std::unique_ptr<TaoFrameLessViewPrivate> d;
};
Loading

0 comments on commit feeeb75

Please sign in to comment.