File indexing completed on 2025-10-12 03:31:35

0001 /*
0002     File                 : SlidingPanel.cpp
0003     Project              : LabPlot
0004     Description          : Sliding panel shown in the presenter widget
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2016 Fabian Kristof <fkristofszabolcs@gmail.com>
0007     SPDX-FileCopyrightText: 2016-2023 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "SlidingPanel.h"
0011 
0012 #include "commonfrontend/worksheet/WorksheetView.h"
0013 
0014 #include <QAction>
0015 #include <QApplication>
0016 #include <QHBoxLayout>
0017 #include <QLabel>
0018 #include <QPushButton>
0019 #include <QScreen>
0020 #include <QSize>
0021 #include <QTimeLine>
0022 #include <QToolBar>
0023 
0024 #include <KLocalizedString>
0025 
0026 SlidingPanel::SlidingPanel(const QRect& screenRect, Position position, QWidget* parent)
0027     : QFrame(parent)
0028     , m_screenRect(screenRect)
0029     , m_pos(position)
0030     , m_timeLine(new QTimeLine(400, this)) {
0031     setAttribute(Qt::WA_DeleteOnClose);
0032     connect(m_timeLine, &QTimeLine::valueChanged, this, &SlidingPanel::movePanel);
0033 }
0034 
0035 SlidingPanel::~SlidingPanel() {
0036 }
0037 
0038 void SlidingPanel::slideShow() {
0039     // timeline: 0 --> 1
0040     m_timeLine->setDirection(QTimeLine::Forward);
0041     startTimeline();
0042 }
0043 
0044 void SlidingPanel::slideHide() {
0045     // timeline: 1 --> 0
0046     m_timeLine->setDirection(QTimeLine::Backward);
0047     startTimeline();
0048 }
0049 
0050 void SlidingPanel::startTimeline() {
0051     if (m_timeLine->state() != QTimeLine::Running)
0052         m_timeLine->start();
0053 }
0054 
0055 void SlidingPanel::movePanel(qreal value) {
0056     switch (m_pos) {
0057     case Position::Top:
0058         move(pos().x(), -height() + static_cast<int>(value * height()));
0059         break;
0060     case Position::Bottom:
0061         move(pos().x(), m_screenRect.height() - static_cast<int>((1 - value) * height()));
0062         break;
0063     }
0064     raise();
0065 }
0066 
0067 bool SlidingPanel::insideRect(QPoint screenPos) {
0068     const auto leftTop = mapToGlobal(QPoint(rect().left(), rect().top()));
0069     const auto rightBottom = mapToGlobal(QPoint(rect().right(), rect().bottom()));
0070     const auto globalRect = QRect(leftTop.x(), leftTop.y(), rightBottom.x(), rightBottom.y());
0071     return globalRect.contains(mapToGlobal(screenPos));
0072 }
0073 
0074 // ####################################################################################################
0075 
0076 SlidingPanelTop::SlidingPanelTop(const QRect& screenRect, const QString& worksheetName, QWidget* parent)
0077     : SlidingPanel(screenRect, SlidingPanel::Position::Top, parent) {
0078     setAttribute(Qt::WA_DeleteOnClose);
0079 
0080     m_worksheetName = new QLabel(worksheetName, this);
0081     QFont nameFont;
0082     nameFont.setPointSize(20);
0083     nameFont.setBold(true);
0084     m_worksheetName->setFont(nameFont);
0085 
0086     m_quitPresentingMode = new QPushButton(i18n("Quit Presentation"), this);
0087     m_quitPresentingMode->setIcon(QIcon::fromTheme(QLatin1String("window-close")));
0088 
0089     auto* hlayout = new QHBoxLayout;
0090     hlayout->addWidget(m_worksheetName);
0091     auto* spacer = new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum);
0092     hlayout->addItem(spacer);
0093     hlayout->addWidget(m_quitPresentingMode);
0094     setLayout(hlayout);
0095 
0096     QPalette pal(palette());
0097     pal.setColor(QPalette::Window, Qt::lightGray);
0098     setAutoFillBackground(true);
0099     setPalette(pal);
0100 
0101     move(0, 0);
0102     raise();
0103     show();
0104 }
0105 
0106 QPushButton* SlidingPanelTop::quitButton() const {
0107     return m_quitPresentingMode;
0108 }
0109 
0110 QSize SlidingPanelTop::sizeHint() const {
0111     QSize sh;
0112     sh.setWidth(m_screenRect.width());
0113     sh.setHeight(m_worksheetName->sizeHint().height() + layout()->contentsMargins().top() + layout()->contentsMargins().bottom());
0114 
0115     return sh;
0116 }
0117 
0118 // ####################################################################################################
0119 SlidingPanelBottom::SlidingPanelBottom(const QRect& screenRect, WorksheetView* view, bool fixed, QWidget* parent)
0120     : SlidingPanel(screenRect, SlidingPanel::Position::Bottom, parent)
0121     , m_toolBar(new QToolBar(this))
0122     , m_fixed(fixed) {
0123     auto* layout = new QHBoxLayout();
0124     layout->setContentsMargins(0, 0, 0, 0);
0125     setLayout(layout);
0126 
0127     view->fillCartesianPlotNavigationToolBar(m_toolBar, false /* disable cursor action */);
0128 
0129     // add an action to pin/unpin the panel (to make it fixed or floating)
0130     m_toolBar->addSeparator();
0131     auto* pinAction = new QAction(QIcon::fromTheme(QStringLiteral("pin")), i18n("Pin the navigation panel"));
0132     pinAction->setCheckable(true);
0133     pinAction->setChecked(m_fixed);
0134     connect(pinAction, &QAction::toggled, this, [=](bool toggled) {
0135         m_fixed = toggled;
0136     });
0137     m_toolBar->addAction(pinAction);
0138 
0139     layout->addWidget(m_toolBar);
0140 
0141     QPalette pal(palette());
0142     pal.setColor(QPalette::Window, Qt::lightGray);
0143     setAutoFillBackground(true);
0144     setPalette(pal);
0145 
0146     move(screenRect.width() / 2 - m_toolBar->sizeHint().width() / 2, screenRect.bottom() - m_toolBar->sizeHint().height());
0147     raise();
0148     show();
0149 }
0150 
0151 bool SlidingPanelBottom::isFixed() const {
0152     return m_fixed;
0153 }
0154 
0155 // TODO: why is SlidingPanel::insideRect() not enough?
0156 bool SlidingPanelBottom::insideRect(QPoint screenPos) {
0157     QRect rect = this->rect();
0158     rect.moveTo(screen()->geometry().width() / 2 - m_toolBar->sizeHint().width() / 2, screen()->geometry().bottom() - rect.height());
0159     // Last part is a hack, because contains seems to be failing here
0160     const bool inside = rect.contains(screenPos) || screenPos.y() >= screen()->geometry().bottom();
0161     return inside;
0162 }
0163 
0164 QSize SlidingPanelBottom::sizeHint() const {
0165     return m_toolBar->sizeHint();
0166 }