Skip to content

graphicsview

DragEventType

Bases: IntEnum

move class-attribute instance-attribute

move = auto()

repaint class-attribute instance-attribute

repaint = auto()

start class-attribute instance-attribute

start = auto()

stop class-attribute instance-attribute

stop = auto()

GraphicsImageItem

GraphicsImageItem(graphics_item: QGraphicsPixmapItem)
Source code
38
39
40
def __init__(self, graphics_item: QGraphicsPixmapItem) -> None:
    self._graphics_item = graphics_item
    self._pixmap = self._graphics_item.pixmap()

contains

contains(point: QPointF) -> bool
Source code
42
43
def contains(self, point: QPointF) -> bool:
    return self._graphics_item.contains(point)

hide

hide() -> None
Source code
45
46
def hide(self) -> None:
    self._graphics_item.hide()

pixmap

pixmap() -> QPixmap
Source code
48
49
def pixmap(self) -> QPixmap:
    return self._graphics_item.pixmap()

setPixmap

setPixmap(
    new_pixmap: QPixmap | None,
    crop_values: CroppingInfo | None = None,
    ar_values: ArInfo | None = None,
) -> None
Source code
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def setPixmap(
    self, new_pixmap: QPixmap | None,
    crop_values: CroppingInfo | None = None,
    ar_values: ArInfo | None = None
) -> None:

    sizes = (self._pixmap.width(), self._pixmap.height())

    if new_pixmap is None:
        new_pixmap = self._pixmap
    else:
        self._pixmap = new_pixmap

    if ar_values is not None and ar_values.active:
        new_pixmap = self._set_ar(new_pixmap, ar_values)

    if crop_values is not None and crop_values.active:
        new_pixmap = self._set_crop(new_pixmap, crop_values)

    self._graphics_item.setPixmap(new_pixmap)

    if sizes != (new_pixmap.width(), new_pixmap.height()):
        from ...core import main_window

        main_window().refresh_graphics_views()

show

show() -> None
Source code
77
78
def show(self) -> None:
    self._graphics_item.show()

GraphicsScene

GraphicsScene(view: GraphicsView)

Bases: QGraphicsScene

Source code
128
129
130
131
132
133
134
def __init__(self, view: GraphicsView) -> None:
    self.view = view
    self.main = self.view.main

    self.graphics_items = list[GraphicsImageItem]()

    super().__init__(self.main)

current_scene property

current_scene: GraphicsImageItem

graphics_items instance-attribute

graphics_items = list[GraphicsImageItem]()

main instance-attribute

main = main

view instance-attribute

view = view

init_scenes

init_scenes() -> None
Source code
136
137
138
139
140
141
142
143
144
def init_scenes(self) -> None:
    self.clear()
    self.graphics_items.clear()

    for _ in range(len(self.main.outputs)):
        raw_frame_item = self.addPixmap(QPixmap())
        raw_frame_item.hide()

        self.graphics_items.append(GraphicsImageItem(raw_frame_item))

GraphicsView

GraphicsView(main: MainWindow, parent: QWidget | None = None)

Bases: QGraphicsView

Source code
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def __init__(self, main: MainWindow, parent: QWidget | None = None) -> None:
    from ...core import CheckBox, HBoxLayout
    from .combobox import ComboBox

    super().__init__(parent)

    self.main = main

    self.app = QApplication.instance()
    self.angleRemainder = 0
    self.zoomValue = 0.0
    self.currentZoom = 0.0
    self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
    self.drag_mode = self.dragMode()

    self.main.reload_stylesheet_signal.connect(
        lambda: self.setBackgroundBrush(self.main.palette().brush(QPalette.ColorRole.Window))
    )

    self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
    self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)

    if self.main.settings.opengl_rendering_enabled:
        from PyQt6.QtOpenGLWidgets import QOpenGLWidget
        self.setViewport(QOpenGLWidget())

    self.wheelScrolled.connect(self.on_wheel_scrolled)
    self.main.reload_before_signal.connect(self.beforeReload)
    self.main.reload_after_signal.connect(self.afterReload)

    self.graphics_scene = GraphicsScene(self)
    self.setScene(self.graphics_scene)

    self.zoom_combobox = ComboBox[float](self, minimumContentsLength=4)

    self.auto_fit_button = CheckBox('Auto-fit', self, clicked=self.auto_fit_button_clicked)

    self.controls = QFrame()
    HBoxLayout(self.controls, [self.zoom_combobox, self.auto_fit_button])

    self.main.register_graphic_view(self)

    self.dragEvent.connect(self.propagate_move_event)

