From f8975a7d449bac21a2fdbc1a8ca85d1f5b99b362 Mon Sep 17 00:00:00 2001 From: Sine Striker <trueful@163.com> Date: 周二, 05 12月 2023 02:17:12 +0800 Subject: [PATCH] Implement mainwindow example --- examples/shared/widgetframe/CMakeLists.txt | 16 + examples/shared/widgetframe/windowbar.cpp | 288 ++++++++++++++++++++++++++++ examples/shared/widgetframe/windowbar_p.h | 50 +++++ src/quick/quickwindowagent.h | 4 src/core/contexts/abstractwindowcontext.cpp | 8 examples/mainwindow/CMakeLists.txt | 2 qmsetup | 2 examples/shared/widgetframe/windowbar.h | 70 +++++++ examples/mainwindow/mainwindow.h | 3 examples/shared/CMakeLists.txt | 1 src/widgets/widgetwindowagent.cpp | 4 src/widgets/widgetwindowagent.h | 4 examples/mainwindow/mainwindow.cpp | 89 ++++++++ examples/CMakeLists.txt | 2 14 files changed, 527 insertions(+), 16 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c6a5640..ea64e87 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1 +1,3 @@ +add_subdirectory(shared) + add_subdirectory(mainwindow) \ No newline at end of file diff --git a/examples/mainwindow/CMakeLists.txt b/examples/mainwindow/CMakeLists.txt index f981f1a..1554a8a 100644 --- a/examples/mainwindow/CMakeLists.txt +++ b/examples/mainwindow/CMakeLists.txt @@ -11,5 +11,5 @@ qm_configure_target(${PROJECT_NAME} SOURCES ${_src} QT_LINKS Core Gui Widgets - LINKS QWKWidgets + LINKS QWKWidgets WidgetFrame ) \ No newline at end of file diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index f551a7f..65c4b12 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -1,15 +1,96 @@ #include "mainwindow.h" #include <QtCore/QDebug> +#include <QtCore/QTime> +#include <QtWidgets/QPushButton> #include <QWKWidgets/widgetwindowagent.h> -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { - auto agent = new QWK::WidgetWindowAgent(this); - if (!agent->setup(this)) { - qDebug() << "Frameless handle failed to initialize."; +#include <widgetframe/windowbar.h> + +class ClockWidget : public QPushButton { +public: + explicit ClockWidget(QWidget *parent = nullptr) : QPushButton(parent) { + startTimer(100); } + + ~ClockWidget() override = default; + +protected: + void timerEvent(QTimerEvent *event) override { + setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss"))); + } +}; + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { + installWindowAgent(); } MainWindow::~MainWindow() { } + +void MainWindow::installWindowAgent() { + auto agent = new QWK::WidgetWindowAgent(this); + if (!agent->setup(this)) { + qDebug() << "Frameless handle failed to initialize."; + return; + } + + auto titleLabel = new QLabel(); + titleLabel->setAlignment(Qt::AlignCenter); + + auto menuBar = []() { + auto menuBar = new QMenuBar(); + auto file = new QMenu("File(&F)"); + file->addAction(new QAction("New(&N)")); + file->addAction(new QAction("Open(&O)")); + + auto edit = new QMenu("Edit(&E)"); + edit->addAction(new QAction("Undo(&U)")); + edit->addAction(new QAction("Redo(&R)")); + + menuBar->addMenu(file); + menuBar->addMenu(edit); + return menuBar; + }(); + + auto iconButton = new QPushButton("I"); + auto minButton = new QPushButton("鈥�"); + auto maxButton = new QPushButton("馃棖"); + maxButton->setCheckable(true); + auto closeButton = new QPushButton("鉁�"); + + auto windowBar = new QWK::WindowBar(); + windowBar->setIconButton(iconButton); + windowBar->setMinButton(minButton); + windowBar->setMaxButton(maxButton); + windowBar->setCloseButton(closeButton); + windowBar->setMenuBar(menuBar); + windowBar->setTitleLabel(titleLabel); + windowBar->setHostWidget(this); + + agent->setTitleBar(windowBar); + agent->setSystemButton(QWK::CoreWindowAgent::WindowIcon, iconButton); + agent->setSystemButton(QWK::CoreWindowAgent::Minimize, minButton); + agent->setSystemButton(QWK::CoreWindowAgent::Maximize, maxButton); + agent->setSystemButton(QWK::CoreWindowAgent::Close, closeButton); + agent->setHitTestVisible(menuBar, true); + + connect(windowBar, &QWK::WindowBar::minimizeRequested, this, &QWidget::showMinimized); + connect(windowBar, &QWK::WindowBar::maximizeRequested, this, [this](bool max) { + if (max) { + showMaximized(); + } else { + showNormal(); + } + }); + connect(windowBar, &QWK::WindowBar::closeRequested, this, &QWidget::close); + + auto clockWidget = new ClockWidget(); + clockWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + setMenuWidget(windowBar); + setCentralWidget(clockWidget); + setWindowTitle("Example MainWindow"); + resize(1024, 768); +} diff --git a/examples/mainwindow/mainwindow.h b/examples/mainwindow/mainwindow.h index c0d595d..46f23d3 100644 --- a/examples/mainwindow/mainwindow.h +++ b/examples/mainwindow/mainwindow.h @@ -7,6 +7,9 @@ public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); + +protected: + void installWindowAgent(); }; #endif // MAINWINDOW_H diff --git a/examples/shared/CMakeLists.txt b/examples/shared/CMakeLists.txt new file mode 100644 index 0000000..187da26 --- /dev/null +++ b/examples/shared/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(widgetframe) \ No newline at end of file diff --git a/examples/shared/widgetframe/CMakeLists.txt b/examples/shared/widgetframe/CMakeLists.txt new file mode 100644 index 0000000..ccd7aa6 --- /dev/null +++ b/examples/shared/widgetframe/CMakeLists.txt @@ -0,0 +1,16 @@ +project(WidgetFrame) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +file(GLOB _src *.h *.cpp) + +add_library(${PROJECT_NAME} STATIC) + +qm_configure_target(${PROJECT_NAME} + SOURCES ${_src} + QT_LINKS Core Gui Widgets +) + +target_include_directories(${PROJECT_NAME} PUBLIC . ..) \ No newline at end of file diff --git a/examples/shared/widgetframe/windowbar.cpp b/examples/shared/widgetframe/windowbar.cpp new file mode 100644 index 0000000..fba9a49 --- /dev/null +++ b/examples/shared/widgetframe/windowbar.cpp @@ -0,0 +1,288 @@ +#include "WindowBar.h" +#include "WindowBar_p.h" + +#include <QtCore/QDebug> +#include <QtGui/QtEvents> + +namespace QWK { + + WindowBarPrivate::WindowBarPrivate() { + w = nullptr; + autoTitle = true; + autoIcon = false; + } + + WindowBarPrivate::~WindowBarPrivate() { + } + + void WindowBarPrivate::init() { + Q_Q(WindowBar); + layout = new QHBoxLayout(); + layout->setMargin(0); + layout->setSpacing(0); + for (int i = IconButton; i <= CloseButton; ++i) { + insertDefaultSpace(i); + } + q->setLayout(layout); + } + + void WindowBarPrivate::setWidgetAt(int index, QWidget *widget) { + auto item = layout->takeAt(index); + auto orgWidget = item->widget(); + if (orgWidget) { + orgWidget->deleteLater(); + } + delete item; + if (!widget) { + insertDefaultSpace(index); + } else { + layout->insertWidget(index, widget); + } + } + + QWidget *WindowBarPrivate::takeWidgetAt(int index) { + auto item = layout->itemAt(index); + auto orgWidget = item->widget(); + if (orgWidget) { + item = layout->takeAt(index); + delete item; + insertDefaultSpace(index); + } + return orgWidget; + } + + WindowBar::WindowBar(QWidget *parent) : WindowBar(*new WindowBarPrivate(), parent) { + } + + WindowBar::~WindowBar() { + } + + QMenuBar *WindowBar::menuBar() const { + Q_D(const WindowBar); + return static_cast<QMenuBar *>(d->widgetAt(WindowBarPrivate::MenuWidget)); + } + + QLabel *WindowBar::titleLabel() const { + Q_D(const WindowBar); + return static_cast<QLabel *>(d->widgetAt(WindowBarPrivate::TitleLabel)); + } + + QAbstractButton *WindowBar::iconButton() const { + Q_D(const WindowBar); + return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::IconButton)); + } + + QAbstractButton *WindowBar::minButton() const { + Q_D(const WindowBar); + return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::MinimumButton)); + } + + QAbstractButton *WindowBar::maxButton() const { + Q_D(const WindowBar); + return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::MaximumButton)); + } + + QAbstractButton *WindowBar::closeButton() const { + Q_D(const WindowBar); + return static_cast<QAbstractButton *>(d->widgetAt(WindowBarPrivate::CloseButton)); + } + + void WindowBar::setMenuBar(QMenuBar *menuBar) { + Q_D(WindowBar); + auto org = takeMenuBar(); + if (org) + org->deleteLater(); + if (!menuBar) + return; + d->setWidgetAt(WindowBarPrivate::MenuWidget, menuBar); + menuBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); + } + + void WindowBar::setTitleLabel(QLabel *label) { + Q_D(WindowBar); + auto org = takeTitleLabel(); + if (org) + org->deleteLater(); + if (!label) + return; + d->setWidgetAt(WindowBarPrivate::TitleLabel, label); + if (d->autoTitle && d->w) + label->setText(d->w->windowTitle()); + label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + } + + void WindowBar::setIconButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeIconButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::IconButton, btn); + if (d->autoIcon && d->w) + btn->setIcon(d->w->windowIcon()); + btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + } + + void WindowBar::setMinButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeMinButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::MinimumButton, btn); + connect(btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested); + } + + void WindowBar::setMaxButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeMaxButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::MaximumButton, btn); + connect(btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested); + } + + void WindowBar::setCloseButton(QAbstractButton *btn) { + Q_D(WindowBar); + auto org = takeCloseButton(); + if (org) + org->deleteLater(); + if (!btn) + return; + d->setWidgetAt(WindowBarPrivate::CloseButton, btn); + connect(btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested); + } + + QMenuBar *WindowBar::takeMenuBar() { + Q_D(WindowBar); + return static_cast<QMenuBar *>(d->takeWidgetAt(WindowBarPrivate::MenuWidget)); + } + + QLabel *WindowBar::takeTitleLabel() { + Q_D(WindowBar); + return static_cast<QLabel *>(d->takeWidgetAt(WindowBarPrivate::TitleLabel)); + } + + QAbstractButton *WindowBar::takeIconButton() { + Q_D(WindowBar); + return static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::IconButton)); + } + + QAbstractButton *WindowBar::takeMinButton() { + Q_D(WindowBar); + auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::MinimumButton)); + if (!btn) { + return nullptr; + } + disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::minimizeRequested); + return btn; + } + + QAbstractButton *WindowBar::takeMaxButton() { + Q_D(WindowBar); + auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::MaximumButton)); + if (!btn) { + return nullptr; + } + disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::maximizeRequested); + return btn; + } + + QAbstractButton *WindowBar::takeCloseButton() { + Q_D(WindowBar); + auto btn = static_cast<QAbstractButton *>(d->takeWidgetAt(WindowBarPrivate::CloseButton)); + if (!btn) { + return nullptr; + } + disconnect(btn, &QAbstractButton::clicked, this, &WindowBar::closeRequested); + return btn; + } + + QWidget *WindowBar::hostWidget() const { + Q_D(const WindowBar); + return d->w; + } + + void WindowBar::setHostWidget(QWidget *w) { + Q_D(WindowBar); + + QWidget *org = d->w; + if (org) { + org->removeEventFilter(this); + } + d_ptr->w = w; + if (w) { + w->installEventFilter(this); + } + } + + bool WindowBar::titleFollowWindow() const { + Q_D(const WindowBar); + return d->autoTitle; + } + + void WindowBar::setTitleFollowWindow(bool value) { + Q_D(WindowBar); + d->autoTitle = value; + } + + bool WindowBar::iconFollowWindow() const { + Q_D(const WindowBar); + return d->autoIcon; + } + + void WindowBar::setIconFollowWindow(bool value) { + Q_D(WindowBar); + d->autoIcon = value; + } + + bool WindowBar::eventFilter(QObject *obj, QEvent *event) { + Q_D(WindowBar); + auto w = d->w; + if (obj == w) { + QAbstractButton *iconBtn = iconButton(); + QLabel *label = titleLabel(); + QAbstractButton *maxBtn = maxButton(); + switch (event->type()) { + case QEvent::WindowIconChange: + if (d_ptr->autoIcon && iconBtn) { + iconBtn->setIcon(w->windowIcon()); + iconChanged(w->windowIcon()); + } + break; + case QEvent::WindowTitleChange: + if (d_ptr->autoTitle && label) { + label->setText(w->windowTitle()); + titleChanged(w->windowTitle()); + } + break; + case QEvent::WindowStateChange: + if (maxBtn) { + maxBtn->setChecked(w->isMaximized()); + } + break; + default: + break; + } + } + return QWidget::eventFilter(obj, event); + } + + void WindowBar::titleChanged(const QString &text) { + Q_UNUSED(text) + } + + void WindowBar::iconChanged(const QIcon &icon){Q_UNUSED(icon)} + + WindowBar::WindowBar(WindowBarPrivate &d, QWidget *parent) + : QFrame(parent), d_ptr(&d) { + d.q_ptr = this; + + d.init(); + } + +} diff --git a/examples/shared/widgetframe/windowbar.h b/examples/shared/widgetframe/windowbar.h new file mode 100644 index 0000000..e8ea69b --- /dev/null +++ b/examples/shared/widgetframe/windowbar.h @@ -0,0 +1,70 @@ +#ifndef WINDOWBAR_H +#define WINDOWBAR_H + +#include <QFrame> +#include <QAbstractButton> +#include <QMenuBar> +#include <QLabel> + +namespace QWK { + + class WindowBarPrivate; + + class WindowBar : public QFrame { + Q_OBJECT + Q_DECLARE_PRIVATE(WindowBar) + public: + explicit WindowBar(QWidget *parent = nullptr); + ~WindowBar(); + + public: + QMenuBar *menuBar() const; + QLabel *titleLabel() const; + QAbstractButton *iconButton() const; + QAbstractButton *minButton() const; + QAbstractButton *maxButton() const; + QAbstractButton *closeButton() const; + + void setMenuBar(QMenuBar *menuBar); + void setTitleLabel(QLabel *label); + void setIconButton(QAbstractButton *btn); + void setMinButton(QAbstractButton *btn); + void setMaxButton(QAbstractButton *btn); + void setCloseButton(QAbstractButton *btn); + + QMenuBar *takeMenuBar(); + QLabel *takeTitleLabel(); + QAbstractButton *takeIconButton(); + QAbstractButton *takeMinButton(); + QAbstractButton *takeMaxButton(); + QAbstractButton *takeCloseButton(); + + QWidget *hostWidget() const; + void setHostWidget(QWidget *w); + + bool titleFollowWindow() const; + void setTitleFollowWindow(bool value); + + bool iconFollowWindow() const; + void setIconFollowWindow(bool value); + + Q_SIGNALS: + void minimizeRequested(); + void maximizeRequested(bool max = false); + void closeRequested(); + + protected: + bool eventFilter(QObject *obj, QEvent *event) override; + + virtual void titleChanged(const QString &text); + virtual void iconChanged(const QIcon &icon); + + protected: + WindowBar(WindowBarPrivate &d, QWidget *parent = nullptr); + + QScopedPointer<WindowBarPrivate> d_ptr; + }; + +} + +#endif // WINDOWBAR_H \ No newline at end of file diff --git a/examples/shared/widgetframe/windowbar_p.h b/examples/shared/widgetframe/windowbar_p.h new file mode 100644 index 0000000..cea8a99 --- /dev/null +++ b/examples/shared/widgetframe/windowbar_p.h @@ -0,0 +1,50 @@ +#ifndef WINDOWBARPRIVATE_H +#define WINDOWBARPRIVATE_H + +#include <QBoxLayout> + +#include "WindowBar.h" + +namespace QWK { + + class WindowBarPrivate { + Q_DECLARE_PUBLIC(WindowBar) + public: + WindowBarPrivate(); + virtual ~WindowBarPrivate(); + + void init(); + + WindowBar *q_ptr; + + QWidget *w; + bool autoTitle; + bool autoIcon; + + enum WindowBarItem { + IconButton, + MenuWidget, + TitleLabel, + MinimumButton, + MaximumButton, + CloseButton, + }; + + QHBoxLayout *layout; + + inline QWidget *widgetAt(int index) const { + return layout->itemAt(index)->widget(); + } + + void setWidgetAt(int index, QWidget *widget); + + QWidget *takeWidgetAt(int index); + + inline void insertDefaultSpace(int index) { + layout->insertSpacerItem(index, new QSpacerItem(0, 0)); + } + }; + +} + +#endif // WINDOWBARPRIVATE_H \ No newline at end of file diff --git a/qmsetup b/qmsetup index 65369fc..451eaba 160000 --- a/qmsetup +++ b/qmsetup @@ -1 +1 @@ -Subproject commit 65369fcf7def72a0aeec59724cdb63e9c5f0475d +Subproject commit 451eabac4f7249fab81295509cbbc4967353a634 diff --git a/src/core/contexts/abstractwindowcontext.cpp b/src/core/contexts/abstractwindowcontext.cpp index 2e32d25..5329634 100644 --- a/src/core/contexts/abstractwindowcontext.cpp +++ b/src/core/contexts/abstractwindowcontext.cpp @@ -129,22 +129,22 @@ if (currentButton && m_delegate->isVisible(currentButton) && m_delegate->isEnabled(currentButton) && m_delegate->mapGeometryToScene(currentButton).contains(pos)) { - return true; + return false; } } for (auto widget : m_hitTestVisibleItems) { if (widget && m_delegate->isVisible(widget) && m_delegate->isEnabled(widget) && m_delegate->mapGeometryToScene(widget).contains(pos)) { - return true; + return false; } } if (hitTestShape().contains(pos)) { - return true; + return false; } - return false; + return true; } } \ No newline at end of file diff --git a/src/quick/quickwindowagent.h b/src/quick/quickwindowagent.h index 8935777..eb408ed 100644 --- a/src/quick/quickwindowagent.h +++ b/src/quick/quickwindowagent.h @@ -28,8 +28,8 @@ void setSystemButton(SystemButton button, QQuickItem *item); bool isHitTestVisible(QQuickItem *item) const; - void setHitTestVisible(QQuickItem *item, bool visible); - void setHitTestVisible(const QRect &rect, bool visible); + void setHitTestVisible(QQuickItem *item, bool visible = true); + void setHitTestVisible(const QRect &rect, bool visible = true); Q_SIGNALS: void titleBarWidgetChanged(QQuickItem *item); diff --git a/src/widgets/widgetwindowagent.cpp b/src/widgets/widgetwindowagent.cpp index 91f5031..73a4334 100644 --- a/src/widgets/widgetwindowagent.cpp +++ b/src/widgets/widgetwindowagent.cpp @@ -53,12 +53,12 @@ Q_EMIT titleBarWidgetChanged(w); } - QWidget *WidgetWindowAgent::systemButton(CoreWindowAgent::SystemButton button) const { + QWidget *WidgetWindowAgent::systemButton(SystemButton button) const { Q_D(const WidgetWindowAgent); return static_cast<QWidget *>(d->context->systemButton(button)); } - void WidgetWindowAgent::setSystemButton(CoreWindowAgent::SystemButton button, QWidget *w) { + void WidgetWindowAgent::setSystemButton(SystemButton button, QWidget *w) { Q_D(WidgetWindowAgent); if (!d->context->setSystemButton(button, w)) { return; diff --git a/src/widgets/widgetwindowagent.h b/src/widgets/widgetwindowagent.h index dd3e2d9..791646a 100644 --- a/src/widgets/widgetwindowagent.h +++ b/src/widgets/widgetwindowagent.h @@ -27,8 +27,8 @@ void setSystemButton(SystemButton button, QWidget *w); bool isHitTestVisible(QWidget *w) const; - void setHitTestVisible(QWidget *w, bool visible); - void setHitTestVisible(const QRect &rect, bool visible); + void setHitTestVisible(QWidget *w, bool visible = true); + void setHitTestVisible(const QRect &rect, bool visible = true); Q_SIGNALS: void titleBarWidgetChanged(QWidget *w); -- Gitblit v1.9.1