eric7/Graphics/PixmapDiagram.py

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

eric ide

mercurial