Пример #1
0
class DynamicView(QGraphicsView):
    viewChanged = Signal(QRect, float, int, int)

    def __init__(self, image, parent=None):
        super(DynamicView, self).__init__(parent)
        self.scene = QGraphicsScene()
        self.scene.setBackgroundBrush(Qt.darkGray)
        self.setScene(self.scene)
        self.set_image(image)
        self.setRenderHint(QPainter.SmoothPixmapTransform)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.ZOOM_STEP = 0.2
        self.mouse_pressed = False
        self.next_fit = False
        self.fit_scale = 0
        self.zoom_fit()

    def set_image(self, image):
        if type(image) is QPixmap:
            pixmap = image
        elif type(image) is QImage:
            pixmap = QPixmap.fromImage(image)
        elif type(image) is np.ndarray:
            pixmap = QPixmap.fromImage(mat2img(image))
        else:
            raise TypeError(
                self.tr('DynamicView.set_image: Unsupported type: {}'.format(
                    type(image))))
        if not self.scene.items():
            self.scene.addPixmap(pixmap)
        else:
            self.scene.items()[0].setPixmap(pixmap)
        self.scene.setSceneRect(QRectF(pixmap.rect()))

    def zoom_full(self):
        self.set_scaling(1)
        self.next_fit = True
        self.notify_change()

    def zoom_fit(self):
        self.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
        self.fit_scale = self.matrix().m11()
        if self.fit_scale > 1:
            self.fit_scale = 1
            self.zoom_full()
        else:
            self.next_fit = False
            self.notify_change()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mouse_pressed = True
        QGraphicsView.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        QGraphicsView.mouseMoveEvent(self, event)
        if self.mouse_pressed:
            self.notify_change()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mouse_pressed = False
        QGraphicsView.mouseReleaseEvent(self, event)

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            if self.next_fit:
                self.zoom_fit()
            else:
                self.zoom_full()
        QGraphicsView.mouseDoubleClickEvent(self, event)

    def wheelEvent(self, event):
        if event.delta() > 0:
            self.change_zoom(+1)
        else:
            self.change_zoom(-1)

    def resizeEvent(self, event):
        # FIXME: Se la finestra viene massimizzata, il valore di fit_scale non si aggiorna
        if self.matrix().m11() <= self.fit_scale:
            self.zoom_fit()
        else:
            self.notify_change()
        QGraphicsView.resizeEvent(self, event)

    def change_zoom(self, direction):
        level = math.log2(self.matrix().m11())
        if direction > 0:
            level += self.ZOOM_STEP
        else:
            level -= self.ZOOM_STEP
        scaling = 2**level
        if scaling < self.fit_scale:
            scaling = self.fit_scale
            self.next_fit = False
        elif scaling > 1:
            # scaling = 1
            if scaling > 4:
                scaling = 4
            self.next_fit = True
        self.set_scaling(scaling)
        self.notify_change()

    def set_scaling(self, scaling):
        matrix = QMatrix()
        matrix.scale(scaling, scaling)
        self.setMatrix(matrix)

    def change_view(self, _, new_scaling, new_horiz, new_vert):
        old_factor = self.matrix().m11()
        old_horiz = self.horizontalScrollBar().value()
        old_vert = self.verticalScrollBar().value()
        if new_scaling != old_factor or new_horiz != old_horiz or new_vert != old_vert:
            self.set_scaling(new_scaling)
            self.horizontalScrollBar().setValue(new_horiz)
            self.verticalScrollBar().setValue(new_vert)
            self.notify_change()

    def notify_change(self):
        scene_rect = self.get_rect()
        horiz_scroll = self.horizontalScrollBar().value()
        vert_scroll = self.verticalScrollBar().value()
        zoom_factor = self.matrix().m11()
        self.viewChanged.emit(scene_rect, zoom_factor, horiz_scroll,
                              vert_scroll)

    def get_rect(self):
        top_left = self.mapToScene(0, 0).toPoint()
        if top_left.x() < 0:
            top_left.setX(0)
        if top_left.y() < 0:
            top_left.setY(0)
        view_size = self.viewport().size()
        bottom_right = self.mapToScene(view_size.width(),
                                       view_size.height()).toPoint()
        image_size = self.sceneRect().toRect()
        if bottom_right.x() >= image_size.width():
            bottom_right.setX(image_size.width() - 1)
        if bottom_right.y() >= image_size.height():
            bottom_right.setY(image_size.height() - 1)
        return QRect(top_left, bottom_right)
Пример #2
0
    QGraphicsRectItem,
    QWidget,
    QGraphicsSimpleTextItem,
    QGraphicsEllipseItem,
    QGraphicsPolygonItem,
)
from PySide2.QtGui import (QPen, QBrush, QPolygonF)
from PySide2.QtCore import (Qt, QRectF, QPoint, QPointF)

import sys

if __name__ == '__main__':
    app = QApplication(sys.argv)
    scene = QGraphicsScene(QRectF(-50, -50, 400, 200))

    rect = QGraphicsRectItem(scene.sceneRect().adjusted(1, 1, -1, -1))
    rect.setPen(QPen(Qt.red, 1))
    scene.addItem(rect)

    rectItem = QGraphicsRectItem(QRectF(-25, 25, 200, 40))
    rectItem.setPen(QPen(Qt.red, 3, Qt.DashDotLine))
    rectItem.setBrush(Qt.gray)
    scene.addItem(rectItem)
    print(f'Rect Pos: {rectItem.pos()}')

    textItem = QGraphicsSimpleTextItem("Foundation of Qt")
    scene.addItem(textItem)
    print(f'Text Pos: {textItem.pos()}')
    textItem.setPos(50, 0)
    print(f'Text Pos: {textItem.pos()}')
