# -*- coding: utf-8 -*-
### Copyright (C) 2008-2012 Antonio Valentino <a_valentino@users.sf.net>
### This file is part of GSDView.
### GSDView is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.
### GSDView is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU General Public License for more details.
### You should have received a copy of the GNU General Public License
### along with GSDView; if not, write to the Free Software
### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
'''Drawing components for Qt4.'''
from qt import QtCore, QtGui
from .mousemanager import MouseMode # , RubberBandMode
__author__ = 'Antonio Valentino <a_valentino@users.sf.net>'
__date__ = '$Date$'
__revision__ = '$Revision$'
### Graphics Items ############################################################
def _highlightSelectedGraphicsItem(item, painter, option, boundingrect=None):
'''Highlights item as selected.
.. note:: This function is a duplicate of
qt_graphicsItem_highlightSelected() in
qgraphicssvgitem.cpp!
'''
murect = painter.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
if abs(max(murect.width(), murect.height())) <= 0.000000000001:
return
if boundingrect is None:
boundingrect = item.boundingRect()
mbrect = painter.transform().mapRect(boundingrect)
if min(mbrect.width(), mbrect.height()) < 1.0:
return
try:
#if item.type() in (QGraphicsEllipseItem.Type,
# QGraphicsPathItem.Type,
# QGraphicsPolygonItem.Type,
# QGraphicsRectItem.Type,
# QGraphicsSimpleTextItem.Type,
# QGraphicsLineItem.Type):
itemPenWidth = item.pen().widthF()
except AttributeError:
itemPenWidth = 1.0
pad = itemPenWidth / 2
penWidth = 0 # cosmetic pen
fgcolor = option.palette.windowText().color()
# ensure good contrast against fgcolor
bgcolor = QtGui.QColor(0 if fgcolor.red() > 127 else 255,
0 if fgcolor.green() > 127 else 255,
0 if fgcolor.blue() > 127 else 255)
painter.setPen(QtGui.QPen(bgcolor, penWidth, QtCore.Qt.SolidLine))
painter.setBrush(QtCore.Qt.NoBrush)
painter.drawRect(boundingrect.adjusted(pad, pad, -pad, -pad))
painter.setPen(QtGui.QPen(option.palette.windowText(), 0,
QtCore.Qt.DashLine))
painter.setBrush(QtCore.Qt.NoBrush)
painter.drawRect(boundingrect.adjusted(pad, pad, -pad, -pad))
[docs]class GraphicsPointItem(QtGui.QAbstractGraphicsShapeItem):
'''Qt graphics item for point merkers.
Draw a symbol that scales its size according to the zoom level in
order to keep approximatively constant size.
Original size and maximum scaling factor are configurable.
.. note:: currently the only symbol supported is a filled circle
(pen and brush are configurable).
.. note:: this class don't depends on OGR so it can be moved in a
module out of the gdalbackend.
'''
Type = QtGui.QGraphicsItem.UserType + 100
def __init__(self, x=None, y=None, radius=None, parent=None, scene=None,
**kargs):
super(GraphicsPointItem, self).__init__(parent, scene, **kargs)
# @COMPATIBILITY: Qt >= 4.6.0 needs this flag to be set otherwise the
# exact exposedRect is not computed
# @SEEALSO: ItemUsesExtendedStyleOption item at
# http://doc.qt.nokia.com/4.6/qgraphicsitem.html#GraphicsItemFlag-enum
try:
self.setFlag(QtGui.QGraphicsItem.ItemUsesExtendedStyleOptions)
except AttributeError:
ItemUsesExtendedStyleOptions = 0x200
self.setFlag(ItemUsesExtendedStyleOptions)
if None not in (x, y):
self.setPos(x, y)
self._radius = 1
if radius is not None:
self._radius = radius
self._maxfact = 10
brush = self.brush()
brush.setStyle(QtCore.Qt.SolidPattern)
self.setBrush(brush)
[docs] def radius(self):
return self._radius
[docs] def setRadius(self, radius):
if radius < 0:
raise ValueError('invalid radius: "%s"' % radius)
self._radius = float(radius)
[docs] def maxFactor(self):
return self._maxfact
[docs] def setMaxFactor(self, maxfact):
if maxfact < 0:
raise ValueError('invalid saling factor: "%s"' % maxfact)
self._maxfact = float(maxfact)
[docs] def type(self):
return self.Type
[docs] def boundingRect(self):
penwidth = self.pen().widthF()
radius = self._maxfact * self._radius
diameter = 2. * radius
return QtCore.QRectF(-radius - penwidth / 2, -radius - penwidth / 2,
diameter + penwidth, diameter + penwidth)
[docs] def paint(self, painter, option, widget):
levelOfDetail = option.levelOfDetailFromTransform(painter.transform())
painter.setPen(self.pen())
painter.setBrush(self.brush())
radius = min(self._radius / levelOfDetail,
self._radius * self._maxfact)
painter.drawEllipse(QtCore.QPointF(0, 0), radius, radius)
if option.state & QtGui.QStyle.State_Selected:
penwidth = self.pen().widthF()
diameter = 2. * radius
rect = QtCore.QRectF(-radius - penwidth / 2,
-radius - penwidth / 2,
diameter + penwidth, diameter + penwidth)
_highlightSelectedGraphicsItem(self, painter, option, rect)
[docs]class GraphicsItemGroup(QtGui.QGraphicsItemGroup):
'''Qt graphics item group with common style.'''
Type = QtGui.QGraphicsItem.UserType + 101
def __init__(self, parent=None, scene=None, **kargs):
super(GraphicsItemGroup, self).__init__(parent, scene, **kargs)
self._pen = QtGui.QPen()
self._brush = QtGui.QBrush()
[docs] def addToGroup(self, item):
super(GraphicsItemGroup, self).addToGroup(item)
try:
item.setPen(self._pen)
item.setBrusH(self._brush)
except AttributeError:
pass
# @TODO: check pyqtProperty
[docs] def pen(self):
return self._pen
[docs] def setPen(self, pen):
if not isinstance(pen, QtGui.QPen):
raise TypeError('invalid pen object: %s' % pen)
self._pen = pen
for item in self.childItems():
try:
item.setPen(pen)
except AttributeError:
pass
[docs] def brush(self):
return self._brush
[docs] def setBrush(self, brush):
if not isinstance(brush, QtGui.QBrush):
raise TypeError('invalid brush object: %s' % brush)
self._brush = brush
for item in self.childItems():
try:
item.setBrush(brush)
except AttributeError:
pass
### Drawing tools #############################################################
[docs]class DrawPointMode(MouseMode):
dragmode = QtGui.QGraphicsView.NoDrag
cursor = QtCore.Qt.CrossCursor
icon = ':/trolltech/styles/commonstyle/images/standardbutton-yes-128.png'
label = 'Draw Point'
name = 'drawPoint'
[docs] def sceneEventFilter(self, obj, event):
if (event.type() == QtCore.QEvent.GraphicsSceneMousePress and
event.button() == QtCore.Qt.LeftButton):
return True
elif (event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and
event.button() == QtCore.Qt.LeftButton):
pen = QtGui.QPen()
pen.setColor(QtCore.Qt.red)
brush = QtGui.QBrush()
brush.setColor(QtCore.Qt.red)
brush.setStyle(QtCore.Qt.SolidPattern)
RADIUS = 3
point = event.scenePos()
item = GraphicsPointItem(point.x(), point.y(), RADIUS)
item.setPen(pen)
item.setBrush(brush)
item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
item.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
obj.addItem(item)
return True
return False
[docs]class DrawLineMode(MouseMode):
dragmode = QtGui.QGraphicsView.NoDrag
cursor = QtCore.Qt.CrossCursor
icon = ':/trolltech/dialogs/qprintpreviewdialog/images/fit-width-24.png'
label = 'Draw Line'
name = 'drawLine'
def __init__(self, parent=None):
super(DrawLineMode, self).__init__(parent)
self.rubberband = None
self.pen = QtGui.QPen()
self.pen.setWidth(1)
self.pen.setColor(QtCore.Qt.red)
[docs] def sceneEventFilter(self, obj, event):
if (event.type() == QtCore.QEvent.GraphicsSceneMousePress and
event.button() == QtCore.Qt.LeftButton):
assert(self.rubberband is None)
self.rubberband = QtGui.QRubberBand(QtGui.QRubberBand.Line)
self.rubberband.setGeometry(QtCore.QRect(event.screenPos(),
QtCore.QSize()))
self.rubberband.show()
return True
if (event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and
event.button() == QtCore.Qt.LeftButton):
assert(self.rubberband is not None)
self.rubberband.hide()
self.rubberband = None
line = QtCore.QLineF(
event.buttonDownScenePos(QtCore.Qt.LeftButton),
event.scenePos())
item = obj.addLine(line, self.pen)
item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
item.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
return True
elif (event.type() == QtCore.QEvent.GraphicsSceneMouseMove and
bool(event.buttons() & QtCore.Qt.LeftButton)):
assert(self.rubberband is not None)
rect = QtCore.QRect(
event.buttonDownScreenPos(QtCore.Qt.LeftButton),
event.screenPos()).normalized()
self.rubberband.setGeometry(rect)
return True
return False
#~ class DrawPolygonMode(MouseMode):
#~ dragmode = QtGui.QGraphicsView.NoDrag
#~ cursor = QtCore.Qt.CrossCursor
#~ icon = ':/trolltech/dialogs/qprintpreviewdialog/images/fit-width-24.png'
#~ label = 'Draw Line'
#~ name = 'drawLine'
#~ def __init__(self, parent=None):
#~ super(DrawPolygonMode, self).__init__(parent)
#~ self.rubberband = None
#~ self.pen = QtGui.QPen()
#~ self.pen.setWidth(1)
#~ self.pen.setColor(QtCore.Qt.red)
#~ self.brush = QtGui.QBrush()
#~ #self.brush.setStyle(QtCore.Qt.SolidPattern)
#~ #self.brush.setColor(QtCore.Qt.red)
#~ def sceneEventFilter(self, obj, event):
#~ if (event.type() == QtCore.QEvent.GraphicsSceneMousePress and
#~ event.button() == QtCore.Qt.LeftButton):
#~ assert(self.rubberband is None)
#~ self.rubberband = QtGui.QRubberBand(QtGui.QRubberBand.Line)
#~ self.rubberband.setGeometry(QtCore.QRect(event.screenPos(),
#~ QtCore.QSize()))
#~ self.rubberband.show()
#~ return True
#~ if (event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and
#~ event.button() == QtCore.Qt.LeftButton):
#~ assert(self.rubberband is not None)
#~ self.rubberband.hide()
#~ self.rubberband = None
#~ line = QtCore.QLineF(
#~ event.buttonDownScenePos(QtCore.Qt.LeftButton),
#~ event.scenePos())
#~ item = obj.addLine(line, self.pen)
#~ item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
#~ item.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
#~ return True
#~ elif (event.type() == QtCore.QEvent.GraphicsSceneMouseMove and
#~ bool(event.buttons() & QtCore.Qt.LeftButton)):
#~ assert(self.rubberband is not None)
#~ rect = QtCore.QRect(
#~ event.buttonDownScreenPos(QtCore.Qt.LeftButton),
#~ event.screenPos()).normalized()
#~ self.rubberband.setGeometry(rect)
#~ return True
#~ return False
[docs]class DrawRectMode(MouseMode):
dragmode = QtGui.QGraphicsView.NoDrag
cursor = QtCore.Qt.CrossCursor
icon = ':/trolltech/styles/commonstyle/images/media-stop-32.png'
label = 'Draw Rect'
name = 'drawRect'
def __init__(self, parent=None):
super(DrawRectMode, self).__init__(parent)
self.rubberband = None
self.pen = QtGui.QPen()
self.pen.setWidth(1)
self.pen.setColor(QtCore.Qt.red)
self.brush = QtGui.QBrush()
#self.brush.setStyle(QtCore.Qt.SolidPattern)
#self.brush.setColor(QtCore.Qt.red)
[docs] def sceneEventFilter(self, obj, event):
if (event.type() == QtCore.QEvent.GraphicsSceneMousePress and
event.button() == QtCore.Qt.LeftButton):
assert(self.rubberband is None)
self.rubberband = QtGui.QRubberBand(QtGui.QRubberBand.Rectangle)
self.rubberband.setGeometry(QtCore.QRect(event.screenPos(),
QtCore.QSize()))
self.rubberband.show()
return True
if (event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and
event.button() == QtCore.Qt.LeftButton):
assert(self.rubberband is not None)
self.rubberband.hide()
self.rubberband = None
rect = QtCore.QRectF(
event.buttonDownScenePos(QtCore.Qt.LeftButton),
event.scenePos()).normalized()
item = obj.addRect(rect, self.pen, self.brush)
item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
item.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
return True
elif (event.type() == QtCore.QEvent.GraphicsSceneMouseMove and
bool(event.buttons() & QtCore.Qt.LeftButton)):
assert(self.rubberband is not None)
rect = QtCore.QRect(
event.buttonDownScreenPos(QtCore.Qt.LeftButton),
event.screenPos()).normalized()
self.rubberband.setGeometry(rect)
return True
return False
[docs]class DrawEllipseMode(MouseMode):
dragmode = QtGui.QGraphicsView.NoDrag
cursor = QtCore.Qt.CrossCursor
icon = ':/trolltech/styles/commonstyle/images/standardbutton-no-128.png'
label = 'Draw Ellipse'
name = 'drawEllipse'
def __init__(self, parent=None):
super(DrawEllipseMode, self).__init__(parent)
self.rubberband = None
self.pen = QtGui.QPen()
self.pen.setWidth(1)
self.pen.setColor(QtCore.Qt.red)
self.brush = QtGui.QBrush()
#self.brush.setStyle(QtCore.Qt.SolidPattern)
#self.brush.setColor(QtCore.Qt.red)
[docs] def sceneEventFilter(self, obj, event):
if (event.type() == QtCore.QEvent.GraphicsSceneMousePress and
event.button() == QtCore.Qt.LeftButton):
assert(self.rubberband is None)
self.rubberband = QtGui.QRubberBand(QtGui.QRubberBand.Rectangle)
self.rubberband.setGeometry(QtCore.QRect(event.screenPos(),
QtCore.QSize()))
self.rubberband.show()
return True
if (event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and
event.button() == QtCore.Qt.LeftButton):
assert(self.rubberband is not None)
self.rubberband.hide()
self.rubberband = None
rect = QtCore.QRectF(
event.buttonDownScenePos(QtCore.Qt.LeftButton),
event.scenePos()).normalized()
item = obj.addEllipse(rect, self.pen, self.brush)
item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
item.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
return True
elif (event.type() == QtCore.QEvent.GraphicsSceneMouseMove and
bool(event.buttons() & QtCore.Qt.LeftButton)):
assert(self.rubberband is not None)
rect = QtCore.QRect(
event.buttonDownScreenPos(QtCore.Qt.LeftButton),
event.screenPos()).normalized()
self.rubberband.setGeometry(rect)
return True
return False