FramelessMainWindowLinux

This commit is contained in:
Le Tan 2021-10-20 21:23:39 +08:00
parent 5bc48be5d0
commit 810438b5e5
11 changed files with 357 additions and 31 deletions

View File

@ -21,6 +21,12 @@ NotebookMgr::NotebookMgr(QObject *p_parent)
{ {
} }
void NotebookMgr::close()
{
m_notebooks.clear();
m_currentNotebookId = -1;
}
void NotebookMgr::init() void NotebookMgr::init()
{ {
initVersionControllerServer(); initVersionControllerServer();

View File

@ -32,6 +32,8 @@ namespace vnotex
void init(); void init();
void close();
QSharedPointer<INotebookFactory> getBundleNotebookFactory() const; QSharedPointer<INotebookFactory> getBundleNotebookFactory() const;
QList<QSharedPointer<INotebookFactory>> getAllNotebookFactories() const; QList<QSharedPointer<INotebookFactory>> getAllNotebookFactories() const;

View File

@ -10,8 +10,6 @@ FramelessMainWindow::FramelessMainWindow(bool p_frameless, QWidget *p_parent)
m_defaultFlags(windowFlags()) m_defaultFlags(windowFlags())
{ {
if (m_frameless) { if (m_frameless) {
m_resizeAreaWidth *= devicePixelRatio();
setWindowFlags(m_defaultFlags | Qt::FramelessWindowHint); setWindowFlags(m_defaultFlags | Qt::FramelessWindowHint);
} }
} }
@ -27,7 +25,6 @@ void FramelessMainWindow::setTitleBar(QWidget *p_titleBar)
Q_ASSERT(!m_titleBar && m_frameless); Q_ASSERT(!m_titleBar && m_frameless);
m_titleBar = p_titleBar; m_titleBar = p_titleBar;
m_titleBar->installEventFilter(this);
} }
void FramelessMainWindow::changeEvent(QEvent *p_event) void FramelessMainWindow::changeEvent(QEvent *p_event)
@ -36,7 +33,8 @@ void FramelessMainWindow::changeEvent(QEvent *p_event)
if (p_event->type() == QEvent::WindowStateChange) { if (p_event->type() == QEvent::WindowStateChange) {
m_windowStates = windowState(); m_windowStates = windowState();
m_resizable = m_movable = m_windowStates == Qt::WindowNoState; m_resizable = m_windowStates == Qt::WindowNoState;
m_movable = m_windowStates == Qt::WindowNoState;
emit windowStateChanged(m_windowStates); emit windowStateChanged(m_windowStates);
} }
} }

View File

@ -13,11 +13,11 @@ namespace vnotex
{ {
Q_OBJECT Q_OBJECT
public: public:
FramelessMainWindow(bool p_frameless, QWidget *p_parent); FramelessMainWindow(bool p_frameless, QWidget *p_parent = nullptr);
bool isFrameless() const; bool isFrameless() const;
void setTitleBar(QWidget *p_titleBar); virtual void setTitleBar(QWidget *p_titleBar);
signals: signals:
void windowStateChanged(Qt::WindowStates p_state); void windowStateChanged(Qt::WindowStates p_state);
@ -30,8 +30,6 @@ namespace vnotex
const bool m_frameless = true; const bool m_frameless = true;
int m_resizeAreaWidth = 5;
bool m_movable = true; bool m_movable = true;
bool m_resizable = true; bool m_resizable = true;

View File

@ -2,13 +2,14 @@
#define FRAMELESSMAINWINDOWIMPL_H #define FRAMELESSMAINWINDOWIMPL_H
#include "framelessmainwindowwin.h" #include "framelessmainwindowwin.h"
#include "framelessmainwindowlinux.h"
namespace vnotex namespace vnotex
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
typedef FramelessMainWindowWin FramelessMainWindowImpl; typedef FramelessMainWindowWin FramelessMainWindowImpl;
#else #else
typedef FramelessMainWindow FramelessMainWindowImpl; typedef FramelessMainWindowLinux FramelessMainWindowImpl;
#endif #endif
} }

View File

