diff options
| author | Felix (xq) Queißner <git@mq32.de> | 2020-06-10 02:01:44 +0200 |
|---|---|---|
| committer | Felix (xq) Queißner <git@mq32.de> | 2020-06-10 02:01:44 +0200 |
| commit | a2aaa3c71b8f7e1846a490525001342c6a17f437 (patch) | |
| tree | 0af23617d02948e3ce28ae13d03107aff1d3dc2a | |
| parent | 9b93c4d7c5a450607eca0174b1899e56d6a09a48 (diff) | |
| download | kristall-a2aaa3c71b8f7e1846a490525001342c6a17f437.tar.gz | |
Improves image panning and zoom. Image view is now on a better default and usability.
| -rw-r--r-- | Changelog.txt | 2 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | lib/luis-l-gist/interactiveview.cpp | 133 | ||||
| -rw-r--r-- | lib/luis-l-gist/interactiveview.hpp | 47 | ||||
| -rw-r--r-- | src/browsertab.cpp | 27 | ||||
| -rw-r--r-- | src/browsertab.ui | 10 | ||||
| -rw-r--r-- | src/gophermaprenderer.cpp | 2 | ||||
| -rw-r--r-- | src/kristall.pro | 5 |
8 files changed, 217 insertions, 11 deletions
diff --git a/Changelog.txt b/Changelog.txt index a0a544e..23e5af8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -28,7 +28,7 @@ Kristall Changelog - Added possibility to open links into a new tab - Added possibility to open history and favourite items into new tab or same tab - Added option to use your default OS protocol handler instead of displaying an error message. -- +- Improved image pan and zooming. Explore those graphics! == 0.1 - Initial release
\ No newline at end of file @@ -106,8 +106,6 @@ ln -s Kristall.desktop ~/.local/share/applications/kristall.desktop - [ ] Implement more protocols - [ ] Gopher - [ ] Support more media types (include uudecode and hexbin decoder) - - [x] Read non-binary media only until `.` -- [ ] Image Zoom and Pan ### 0.3 release - [ ] TLS Handling diff --git a/lib/luis-l-gist/interactiveview.cpp b/lib/luis-l-gist/interactiveview.cpp new file mode 100644 index 0000000..2707352 --- /dev/null +++ b/lib/luis-l-gist/interactiveview.cpp @@ -0,0 +1,133 @@ +#include "interactiveview.hpp" + +#define VIEW_CENTER viewport()->rect().center() +#define VIEW_WIDTH viewport()->rect().width() +#define VIEW_HEIGHT viewport()->rect().height() + +InteractiveView::InteractiveView(QWidget * parent) : + QGraphicsView(parent) +{ + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + setMaxSize(); + centerOn(0, 0); + + zoomDelta = 0.1; + panSpeed = 4; + _doMousePanning = false; + _doKeyZoom = false; + _scale = 1.0; + + panButton = Qt::MiddleButton; + zoomKey = Qt::Key_Z; +} + +qreal InteractiveView::getScale() const +{ + return _scale; +} + +void InteractiveView::keyPressEvent(QKeyEvent * event) +{ + qint32 key = event->key(); + + if(key == zoomKey){ + _doKeyZoom = true; + } + + if (_doKeyZoom){ + if (key == Qt::Key_Up) + zoomIn(); + + else if (key == Qt::Key_Down) + zoomOut(); + } + + else{ + QGraphicsView::keyPressEvent(event); + } +} + +void InteractiveView::keyReleaseEvent(QKeyEvent * event) +{ + if (event->key() == zoomKey){ + _doKeyZoom = false; + } + + QGraphicsView::keyReleaseEvent(event); +} + +void InteractiveView::mouseMoveEvent(QMouseEvent * event) +{ + if (_doMousePanning){ + QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(_lastMousePos); + pan(mouseDelta); + } + + QGraphicsView::mouseMoveEvent(event); + _lastMousePos = event->pos(); +} + +void InteractiveView::mousePressEvent(QMouseEvent * event) +{ + if (event->button() == panButton){ + _lastMousePos = event->pos(); + _doMousePanning = true; + } + + QGraphicsView::mousePressEvent(event); +} + +void InteractiveView::mouseReleaseEvent(QMouseEvent * event) +{ + if (event->button() == panButton){ + _doMousePanning = false; + } + + QGraphicsView::mouseReleaseEvent(event); +} + +void InteractiveView::wheelEvent(QWheelEvent *event) +{ + QPoint scrollAmount = event->angleDelta(); + + // Apply zoom. + scrollAmount.y() > 0 ? zoomIn() : zoomOut(); +} + +void InteractiveView::setMaxSize() +{ + setSceneRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX); +} + +void InteractiveView::zoom(float scaleFactor) +{ + scale(scaleFactor, scaleFactor); + _scale *= scaleFactor; +} + +void InteractiveView::zoomIn() +{ + zoom(1 + zoomDelta); +} + +void InteractiveView::zoomOut() +{ + zoom (1 - zoomDelta); +} + +void InteractiveView::pan(QPointF delta) +{ + // Scale the pan amount by the current zoom. + delta *= _scale; + delta *= panSpeed; + + // Have panning be anchored from the mouse. + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + QPoint newCenter(VIEW_WIDTH / 2 - delta.x(), VIEW_HEIGHT / 2 - delta.y()); + centerOn(mapToScene(newCenter)); + + // For zooming to anchor from the view center. + setTransformationAnchor(QGraphicsView::AnchorViewCenter); +} diff --git a/lib/luis-l-gist/interactiveview.hpp b/lib/luis-l-gist/interactiveview.hpp new file mode 100644 index 0000000..1a0b1f8 --- /dev/null +++ b/lib/luis-l-gist/interactiveview.hpp @@ -0,0 +1,47 @@ +#ifndef INTERACTIVE_VIEW_H +#define INTERACTIVE_VIEW_H + +#include <QGraphicsView> +#include <QWheelEvent> +#include <QKeyEvent> + +class InteractiveView : public QGraphicsView +{ +public: + explicit InteractiveView(QWidget * parent); + + qreal panSpeed; + qreal zoomDelta; + qreal zoomKey; + Qt::MouseButton panButton; + + void pan(QPointF delta); + void zoom(float scaleFactor); + void zoomIn(); + void zoomOut(); + + qreal getScale() const; + +protected: + + void keyPressEvent(QKeyEvent*) override; + void keyReleaseEvent(QKeyEvent*) override; + + void mouseMoveEvent(QMouseEvent*) override; + void mousePressEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; + void wheelEvent(QWheelEvent*) override; + +private: + + // Flags to determine if zooming or panning should be done. + bool _doMousePanning; + bool _doKeyZoom; + + QPoint _lastMousePos; + qreal _scale; + + void setMaxSize(); +}; + +#endif // INTERACTIVE_VIEW_H diff --git a/src/browsertab.cpp b/src/browsertab.cpp index 086af38..d9f2ffa 100644 --- a/src/browsertab.cpp +++ b/src/browsertab.cpp @@ -21,6 +21,7 @@ #include <QFile> #include <QMimeDatabase> #include <QMimeType> +#include <QImageReader> #include <QGraphicsPixmapItem> #include <QGraphicsTextItem> @@ -65,8 +66,6 @@ BrowserTab::BrowserTab(MainWindow * mainWindow) : this->ui->text_browser->setVisible(true); this->ui->text_browser->setContextMenuPolicy(Qt::CustomContextMenu); - - this->ui->graphics_browser->setScene(&graphics_scene); } BrowserTab::~BrowserTab() @@ -337,16 +336,34 @@ void BrowserTab::on_requestComplete(const QByteArray &data, const QString &mime) else if(mime.startsWith("image/")) { doc_type = Image; + QBuffer buffer; + buffer.setData(data); + + QImageReader reader { &buffer }; + reader.setAutoTransform(true); + reader.setAutoDetectImageFormat(true); + + QImage img; - if(img.loadFromData(data, nullptr)) + if(reader.read(&img)) { - this->graphics_scene.addPixmap(QPixmap::fromImage(img)); + auto pixmap = QPixmap::fromImage(img); + this->graphics_scene.addPixmap(pixmap); + this->graphics_scene.setSceneRect(pixmap.rect()); } else { - this->graphics_scene.addText("Failed to load picture!"); + this->graphics_scene.addText(QString("Failed to load picture:\r\n%1").arg(reader.errorString())); } + this->ui->graphics_browser->setScene(&graphics_scene); + + auto * invoker = new QObject(); + connect(invoker, &QObject::destroyed, [this]() { + this->ui->graphics_browser->fitInView(graphics_scene.sceneRect(), Qt::KeepAspectRatio); + }); + invoker->deleteLater(); + this->ui->graphics_browser->fitInView(graphics_scene.sceneRect(), Qt::KeepAspectRatio); } else if(mime.startsWith("video/") or mime.startsWith("audio/")) { diff --git a/src/browsertab.ui b/src/browsertab.ui index 6903bd8..7be4d3c 100644 --- a/src/browsertab.ui +++ b/src/browsertab.ui @@ -164,7 +164,10 @@ p, li { white-space: pre-wrap; } </widget> </item> <item> - <widget class="QGraphicsView" name="graphics_browser"> + <widget class="InteractiveView" name="graphics_browser"> + <property name="interactive"> + <bool>true</bool> + </property> <property name="dragMode"> <enum>QGraphicsView::ScrollHandDrag</enum> </property> @@ -190,6 +193,11 @@ p, li { white-space: pre-wrap; } <header>mediaplayer.hpp</header> <container>1</container> </customwidget> + <customwidget> + <class>InteractiveView</class> + <extends>QGraphicsView</extends> + <header location="global">interactiveview.hpp</header> + </customwidget> </customwidgets> <resources> <include location="icons.qrc"/> diff --git a/src/gophermaprenderer.cpp b/src/gophermaprenderer.cpp index 89f3905..e2fe434 100644 --- a/src/gophermaprenderer.cpp +++ b/src/gophermaprenderer.cpp @@ -137,8 +137,6 @@ std::unique_ptr<QTextDocument> GophermapRenderer::render(const QByteArray &input QString title = items.at(0); - // 1Phlog /phlog octotherp.org 70 + - if (type == 'i') { cursor.insertText(title + "\n", standard); diff --git a/src/kristall.pro b/src/kristall.pro index dc69b8b..0321179 100644 --- a/src/kristall.pro +++ b/src/kristall.pro @@ -18,7 +18,11 @@ DEFINES += QT_DEPRECATED_WARNINGS QMAKE_CFLAGS += -Wno-unused-parameter QMAKE_CXXFLAGS += -Wno-unused-parameter +INCLUDEPATH += $$PWD/../lib/luis-l-gist/ +DEPENDPATH += $$PWD/../lib/luis-l-gist/ + SOURCES += \ + ../lib/luis-l-gist/interactiveview.cpp \ browsertab.cpp \ documentoutlinemodel.cpp \ documentstyle.cpp \ @@ -39,6 +43,7 @@ SOURCES += \ webclient.cpp HEADERS += \ + ../lib/luis-l-gist/interactiveview.hpp \ browsertab.hpp \ documentoutlinemodel.hpp \ documentstyle.hpp \ |
