File indexing completed on 2024-04-21 08:30:55

0001 /***************************************************************************
0002  *   Copyright (C) 2017-2018 by Emmanuel Lepage Vallee                     *
0003  *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@kde.org>             *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 3 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0017  **************************************************************************/
0018 #include "flickablescrollbar.h"
0019 
0020 // KQuickItemViews
0021 #include "views/flickable.h"
0022 
0023 class FlickableScrollBarPrivate : public QObject
0024 {
0025     Q_OBJECT
0026 public:
0027     Flickable *m_pView        {nullptr};
0028     qreal      m_HandleHeight {   0   };
0029     qreal      m_Position     {   0   };
0030     bool       m_Visible      { false };
0031 
0032     FlickableScrollBar* q_ptr;
0033 
0034 public Q_SLOTS:
0035     void recomputeGeometry();
0036 };
0037 
0038 FlickableScrollBar::FlickableScrollBar(QQuickItem* parent) : QQuickItem(parent),
0039     d_ptr(new FlickableScrollBarPrivate)
0040 {
0041     d_ptr->q_ptr = this;
0042 }
0043 
0044 FlickableScrollBar::~FlickableScrollBar()
0045 {
0046     delete d_ptr;
0047 }
0048 
0049 QObject* FlickableScrollBar::view() const
0050 {
0051     return d_ptr->m_pView;
0052 }
0053 
0054 void FlickableScrollBar::setView(QObject* v)
0055 {
0056     if (d_ptr->m_pView) {
0057         disconnect(d_ptr->m_pView, &Flickable::contentHeightChanged,
0058             d_ptr, &FlickableScrollBarPrivate::recomputeGeometry);
0059         disconnect(d_ptr->m_pView, &Flickable::contentYChanged,
0060             d_ptr, &FlickableScrollBarPrivate::recomputeGeometry);
0061         disconnect(d_ptr->m_pView, &Flickable::heightChanged,
0062             d_ptr, &FlickableScrollBarPrivate::recomputeGeometry);
0063     }
0064 
0065     d_ptr->m_pView = qobject_cast<Flickable*>(v);
0066 
0067     Q_ASSERT((!v) || d_ptr->m_pView);
0068 
0069     connect(d_ptr->m_pView, &Flickable::contentHeightChanged,
0070         d_ptr, &FlickableScrollBarPrivate::recomputeGeometry);
0071     connect(d_ptr->m_pView, &Flickable::contentYChanged,
0072         d_ptr, &FlickableScrollBarPrivate::recomputeGeometry);
0073     connect(d_ptr->m_pView, &Flickable::heightChanged,
0074         d_ptr, &FlickableScrollBarPrivate::recomputeGeometry);
0075 
0076     d_ptr->recomputeGeometry();
0077 }
0078 
0079 qreal FlickableScrollBar::position() const
0080 {
0081     return d_ptr->m_Position;
0082 }
0083 
0084 void FlickableScrollBar::setPosition(qreal p)
0085 {
0086     if (!d_ptr->m_pView)
0087         return;
0088 
0089     // Simple rule of 3
0090     d_ptr->m_pView->setContentY(
0091         (p * d_ptr->m_pView->contentHeight()) / d_ptr->m_pView->height()
0092     );
0093 }
0094 
0095 qreal FlickableScrollBar::handleHeight() const
0096 {
0097     return d_ptr->m_HandleHeight;
0098 }
0099 
0100 bool FlickableScrollBar::isHandleVisible() const
0101 {
0102     return d_ptr->m_Visible;
0103 }
0104 
0105 /**
0106  * The idea behind the scrollhandle is that the height represent the height of a
0107  * page until it gets too small. In mobile mode, the height is always the same
0108  * regardless of the content height to hide less space on the smaller screen.
0109  */
0110 void FlickableScrollBarPrivate::recomputeGeometry()
0111 {
0112     if (!m_pView)
0113         return;
0114 
0115     const qreal oldP = m_Position;
0116     const qreal oldH = m_HandleHeight;
0117 
0118     const qreal totalHeight  = m_pView->contentHeight();
0119     const qreal pageHeight   = m_pView->height();
0120     const qreal pageCount    = totalHeight/pageHeight;
0121     const qreal handleHeight = std::max(pageHeight/pageCount, 50.0);
0122     const qreal handleBegin  = (m_pView->contentY()*pageHeight)/totalHeight;
0123 
0124     m_HandleHeight = handleHeight;
0125     m_Position     = handleBegin;
0126     m_Visible      = totalHeight > pageHeight;
0127 
0128     if (oldH != m_HandleHeight)
0129         emit q_ptr->handleHeightChanged();
0130 
0131     if (oldP != m_Position)
0132         emit q_ptr->positionChanged ();
0133 }
0134 
0135 #include <flickablescrollbar.moc>