Exemplo n.º 1
0
class UndoList(QDialog):
    __instance = None

    @classmethod
    def __getInstance(cls):
        return cls.__instance

    @classmethod
    def getInstance(cls):
        cls.__instance = cls()
        cls.getInstance = cls.__getInstance
        return cls.__instance

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Command List")
        self.stack = UndoAction()

        self.view = QUndoView()
        self.view.setStack(self.stack)

        layout = QGridLayout()
        layout.addWidget(self.view)

        self.setLayout(layout)
Exemplo n.º 2
0
class UndoDock(DockWidget):

    def __init__(self, parent=None):
        DockWidget.__init__(self, "历史", parent)
        self.setObjectName("undoViewDock")
        self._undo_view = QUndoView(self)
        self._clear_icon = QIcon(":/drive-harddisk.png")

        self._undo_view.setCleanIcon(self._clear_icon)
        self._undo_view.setUniformItemSizes(True)
        self._widget = QWidget(self)
        self._layout = QVBoxLayout(self._widget)
        self._layout.setStretch(0, 0)
        self._layout.setContentsMargins(0, 6, 6, 6)
        self._layout.addWidget(self._undo_view)
        self.setWidget(self._widget)
        self.retranslateUi()

    def set_stack(self, stack: QUndoStack):
        self._undo_view.setStack(stack)

    def set_group(self, group: QUndoGroup):
        self._undo_view.setGroup(group)

    def changeEvent(self, event: QEvent) -> None:
        pass
        # if e.type():
        # self.LanguageChange
        # self.retranslateUi()

    def retranslateUi(self):
        self.setWindowTitle("历史")
        self._undo_view.setEmptyLabel("<空>")
Exemplo n.º 3
0
    def _createUndoView(self, history):
        undoGroup = QGroupBox(_("History of changes"), self)
        undoGroupLayout = QVBoxLayout()
        undoGroup.setLayout(undoGroupLayout)

        undoView = QUndoView(history, self)
        undoView.setEmptyLabel(_("<Original file>"))
        undoGroupLayout.addWidget(undoView)

        mainLayout = self.layout()
        mainLayout.addWidget(undoGroup)
Exemplo n.º 4
0
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Command List")
        self.stack = UndoAction()

        self.view = QUndoView()
        self.view.setStack(self.stack)

        layout = QGridLayout()
        layout.addWidget(self.view)

        self.setLayout(layout)
Exemplo n.º 5
0
    def __init__(self, undoGroup, parent=None):
        super().__init__(parent)

        self.setObjectName("undoViewDock")
        self.mUndoView = QUndoView(undoGroup, self)
        cleanIcon = QIcon(":images/16x16/drive-harddisk.png")
        self.mUndoView.setCleanIcon(cleanIcon)
        self.mUndoView.setUniformItemSizes(True)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(self.mUndoView)
        self.setWidget(widget)
        self.retranslateUi()
Exemplo n.º 6
0
    def __init__(self, parent=None):
        DockWidget.__init__(self, "历史", parent)
        self.setObjectName("undoViewDock")
        self._undo_view = QUndoView(self)
        self._clear_icon = QIcon(":/drive-harddisk.png")

        self._undo_view.setCleanIcon(self._clear_icon)
        self._undo_view.setUniformItemSizes(True)
        self._widget = QWidget(self)
        self._layout = QVBoxLayout(self._widget)
        self._layout.setStretch(0, 0)
        self._layout.setContentsMargins(0, 6, 6, 6)
        self._layout.addWidget(self._undo_view)
        self.setWidget(self._widget)
        self.retranslateUi()
Exemplo n.º 7
0
    def _create_toolbar(self, actions):
        """Fills the main toolbar with QActions"""

        self.addAction(actions.new)
        self.addAction(actions.open)
        self.addAction(actions.save)
        self.addAction(actions.export)

        self.addSeparator()

        self.addAction(actions.print)

        self.addSeparator()

        self.addAction(actions.undo)
        undo_button = self.widgetForAction(actions.undo)
        undo_view = QUndoView(self.main_window.undo_stack)
        add_toolbutton_widget(undo_button, undo_view)

        self.addAction(actions.redo)

        self.addSeparator()

        self.addAction(actions.cut)
        self.addAction(actions.copy)
        self.addAction(actions.copy_results)
        self.addAction(actions.paste)
        self.addAction(actions.paste)

        self.addSeparator()

        self.addAction(actions.toggle_spell_checker)

        self.addWidget(self.get_manager_button())
Exemplo n.º 8
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._undo_stack = QUndoStack(self)
        self._undo_view = QUndoView(self._undo_stack)
        self._undo_view.setCleanIcon(QIcon(":/icons/images/document-save.svg"))
        self._undo_menu = QMenu(self)
        action = QWidgetAction(self._undo_menu)
        action.setDefaultWidget(self._undo_view)
        self._undo_menu.addAction(action)

        self._orig_point = None
        self._item_to_draw = None
        self._item_old_pos = None
        self._item_old_line_or_rect = None
        self._mode = None
        self._dialog = None
        self.setDragMode(QGraphicsView.RubberBandDrag)
Exemplo n.º 9
0
class UndoDock(QDockWidget):
    def __init__(self, undoGroup, parent=None):
        super().__init__(parent)

        self.setObjectName("undoViewDock")
        self.mUndoView = QUndoView(undoGroup, self)
        cleanIcon = QIcon(":images/16x16/drive-harddisk.png")
        self.mUndoView.setCleanIcon(cleanIcon)
        self.mUndoView.setUniformItemSizes(True)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(self.mUndoView)
        self.setWidget(widget)
        self.retranslateUi()

    def changeEvent(self, e):
        super().changeEvent(e)
        x = e.type()
        if x == QEvent.LanguageChange:
            self.retranslateUi()
        else:
            pass

    def retranslateUi(self):
        self.setWindowTitle(self.tr("History"))
        self.mUndoView.setEmptyLabel(self.tr("<empty>"))
