src/eric7/Graphics/PixmapDiagram.py

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

eric ide

mercurial