src/eric7/EricGraphics/EricGraphicsView.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
19 19
20 20
21 class EricGraphicsView(QGraphicsView): 21 class EricGraphicsView(QGraphicsView):
22 """ 22 """
23 Class implementing a graphics view. 23 Class implementing a graphics view.
24 24
25 @signal zoomValueChanged(int) emitted to signal a change of the zoom value 25 @signal zoomValueChanged(int) emitted to signal a change of the zoom value
26 """ 26 """
27
27 zoomValueChanged = pyqtSignal(int) 28 zoomValueChanged = pyqtSignal(int)
28 29
29 ZoomLevels = [ 30 ZoomLevels = [
30 1, 3, 5, 7, 9, 31 1,
31 10, 20, 30, 50, 67, 80, 90, 32 3,
33 5,
34 7,
35 9,
36 10,
37 20,
38 30,
39 50,
40 67,
41 80,
42 90,
32 100, 43 100,
33 110, 120, 133, 150, 170, 200, 240, 300, 400, 44 110,
34 500, 600, 700, 800, 900, 1000, 45 120,
46 133,
47 150,
48 170,
49 200,
50 240,
51 300,
52 400,
53 500,
54 600,
55 700,
56 800,
57 900,
58 1000,
35 ] 59 ]
36 ZoomLevelDefault = 100 60 ZoomLevelDefault = 100
37 61
38 def __init__(self, scene, parent=None): 62 def __init__(self, scene, parent=None):
39 """ 63 """
40 Constructor 64 Constructor
41 65
42 @param scene reference to the scene object (QGraphicsScene) 66 @param scene reference to the scene object (QGraphicsScene)
43 @param parent parent widget (QWidget) 67 @param parent parent widget (QWidget)
44 """ 68 """
45 super().__init__(scene, parent) 69 super().__init__(scene, parent)
46 self.setObjectName("EricGraphicsView") 70 self.setObjectName("EricGraphicsView")
47 71
48 self.__initialSceneSize = self.scene().sceneRect().size() 72 self.__initialSceneSize = self.scene().sceneRect().size()
49 self.setBackgroundBrush(QBrush(self.getBackgroundColor())) 73 self.setBackgroundBrush(QBrush(self.getBackgroundColor()))
50 self.setRenderHint(QPainter.RenderHint.Antialiasing, True) 74 self.setRenderHint(QPainter.RenderHint.Antialiasing, True)
51 self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) 75 self.setDragMode(QGraphicsView.DragMode.RubberBandDrag)
52 self.setAlignment( 76 self.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
53 Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
54 self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) 77 self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
55 self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) 78 self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
56 self.setViewportUpdateMode( 79 self.setViewportUpdateMode(QGraphicsView.ViewportUpdateMode.SmartViewportUpdate)
57 QGraphicsView.ViewportUpdateMode.SmartViewportUpdate) 80
58 81 self.setWhatsThis(
59 self.setWhatsThis(self.tr( 82 self.tr(
60 "<b>Graphics View</b>\n" 83 "<b>Graphics View</b>\n"
61 "<p>This graphics view is used to show a diagram. \n" 84 "<p>This graphics view is used to show a diagram. \n"
62 "There are various actions available to manipulate the \n" 85 "There are various actions available to manipulate the \n"
63 "shown items.</p>\n" 86 "shown items.</p>\n"
64 "<ul>\n" 87 "<ul>\n"
65 "<li>Clicking on an item selects it.</li>\n" 88 "<li>Clicking on an item selects it.</li>\n"
66 "<li>Ctrl-clicking adds an item to the selection.</li>\n" 89 "<li>Ctrl-clicking adds an item to the selection.</li>\n"
67 "<li>Ctrl-clicking a selected item deselects it.</li>\n" 90 "<li>Ctrl-clicking a selected item deselects it.</li>\n"
68 "<li>Clicking on an empty spot of the canvas resets the selection." 91 "<li>Clicking on an empty spot of the canvas resets the selection."
69 "</li>\n" 92 "</li>\n"
70 "<li>Dragging the mouse over the canvas spans a rubberband to \n" 93 "<li>Dragging the mouse over the canvas spans a rubberband to \n"
71 "select multiple items.</li>\n" 94 "select multiple items.</li>\n"
72 "<li>Dragging the mouse over a selected item moves the \n" 95 "<li>Dragging the mouse over a selected item moves the \n"
73 "whole selection.</li>\n" 96 "whole selection.</li>\n"
74 "</ul>\n" 97 "</ul>\n"
75 )) 98 )
76 99 )
100
77 def getDrawingColors(self): 101 def getDrawingColors(self):
78 """ 102 """
79 Public method to get the configured drawing colors. 103 Public method to get the configured drawing colors.
80 104
81 @return tuple containing the foreground and background colors 105 @return tuple containing the foreground and background colors
82 @rtype tuple of (QColor, QColor) 106 @rtype tuple of (QColor, QColor)
83 """ 107 """
84 drawingMode = Preferences.getGraphics("DrawingMode") 108 drawingMode = Preferences.getGraphics("DrawingMode")
85 if drawingMode == "automatic": 109 if drawingMode == "automatic":
86 if ericApp().usesDarkPalette(): 110 if ericApp().usesDarkPalette():
87 drawingMode = "white_black" 111 drawingMode = "white_black"
88 else: 112 else:
89 drawingMode = "black_white" 113 drawingMode = "black_white"
90 114
91 if drawingMode == "white_black": 115 if drawingMode == "white_black":
92 return (QColor("#ffffff"), QColor("#262626")) 116 return (QColor("#ffffff"), QColor("#262626"))
93 else: 117 else:
94 return (QColor("#000000"), QColor("#ffffff")) 118 return (QColor("#000000"), QColor("#ffffff"))
95 119
96 def getForegroundColor(self): 120 def getForegroundColor(self):
97 """ 121 """
98 Public method to get the configured foreground color. 122 Public method to get the configured foreground color.
99 123
100 @return foreground color 124 @return foreground color
101 @rtype QColor 125 @rtype QColor
102 """ 126 """
103 return self.getDrawingColors()[0] 127 return self.getDrawingColors()[0]
104 128
105 def getBackgroundColor(self): 129 def getBackgroundColor(self):
106 """ 130 """
107 Public method to get the configured background color. 131 Public method to get the configured background color.
108 132
109 @return background color 133 @return background color
110 @rtype QColor 134 @rtype QColor
111 """ 135 """
112 return self.getDrawingColors()[1] 136 return self.getDrawingColors()[1]
113 137
114 def __levelForZoom(self, zoom): 138 def __levelForZoom(self, zoom):
115 """ 139 """
116 Private method determining the zoom level index given a zoom factor. 140 Private method determining the zoom level index given a zoom factor.
117 141
118 @param zoom zoom factor (integer) 142 @param zoom zoom factor (integer)
119 @return index of zoom factor (integer) 143 @return index of zoom factor (integer)
120 """ 144 """
121 try: 145 try:
122 index = EricGraphicsView.ZoomLevels.index(zoom) 146 index = EricGraphicsView.ZoomLevels.index(zoom)
123 except ValueError: 147 except ValueError:
124 for index in range(len(EricGraphicsView.ZoomLevels)): 148 for index in range(len(EricGraphicsView.ZoomLevels)):
125 if zoom <= EricGraphicsView.ZoomLevels[index]: 149 if zoom <= EricGraphicsView.ZoomLevels[index]:
126 break 150 break
127 return index 151 return index
128 152
129 def zoomIn(self): 153 def zoomIn(self):
130 """ 154 """
131 Public method to zoom in. 155 Public method to zoom in.
132 """ 156 """
133 index = self.__levelForZoom(self.zoom()) 157 index = self.__levelForZoom(self.zoom())
134 if index < len(EricGraphicsView.ZoomLevels) - 1: 158 if index < len(EricGraphicsView.ZoomLevels) - 1:
135 self.setZoom(EricGraphicsView.ZoomLevels[index + 1]) 159 self.setZoom(EricGraphicsView.ZoomLevels[index + 1])
136 160
137 def zoomOut(self): 161 def zoomOut(self):
138 """ 162 """
139 Public method to zoom out. 163 Public method to zoom out.
140 """ 164 """
141 index = self.__levelForZoom(self.zoom()) 165 index = self.__levelForZoom(self.zoom())
142 if index > 0: 166 if index > 0:
143 self.setZoom(EricGraphicsView.ZoomLevels[index - 1]) 167 self.setZoom(EricGraphicsView.ZoomLevels[index - 1])
144 168
145 def zoomReset(self): 169 def zoomReset(self):
146 """ 170 """
147 Public method to handle the reset the zoom value. 171 Public method to handle the reset the zoom value.
148 """ 172 """
149 self.setZoom( 173 self.setZoom(EricGraphicsView.ZoomLevels[EricGraphicsView.ZoomLevelDefault])
150 EricGraphicsView.ZoomLevels[EricGraphicsView.ZoomLevelDefault]) 174
151
152 def setZoom(self, value): 175 def setZoom(self, value):
153 """ 176 """
154 Public method to set the zoom value in percent. 177 Public method to set the zoom value in percent.
155 178
156 @param value zoom value in percent (integer) 179 @param value zoom value in percent (integer)
157 """ 180 """
158 if value != self.zoom(): 181 if value != self.zoom():
159 self.resetTransform() 182 self.resetTransform()
160 factor = value / 100.0 183 factor = value / 100.0
161 self.scale(factor, factor) 184 self.scale(factor, factor)
162 self.zoomValueChanged.emit(value) 185 self.zoomValueChanged.emit(value)
163 186
164 def zoom(self): 187 def zoom(self):
165 """ 188 """
166 Public method to get the current zoom factor in percent. 189 Public method to get the current zoom factor in percent.
167 190
168 @return current zoom factor in percent (integer) 191 @return current zoom factor in percent (integer)
169 """ 192 """
170 return int(self.transform().m11() * 100.0) 193 return int(self.transform().m11() * 100.0)
171 194
172 def resizeScene(self, amount, isWidth=True): 195 def resizeScene(self, amount, isWidth=True):
173 """ 196 """
174 Public method to resize the scene. 197 Public method to resize the scene.
175 198
176 @param amount size increment (integer) 199 @param amount size increment (integer)
177 @param isWidth flag indicating width is to be resized (boolean) 200 @param isWidth flag indicating width is to be resized (boolean)
178 """ 201 """
179 sceneRect = self.scene().sceneRect() 202 sceneRect = self.scene().sceneRect()
180 width = sceneRect.width() 203 width = sceneRect.width()
186 rect = self._getDiagramRect(10) 209 rect = self._getDiagramRect(10)
187 if width < rect.width(): 210 if width < rect.width():
188 width = rect.width() 211 width = rect.width()
189 if height < rect.height(): 212 if height < rect.height():
190 height = rect.height() 213 height = rect.height()
191 214
192 self.setSceneSize(width, height) 215 self.setSceneSize(width, height)
193 216
194 def setSceneSize(self, width, height): 217 def setSceneSize(self, width, height):
195 """ 218 """
196 Public method to set the scene size. 219 Public method to set the scene size.
197 220
198 @param width width for the scene (real) 221 @param width width for the scene (real)
199 @param height height for the scene (real) 222 @param height height for the scene (real)
200 """ 223 """
201 rect = self.scene().sceneRect() 224 rect = self.scene().sceneRect()
202 rect.setHeight(height) 225 rect.setHeight(height)
203 rect.setWidth(width) 226 rect.setWidth(width)
204 self.scene().setSceneRect(rect) 227 self.scene().setSceneRect(rect)
205 228
206 def autoAdjustSceneSize(self, limit=False): 229 def autoAdjustSceneSize(self, limit=False):
207 """ 230 """
208 Public method to adjust the scene size to the diagram size. 231 Public method to adjust the scene size to the diagram size.
209 232
210 @param limit flag indicating to limit the scene to the 233 @param limit flag indicating to limit the scene to the
211 initial size (boolean) 234 initial size (boolean)
212 """ 235 """
213 size = self._getDiagramSize(10) 236 size = self._getDiagramSize(10)
214 if limit: 237 if limit:
216 newHeight = max(size.height(), self.__initialSceneSize.height()) 239 newHeight = max(size.height(), self.__initialSceneSize.height())
217 else: 240 else:
218 newWidth = size.width() 241 newWidth = size.width()
219 newHeight = size.height() 242 newHeight = size.height()
220 self.setSceneSize(newWidth, newHeight) 243 self.setSceneSize(newWidth, newHeight)
221 244
222 def _getDiagramRect(self, border=0): 245 def _getDiagramRect(self, border=0):
223 """ 246 """
224 Protected method to calculate the minimum rectangle fitting the 247 Protected method to calculate the minimum rectangle fitting the
225 diagram. 248 diagram.
226 249
227 @param border border width to include in the calculation (integer) 250 @param border border width to include in the calculation (integer)
228 @return the minimum rectangle (QRectF) 251 @return the minimum rectangle (QRectF)
229 """ 252 """
230 startx = sys.maxsize 253 startx = sys.maxsize
231 starty = sys.maxsize 254 starty = sys.maxsize
249 if border: 272 if border:
250 startx -= border 273 startx -= border
251 starty -= border 274 starty -= border
252 endx += border 275 endx += border
253 endy += border 276 endy += border
254 277
255 return QRectF(startx, starty, endx - startx + 1, endy - starty + 1) 278 return QRectF(startx, starty, endx - startx + 1, endy - starty + 1)
256 279
257 def _getDiagramSize(self, border=0): 280 def _getDiagramSize(self, border=0):
258 """ 281 """
259 Protected method to calculate the minimum size fitting the diagram. 282 Protected method to calculate the minimum size fitting the diagram.
260 283
261 @param border border width to include in the calculation (integer) 284 @param border border width to include in the calculation (integer)
262 @return the minimum size (QSizeF) 285 @return the minimum size (QSizeF)
263 """ 286 """
264 endx = 0 287 endx = 0
265 endy = 0 288 endy = 0
273 if endy <= itmEndY: 296 if endy <= itmEndY:
274 endy = itmEndY 297 endy = itmEndY
275 if border: 298 if border:
276 endx += border 299 endx += border
277 endy += border 300 endy += border
278 301
279 return QSizeF(endx + 1, endy + 1) 302 return QSizeF(endx + 1, endy + 1)
280 303
281 def __getDiagram(self, rect, imageFormat="PNG", filename=None): 304 def __getDiagram(self, rect, imageFormat="PNG", filename=None):
282 """ 305 """
283 Private method to retrieve the diagram from the scene fitting it 306 Private method to retrieve the diagram from the scene fitting it
284 in the minimum rectangle. 307 in the minimum rectangle.
285 308
286 @param rect minimum rectangle fitting the diagram 309 @param rect minimum rectangle fitting the diagram
287 @type QRectF 310 @type QRectF
288 @param imageFormat format for the image file 311 @param imageFormat format for the image file
289 @type str 312 @type str
290 @param filename name of the file for non pixmaps 313 @param filename name of the file for non pixmaps
291 str 314 str
292 @return paint device containing the diagram 315 @return paint device containing the diagram
293 @rtype QPixmap or QSvgGenerator 316 @rtype QPixmap or QSvgGenerator
294 """ 317 """
295 selectedItems = self.scene().selectedItems() 318 selectedItems = self.scene().selectedItems()
296 319
297 # step 1: deselect all widgets 320 # step 1: deselect all widgets
298 if selectedItems: 321 if selectedItems:
299 for item in selectedItems: 322 for item in selectedItems:
300 item.setSelected(False) 323 item.setSelected(False)
301 324
302 # step 2: grab the diagram 325 # step 2: grab the diagram
303 if imageFormat == "PNG": 326 if imageFormat == "PNG":
304 paintDevice = QPixmap(int(rect.width()), int(rect.height())) 327 paintDevice = QPixmap(int(rect.width()), int(rect.height()))
305 paintDevice.fill(self.backgroundBrush().color()) 328 paintDevice.fill(self.backgroundBrush().color())
306 else: 329 else:
307 from PyQt6.QtSvg import QSvgGenerator 330 from PyQt6.QtSvg import QSvgGenerator
331
308 paintDevice = QSvgGenerator() 332 paintDevice = QSvgGenerator()
309 paintDevice.setResolution(100) # 100 dpi 333 paintDevice.setResolution(100) # 100 dpi
310 paintDevice.setSize(QSize(int(rect.width()), int(rect.height()))) 334 paintDevice.setSize(QSize(int(rect.width()), int(rect.height())))
311 paintDevice.setViewBox(rect) 335 paintDevice.setViewBox(rect)
312 paintDevice.setFileName(filename) 336 paintDevice.setFileName(filename)
313 painter = QPainter(paintDevice) 337 painter = QPainter(paintDevice)
314 painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) 338 painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
315 self.scene().render(painter, QRectF(), rect) 339 self.scene().render(painter, QRectF(), rect)
316 340
317 # step 3: reselect the widgets 341 # step 3: reselect the widgets
318 if selectedItems: 342 if selectedItems:
319 for item in selectedItems: 343 for item in selectedItems:
320 item.setSelected(True) 344 item.setSelected(True)
321 345
322 return paintDevice 346 return paintDevice
323 347
324 def saveImage(self, filename, imageFormat="PNG"): 348 def saveImage(self, filename, imageFormat="PNG"):
325 """ 349 """
326 Public method to save the scene to a file. 350 Public method to save the scene to a file.
327 351
328 @param filename name of the file to write the image to (string) 352 @param filename name of the file to write the image to (string)
329 @param imageFormat format for the image file (string) 353 @param imageFormat format for the image file (string)
330 @return flag indicating success (boolean) 354 @return flag indicating success (boolean)
331 """ 355 """
332 rect = self._getDiagramRect(self.border) 356 rect = self._getDiagramRect(self.border)
334 self.__getDiagram(rect, imageFormat=imageFormat, filename=filename) 358 self.__getDiagram(rect, imageFormat=imageFormat, filename=filename)
335 return True 359 return True
336 else: 360 else:
337 pixmap = self.__getDiagram(rect) 361 pixmap = self.__getDiagram(rect)
338 return pixmap.save(filename, imageFormat) 362 return pixmap.save(filename, imageFormat)
339 363
340 def printDiagram(self, printer, diagramName=""): 364 def printDiagram(self, printer, diagramName=""):
341 """ 365 """
342 Public method to print the diagram. 366 Public method to print the diagram.
343 367
344 @param printer reference to a ready configured printer object 368 @param printer reference to a ready configured printer object
345 (QPrinter) 369 (QPrinter)
346 @param diagramName name of the diagram (string) 370 @param diagramName name of the diagram (string)
347 """ 371 """
348 painter = QPainter(printer) 372 painter = QPainter(printer)
349 373
350 font = QFont(["times"], 10) 374 font = QFont(["times"], 10)
351 painter.setFont(font) 375 painter.setFont(font)
352 fm = painter.fontMetrics() 376 fm = painter.fontMetrics()
353 fontHeight = fm.lineSpacing() 377 fontHeight = fm.lineSpacing()
354 marginX = ( 378 marginX = (
355 printer.pageLayout().paintRectPixels(printer.resolution()).x() - 379 printer.pageLayout().paintRectPixels(printer.resolution()).x()
356 printer.pageLayout().fullRectPixels(printer.resolution()).x() 380 - printer.pageLayout().fullRectPixels(printer.resolution()).x()
357 ) 381 )
358 marginX = ( 382 marginX = (
359 Preferences.getPrinter("LeftMargin") * 383 Preferences.getPrinter("LeftMargin") * int(printer.resolution() / 2.54)
360 int(printer.resolution() / 2.54) - marginX 384 - marginX
361 ) 385 )
362 marginY = ( 386 marginY = (
363 printer.pageLayout().paintRectPixels(printer.resolution()).y() - 387 printer.pageLayout().paintRectPixels(printer.resolution()).y()
364 printer.pageLayout().fullRectPixels(printer.resolution()).y() 388 - printer.pageLayout().fullRectPixels(printer.resolution()).y()
365 ) 389 )
366 marginY = ( 390 marginY = (
367 Preferences.getPrinter("TopMargin") * 391 Preferences.getPrinter("TopMargin") * int(printer.resolution() / 2.54)
368 int(printer.resolution() / 2.54) - marginY 392 - marginY
369 ) 393 )
370 394
371 width = ( 395 width = (
372 printer.width() - marginX - 396 printer.width()
373 Preferences.getPrinter("RightMargin") * 397 - marginX
374 int(printer.resolution() / 2.54) 398 - Preferences.getPrinter("RightMargin") * int(printer.resolution() / 2.54)
375 ) 399 )
376 height = ( 400 height = (
377 printer.height() - fontHeight - 4 - marginY - 401 printer.height()
378 Preferences.getPrinter("BottomMargin") * 402 - fontHeight
379 int(printer.resolution() / 2.54) 403 - 4
380 ) 404 - marginY
381 405 - Preferences.getPrinter("BottomMargin") * int(printer.resolution() / 2.54)
382 self.scene().render(painter, 406 )
383 target=QRectF(marginX, marginY, width, height)) 407
384 408 self.scene().render(painter, target=QRectF(marginX, marginY, width, height))
409
385 # write a foot note 410 # write a foot note
386 tc = QColor(50, 50, 50) 411 tc = QColor(50, 50, 50)
387 painter.setPen(tc) 412 painter.setPen(tc)
388 painter.drawRect(marginX, marginY, width, height) 413 painter.drawRect(marginX, marginY, width, height)
389 painter.drawLine(marginX, marginY + height + 2, 414 painter.drawLine(
390 marginX + width, marginY + height + 2) 415 marginX, marginY + height + 2, marginX + width, marginY + height + 2
416 )
391 painter.setFont(font) 417 painter.setFont(font)
392 painter.drawText(marginX, marginY + height + 4, width, 418 painter.drawText(
393 fontHeight, Qt.AlignmentFlag.AlignRight, diagramName) 419 marginX,
394 420 marginY + height + 4,
421 width,
422 fontHeight,
423 Qt.AlignmentFlag.AlignRight,
424 diagramName,
425 )
426
395 painter.end() 427 painter.end()
396 428
397 ########################################################################### 429 ###########################################################################
398 ## The methods below should be overridden by subclasses to get special 430 ## The methods below should be overridden by subclasses to get special
399 ## behavior. 431 ## behavior.
400 ########################################################################### 432 ###########################################################################
401 433
402 def filteredItems(self, items): 434 def filteredItems(self, items):
403 """ 435 """
404 Public method to filter a list of items. 436 Public method to filter a list of items.
405 437
406 @param items list of items as returned by the scene object 438 @param items list of items as returned by the scene object
407 (QGraphicsItem) 439 (QGraphicsItem)
408 @return list of interesting collision items (QGraphicsItem) 440 @return list of interesting collision items (QGraphicsItem)
409 """ 441 """
410 # just return the list unchanged 442 # just return the list unchanged

eric ide

mercurial