File indexing completed on 2024-05-19 04:59:14
0001 /* ============================================================ 0002 * AutoScroll - Autoscroll for Falkon 0003 * Copyright (C) 2014-2017 David Rosca <nowrep@gmail.com> 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 "autoscroller.h" 0019 #include "framescroller.h" 0020 #include "webview.h" 0021 #include "webpage.h" 0022 #include "webhittestresult.h" 0023 0024 #include <QApplication> 0025 #include <QMouseEvent> 0026 #include <QSettings> 0027 #include <QIcon> 0028 #include <QPainter> 0029 0030 ScrollIndicator::ScrollIndicator(QWidget *parent) 0031 : QLabel(parent) 0032 { 0033 resize(33, 33); 0034 setContentsMargins(0, 0, 0, 0); 0035 } 0036 0037 Qt::Orientations ScrollIndicator::orientations() const 0038 { 0039 return m_orientations; 0040 } 0041 0042 void ScrollIndicator::setOrientations(Qt::Orientations orientations) 0043 { 0044 m_orientations = orientations; 0045 0046 if (m_orientations == Qt::Vertical) { 0047 setPixmap(QIcon(QSL(":/autoscroll/data/scroll_vertical.png")).pixmap(33)); 0048 } else if (m_orientations == Qt::Horizontal) { 0049 setPixmap(QIcon(QSL(":/autoscroll/data/scroll_horizontal.png")).pixmap(33)); 0050 } else { 0051 setPixmap(QIcon(QSL(":/autoscroll/data/scroll_all.png")).pixmap(33)); 0052 } 0053 0054 update(); 0055 } 0056 0057 void ScrollIndicator::paintEvent(QPaintEvent *event) 0058 { 0059 QPainter p(this); 0060 p.setRenderHint(QPainter::Antialiasing); 0061 0062 QRectF r(rect()); 0063 r.adjust(1, 1, -1, -1); 0064 0065 QColor c1(Qt::gray); 0066 c1.setAlpha(190); 0067 0068 QColor c2(Qt::white); 0069 c2.setAlpha(190); 0070 0071 QRadialGradient g(r.center(), r.height() / 2.0); 0072 g.setColorAt(1, c1); 0073 g.setColorAt(0.7, c2); 0074 0075 p.setPen(Qt::NoPen); 0076 p.setBrush(g); 0077 p.drawEllipse(r); 0078 0079 QLabel::paintEvent(event); 0080 } 0081 0082 AutoScroller::AutoScroller(const QString &settingsFile, QObject* parent) 0083 : QObject(parent) 0084 , m_view(nullptr) 0085 , m_settingsFile(settingsFile) 0086 { 0087 m_indicator = new ScrollIndicator; 0088 m_indicator->installEventFilter(this); 0089 0090 QSettings settings(m_settingsFile, QSettings::IniFormat); 0091 settings.beginGroup("AutoScroll"); 0092 0093 m_frameScroller = new FrameScroller(this); 0094 m_frameScroller->setScrollDivider(settings.value("ScrollDivider", 8.0).toDouble()); 0095 0096 settings.endGroup(); 0097 } 0098 0099 AutoScroller::~AutoScroller() 0100 { 0101 delete m_indicator; 0102 } 0103 0104 bool AutoScroller::mouseMove(QObject* obj, QMouseEvent* event) 0105 { 0106 Q_UNUSED(obj) 0107 0108 if (m_indicator->isVisible()) { 0109 QRect rect = indicatorGlobalRect(); 0110 int xlength = 0; 0111 int ylength = 0; 0112 0113 if (rect.left() > event->globalPosition().toPoint().x()) { 0114 xlength = event->globalPosition().toPoint().x() - rect.left(); 0115 } 0116 else if (rect.right() < event->globalPosition().toPoint().x()) { 0117 xlength = event->globalPosition().toPoint().x() - rect.right(); 0118 } 0119 if (rect.top() > event->globalPosition().toPoint().y()) { 0120 ylength = event->globalPosition().toPoint().y() - rect.top(); 0121 } 0122 else if (rect.bottom() < event->globalPosition().toPoint().y()) { 0123 ylength = event->globalPosition().toPoint().y() - rect.bottom(); 0124 } 0125 0126 m_frameScroller->startScrolling(xlength, ylength); 0127 } 0128 0129 return false; 0130 } 0131 0132 bool AutoScroller::mousePress(QObject* obj, QMouseEvent* event) 0133 { 0134 bool middleButton = event->buttons() == Qt::MiddleButton; 0135 auto* view = qobject_cast<WebView*>(obj); 0136 Q_ASSERT(view); 0137 0138 // Start? 0139 if (m_view != view && middleButton) { 0140 return showIndicator(view, event->position().toPoint()); 0141 } 0142 else if (!m_indicator->isVisible() && middleButton) { 0143 return showIndicator(view, event->position().toPoint()); 0144 } 0145 0146 // Stop 0147 if (m_indicator->isVisible()) { 0148 stopScrolling(); 0149 return true; 0150 } 0151 0152 return false; 0153 } 0154 0155 bool AutoScroller::mouseRelease(QObject* obj, QMouseEvent* event) 0156 { 0157 Q_UNUSED(obj) 0158 0159 if (m_indicator->isVisible()) { 0160 if (!indicatorGlobalRect().contains(event->globalPosition().toPoint())) { 0161 stopScrolling(); 0162 } 0163 return true; 0164 } 0165 0166 return false; 0167 } 0168 0169 bool AutoScroller::wheel(QObject *obj, QWheelEvent *event) 0170 { 0171 Q_UNUSED(obj) 0172 Q_UNUSED(event); 0173 0174 if (m_indicator->isVisible()) { 0175 stopScrolling(); 0176 return true; 0177 } 0178 0179 return false; 0180 } 0181 0182 double AutoScroller::scrollDivider() const 0183 { 0184 return m_frameScroller->scrollDivider(); 0185 } 0186 0187 void AutoScroller::setScrollDivider(double divider) 0188 { 0189 QSettings settings(m_settingsFile, QSettings::IniFormat); 0190 settings.beginGroup("AutoScroll"); 0191 settings.setValue("ScrollDivider", divider); 0192 settings.endGroup(); 0193 0194 m_frameScroller->setScrollDivider(divider); 0195 } 0196 0197 bool AutoScroller::eventFilter(QObject* obj, QEvent* event) 0198 { 0199 if (obj == m_indicator) { 0200 switch (event->type()) { 0201 case QEvent::Enter: 0202 m_frameScroller->stopScrolling(); 0203 break; 0204 0205 case QEvent::Wheel: 0206 case QEvent::Hide: 0207 case QEvent::MouseButtonPress: 0208 stopScrolling(); 0209 break; 0210 0211 default: 0212 break; 0213 } 0214 } 0215 0216 return false; 0217 } 0218 0219 bool AutoScroller::showIndicator(WebView* view, const QPoint &pos) 0220 { 0221 const WebHitTestResult res = view->page()->hitTestContent(pos); 0222 0223 if (res.isContentEditable() || !res.linkUrl().isEmpty() || res.tagName().endsWith(QL1S("frame"))) { 0224 return false; 0225 } 0226 0227 QString source = QL1S("var out = {" 0228 " vertical: window.innerWidth > document.documentElement.clientWidth," 0229 " horizontal: window.innerHeight > document.documentElement.clientHeight" 0230 "};" 0231 "out;"); 0232 0233 const QVariantMap &map = view->page()->execJavaScript(source, WebPage::SafeJsWorld).toMap(); 0234 0235 bool vertical = map.value(QSL("vertical")).toBool(); 0236 bool horizontal = map.value(QSL("horizontal")).toBool(); 0237 0238 if (!vertical && !horizontal) { 0239 return false; 0240 } 0241 0242 Qt::Orientations orientations; 0243 if (vertical) { 0244 orientations |= Qt::Vertical; 0245 } 0246 if (horizontal) { 0247 orientations |= Qt::Horizontal; 0248 } 0249 m_indicator->setOrientations(orientations); 0250 0251 m_view = view; 0252 0253 QPoint p; 0254 p.setX(pos.x() - m_indicator->width() / 2); 0255 p.setY(pos.y() - m_indicator->height() / 2); 0256 0257 m_indicator->setParent(m_view->overlayWidget()); 0258 m_indicator->move(m_view->mapTo(m_view->overlayWidget(), p)); 0259 m_indicator->show(); 0260 0261 m_frameScroller->setPage(view->page()); 0262 0263 m_view->inputWidget()->grabMouse(); 0264 QApplication::setOverrideCursor(Qt::ArrowCursor); 0265 0266 return true; 0267 } 0268 0269 void AutoScroller::stopScrolling() 0270 { 0271 m_view->inputWidget()->releaseMouse(); 0272 QApplication::restoreOverrideCursor(); 0273 0274 m_indicator->hide(); 0275 m_indicator->setParent(nullptr); 0276 m_frameScroller->stopScrolling(); 0277 } 0278 0279 QRect AutoScroller::indicatorGlobalRect() const 0280 { 0281 QPoint pos = m_indicator->parentWidget()->mapToGlobal(m_indicator->geometry().topLeft()); 0282 return QRect(pos.x(), pos.y(), m_indicator->width(), m_indicator->height()); 0283 }