WHEEL_STEP class-attribute instance-attribute

WHEEL_STEP = 15 * 8

angleRemainder instance-attribute

angleRemainder = 0

app instance-attribute

app = instance()

auto_fit_button instance-attribute

auto_fit_button = CheckBox('Auto-fit', self, clicked=auto_fit_button_clicked)

autofit property writable

autofit: bool

content_height property

content_height: int

content_width property

content_width: int

controls instance-attribute

controls = QFrame()

currentZoom instance-attribute

currentZoom = 0.0

current_scene property

current_scene: GraphicsImageItem

dragEvent class-attribute instance-attribute

dragEvent = pyqtSignal(DragEventType)

drag_mode instance-attribute

drag_mode: DragMode = dragMode()

graphics_scene instance-attribute

graphics_scene = GraphicsScene(self)

last_positions class-attribute instance-attribute

last_positions = (0, 0)

main instance-attribute

main: MainWindow = main

mouseMoved class-attribute instance-attribute

mouseMoved = pyqtSignal(QMouseEvent)

mousePressed class-attribute instance-attribute

mousePressed = pyqtSignal(QMouseEvent)

mouseReleased class-attribute instance-attribute

mouseReleased = pyqtSignal(QMouseEvent)

underReload class-attribute instance-attribute

underReload = False

wheelScrolled class-attribute instance-attribute

wheelScrolled = pyqtSignal(int)

zoomValue instance-attribute

zoomValue = 0.0

zoom_combobox instance-attribute

zoom_combobox = ComboBox[float](self, minimumContentsLength=4)

afterReload

afterReload() -> None
Source code
367
368
369
370
371
def afterReload(self) -> None:
    self.underReload = False
    self.verticalScrollBar().setValue(self.last_positions[0])
    self.horizontalScrollBar().setValue(self.last_positions[1])
    self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)

auto_fit_button_clicked

auto_fit_button_clicked(checked: bool) -> None
Source code
213
214
def auto_fit_button_clicked(self, checked: bool) -> None:
    self.autofit = checked

beforeReload

beforeReload() -> None
Source code
362
363
364
365
def beforeReload(self) -> None:
    self.underReload = True
    self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorViewCenter)
    self.last_positions = (self.verticalScrollBar().value(), self.horizontalScrollBar().value())

bind_to

bind_to(other_view: GraphicsView, *, mutual: bool = True) -> None
Source code
242
243
244
245
246
def bind_to(self, other_view: GraphicsView, *, mutual: bool = True) -> None:
    self.main.bound_graphics_views[other_view].add(self)

    if mutual:
        self.main.bound_graphics_views[self].add(other_view)

event

event(event: QEvent) -> bool
Source code
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def event(self, event: QEvent) -> bool:
    if self.underReload:
        event.ignore()
        return False

    if isinstance(event, QNativeGestureEvent):
        typ = event.gestureType()
        if typ == Qt.NativeGestureType.BeginNativeGesture:
            self.zoomValue = 0.0
        elif typ == Qt.NativeGestureType.ZoomNativeGesture:
            self.zoomValue += event.value()
        if typ == Qt.NativeGestureType.EndNativeGesture:
            self.wheelScrolled.emit(-1 if self.zoomValue < 0 else 1)

    return super().event(event)

mouseMoveEvent