Пример #3
0
    ellipseItem.setBrush(Qt.white)
    # scene.addItem(ellipseItem)
    return rectItem


def timerHandler():
    global sec
    item2.setTransformOriginPoint(300, 100)
    item2.setRotation(sec)
    sec += 1


if __name__ == '__main__':
    app = QApplication(sys.argv)
    scene = QGraphicsScene(QRectF(0, 0, 1000, 200))
    scene.addItem(QGraphicsRectItem(scene.sceneRect()))

    item1 = createItem(0, scene)
    sec = 0
    item2 = createItem(200, scene)

    timer = QTimer()
    timer.setInterval(1000)
    timer.timeout.connect(timerHandler)
    # item2.mapToScene(300, 100)
    # # item2.translate(300, 100)
    item2.setTransformOriginPoint(300, 100)
    item2.setRotation(30)
    # # item2.translate(-300, -100)
    # item2.mapToScene(-300, -100)
Пример #4
0
class Apartment2D(object):
    def __init__(self, ui):
        #self.ui = ui
        #self.ui.guiDlg.resize(QDesktopWidget().availableGeometry(self).size() * 0.6)
        self.scene = QGraphicsScene()
        self.dim = {
            "HMIN": -3000,
            "VMIN": -4000,
            "WIDTH": 6000,
            "HEIGHT": 8000
        }
        self.scene.setSceneRect(self.dim['HMIN'], self.dim['VMIN'],
                                self.dim['WIDTH'], self.dim['HEIGHT'])
        ui.graphicsView.setScene(self.scene)
        self.boxes = []
        #self.ui.graphicsView.setViewport(QGLWidget())
        ui.graphicsView.scale(1, -1)
        ui.graphicsView.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
        ui.graphicsView.setTransformationAnchor(QGraphicsView.NoAnchor)
        ui.graphicsView.setResizeAnchor(QGraphicsView.NoAnchor)

        self.persons = {}
        self.pixmapSize = (0, 0)
        self.initializeWorld()

    def addPerson(self, pos, angle=0, color=-1, size=100):
        colors = QColor.colorNames()
        color = colors[random.randint(0,
                                      len(colors) -
                                      1)] if color == -1 else color
        pos = [pos[0], pos[2]] if len(pos) > 2 else pos
        p = self.scene.addEllipse(pos[0] - size // 2,
                                  pos[1] - size // 2,
                                  size,
                                  size,
                                  pen=QPen(QColor(color), 20),
                                  brush=QBrush(color=QColor(color)))

        # pixmap
        pixmap = QPixmap("person.png").scaled(600, 300)
        self.pixmapSize = (pixmap.width() / 2, pixmap.height() / 2)
        pixItem = QGraphicsPixmapItem(pixmap)
        pixItem.setTransformOriginPoint(pixItem.boundingRect().center())
        pixItem.setZValue(20)
        self.scene.addItem(pixItem)

        self.persons[p] = pixItem

        return p

    def movePerson(self, elipse, pos, size=100):
        #elipse.setPos(pos[0], pos[1])
        pos = [pos[0], pos[2]] if len(pos) > 2 else pos
        color = elipse.pen().color()
        self.scene.addEllipse(pos[0] - size // 2,
                              pos[1] - size // 2,
                              size,
                              size,
                              pen=QPen(QColor(color), 20),
                              brush=QBrush(color=QColor(color)))
        # pixmap
        self.persons[elipse].setPos(pos[0] - self.pixmapSize[0],
                                    pos[1] - self.pixmapSize[1])

        # change rotation value when provided
        self.persons[elipse].setRotation(180)

    def wheelEvent(self, event):
        zoomInFactor = 1.15
        zoomOutFactor = 1 / zoomInFactor
        # Zoom
        if event.delta() > 0:
            zoomFactor = zoomInFactor
        else:
            zoomFactor = zoomOutFactor
        self.graphicsView.scale(zoomFactor, zoomFactor)

    def initializeWorld(self):
        with open('autonomy.json', 'r') as f:
            world = json.load(f)

        #load dimensions
        dim = world["dimensions"]
        x_offset = -3200
        y_offset = 1850

        # load roundtables
        # for k,v in world["roundTables"].items():
        #     print(v)
        #     box = self.scene.addEllipse(QRectF(-v[2]// 2, -v[3]// 2, v[2], v[3]), QPen(QColor("Khaki")), QBrush(QColor("Khaki")));
        #     box.setPos(v[4]+x_offset, v[5]+x_offset);
        #     self.boxes.append(box)

        # load tables
        for k, v in world["tables"].items():
            box = self.scene.addRect(
                QRectF(-v[2] // 2, -v[3] // 2, v[2], v[3]),
                QPen(QColor("SandyBrown")), QBrush(QColor("SandyBrown")))
            box.setPos(v[4] + x_offset, v[5] + y_offset)
            box.setTransformOriginPoint(box.mapFromScene(QPointF(0, 0)))
            box.setRotation(v[6])
            self.boxes.append(box)

        # load walls
        for k, v in world['walls'].items():
            box = self.scene.addRect(
                QRectF(-v[2] // 2, -v[3] // 2, v[2], v[3]),
                QPen(QColor("Brown")), QBrush(QColor("Brown")))
            box.setPos(v[4] + x_offset, v[5] + y_offset)
            box.setTransformOriginPoint(box.mapFromScene(QPointF(0, 0)))
            box.setRotation(v[6])
            self.boxes.append(box)
        # }

        # //load points
        # QVariantMap points = mainMap[QString("points")].toMap();
        # for (auto &t : points)
        # {
        #     QVariantList object = t.toList();
        #     auto box = scene.addRect(QRectF(-object[2].toFloat() / 2, -object[3].toFloat() / 2, object[2].toFloat(), object[3].toFloat()), QPen(QColor("Brown")), QBrush(QColor("Brown")));
        #     box->setPos(object[4].toFloat()+x_offset, object[5].toFloat()+y_offset);
        #     boxes.push_back(box);
        # }
        # //load boxes
        # QVariantMap cajas = mainMap[QString("boxes")].toMap();
        # for (auto &t : cajas)
        # {
        #     QVariantList object = t.toList();
        #     auto box = scene.addRect(QRectF(-object[2].toFloat() / 2, -object[3].toFloat() / 2, object[2].toFloat(), object[3].toFloat()), QPen(QColor("Brown")), QBrush(QColor("Orange")));
        #     box->setPos(object[4].toFloat()+x_offset, object[5].toFloat()+y_offset);
        #     //box->setPos(object[4].toFloat(), object[5].toFloat());
        #     //box->setRotation(object[6].toFloat()*180/M_PI2);
        #     box->setFlag(QGraphicsItem::ItemIsMovable);
        #     boxes.push_back(box);
        # }
        # QTransform t;
        # //t.translate(3200, -1850);
        # t.rotate(-90);
        # //t.translate(-3200, 1850);
        # for(auto &item : boxes)
        # {
        #     item->setPos(t.map(item->pos()));
        #     item->setRotation(item->rotation() + 90);
        #     item->setPos(item->pos() + QPointF(1850,3200));
        # }
        # /////////////
        # //AXIS
        self.scene.addLine(0, 0, 400, 0, QPen(QBrush(QColor("red")), 20))
        self.scene.addLine(0, 0, 0, 400, QPen(QBrush(QColor("blue")), 20))
Пример #5
0
class Window(QObject):
    def __init__(self, ui):
        super().__init__()
        self.ui = ui
        ui.show()
        self.ui.setWindowTitle("Display Configuration")
        self.ui.screenCombo.currentTextChanged.connect(self.monitor_selected)
        self.ui.replicaOf.currentTextChanged.connect(self.replica_changed)
        self.ui.orientationCombo.currentIndexChanged.connect(
            self.orientation_changed)
        self.xrandr_info = {}
        self.get_xrandr_info()
        self.orig_xrandr_info = deepcopy(self.xrandr_info)
        self.fill_ui()
        self.ui.horizontalScale.valueChanged.connect(self.scale_changed)
        self.ui.verticalScale.valueChanged.connect(self.scale_changed)
        self.ui.modes.currentTextChanged.connect(self.mode_changed)
        self.ui.applyButton.clicked.connect(self.do_apply)
        self.ui.okButton.clicked.connect(self.do_ok)
        self.ui.resetButton.clicked.connect(self.do_reset)
        self.ui.cancelButton.clicked.connect(self.ui.reject)
        self.ui.scaleModeCombo.currentTextChanged.connect(
            self.scale_mode_changed)
        self.ui.primary.stateChanged.connect(self.primary_changed)
        self.ui.enabled.stateChanged.connect(self.enabled_changed)

        self.pos_label = QLabel(self.ui.sceneView)
        self.pos_label.move(5, 5)

    def enabled_changed(self):
        mon = self.ui.screenCombo.currentText()
        enabled = self.ui.enabled.isChecked()
        print(f"Setting {mon} enabled status to {enabled}")
        monitor = self.xrandr_info[mon]
        monitor["enabled"] = enabled
        if enabled and not monitor["current_mode"]:
            # Choose a mode
            self.ui.modes.setCurrentIndex(0)
            self.mode_changed()
        self.update_replica_of_data()
        for _, mon in self.xrandr_info.items():
            mon["item"].update_visuals(mon)
        self.adjust_view()

    def primary_changed(self):
        mon = self.ui.screenCombo.currentText()
        primary = self.ui.primary.isChecked()

        # Update visuals on all monitos
        for name, monitor in self.xrandr_info.items():
            if name == mon:
                monitor["primary"] = primary
            else:
                if primary:  # There can only be one primary
                    monitor["primary"] = False
            monitor["item"].update_visuals(monitor)

    def scale_mode_changed(self):
        mon = self.ui.screenCombo.currentText()
        scale_mode = self.ui.scaleModeCombo.currentText()
        print(f"Set {mon} scale mode to {scale_mode}")
        if scale_mode == "Manual":
            self.ui.horizontalScale.setEnabled(True)
            self.ui.verticalScale.setEnabled(True)
            try:
                self.ui.horizontalScale.valueChanged.disconnect(
                    self.ui.verticalScale.setValue)
            except RuntimeError:  # Not connected
                pass
        elif scale_mode == "Disabled (1x1)":
            self.ui.verticalScale.setEnabled(False)
            self.ui.horizontalScale.setEnabled(False)
            self.ui.horizontalScale.setValue(1000)
            self.ui.verticalScale.setValue(1000)
            try:
                self.ui.horizontalScale.valueChanged.disconnect(
                    self.ui.verticalScale.setValue)
            except RuntimeError:  # Not connected
                pass
        elif scale_mode == "Automatic: physical dimensions":
            # Calculate scale factors so that the logical pixels will be the same
            # size as in the primary window
            if self.ui.primary.isChecked():
                print("Has no effect on primary display.")
                return

            # Find the primary monitor
            primary = [
                k for k in self.xrandr_info if self.xrandr_info[k]["primary"]
            ]
            if not primary:
                print("Oops, no primary!")
                return
            primary = self.xrandr_info[primary[0]]
            monitor = self.xrandr_info[mon]

            prim_density_x = primary["res_x"] / primary["w_in_mm"]
            prim_density_y = primary["res_y"] / primary["h_in_mm"]

            dens_x = monitor["res_x"] / monitor["w_in_mm"]
            dens_y = monitor["res_y"] / monitor["h_in_mm"]

            try:
                self.ui.horizontalScale.valueChanged.disconnect(
                    self.ui.verticalScale.setValue)
            except RuntimeError:  # Not connected
                pass
            self.ui.horizontalScale.setEnabled(False)
            self.ui.verticalScale.setEnabled(False)
            self.ui.horizontalScale.setValue(prim_density_x / dens_x * 1000)
            self.ui.verticalScale.setValue(prim_density_y / dens_y * 1000)

        elif scale_mode == "Manual, same in both dimensions":
            self.ui.horizontalScale.setEnabled(True)
            self.ui.verticalScale.setEnabled(False)
            self.ui.horizontalScale.valueChanged.connect(
                self.ui.verticalScale.setValue)
            self.ui.verticalScale.setValue(self.ui.horizontalScale.value())

    def replica_changed(self):
        mon = self.ui.screenCombo.currentText()
        replicate = self.ui.replicaOf.currentText()
        print(f"Making {mon} a replica of {replicate}")
        if replicate in ("None", "", None):
            print("TODO: make things non-replicas")
            return
        mon = self.xrandr_info[mon]
        replicate = self.xrandr_info[replicate]

        # Making a replica implies:
        # Set the same position
        mon["pos_x"] = replicate["pos_x"]
        mon["pos_y"] = replicate["pos_y"]

        # Set the same mode if possible
        if replicate["current_mode"] in mon["modes"]:
            mon["current_mode"] = replicate["current_mode"]
        else:
            # Keep the current mode, and change scaling so it
            # has the same effective size as the desired mode
            mod_x, mod_y = [int(x) for x in mon["current_mode"].split("x")]
            target_x, target_y = [replicate[x] for x in ["res_x", "res_y"]]
            scale_x = 1000 * target_x / mod_x
            scale_y = 1000 * target_y / mod_y
            self.ui.horizontalScale.setValue(scale_x)
            self.ui.verticalScale.setValue(scale_y)

        self.update_replica_of_data()
        for _, mon in self.xrandr_info.items():
            mon["item"].update_visuals(mon)

    def do_reset(self):
        for n in self.xrandr_info:
            self.xrandr_info[n].update(self.orig_xrandr_info[n])
        self.fill_ui()

    def do_ok(self):
        self.do_apply()
        self.ui.accept()

    def do_apply(self):
        cli = gen_xrandr_from_data(self.xrandr_info)
        print(cli)
        subprocess.check_call(shlex.split(cli))

    def fill_ui(self):
        """Load data from xrandr and setup the whole thing."""
        self.scene = QGraphicsScene(self)
        self.ui.sceneView.setScene(self.scene)
        self.ui.screenCombo.clear()

        for name, monitor in self.xrandr_info.items():
            self.ui.screenCombo.addItem(name)
            mon_item = MonitorItem(
                data=monitor,
                window=self,
                name=name,
            )
            self.scene.addItem(mon_item)
            monitor["item"] = mon_item
        self.ui.screenCombo.setCurrentText(self.choose_a_monitor())
        self.adjust_view()
        self.scale_changed()  # Trigger scale labels update

    def detect_scale_mode(self, monitor):
        """Given a monitor's data, try to guess what scaling
        mode it's using.

        TODO: detect "Automatic: physical dimensions"
        """
        if not monitor["current_mode"]:  # Disabled, whatever
            return None

        mod_x, mod_y = [int(x) for x in monitor["current_mode"].split("x")]
        scale_x = monitor["res_x"] / mod_x
        scale_y = monitor["res_y"] / mod_y

        if 1 == scale_x == scale_y:
            print("Scale mode looks like 1x1")
            return "Disabled (1x1)"
        elif scale_x == scale_y:
            print("Looks like Manual, same in both dimensions")
            return "Manual, same in both dimensions"
        else:
            return "Manual"

    def choose_a_monitor(self):
        """Choose what monitor to select by default.

        * Not disabled
        * Primary, if possible
        """

        candidate = None
        for name, mon in self.xrandr_info.items():
            if not mon["enabled"]:
                continue
            if mon["primary"]:
                return name
            candidate = name
        return candidate

    def orientation_changed(self):
        mon = self.ui.screenCombo.currentText()
        orientation = self.ui.orientationCombo.currentIndex()
        self.xrandr_info[mon]["orientation"] = orientation
        self.mode_changed()

    def mode_changed(self):
        mon = self.ui.screenCombo.currentText()
        mode = self.ui.modes.currentText()
        if not mode:
            return
        print(f"Changing {mon} to {mode}")
        self.xrandr_info[mon]["current_mode"] = mode
        mode_x, mode_y = mode.split("x")
        # use resolution via scaling
        if self.xrandr_info[mon]["orientation"] in (0, 2):
            self.xrandr_info[mon]["res_x"] = int(
                int(mode_x) * self.ui.horizontalScale.value() / 1000)
            self.xrandr_info[mon]["res_y"] = int(
                int(mode_y) * self.ui.verticalScale.value() / 1000)
        else:
            self.xrandr_info[mon]["res_x"] = int(
                int(mode_y) * self.ui.horizontalScale.value() / 1000)
            self.xrandr_info[mon]["res_y"] = int(
                int(mode_x) * self.ui.verticalScale.value() / 1000)
        self.xrandr_info[mon]["item"].update_visuals(self.xrandr_info[mon])

    def show_pos(self, x, y):
        self.pos_label.setText(f"{x},{y}")
        self.pos_label.resize(self.pos_label.sizeHint())

    def monitor_moved(self):
        "Update xrandr_info with new monitor positions"
        for _, mon in self.xrandr_info.items():
            item = mon["item"]
            mon["pos_x"] = item.x()
            mon["pos_y"] = item.y()
        self.update_replica_of_data()
        for _, mon in self.xrandr_info.items():
            mon["item"].update_visuals(mon)
        self.adjust_view()

    def adjust_view(self):
        self.ui.sceneView.resetTransform()
        self.ui.sceneView.ensureVisible(self.scene.sceneRect(), 100, 100)
        scale_factor = 0.8 * min(
            self.ui.sceneView.width() / self.scene.sceneRect().width(),
            self.ui.sceneView.height() / self.scene.sceneRect().height(),
        )
        self.ui.sceneView.scale(scale_factor, scale_factor)

    def get_xrandr_info(self):
        data = subprocess.check_output(["xrandr"]).decode("utf-8").splitlines()
        name = None
        for line in data:
            if (line and line[0] not in "S \t"
                    and "disconnected" not in line):  # Output line
                (
                    name,
                    primary,
                    res_x,
                    res_y,
                    w_in_mm,
                    h_in_mm,
                    pos_x,
                    pos_y,
                    enabled,
                    orientation,
                ) = parse_monitor(line)
                self.xrandr_info[name] = dict(
                    primary=primary,
                    res_x=res_x,
                    res_y=res_y,
                    w_in_mm=w_in_mm,
                    h_in_mm=h_in_mm,
                    pos_x=pos_x,
                    pos_y=pos_y,
                    modes=[],
                    current_mode=None,
                    enabled=enabled,
                    replica_of=[],
                    orientation=orientation,
                )
            elif line[0] == " ":  # A mode
                mode_name = line.strip().split()[0]
                self.xrandr_info[name]["modes"].append(mode_name)
                if "*" in line:
                    print(f"Current mode for {name}: {mode_name}")
                    self.xrandr_info[name]["current_mode"] = mode_name
        self.update_replica_of_data()

    def update_replica_of_data(self):
        for a in self.xrandr_info:
            self.xrandr_info[a]["replica_of"] = []
            for b in self.xrandr_info:
                if a != b and is_replica_of(self.xrandr_info[a],
                                            self.xrandr_info[b]):
                    self.xrandr_info[a]["replica_of"].append(b)

    def monitor_selected(self, name):
        if not name:
            return
        # needed so we don't flip through all modes as they are added
        self.ui.modes.blockSignals(True)
        # Show modes
        self.ui.modes.clear()
        for mode in self.xrandr_info[name]["modes"]:
            self.ui.modes.addItem(mode)
        if (self.xrandr_info[name]["current_mode"] is
                None):  # Happens with turned off monitors
            self.xrandr_info[name]["enabled"] = False
            h_scale = v_scale = 1
        else:
            self.ui.modes.setCurrentText(
                self.xrandr_info[name]["current_mode"])
            mod_x, mod_y = [
                int(x)
                for x in self.xrandr_info[name]["current_mode"].split("x")
            ]
            if self.xrandr_info[name]["orientation"] in (0, 2):
                h_scale = self.xrandr_info[name]["res_x"] / mod_x
                v_scale = self.xrandr_info[name]["res_y"] / mod_y
            else:
                h_scale = self.xrandr_info[name]["res_y"] / mod_x
                v_scale = self.xrandr_info[name]["res_x"] / mod_y
        self.ui.horizontalScale.setValue(h_scale * 1000)
        self.ui.verticalScale.setValue(v_scale * 1000)
        self.ui.primary.setChecked(self.xrandr_info[name]["primary"])
        self.ui.enabled.setChecked(self.xrandr_info[name]["enabled"])
        self.ui.orientationCombo.setCurrentIndex(
            self.xrandr_info[name]["orientation"])

        self.ui.replicaOf.clear()
        self.ui.replicaOf.addItem("None")
        for mon in self.xrandr_info:
            if mon != name:
                self.ui.replicaOf.addItem(mon)
                if mon in self.xrandr_info[name]["replica_of"]:
                    self.ui.replicaOf.setCurrentText(mon)
        self.ui.modes.blockSignals(False)

        guessed_scale_mode = self.detect_scale_mode(self.xrandr_info[name])
        self.ui.scaleModeCombo.setCurrentText(guessed_scale_mode)
        self.scale_mode_changed()

    def scale_changed(self):
        self.ui.horizontalScaleLabel.setText(
            f"{int(self.ui.horizontalScale.value()/10)}%")
        self.ui.verticalScaleLabel.setText(
            f"{int(self.ui.verticalScale.value()/10)}%")
        self.mode_changed()  # Not really, but it's the same thing
Пример #6
0
class LabelingWidget(QGraphicsView):
    def __init__(self):
        super().__init__()

        self._tag_brushes = []
        self._tag_brushes.append(QBrush(QColor(0, 0, 0, 0)))
        self._tag_brushes.append(QBrush(QColor(255, 0, 0, 90)))

        self._image_item = QGraphicsPixmapItem()
        self._create_default_scene()

        self.setScene(self._scene)

    def _create_default_scene(self):
        self._scene = QGraphicsScene()

        self._scene.addItem(self._image_item)

        line_pen = QPen(Qt.black, 2)
        for i in range(LABELING_TAG_WIDTH + 1):
            self._scene.addLine(i * LABELING_STEP, 0, i * LABELING_STEP,
                                LABELING_HEIGHT, line_pen)

        for i in range(LABELING_TAG_HEIGHT + 1):
            self._scene.addLine(0, i * LABELING_STEP, LABELING_WIDTH,
                                i * LABELING_STEP, line_pen)

        self._tags = np.zeros((LABELING_TAG_HEIGHT, LABELING_TAG_WIDTH),
                              dtype=int)
        self._tags_items = []

        tag_pen = QPen(Qt.black, 0)
        for i in range(LABELING_TAG_HEIGHT):
            tags = []
            for j in range(LABELING_TAG_WIDTH):
                item = self._scene.addRect(j * LABELING_STEP,
                                           i * LABELING_STEP, LABELING_STEP,
                                           LABELING_STEP, tag_pen,
                                           self._tag_brushes[0])
                tags.append(item)

            self._tags_items.append(tags)

    def _update_tags(self):
        for i in range(LABELING_TAG_HEIGHT):
            for j in range(LABELING_TAG_WIDTH):
                self._tags_items[i][j].setBrush(
                    self._tag_brushes[self._tags[i, j]])

    def set_image(self, path):
        self._image_item.setPixmap(QPixmap(path))

    def clear(self):
        self._tags[:, :] = 0
        self._update_tags()

    def get_tags(self):
        return self._tags.copy()

    def set_tags(self, tags):
        if tags.shape[0] != LABELING_TAG_HEIGHT or tags.shape[
                1] != LABELING_TAG_WIDTH:
            raise ValueError('Wrong tags shape')

        self._tags = tags.copy()
        self._update_tags()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio)

    def mousePressEvent(self, event):
        point = self.mapToScene(event.pos())
        index_x = int(point.x() / LABELING_STEP)
        index_y = int(point.y() / LABELING_STEP)

        if event.buttons() & Qt.LeftButton != 0:
            self._tags[index_y, index_x] = 1
        elif event.buttons() & Qt.RightButton != 0:
            self._tags[index_y, index_x] = 0

        self._update_tags()

    def mouseMoveEvent(self, event):
        point = self.mapToScene(event.pos())
        index_x = int(point.x() / LABELING_STEP)
        index_y = int(point.y() / LABELING_STEP)

        if event.buttons() & Qt.LeftButton != 0:
            self._tags[index_y, index_x] = 1
        elif event.buttons() & Qt.RightButton != 0:
            self._tags[index_y, index_x] = 0

        self._update_tags()
Пример #7
0
            self.mapToParent(-(self.boundingRect().width()),
                             -(self.boundingRect().width() + 2)))

        if not self.scene().sceneRect().contains((newPoint)):
            print('move to 0, 0')
            newPoint = self.mapToParent(0, 0)
        else:
            self.setPos(newPoint)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    scene = QGraphicsScene(QRectF(-200, -200, 300, 300))

    view = QGraphicsView()
    view.setRenderHint(QPainter.Antialiasing)
    boundaryPen = QPen(Qt.red)
    scene.addRect(scene.sceneRect())

    itemCount = 20
    for i in range(0, itemCount):
        item = MyItem()
        scene.addItem(item)

    timer = QTimer()
    timer.setInterval(500)
    timer.timeout.connect(scene.advance)

    view.setScene(scene)
    view.show()
    sys.exit(app.exec_())
