aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-06-10 02:01:44 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-06-10 02:01:44 +0200
commita2aaa3c71b8f7e1846a490525001342c6a17f437 (patch)
tree0af23617d02948e3ce28ae13d03107aff1d3dc2a
parent9b93c4d7c5a450607eca0174b1899e56d6a09a48 (diff)
downloadkristall-a2aaa3c71b8f7e1846a490525001342c6a17f437.tar.gz
Improves image panning and zoom. Image view is now on a better default and usability.
-rw-r--r--Changelog.txt2
-rw-r--r--README.md2
-rw-r--r--lib/luis-l-gist/interactiveview.cpp133
-rw-r--r--lib/luis-l-gist/interactiveview.hpp47
-rw-r--r--src/browsertab.cpp27
-rw-r--r--src/browsertab.ui10
-rw-r--r--src/gophermaprenderer.cpp2
-rw-r--r--src/kristall.pro5
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
diff --git a/README.md b/README.md
index 297bb80..8800e46 100644
--- a/README.md
+++ b/README.md
@@ -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 \