Exemplo n.º 10
0
class UndoDock(QDockWidget):

    def __init__(self, undoGroup, parent = None):
        super().__init__(parent)

        self.setObjectName("undoViewDock")
        self.mUndoView = QUndoView(undoGroup, self)
        cleanIcon = QIcon(":images/16x16/drive-harddisk.png")
        self.mUndoView.setCleanIcon(cleanIcon)
        self.mUndoView.setUniformItemSizes(True)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(self.mUndoView)
        self.setWidget(widget)
        self.retranslateUi()

    def changeEvent(self, e):
        super().changeEvent(e)
        x = e.type()
        if x==QEvent.LanguageChange:
            self.retranslateUi()
        else:
            pass

    def retranslateUi(self):
        self.setWindowTitle(self.tr("History"))
        self.mUndoView.setEmptyLabel(self.tr("<empty>"))
Exemplo n.º 11
0
    def __init__(self, undoGroup, parent = None):
        super().__init__(parent)

        self.setObjectName("undoViewDock")
        self.mUndoView = QUndoView(undoGroup, self)
        cleanIcon = QIcon(":images/16x16/drive-harddisk.png")
        self.mUndoView.setCleanIcon(cleanIcon)
        self.mUndoView.setUniformItemSizes(True)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(self.mUndoView)
        self.setWidget(widget)
        self.retranslateUi()
Exemplo n.º 12
0
 def nf2_mw(x2_mw):
     np2_acs(x2_mw)
     self.wu_mb = nf2_mb(x2_mw.menuBar())
     self.wu_us = nf2_us(QUndoStack())
     self.wu_uv = nf2_uv(x2_mw, QUndoView(self.wu_us))
     self.wu_ds = nf2_ds(WDiagramScene())
     x2_mw.setWindowTitle(GC_APP_NM)
     x2_mw.showEvent = lambda _: self.wn_on_shown()
     x2_mw.closeEvent = lambda _: self.wn_on_quit()
     x2_mw.setCentralWidget(QGraphicsView(self.wu_ds))
     x2_mw.resize(710, 590)
     x2_mw.show()
     x2_mw.raise_()
     return x2_mw
