From 88b5e9283424ba4f94f8e7b01e8278e85307309d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20M=C3=BCller?= <d_muel20@uni-muenster.de>
Date: Tue, 5 Jun 2018 16:02:50 +0200
Subject: [PATCH] * Added a zoom tool

---
 Grinder/Grinder.pro                      |   6 +-
 Grinder/Version.h                        |   6 +-
 Grinder/res/Grinder.qrc                  |   2 +
 Grinder/res/Resources.h                  |   2 +
 Grinder/res/cursors/zoom-cursor.png      | Bin 0 -> 465 bytes
 Grinder/res/icons/zoom.png               | Bin 0 -> 12790 bytes
 Grinder/ui/image/ImageEditorToolList.cpp |   2 +
 Grinder/ui/image/tools/EraserTool.cpp    |  15 ++---
 Grinder/ui/image/tools/EraserTool.h      |   2 -
 Grinder/ui/image/tools/ZoomTool.cpp      |  74 +++++++++++++++++++++++
 Grinder/ui/image/tools/ZoomTool.h        |  42 +++++++++++++
 Grinder/ui/visscene/RubberBandNode.cpp   |  13 +++-
 Grinder/ui/visscene/RubberBandNode.h     |   2 +
 Grinder/ui/visscene/VisualSceneView.cpp  |  42 +++++++------
 Grinder/ui/visscene/VisualSceneView.h    |   1 +
 15 files changed, 177 insertions(+), 32 deletions(-)
 create mode 100644 Grinder/res/cursors/zoom-cursor.png
 create mode 100644 Grinder/res/icons/zoom.png
 create mode 100644 Grinder/ui/image/tools/ZoomTool.cpp
 create mode 100644 Grinder/ui/image/tools/ZoomTool.h

diff --git a/Grinder/Grinder.pro b/Grinder/Grinder.pro
index 23c2b83..e2ac016 100644
--- a/Grinder/Grinder.pro
+++ b/Grinder/Grinder.pro
@@ -227,7 +227,8 @@ SOURCES += \
     image/draftitems/PixelsDraftItem.cpp \
     image/renderers/PixelsDraftItemRenderer.cpp \
     ui/image/draftitems/PixelsDraftItemNode.cpp \
-    ui/visscene/RubberBandNode.cpp
+    ui/visscene/RubberBandNode.cpp \
+    ui/image/tools/ZoomTool.cpp
 
 HEADERS += \        
 	ui/mainwnd/GrinderWindow.h \
@@ -498,7 +499,8 @@ HEADERS += \
     image/draftitems/PixelsDraftItem.h \
     image/renderers/PixelsDraftItemRenderer.h \
     ui/image/draftitems/PixelsDraftItemNode.h \
-    ui/visscene/RubberBandNode.h
+    ui/visscene/RubberBandNode.h \
+    ui/image/tools/ZoomTool.h
 
 FORMS += \        
 	ui/mainwnd/GrinderWindow.ui \
diff --git a/Grinder/Version.h b/Grinder/Version.h
index 358ef6d..29df668 100644
--- a/Grinder/Version.h
+++ b/Grinder/Version.h
@@ -10,14 +10,14 @@
 
 #define GRNDR_INFO_TITLE		"Grinder"
 #define GRNDR_INFO_COPYRIGHT	"Copyright (c) WWU Muenster"
-#define GRNDR_INFO_DATE			"02.06.2018"
+#define GRNDR_INFO_DATE			"05.06.2018"
 #define GRNDR_INFO_COMPANY		"WWU Muenster"
 #define GRNDR_INFO_WEBSITE		"http://www.uni-muenster.de"
 
 #define GRNDR_VERSION_MAJOR		0
-#define GRNDR_VERSION_MINOR		4
+#define GRNDR_VERSION_MINOR		5
 #define GRNDR_VERSION_REVISION	0
