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"