Exemplo n.º 13
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Pangolin")
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.setGeometry(50, 50, 1200, 675)

        # Models and Views
        self.interface = PangoModelSceneInterface()

        self.tree_view = QTreeView()
        self.tree_view.setUniformRowHeights(True)
        self.tree_view.setModel(self.interface.model)
        self.interface.set_tree(self.tree_view)

        self.graphics_view = PangoGraphicsView()
        self.graphics_view.setScene(self.interface.scene)

        self.undo_view = QUndoView()

        # Dock widgets
        self.label_widget = PangoLabelWidget("Labels", self.tree_view)
        self.undo_widget = PangoUndoWidget("History", self.undo_view)
        self.file_widget = PangoFileWidget("Files")

        # Menu and toolbars
        self.menu_bar = PangoMenuBarWidget()
        self.tool_bar = PangoToolBarWidget()
        self.tool_bar.set_scene(self.interface.scene)
        self.tool_bar.label_select.setModel(self.interface.model)

        # Signals and Slots
        self.menu_bar.open_images_action.triggered.connect(self.load_images)
        self.menu_bar.export_action.triggered.connect(self.export_project)
        self.menu_bar.import_action.triggered.connect(self.import_project)
        self.menu_bar.save_project_action.triggered.connect(self.save_project)

        self.file_widget.file_view.selectionModel().currentChanged.connect(
            self.switch_image)
        self.file_widget.file_model.directoryLoaded.connect(
            self.after_loaded_images)
        self.tool_bar.label_select.currentIndexChanged.connect(
            self.interface.switch_label)
        self.tool_bar.del_labels_signal.connect(self.interface.del_labels)

        # Layouts
        self.bg = QWidget()
        self.setCentralWidget(self.bg)

        self.bg_layout = QVBoxLayout(self.bg)
        self.bg_layout.setContentsMargins(0, 0, 0, 0)
        self.bg_layout.setSpacing(0)
        self.bg_layout.addWidget(self.tool_bar)
        self.bg_layout.addWidget(self.graphics_view)

        self.addDockWidget(Qt.RightDockWidgetArea, self.label_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, self.undo_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.file_widget)

        self.addToolBar(Qt.TopToolBarArea, self.menu_bar)

        # Shortcuts
        self.sh_reset_tool = QShortcut(QKeySequence('Esc'), self)
        self.sh_reset_tool.activated.connect(self.tool_bar.reset_tool)

        self.sh_inc_tool_size = QShortcut(
            QKeySequence(Qt.SHIFT + Qt.Key_Underscore), self)
        self.sh_inc_tool_size.activated.connect(
            lambda: self.tool_bar.set_tool_size(1, additive=True))

        self.sh_dec_tool_size = QShortcut(
            QKeySequence(Qt.SHIFT + Qt.Key_Equal), self)
        self.sh_dec_tool_size.activated.connect(
            lambda: self.tool_bar.set_tool_size(-1, additive=True))

        self.sh_select_next_image = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Down), self)
        self.sh_select_next_image.activated.connect(
            self.file_widget.select_next_image)

        self.sh_select_prev_image = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Up), self)
        self.sh_select_prev_image.activated.connect(
            self.file_widget.select_prev_image)

        self.sh_select_next_label = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Right), self)
        self.sh_select_next_label.activated.connect(
            self.tool_bar.label_select.select_next_label)

        self.sh_select_prev_label = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Left), self)
        self.sh_select_prev_label.activated.connect(
            self.tool_bar.label_select.select_prev_label)

        self.sh_undo = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Z), self)
        self.sh_undo.activated.connect(self.undo_widget.undo)

        self.sh_redo = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Y), self)
        self.sh_redo.activated.connect(self.undo_widget.redo)

    def switch_image(self, c_idx, p_idx):
        c_fpath = self.file_widget.file_model.filePath(c_idx)
        p_fpath = self.file_widget.file_model.filePath(p_idx)

        self.interface.scene.set_fpath(c_fpath)
        self.interface.scene.reset_com()
        self.graphics_view.fitInView(self.interface.scene.sceneRect(),
                                     Qt.KeepAspectRatio)

        # Handling unsaved changes
        if c_fpath not in self.interface.scene.change_stacks.keys():
            self.interface.scene.change_stacks[c_fpath] = QUndoStack()
        self.undo_view.setStack(self.interface.scene.change_stacks[c_fpath])
        self.interface.scene.stack = self.interface.scene.change_stacks[
            c_fpath]
        self.interface.filter_tree(c_fpath, p_fpath)

    def load_images(self, action=None, fpath=None):
        if fpath is None:
            dialog = QFileDialog()
            dialog.setFileMode(QFileDialog.DirectoryOnly)
            fpath = QFileDialog.getExistingDirectory()

        if fpath != "":
            self.file_widget.file_model.setRootPath(fpath)
            root_idx = self.file_widget.file_model.index(fpath)
            self.file_widget.file_view.setRootIndex(root_idx)
            self.images_are_new = True

    def after_loaded_images(self):
        if self.images_are_new is True:
            folder_path = self.file_widget.file_model.rootPath()
            for f in sorted(os.listdir(folder_path)):
                if f.endswith(".jpg") or f.endswith(".png"):
                    idx = self.file_widget.file_model.index(
                        os.path.join(folder_path, f))
                    self.file_widget.file_view.setCurrentIndex(idx)
                    break

            self.file_widget.file_view.scrollToTop()
            self.load_project()
            self.images_are_new = False

    def save_project(self, action=None, project_path=None):
        if project_path is None:
            project_path = os.path.join(self.file_widget.file_model.rootPath(),
                                        "pangolin_project.p")

        pickle_items = []
        for k in self.interface.map.keys():
            pickle_items.append(
                self.interface.model.itemFromIndex(QModelIndex(k)))
        pickle.dump(pickle_items, open(project_path, "wb"))

    def load_project(self, action=None, project_path=None):
        if project_path is None:
            project_path = os.path.join(self.file_widget.file_model.rootPath(),
                                        "pangolin_project.p")

        if os.path.exists(project_path):
            self.clear_project()

            unpickled_items = pickle.load(open(project_path, "rb"))
            for item in unpickled_items:
                if item.parent() is None:
                    self.interface.model.appendRow(item)
                item.force_update()

            self.interface.filter_tree(self.interface.scene.fpath, None)

    def clear_project(self, action=None, show_dialog=True):
        self.interface.map.clear()
        self.interface.model.clear()
        self.interface.scene.full_clear()

    def export_project(self, action=None):
        folder_path = self.file_widget.file_model.rootPath()
        fpaths = self.interface.scene.change_stacks.keys()

        dialog = ExportSettingsDialog(self, fpaths)
        if dialog.exec():
            s_fpaths = dialog.selected_fnames()
            file_format = dialog.file_format()

            if file_format == "PascalVOC (XML)":
                for fpath in s_fpaths:
                    pascal_voc_write(self.interface, fpath)

            elif file_format == "COCO (JSON)":
                #export_fpath, _ = QFileDialog().getSaveFileName(
                #    self, "Save Project", os.path.join(default, "annotations.xml"),
                #    "XML files (*.xml)")
                pass

            elif file_format == "YOLOv3 (TXT)":
                for fpath in s_fpaths:
                    yolo_write(self.interface, fpath)

            elif file_format == "Image Mask (PNG)":
                mask_folder = os.path.join(folder_path, "Masks")
                if not os.path.exists(mask_folder):
                    os.mkdir(mask_folder)
                for fpath in s_fpaths:
                    idx = self.file_widget.file_model.index(fpath)
                    self.file_widget.file_view.setCurrentIndex(idx)
                    image_mask_write(self.interface, fpath, mask_folder)

        self.interface.filter_tree(self.interface.scene.fpath, None)

    def import_project(self, action=None, folder=None):
        if folder is None:
            folder = self.file_widget.file_model.rootPath()
        fpaths = []
        for fname in os.listdir(folder):
            pre, ext = os.path.splitext(fname)
            if ext in (".xml", ".txt"):
                fpaths.append(os.path.join(folder, fname))
        if fpaths == []:
            return

        dialog = ImportSettingsDialog(self, fpaths)
        if dialog.exec():
            s_fpaths = dialog.selected_fnames()

            for fpath in s_fpaths:
                pre, ext = os.path.splitext(fpath)
                if ext == ".xml":  # PascalVOC (XML)
                    pascal_voc_read(self.interface, fpath)
                elif ext == ".txt":
                    yolo_read(self.interface, fpath)

    def unsaved_files_dialog(self):
        #if pfile != "":
        #    # Save changes?
        #    if self.interface.map:
        #        result = self.unsaved_files_dialog()
        #        if result == QMessageBox.Cancel:
        #            return
        #        elif result == QMessageBox.Save:
        #            self.save_project()

        dialog = QMessageBox()
        dialog.setText("The project has been modified.")
        dialog.setInformativeText("Do you want to save your changes?")
        dialog.setStandardButtons(QMessageBox.Save | QMessageBox.Discard
                                  | QMessageBox.Cancel)
        dialog.setDefaultButton(QMessageBox.Save)
        return dialog.exec()

    def unsaved_commands_dialog(self):
        res = QMessageBox().question(
            self.parent(), "Unsaved shape commands",
            "Command history will be cleaned, are you sure you want to continue?"
        )
        if res == QMessageBox.Yes:
            for stack in self.interface.scene.change_stacks.values():
                stack.clear()
        return res

    def export_warning_dialog(self):
        pass
Exemplo n.º 14
0
 def addUndoView(self, stack):
     view = QUndoView(stack)
     self.stackedWidget.addWidget(view)
     return view
Exemplo n.º 15
0
 def createUndoView(self, parent):
     # creates an undo stack view for current QGraphicsScene
     undoView = QUndoView(self.undoStack, parent)
     showUndoDialog(undoView, parent)