@ -0,0 +1,233 @@
#include "framelessmainwindowlinux.h"
#ifndef Q_OS_WIN
#include <QEvent>
#include <QMouseEvent>
#include <QDebug>
#include <QHoverEvent>
#include <QGuiApplication>
using namespace vnotex;
FramelessMainWindowLinux::FramelessMainWindowLinux(bool p_frameless, QWidget *p_parent)
: FramelessMainWindow(p_frameless, p_parent)
{
if (m_frameless) {
// installEventFilter(this);
}
}
bool FramelessMainWindowLinux::eventFilter(QObject *p_obj, QEvent *p_event)
{
if (!m_frameless) {
return FramelessMainWindow::eventFilter(p_obj, p_event);
}
if (p_obj == m_titleBar) {
const auto type = p_event->type();
if (type == QEvent::MouseButtonDblClick
|| type == QEvent::NonClientAreaMouseButtonDblClick) {
if (!(m_windowStates & Qt::WindowFullScreen)) {
if (m_windowStates & Qt::WindowMaximized) {
showNormal();
} else {
showMaximized();
}
}
}
} else if (p_obj == this) {
doResize(p_event);
}
return FramelessMainWindow::eventFilter(p_obj, p_event);
}
void FramelessMainWindowLinux::setTitleBar(QWidget *p_titleBar)
{
FramelessMainWindow::setTitleBar(p_titleBar);
m_titleBar->installEventFilter(this);
}
void FramelessMainWindowLinux::mousePressEvent(QMouseEvent *p_event)
{
FramelessMainWindow::mousePressEvent(p_event);
if (m_frameless) {
recordMousePress(p_event->pos());
}
}
void FramelessMainWindowLinux::recordMousePress(const QPoint &p_pos)
{
m_mousePressed = true;
m_mousePressPoint = p_pos;
m_rectOnMousePress = geometry();
m_mousePressArea = hitArea(m_mousePressPoint);
}
void FramelessMainWindowLinux::mouseReleaseEvent(QMouseEvent *p_event)
{
FramelessMainWindow::mouseReleaseEvent(p_event);
if (m_frameless) {
// setCursor(Qt::ArrowCursor);
m_mousePressed = false;
}
}
void FramelessMainWindowLinux::mouseMoveEvent(QMouseEvent *p_event)
{
FramelessMainWindow::mouseMoveEvent(p_event);
if (m_frameless) {
Q_ASSERT(m_mousePressed);
if (m_movable && m_mousePressArea == Area::Caption) {
const auto delta = p_event->pos() - m_mousePressPoint;
move(pos() + delta);
}
}
}
void FramelessMainWindowLinux::doResize(QEvent *p_event)
{
Q_UNUSED(p_event);
#if 0
static bool needResetCursor = false;
switch (p_event->type()) {
case QEvent::HoverMove:
{
if (!m_resizable) {
return;
}
auto eve = static_cast<QHoverEvent *>(p_event);
const auto evePos = eve->pos();
const auto area = hitArea(evePos);
if (!m_mousePressed && area != Area::None && area != Area::Caption) {
// Mouse press event may be blocked by the children of QMainWindow.
if (QGuiApplication::mouseButtons() != Qt::NoButton) {
recordMousePress(evePos);
return;
}
}
if (m_mousePressed) {
const auto delta = evePos - m_mousePressPoint;
switch (m_mousePressArea) {
case Area::Left:
{
int newWidth = m_rectOnMousePress.width() - delta.x();
qDebug() << newWidth << minimumWidth();
if (minimumWidth() <= newWidth) {
setGeometry(m_rectOnMousePress.x() + delta.x(),
m_rectOnMousePress.y(),
newWidth,
m_rectOnMousePress.height());
}
break;
}
default:
break;
}
} else {
switch (area) {
case Area::Left:
Q_FALLTHROUGH();
case Area::Right:
needResetCursor = true;
setCursor(Qt::SizeHorCursor);
break;
case Area::Top:
Q_FALLTHROUGH();
case Area::Bottom:
needResetCursor = true;
setCursor(Qt::SizeVerCursor);
break;
case Area::TopLeft:
Q_FALLTHROUGH();
case Area::BottomRight:
needResetCursor = true;
setCursor(Qt::SizeFDiagCursor);
break;
case Area::TopRight:
Q_FALLTHROUGH();
case Area::BottomLeft:
needResetCursor = true;
setCursor(Qt::SizeBDiagCursor);
break;
default:
if (needResetCursor) {
needResetCursor = false;
setCursor(Qt::ArrowCursor);
}
break;
}
}
return;
}
default:
break;
}
#endif
}
FramelessMainWindowLinux::Area FramelessMainWindowLinux::hitArea(const QPoint &p_pos) const
{
const int x = p_pos.x();
const int y = p_pos.y();
Area area = Area::None;
if (x < m_resizeAreaWidth) {
// Left.
if (y < m_resizeAreaWidth) {
// Top.
area = Area::TopLeft;
} else if (y > height() - m_resizeAreaWidth) {
// Bottom.
area = Area::BottomLeft;
} else {
area = Area::Left;
}
} else if (x > width() - m_resizeAreaWidth) {
// Right.
if (y < m_resizeAreaWidth) {
// Top.
area = Area::TopRight;
} else if (y > height() - m_resizeAreaWidth) {
// Bottom.
area = Area::BottomRight;
} else {
area = Area::Right;
}
} else if (y < m_resizeAreaWidth) {
// Top.
area = Area::Top;
} else if (y > height() - m_resizeAreaWidth) {
// Bottom.
area = Area::Bottom;
} else if (y < m_titleBarHeight) {
area = Area::Caption;
}
return area;
}
void FramelessMainWindowLinux::showEvent(QShowEvent *p_event)
{
FramelessMainWindow::showEvent(p_event);
if (m_frameless && m_titleBarHeight == 0 && m_titleBar) {
m_titleBarHeight = m_titleBar->height();
}
}
#endif