mouseMoveEvent(event: QMouseEvent) -> None
Source code
326
327
328
329
330
331
332
333
334
335
def mouseMoveEvent(self, event: QMouseEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    super().mouseMoveEvent(event)

    if self.hasMouseTracking():
        self.mouseMoved.emit(event)

    self.dragEvent.emit(DragEventType.move)

mousePressEvent

mousePressEvent(event: QMouseEvent) -> None
Source code
337
338
339
340
341
342
343
344
345
346
347
348
def mousePressEvent(self, event: QMouseEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    if event.button() == Qt.MouseButton.LeftButton:
        self.drag_mode = self.dragMode()
        self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)

    super().mousePressEvent(event)

    self.mousePressed.emit(event)
    self.dragEvent.emit(DragEventType.start)

mouseReleaseEvent

mouseReleaseEvent(event: QMouseEvent) -> None
Source code
350
351
352
353
354
355
356
357
358
359
360
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    super().mouseReleaseEvent(event)

    if event.button() == Qt.MouseButton.LeftButton:
        self.setDragMode(self.drag_mode)

    self.mouseReleased.emit(event)
    self.dragEvent.emit(DragEventType.stop)

on_wheel_scrolled

on_wheel_scrolled(steps: int) -> None
Source code
248
249
250
251
def on_wheel_scrolled(self, steps: int) -> None:
    self.zoom_combobox.setCurrentIndex(
        clamp(self.zoom_combobox.currentIndex() + steps, 0, len(self.zoom_combobox) - 1)
    )

propagate_move_event

propagate_move_event(_: Any = None) -> None
Source code
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
def propagate_move_event(self, _: Any = None) -> None:
    scrollbarW, scrollbarH = self.horizontalScrollBar(), self.verticalScrollBar()

    if not any({scrollbarW.isVisible(), scrollbarH.isVisible()}):
        return

    widthMax, heightMax = scrollbarW.maximum(), scrollbarH.maximum()

    for view in self.main.bound_graphics_views[self] - {self}:
        if view.isVisible():
            wBar, hBar = view.horizontalScrollBar(), view.verticalScrollBar()

            if widthMax:
                wBar.setValue(int(scrollbarW.value() * wBar.maximum() / widthMax))

            if heightMax:
                hBar.setValue(int(scrollbarH.value() * hBar.maximum() / heightMax))

resizeEvent

resizeEvent(event: QResizeEvent) -> None
Source code
373
374
375
def resizeEvent(self, event: QResizeEvent) -> None:
    super().resizeEvent(event)
    self.setZoom(None)

setZoom

setZoom(value: float | None) -> None
Source code
253
254
255
def setZoom(self, value: float | None) -> None:
    for view in self.main.bound_graphics_views[self]:
        view._setZoom(value)

setup_view

setup_view() -> None
Source code
235
236
237
238
239
240
def setup_view(self) -> None:
    for item in self.graphics_scene.graphics_items:
        item.hide()

    self.current_scene.show()
    self.graphics_scene.setSceneRect(QRectF(self.current_scene.pixmap().rect()))

wheelEvent

wheelEvent(event: QWheelEvent) -> None
Source code
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def wheelEvent(self, event: QWheelEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    assert self.app

    modifier = event.modifiers()
    mouse = event.buttons()

    self.propagate_move_event()

    if modifier == Qt.KeyboardModifier.ControlModifier or mouse in {
        Qt.MouseButton.RightButton, Qt.MouseButton.MiddleButton
    }:
        angleDelta = event.angleDelta().y()

        # check if wheel wasn't rotated the other way since last rotation
        if self.angleRemainder * angleDelta < 0:
            self.angleRemainder = 0

        self.angleRemainder += angleDelta

        if abs(self.angleRemainder) >= self.WHEEL_STEP:
            self.wheelScrolled.emit(self.angleRemainder // self.WHEEL_STEP)
            self.angleRemainder %= self.WHEEL_STEP
        return
    elif modifier == Qt.KeyboardModifier.NoModifier:
        self.verticalScrollBar().setValue(self.verticalScrollBar().value() - event.angleDelta().y())
        self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - event.angleDelta().x())
        return
    elif modifier == Qt.KeyboardModifier.ShiftModifier:
        self.verticalScrollBar().setValue(self.verticalScrollBar().value() - event.angleDelta().x())
        self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - event.angleDelta().y())
        return

    event.ignore()

MainVideoOutputGraphicsView

MainVideoOutputGraphicsView(main: MainWindow, parent: QWidget | None = None)

Bases: GraphicsView

Source code
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def __init__(self, main: MainWindow, parent: QWidget | None = None) -> None:
    from ...core import CheckBox, HBoxLayout
    from .combobox import ComboBox

    super().__init__(parent)

    self.main = main

    self.app = QApplication.instance()
    self.angleRemainder = 0
    self.zoomValue = 0.0
    self.currentZoom = 0.0
    self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
    self.drag_mode = self.dragMode()

    self.main.reload_stylesheet_signal.connect(
        lambda: self.setBackgroundBrush(self.main.palette().brush(QPalette.ColorRole.Window))
    )

    self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
    self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)

    if self.main.settings.opengl_rendering_enabled:
        from PyQt6.QtOpenGLWidgets import QOpenGLWidget
        self.setViewport(QOpenGLWidget())

    self.wheelScrolled.connect(self.on_wheel_scrolled)
    self.main.reload_before_signal.connect(self.beforeReload)
    self.main.reload_after_signal.connect(self.afterReload)

    self.graphics_scene = GraphicsScene(self)
    self.setScene(self.graphics_scene)

    self.zoom_combobox = ComboBox[float](self, minimumContentsLength=4)

    self.auto_fit_button = CheckBox('Auto-fit', self, clicked=self.auto_fit_button_clicked)

    self.controls = QFrame()
    HBoxLayout(self.controls, [self.zoom_combobox, self.auto_fit_button])

    self.main.register_graphic_view(self)

    self.dragEvent.connect(self.propagate_move_event)