Пример #8
0
class Window(QObject):
    def __init__(self, ui):
        super().__init__()
        self.ui = ui
        ui.show()
        self.ui.setWindowTitle("Display Configuration")
        self.ui.screenCombo.currentTextChanged.connect(self.monitor_selected)
        self.ui.replicaOf.currentTextChanged.connect(self.replica_changed)
        self.ui.orientationCombo.currentIndexChanged.connect(
            self.orientation_changed)
        self.get_xrandr_info()
        self.fill_ui()
        self.ui.horizontalScale.valueChanged.connect(self.scale_changed)
        self.ui.verticalScale.valueChanged.connect(self.scale_changed)
        self.ui.modes.currentTextChanged.connect(self.mode_changed)
        self.ui.applyButton.clicked.connect(self.do_apply)
        self.ui.okButton.clicked.connect(self.do_ok)
        self.ui.resetButton.clicked.connect(self.do_reset)
        self.ui.cancelButton.clicked.connect(self.ui.reject)
        self.ui.scaleModeCombo.currentTextChanged.connect(
            self.scale_mode_changed)
        self.ui.primary.stateChanged.connect(self.primary_changed)
        self.ui.enabled.stateChanged.connect(self.enabled_changed)

        self.pos_label = QLabel(self.ui.sceneView)
        self.pos_label.move(5, 5)

    def enabled_changed(self):
        mon = self.ui.screenCombo.currentText()
        enabled = self.ui.enabled.isChecked()
        print(f"Setting {mon} enabled status to {enabled}")
        monitor = self.screen.monitors[mon]
        monitor.enabled = enabled
        if enabled and not monitor.get_current_mode():
            # Choose a mode
            self.ui.modes.setCurrentText(monitor.get_preferred_mode_name())
            self.mode_changed()
        self.screen.update_replica_of()
        for mon in self.screen.monitors.values():
            mon.item.update_visuals(mon)
        self.adjust_view()

    def primary_changed(self):
        mon_name = self.ui.screenCombo.currentText()
        primary = self.ui.primary.isChecked()
        if primary:
            self.screen.set_primary(mon_name)
        else:
            self.screen.set_primary("foobar")  # no primary

        for monitor in self.screen.monitors.values():
            monitor.item.update_visuals(monitor)

    def scale_mode_changed(self):
        mon = self.ui.screenCombo.currentText()
        scale_mode = self.ui.scaleModeCombo.currentText()
        print(f"Set {mon} scale mode to {scale_mode}")
        if scale_mode == "Manual":
            self.ui.horizontalScale.setEnabled(True)
            self.ui.verticalScale.setEnabled(True)
            try:
                self.ui.horizontalScale.valueChanged.disconnect(
                    self.ui.verticalScale.setValue)
            except RuntimeError:  # Not connected
                pass
        elif scale_mode == "Disabled (1x1)":
            self.ui.verticalScale.setEnabled(False)
            self.ui.horizontalScale.setEnabled(False)
            self.ui.horizontalScale.setValue(1000)
            self.ui.verticalScale.setValue(1000)
            try:
                self.ui.horizontalScale.valueChanged.disconnect(
                    self.ui.verticalScale.setValue)
            except RuntimeError:  # Not connected
                pass
        elif scale_mode == "Automatic: physical dimensions":
            # Calculate scale factors so that the logical pixels will be the same
            # size as in the primary window
            if self.ui.primary.isChecked():
                print("Has no effect on primary display.")
                return

            # Find the primary monitor
            primary = self.screen.get_primary()
            if not primary:
                print("Oops, no primary!")
                return
            monitor = self.screen.monitors[mon]

            prim_density_x = primary.res_x / primary.w_in_mm
            prim_density_y = primary.res_y / primary.h_in_mm

            dens_x = monitor.res_x / monitor.w_in_mm
            dens_y = monitor.res_y / monitor.h_in_mm

            try:
                self.ui.horizontalScale.valueChanged.disconnect(
                    self.ui.verticalScale.setValue)
            except RuntimeError:  # Not connected
                pass
            self.ui.horizontalScale.setEnabled(False)
            self.ui.verticalScale.setEnabled(False)
            self.ui.horizontalScale.setValue(prim_density_x / dens_x * 1000)
            self.ui.verticalScale.setValue(prim_density_y / dens_y * 1000)

        elif scale_mode == "Manual, same in both dimensions":
            self.ui.horizontalScale.setEnabled(True)
            self.ui.verticalScale.setEnabled(False)
            self.ui.horizontalScale.valueChanged.connect(
                self.ui.verticalScale.setValue)
            self.ui.verticalScale.setValue(self.ui.horizontalScale.value())

    def replica_changed(self):
        mon_name = self.ui.screenCombo.currentText()
        replicate = self.ui.replicaOf.currentText()
        print(f"Making {mon_name} a replica of {replicate}")
        if replicate in ("None", "", None):
            print("TODO: make things non-replicas")
            return
        mon = self.screen.monitors[mon_name]
        replicate = self.screen.monitors[replicate]

        # Making a replica implies:
        # Set the same position
        mon.pos_x = replicate.pos_x
        mon.pos_y = replicate.pos_y

        # Set the same mode if possible
        matching_mode = mon.get_matching_mode(replicate.get_current_mode())
        if matching_mode:
            mon.set_current_mode(matching_mode.name)
        else:
            # Keep the current mode, and change scaling so it
            # has the same effective size as the desired mode
            c_mode = mon.get_current_mode()
            mod_x, mod_y = c_mode.res_x, c_mode.res_y
            r_mode = replicate.get_current_mode
            target_x, target_y = r_mode.res_x, r_mode.res_y
            scale_x = 1000 * target_x / mod_x
            scale_y = 1000 * target_y / mod_y
            self.ui.horizontalScale.setValue(scale_x)
            self.ui.verticalScale.setValue(scale_y)

        self.screen.update_replica_of()
        for mon in self.screen.monitors.values():
            mon.item.update_visuals(mon)

    def run(self, commands):
        for i, cmd in enumerate(commands, 1):
            print(f"Running {cmd} [{i}/{len(commands)}]")
            subprocess.check_call(shlex.split(cmd))

    def do_reset(self):
        self.run(self.reset_screen.generate())
        self.fill_ui()

    def do_ok(self):
        self.do_apply()
        self.ui.accept()

    def do_apply(self):
        cli = self.screen.generate()
        self.run(cli)

    def fill_ui(self):
        """Configure UI out of our screen data."""
        self.scene = QGraphicsScene(self)
        self.ui.sceneView.setScene(self.scene)
        self.ui.screenCombo.clear()

        for name, monitor in self.screen.monitors.items():
            self.ui.screenCombo.addItem(name)
            mon_item = MonitorItem(
                data=monitor,
                window=self,
                name=name,
            )
            self.scene.addItem(mon_item)
            monitor.item = mon_item
        self.ui.screenCombo.setCurrentText(self.screen.choose_a_monitor())
        self.adjust_view()
        # self.scale_changed()  # Trigger scale labels update

    def orientation_changed(self):
        mon_name = self.ui.screenCombo.currentText()
        orientation = self.ui.orientationCombo.currentText().split()[0].lower()
        self.screen.monitors[mon_name].orientation = orientation
        self.mode_changed()

    def mode_changed(self):
        mon = self.ui.screenCombo.currentText()
        mode = self.ui.modes.currentText()
        if not mode:
            return
        print(f"Changing {mon} to {mode}")
        monitor = self.screen.monitors[mon]
        monitor.set_current_mode(mode)
        mode_x, mode_y = (
            monitor.get_current_mode().res_x,
            monitor.get_current_mode().res_y,
        )
        # use resolution via scaling
        if monitor.orientation in ("normal", "inverted"):
            monitor.res_x = int(mode_x * self.ui.horizontalScale.value() /
                                1000)
            monitor.res_y = int(mode_y * self.ui.verticalScale.value() / 1000)
        else:
            monitor.res_x = int(mode_y * self.ui.horizontalScale.value() /
                                1000)
            monitor.res_y = int(mode_x * self.ui.verticalScale.value() / 1000)
        monitor.item.update_visuals(monitor)

    def show_pos(self, x, y):
        self.pos_label.setText(f"{x},{y}")
        self.pos_label.resize(self.pos_label.sizeHint())

    def monitor_moved(self):
        "Update screen with new monitor positions"
        for mon in self.screen.monitors.values():
            item = mon.item
            mon.pos_x = item.x()
            mon.pos_y = item.y()
        self.screen.update_replica_of()
        for mon in self.screen.monitors.values():
            mon.item.update_visuals(mon)
        # Adjust view a little later
        QTimer.singleShot(0, self.adjust_view)

    def possible_snaps(self, name):
        """Return two lists of values to which the x and y position
        of monitor "name" could snap to."""
        snaps_x = []
        snaps_y = []

        for output, monitor in self.screen.monitors.items():
            if output == name:
                continue
            else:
                mode = monitor.get_current_mode()
                mod_x, mod_y = mode.res_x, mode.res_y
                snaps_x.append(monitor.pos_x)
                snaps_x.append(monitor.pos_x + mod_x)
                snaps_y.append(monitor.pos_x)
                snaps_y.append(monitor.pos_x + mod_y)
        return snaps_x, snaps_y

    def adjust_view(self):
        print("Adjusting view")
        self.ui.sceneView.resetTransform()
        self.ui.sceneView.ensureVisible(self.scene.sceneRect(), 100, 100)
        try:
            scale_factor = 0.8 * min(
                self.ui.sceneView.width() / self.scene.sceneRect().width(),
                self.ui.sceneView.height() / self.scene.sceneRect().height(),
            )
            self.ui.sceneView.scale(scale_factor, scale_factor)
        except ZeroDivisionError:
            # Don't worry
            pass

    def get_xrandr_info(self):
        _xrandr_data = xrandr.read_data()
        self.screen = xrandr.parse_data(_xrandr_data)
        self.screen.update_replica_of()
        self.reset_screen = xrandr.parse_data(_xrandr_data)

    def monitor_selected(self, name):
        if not name:
            return
        # needed so we don't flip through all modes as they are added
        self.ui.modes.blockSignals(True)
        self.ui.primary.blockSignals(True)
        # Show modes
        self.ui.modes.clear()
        monitor = self.screen.monitors[name]
        for mode in monitor.modes:
            self.ui.modes.addItem(mode)

        mode = monitor.get_current_mode()
        self.ui.modes.setCurrentText(mode.name)
        if monitor.orientation in ("normal", "inverted"):
            h_scale = monitor.res_x / mode.res_x
            v_scale = monitor.res_y / mode.res_y
        else:
            h_scale = monitor.res_y / mode.res_x
            v_scale = monitor.res_x / mode.res_y

        self.ui.horizontalScale.setValue(h_scale * 1000)
        self.ui.verticalScale.setValue(v_scale * 1000)
        self.ui.primary.setChecked(monitor.primary)
        self.ui.enabled.setChecked(monitor.enabled)
        self.ui.orientationCombo.setCurrentText(monitor.orientation)

        self.ui.replicaOf.clear()
        self.ui.replicaOf.addItem("None")
        for mon in self.screen.monitors:
            if mon != name:
                self.ui.replicaOf.addItem(mon)
                if mon in self.screen.monitors[name].replica_of:
                    self.ui.replicaOf.setCurrentText(mon)
        self.ui.modes.blockSignals(False)
        self.ui.primary.blockSignals(False)

        guessed_scale_mode = monitor.guess_scale_mode()
        self.ui.scaleModeCombo.setCurrentText(guessed_scale_mode)
        self.scale_mode_changed()

    def scale_changed(self):
        self.ui.horizontalScaleLabel.setText(
            f"{int(self.ui.horizontalScale.value()/10)}%")
        self.ui.verticalScaleLabel.setText(
            f"{int(self.ui.verticalScale.value()/10)}%")
        self.mode_changed()  # Not really, but it's the same thing