-#define GRNDR_VERSION_BUILD		176
+#define GRNDR_VERSION_BUILD		177
 
 namespace grndr
 {
diff --git a/Grinder/res/Grinder.qrc b/Grinder/res/Grinder.qrc
index f893cb0..fb4a86a 100644
--- a/Grinder/res/Grinder.qrc
+++ b/Grinder/res/Grinder.qrc
@@ -47,6 +47,7 @@
         <file>icons/painting/eraser.png</file>
         <file>icons/painting/paint-brush.png</file>
         <file>icons/painting/051-vector-1.png</file>
+        <file>icons/zoom.png</file>
     </qresource>
     <qresource prefix="/">
         <file>css/global.css</file>
@@ -65,5 +66,6 @@
         <file>cursors/picker-cursor.png</file>
         <file>cursors/paintbrush-cursor.png</file>
         <file>cursors/eraser-cursor.png</file>
+        <file>cursors/zoom-cursor.png</file>
     </qresource>
 </RCC>
diff --git a/Grinder/res/Resources.h b/Grinder/res/Resources.h
index 90ebfd6..07eaede 100644
--- a/Grinder/res/Resources.h
+++ b/Grinder/res/Resources.h
@@ -62,6 +62,7 @@
 #define FILE_ICON_EDITOR_CONVERTTOITEMS ":/icons/icons/painting/051-vector-1.png"
 #define FILE_ICON_EDITOR_PAINTBRUSH ":/icons/icons/painting/paint-brush.png"
 #define FILE_ICON_EDITOR_ERASER ":/icons/icons/painting/eraser.png"
+#define FILE_ICON_EDITOR_ZOOM ":/icons/icons/zoom.png"
 
 /* Cursors */
 
@@ -70,5 +71,6 @@
 #define FILE_CURSOR_EDITOR_COLORPICKER ":/cursors/cursors/picker-cursor.png"
 #define FILE_CURSOR_EDITOR_PAINTBRUSH ":/cursors/cursors/paintbrush-cursor.png"
 #define FILE_CURSOR_EDITOR_ERASER ":/cursors/cursors/eraser-cursor.png"
+#define FILE_CURSOR_EDITOR_ZOOM ":/cursors/cursors/zoom-cursor.png"
 
 #endif
diff --git a/Grinder/res/cursors/zoom-cursor.png b/Grinder/res/cursors/zoom-cursor.png
new file mode 100644
index 0000000000000000000000000000000000000000..e97b4f46f4d0530dca3282014057c74833ad17df
GIT binary patch
literal 465
zcmV;?0WSWDP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00004XF*Lt006O%
z3;baP00009a7bBm000hA000hA0o1nlv;Y7A8FWQhbW?9;ba!ELWdLwtX>N2bZe?^J
zG%heMGBNQWX_Wu~0ZvIoK~zXf?UXS}Ls1Y#6A@BrW8(%a1Mb1f#&u|CXBJ^E0b45@
zZ56@J!rIP4>;;2`AYyV(VBqsH&V0o#7f$hC=FJTA?xfdJANJq^USJAe@C0KR!mqUn
zH(=65e8MrTLMNI05h9V@pTZ#=!6ke^{C*BAP?BS5c5dP|Xlo1ZA>u4tk~426|4Hlc
z0LH$-2Bh*qz2I2B>%6TUh=vY4$P{kLx(_+hXYkIM2brQ9AGE3~@Xqc0E0I1oxcq3y
z#NN4{e<gB>4AzPj4d4~LbK*fJH`HK#t`#%wgYlvRQ@Q?bs2B9PR$QcQn1Hb^W_hDs
z|L97eYen4>ax8Wp$z=p(*@^2Pmqjb;79TWb-sBy2p)CJfbdnp|P8K*8J2$!Cor@^f
z-wkz%>|QJC79TWbZqh#$sc2cGla@s~saeFG`WIP*<h{EY?%9gWEvbTR00000NkvXX
Hu0mjf+3&$o

literal 0
HcmV?d00001