View File

@ -0,0 +1,71 @@
#ifndef FRAMELESSMAINWINDOWLINUX_H
#define FRAMELESSMAINWINDOWLINUX_H
#include "framelessmainwindow.h"
#include <QRect>
#include <QVector>
namespace vnotex
{
#ifndef Q_OS_WIN
class FramelessMainWindowLinux : public FramelessMainWindow
{
Q_OBJECT
public:
FramelessMainWindowLinux(bool p_frameless, QWidget *p_parent = nullptr);
void setTitleBar(QWidget *p_titleBar) Q_DECL_OVERRIDE;
protected:
bool eventFilter(QObject *p_obj, QEvent *p_event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *p_event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *p_event) Q_DECL_OVERRIDE;
void mouseMoveEvent(QMouseEvent *p_event) Q_DECL_OVERRIDE;
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
private:
enum Area
{
Left = 0,
TopLeft,
Top,
TopRight,
Right,
BottomRight,
Bottom,
BottomLeft,
Caption,
None
};
Area hitArea(const QPoint &p_pos) const;
void doResize(QEvent *p_event);
void recordMousePress(const QPoint &p_pos);
const int m_resizeAreaWidth = 6;
int m_titleBarHeight = 0;
Area m_mousePressArea = Area::None;
QPoint m_mousePressPoint;
bool m_mousePressed = false;
QRect m_rectOnMousePress;
};
#else
class FramelessMainWindowLinuxDummy
{
};
#endif
}
#endif // FRAMELESSMAINWINDOWLINUX_H

View File

