From 43a40c3b9a5c7c78343dfbbf3e971ac5c98836a1 Mon Sep 17 00:00:00 2001
From: EXL <exlmotodev@gmail.com>
Date: Thu, 18 Aug 2016 15:35:39 +0000
Subject: [PATCH] Add zooming in media viewer on Ctrl + mouse wheel

Mouse wheel without Ctrl key is used for switch to the prev/next image;
Clicking on mouse wheel is used to reset zoom;
To switch images are taken only a physical mouse wheel events.

Signed-off-by: Serg Koles <exlmotodev@gmail.com> (github: EXL)
---
 Telegram/SourceFiles/mediaview.cpp | 144 +++++++++++++++++++----------
 Telegram/SourceFiles/mediaview.h   |   6 ++
 2 files changed, 99 insertions(+), 51 deletions(-)

diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp
index 44669a276..fcaaf98e0 100644
--- a/Telegram/SourceFiles/mediaview.cpp
+++ b/Telegram/SourceFiles/mediaview.cpp
@@ -520,6 +520,74 @@ void MediaView::step_radial(uint64 ms, bool timer) {
 	}
 }
 
+void MediaView::zoomIn() {
+	int32 newZoom = _zoom;
+	if (newZoom == ZoomToScreenLevel) {
+		if (qCeil(_zoomToScreen) <= MaxZoomLevel) {
+			newZoom = qCeil(_zoomToScreen);
+		}
+	} else {
+		if (newZoom < _zoomToScreen && (newZoom + 1 > _zoomToScreen || (_zoomToScreen > MaxZoomLevel && newZoom == MaxZoomLevel))) {
+			newZoom = ZoomToScreenLevel;
+		} else if (newZoom < MaxZoomLevel) {
+			++newZoom;
+		}
+	}
+	zoomUpdate(newZoom);
+}
+
+void MediaView::zoomOut() {
+	int32 newZoom = _zoom;
+	if (newZoom == ZoomToScreenLevel) {
+		if (qFloor(_zoomToScreen) >= -MaxZoomLevel) {
+			newZoom = qFloor(_zoomToScreen);
+		}
+	} else {
+		if (newZoom > _zoomToScreen && (newZoom - 1 < _zoomToScreen || (_zoomToScreen < -MaxZoomLevel && newZoom == -MaxZoomLevel))) {
+			newZoom = ZoomToScreenLevel;
+		} else if (newZoom > -MaxZoomLevel) {
+			--newZoom;
+		}
+	}
+	zoomUpdate(newZoom);
+}
+
+void MediaView::zoomReset() {
+	int32 newZoom = _zoom;
+	if (_zoom == 0) {
+		if (qFloor(_zoomToScreen) == qCeil(_zoomToScreen) && qRound(_zoomToScreen) >= -MaxZoomLevel && qRound(_zoomToScreen) <= MaxZoomLevel) {
+			newZoom = qRound(_zoomToScreen);
+		} else {
+			newZoom = ZoomToScreenLevel;
+		}
+	} else {
+		newZoom = 0;
+	}
+	_x = -_width / 2;
+	_y = -((gifShown() ? _gif->height() : (_current.height() / cIntRetinaFactor())) / 2);
+	float64 z = (_zoom == ZoomToScreenLevel) ? _zoomToScreen : _zoom;
+	if (z >= 0) {
+		_x = qRound(_x * (z + 1));
+		_y = qRound(_y * (z + 1));
+	} else {
+		_x = qRound(_x / (-z + 1));
+		_y = qRound(_y / (-z + 1));
+	}
+	_x += width() / 2;
+	_y += height() / 2;
+	update();
+	zoomUpdate(newZoom);
+}
+
+void MediaView::zoomUpdate(int32 &newZoom) {
+	if (newZoom != ZoomToScreenLevel) {
+		while ((newZoom < 0 && (-newZoom + 1) > _w) || (-newZoom + 1) > _h) {
+			++newZoom;
+		}
+	}
+	setZoomLevel(newZoom);
+}
+
 void MediaView::clearData() {
 	if (!isHidden()) {
 		hide();
@@ -1810,62 +1878,34 @@ void MediaView::keyPressEvent(QKeyEvent *e) {
 		moveToNext(-1);
 	} else if (e->key() == Qt::Key_Right) {
 		moveToNext(1);
-    } else if (e->modifiers().testFlag(Qt::ControlModifier) && (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == ']' || e->key() == Qt::Key_Asterisk || e->key() == Qt::Key_Minus || e->key() == Qt::Key_Underscore || e->key() == Qt::Key_0)) {
-		int32 newZoom = _zoom;
-        if (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == Qt::Key_Asterisk || e->key() == ']') {
-			if (newZoom == ZoomToScreenLevel) {
-				if (qCeil(_zoomToScreen) <= MaxZoomLevel) {
-					newZoom = qCeil(_zoomToScreen);
-				}
-			} else {
-				if (newZoom < _zoomToScreen && (newZoom + 1 > _zoomToScreen || (_zoomToScreen > MaxZoomLevel && newZoom == MaxZoomLevel))) {
-					newZoom = ZoomToScreenLevel;
-				} else if (newZoom < MaxZoomLevel) {
-					++newZoom;
-				}
-			}
+	} else if (e->modifiers().testFlag(Qt::ControlModifier) && (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == ']' || e->key() == Qt::Key_Asterisk || e->key() == Qt::Key_Minus || e->key() == Qt::Key_Underscore || e->key() == Qt::Key_0)) {
+		if (e->key() == Qt::Key_Plus || e->key() == Qt::Key_Equal || e->key() == Qt::Key_Asterisk || e->key() == ']') {
+			zoomIn();
 		} else if (e->key() == Qt::Key_Minus || e->key() == Qt::Key_Underscore) {
-			if (newZoom == ZoomToScreenLevel) {
-				if (qFloor(_zoomToScreen) >= -MaxZoomLevel) {
-					newZoom = qFloor(_zoomToScreen);
-				}
-			} else {
-				if (newZoom > _zoomToScreen && (newZoom - 1 < _zoomToScreen || (_zoomToScreen < -MaxZoomLevel && newZoom == -MaxZoomLevel))) {
-					newZoom = ZoomToScreenLevel;
-				} else if (newZoom > -MaxZoomLevel) {
-					--newZoom;
-				}
-			}
+			zoomOut();
 		} else {
-			if (_zoom == 0) {
-				if (qFloor(_zoomToScreen) == qCeil(_zoomToScreen) && qRound(_zoomToScreen) >= -MaxZoomLevel && qRound(_zoomToScreen) <= MaxZoomLevel) {
-					newZoom = qRound(_zoomToScreen);
-				} else {
-					newZoom = ZoomToScreenLevel;
-				}
-			} else {
-				newZoom = 0;
-			}
-			_x = -_width / 2;
-			_y = -((gifShown() ? _gif->height() : (_current.height() / cIntRetinaFactor())) / 2);
-			float64 z = (_zoom == ZoomToScreenLevel) ? _zoomToScreen : _zoom;
-			if (z >= 0) {
-				_x = qRound(_x * (z + 1));
-				_y = qRound(_y * (z + 1));
-			} else {
-				_x = qRound(_x / (-z + 1));
-				_y = qRound(_y / (-z + 1));
-			}
-			_x += width() / 2;
-			_y += height() / 2;
-			update();
+			zoomReset();
 		}
-		if (newZoom != ZoomToScreenLevel) {
-			while ((newZoom < 0 && (-newZoom + 1) > _w) || (-newZoom + 1) > _h) {
-				++newZoom;
+	}
+}
+
+void MediaView::wheelEvent(QWheelEvent *e) {
+	if (e->delta() < 0) {
+		if (e->modifiers().testFlag(Qt::ControlModifier)) {
+			zoomOut();
+		} else {
+			if (e->source() == Qt::MouseEventNotSynthesized) {
+				moveToNext(-1);
+			}
+		}
+	} else {
+		if (e->modifiers().testFlag(Qt::ControlModifier)) {
+			zoomIn();
+		} else {
+			if (e->source() == Qt::MouseEventNotSynthesized) {
+				moveToNext(1);
 			}
 		}
-		setZoomLevel(newZoom);
 	}
 }
 
@@ -2114,6 +2154,8 @@ void MediaView::mousePressEvent(QMouseEvent *e) {
 				_yStart = _y;
 			}
 		}
+	} else if (e->button() == Qt::MiddleButton) {
+		zoomReset();
 	}
 	activateControls();
 }
diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h
index c33222545..3f8756b39 100644
--- a/Telegram/SourceFiles/mediaview.h
+++ b/Telegram/SourceFiles/mediaview.h
@@ -107,6 +107,7 @@ protected:
 	void paintEvent(QPaintEvent *e) override;
 
 	void keyPressEvent(QKeyEvent *e) override;
+	void wheelEvent(QWheelEvent *e) override;
 	void mousePressEvent(QMouseEvent *e) override;
 	void mouseDoubleClickEvent(QMouseEvent *e) override;
 	void mouseMoveEvent(QMouseEvent *e) override;
@@ -170,6 +171,11 @@ private:
 	void step_state(uint64 ms, bool timer);
 	void step_radial(uint64 ms, bool timer);
 
+	void zoomIn();
+	void zoomOut();
+	void zoomReset();
+	void zoomUpdate(int32 &newZoom);
+
 	void paintDocRadialLoading(Painter &p, bool radial, float64 radialOpacity);
 
 	QBrush _transparentBrush;