$search
00001 # Copyright (c) 2011, Dirk Thomas, TU Darmstadt 00002 # All rights reserved. 00003 # Copyright (c) 2013, Jonathan Bohren, The Johns Hopkins University 00004 # All rights reserved 00005 # 00006 # Redistribution and use in source and binary forms, with or without 00007 # modification, are permitted provided that the following conditions 00008 # are met: 00009 # 00010 # * Redistributions of source code must retain the above copyright 00011 # notice, this list of conditions and the following disclaimer. 00012 # * Redistributions in binary form must reproduce the above 00013 # copyright notice, this list of conditions and the following 00014 # disclaimer in the documentation and/or other materials provided 00015 # with the distribution. 00016 # * Neither the name of the TU Darmstadt nor the names of its 00017 # contributors may be used to endorse or promote products derived 00018 # from this software without specific prior written permission. 00019 # 00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00024 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00031 # POSSIBILITY OF SUCH DAMAGE. 00032 00033 from __future__ import division 00034 00035 from python_qt_binding.QtCore import QPointF, QRectF, Qt 00036 from python_qt_binding.QtGui import QGraphicsView, QTransform 00037 00038 00039 class InteractiveGraphicsView(QGraphicsView): 00040 00041 def __init__(self, parent=None): 00042 super(InteractiveGraphicsView, self).__init__(parent) 00043 self.setObjectName('InteractiveGraphicsView') 00044 00045 self._last_pan_point = None 00046 self._last_scene_center = None 00047 00048 def mousePressEvent(self, mouse_event): 00049 self._last_pan_point = mouse_event.pos() 00050 self._last_scene_center = self._map_to_scene_f(QRectF(self.frameRect()).center()) 00051 self.setCursor(Qt.ClosedHandCursor) 00052 00053 def mouseReleaseEvent(self, mouse_event): 00054 self.setCursor(Qt.OpenHandCursor) 00055 self._last_pan_point = None 00056 00057 def mouseMoveEvent(self, mouse_event): 00058 if self._last_pan_point is not None: 00059 delta_scene = self.mapToScene(mouse_event.pos()) - self.mapToScene(self._last_pan_point) 00060 if not delta_scene.isNull(): 00061 self.centerOn(self._last_scene_center - delta_scene) 00062 self._last_scene_center -= delta_scene 00063 self._last_pan_point = mouse_event.pos() 00064 QGraphicsView.mouseMoveEvent(self, mouse_event) 00065 00066 def wheelEvent(self, wheel_event): 00067 if wheel_event.modifiers() == Qt.NoModifier: 00068 num_degrees = wheel_event.delta() / 8.0 00069 num_steps = num_degrees / 15.0 00070 mouse_before_scale_in_scene = self.mapToScene(wheel_event.pos()) 00071 00072 scale_factor = 1.2 * num_steps 00073 if num_steps < 0: 00074 scale_factor = -1.0 / scale_factor 00075 scaling = QTransform(scale_factor, 0, 0, scale_factor, 0, 0) 00076 self.setTransform(self.transform() * scaling) 00077 00078 mouse_after_scale_in_scene = self.mapToScene(wheel_event.pos()) 00079 center_in_scene = self.mapToScene(self.frameRect().center()) 00080 self.centerOn(center_in_scene + mouse_before_scale_in_scene - mouse_after_scale_in_scene) 00081 00082 wheel_event.accept() 00083 else: 00084 QGraphicsView.wheelEvent(self, wheel_event) 00085 00086 def _map_to_scene_f(self, pointf): 00087 point = pointf.toPoint() 00088 if pointf.x() == point.x() and pointf.y() == point.y(): 00089 # map integer coordinates 00090 return self.mapToScene(point) 00091 elif pointf.x() == point.x(): 00092 # map integer x and decimal y coordinates 00093 pointA = self.mapToScene((pointf + QPointF(0, -0.5)).toPoint()) 00094 pointB = self.mapToScene((pointf + QPointF(0, 0.5)).toPoint()) 00095 return (pointA + pointB) / 2.0 00096 elif pointf.y() == point.y(): 00097 # map decimal x and integer y and coordinates 00098 pointA = self.mapToScene((pointf + QPointF(-0.5, 0)).toPoint()) 00099 pointB = self.mapToScene((pointf + QPointF(0.5, 0)).toPoint()) 00100 return (pointA + pointB) / 2.0 00101 else: 00102 # map decimal coordinates 00103 pointA = self.mapToScene((pointf + QPointF(-0.5, -0.5)).toPoint()) 00104 pointB = self.mapToScene((pointf + QPointF(-0.5, 0.5)).toPoint()) 00105 pointC = self.mapToScene((pointf + QPointF(0.5, -0.5)).toPoint()) 00106 pointD = self.mapToScene((pointf + QPointF(0.5, 0.5)).toPoint()) 00107 return (pointA + pointB + pointC + pointD) / 4.0