feat: add option to provide a titlebar (default on)
This commit is contained in:
@@ -44,6 +44,7 @@ set (PPIC_CPP_FILES
|
|||||||
app/graphicsview.cpp
|
app/graphicsview.cpp
|
||||||
app/graphicsscene.cpp
|
app/graphicsscene.cpp
|
||||||
app/bottombuttongroup.cpp
|
app/bottombuttongroup.cpp
|
||||||
|
app/titlebar.cpp
|
||||||
app/navigatorview.cpp
|
app/navigatorview.cpp
|
||||||
app/opacityhelper.cpp
|
app/opacityhelper.cpp
|
||||||
app/toolbutton.cpp
|
app/toolbutton.cpp
|
||||||
@@ -65,6 +66,7 @@ set (PPIC_HEADER_FILES
|
|||||||
app/graphicsview.h
|
app/graphicsview.h
|
||||||
app/graphicsscene.h
|
app/graphicsscene.h
|
||||||
app/bottombuttongroup.h
|
app/bottombuttongroup.h
|
||||||
|
app/titlebar.h
|
||||||
app/navigatorview.h
|
app/navigatorview.h
|
||||||
app/opacityhelper.h
|
app/opacityhelper.h
|
||||||
app/toolbutton.h
|
app/toolbutton.h
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "toolbutton.h"
|
#include "toolbutton.h"
|
||||||
#include "bottombuttongroup.h"
|
#include "bottombuttongroup.h"
|
||||||
|
#include "titlebar.h"
|
||||||
#include "graphicsview.h"
|
#include "graphicsview.h"
|
||||||
#include "navigatorview.h"
|
#include "navigatorview.h"
|
||||||
#include "graphicsscene.h"
|
#include "graphicsscene.h"
|
||||||
@@ -101,20 +102,20 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
connect(m_graphicsView, &GraphicsView::viewportRectChanged,
|
connect(m_graphicsView, &GraphicsView::viewportRectChanged,
|
||||||
m_gv, &NavigatorView::updateMainViewportRegion);
|
m_gv, &NavigatorView::updateMainViewportRegion);
|
||||||
|
|
||||||
m_closeButton = new ToolButton(true, m_graphicsView);
|
m_titleBar = new TitleBar(this);
|
||||||
m_closeButton->setIconSize(QSize(32, 32));
|
m_titleBar->setCloseButtonOnly(!Settings::instance()->showTitleBar());
|
||||||
m_closeButton->setFixedSize(QSize(50, 50));
|
|
||||||
m_closeButton->setIconResourcePath(":/icons/window-close.svg");
|
|
||||||
|
|
||||||
connect(m_closeButton, &QAbstractButton::clicked,
|
connect(m_titleBar, &TitleBar::closeRequested,
|
||||||
this, &MainWindow::closeWindow);
|
this, &MainWindow::closeWindow);
|
||||||
|
connect(m_titleBar, &TitleBar::maximizeToggleRequested,
|
||||||
|
this, &MainWindow::toggleMaximize);
|
||||||
|
|
||||||
m_prevButton = new ToolButton(false, m_graphicsView);
|
m_prevButton = new ToolButton(m_graphicsView);
|
||||||
m_prevButton->setIconSize(QSize(75, 75));
|
m_prevButton->setIconSize(QSize(75, 75));
|
||||||
m_prevButton->setIconResourcePath(":/icons/go-previous.svg");
|
m_prevButton->setIconResourcePath(":/icons/go-previous.svg");
|
||||||
m_prevButton->setVisible(false);
|
m_prevButton->setVisible(false);
|
||||||
m_prevButton->setOpacity(0, false);
|
m_prevButton->setOpacity(0, false);
|
||||||
m_nextButton = new ToolButton(false, m_graphicsView);
|
m_nextButton = new ToolButton(m_graphicsView);
|
||||||
m_nextButton->setIconSize(QSize(75, 75));
|
m_nextButton->setIconSize(QSize(75, 75));
|
||||||
m_nextButton->setIconResourcePath(":/icons/go-next.svg");
|
m_nextButton->setIconResourcePath(":/icons/go-next.svg");
|
||||||
m_nextButton->setVisible(false);
|
m_nextButton->setVisible(false);
|
||||||
@@ -138,7 +139,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
|
|
||||||
m_bottomButtonGroup->setOpacity(0, false);
|
m_bottomButtonGroup->setOpacity(0, false);
|
||||||
m_gv->setOpacity(0, false);
|
m_gv->setOpacity(0, false);
|
||||||
m_closeButton->setOpacity(0, false);
|
m_titleBar->setOpacity(0, false);
|
||||||
|
|
||||||
connect(m_pm, &PlaylistManager::totalCountChanged, this, &MainWindow::updateGalleryButtonsVisibility);
|
connect(m_pm, &PlaylistManager::totalCountChanged, this, &MainWindow::updateGalleryButtonsVisibility);
|
||||||
|
|
||||||
@@ -161,7 +162,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
});
|
});
|
||||||
|
|
||||||
// allow some mouse events can go through these widgets for resizing window.
|
// allow some mouse events can go through these widgets for resizing window.
|
||||||
installResizeCapture(m_closeButton);
|
installResizeCapture(m_titleBar);
|
||||||
installResizeCapture(m_graphicsView);
|
installResizeCapture(m_graphicsView);
|
||||||
installResizeCapture(m_graphicsView->viewport());
|
installResizeCapture(m_graphicsView->viewport());
|
||||||
installResizeCapture(m_gv);
|
installResizeCapture(m_gv);
|
||||||
@@ -323,7 +324,7 @@ void MainWindow::enterEvent(QEnterEvent *event)
|
|||||||
m_bottomButtonGroup->setOpacity(1);
|
m_bottomButtonGroup->setOpacity(1);
|
||||||
m_gv->setOpacity(1);
|
m_gv->setOpacity(1);
|
||||||
|
|
||||||
m_closeButton->setOpacity(1);
|
m_titleBar->setOpacity(1);
|
||||||
m_prevButton->setOpacity(1);
|
m_prevButton->setOpacity(1);
|
||||||
m_nextButton->setOpacity(1);
|
m_nextButton->setOpacity(1);
|
||||||
|
|
||||||
@@ -335,7 +336,7 @@ void MainWindow::leaveEvent(QEvent *event)
|
|||||||
m_bottomButtonGroup->setOpacity(0);
|
m_bottomButtonGroup->setOpacity(0);
|
||||||
m_gv->setOpacity(0);
|
m_gv->setOpacity(0);
|
||||||
|
|
||||||
m_closeButton->setOpacity(0);
|
m_titleBar->setOpacity(0);
|
||||||
m_prevButton->setOpacity(0);
|
m_prevButton->setOpacity(0);
|
||||||
m_nextButton->setOpacity(0);
|
m_nextButton->setOpacity(0);
|
||||||
|
|
||||||
@@ -612,7 +613,12 @@ void MainWindow::closeWindow()
|
|||||||
|
|
||||||
void MainWindow::updateWidgetsPosition()
|
void MainWindow::updateWidgetsPosition()
|
||||||
{
|
{
|
||||||
m_closeButton->move(width() - m_closeButton->width(), 0);
|
if (m_titleBar->closeButtonOnly()) {
|
||||||
|
const int bw = m_titleBar->closeButtonWidth();
|
||||||
|
m_titleBar->setGeometry(width() - bw, 0, bw, m_titleBar->height());
|
||||||
|
} else {
|
||||||
|
m_titleBar->setGeometry(0, 0, width(), m_titleBar->height());
|
||||||
|
}
|
||||||
m_prevButton->move(25, (height() - m_prevButton->sizeHint().height()) / 2);
|
m_prevButton->move(25, (height() - m_prevButton->sizeHint().height()) / 2);
|
||||||
m_nextButton->move(width() - m_nextButton->sizeHint().width() - 25,
|
m_nextButton->move(width() - m_nextButton->sizeHint().width() - 25,
|
||||||
(height() - m_prevButton->sizeHint().height()) / 2);
|
(height() - m_prevButton->sizeHint().height()) / 2);
|
||||||
@@ -624,7 +630,7 @@ void MainWindow::updateWidgetsPosition()
|
|||||||
void MainWindow::toggleProtectedMode()
|
void MainWindow::toggleProtectedMode()
|
||||||
{
|
{
|
||||||
m_protectedMode = !m_protectedMode;
|
m_protectedMode = !m_protectedMode;
|
||||||
m_closeButton->setVisible(!m_protectedMode);
|
m_titleBar->setCloseButtonVisible(!m_protectedMode);
|
||||||
updateGalleryButtonsVisibility();
|
updateGalleryButtonsVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ QT_END_NAMESPACE
|
|||||||
class ActionManager;
|
class ActionManager;
|
||||||
class PlaylistManager;
|
class PlaylistManager;
|
||||||
class ToolButton;
|
class ToolButton;
|
||||||
|
class TitleBar;
|
||||||
class GraphicsView;
|
class GraphicsView;
|
||||||
class NavigatorView;
|
class NavigatorView;
|
||||||
class BottomButtonGroup;
|
class BottomButtonGroup;
|
||||||
@@ -123,9 +124,9 @@ private:
|
|||||||
QPropertyAnimation *m_floatUpAnimation;
|
QPropertyAnimation *m_floatUpAnimation;
|
||||||
QParallelAnimationGroup *m_exitAnimationGroup;
|
QParallelAnimationGroup *m_exitAnimationGroup;
|
||||||
QFileSystemWatcher *m_fileSystemWatcher;
|
QFileSystemWatcher *m_fileSystemWatcher;
|
||||||
ToolButton *m_closeButton;
|
|
||||||
ToolButton *m_prevButton;
|
ToolButton *m_prevButton;
|
||||||
ToolButton *m_nextButton;
|
ToolButton *m_nextButton;
|
||||||
|
TitleBar *m_titleBar;
|
||||||
GraphicsView *m_graphicsView;
|
GraphicsView *m_graphicsView;
|
||||||
NavigatorView *m_gv;
|
NavigatorView *m_gv;
|
||||||
BottomButtonGroup *m_bottomButtonGroup;
|
BottomButtonGroup *m_bottomButtonGroup;
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ bool Settings::useBuiltInCloseAnimation() const
|
|||||||
return m_qsettings->value("use_built_in_close_animation", true).toBool();
|
return m_qsettings->value("use_built_in_close_animation", true).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Settings::showTitleBar() const
|
||||||
|
{
|
||||||
|
return m_qsettings->value("show_title_bar", true).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
bool Settings::useLightCheckerboard() const
|
bool Settings::useLightCheckerboard() const
|
||||||
{
|
{
|
||||||
return m_qsettings->value("use_light_checkerboard", false).toBool();
|
return m_qsettings->value("use_light_checkerboard", false).toBool();
|
||||||
@@ -123,6 +128,12 @@ void Settings::setUseBuiltInCloseAnimation(bool on)
|
|||||||
m_qsettings->sync();
|
m_qsettings->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Settings::setShowTitleBar(bool on)
|
||||||
|
{
|
||||||
|
m_qsettings->setValue("show_title_bar", on);
|
||||||
|
m_qsettings->sync();
|
||||||
|
}
|
||||||
|
|
||||||
void Settings::setUseLightCheckerboard(bool light)
|
void Settings::setUseLightCheckerboard(bool light)
|
||||||
{
|
{
|
||||||
m_qsettings->setValue("use_light_checkerboard", light);
|
m_qsettings->setValue("use_light_checkerboard", light);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
|
|
||||||
bool stayOnTop() const;
|
bool stayOnTop() const;
|
||||||
bool useBuiltInCloseAnimation() const;
|
bool useBuiltInCloseAnimation() const;
|
||||||
|
bool showTitleBar() const;
|
||||||
bool useLightCheckerboard() const;
|
bool useLightCheckerboard() const;
|
||||||
bool loopGallery() const;
|
bool loopGallery() const;
|
||||||
bool autoLongImageMode() const;
|
bool autoLongImageMode() const;
|
||||||
@@ -47,6 +48,7 @@ public:
|
|||||||
|
|
||||||
void setStayOnTop(bool on);
|
void setStayOnTop(bool on);
|
||||||
void setUseBuiltInCloseAnimation(bool on);
|
void setUseBuiltInCloseAnimation(bool on);
|
||||||
|
void setShowTitleBar(bool on);
|
||||||
void setUseLightCheckerboard(bool light);
|
void setUseLightCheckerboard(bool light);
|
||||||
void setLoopGallery(bool on);
|
void setLoopGallery(bool on);
|
||||||
void setAutoLongImageMode(bool on);
|
void setAutoLongImageMode(bool on);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
|
|||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, m_stayOnTop(new QCheckBox)
|
, m_stayOnTop(new QCheckBox)
|
||||||
, m_useBuiltInCloseAnimation(new QCheckBox)
|
, m_useBuiltInCloseAnimation(new QCheckBox)
|
||||||
|
, m_showTitleBar(new QCheckBox)
|
||||||
, m_useLightCheckerboard(new QCheckBox)
|
, m_useLightCheckerboard(new QCheckBox)
|
||||||
, m_loopGallery(new QCheckBox)
|
, m_loopGallery(new QCheckBox)
|
||||||
, m_autoLongImageMode(new QCheckBox)
|
, m_autoLongImageMode(new QCheckBox)
|
||||||
@@ -123,6 +124,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
|
|||||||
|
|
||||||
settingsForm->addRow(tr("Stay on top when start-up"), m_stayOnTop);
|
settingsForm->addRow(tr("Stay on top when start-up"), m_stayOnTop);
|
||||||
settingsForm->addRow(tr("Use built-in close window animation"), m_useBuiltInCloseAnimation);
|
settingsForm->addRow(tr("Use built-in close window animation"), m_useBuiltInCloseAnimation);
|
||||||
|
settingsForm->addRow(tr("Show title bar"), m_showTitleBar);
|
||||||
settingsForm->addRow(tr("Use light-color checkerboard"), m_useLightCheckerboard);
|
settingsForm->addRow(tr("Use light-color checkerboard"), m_useLightCheckerboard);
|
||||||
settingsForm->addRow(tr("Loop the loaded gallery"), m_loopGallery);
|
settingsForm->addRow(tr("Loop the loaded gallery"), m_loopGallery);
|
||||||
settingsForm->addRow(tr("Auto long image mode"), m_autoLongImageMode);
|
settingsForm->addRow(tr("Auto long image mode"), m_autoLongImageMode);
|
||||||
@@ -134,6 +136,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
|
|||||||
|
|
||||||
m_stayOnTop->setChecked(Settings::instance()->stayOnTop());
|
m_stayOnTop->setChecked(Settings::instance()->stayOnTop());
|
||||||
m_useBuiltInCloseAnimation->setChecked(Settings::instance()->useBuiltInCloseAnimation());
|
m_useBuiltInCloseAnimation->setChecked(Settings::instance()->useBuiltInCloseAnimation());
|
||||||
|
m_showTitleBar->setChecked(Settings::instance()->showTitleBar());
|
||||||
m_useLightCheckerboard->setChecked(Settings::instance()->useLightCheckerboard());
|
m_useLightCheckerboard->setChecked(Settings::instance()->useLightCheckerboard());
|
||||||
m_loopGallery->setChecked(Settings::instance()->loopGallery());
|
m_loopGallery->setChecked(Settings::instance()->loopGallery());
|
||||||
m_autoLongImageMode->setChecked(Settings::instance()->autoLongImageMode());
|
m_autoLongImageMode->setChecked(Settings::instance()->autoLongImageMode());
|
||||||
@@ -172,6 +175,10 @@ SettingsDialog::SettingsDialog(QWidget *parent)
|
|||||||
Settings::instance()->setUseBuiltInCloseAnimation(state == Qt::Checked);
|
Settings::instance()->setUseBuiltInCloseAnimation(state == Qt::Checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(m_showTitleBar, &QCHECKBOX_CHECKSTATECHANGED, this, [ = ](QT_CHECKSTATE state){
|
||||||
|
Settings::instance()->setShowTitleBar(state == Qt::Checked);
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_useLightCheckerboard, &QCHECKBOX_CHECKSTATECHANGED, this, [ = ](QT_CHECKSTATE state){
|
connect(m_useLightCheckerboard, &QCHECKBOX_CHECKSTATECHANGED, this, [ = ](QT_CHECKSTATE state){
|
||||||
Settings::instance()->setUseLightCheckerboard(state == Qt::Checked);
|
Settings::instance()->setUseLightCheckerboard(state == Qt::Checked);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
QCheckBox * m_stayOnTop = nullptr;
|
QCheckBox * m_stayOnTop = nullptr;
|
||||||
QCheckBox * m_useBuiltInCloseAnimation = nullptr;
|
QCheckBox * m_useBuiltInCloseAnimation = nullptr;
|
||||||
|
QCheckBox * m_showTitleBar = nullptr;
|
||||||
QCheckBox * m_useLightCheckerboard = nullptr;
|
QCheckBox * m_useLightCheckerboard = nullptr;
|
||||||
QCheckBox * m_loopGallery = nullptr;
|
QCheckBox * m_loopGallery = nullptr;
|
||||||
QCheckBox * m_autoLongImageMode = nullptr;
|
QCheckBox * m_autoLongImageMode = nullptr;
|
||||||
|
|||||||
218
app/titlebar.cpp
Normal file
218
app/titlebar.cpp
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "titlebar.h"
|
||||||
|
|
||||||
|
#include "opacityhelper.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QEnterEvent>
|
||||||
|
#include <QWindow>
|
||||||
|
#include <QCursor>
|
||||||
|
|
||||||
|
TitleBar::TitleBar(QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_opacityHelper(new OpacityHelper(this))
|
||||||
|
, m_closeIcon(QStringLiteral(":/icons/window-close.svg"))
|
||||||
|
{
|
||||||
|
setFixedHeight(32);
|
||||||
|
setMouseTracking(true);
|
||||||
|
setAttribute(Qt::WA_Hover, true);
|
||||||
|
|
||||||
|
if (QWidget *win = window())
|
||||||
|
win->installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::setOpacity(qreal opacity, bool animated)
|
||||||
|
{
|
||||||
|
m_opacityHelper->setOpacity(opacity, animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::setCloseButtonVisible(bool visible)
|
||||||
|
{
|
||||||
|
if (m_closeButtonVisible == visible)
|
||||||
|
return;
|
||||||
|
m_closeButtonVisible = visible;
|
||||||
|
if (!visible) {
|
||||||
|
m_closeHovered = false;
|
||||||
|
m_closePressed = false;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::setCloseButtonOnly(bool only)
|
||||||
|
{
|
||||||
|
if (m_closeButtonOnly == only)
|
||||||
|
return;
|
||||||
|
m_closeButtonOnly = only;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect TitleBar::closeButtonRect() const
|
||||||
|
{
|
||||||
|
const int btnWidth = closeButtonWidth();
|
||||||
|
return QRect(width() - btnWidth, 0, btnWidth, height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
// Subtle translucent backdrop so the title bar region is distinguishable
|
||||||
|
// (similar to the bottom button group). Skipped in close-button-only mode.
|
||||||
|
if (!m_closeButtonOnly) {
|
||||||
|
painter.fillRect(rect(), QColor(0, 0, 0, 120));
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRect closeRect = closeButtonRect();
|
||||||
|
|
||||||
|
// Title text (leave room for the close button).
|
||||||
|
QRect labelRect = rect().adjusted(8, 0, 0, 0);
|
||||||
|
if (m_closeButtonVisible)
|
||||||
|
labelRect.setRight(closeRect.left() - 2);
|
||||||
|
|
||||||
|
const QString title = window() ? window()->windowTitle() : QString();
|
||||||
|
if (!m_closeButtonOnly && !title.isEmpty()) {
|
||||||
|
const QString elided = painter.fontMetrics().elidedText(title, Qt::ElideRight, labelRect.width());
|
||||||
|
const int flags = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine;
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
painter.drawText(labelRect.adjusted(1, 1, 1, 1), flags, elided);
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
painter.drawText(labelRect, flags, elided);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_closeButtonVisible) {
|
||||||
|
if (m_closeHovered) {
|
||||||
|
painter.fillRect(closeRect,
|
||||||
|
m_closePressed ? QColor(0xC5, 0x0F, 0x1F)
|
||||||
|
: QColor(0xE8, 0x11, 0x23));
|
||||||
|
}
|
||||||
|
const int sz = height() / 3 * 2;
|
||||||
|
const QRect iconRect = QStyle::alignedRect(layoutDirection(), Qt::AlignCenter,
|
||||||
|
QSize(sz, sz), closeRect);
|
||||||
|
m_closeIcon.paint(&painter, iconRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() != Qt::LeftButton) {
|
||||||
|
QWidget::mousePressEvent(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_closeButtonVisible && closeButtonRect().contains(event->pos())) {
|
||||||
|
m_closePressed = true;
|
||||||
|
m_dragPending = false;
|
||||||
|
update();
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dragPending = true;
|
||||||
|
m_moveStartPos = event->pos();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::mouseMoveEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (m_closeButtonVisible) {
|
||||||
|
const bool hovered = closeButtonRect().contains(event->pos());
|
||||||
|
if (hovered != m_closeHovered) {
|
||||||
|
m_closeHovered = hovered;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->buttons() & Qt::LeftButton && m_dragPending
|
||||||
|
&& !window()->isMaximized() && !window()->isFullScreen()) {
|
||||||
|
if (QWindow *wh = window()->windowHandle()) {
|
||||||
|
if (!wh->startSystemMove())
|
||||||
|
window()->move(event->globalPosition().toPoint() - m_moveStartPos);
|
||||||
|
}
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::mouseMoveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
const bool wasClosePressed = m_closePressed;
|
||||||
|
m_closePressed = false;
|
||||||
|
m_dragPending = false;
|
||||||
|
update();
|
||||||
|
if (wasClosePressed && m_closeButtonVisible
|
||||||
|
&& closeButtonRect().contains(event->pos())) {
|
||||||
|
emit closeRequested();
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::mouseReleaseEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton
|
||||||
|
&& !(m_closeButtonVisible && closeButtonRect().contains(event->pos()))) {
|
||||||
|
emit maximizeToggleRequested();
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::mouseDoubleClickEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::enterEvent(QEnterEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
if (m_closeButtonVisible) {
|
||||||
|
const bool hovered = closeButtonRect().contains(mapFromGlobal(QCursor::pos()));
|
||||||
|
if (hovered != m_closeHovered) {
|
||||||
|
m_closeHovered = hovered;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::enterEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleBar::leaveEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
if (m_closeHovered) {
|
||||||
|
m_closeHovered = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::leaveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TitleBar::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
if (watched == window()) {
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::WindowTitleChange:
|
||||||
|
case QEvent::WindowStateChange:
|
||||||
|
case QEvent::ActivationChange:
|
||||||
|
update();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QWidget::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize TitleBar::sizeHint() const
|
||||||
|
{
|
||||||
|
return QSize(0, 32);
|
||||||
|
}
|
||||||
60
app/titlebar.h
Normal file
60
app/titlebar.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#ifndef TITLEBAR_H
|
||||||
|
#define TITLEBAR_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QPaintEvent;
|
||||||
|
class QMouseEvent;
|
||||||
|
class QEvent;
|
||||||
|
class QEnterEvent;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class OpacityHelper;
|
||||||
|
|
||||||
|
class TitleBar : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TitleBar(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void setOpacity(qreal opacity, bool animated = true);
|
||||||
|
void setCloseButtonVisible(bool visible);
|
||||||
|
bool closeButtonOnly() const { return m_closeButtonOnly; }
|
||||||
|
void setCloseButtonOnly(bool only);
|
||||||
|
int closeButtonWidth() const { return qMax(height(), 46); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeRequested();
|
||||||
|
void maximizeToggleRequested();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
|
void enterEvent(QEnterEvent *event) override;
|
||||||
|
void leaveEvent(QEvent *event) override;
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QRect closeButtonRect() const;
|
||||||
|
|
||||||
|
OpacityHelper *m_opacityHelper;
|
||||||
|
QIcon m_closeIcon;
|
||||||
|
bool m_closeButtonVisible = true;
|
||||||
|
bool m_closeButtonOnly = false;
|
||||||
|
bool m_closeHovered = false;
|
||||||
|
bool m_closePressed = false;
|
||||||
|
bool m_dragPending = false;
|
||||||
|
QPoint m_moveStartPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TITLEBAR_H
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#include <QGraphicsOpacityEffect>
|
#include <QGraphicsOpacityEffect>
|
||||||
#include <QPropertyAnimation>
|
#include <QPropertyAnimation>
|
||||||
|
|
||||||
ToolButton::ToolButton(bool hoverColor, QWidget *parent)
|
ToolButton::ToolButton(QWidget *parent)
|
||||||
: QPushButton(parent)
|
: QPushButton(parent)
|
||||||
, m_opacityHelper(new OpacityHelper(this))
|
, m_opacityHelper(new OpacityHelper(this))
|
||||||
{
|
{
|
||||||
@@ -19,11 +19,6 @@ ToolButton::ToolButton(bool hoverColor, QWidget *parent)
|
|||||||
QString qss = "QPushButton {"
|
QString qss = "QPushButton {"
|
||||||
"background: transparent;"
|
"background: transparent;"
|
||||||
"}";
|
"}";
|
||||||
if (hoverColor) {
|
|
||||||
qss += "QPushButton:hover {"
|
|
||||||
"background: red;"
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
setStyleSheet(qss);
|
setStyleSheet(qss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class ToolButton : public QPushButton
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ToolButton(bool hoverColor = false, QWidget * parent = nullptr);
|
ToolButton(QWidget * parent = nullptr);
|
||||||
void setIconResourcePath(const QString &iconp);
|
void setIconResourcePath(const QString &iconp);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
Reference in New Issue
Block a user