diff --git a/Grinder/res/icons/zoom.png b/Grinder/res/icons/zoom.png
new file mode 100644
index 0000000000000000000000000000000000000000..76b36008ffa446dddc839f04c7ffbeab75799806
GIT binary patch
literal 12790
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
Y534^8h1gaChYDGl+ny*s=5_P`0c{?;WB>pF

literal 0
HcmV?d00001

diff --git a/Grinder/ui/image/ImageEditorToolList.cpp b/Grinder/ui/image/ImageEditorToolList.cpp
index 48ac272..98b4ec9 100644
--- a/Grinder/ui/image/ImageEditorToolList.cpp
+++ b/Grinder/ui/image/ImageEditorToolList.cpp
@@ -15,6 +15,7 @@
 #include "tools/ColorPickerTool.h"
 #include "tools/PaintbrushTool.h"
 #include "tools/EraserTool.h"
+#include "tools/ZoomTool.h"
 
 const char* ImageEditorToolList::Serialization_Group = "Tools";
 const char* ImageEditorToolList::Serialization_Element = "Tool";
@@ -30,6 +31,7 @@ ImageEditorToolList::ImageEditorToolList(ImageEditor* imageEditor) : ImageEditor
 	_tools.push_back(ToolEntry{createTool<LineDraftItemTool>(imageEditor), nullptr});
 	_tools.push_back(ToolEntry{createTool<PaintbrushTool>(imageEditor), nullptr});
 	_tools.push_back(ToolEntry{createTool<EraserTool>(imageEditor), nullptr});
+	_tools.push_back(ToolEntry{createTool<ZoomTool>(imageEditor), nullptr});
 }
 
 void ImageEditorToolList::assignUiComponents(QWidget* actionOwner)
diff --git a/Grinder/ui/image/tools/EraserTool.cpp b/Grinder/ui/image/tools/EraserTool.cpp
index 03ff7ab..835d710 100644
--- a/Grinder/ui/image/tools/EraserTool.cpp
+++ b/Grinder/ui/image/tools/EraserTool.cpp
@@ -28,18 +28,19 @@ void EraserTool::createProperties()
 
 VisualSceneInputHandler::InputEventResult EraserTool::rightMousePressed(const QGraphicsSceneMouseEvent* event)
 {
-	// Create a rubber band for selecting a region to erase
 	createRubberBand(event->scenePos());
-
 	return InputEventResult::Process;
 }
 
 VisualSceneInputHandler::InputEventResult EraserTool::rightMouseMoved(const QGraphicsSceneMouseEvent* event)
 {
 	if (_rubberBandNode)
+	{
 		_rubberBandNode->move(event->scenePos());
-
-	return InputEventResult::Process;
+		return InputEventResult::Process;
+	}
+	else
+		return InputEventResult::Ignore;
 }
 
 VisualSceneInputHandler::InputEventResult EraserTool::rightMouseReleased(const QGraphicsSceneMouseEvent* event)
@@ -60,11 +61,11 @@ VisualSceneInputHandler::InputEventResult EraserTool::rightMouseReleased(const Q
 
 		_imageEditor->controller().paintPixels(nullptr, QColor{}, points);
 
-		// Remove the rubber band
 		removeRubberBand();
-	}
-
 		return InputEventResult::Process;
+	}
+	else
+		return InputEventResult::Ignore;
 }
 
 void EraserTool::createRubberBand(QPointF pos)
diff --git a/Grinder/ui/image/tools/EraserTool.h b/Grinder/ui/image/tools/EraserTool.h
index 5453889..eaa5914 100644
--- a/Grinder/ui/image/tools/EraserTool.h
+++ b/Grinder/ui/image/tools/EraserTool.h
@@ -6,8 +6,6 @@
 #ifndef ERASERTOOL_H
 #define ERASERTOOL_H
 
-#include <QGraphicsProxyWidget>
-
 #include "PaintbrushTool.h"
 #include "ui/visscene/RubberBandNode.h"
 
diff --git a/Grinder/ui/image/tools/ZoomTool.cpp b/Grinder/ui/image/tools/ZoomTool.cpp
new file mode 100644
index 0000000..5b87293
--- /dev/null
+++ b/Grinder/ui/image/tools/ZoomTool.cpp
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * File: ZoomTool.cpp
+ * Date: 05.6.2018
+ *****************************************************************************/
+
+#include "Grinder.h"
+#include "ZoomTool.h"
+#include "ui/image/ImageEditor.h"
+#include "res/Resources.h"
+
+const char* ZoomTool::tool_type = "ZoomTool";
+
+ZoomTool::ZoomTool(ImageEditor* imageEditor) : ImageEditorTool(imageEditor, "Zoom", FILE_ICON_EDITOR_ZOOM, "Z", QCursor{QPixmap{FILE_CURSOR_EDITOR_ZOOM}, 7, 7})
+{
+
+}
+
+VisualSceneInputHandler::InputEventResult ZoomTool::mousePressed(const QGraphicsSceneMouseEvent* event)
+{
+	createRubberBand(event->scenePos());
+	return InputEventResult::Process;
+}
+
+VisualSceneInputHandler::InputEventResult ZoomTool::mouseMoved(const QGraphicsSceneMouseEvent* event)
+{
+	if (_rubberBandNode)
+	{
+		_rubberBandNode->move(event->scenePos());
+		return InputEventResult::Process;
+	}
+	else
+		return InputEventResult::Ignore;
+}
+
+VisualSceneInputHandler::InputEventResult ZoomTool::mouseReleased(const QGraphicsSceneMouseEvent* event)
+{
+	Q_UNUSED(event);
+
+	if (_rubberBandNode)
+	{
+		// Zoom into the rubber band rectangle
+		if (auto scene = _imageEditor->controller().activeScene())
+			scene->view()->zoomToRect(_rubberBandNode->getRect());
+
+		removeRubberBand();
+		return InputEventResult::Process;
+	}
+	else
+		return InputEventResult::Ignore;
+}
+
+void ZoomTool::createRubberBand(QPointF pos)
+{
+	if (!_rubberBandNode)
+	{
+		if (auto scene = _imageEditor->controller().activeScene())
+			_rubberBandNode = new RubberBandNode{scene, pos};
+	}
+}
+
+void ZoomTool::removeRubberBand()
+{
+	if (_rubberBandNode)
+	{
+		delete _rubberBandNode;
+		_rubberBandNode = nullptr;
+
+		if (auto scene = _imageEditor->controller().activeScene())
+		{
+			scene->view()->setDragMode(QGraphicsView::ScrollHandDrag);
+			scene->view()->setDragMode(QGraphicsView::RubberBandDrag);
+		}
+	}
+}
diff --git a/Grinder/ui/image/tools/ZoomTool.h b/Grinder/ui/image/tools/ZoomTool.h
new file mode 100644
index 0000000..8928e3d
--- /dev/null
+++ b/Grinder/ui/image/tools/ZoomTool.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * File: ZoomTool.h
+ * Date: 05.6.2018
+ *****************************************************************************/
+
+#ifndef ZOOMTOOL_H
+#define ZOOMTOOL_H
+
+#include "ui/image/ImageEditorTool.h"
+#include "ui/visscene/RubberBandNode.h"
+
+namespace grndr
+{
+	class ZoomTool : public ImageEditorTool
+	{
+	public:
+		static const char* tool_type;
+
+	public:
+		ZoomTool(ImageEditor* imageEditor);
+
+	public:
+		virtual QString getToolType() const override { return tool_type; }
+
+	public:
+		virtual void toolDeactivated(ImageEditorTool* nextTool) override { Q_UNUSED(nextTool); removeRubberBand(); }
+
+	protected:
+		virtual InputEventResult mousePressed(const QGraphicsSceneMouseEvent* event) override;
+		virtual InputEventResult mouseMoved(const QGraphicsSceneMouseEvent* event) override;
+		virtual InputEventResult mouseReleased(const QGraphicsSceneMouseEvent* event) override;
+
+	private:
+		void createRubberBand(QPointF pos);
+		void removeRubberBand();
+
+	private:
+		RubberBandNode* _rubberBandNode{nullptr};
+	};
+}
+
+#endif
diff --git a/Grinder/ui/visscene/RubberBandNode.cpp b/Grinder/ui/visscene/RubberBandNode.cpp
index 2e1d047..fe306f5 100644
--- a/Grinder/ui/visscene/RubberBandNode.cpp
+++ b/Grinder/ui/visscene/RubberBandNode.cpp
@@ -7,7 +7,7 @@
 #include "RubberBandNode.h"
 
 RubberBandNode::RubberBandNode(QGraphicsScene* scene, QPointF pos) : QObject(scene),
-	_startPosition{pos}
+	_scene{scene}, _startPosition{pos}
 {
 	_rubberBand = new QRubberBand{QRubberBand::Rectangle};
 	_rubberBand->move(pos.toPoint());
@@ -20,6 +20,17 @@ RubberBandNode::RubberBandNode(QGraphicsScene* scene, QPointF pos) : QObject(sce
 
 RubberBandNode::~RubberBandNode()
 {
+	if (_scene)
+	{
+		for (auto& view : _scene->views())
+		{
+			// Fix Qt's cursor hell
+			auto dragMode = view->dragMode();
+			view->setDragMode(QGraphicsView::ScrollHandDrag);
+			view->setDragMode(dragMode);
+		}
+	}
+
 	if (_rubberBandNode)
 		delete _rubberBandNode;
 }
diff --git a/Grinder/ui/visscene/RubberBandNode.h b/Grinder/ui/visscene/RubberBandNode.h
index 56e51ca..8aaf3f5 100644
--- a/Grinder/ui/visscene/RubberBandNode.h
+++ b/Grinder/ui/visscene/RubberBandNode.h
@@ -26,6 +26,8 @@ namespace grndr
 		QRect getRect() const { if (_rubberBand) return _rubberBand->geometry(); else return QRect{}; }
 
 	private:
+		QGraphicsScene* _scene{nullptr};
+
 		QRubberBand* _rubberBand{nullptr};
 		QGraphicsProxyWidget* _rubberBandNode{nullptr};
 
diff --git a/Grinder/ui/visscene/VisualSceneView.cpp b/Grinder/ui/visscene/VisualSceneView.cpp
index e615afb..c3140f6 100644
--- a/Grinder/ui/visscene/VisualSceneView.cpp
+++ b/Grinder/ui/visscene/VisualSceneView.cpp
@@ -80,22 +80,6 @@ void VisualSceneView::updateActions()
 	_zoomFullAction->setEnabled(_scene && (zoom != 1.0));
 }
 
-void VisualSceneView::fitToWindow(QGraphicsItem* item)
-{
-	if (item)
-	{
-		fitInView(item, Qt::KeepAspectRatio);
-	}
-	else
-	{
-		if (_scene)
-			fitInView(_scene->sceneRect(), Qt::KeepAspectRatio);
-	}
-
-	emit zoomChanged(getZoom());
-	updateActions();
-}
-
 void VisualSceneView::selectAllItems() const
 {
 	if (_scene)
@@ -114,10 +98,34 @@ void VisualSceneView::moveSelectedItems(QPoint delta)
 	}
 }
 
+void VisualSceneView::zoomToRect(QRect rect)
+{
+	fitInView(rect, Qt::KeepAspectRatio);
+
+	emit zoomChanged(getZoom());
+	updateActions();
+}
+
+void VisualSceneView::fitToWindow(QGraphicsItem* item)
+{
+	if (item)
+	{
+		fitInView(item, Qt::KeepAspectRatio);
+	}
+	else
+	{
+		if (_scene)
+			fitInView(_scene->sceneRect(), Qt::KeepAspectRatio);
+	}
+
+	emit zoomChanged(getZoom());
+	updateActions();
+}
+
 void VisualSceneView::wheelEvent(QWheelEvent* event)
 {
 	// Only zoom if CTRL is pressed
-	if (!(event->modifiers() & Qt::ControlModifier))
+	if (!event->modifiers().testFlag(Qt::ControlModifier))
 	{
 		QGraphicsView::wheelEvent(event);
 		return;
diff --git a/Grinder/ui/visscene/VisualSceneView.h b/Grinder/ui/visscene/VisualSceneView.h
index 30fb47f..cd120c8 100644
--- a/Grinder/ui/visscene/VisualSceneView.h
+++ b/Grinder/ui/visscene/VisualSceneView.h
@@ -35,6 +35,7 @@ namespace grndr
 		void zoomIn() { zoom(sceneStyle().getViewStyle().zoomFactor); }
 		void zoomOut() { zoom(1.0 / sceneStyle().getViewStyle().zoomFactor); }
 		void zoomFull() { setZoom(1.0); }
+		void zoomToRect(QRect rect);
 		void fitToWindow(QGraphicsItem* item = nullptr);		
 
 	public:
-- 
GitLab