Пример #9
0
class Escena(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.resize(QDesktopWidget().availableGeometry(self).size() * 0.6)
        self.scene = QGraphicsScene()
        self.scene.setSceneRect(-3000, -4000, 6000, 8000)
        self.view = QGraphicsView(self.scene)
        self.view.resize(self.size())
        self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
        self.view.setParent(self)
        self.view.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.view.setResizeAnchor(QGraphicsView.NoAnchor)
        self.view.scale(3, -3)
        self.lines = []
        self.show()

    def wheelEvent(self, event):
        zoomInFactor = 1.15
        zoomOutFactor = 1 / zoomInFactor
        # Zoom
        if event.delta() > 0:
            zoomFactor = zoomInFactor
        else:
            zoomFactor = zoomOutFactor
        self.view.scale(zoomFactor, zoomFactor)

    def resizeEvent(self, event):
        self.view.resize(self.size())

    def draw(self, comps, cluster):
        colors = QColor.colorNames()

        # for co in sample:
        #     print(co)
        #     x, _, z, _ = co['world']
        #     self.scene.addEllipse(x-50,z-50,100,100, pen=QPen(QColor('orange'), 5))

        # x,_,z,_ = sample[-1]['world']
        # self.scene.addRect(x,z,60,60, pen=QPen(QColor('red'), 100))
        # x,_,z,_ = sample[0]['world']
        # self.scene.addRect(x,z,60,60, pen=QPen(QColor('green'), 100))

        # for co in comps:
        #     if sample[co[-1]]['timestamp']-sample[co[0]]['timestamp'] > 200 and len(co)> 4:
        #         color = colors[random.randint(0, len(colors)-1)]
        #         for c in co:
        #             x, _, z, _ = sample[c]['world']
        #             self.scene.addEllipse(x-15,z-15,30,30, pen=QPen(QColor(color), 100), brush=QBrush(color=QColor(color)))

        if cluster[-1]['timestamp'] - cluster[0]['timestamp'] > 200 and len(
                cluster) > 4:
            color = colors[random.randint(0, len(colors) - 1)]
            for sample in cluster:
                x, _, z, _ = sample['world']
                self.scene.addEllipse(x - 15,
                                      z - 15,
                                      30,
                                      30,
                                      pen=QPen(QColor(color), 100),
                                      brush=QBrush(color=QColor(color)))

    def drawTrack(self, clusters):
        colors = QColor.colorNames()
        # for line in self.lines:
        #     self.scene.removeItem(line)
        self.scene.clear()
        for cluster in clusters:
            color = colors[random.randint(0, len(colors) - 1)]
            for t in cluster:
                self.scene.addLine(t[0][0],
                                   t[0][1],
                                   t[1][0],
                                   t[1][1],
                                   pen=QPen(QColor(color), 60))