File indexing completed on 2024-04-28 04:20:56

0001 // SPDX-FileCopyrightText: 2003-2019 The KPhotoAlbum Development Team
0002 // SPDX-FileCopyrightText: 2022-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0003 //
0004 // SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006 #include "MouseHandler.h"
0007 
0008 #include "DateBarWidget.h"
0009 
0010 #include <DB/ImageDateCollection.h>
0011 
0012 #include <math.h>
0013 #include <qcursor.h>
0014 #include <qtimer.h>
0015 
0016 /**
0017  * \class DateBar::MouseHandler
0018  * \brief Base class for handling mouse events in the \ref DateBar
0019  *
0020  * The mouse events in the date bar are handled by subclasses of MouseHandler.
0021  * The subclasses are:
0022  * \li DateBar::BarDragHandler - used during dragging the bar (control left mouse button)
0023  * \li DateBar::FocusItemDragHandler - used during dragging the focus item (drag the top of the bar)
0024  * \li DateBar::SelectionHandler - used during range selection (drag on the bottom of the bar)
0025  */
0026 
0027 /**
0028  * \class DateBar::BarDragHandler
0029  * \brief Mouse handler used when dragging the date bar (using control left mouse button on the bar)
0030  */
0031 
0032 /**
0033  * \class DateBar::FocusItemDragHandler
0034  * \brief Handler used during dragging of the focus rectangle in the date bar (mouse button on upper part of the bar)
0035  */
0036 
0037 /**
0038  * \class DateBar::SelectionHandler
0039  * \brief Handler used during range selection in the date bar (mouse button on lower part of the bar)
0040  */
0041 DateBar::MouseHandler::MouseHandler(DateBarWidget *dateBar)
0042     : QObject(dateBar)
0043     , m_dateBar(dateBar)
0044 {
0045     m_autoScrollTimer = new QTimer(this);
0046     connect(m_autoScrollTimer, &QTimer::timeout, this, &SelectionHandler::autoScroll);
0047 }
0048 
0049 void DateBar::MouseHandler::autoScroll()
0050 {
0051     mouseMoveEvent(m_dateBar->mapFromGlobal(QCursor::pos()).x());
0052 }
0053 
0054 void DateBar::MouseHandler::startAutoScroll()
0055 {
0056     m_autoScrollTimer->start(100);
0057 }
0058 
0059 void DateBar::MouseHandler::endAutoScroll()
0060 {
0061     m_autoScrollTimer->stop();
0062 }
0063 
0064 DateBar::SelectionHandler::SelectionHandler(DateBarWidget *dateBar)
0065     : MouseHandler(dateBar)
0066 {
0067 }
0068 
0069 void DateBar::SelectionHandler::mousePressEvent(int x)
0070 {
0071     const int unit = m_dateBar->unitAtPos(x);
0072     if (unit < 0)
0073         return;
0074 
0075     m_start = m_dateBar->dateForUnit(unit);
0076     m_end = m_dateBar->dateForUnit(unit + 1).addSecs(-1);
0077 }
0078 
0079 void DateBar::SelectionHandler::mouseMoveEvent(int x)
0080 {
0081     const int unit = m_dateBar->unitAtPos(x);
0082     if (unit < 0)
0083         return;
0084 
0085     Utilities::FastDateTime date = m_dateBar->dateForUnit(unit);
0086     if (m_start < date) {
0087         m_end = m_dateBar->dateForUnit(unit + 1).addSecs(-1);
0088     } else {
0089         m_end = date;
0090     }
0091     m_dateBar->redraw();
0092 }
0093 
0094 DateBar::FocusItemDragHandler::FocusItemDragHandler(DateBarWidget *dateBar)
0095     : MouseHandler(dateBar)
0096 {
0097 }
0098 
0099 void DateBar::FocusItemDragHandler::mousePressEvent(int x)
0100 {
0101     const int unit = m_dateBar->unitAtPos(x);
0102     if (unit < 0)
0103         return;
0104 
0105     m_dateBar->m_currentUnit = unit;
0106     m_dateBar->m_currentDate = m_dateBar->dateForUnit(unit);
0107     if (m_dateBar->hasSelection() && !m_dateBar->currentSelection().includes(m_dateBar->m_currentDate))
0108         m_dateBar->clearSelection();
0109 }
0110 
0111 void DateBar::FocusItemDragHandler::mouseMoveEvent(int x)
0112 {
0113     int oldUnit = m_dateBar->m_currentUnit;
0114     int newUnit = (x - m_dateBar->barAreaGeometry().left()) / m_dateBar->m_barWidth;
0115 
0116     // Don't scroll further down than the last image
0117     // We use oldUnit here, to ensure that we scroll all the way to the end
0118     // better scroll a bit over than not all the way.
0119     if ((newUnit > oldUnit && m_dateBar->dateForUnit(oldUnit) > m_dateBar->m_dates->upperLimit()) || (newUnit < oldUnit && m_dateBar->dateForUnit(oldUnit) < m_dateBar->m_dates->lowerLimit()))
0120         return;
0121     m_dateBar->m_currentUnit = newUnit;
0122 
0123     if (m_dateBar->m_currentUnit < 0 || m_dateBar->m_currentUnit > m_dateBar->numberOfUnits()) {
0124         static double rest = 0;
0125         // Slow down scrolling outside date bar.
0126         double newUnit = oldUnit + (m_dateBar->m_currentUnit - oldUnit) / 4.0 + rest;
0127         m_dateBar->m_currentUnit = (int)floor(newUnit);
0128         rest = newUnit - m_dateBar->m_currentUnit;
0129         startAutoScroll();
0130     }
0131 
0132     m_dateBar->m_currentDate = m_dateBar->dateForUnit(m_dateBar->m_currentUnit);
0133     m_dateBar->m_currentUnit = qMax(m_dateBar->m_currentUnit, 0);
0134     m_dateBar->m_currentUnit = qMin(m_dateBar->m_currentUnit, m_dateBar->numberOfUnits());
0135     m_dateBar->redraw();
0136     m_dateBar->emitDateSelected();
0137 }
0138 
0139 DateBar::BarDragHandler::BarDragHandler(DateBarWidget *dateBar)
0140     : MouseHandler(dateBar)
0141     , m_movementOffset(0)
0142 {
0143 }
0144 
0145 void DateBar::BarDragHandler::mousePressEvent(int x)
0146 {
0147     m_movementOffset = m_dateBar->m_currentUnit * m_dateBar->m_barWidth - (x - m_dateBar->barAreaGeometry().left());
0148 }
0149 
0150 void DateBar::BarDragHandler::mouseMoveEvent(int x)
0151 {
0152     int oldUnit = m_dateBar->m_currentUnit;
0153     int newUnit = (x + m_movementOffset - m_dateBar->barAreaGeometry().left()) / m_dateBar->m_barWidth;
0154 
0155     // Don't scroll further down than the last image
0156     // We use oldUnit here, to ensure that we scroll all the way to the end
0157     // better scroll a bit over than not all the way.
0158     if ((newUnit > oldUnit && m_dateBar->dateForUnit(0) < m_dateBar->m_dates->lowerLimit()) || (newUnit < oldUnit && m_dateBar->dateForUnit(m_dateBar->numberOfUnits()) > m_dateBar->m_dates->upperLimit()))
0159         return;
0160 
0161     m_dateBar->m_currentUnit = newUnit;
0162 
0163     if (m_dateBar->m_currentUnit < 0) {
0164         m_dateBar->m_currentDate = m_dateBar->dateForUnit(-m_dateBar->m_currentUnit);
0165         m_dateBar->m_currentUnit = 0;
0166         m_movementOffset = m_dateBar->barAreaGeometry().left() - x;
0167     } else if (m_dateBar->m_currentUnit > m_dateBar->numberOfUnits()) {
0168         int diff = m_dateBar->numberOfUnits() - m_dateBar->m_currentUnit;
0169         m_dateBar->m_currentDate = m_dateBar->dateForUnit(m_dateBar->numberOfUnits() + diff);
0170         m_dateBar->m_currentUnit = m_dateBar->numberOfUnits();
0171         m_movementOffset = (m_dateBar->numberOfUnits() * m_dateBar->m_barWidth) - x + m_dateBar->m_barWidth / 2;
0172     }
0173     m_dateBar->redraw();
0174     m_dateBar->emitDateSelected();
0175 }
0176 
0177 Utilities::FastDateTime DateBar::SelectionHandler::min() const
0178 {
0179     if (m_start < m_end)
0180         return m_start;
0181     else
0182         return m_end;
0183 }
0184 
0185 Utilities::FastDateTime DateBar::SelectionHandler::max() const
0186 {
0187     if (m_start >= m_end)
0188         return m_dateBar->dateForUnit(1, m_start);
0189     else
0190         return m_end;
0191 }
0192 
0193 void DateBar::SelectionHandler::clearSelection()
0194 {
0195     m_start = Utilities::FastDateTime();
0196     m_end = Utilities::FastDateTime();
0197 }
0198 
0199 void DateBar::SelectionHandler::mouseReleaseEvent()
0200 {
0201     m_dateBar->emitRangeSelection(dateRange());
0202 }
0203 
0204 DB::ImageDate DateBar::SelectionHandler::dateRange() const
0205 {
0206     return DB::ImageDate(min(), max());
0207 }
0208 
0209 bool DateBar::SelectionHandler::hasSelection() const
0210 {
0211     return min().isValid();
0212 }
0213 
0214 void DateBar::SelectionHandler::setOrExtendSelection(const Utilities::FastDateTime &date)
0215 {
0216     if (hasSelection()) {
0217         if (date < m_start) {
0218             m_start = date;
0219             m_dateBar->emitRangeSelection(dateRange());
0220         } else if (date > m_end) {
0221             const auto unit = m_dateBar->unitForDate(date);
0222             m_end = m_dateBar->dateForUnit(unit + 1).addSecs(-1);
0223             m_dateBar->emitRangeSelection(dateRange());
0224         }
0225     } else {
0226         m_start = date;
0227         const auto unit = m_dateBar->unitForDate(date);
0228         m_end = m_dateBar->dateForUnit(unit + 1).addSecs(-1);
0229         m_dateBar->emitRangeSelection(dateRange());
0230     }
0231 }
0232 
0233 // vi:expandtab:tabstop=4 shiftwidth=4:
0234 
0235 #include "moc_MouseHandler.cpp"