Exemplo n.º 16
0
 def setContent(self, widget):
     self.clear()
     undoview = QUndoView(widget.history, self)
     undoview.setEmptyLabel(_("<Original file>"))
     self.layout().addWidget(undoview)
Exemplo n.º 17
0
class AnnotationsNetworkView(NetworkView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._undo_stack = QUndoStack(self)
        self._undo_view = QUndoView(self._undo_stack)
        self._undo_view.setCleanIcon(QIcon(":/icons/images/document-save.svg"))
        self._undo_menu = QMenu(self)
        action = QWidgetAction(self._undo_menu)
        action.setDefaultWidget(self._undo_view)
        self._undo_menu.addAction(action)

        self._orig_point = None
        self._item_to_draw = None
        self._item_old_pos = None
        self._item_old_line_or_rect = None
        self._mode = None
        self._dialog = None
        self.setDragMode(QGraphicsView.RubberBandDrag)

    def setScene(self, scene: AnnotationsNetworkScene):
        scene.editAnnotationItemRequested.connect(
            self.on_edit_annotation_item_requested)
        self._undo_stack.clear()
        super().setScene(scene)

    def addAnnotationItem(self, item: QGraphicsItem, pos: QPointF):
        scene = self.scene()
        if scene is None:
            return

        if isinstance(item, (ArrowItem, RectItem, EllipseItem)):
            item.setPen(
                QPen(Qt.black, scene.getDefaultPenSizeFromRect(),
                     Qt.SolidLine))

        self._undo_stack.push(AddCommand(item, scene))
        item.setPos(pos)
        scene.annotationAdded.emit(item)

        return item

    def addAnnotationLine(self, line: QLineF,
                          pos: QPointF) -> Union[ArrowItem, None]:
        return self.addAnnotationArrow(line, pos, False, False)

    def addAnnotationArrow(self,
                           line: QLineF,
                           pos: QPointF,
                           has_head=True,
                           has_tail=False) -> Union[ArrowItem, None]:
        item = ArrowItem(line, has_head=has_head, has_tail=has_tail)
        return self.addAnnotationItem(item, pos)

    def addAnnotationRect(self, rect: QRectF,
                          pos: QPointF) -> Union[RectItem, None]:
        return self.addAnnotationItem(RectItem(rect), pos)

    def addAnnotationEllipse(
            self, rect: QRectF,
            pos: QPointF) -> Union[QGraphicsEllipseItem, None]:
        return self.addAnnotationItem(EllipseItem(rect), pos)

    def addAnnotationText(self, text: str, font: QFont,
                          pos: QPointF) -> Union[TextItem, None]:
        item = TextItem(text)
        item.setFont(font)
        return self.addAnnotationItem(item, pos)

    def setDrawMode(self, mode):
        self._mode = mode
        if mode is None:
            self.setDragMode(QGraphicsView.RubberBandDrag)
            self._orig_point = None
        else:
            self.setDragMode(QGraphicsView.NoDrag)

    def mode(self):
        return self._mode

    def undoView(self):
        return self._undo_view

    def undoStack(self):
        return self._undo_stack

    def undoMenu(self):
        return self._undo_menu

    def loadAnnotations(self, buffer: bytes) -> None:
        if not buffer:
            return

        scene = self.scene()
        if scene is None:
            return

        def read(len):
            nonlocal buffer, pos
            data = buffer[pos:pos + len]
            pos += len
            return data

        pos = 0
        data = read(1)

        while data:
            if data in (b'L', b'A'):
                x1, y1, x2, y2 = struct.unpack("ffff", read(16))
                line = QLineF(0., 0., x2, y2)
                if data == b'L':
                    self.addAnnotationLine(line, QPointF(x1, y1))
                elif data == b'A':
                    data, = struct.unpack("B", read(1))
                    has_head = (data >> 0) & 1
                    has_tail = (data >> 1) & 1
                    self.addAnnotationArrow(line, QPointF(x1, y1), has_head,
                                            has_tail)
            elif data in (b'R', b'C'):
                x, y, w, h = struct.unpack("ffff", read(16))
                rect = QRectF(0., 0., w, h)
                if data == b'R':
                    self.addAnnotationRect(rect, QPointF(x, y))
                elif data == b'C':
                    self.addAnnotationEllipse(rect, QPointF(x, y))
            elif data == b'T':
                x, y, len = struct.unpack("ffH", read(10))
                text = read(len).decode()
                font_size, = struct.unpack("H", read(2))
                font = QFont()
                font.setPointSize(font_size)
                self.addAnnotationText(text, font, QPointF(x, y))

            data = read(1)

        self._undo_stack.setClean()

    def saveAnnotations(self) -> bytes:
        scene = self.scene()
        if scene is None:
            return b''

        buffer = b''
        for item in scene.items():
            if isinstance(item, ArrowItem):
                char = b'A' if item.hasHead() or item.hasTail() else b'L'
                line = item.line()
                pos = item.pos()
                buffer += char
                buffer += struct.pack("ffff", pos.x(), pos.y(), line.x2(),
                                      line.y2())
                if char == b'A':
                    buffer += struct.pack("B",
                                          item.hasHead() + item.hasTail() * 2)
            elif isinstance(item, (RectItem, EllipseItem)):
                char = b'R' if isinstance(item, RectItem) else b'C'
                rect = item.rect()
                pos = item.pos()
                buffer += char
                buffer += struct.pack("ffff", pos.x(), pos.y(), rect.width(),
                                      rect.height())
            elif isinstance(item, TextItem):
                pos = item.pos()
                text = item.text()
                font = item.font()
                buffer += b'T'
                buffer += struct.pack("ff", pos.x(), pos.y())
                buffer += struct.pack("H", len(text))
                buffer += str.encode(text)
                buffer += struct.pack("H", font.pointSize())

        return buffer

    def deleteSelectedAnnotations(self):
        scene = self.scene()
        if scene is None:
            return

        for item in scene.annotationsLayer.childItems():
            if item.isSelected():
                self._undo_stack.push(DeleteCommand(item, self))

    def on_edit_annotation_item_requested(self, item: QGraphicsItem):
        # Edit text item
        if isinstance(item, TextItem):

            def edit_text_item(result):
                if result == QDialog.Accepted:
                    old_text = item.text()
                    old_font = item.font()
                    text, font_size = self._dialog.getValues()
                    font = QFont()
                    font.setPointSize(font_size)
                    item.setText(text)
                    item.setFont(font)
                    self._undo_stack.push(
                        EditTextCommand(item, old_text, old_font.pointSize(),
                                        self.scene()))

            self._dialog = TextItemInputDialog(self)
            self._dialog.setValues(item.text(), item.font().pointSize())
            self._dialog.finished.connect(edit_text_item)
            self._dialog.open()

    def mouseDoubleClickEvent(self, event: QMouseEvent) -> None:
        scene = self.scene()
        if scene:
            if self._mode is None or self._mode == MODE_TEXT:
                item = self.itemAt(event.pos())

                if self._mode is None:
                    self.on_edit_annotation_item_requested(item)

                # Add a text item at mouse position
                elif self._mode == MODE_TEXT:

                    def add_text_item(result):
                        if result == QDialog.Accepted:
                            text, font_size = self._dialog.getValues()
                            font = QFont()
                            font.setPointSize(font_size)
                            self.addAnnotationText(text, font, pos)

                    pos = self.mapToScene(event.pos())
                    self._dialog = TextItemInputDialog(self)
                    self._dialog.setValues("",
                                           scene.getDefaultFontSizeFromRect())
                    self._dialog.finished.connect(add_text_item)
                    self._dialog.open()
        else:
            super().mouseDoubleClickEvent(event)

    def mousePressEvent(self, event: QMouseEvent) -> None:
        scene = self.scene()
        if scene:
            # Edit item (line, rect, ellipse, etc)
            if self._mode is None:
                self._item_to_draw = item = self.itemAt(event.pos())
                if item:
                    self._item_old_pos = item.pos()
                    event_pos = self.mapToScene(event.pos()) - item.pos()

                    # Edit Arrows head and tails
                    if isinstance(item, ArrowItem) and event.modifiers(
                    ) & Qt.ShiftModifier == Qt.ShiftModifier:
                        tol = item.pen().width() * 2.
                        if (event_pos -
                                item.line().p1()).manhattanLength() < tol:
                            has_tail = item.hasTail()
                            item.setTail(not has_tail)
                            self._undo_stack.push(
                                EditArrowCommand(item, has_tail,
                                                 item.hasHead(), self.scene()))
                            scene.arrowEdited.emit(item)
                        elif (event_pos -
                              item.line().p2()).manhattanLength() < tol:
                            has_head = item.hasHead()
                            item.setHead(not has_head)
                            self._undo_stack.push(
                                EditArrowCommand(item, item.hasTail(),
                                                 has_head, self.scene()))
                            scene.arrowEdited.emit(item)

                    # Resize Line and Arrow
                    if isinstance(item, ArrowItem):
                        tol = item.pen().width() * 2.
                        self._item_old_line_or_rect = item.line()
                        if (event_pos -
                                item.line().p1()).manhattanLength() < tol:
                            self._orig_point = item.line().p2() + item.pos()
                        elif (event_pos -
                              item.line().p2()).manhattanLength() < tol:
                            self._orig_point = item.line().p1() + item.pos()

                    # Resize Rect and Ellipse
                    elif isinstance(item, (EllipseItem, RectItem)):
                        self._item_old_line_or_rect = item.rect()
                        tol = item.pen().width()
                        if (event_pos -
                                item.rect().topLeft()).manhattanLength() < tol:
                            self._orig_point = item.rect().bottomRight(
                            ) + item.pos()
                        elif (event_pos - item.rect().bottomRight()
                              ).manhattanLength() < tol:
                            self._orig_point = item.rect().topLeft(
                            ) + item.pos()
                        elif (event_pos -
                              item.rect().topRight()).manhattanLength() < tol:
                            self._orig_point = item.rect().bottomLeft(
                            ) + item.pos()
                        elif (event_pos - item.rect().bottomLeft()
                              ).manhattanLength() < tol:
                            self._orig_point = item.rect().topRight(
                            ) + item.pos()

            # Define starting point of item (line, rect, ellipse, etc)
            elif self._mode != MODE_TEXT:
                self._orig_point = self.mapToScene(event.pos())

        super().mousePressEvent(event)

    def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
        scene = self.scene()
        if scene and self._orig_point is not None:
            # Edit line or arrow
            if self._mode in (MODE_LINE, MODE_ARROW) \
                    or (self._mode is None and isinstance(self._item_to_draw, QGraphicsLineItem)):
                pos = self.mapToScene(event.pos())
                x = pos.x() - self._orig_point.x()
                y = pos.y() - self._orig_point.y()
                if self._item_to_draw and self._orig_point == self._item_to_draw.line(
                ).p2() + self._item_to_draw.pos():
                    # Moving line around head
                    line = QLineF(0, 0, -x, -y)
                    point = pos
                else:
                    line = QLineF(0, 0, x, y)
                    point = None

                if self._item_to_draw is None:
                    if self._mode == MODE_LINE:
                        self._item_to_draw = self.addAnnotationLine(
                            line, self._orig_point)
                    elif self._mode == MODE_ARROW:
                        self._item_to_draw = self.addAnnotationArrow(
                            line, self._orig_point)
                else:
                    self._item_to_draw.setLine(line)
                    if point is not None:
                        self._item_to_draw.setPos(point)
                return

            # Edit rect or circle
            elif self._mode in (MODE_RECT, MODE_ELLIPSE) \
                    or (self._mode is None and isinstance(self._item_to_draw, (RectItem, EllipseItem))):
                pos = self.mapToScene(event.pos())
                width = pos.x() - self._orig_point.x()
                height = pos.y() - self._orig_point.y()
                dx = 0 if width >= 0 else width
                dy = 0 if height >= 0 else height
                rect = QRectF(0, 0, abs(width), abs(height))
                point = self._orig_point + QPointF(dx, dy)
                if self._item_to_draw is None:
                    if self._mode == MODE_RECT:
                        self._item_to_draw = self.addAnnotationRect(
                            rect, point)
                    elif self._mode == MODE_ELLIPSE:
                        self._item_to_draw = self.addAnnotationEllipse(
                            rect, point)
                else:
                    self._item_to_draw.setRect(rect)
                    self._item_to_draw.setPos(point)
                return

        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
        if self._mode is None and self._item_to_draw is not None and event.button(
        ) == Qt.LeftButton:
            if isinstance(self._item_old_line_or_rect, QRectF):
                line_or_rect = self._item_to_draw.rect()
            elif isinstance(self._item_old_line_or_rect, QLineF):
                line_or_rect = self._item_to_draw.line()
            else:
                line_or_rect = None

            if line_or_rect is None or self._item_old_line_or_rect == line_or_rect:
                if self._item_old_pos != self._item_to_draw.pos():
                    self._undo_stack.push(
                        MoveCommand(self._item_to_draw, self._item_old_pos,
                                    self.scene()))
            else:
                self._undo_stack.push(
                    ResizeCommand(self._item_to_draw, self._item_old_pos,
                                  self._item_old_line_or_rect, self.scene()))
        self._item_old_pos = None
        self._item_old_line_or_rect = None
        self._item_to_draw = None
        self._orig_point = None
        super().mouseReleaseEvent(event)
Exemplo n.º 18
0
    def __init__(self, parent = None):
        super().__init__(parent)

        self.setWindowIcon(QtGui.QIcon(paths.ICON_PATH))
        if settings.FRAMELESS.get_value():
            self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)

        self._notification_frame = NotificationFrame(self)

        self.setWindowTitle(values.APPLICATION_NAME)

        self.layout().setContentsMargins(0, 0, 0, 0)

        self._printing_view = CubeableView(self)
        Context.focus_card_changed.connect(self._printing_view.new_cubeable)

        self._rating_view = RatingView()
        Context.focus_card_changed.connect(self._rating_view.on_focus_event)

        self._login_status_label = QtWidgets.QLabel('')
        LOGIN_CONTROLLER.login_success.connect(lambda u, h: self._login_status_label.setText(f'{u.username}@{h}'))
        LOGIN_CONTROLLER.login_failed.connect(lambda e: self._login_status_label.setText(''))
        LOGIN_CONTROLLER.login_terminated.connect(lambda: self._login_status_label.setText(''))
        LOGIN_CONTROLLER.login_pending.connect(lambda u, h: self._login_status_label.setText(f'logging in @ {h}'))

        self.statusBar().setContentsMargins(10, 0, 10, 0)
        self.statusBar().addPermanentWidget(self._login_status_label)
        Context.status_message.connect(lambda m, _t: self.statusBar().showMessage(m, _t))

        self.statusBar().addPermanentWidget(QtWidgets.QLabel(version_formatted()))

        self._card_view_dock = Dock('Card View', 'card_view_dock', self, self._printing_view, wants_focus = False)
        Context.focus_freeze_changed.connect(
            lambda frozen: self._card_view_dock.setWindowTitle(
                'Card View'
                + (' (frozen)' if frozen else '')
            )
        )

        self._rating_view_dock = Dock('Rating View', 'rating_view_dock', self, self._rating_view, wants_focus = False)
        Context.focus_freeze_changed.connect(
            lambda frozen: self._rating_view_dock.setWindowTitle(
                'Rating View'
                + (' (frozen)' if frozen else '')
            )
        )

        self._card_adder = PrintingSelector(self)
        self._card_adder.add_printings.connect(self._on_add_printings)

        self._card_adder_dock = Dock('Card Adder', 'card adder dock', self, self._card_adder)

        self._undo_view = QUndoView(Context.undo_group)

        self._undo_view_dock = Dock('Undo View', 'undo view dock', self, self._undo_view)

        self._lobby_view = LobbiesView(
            LobbyModelClientConnection()
        )
        self._lobby_view_dock = Dock(
            'Lobby View',
            'lobbies',
            self,
            self._lobby_view,
            allowed_areas = QtCore.Qt.RightDockWidgetArea
                            | QtCore.Qt.LeftDockWidgetArea
                            | QtCore.Qt.BottomDockWidgetArea,
        )

        self._cube_view_minimap = GraphicsMiniView()
        Context.focus_scene_changed.connect(lambda scene: self._cube_view_minimap.set_scene(scene))

        self._cube_view_minimap_dock = Dock('Minimap', 'minimap', self, self._cube_view_minimap, wants_focus = False)

        self._limited_sessions_view = LimitedSessionsView()

        self._limited_sessions_dock = Dock('Limited', 'Limited', self, self._limited_sessions_view)

        self._matches_view = ScheduledMatchesView()

        self._matches_view_dock = Dock('Matches', 'Matches', self, self._matches_view)

        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self._card_adder_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._card_view_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._rating_view_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._undo_view_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._lobby_view_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._cube_view_minimap_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._limited_sessions_dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self._matches_view_dock)

        self._card_view_dock.hide()
        self._rating_view_dock.hide()
        self._card_adder_dock.hide()
        self._undo_view_dock.hide()
        self._lobby_view_dock.hide()
        self._cube_view_minimap_dock.hide()
        self._limited_sessions_dock.hide()
        self._matches_view_dock.hide()

        self._main_view = MainView(self)

        self.setCentralWidget(self._main_view)

        menu_bar = self.menuBar()

        all_menus = [
            (
                menu_bar.addMenu('File'),
                (
                    ('New Deck', 'Ctrl+N', self._new_deck),
                    ('Open Deck', 'Ctrl+O', lambda: self.open(Deck)),
                    ('Open Pool', 'Ctrl+P', lambda: self.open(Pool)),
                    ('Save', 'Ctrl+S', self._save),
                    ('Save As', 'Ctrl+Shift+S', self._save_as),
                    ('Export Deck', 'Ctrl+Shift+E', self._export_deck),
                    ('Close Tab', 'Ctrl+W', self._close_tab),
                    'line',
                    ('Exit', 'Ctrl+Q', self.close),

                ),
            ),
            (
                menu_bar.addMenu('Edit'),
                (
                    ('Undo', 'Ctrl+Z', Context.undo_group.undo),
                    ('Redo', 'Ctrl+Shift+Z', Context.undo_group.redo),
                    'line',
                    ('Add cards', 'Ctrl+F', self._add_cards),
                    ('Sort Macroes', 'Ctrl+M', self._edit_sort_macroes),
                ),
            ),
            (
                menu_bar.addMenu('View'),
                (
                    ('Card View', 'Meta+1', lambda: self._toggle_dock_view(self._card_view_dock)),
                    ('Card Adder', 'Meta+2', lambda: self._toggle_dock_view(self._card_adder_dock)),
                    ('Limited', 'Meta+3', lambda: self._toggle_dock_view(self._limited_sessions_dock)),
                    ('Lobbies', 'Meta+4', lambda: self._toggle_dock_view(self._lobby_view_dock)),
                    ('Matches', 'Meta+5', lambda: self._toggle_dock_view(self._matches_view_dock)),
                    ('Rating', 'Meta+6', lambda: self._toggle_dock_view(self._rating_view_dock)),
                    ('Undo', None, lambda: self._toggle_dock_view(self._undo_view_dock)),
                    ('Minimap', None, lambda: self._toggle_dock_view(self._cube_view_minimap_dock)),
                ),
            ),
            (
                menu_bar.addMenu('Connect'),
                (
                    ('Login', 'Ctrl+L', LoginDialog(self).exec_),
                    ('Logout', None, LOGIN_CONTROLLER.log_out),
                ),
            ),
            (
                menu_bar.addMenu('Draft'),
                (
                    ('Go To Latest', 'Alt+Up', self._draft_history_wrapper('go_to_latest')),
                    ('Go Back', 'Alt+Left', self._draft_history_wrapper('go_backwards')),
                    ('Go Forward', 'Alt+Right', self._draft_history_wrapper('go_forward')),
                    ('Go To Start', 'Alt+Down', self._draft_history_wrapper('go_to_start')),
                ),
            ),
            (
                menu_bar.addMenu('Simulate'),
                (
                    ('Sample Hand', 'Ctrl+H', self._sample_hand),
                )
            ),
            (
                menu_bar.addMenu('Preferences'),
                (
                    ('Settings', 'Ctrl+Alt+S', lambda: SettingsDialog.get().exec_()),
                ),
            ),
            (
                menu_bar.addMenu('DB'),
                (
                    ('Info', None, lambda: DBInfoDialog().exec_()),
                    ('Update', None, lambda: DBUpdateDialog().exec_()),
                    ('Validate', None, lambda: LOGIN_CONTROLLER.validate(True)),
                ),
            ),
            (
                menu_bar.addMenu('Help'),
                (
                    ('About', None, lambda: AboutDialog().exec_()),
                ),
            ),
        ]

        if Context.debug:
            all_menus.append(
                (
                    menu_bar.addMenu('Test'),
                    (
                        ('Test', 'Ctrl+T', self._test),
                    ),
                )
            )

        for menu, lines in all_menus:
            for line in lines:
                if line == 'line':
                    menu.addSeparator()
                else:
                    name, shortcut, action = line
                    _action = QAction(name, self)
                    if shortcut:
                        _action.setShortcut(shortcut)
                    _action.triggered.connect(action)
                    menu.addAction(_action)

        self._create_action('toggle freeze focus', Context.toggle_frozen_focus, 'Alt+F')

        self._reset_dock_width = 500
        self._reset_dock_height = 1200

        self.resizeDocks([self._card_view_dock], [self._reset_dock_width], QtCore.Qt.Horizontal)

        Context.notification_message.connect(self._notification_frame.notify)
        Context.draft_started.connect(self._on_draft_started)

        self._load_state()
