Browse Source

FramelessMainWindowLinux

Le Tan 4 years ago
parent
commit
810438b5e5

+ 6 - 0
src/core/notebookmgr.cpp

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

+ 2 - 0
src/core/notebookmgr.h

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

+ 2 - 4
src/widgets/framelessmainwindow/framelessmainwindow.cpp

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

+ 2 - 4
src/widgets/framelessmainwindow/framelessmainwindow.h

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

+ 2 - 1
src/widgets/framelessmainwindow/framelessmainwindowimpl.h

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

+ 233 - 0
src/widgets/framelessmainwindow/framelessmainwindowlinux.cpp

@@ -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

+ 71 - 0
src/widgets/framelessmainwindow/framelessmainwindowlinux.h

@@ -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

+ 28 - 21
src/widgets/framelessmainwindow/framelessmainwindowwin.cpp

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

+ 7 - 1
src/widgets/framelessmainwindow/framelessmainwindowwin.h

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

+ 2 - 0
src/widgets/mainwindow.cpp

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

+ 2 - 0
src/widgets/widgets.pri

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