WHEEL_STEP class-attribute instance-attribute

WHEEL_STEP = 15 * 8

angleRemainder instance-attribute

angleRemainder = 0

app instance-attribute

app = instance()

auto_fit_button instance-attribute

auto_fit_button = CheckBox('Auto-fit', self, clicked=auto_fit_button_clicked)

autofit property writable

autofit: bool

content_height property

content_height: int

content_width property

content_width: int

controls instance-attribute

controls = QFrame()

currentZoom instance-attribute

currentZoom = 0.0

current_scene property

current_scene: GraphicsImageItem

dragEvent class-attribute instance-attribute

dragEvent = pyqtSignal(DragEventType)

drag_mode instance-attribute

drag_mode: DragMode = dragMode()

graphics_scene instance-attribute

graphics_scene = GraphicsScene(self)

last_positions class-attribute instance-attribute

last_positions = (0, 0)

main instance-attribute

main: MainWindow = main

mouseMoved class-attribute instance-attribute

mouseMoved = pyqtSignal(QMouseEvent)

mousePressed class-attribute instance-attribute

mousePressed = pyqtSignal(QMouseEvent)

mouseReleased class-attribute instance-attribute

mouseReleased = pyqtSignal(QMouseEvent)

underReload class-attribute instance-attribute

underReload = False

wheelScrolled class-attribute instance-attribute

wheelScrolled = pyqtSignal(int)

zoomValue instance-attribute

zoomValue = 0.0

zoom_combobox instance-attribute

zoom_combobox = ComboBox[float](self, minimumContentsLength=4)

afterReload

afterReload() -> None
Source code
367
368
369
370
371
def afterReload(self) -> None:
    self.underReload = False
    self.verticalScrollBar().setValue(self.last_positions[0])
    self.horizontalScrollBar().setValue(self.last_positions[1])
    self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)

auto_fit_button_clicked

auto_fit_button_clicked(checked: bool) -> None
Source code
213
214
def auto_fit_button_clicked(self, checked: bool) -> None:
    self.autofit = checked

beforeReload

beforeReload() -> None
Source code
362
363
364
365
def beforeReload(self) -> None:
    self.underReload = True
    self.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorViewCenter)
    self.last_positions = (self.verticalScrollBar().value(), self.horizontalScrollBar().value())

bind_to

bind_to(other_view: GraphicsView, *, mutual: bool = True) -> None
Source code
242
243
244
245
246
def bind_to(self, other_view: GraphicsView, *, mutual: bool = True) -> None:
    self.main.bound_graphics_views[other_view].add(self)

    if mutual:
        self.main.bound_graphics_views[self].add(other_view)

event

event(event: QEvent) -> bool
Source code
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def event(self, event: QEvent) -> bool:
    if self.underReload:
        event.ignore()
        return False

    if isinstance(event, QNativeGestureEvent):
        typ = event.gestureType()
        if typ == Qt.NativeGestureType.BeginNativeGesture:
            self.zoomValue = 0.0
        elif typ == Qt.NativeGestureType.ZoomNativeGesture:
            self.zoomValue += event.value()
        if typ == Qt.NativeGestureType.EndNativeGesture:
            self.wheelScrolled.emit(-1 if self.zoomValue < 0 else 1)

    return super().event(event)

mouseMoveEvent