Exemplo n.º 19
0
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Pangolin")
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.setGeometry(50, 50, 1200, 675)

        # Models and Views
        self.interface = PangoModelSceneInterface()

        self.tree_view = QTreeView()
        self.tree_view.setUniformRowHeights(True)
        self.tree_view.setModel(self.interface.model)
        self.interface.set_tree(self.tree_view)

        self.graphics_view = PangoGraphicsView()
        self.graphics_view.setScene(self.interface.scene)

        self.undo_view = QUndoView()

        # Dock widgets
        self.label_widget = PangoLabelWidget("Labels", self.tree_view)
        self.undo_widget = PangoUndoWidget("History", self.undo_view)
        self.file_widget = PangoFileWidget("Files")

        # Menu and toolbars
        self.menu_bar = PangoMenuBarWidget()
        self.tool_bar = PangoToolBarWidget()
        self.tool_bar.set_scene(self.interface.scene)
        self.tool_bar.label_select.setModel(self.interface.model)

        # Signals and Slots
        self.menu_bar.open_images_action.triggered.connect(self.load_images)
        self.menu_bar.export_action.triggered.connect(self.export_project)
        self.menu_bar.import_action.triggered.connect(self.import_project)
        self.menu_bar.save_project_action.triggered.connect(self.save_project)

        self.file_widget.file_view.selectionModel().currentChanged.connect(
            self.switch_image)
        self.file_widget.file_model.directoryLoaded.connect(
            self.after_loaded_images)
        self.tool_bar.label_select.currentIndexChanged.connect(
            self.interface.switch_label)
        self.tool_bar.del_labels_signal.connect(self.interface.del_labels)

        # Layouts
        self.bg = QWidget()
        self.setCentralWidget(self.bg)

        self.bg_layout = QVBoxLayout(self.bg)
        self.bg_layout.setContentsMargins(0, 0, 0, 0)
        self.bg_layout.setSpacing(0)
        self.bg_layout.addWidget(self.tool_bar)
        self.bg_layout.addWidget(self.graphics_view)

        self.addDockWidget(Qt.RightDockWidgetArea, self.label_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, self.undo_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.file_widget)

        self.addToolBar(Qt.TopToolBarArea, self.menu_bar)

        # Shortcuts
        self.sh_reset_tool = QShortcut(QKeySequence('Esc'), self)
        self.sh_reset_tool.activated.connect(self.tool_bar.reset_tool)

        self.sh_inc_tool_size = QShortcut(
            QKeySequence(Qt.SHIFT + Qt.Key_Underscore), self)
        self.sh_inc_tool_size.activated.connect(
            lambda: self.tool_bar.set_tool_size(1, additive=True))

        self.sh_dec_tool_size = QShortcut(
            QKeySequence(Qt.SHIFT + Qt.Key_Equal), self)
        self.sh_dec_tool_size.activated.connect(
            lambda: self.tool_bar.set_tool_size(-1, additive=True))

        self.sh_select_next_image = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Down), self)
        self.sh_select_next_image.activated.connect(
            self.file_widget.select_next_image)

        self.sh_select_prev_image = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Up), self)
        self.sh_select_prev_image.activated.connect(
            self.file_widget.select_prev_image)

        self.sh_select_next_label = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Right), self)
        self.sh_select_next_label.activated.connect(
            self.tool_bar.label_select.select_next_label)

        self.sh_select_prev_label = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_Left), self)
        self.sh_select_prev_label.activated.connect(
            self.tool_bar.label_select.select_prev_label)

        self.sh_undo = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Z), self)
        self.sh_undo.activated.connect(self.undo_widget.undo)

        self.sh_redo = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Y), self)
        self.sh_redo.activated.connect(self.undo_widget.redo)
