diff --git a/src/plugins/help/litehtmlhelpviewer.cpp b/src/plugins/help/litehtmlhelpviewer.cpp index 1738280d216..de86df33a5f 100644 --- a/src/plugins/help/litehtmlhelpviewer.cpp +++ b/src/plugins/help/litehtmlhelpviewer.cpp @@ -65,6 +65,7 @@ LiteHtmlHelpViewer::LiteHtmlHelpViewer(QWidget *parent) , m_viewer(new QLiteHtmlWidget) { m_viewer->setResourceHandler([](const QUrl &url) { return getData(url); }); + m_viewer->viewport()->installEventFilter(this); connect(m_viewer, &QLiteHtmlWidget::linkClicked, this, &LiteHtmlHelpViewer::setSource); connect(m_viewer, &QLiteHtmlWidget::contextMenuRequested, @@ -99,28 +100,28 @@ void LiteHtmlHelpViewer::setViewerFont(const QFont &newFont) void LiteHtmlHelpViewer::scaleUp() { - // TODO + setScale(scale() * 1.1); } void LiteHtmlHelpViewer::scaleDown() { - // TODO + setScale(scale() * .9); } void LiteHtmlHelpViewer::resetScale() { - // TODO + m_viewer->setZoomFactor(1); } qreal LiteHtmlHelpViewer::scale() const { - // TODO - return 1; + return m_viewer->zoomFactor(); } void LiteHtmlHelpViewer::setScale(qreal scale) { - // TODO + // interpret 0 as "default" + m_viewer->setZoomFactor(scale == 0 ? qreal(1) : scale); } QString LiteHtmlHelpViewer::title() const @@ -253,6 +254,16 @@ void LiteHtmlHelpViewer::print(QPrinter *printer) // TODO } +bool LiteHtmlHelpViewer::eventFilter(QObject *src, QEvent *e) +{ + if (isScrollWheelZoomingEnabled() && e->type() == QEvent::Wheel) { + auto we = static_cast(e); + if (we->modifiers() == Qt::ControlModifier) + return true; + } + return HelpViewer::eventFilter(src, e); +} + void LiteHtmlHelpViewer::setSourceInternal(const QUrl &url, Utils::optional vscroll) { slotLoadStarted(); diff --git a/src/plugins/help/litehtmlhelpviewer.h b/src/plugins/help/litehtmlhelpviewer.h index b596bf64cf2..7161abd7ce7 100644 --- a/src/plugins/help/litehtmlhelpviewer.h +++ b/src/plugins/help/litehtmlhelpviewer.h @@ -77,6 +77,8 @@ public: void backward() override; void print(QPrinter *printer) override; + bool eventFilter(QObject *src, QEvent *e) override; + private: void goForward(int count); void goBackward(int count); diff --git a/src/plugins/help/qlitehtml/qlitehtmlwidget.cpp b/src/plugins/help/qlitehtml/qlitehtmlwidget.cpp index 66c5a5f2bbb..1d83413f4d1 100644 --- a/src/plugins/help/qlitehtml/qlitehtmlwidget.cpp +++ b/src/plugins/help/qlitehtml/qlitehtmlwidget.cpp @@ -373,6 +373,7 @@ public: litehtml::context context; QUrl url; DocumentContainer documentContainer; + qreal zoomFactor = 1; }; QLiteHtmlWidget::QLiteHtmlWidget(QWidget *parent) @@ -434,6 +435,18 @@ QString QLiteHtmlWidget::title() const return d->documentContainer.caption(); } +void QLiteHtmlWidget::setZoomFactor(qreal scale) +{ + Q_ASSERT(scale != 0); + d->zoomFactor = scale; + render(); +} + +qreal QLiteHtmlWidget::zoomFactor() const +{ + return d->zoomFactor; +} + bool QLiteHtmlWidget::findText(const QString &text, QTextDocument::FindFlags flags, bool incremental, @@ -451,13 +464,14 @@ bool QLiteHtmlWidget::findText(const QString &text, if (success && verticalScrollBar()->value() > newSelectionCombined.top()) { verticalScrollBar()->setValue(newSelectionCombined.top()); } else if (success - && verticalScrollBar()->value() + viewport()->height() + && verticalScrollBar()->value() + toVirtual(viewport()->size()).height() < newSelectionCombined.bottom()) { - verticalScrollBar()->setValue(newSelectionCombined.bottom() - viewport()->height()); + verticalScrollBar()->setValue(newSelectionCombined.bottom() + - toVirtual(viewport()->size()).height()); } else { - viewport()->update(newSelectionCombined.translated(-scrollPosition())); + viewport()->update(fromVirtual(newSelectionCombined.translated(-scrollPosition()))); for (const QRect &r : oldSelection) - viewport()->update(r.translated(-scrollPosition())); + viewport()->update(fromVirtual(r.translated(-scrollPosition()))); } return success; } @@ -510,9 +524,10 @@ void QLiteHtmlWidget::paintEvent(QPaintEvent *event) return; d->documentContainer.setScrollPosition(scrollPosition()); const QPoint pos = -scrollPosition(); - const QRect r = event->rect(); + const QRect r = toVirtual(event->rect()); const litehtml::position clip = {r.x(), r.y(), r.width(), r.height()}; QPainter p(viewport()); + p.setWorldTransform(QTransform().scale(d->zoomFactor, d->zoomFactor)); d->documentContainer.document()->draw(reinterpret_cast(&p), pos.x(), pos.y(), @@ -531,7 +546,7 @@ void QLiteHtmlWidget::mouseMoveEvent(QMouseEvent *event) QPoint pos; htmlPos(event->pos(), &viewportPos, &pos); for (const QRect &r : d->documentContainer.mouseMoveEvent(pos, viewportPos)) - viewport()->update(r.translated(-scrollPosition())); + viewport()->update(fromVirtual(r.translated(-scrollPosition()))); } void QLiteHtmlWidget::mousePressEvent(QMouseEvent *event) @@ -540,7 +555,7 @@ void QLiteHtmlWidget::mousePressEvent(QMouseEvent *event) QPoint pos; htmlPos(event->pos(), &viewportPos, &pos); for (const QRect &r : d->documentContainer.mousePressEvent(pos, viewportPos, event->button())) - viewport()->update(r.translated(-scrollPosition())); + viewport()->update(fromVirtual(r.translated(-scrollPosition()))); } void QLiteHtmlWidget::mouseReleaseEvent(QMouseEvent *event) @@ -549,7 +564,7 @@ void QLiteHtmlWidget::mouseReleaseEvent(QMouseEvent *event) QPoint pos; htmlPos(event->pos(), &viewportPos, &pos); for (const QRect &r : d->documentContainer.mouseReleaseEvent(pos, viewportPos, event->button())) - viewport()->update(r.translated(-scrollPosition())); + viewport()->update(fromVirtual(r.translated(-scrollPosition()))); } void QLiteHtmlWidget::mouseDoubleClickEvent(QMouseEvent *event) @@ -559,7 +574,7 @@ void QLiteHtmlWidget::mouseDoubleClickEvent(QMouseEvent *event) htmlPos(event->pos(), &viewportPos, &pos); for (const QRect &r : d->documentContainer.mouseDoubleClickEvent(pos, viewportPos, event->button())) { - viewport()->update(r.translated(-scrollPosition())); + viewport()->update(fromVirtual(r.translated(-scrollPosition()))); } } @@ -567,7 +582,7 @@ void QLiteHtmlWidget::leaveEvent(QEvent *event) { Q_UNUSED(event) for (const QRect &r : d->documentContainer.leaveEvent()) - viewport()->update(r.translated(-scrollPosition())); + viewport()->update(fromVirtual(r.translated(-scrollPosition()))); } void QLiteHtmlWidget::contextMenuEvent(QContextMenuEvent *event) @@ -582,17 +597,19 @@ void QLiteHtmlWidget::render() { if (!d->documentContainer.document()) return; + const int fullWidth = width() / d->zoomFactor; + const QSize vViewportSize = toVirtual(viewport()->size()); const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr, this); - const int w = width() - scrollbarWidth - 2; - d->documentContainer.render(w, viewport()->height()); - horizontalScrollBar()->setPageStep(viewport()->width()); - horizontalScrollBar() - ->setRange(0, std::max(0, d->documentContainer.document()->width() - viewport()->width())); - verticalScrollBar()->setPageStep(viewport()->height()); + const int w = fullWidth - scrollbarWidth - 2; + d->documentContainer.render(w, vViewportSize.height()); + // scroll bars reflect virtual/scaled size of html document + horizontalScrollBar()->setPageStep(vViewportSize.width()); + horizontalScrollBar()->setRange(0, std::max(0, d->documentContainer.document()->width() - w)); + verticalScrollBar()->setPageStep(vViewportSize.height()); verticalScrollBar()->setRange(0, std::max(0, d->documentContainer.document()->height() - - viewport()->height())); + - vViewportSize.height())); viewport()->update(); } @@ -603,6 +620,36 @@ QPoint QLiteHtmlWidget::scrollPosition() const void QLiteHtmlWidget::htmlPos(const QPoint &pos, QPoint *viewportPos, QPoint *htmlPos) const { - *viewportPos = viewport()->mapFromParent(pos); + *viewportPos = toVirtual(viewport()->mapFromParent(pos)); *htmlPos = *viewportPos + scrollPosition(); } + +QPoint QLiteHtmlWidget::toVirtual(const QPoint &p) const +{ + return {int(p.x() / d->zoomFactor), int(p.y() / d->zoomFactor)}; +} + +QPoint QLiteHtmlWidget::fromVirtual(const QPoint &p) const +{ + return {int(p.x() * d->zoomFactor), int(p.y() * d->zoomFactor)}; +} + +QSize QLiteHtmlWidget::toVirtual(const QSize &s) const +{ + return {int(s.width() / d->zoomFactor), int(s.height() / d->zoomFactor)}; +} + +QSize QLiteHtmlWidget::fromVirtual(const QSize &s) const +{ + return {int(s.width() * d->zoomFactor + 0.5), int(s.height() * d->zoomFactor + 0.5)}; +} + +QRect QLiteHtmlWidget::toVirtual(const QRect &r) const +{ + return {toVirtual(r.topLeft()), toVirtual(r.size())}; +} + +QRect QLiteHtmlWidget::fromVirtual(const QRect &r) const +{ + return {fromVirtual(r.topLeft()), fromVirtual(r.size())}; +} diff --git a/src/plugins/help/qlitehtml/qlitehtmlwidget.h b/src/plugins/help/qlitehtml/qlitehtmlwidget.h index 54c3d65baa5..97f5be6c63b 100644 --- a/src/plugins/help/qlitehtml/qlitehtmlwidget.h +++ b/src/plugins/help/qlitehtml/qlitehtmlwidget.h @@ -44,6 +44,9 @@ public: void setHtml(const QString &content); QString title() const; + void setZoomFactor(qreal scale); + qreal zoomFactor() const; + bool findText(const QString &text, QTextDocument::FindFlags flags, bool incremental, @@ -77,6 +80,12 @@ private: void render(); QPoint scrollPosition() const; void htmlPos(const QPoint &pos, QPoint *viewportPos, QPoint *htmlPos) const; + QPoint toVirtual(const QPoint &p) const; + QPoint fromVirtual(const QPoint &p) const; + QSize toVirtual(const QSize &s) const; + QSize fromVirtual(const QSize &s) const; + QRect toVirtual(const QRect &r) const; + QRect fromVirtual(const QRect &r) const; QLiteHtmlWidgetPrivate *d; };