@ -18,6 +18,8 @@ FramelessMainWindowWin::FramelessMainWindowWin(bool p_frameless, QWidget *p_pare
: FramelessMainWindow(p_frameless, p_parent) : FramelessMainWindow(p_frameless, p_parent)
{ {
if (m_frameless) { if (m_frameless) {
m_resizeAreaWidth *= devicePixelRatio();
m_redrawTimer = new QTimer(this); m_redrawTimer = new QTimer(this);
m_redrawTimer->setSingleShot(true); m_redrawTimer->setSingleShot(true);
m_redrawTimer->setInterval(500); m_redrawTimer->setInterval(500);
@ -68,31 +70,36 @@ bool FramelessMainWindowWin::nativeEvent(const QByteArray &p_eventType, void *p_
::GetWindowRect(msg->hwnd, &windowRect); ::GetWindowRect(msg->hwnd, &windowRect);
// x and y could not be compared with width() and height() in hidpi case. // x and y could not be compared with width() and height() in hidpi case.
int x = static_cast<int>(GET_X_LPARAM(msg->lParam) - windowRect.left); const int x = static_cast<int>(GET_X_LPARAM(msg->lParam) - windowRect.left);
int y = static_cast<int>(GET_Y_LPARAM(msg->lParam) - windowRect.top); const int y = static_cast<int>(GET_Y_LPARAM(msg->lParam) - windowRect.top);
bool onLeft = x < m_resizeAreaWidth;
bool onRight = x > windowRect.right - windowRect.left - m_resizeAreaWidth;
bool onTop = y < m_resizeAreaWidth;
bool onBottom = y > windowRect.bottom - windowRect.top - m_resizeAreaWidth;
*p_result = 0; *p_result = 0;
if (m_resizable) { if (m_resizable) {
if (onLeft && onTop) { if (x < m_resizeAreaWidth) {
// Left.
if (y < m_resizeAreaWidth) {
// Top.
*p_result = HTTOPLEFT; *p_result = HTTOPLEFT;
} else if (onLeft && onBottom) { } else if (y > windowRect.bottom - windowRect.top - m_resizeAreaWidth) {
// Bottom.
*p_result = HTBOTTOMLEFT; *p_result = HTBOTTOMLEFT;
} else if (onRight && onTop) { } else {
*p_result = HTTOPRIGHT;
} else if (onRight && onBottom) {
*p_result = HTBOTTOMRIGHT;
} else if (onLeft) {
*p_result = HTLEFT; *p_result = HTLEFT;
} else if (onRight) { }
} else if (x > windowRect.right - windowRect.left - m_resizeAreaWidth) {
// Right.
if (y < m_resizeAreaWidth) {
// Top.
*p_result = HTTOPRIGHT;
} else if (y > windowRect.bottom - windowRect.top - m_resizeAreaWidth) {
// Bottom.
*p_result = HTBOTTOMRIGHT;
} else {
*p_result = HTRIGHT; *p_result = HTRIGHT;
} else if (onTop) { }
} else if (y < m_resizeAreaWidth) {
*p_result = HTTOP; *p_result = HTTOP;
} else if (onBottom) { } else if (y > windowRect.bottom - windowRect.top - m_resizeAreaWidth) {
*p_result = HTBOTTOM; *p_result = HTBOTTOM;
} }
} }

View File

@ -10,7 +10,7 @@ namespace vnotex
{ {
Q_OBJECT Q_OBJECT
public: public:
FramelessMainWindowWin(bool p_frameless = true, QWidget *p_parent = nullptr); FramelessMainWindowWin(bool p_frameless, QWidget *p_parent = nullptr);
protected: protected:
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) #if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
@ -27,6 +27,8 @@ namespace vnotex
void updateMargins(); void updateMargins();
int m_resizeAreaWidth = 6;
QTimer *m_redrawTimer = nullptr; QTimer *m_redrawTimer = nullptr;
QSize m_sizeBeforeMove; QSize m_sizeBeforeMove;
@ -35,6 +37,10 @@ namespace vnotex
int m_titleBarHeight = 0; int m_titleBarHeight = 0;
}; };
#else
class FramelessMainWindowWinDummy
{
};
#endif #endif
} }

View File

@ -547,6 +547,8 @@ void MainWindow::closeOnQuit()
{ {
// No user interaction is available. // No user interaction is available.
emit mainWindowClosedOnQuit(); emit mainWindowClosedOnQuit();
VNoteX::getInst().getNotebookMgr().close();
} }
void MainWindow::setupShortcuts() void MainWindow::setupShortcuts()

View File

@ -59,6 +59,7 @@ SOURCES += \
$$PWD/findandreplacewidget.cpp \ $$PWD/findandreplacewidget.cpp \
$$PWD/floatingwidget.cpp \ $$PWD/floatingwidget.cpp \
$$PWD/framelessmainwindow/framelessmainwindow.cpp \ $$PWD/framelessmainwindow/framelessmainwindow.cpp \
$$PWD/framelessmainwindow/framelessmainwindowlinux.cpp \
$$PWD/framelessmainwindow/framelessmainwindowwin.cpp \ $$PWD/framelessmainwindow/framelessmainwindowwin.cpp \
$$PWD/fullscreentoggleaction.cpp \ $$PWD/fullscreentoggleaction.cpp \
$$PWD/historypanel.cpp \ $$PWD/historypanel.cpp \
@ -185,6 +186,7 @@ HEADERS += \
$$PWD/floatingwidget.h \ $$PWD/floatingwidget.h \
$$PWD/framelessmainwindow/framelessmainwindow.h \ $$PWD/framelessmainwindow/framelessmainwindow.h \
$$PWD/framelessmainwindow/framelessmainwindowimpl.h \ $$PWD/framelessmainwindow/framelessmainwindowimpl.h \
$$PWD/framelessmainwindow/framelessmainwindowlinux.h \
$$PWD/framelessmainwindow/framelessmainwindowwin.h \ $$PWD/framelessmainwindow/framelessmainwindowwin.h \
$$PWD/fullscreentoggleaction.h \ $$PWD/fullscreentoggleaction.h \
$$PWD/historypanel.h \ $$PWD/historypanel.h \