eric6/Graphics/PixmapDiagram.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7198
684261ef2165
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2004 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog showing a pixmap.
8 """
9
10 from __future__ import unicode_literals
11
12 from PyQt5.QtCore import Qt, QSize, QEvent
13 from PyQt5.QtGui import QPalette, QImage, QPixmap, QPainter, QFont, QColor
14 from PyQt5.QtWidgets import QLabel, QSizePolicy, QScrollArea, QAction, QMenu, \
15 QToolBar
16 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog
17
18 from E5Gui import E5MessageBox
19 from E5Gui.E5MainWindow import E5MainWindow
20 from E5Gui.E5ZoomWidget import E5ZoomWidget
21
22 import UI.Config
23
24 import Preferences
25 from Globals import qVersionTuple
26
27
28 class PixmapDiagram(E5MainWindow):
29 """
30 Class implementing a dialog showing a pixmap.
31 """
32 ZoomLevels = [
33 1, 3, 5, 7, 9,
34 10, 20, 30, 50, 67, 80, 90,
35 100,
36 110, 120, 133, 150, 170, 200, 240, 300, 400,
37 500, 600, 700, 800, 900, 1000,
38 ]
39 ZoomLevelDefault = 100
40
41 def __init__(self, pixmap, parent=None, name=None):
42 """
43 Constructor
44
45 @param pixmap filename of a graphics file to show (string)
46 @param parent parent widget of the view (QWidget)
47 @param name name of the view widget (string)
48 """
49 super(PixmapDiagram, self).__init__(parent)
50 if name:
51 self.setObjectName(name)
52 else:
53 self.setObjectName("PixmapDiagram")
54 self.setWindowTitle(self.tr("Pixmap-Viewer"))
55
56 self.pixmapLabel = QLabel()
57 self.pixmapLabel.setObjectName("pixmapLabel")
58 self.pixmapLabel.setBackgroundRole(QPalette.Base)
59 self.pixmapLabel.setSizePolicy(
60 QSizePolicy.Ignored, QSizePolicy.Ignored)
61 self.pixmapLabel.setScaledContents(True)
62
63 self.pixmapView = QScrollArea()
64 self.pixmapView.setObjectName("pixmapView")
65 self.pixmapView.setBackgroundRole(QPalette.Dark)
66 self.pixmapView.setWidget(self.pixmapLabel)
67
68 self.setCentralWidget(self.pixmapView)
69
70 self.__zoomWidget = E5ZoomWidget(
71 UI.PixmapCache.getPixmap("zoomOut.png"),
72 UI.PixmapCache.getPixmap("zoomIn.png"),
73 UI.PixmapCache.getPixmap("zoomReset.png"), self)
74 self.statusBar().addPermanentWidget(self.__zoomWidget)
75 self.__zoomWidget.setMapping(
76 PixmapDiagram.ZoomLevels, PixmapDiagram.ZoomLevelDefault)
77 self.__zoomWidget.valueChanged.connect(self.__doZoom)
78
79 # polish up the dialog
80 self.resize(QSize(800, 600).expandedTo(self.minimumSizeHint()))
81
82 self.pixmapfile = pixmap
83 self.status = self.__showPixmap(self.pixmapfile)
84
85 self.__initActions()
86 self.__initContextMenu()
87 self.__initToolBars()
88
89 self.grabGesture(Qt.PinchGesture)
90
91 def __initActions(self):
92 """
93 Private method to initialize the view actions.
94 """
95 self.closeAct = \
96 QAction(UI.PixmapCache.getIcon("close.png"),
97 self.tr("Close"), self)
98 self.closeAct.triggered.connect(self.close)
99
100 self.printAct = \
101 QAction(UI.PixmapCache.getIcon("print.png"),
102 self.tr("Print"), self)
103 self.printAct.triggered.connect(self.__printDiagram)
104
105 self.printPreviewAct = \
106 QAction(UI.PixmapCache.getIcon("printPreview.png"),
107 self.tr("Print Preview"), self)
108 self.printPreviewAct.triggered.connect(self.__printPreviewDiagram)
109
110 def __initContextMenu(self):
111 """
112 Private method to initialize the context menu.
113 """
114 self.__menu = QMenu(self)
115 self.__menu.addAction(self.closeAct)
116 self.__menu.addSeparator()
117 self.__menu.addAction(self.printPreviewAct)
118 self.__menu.addAction(self.printAct)
119
120 self.setContextMenuPolicy(Qt.CustomContextMenu)
121 self.customContextMenuRequested.connect(self.__showContextMenu)
122
123 def __showContextMenu(self, coord):
124 """
125 Private slot to show the context menu of the listview.
126
127 @param coord the position of the mouse pointer (QPoint)
128 """
129 self.__menu.popup(self.mapToGlobal(coord))
130
131 def __initToolBars(self):
132 """
133 Private method to populate the toolbars with our actions.
134 """
135 self.windowToolBar = QToolBar(self.tr("Window"), self)
136 self.windowToolBar.setIconSize(UI.Config.ToolBarIconSize)
137 self.windowToolBar.addAction(self.closeAct)
138
139 self.graphicsToolBar = QToolBar(self.tr("Graphics"), self)
140 self.graphicsToolBar.setIconSize(UI.Config.ToolBarIconSize)
141 self.graphicsToolBar.addAction(self.printPreviewAct)
142 self.graphicsToolBar.addAction(self.printAct)
143
144 self.addToolBar(Qt.TopToolBarArea, self.windowToolBar)
145 self.addToolBar(Qt.TopToolBarArea, self.graphicsToolBar)
146
147 def __showPixmap(self, filename):
148 """
149 Private method to show a file.
150
151 @param filename name of the file to be shown (string)
152 @return flag indicating success (boolean)
153 """
154 image = QImage(filename)
155 if image.isNull():
156 E5MessageBox.warning(
157 self,
158 self.tr("Pixmap-Viewer"),
159 self.tr(
160 """<p>The file <b>{0}</b> cannot be displayed."""
161 """ The format is not supported.</p>""").format(filename))
162 return False
163
164 self.pixmapLabel.setPixmap(QPixmap.fromImage(image))
165 self.pixmapLabel.adjustSize()
166 return True
167
168 def getDiagramName(self):
169 """
170 Public method to retrieve a name for the diagram.
171
172 @return name for the diagram
173 """
174 return self.pixmapfile
175
176 def getStatus(self):
177 """
178 Public method to retrieve the status of the canvas.
179
180 @return flag indicating a successful pixmap loading (boolean)
181 """
182 return self.status
183
184 def wheelEvent(self, evt):
185 """
186 Protected method to handle wheel events.
187
188 @param evt reference to the wheel event (QWheelEvent)
189 """
190 if evt.modifiers() & Qt.ControlModifier:
191 if qVersionTuple() >= (5, 0, 0):
192 delta = evt.angleDelta().y()
193 else:
194 delta = evt.delta()
195 if delta < 0:
196 self.__zoomOut()
197 elif delta > 0:
198 self.__zoomIn()
199 evt.accept()
200 return
201
202 super(PixmapDiagram, self).wheelEvent(evt)
203
204 def event(self, evt):
205 """
206 Public method handling events.
207
208 @param evt reference to the event (QEvent)
209 @return flag indicating, if the event was handled (boolean)
210 """
211 if evt.type() == QEvent.Gesture:
212 self.gestureEvent(evt)
213 return True
214
215 return super(PixmapDiagram, self).event(evt)
216
217 def gestureEvent(self, evt):
218 """
219 Protected method handling gesture events.
220
221 @param evt reference to the gesture event (QGestureEvent
222 """
223 pinch = evt.gesture(Qt.PinchGesture)
224 if pinch:
225 if pinch.state() == Qt.GestureStarted:
226 pinch.setTotalScaleFactor(self.__zoom() / 100)
227 elif pinch.state() == Qt.GestureUpdated:
228 self.__doZoom(int(pinch.totalScaleFactor() * 100))
229 evt.accept()
230
231 ###########################################################################
232 ## Private menu handling methods below.
233 ###########################################################################
234
235 def __adjustScrollBar(self, scrollBar, factor):
236 """
237 Private method to adjust a scrollbar by a certain factor.
238
239 @param scrollBar reference to the scrollbar object (QScrollBar)
240 @param factor factor to adjust by (float)
241 """
242 scrollBar.setValue(int(factor * scrollBar.value() +
243 ((factor - 1) * scrollBar.pageStep() / 2)))
244
245 def __levelForZoom(self, zoom):
246 """
247 Private method determining the zoom level index given a zoom factor.
248
249 @param zoom zoom factor (integer)
250 @return index of zoom factor (integer)
251 """
252 try:
253 index = PixmapDiagram.ZoomLevels.index(zoom)
254 except ValueError:
255 for index in range(len(PixmapDiagram.ZoomLevels)):
256 if zoom <= PixmapDiagram.ZoomLevels[index]:
257 break
258 return index
259
260 def __doZoom(self, value):
261 """
262 Private method to set the zoom value in percent.
263
264 @param value zoom value in percent (integer)
265 """
266 oldValue = self.__zoom()
267 if value != oldValue:
268 self.pixmapLabel.resize(
269 value / 100 * self.pixmapLabel.pixmap().size())
270
271 factor = value / oldValue
272 self.__adjustScrollBar(
273 self.pixmapView.horizontalScrollBar(), factor)
274 self.__adjustScrollBar(
275 self.pixmapView.verticalScrollBar(), factor)
276
277 self.__zoomWidget.setValue(value)
278
279 def __zoomIn(self):
280 """
281 Private method to zoom into the pixmap.
282 """
283 index = self.__levelForZoom(self.__zoom())
284 if index < len(PixmapDiagram.ZoomLevels) - 1:
285 self.__doZoom(PixmapDiagram.ZoomLevels[index + 1])
286
287 def __zoomOut(self):
288 """
289 Private method to zoom out of the pixmap.
290 """
291 index = self.__levelForZoom(self.__zoom())
292 if index > 0:
293 self.__doZoom(PixmapDiagram.ZoomLevels[index - 1])
294
295 def __zoomReset(self):
296 """
297 Private method to reset the zoom value.
298 """
299 self.__doZoom(PixmapDiagram.ZoomLevels[PixmapDiagram.ZoomLevelDefault])
300
301 def __zoom(self):
302 """
303 Private method to get the current zoom factor in percent.
304
305 @return current zoom factor in percent (integer)
306 """
307 return int(self.pixmapLabel.width() /
308 self.pixmapLabel.pixmap().width() * 100.0)
309
310 def __printDiagram(self):
311 """
312 Private slot called to print the diagram.
313 """
314 printer = QPrinter(mode=QPrinter.ScreenResolution)
315 printer.setFullPage(True)
316 if Preferences.getPrinter("ColorMode"):
317 printer.setColorMode(QPrinter.Color)
318 else:
319 printer.setColorMode(QPrinter.GrayScale)
320 if Preferences.getPrinter("FirstPageFirst"):
321 printer.setPageOrder(QPrinter.FirstPageFirst)
322 else:
323 printer.setPageOrder(QPrinter.LastPageFirst)
324 printer.setPrinterName(Preferences.getPrinter("PrinterName"))
325
326 printDialog = QPrintDialog(printer, self)
327 if printDialog.exec_():
328 self.__print(printer)
329
330 def __printPreviewDiagram(self):
331 """
332 Private slot called to show a print preview of the diagram.
333 """
334 from PyQt5.QtPrintSupport import QPrintPreviewDialog
335
336 printer = QPrinter(mode=QPrinter.ScreenResolution)
337 printer.setFullPage(True)
338 if Preferences.getPrinter("ColorMode"):
339 printer.setColorMode(QPrinter.Color)
340 else:
341 printer.setColorMode(QPrinter.GrayScale)
342 if Preferences.getPrinter("FirstPageFirst"):
343 printer.setPageOrder(QPrinter.FirstPageFirst)
344 else:
345 printer.setPageOrder(QPrinter.LastPageFirst)
346 printer.setPageMargins(
347 Preferences.getPrinter("LeftMargin") * 10,
348 Preferences.getPrinter("TopMargin") * 10,
349 Preferences.getPrinter("RightMargin") * 10,
350 Preferences.getPrinter("BottomMargin") * 10,
351 QPrinter.Millimeter
352 )
353 printer.setPrinterName(Preferences.getPrinter("PrinterName"))
354
355 preview = QPrintPreviewDialog(printer, self)
356 preview.paintRequested[QPrinter].connect(self.__print)
357 preview.exec_()
358
359 def __print(self, printer):
360 """
361 Private slot to the actual printing.
362
363 @param printer reference to the printer object (QPrinter)
364 """
365 painter = QPainter()
366 painter.begin(printer)
367
368 # calculate margin and width of printout
369 font = QFont("times", 10)
370 painter.setFont(font)
371 fm = painter.fontMetrics()
372 fontHeight = fm.lineSpacing()
373 marginX = printer.pageRect().x() - printer.paperRect().x()
374 marginX = Preferences.getPrinter("LeftMargin") * \
375 int(printer.resolution() / 2.54) - marginX
376 marginY = printer.pageRect().y() - printer.paperRect().y()
377 marginY = Preferences.getPrinter("TopMargin") * \
378 int(printer.resolution() / 2.54) - marginY
379
380 width = printer.width() - marginX - \
381 Preferences.getPrinter("RightMargin") * \
382 int(printer.resolution() / 2.54)
383 height = printer.height() - fontHeight - 4 - marginY - \
384 Preferences.getPrinter("BottomMargin") * \
385 int(printer.resolution() / 2.54)
386
387 # write a foot note
388 s = self.tr("Diagram: {0}").format(self.getDiagramName())
389 tc = QColor(50, 50, 50)
390 painter.setPen(tc)
391 painter.drawRect(marginX, marginY, width, height)
392 painter.drawLine(marginX, marginY + height + 2,
393 marginX + width, marginY + height + 2)
394 painter.setFont(font)
395 painter.drawText(marginX, marginY + height + 4, width,
396 fontHeight, Qt.AlignRight, s)
397
398 # render the diagram
399 size = self.pixmapLabel.pixmap().size()
400 size.scale(QSize(width - 10, height - 10), # 5 px inner margin
401 Qt.KeepAspectRatio)
402 painter.setViewport(marginX + 5, marginY + 5,
403 size.width(), size.height())
404 painter.setWindow(self.pixmapLabel.pixmap().rect())
405 painter.drawPixmap(0, 0, self.pixmapLabel.pixmap())
406 painter.end()

eric ide

mercurial