Exemplo n.º 20
0
    def __init__(self, debug=False):
        QMainWindow.__init__(self)
        # initialise filename
        self.filename = None
        # make the data store
        from .xmlstore import Store
        self.store = Store(debug = debug)
        # view the current table
        self.tableView = TableView(self)
        #self.tableView.setDragEnabled(True);
        #self.tableView.setDragDropMode(QAbstractItemView.InternalMove)
        #self.tableView.setAcceptDrops(True);
        #self.tableView.setDropIndicatorShown(True);
        self.tableView.verticalHeader().sectionMoved.connect(self.sectionMoved)
        self.tableView.verticalHeader().setSectionsMovable(True)

        self.setCentralWidget(self.tableView)
        # add a custom delegate to it
        self.delegate = ComboBoxDelegate()
        self.tableView.setItemDelegate(self.delegate)
        # dock the table selection on the left
        self.dock1 = QDockWidget(self)
        self.listView = ListView(self)
        self.listView.setDragEnabled(True);
        self.listView.setDragDropMode(QAbstractItemView.InternalMove)
        self.listView.setDropIndicatorShown(True);
        self.dock1.setWidget(self.listView)
        self.dock1.setFeatures(
            QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock1)
        # connect it to the populate method
        self.listView.activated.connect(self.populate)
        self.listView.clicked.connect(self.populate)
        # dock the undoView on the left
        self.dock2 = QDockWidget(self)
        self.undoView = QUndoView(self.store.stack)
        self.dock2.setWidget(self.undoView)
        self.dock2.setFeatures(
            QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
        self.dock2.setWindowTitle('Undo Stack')
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock2)
        # create a menubar
        self.menu = self.menuBar()
        # create file menu headings
        self.menuFile = self.menu.addMenu('File')
        self.menuFile.addAction('New', self.New).setShortcut('CTRL+N')
        self.menuFile.addAction('Open...', self.Open).setShortcut('CTRL+O')
        self.menuFile.addAction('Reload', self.Reload)
        self.menuFile.addAction('Save', self.Save).setShortcut('CTRL+S')
        self.menuFile.addAction('Save As...', self.SaveAs)
        self.menuFile.addSeparator()
        self.menuFile.addAction('Set Architecture...', self.setArch)
        self.menuFile.addSeparator()
        self.menuFile.addAction('Quit', self.closeEvent).setShortcuts(['CTRL+Q', 'ALT+F4'])
        # create edit menu headings
        self.menuEdit = self.menu.addMenu('Edit')
        self.menuEdit.addAction('Insert Row',
            self.tableView.insertRow).setShortcut('CTRL+I')
        self.menuEdit.addAction('Insert Row Under',
            self.tableView.insertRowUnder).setShortcut('CTRL+U')
        self.menuEdit.addAction('Remove Row', self.tableView.removeRow)
        self.menuEdit.addSeparator()
        self.menuEdit.addAction('Cut',
            self.tableView.cut).setShortcut('CTRL+X')
        self.menuEdit.addAction('Copy',
            self.tableView.copy).setShortcuts(['CTRL+C', 'CTRL+INS'])
        self.menuEdit.addAction('Paste',
            self.tableView.paste).setShortcuts(['CTRL+V', 'SHIFT+INS'])
        self.menuEdit.addAction('Clear',
            self.tableView.menuClear).setShortcut('CTRL+D')
        self.menuEdit.addSeparator()
        self.menuEdit.addAction('Fill Cells',
            self.tableView.fillCells).setShortcut('CTRL+L')
        self.menuEdit.addAction('Fill Cells and Increment',
            self.tableView.fillCellsInc).setShortcut('CTRL+R')
        self.menuEdit.addAction('Python Code...',
            self.tableView.pythonCode).setShortcut('CTRL+P')
        self.tableView.codeBox = pythonCode()
        self.menuEdit.addSeparator()
        self.menuEdit.addAction('Undo', self.store.stack.undo).setShortcut('CTRL+Z')
        self.menuEdit.addAction('Redo', self.store.stack.redo).setShortcut('CTRL+SHIFT+Z')
        # create component menu
        self.menuComponents = self.menu.addMenu('Components')
        self.resize(QSize(1000,500))