mouseMoveEvent(event: QMouseEvent) -> None
Source code
326
327
328
329
330
331
332
333
334
335
def mouseMoveEvent(self, event: QMouseEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    super().mouseMoveEvent(event)

    if self.hasMouseTracking():
        self.mouseMoved.emit(event)

    self.dragEvent.emit(DragEventType.move)

mousePressEvent

mousePressEvent(event: QMouseEvent) -> None
Source code
337
338
339
340
341
342
343
344
345
346
347
348
def mousePressEvent(self, event: QMouseEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    if event.button() == Qt.MouseButton.LeftButton:
        self.drag_mode = self.dragMode()
        self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)

    super().mousePressEvent(event)

    self.mousePressed.emit(event)
    self.dragEvent.emit(DragEventType.start)

mouseReleaseEvent

mouseReleaseEvent(event: QMouseEvent) -> None
Source code
350
351
352
353
354
355
356
357
358
359
360
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    super().mouseReleaseEvent(event)

    if event.button() == Qt.MouseButton.LeftButton:
        self.setDragMode(self.drag_mode)

    self.mouseReleased.emit(event)
    self.dragEvent.emit(DragEventType.stop)

on_wheel_scrolled

on_wheel_scrolled(steps: int) -> None
Source code
248
249
250
251
def on_wheel_scrolled(self, steps: int) -> None:
    self.zoom_combobox.setCurrentIndex(
        clamp(self.zoom_combobox.currentIndex() + steps, 0, len(self.zoom_combobox) - 1)
    )

propagate_move_event

propagate_move_event(_: Any = None) -> None
Source code
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
def propagate_move_event(self, _: Any = None) -> None:
    scrollbarW, scrollbarH = self.horizontalScrollBar(), self.verticalScrollBar()

    if not any({scrollbarW.isVisible(), scrollbarH.isVisible()}):
        return

    widthMax, heightMax = scrollbarW.maximum(), scrollbarH.maximum()

    for view in self.main.bound_graphics_views[self] - {self}:
        if view.isVisible():
            wBar, hBar = view.horizontalScrollBar(), view.verticalScrollBar()

            if widthMax:
                wBar.setValue(int(scrollbarW.value() * wBar.maximum() / widthMax))

            if heightMax:
                hBar.setValue(int(scrollbarH.value() * hBar.maximum() / heightMax))

resizeEvent

resizeEvent(event: QResizeEvent) -> None
Source code
373
374
375
def resizeEvent(self, event: QResizeEvent) -> None:
    super().resizeEvent(event)
    self.setZoom(None)

setZoom

setZoom(value: float | None) -> None
Source code
253
254
255
def setZoom(self, value: float | None) -> None:
    for view in self.main.bound_graphics_views[self]:
        view._setZoom(value)

setup_view

setup_view() -> None
Source code
235
236
237
238
239
240
def setup_view(self) -> None:
    for item in self.graphics_scene.graphics_items:
        item.hide()

    self.current_scene.show()
    self.graphics_scene.setSceneRect(QRectF(self.current_scene.pixmap().rect()))

wheelEvent

wheelEvent(event: QWheelEvent) -> None
Source code
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def wheelEvent(self, event: QWheelEvent) -> None:
    if self.underReload or self.autofit:
        return event.ignore()

    assert self.app

    modifier = event.modifiers()
    mouse = event.buttons()

    self.propagate_move_event()

    if modifier == Qt.KeyboardModifier.ControlModifier or mouse in {
        Qt.MouseButton.RightButton, Qt.MouseButton.MiddleButton
    }:
        angleDelta = event.angleDelta().y()

        # check if wheel wasn't rotated the other way since last rotation
        if self.angleRemainder * angleDelta < 0:
            self.angleRemainder = 0

        self.angleRemainder += angleDelta

        if abs(self.angleRemainder) >= self.WHEEL_STEP:
            self.wheelScrolled.emit(self.angleRemainder // self.WHEEL_STEP)
            self.angleRemainder %= self.WHEEL_STEP
        return
    elif modifier == Qt.KeyboardModifier.NoModifier:
        self.verticalScrollBar().setValue(self.verticalScrollBar().value() - event.angleDelta().y())
        self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - event.angleDelta().x())
        return
    elif modifier == Qt.KeyboardModifier.ShiftModifier:
        self.verticalScrollBar().setValue(self.verticalScrollBar().value() - event.angleDelta().x())
        self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - event.angleDelta().y())
        return

    event.ignore()