class CollapsibleSection(QFrame):
    def __init__(self, header_text, init_collapsed=False, is_top=False):
        super().__init__()

        if not is_top:
            self.setObjectName("CollapsibleSection")
            self.setStyleSheet("#CollapsibleSection{border-top: 1px solid lightgrey;}")

        self._layout = QVBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self.setLayout(self._layout)
        self._header_widget = QWidget()
        self.body_widget = QWidget()
        self._layout.addWidget(self._header_widget)
        self._layout.addWidget(self.body_widget)

        self.grid = QGridLayout(self.body_widget)
        self.grid.setContentsMargins(9, 0, 9, 9)
        self.grid.setColumnStretch(0, 1)
        self.grid.setColumnStretch(1, 1)

        self._header_widget_layout = QHBoxLayout(self._header_widget)
        self._header_widget_layout.setContentsMargins(7, 7, 7, 7)
        self._header_widget.setLayout(self._header_widget_layout)

        self._button = QToolButton()
        self._button.setText(header_text)
        self._button.setCheckable(True)
        self._button.setStyleSheet("QToolButton { border: none; }")
        self._button.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
        self._button.pressed.connect(self.button_event)
        self.button_event(override=init_collapsed)
        self._header_widget_layout.addWidget(self._button)
        self._header_widget_layout.addStretch()

    def button_event(self, override=None):
        if override is None:
            checked = not self._button.isChecked()
        else:
            checked = override
            self._button.setChecked(checked)

        if checked:  # collapsed
            self._button.setArrowType(QtCore.Qt.ArrowType.RightArrow)
            self.body_widget.hide()
        else:
            self._button.setArrowType(QtCore.Qt.ArrowType.DownArrow)
            self.body_widget.show()
Esempio n. 2
0
class CollapsibleBox(QWidget):
    def __init__(self, title: str, bg_color: str, parent=None):
        super(CollapsibleBox, self).__init__(parent)

        self.setAutoFillBackground(True)
        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        style_sheet = "border: none;"
        style_sheet += "border-image: url(" + bg_color + ");"
        style_sheet += "font: bold 15px;"
        self.toggle_button.setStyleSheet(style_sheet)
        self.toggle_button.setToolButtonStyle(
            QtCore.Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(QtCore.Qt.RightArrow)
        self.toggle_button.setMinimumHeight(30)
        self.toggle_button.clicked.connect(self.on_clicked)

        self.content_area = QScrollArea()
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)
        self.content_area.setHidden(True)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.toggle_button)
        lay.addWidget(self.content_area)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            QtCore.Qt.DownArrow if checked else QtCore.Qt.RightArrow)
        if checked:
            self.content_area.setHidden(False)
        else:
            self.content_area.setHidden(True)

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        del lay
        self.content_area.setLayout(layout)
Esempio n. 3
0
class MainWindow(QMainWindow):
    def __init__(self, gui):
        super(MainWindow, self).__init__()
        self.gui = gui
        self.gateways = []
        self.welcome_dialog = None
        self.recovery_key_exporter = None

        self.setWindowTitle(APP_NAME)
        self.setMinimumSize(QSize(600, 400))
        self.setUnifiedTitleAndToolBarOnMac(True)

        self.shortcut_new = QShortcut(QKeySequence.New, self)
        self.shortcut_new.activated.connect(self.show_welcome_dialog)

        self.shortcut_open = QShortcut(QKeySequence.Open, self)
        self.shortcut_open.activated.connect(self.select_folder)

        self.shortcut_close = QShortcut(QKeySequence.Close, self)
        self.shortcut_close.activated.connect(self.close)

        self.shortcut_quit = QShortcut(QKeySequence.Quit, self)
        self.shortcut_quit.activated.connect(self.confirm_quit)

        self.central_widget = CentralWidget(self.gui)
        self.setCentralWidget(self.central_widget)

        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(11)
        else:
            font.setPointSize(8)

        folder_icon_default = QFileIconProvider().icon(QFileInfo(config_dir))
        folder_icon_composite = CompositePixmap(
            folder_icon_default.pixmap(256, 256), resource('green-plus.png'))
        folder_icon = QIcon(folder_icon_composite)

        folder_action = QAction(folder_icon, "Add folder", self)
        folder_action.setToolTip("Add a folder...")
        folder_action.setFont(font)
        folder_action.triggered.connect(self.select_folder)

        invite_action = QAction(
            QIcon(resource('invite.png')), "Enter Code", self)
        invite_action.setToolTip("Enter an Invite Code...")
        invite_action.setFont(font)
        invite_action.triggered.connect(self.open_invite_receiver)

        history_action = QAction(
            QIcon(resource('time.png')), 'History', self)
        history_action.setToolTip("View history")
        history_action.setFont(font)
        history_action.triggered.connect(self.on_history_button_clicked)

        self.history_button = QToolButton(self)
        self.history_button.setDefaultAction(history_action)
        self.history_button.setCheckable(True)
        self.history_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        spacer_left = QWidget()
        spacer_left.setSizePolicy(QSizePolicy.Expanding, 0)

        self.combo_box = ComboBox()
        self.combo_box.currentIndexChanged.connect(self.on_grid_selected)

        spacer_right = QWidget()
        spacer_right.setSizePolicy(QSizePolicy.Expanding, 0)

        share_action = QAction(QIcon(resource('share.png')), "Share", self)
        share_action.setToolTip("Share...")
        share_action.setFont(font)
        share_action.triggered.connect(self.open_invite_sender_dialog)

        recovery_action = QAction(
            QIcon(resource('key.png')), "Recovery", self)
        recovery_action.setToolTip("Import/Export Recovery Key...")
        recovery_action.setFont(font)

        import_action = QAction(QIcon(), "Import Recovery Key...", self)
        import_action.setToolTip("Import Recovery Key...")
        import_action.triggered.connect(self.import_recovery_key)

        export_action = QAction(QIcon(), "Export Recovery Key...", self)
        export_action.setToolTip("Export Recovery Key...")
        export_action.setShortcut(QKeySequence.Save)
        export_action.triggered.connect(self.export_recovery_key)

        recovery_menu = QMenu(self)
        recovery_menu.addAction(import_action)
        recovery_menu.addAction(export_action)

        recovery_button = QToolButton(self)
        recovery_button.setDefaultAction(recovery_action)
        recovery_button.setMenu(recovery_menu)
        recovery_button.setPopupMode(2)
        recovery_button.setStyleSheet(
            'QToolButton::menu-indicator { image: none }')
        recovery_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        preferences_action = QAction(
            QIcon(resource('preferences.png')), "Preferences", self)
        preferences_action.setStatusTip("Preferences")
        preferences_action.setToolTip("Preferences")
        preferences_action.setFont(font)
        preferences_action.setShortcut(QKeySequence.Preferences)
        preferences_action.triggered.connect(self.gui.show_preferences_window)

        self.toolbar = self.addToolBar('')
        if sys.platform != 'darwin':
            self.toolbar.setStyleSheet("""
                QToolBar { border: 0px }
                QToolButton { color: rgb(50, 50, 50) }
            """)
        else:
            self.toolbar.setStyleSheet(
                "QToolButton { color: rgb(50, 50, 50) }")
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.toolbar.setIconSize(QSize(24, 24))
        self.toolbar.setMovable(False)
        self.toolbar.addAction(folder_action)
        self.toolbar.addAction(invite_action)
        self.toolbar.addWidget(self.history_button)
        self.toolbar.addWidget(spacer_left)
        self.toolbar.addWidget(self.combo_box)
        self.toolbar.addWidget(spacer_right)
        self.toolbar.addAction(share_action)
        self.toolbar.addWidget(recovery_button)
        self.toolbar.addAction(preferences_action)

        if sys.platform != 'win32':  # Text is getting clipped on Windows 10
            for action in self.toolbar.actions():
                widget = self.toolbar.widgetForAction(action)
                if isinstance(widget, QToolButton):
                    widget.setMaximumWidth(68)

        self.active_invite_sender_dialogs = []
        self.active_invite_receiver_dialogs = []

    def populate(self, gateways):
        for gateway in gateways:
            if gateway not in self.gateways:
                self.central_widget.add_folders_view(gateway)
                self.central_widget.add_history_view(gateway)
                self.combo_box.add_gateway(gateway)
                self.gateways.append(gateway)
        self.gui.systray.menu.populate()

    def current_view(self):
        try:
            w = self.central_widget.folders_views[self.combo_box.currentData()]
        except KeyError:
            return None
        return w.layout().itemAt(0).widget()

    def select_folder(self):
        self.show_folders_view()
        view = self.current_view()
        if view:
            view.select_folder()

    def set_current_grid_status(self):
        current_view = self.current_view()
        if not current_view:
            return
        self.gui.systray.update()

    def show_folders_view(self):
        try:
            self.central_widget.setCurrentWidget(
                self.central_widget.folders_views[self.combo_box.currentData()]
            )
        except KeyError:
            pass
        self.set_current_grid_status()

    def show_history_view(self):
        try:
            self.central_widget.setCurrentWidget(
                self.central_widget.history_views[self.combo_box.currentData()]
            )
        except KeyError:
            pass
        self.set_current_grid_status()

    def show_welcome_dialog(self):
        if self.welcome_dialog:
            self.welcome_dialog.close()
        self.welcome_dialog = WelcomeDialog(self.gui, self.gateways)
        self.welcome_dialog.show()
        self.welcome_dialog.raise_()

    def on_grid_selected(self, index):
        if index == self.combo_box.count() - 1:
            self.show_welcome_dialog()
        if not self.combo_box.currentData():
            return
        if self.history_button.isChecked():
            self.show_history_view()
        else:
            self.show_folders_view()
        self.setWindowTitle(
            "{} - {}".format(APP_NAME, self.combo_box.currentData().name)
        )

    def confirm_export(self, path):
        if os.path.isfile(path):
            info(
                self,
                "Export successful",
                "Recovery Key successfully exported to {}".format(path))
        else:
            error(
                self,
                "Error exporting Recovery Key",
                "Destination file not found after export: {}".format(path))

    def export_recovery_key(self, gateway=None):
        self.show_folders_view()
        if not gateway:
            gateway = self.combo_box.currentData()
        self.recovery_key_exporter = RecoveryKeyExporter(self)
        self.recovery_key_exporter.done.connect(self.confirm_export)
        self.recovery_key_exporter.do_export(gateway)

    def import_recovery_key(self):
        # XXX Quick hack for user-testing; change later
        self.welcome_dialog = WelcomeDialog(self.gui, self.gateways)
        self.welcome_dialog.on_restore_link_activated()

    def on_history_button_clicked(self):
        if not self.history_button.isChecked():
            self.history_button.setChecked(True)
            self.show_history_view()
        else:
            self.history_button.setChecked(False)
            self.show_folders_view()

    def on_invite_received(self, gateway):
        self.populate([gateway])
        for view in self.central_widget.views:
            view.model().monitor.scan_rootcap('star.png')

    def on_invite_closed(self, obj):
        try:
            self.active_invite_receiver_dialogs.remove(obj)
        except ValueError:
            pass

    def open_invite_receiver(self):
        invite_receiver_dialog = InviteReceiverDialog(self.gateways)
        invite_receiver_dialog.done.connect(self.on_invite_received)
        invite_receiver_dialog.closed.connect(self.on_invite_closed)
        invite_receiver_dialog.show()
        self.active_invite_receiver_dialogs.append(invite_receiver_dialog)

    def open_invite_sender_dialog(self):
        gateway = self.combo_box.currentData()
        if gateway:
            view = self.current_view()
            if view:
                invite_sender_dialog = InviteSenderDialog(
                    gateway, self.gui, view.get_selected_folders())
            else:
                invite_sender_dialog = InviteSenderDialog(gateway, self.gui)
            invite_sender_dialog.closed.connect(
                self.active_invite_sender_dialogs.remove)
            invite_sender_dialog.show()
            self.active_invite_sender_dialogs.append(invite_sender_dialog)

    def confirm_quit(self):
        folder_loading = False
        folder_syncing = False
        for model in [view.model() for view in self.central_widget.views]:
            for row in range(model.rowCount()):
                status = model.item(row, 1).data(Qt.UserRole)
                mtime = model.item(row, 2).data(Qt.UserRole)
                if not status and not mtime:  # "Loading..." and not yet synced
                    folder_loading = True
                    break
                elif status == 1:  # "Syncing"
                    folder_syncing = True
                    break
        msg = QMessageBox(self)
        if folder_loading:
            msg.setIcon(QMessageBox.Warning)
            informative_text = (
                "One or more folders have not finished loading. If these "
                "folders were recently added, you may need to add them again.")
        elif folder_syncing:
            msg.setIcon(QMessageBox.Warning)
            informative_text = (
                "One or more folders are currently syncing. If you quit, any "
                "pending upload or download operations will be cancelled "
                "until you launch {} again.".format(APP_NAME))
        else:
            msg.setIcon(QMessageBox.Question)
            informative_text = (
                "If you quit, {} will stop synchronizing your folders until "
                "you launch it again.".format(APP_NAME))
        if sys.platform == 'darwin':
            msg.setText("Are you sure you wish to quit?")
            msg.setInformativeText(informative_text)
        else:
            msg.setWindowTitle("Exit {}?".format(APP_NAME))
            msg.setText(
                "Are you sure you wish to quit? {}".format(informative_text))
        msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg.setDefaultButton(QMessageBox.No)
        if msg.exec_() == QMessageBox.Yes:
            if sys.platform == 'win32':
                self.gui.systray.hide()
            reactor.stop()

    def keyPressEvent(self, event):
        key = event.key()
        if key in (Qt.Key_Backspace, Qt.Key_Delete):
            view = self.current_view()
            selected = (view.selectedIndexes() if view else None)
            if selected:
                view.confirm_remove(view.get_selected_folders())
        if key == Qt.Key_Escape:
            view = self.current_view()
            selected = (view.selectedIndexes() if view else None)
            if selected:
                for index in selected:
                    view.selectionModel().select(
                        index, QItemSelectionModel.Deselect)
            elif self.gui.systray.isSystemTrayAvailable():
                self.hide()

    def closeEvent(self, event):
        if self.gui.systray.isSystemTrayAvailable():
            event.accept()
        else:
            event.ignore()
            self.confirm_quit()
Esempio n. 4
0
class MainWindow(QMainWindow):
    def __init__(self, view_manager: ViewManagerFromViewInterface = None):
        QMainWindow.__init__(self, None)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.view_manager = view_manager
        self.create_widgets()

        pixmap = QPixmap('view/resource/icons_my/icon.png')
        icon = QIcon()
        icon.addPixmap(pixmap, QIcon.Normal, QIcon.Off)

        self.setWindowTitle('P Browser - thumbnail view')
        self.setWindowIcon(icon)

        self.thumb_views = list()

        self.ui.tabWidget.tabCloseRequested.connect(self.close_tab)
        self.ui.tabWidget.currentChanged.connect(self.on_current_tab_changed)
        self.bn_favorite.clicked.connect(self.view_manager.add_to_favorite)
        self.log_button.toggled.connect(self.log_button_toggle)

    def create_widgets(self):
        self.sites = ButtonLine(self.ui.top_frame,
                                height=50,
                                speed=90,
                                space=5)
        self.ui.top_frame_layout.addWidget(self.sites)

        self.history = HistoryView(self, self.view_manager)
        self.ui.controls_frame_layout.addWidget(self.history)

        self.bn_favorite = QToolButton(self.ui.controls_frame)
        self.bn_favorite.setAutoRaise(True)
        icon = QIcon()
        icon.addPixmap(
            QPixmap("view/resource/icons/ic_add_box_white_48dp.png"),
            QIcon.Normal, QIcon.Off)
        self.bn_favorite.setIcon(icon)
        self.bn_favorite.setIconSize(QSize(32, 32))
        self.ui.controls_frame_layout.addWidget(self.bn_favorite)

        self.log_button = QToolButton()
        sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding,
                                 QSizePolicy.Ignored)
        self.log_button.setSizePolicy(sizePolicy)
        self.log_button.setMinimumSize(QSize(0, 10))
        icon = QIcon()
        icon.addPixmap(
            QPixmap("view/resource/icons/ic_arrow_drop_up_white_24dp.png"),
            QIcon.Normal, QIcon.Off)
        icon.addPixmap(
            QPixmap("view/resource/icons/ic_arrow_drop_down_white_24dp.png"),
            QIcon.Normal, QIcon.On)
        self.log_button.setIcon(icon)
        self.log_button.setIconSize(QSize(24, 24))
        self.log_button.setCheckable(True)
        self.log_button.setAutoRaise(True)
        self.ui.bottom_frame_layout.addWidget(self.log_button)

        self.log = LogViewWindow(self.view_manager)
        self.ui.bottom_frame_layout.addWidget(self.log)
        self.log.setMaximumHeight(70)
        self.log.hide()

        # self.updateGeometry()

    def log_button_toggle(self):
        # return
        if self.log_button.isChecked():
            self.log.show()
        else:
            self.log.hide()

    def get_new_thumb_view(self) -> ThumbView:
        tab = self.ui.tabWidget
        view = ThumbView(tab, self.view_manager)
        self.thumb_views.append(view)

        return view

    def get_current_thumb_view(self) -> ThumbView:
        index = self.ui.tabWidget.currentIndex()
        if index >= 0:
            return self.thumb_views[index]
        else:
            return None

    def get_log(self) -> LogViewInterface:
        return self.log

    def set_tab_text(self, view, text: str, tooltip=''):
        try:
            index = self.thumb_views.index(view)
            self.ui.tabWidget.setTabText(index, text)
            self.ui.tabWidget.setTabToolTip(index, tooltip)
        except ValueError:
            pass

    def create_site_button(self, button):
        self.sites.add_button(button)

    def close_tab(self, index: int):
        # self.thumb_views[index].history_event()
        self.thumb_views[index].prepare_to_close()
        self.thumb_views.pop(index)
        self.ui.tabWidget.removeTab(index)
        self.update()

    def panic(self):
        self.showMinimized()

    def on_history_changed(self, history: HistoryFromViewInterface):
        self.history.update_history(history)

    def on_current_tab_changed(self, index: int):
        if index >= 0 and len(self.thumb_views) > 0:
            self.history.set_current_url(self.thumb_views[index].url)
        else:
            self.history.set_current_url(URL())

    def on_url_in_tab_changed(self, view):
        if self.thumb_views[self.ui.tabWidget.currentIndex()] == view:
            # print(view.url.get())
            self.history.set_current_url(view.url)

    def closeEvent(self, *args, **kwargs):
        for thumbs in self.thumb_views:
            thumbs.history_event()
        self.view_manager.on_exit()
Esempio n. 5
0
File: CustomUI.py Progetto: ag-sd/py
class CollapsibleWidget(QWidget):
    def __init__(self, title="", parent=None, animation_duration=300):
        """
        References:
            # Adapted from c++ version
            http://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
        """
        super(CollapsibleWidget, self).__init__(parent)
        self.title = title
        self.toggle_button = QToolButton()
        self.toggle_animation = QParallelAnimationGroup(self)
        self.content_area = QScrollArea()
        self.animation_duration = animation_duration
        self._init_base_ui()

    def _init_base_ui(self):
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)
        self.toggle_button.setText(str(self.title))
        self.toggle_button.setCheckable(True)
        self.toggle_button.setChecked(False)

        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

        layout = QVBoxLayout(self)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.toggle_button)
        layout.addWidget(self.content_area)

    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def set_content_layout(self, layout):
        initial_layout = self.content_area.layout()
        del initial_layout
        self.content_area.setLayout(layout)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(self.animation_duration)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)

    def set_content_widget(self, widget):
        initial_layout = self.content_area.layout()
        del initial_layout
        self.content_area.setWidget(widget)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = widget.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(self.animation_duration)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(self.animation_duration)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Esempio n. 6
0
class CollapsibleBox(QWidget):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(parent)
        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton {border: none;\
                border: 1px solid #FF17365D;\
                border-top-left-radius: 15px;\
                border-top-right-radius: 15px;\
                background-color: #FF17365D;\
                padding: 5px 0px;\
                color: rgb(255, 255, 255);\
                max-height: 30px;\
                font-size: 14px;\
            }\
            QToolButton:hover {\
                background-color: lightgreen;\
                color: black;\
            }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.toggle_button)
        lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

    @QtCore.pyqtSlot()
    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def clear_layout(self, layout):
        try:
            for i in reversed(range(layout.count())):
                widgetToRemove = layout.itemAt(i).widget()
                layout.removeWidget(widgetToRemove)
                widgetToRemove.setPArent(None)
        except AttributeError:
            pass

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        self.clear_layout(lay)
        self.content_area.setLayout(layout)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Esempio n. 7
0
class EventPicker(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('EventPicker 2018.1')


        self.nSubPlots = None # number of traces/subplots
        self.nSamples = None # number of samples per trace
        self.dragFrom = None
        self.segy = None # type: Segy class 

        
        # # {'0': {'2500': {'p':[marker1, marker2]}
        # 				 {'s':[maerker1, marker2]}}
        # 
        self.markers = defaultdict(dict)
        self.eventList = []
        self.markerList = []

        self.currentEvent = defaultdict(dict)
        self.event2file = defaultdict(dict)
        self.currentEventId = int(1)
        self.spanMarker = None
        self.modeFlag = 'a'
        self.componentFlag = int(12)
        self.normFlag = int(1) # traces data normalized before display

        self.zTraces = None
        self.xTraces = None
        self.yTraces = None
                      
        self.xcolor = 'b'
        self.ycolor = 'r'
        self.zcolor = 'green'


        self.fileList = []
        self.currentFile = None
        self.inpath = None
        self.outpath = "F:\\datafolder\\eventspicked"


        self.zLines = [] # list container of line curves of Z traces
        self.xLines = []
        self.yLines = []

        self.autoPickerParams = {            
            'stalta_algorithm': 'Recursive',            
            'nsta': '20',
            'nlta': '50',
            'pthreshold': '2.0',
            'sthreshold': '2.2'
        }


        
        self.initUI()  
    
    def initUI(self):
       
        # Trace plot
        self.fig = plt.figure()
        
        self.staticCanvas = FigureCanvas(self.fig)        
        self.staticCanvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
               
       
        

       
        self.fig.canvas.mpl_connect('button_press_event', self.onClick)
        self.fig.canvas.mpl_connect('button_release_event', self.onRelease)		
        #self.fig.canvas.mpl_connect('scroll_event', self.onScroll)
        self.fig.canvas.mpl_connect('key_press_event', self.onKey)


        self.p_line_style = dict(color='r', linestyle='-', linewidth=2)        
        self.p_marker_style = dict(marker='o', s=40, facecolors='none', edgecolors='r')
        self.s_line_style = dict(color='b', linestyle='-', linewidth=2)
        self.s_marker_style = dict(marker='o', s=40, facecolors='none', edgecolors='b')


        # Reference trace plot
        self.refFig = plt.figure()
        
        self.refCanvas = FigureCanvas(self.refFig)

        self.refFig.set_size_inches(self.size().width()/self.refFig.get_dpi(),
                self.size().height() * 0.25 /self.refFig.get_dpi())

        self.refCanvas.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Fixed)

        self.refCanvas.updateGeometry()

        
        

        self.graphArea = QScrollArea(self)   
        self.graphArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.graphArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)     
        self.graphArea.setWidget(self.staticCanvas)
        self.graphArea.setWidgetResizable(True)

        
        layout = QVBoxLayout() 
         
        layout.addWidget(self.graphArea)
        #layout.addWidget(self.staticCanvas)
        layout.addWidget(self.refCanvas)

        self.main = QWidget()
        self.setCentralWidget(self.main)
        self.main.setLayout(layout)
        

        self.createActions()
        self.createMenus()
        self.createToolBars()


        self.resize(1176, 776)
       



    def createActions(self):

        self.pickSettingAction = QAction(QIcon(':/icons/windows/settings-48.png'), "&AutoPicker Settings",
                self, shortcut= '',
                statusTip="AutoPicker settings", triggered=self.onPickSettingsClicked)
        self.pickSettingAction.setEnabled(False)
        
        self.selectFolderAction = QAction(QIcon(':/icons/windows/add-folder-48.png'), "&Select SEG-Y Folder",
                self, shortcut= '',
                statusTip="Select SEG-Y files folder", triggered=self.onSelectFolder)

        self.exportAction = QAction(QIcon(':/icons/windows/export-one-48.png'), "&Export Current Event",
                self, shortcut= '',
                statusTip="Export current picked event", triggered=self.onExport)
        
        self.exportAllAction = QAction(QIcon(':/icons/windows/export-all-48.png'), "&Export All Events",
                self, shortcut= '',
                statusTip="Export all picked events", triggered=self.onExportAll)

        self.editEventsAction = QAction(QIcon(':/icons/windows/edit-event-48.png'), "&Edit Events",
                self, shortcut= '',
                statusTip="Edit all picked events", triggered=self.onEditEvents)

        
        
        
        
    def createMenus(self):
        
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.selectFolderAction)

        self.editMenu = self.menuBar().addMenu("&Edit")
        self.editMenu.addAction(self.editEventsAction)

        self.exportMenu = self.menuBar().addMenu("&Export")
        self.exportMenu.addAction(self.exportAction)
        self.exportMenu.addAction(self.exportAllAction)
        

    def createToolBars(self):

        # Component Toolbar
        self.componentToolBar = QToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.componentToolBar)


        self.zComponentToolButton = QToolButton(self)
        self.zComponentToolButton.setToolTip('Z Component')
        self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-checked-48.png'))
        self.zComponentToolButton.setCheckable(True)
        self.zComponentToolButton.setChecked(True)
        self.zComponentToolButton.toggled.connect(self.update) 

        self.xComponentToolButton = QToolButton(self)
        self.xComponentToolButton.setToolTip('X Component')
        self.xComponentToolButton.setIcon(QIcon(':/icons/windows/n-48.png'))
        self.xComponentToolButton.setCheckable(True)
        self.xComponentToolButton.toggled.connect(self.update) 

        self.yComponentToolButton = QToolButton(self)
        self.yComponentToolButton.setToolTip('Y Component')
        self.yComponentToolButton.setIcon(QIcon(':/icons/windows/e-48.png'))
        self.yComponentToolButton.setCheckable(True)
        self.yComponentToolButton.toggled.connect(self.update) 

        
        
        self.componentToolBar.addWidget(self.yComponentToolButton)
        self.componentToolBar.addWidget(self.xComponentToolButton)
        self.componentToolBar.addWidget(self.zComponentToolButton)

        # Auto Pick Toolbar
        self.autoPickToolBar = QToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.autoPickToolBar)

        self.autoPickToolButton = QToolButton(self)
        self.autoPickToolButton.setToolTip('Run AutoPicker')
        self.autoPickToolButton.setIcon(QIcon(':/icons/windows/autopick-purple-48.png'))
        self.autoPickToolButton.clicked.connect(self.onAutoPickClicked)
        self.autoPickToolButton.setEnabled(False)
        
        self.autoPickToolBar.addAction(self.pickSettingAction)        
        self.autoPickToolBar.addWidget(self.autoPickToolButton)

        # Manual Pick Toolbar
        self.manualPickToolBar = QToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.manualPickToolBar)

        self.pickPwaveToolButton = QToolButton(self)
        self.pickPwaveToolButton.setToolTip('Pick P-phase Arrival')
        self.pickPwaveToolButton.setIcon(QIcon(':/icons/windows/pickp-48.png'))
        self.pickPwaveToolButton.setCheckable(True)
        self.pickPwaveToolButton.toggled.connect(self.onPickPwaveToggled)

        self.pickSwaveToolButton = QToolButton(self)
        self.pickSwaveToolButton.setToolTip('Pick S-phase Arrival')
        self.pickSwaveToolButton.setIcon(QIcon(':/icons/windows/picks-48.png'))
        self.pickSwaveToolButton.setCheckable(True)
        self.pickSwaveToolButton.toggled.connect(self.onPickSwaveToggled)

        self.manualPickToolBar.addWidget(self.pickPwaveToolButton)
        self.manualPickToolBar.addWidget(self.pickSwaveToolButton)

        
        # Event Toolbar
        self.eventToolBar = QToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.eventToolBar)
        

        self.clearPickToolButton = QToolButton(self)
        self.clearPickToolButton.setToolTip('Clear Current Picks')
        self.clearPickToolButton.setIcon(QIcon(':/icons/windows/clear-picks-48.png'))
        self.clearPickToolButton.clicked.connect(self.onClearPick) 

        self.clearAllPickToolButton = QToolButton(self)
        self.clearAllPickToolButton.setToolTip('Clear All Picks')
        self.clearAllPickToolButton.setIcon(QIcon(':/icons/windows/clear-all-picks-48.png'))
        self.clearAllPickToolButton.clicked.connect(self.onClearAllPick) 
        self.eventIdWidget = EventIDWidget(self) 

        
        self.eventToolBar.addWidget(self.clearPickToolButton)
        self.eventToolBar.addWidget(self.clearAllPickToolButton)
        self.eventToolBar.addWidget(self.eventIdWidget)
        self.eventToolBar.addAction(self.editEventsAction)
        self.eventToolBar.addAction(self.exportAction)
        self.eventToolBar.addAction(self.exportAllAction)
        
        



        # Matplotlib Navigation ToolBar
        self.pltToolBar = NavigationToolbar(self.staticCanvas, self)
        self.addToolBar(self.pltToolBar)

        self.addToolBarBreak()
        # Manual Pick Toolbar
        self.fileToolBar = FileToolBar(self)
        self.addToolBar(Qt.TopToolBarArea, self.fileToolBar)
        
        
    def onExportAll(self):

        self.updateCurrentEvent2File()
        
        fileName, ok = QFileDialog.getSaveFileName(self,
                                    "Export",
                                    "C:\\",
                                    "All Files (*);;CSV Files (*.csv)")

        if fileName:
            markers = self.markers

            dics = []

            dic = {'event_id':None,
                'file_name': None,
                'receiver_id': None,
                'p_pos': None, 
                's_pos':None}
            

            if len(markers):
                for event_id, item in self.markers.items():                
                    for plot_id, markers in item.items():
                        dic['event_id'] = int(event_id)
                        dic['file_name'] = self.event2file[event_id]
                        dic['receiver_id'] = int(plot_id) + 1
                        if markers['p'] != None:
                            dic['p_pos'] =  markers['p']['pos']
                        else:
                            dic['p_pos'] =  DEFAULT_NUMERIC_VALUE
                        if markers['s'] != None:
                            dic['s_pos'] =  markers['s']['pos']
                        else:
                            dic['s_pos'] =  DEFAULT_NUMERIC_VALUE

                        
                        dics.append(copy.deepcopy(dic))
                        

                
                
                df = pd.DataFrame(dics)
                df.to_csv(fileName)
                
                QMessageBox.information(self,
                                            "Information",  
                                            "All Events have been saved successfully!",  
                                            QMessageBox.Ok) 
            else:
                QMessageBox.warning(self,
                                            "Warning",  
                                            "No P-wave or S-wave arrival time has been picked!\nPlease pick at least one arrival time for exporting.",  
                                            QMessageBox.Ok)

    def onSelectFolder (self):
        
        folderPath = QFileDialog.getExistingDirectory(self,"Select SEG-Y folder","C:\\")
        if folderPath:            
            self.inpath = folderPath
            self.fileList = self.getAllFiles(folderPath)
            self.updateAll(self.fileList[0])
            self.fileToolBar.initWidget(self.fileList)
        
    def getAllFiles(self, path_dir):        
        if os.path.exists(path_dir) and os.path.isdir(path_dir):
            path_dir = os.path.abspath(path_dir)
            for i in os.listdir(path_dir):
                path_i = os.path.join(path_dir, i)
                if os.path.isfile(path_i) and os.path.splitext(os.path.basename(path_i))[1] == '.sgy':
                    self.fileList.append(path_i)
                    #print(path_i)
                else:
                    self.getAllFiles(path_i)
        return self.fileList 
    

    def updateMarkers(self, params):
        '''
        NOT FINISHED YET
        '''
        pass
        # for subPlotNr in range(self.nSubPlots):
        #     if str(subPlotNr) not in self.markers[str(self.currentEventId)]:
        #         self.markers[str(self.currentEventId)][str(subPlotNr)] = []    

        

        # if  'stalta_algorithm' in params.keys():
        #     method =  params['stalta_algorithm']
        #     nsta = int(params['nsta'])
        #     lsta = int(params['nlta'])
        #     pthres = float(params['pthreshold'])
        #     sthres = float(params['sthreshold'])

        
        # pCfs, sCfs = self.segy.calcStaLtaCF(nsta, lsta, method)
        # pPicks, sPicks = self.segy.pickPS(pCfs, sCfs, pthres, sthres)      
        
          

        # for subPlotNr in range(self.nSubPlots):            
            
        #     xP = pPicks[str(subPlotNr)] 
        #     xS = sPicks[str(subPlotNr)]

        #     subPlot = self.selectSubPlot(subPlotNr)

        #     markerList = []
                        

        #     for i in range(len(xP)):
        #         xp = xP[i]           
                
                                 
        #         pMarker1 = subPlot.axvline(xp, 0.1, 0.9, **self.p_line_style)
        #         pMarker2 = subPlot.scatter(xp, 0.0, **self.p_marker_style)	
 
        #         markerList.append({'px': xp, 
        #                         'pmarker': [pMarker1, pMarker2]
        #         })               
                
                
                    
        #     for i in range(len(xS)):
        #         xs = xS[i]
                 
        #         sMarker1 = subPlot.axvline(xs, 0.1, 0.9, **self.s_line_style)
        #         sMarker2 = subPlot.scatter(xs, 0.0, **self.s_marker_style)	
                	
        #         markerList.append({'sx': xs, 
        #                         'smarker': [sMarker1, sMarker2]
        #         })
            
            
        #     self.markers[str(self.currentEventId)][str(subPlotNr)] = markerList
            
        # self.fig.canvas.draw()                          
                    
           
            
        

    def setAutoPicker(self, object):

        self.autoPickerParams.clear()
        self.autoPickerParams = object
        print(self.autoPickerParams)


    def getComponentFlag(self):
	
        if self.xComponentToolButton.isChecked():
            xflag = 14
            self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-checked-48.png'))
        else:
            xflag = 0
            self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-48.png'))
        
        if self.yComponentToolButton.isChecked():
            yflag = 13 
            self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-checked-48.png'))
        else:
            yflag = 0
            self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-48.png'))
        
        if self.zComponentToolButton.isChecked():
            zflag = 12
            self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-checked-48.png'))
        else:
            zflag = 0
            self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-48.png'))
        
        flag = xflag + yflag +zflag

        return flag

    def onPickPwaveToggled(self, checked):
        
        if checked:
            self.modeFlag = 'p'
            self.pickSwaveToolButton.setChecked(False)
        elif self.pickSwaveToolButton.isChecked() == False:
            self.modeFlag = 'a'
        
        
        
    
    def onPickSwaveToggled(self, checked):
        
        if checked:
            self.modeFlag = 's'
            self.pickPwaveToolButton.setChecked(False)
        elif self.pickPwaveToolButton.isChecked() == False:
            self.modeFlag = 'a'
        

    def onAutoPickClicked(self):
                
        self.updateMarkers(self.autoPickerParams)

    def onPickSettingsClicked(self):

        dialog = AutoPickerSettingDialog(self)
        dialog.applySignal.connect(self.updateMarkers)
        dialog.show()
        dialog.exec_()       


    
    def setSegy(self, segy):
        self.segy = segy

    def getSegy(self):
        return self.segy 

    def updateAll(self, file):
               
        self.currentFile = file
        segy = pssegy.Segy(file)
        self.setSegy(segy) 
        self.xComponentToolButton.setChecked(False)
        self.yComponentToolButton.setChecked(False)
        self.zComponentToolButton.setChecked(True)
        self.initPlot()

    def updateEvent2File(self, ind):

        
        if str(ind) not in self.event2file and len(self.markers[str(ind)]):
            self.event2file[str(ind)] = self.currentFile
        
    def updateCurrentEvent2File(self):

        ind = self.currentEventId
        if str(ind) not in self.event2file and len(self.markers[str(ind)]):
            self.event2file[str(ind)] = self.currentFile    

    def initPlot(self):

        

        df = self.segy.df
        
        
        if self.normFlag == 1:
            self.zTraces = signorm(self.segy.zTraces)
            self.xTraces = signorm(self.segy.xTraces)
            self.yTraces = signorm(self.segy.yTraces) # @TODO: add norm flag here
        else:
            self.zTraces = self.segy.zTraces
            self.xTraces = self.segy.xTraces
            self.yTraces = self.segy.yTraces

        ns, ntr = self.zTraces.shape
        self.nSamples = ns
        self.nSubPlots  = ntr

        if self.nSubPlots > 12:
            self.fig.set_size_inches(self.size().width()/self.fig.get_dpi(),
                self.size().height() * self.nSubPlots / 12 /self.fig.get_dpi())
            self.staticCanvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            self.staticCanvas.setMinimumHeight(self.size().height() * self.nSubPlots / 12 )
        
        
        t = np.arange(self.nSamples, dtype=np.float32) / df

        


        # if len(self.fig.axes):
        #     xlim = self.fig.axes[0].get_xlim()
        #     #print(xlim)
        # else:
        #     
        
        self.fig.clear()
        
        xlim = (0, ns)
        nrow = int(ntr)
        ncol = 1
        

        self.zLines = self.plotWaveform(self.zTraces, xlim, nrow, ncol, self.fig, self.zcolor)
        #self.nSubPlots = len(self.fig.axes)       
        

        
        self.plotRefWaveform(self.zTraces, self.nSubPlots, df, self.refFig) 


    def updatePlot(self):

        

        if len(self.fig.axes):
            xlim = self.fig.axes[0].get_xlim()
            #print(xlim)
        else:
            xlim = (0, self.nSamples)

        nrow = int(self.nSubPlots)
        ncol = 1

        if self.zComponentToolButton.isChecked() == False:
        
            self.removeLines(self.zLines)
            self.zLines = []
            
        else:
            if not len(self.zLines):            
                self.zLines = self.plotWaveform(self.zTraces, xlim, nrow, ncol, self.fig, self.zcolor)

        
        if self.xComponentToolButton.isChecked() == False:
            
            self.removeLines(self.xLines)
            self.xLines = []
            
        else: 
            if not len(self.xLines):           
                self.xLines = self.plotWaveform(self.xTraces, xlim, nrow, ncol, self.fig, self.xcolor)


        if self.yComponentToolButton.isChecked() == False:
            
            self.removeLines(self.yLines)
            self.yLines = []
            
        else:  
            if not len(self.yLines):          
                self.yLines = self.plotWaveform(self.yTraces, xlim, nrow, ncol, self.fig, self.ycolor)

        
        
        self.fig.canvas.draw()

        if not len(self.zLines) and not len(self.xLines) and not len(self.yLines):
            self.autoPickToolButton.setEnabled(False)
        else:
            self.autoPickToolButton.setEnabled(True)
            

    
    def removeLines(self, lines):
        if len(lines):
               for subPlotNr in range(self.nSubPlots):
                    
                    subPlot = self.selectSubPlot(subPlotNr)
                    line = lines[subPlotNr]
                    if line in subPlot.lines:
                        #print('line in subplot.lines')
                        subPlot.lines.remove(line)

    def updateToolBar(self):
		
        if self.xComponentToolButton.isChecked():
            
            self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-checked-48.png'))
        else:
            
            self.xComponentToolButton.setIcon(QIcon(':/icons/windows/e-48.png'))
        
        if self.yComponentToolButton.isChecked():
             
            self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-checked-48.png'))
        else:
            
            self.yComponentToolButton.setIcon(QIcon(':/icons/windows/n-48.png'))
        
        if self.zComponentToolButton.isChecked():
            
            self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-checked-48.png'))
        else:
            
            self.zComponentToolButton.setIcon(QIcon(':/icons/windows/z-48.png'))
        
    
    # Declare and register callbacks
    def onXlimsChanged(self, ax):
        
        if len(self.refFig.axes):
            #print ("updated xlims: ", ax.get_xlim())
            xlim = ax.get_xlim()

            self.refFig.axes[0].patches = [] 
            self.refFig.axes[1].patches = []
                
            # if self.spanMarker in self.refFig.axes[0].patches:
            #     #print('spanMarker in subplot.patches')
            #     self.refFig.axes[0].patches.remove(self.spanMarker)                
            #     self.spanMarker = None
                    
            df = self.segy.df
            
            self.spanMarker = self.refFig.axes[0].axvspan(xlim[0]/df, xlim[1]/df, facecolor='#2ca02c', alpha=0.25)
        self.refFig.canvas.draw()



    def onYlimsChanged(self, ax):
        pass
        #print ("updated ylims: ", ax.get_ylim())

      
    
    def update(self):
        self.updateToolBar()
        if self.segy is not None:
            self.updatePlot()   

                
    def plotRefWaveform(self, traces, ind, df, fig):

        fig.clear()
        ns, ntr = traces.shape

        xlim = (0/df, ns/df) 

        nTick = 10
        step = divmod(ns, nTick)[0]


        x_n =  np.linspace(0, ns, ns)
        x_t =  np.arange(ns, dtype=np.float32) / df

        ax1 = fig.add_subplot(1,1,1)

        line = ax1.plot(x_t, traces[:, ind -1] , linewidth=1.0, c = 'k', figure=fig)
        #ax1.set_xlabel(u'Time [second]')
        ax1.set_yticks([])
        ax1.set_xlim(xlim[0], xlim[1])
        

        # Set scond x-axis
        ax2 = ax1.twiny()

        # Decide the ticklabel position in the new x-axis,
        # then convert them to the position in the old x-axis
        newlabel = []
        for i in range(nTick+1):
            newlabel.append(i*step) # labels of the xticklabels: the position in the new x-axis
        n2t = lambda t: t/df # convert function: from Kelvin to Degree Celsius
        newpos   = [n2t(t) for t in newlabel]   # position of the xticklabels in the old x-axis
        ax2.set_xticks(newpos)
        ax2.set_xticklabels(newlabel)
        ax2.set_yticks([])
        #ax2.set_xlabel('Sample')
        ax2.set_xlim(ax1.get_xlim())

        self.spanMarker = self.refFig.axes[0].axvspan(xlim[0], xlim[1], facecolor='#2ca02c', alpha=0.5)   
        fig.subplots_adjust(left=0.02, bottom=0.25, right=0.98, top=0.75)
        
        fig.canvas.draw()

        

        
        return line
        
    def resizeEvent(self, ev):
        pass
        #print(ev)
        
        # # incorrect code here: only figure size changed while canvas not
        # self.refFig.set_size_inches(self.size().width()/self.refFig.get_dpi(),
        #         self.size().height() * 0.1/self.refFig.get_dpi())
        # self.refFig.canvas.draw()
        


    def plotWaveform(self, traces, xlim, nrow, ncol, fig, color):

        
        ns, ntr = traces.shape
        #t = np.arange(ns, dtype=np.float32) / df
        
        
        xData = np.linspace(1, ns, ns)
        lines = []


        for irow in range(nrow):
            if irow == 0:
                
                ax1 = fig.add_subplot(nrow, ncol, irow + 1)
                line = ax1.plot(xData, traces[:, irow]  , linewidth=1.0, c = color, figure=fig)
                ax1.callbacks.connect('xlim_changed', self.onXlimsChanged)  
                
                ax1.set_yticks([])
                ax1.set_xlim(int(xlim[0]), int(xlim[1]))
                ax1.set_xticks([])
            
            else:
                    
                subPlot = fig.add_subplot(nrow, ncol, irow + 1, sharex = ax1, sharey = ax1)
                subPlot.callbacks.connect('xlim_changed', self.onXlimsChanged)
                line = subPlot.plot(xData, traces[:, irow]  , linewidth=1.0, c = color, figure=self.fig)

            lines.append(line[0])

        fig.subplots_adjust(left=0.02, bottom=0.02, right=0.99, top=0.98)
        #self.fig.tight_layout() 
        fig.canvas.draw()
        return lines

    def onExport(self):

        self.updateCurrentEvent2File()
        
        fileName, ok = QFileDialog.getSaveFileName(self,
                                    "Export",
                                    "C:\\",
                                    "All Files (*);;CSV Files (*.csv)")

        if fileName:

            markers = self.markers

            dics = []

            dic = {'event_id':None,
                'file_name': None,
                'receiver_id': None,
                'p_pos': None, 
                's_pos':None}
            

            if len(markers[str(self.currentEventId)]):

                item  = markers[str(self.currentEventId)]
                    
                for plot_id, markers in item.items():

                    dic['event_id'] = self.currentEventId
                    dic['file_name'] = self.currentFile
                    dic['receiver_id'] = int(plot_id) + 1
                    if markers['p'] != None:
                        dic['p_pos'] =  markers['p']['pos']
                    else:
                        dic['p_pos'] =  DEFAULT_NUMERIC_VALUE
                    if markers['s'] != None:
                        dic['s_pos'] =  markers['s']['pos']
                    else:
                        dic['s_pos'] =  DEFAULT_NUMERIC_VALUE

                    
                    dics.append(copy.deepcopy(dic))
                        

                
                
                df = pd.DataFrame(dics)
                df.to_csv(fileName)
                
                QMessageBox.information(self,
                                            "Information",  
                                            "Event #" + str(self.currentEventId) + " has been saved successfully!",  
                                            QMessageBox.Ok) 
            else:
                QMessageBox.warning(self,
                                            "Warning",  
                                            "No P-wave or S-wave arrival time has been picked for Event #" + str(self.currentEventId) + ".\nPlease pick at least one arrival time for exporting.",  
                                            QMessageBox.Ok)  


        

        
        


    def onEditEvents(self):
        print('edit event list')



    def onClearPick(self):
        self.clearMarkers()

    def onClearAllPick(self):
        self.clearAllMarkers()

    def clearMarkers(self):

                      
        if len(self.markers[str(self.currentEventId)]):
            item = self.markers[str(self.currentEventId)]            
            for plot_id, markers in item.items():
                subPlot = self.selectSubPlot(int(plot_id))	
                for flag in ['p', 's']:
                    marker = markers[flag] 
                    if marker != None:                                               
                        mk = marker['marker']
                        subPlot.lines.remove(mk)
                        markers[flag] = None 
            self.markers[str(self.currentEventId)].clear()
            self.markers.pop(str(self.currentEventId)) 
            self.fig.canvas.draw()  
                

    def clearAllMarkers(self):
    
                      
        if len(self.markers):
            for event_id, item in self.markers.items():
                for plot_id, markers in item.items():
                    subPlot = self.selectSubPlot(int(plot_id))	
                    for flag in ['p', 's']:
                        marker = markers[flag] 
                        if marker != None:                                               
                            mk = marker['marker']
                            subPlot.lines.remove(mk)
                            markers[flag] = None 
            self.markers.clear() 
            self.fig.canvas.draw()  
                
                    
        

    def deleteMarker(self,event):

        subPlotNr = self.getSubPlotNr(event)
        
        if subPlotNr == None:
            return

        subPlot = self.selectSubPlot(subPlotNr)	

        
        plotIdPopped = None
        for event_id, item in self.markers.items():
            for plot_id, markers in item.items():
                if plot_id == str(subPlotNr):
                    for flag in ['p', 's']:
                        marker = markers[flag]
                        if marker != None and abs (marker['pos'] - event.xdata) <=10:                        
                            mk = marker['marker']
                            subPlot.lines.remove(mk)
                            markers[flag] = None 
                if markers['p'] == None and markers['s'] == None:
                    plotIdPopped = plot_id

        if plotIdPopped != None:
            self.markers[str(self.currentEventId)].pop(plotIdPopped)
        self.fig.canvas.draw()            
        

        


        
    def getSubPlotNr(self, event):
    
        """
        Get the nr of the subplot that has been clicked
        
        Arguments:
        event -- an event
        
        Returns:
        A number or None if no subplot has been clicked
        """
    
        i = 0
        axisNr = None
        for axis in self.fig.axes:
            if axis == event.inaxes:
                axisNr = i		
                break
            i += 1
        return axisNr
        


        
    def selectSubPlot(self, i):	
        """
        Select a subplot		

        Arguments:
        i -- the nr of the subplot to select

        Returns:
        A subplot
        """
        
        
        #pyplot.subplot(self.nSubPlots, 1, i+1)
        return self.fig.axes[ i ]
    
        
    def onClick(self, event):
    
        """
        Process a mouse click event. If a mouse is right clicked within a
        subplot, the return value is set to a (subPlotNr, xVal, yVal) tuple and
        the plot is closed. With right-clicking and dragging, the plot can be
        moved.
        
        Arguments:
        event -- a MouseEvent event
        """
            
        mode = self.pltToolBar.mode 
        if event.button == 1 and mode != 'zoom rect' and self.modeFlag != 'a':	# left clicked	
        
            subPlotNr = self.getSubPlotNr(event)

            if subPlotNr == None:
                return
            else:
                if str(subPlotNr) not in self.markers[str(self.currentEventId)]:
                    self.markers[str(self.currentEventId)][str(subPlotNr)] = {'p': None, 's':None}    
                
                
                marker = {'pos': None,
                            'marker': None
                            }
            
            subPlot = self.selectSubPlot(subPlotNr)
            
            

            if self.markers[str(self.currentEventId)][str(subPlotNr)][self.modeFlag] == None:

                if self.modeFlag == 'p':
                    mks = subPlot.axvline(event.xdata, 0.1, 0.9, **self.p_line_style)
                else:
                    mks = subPlot.axvline(event.xdata, 0.1, 0.9, **self.s_line_style)

                marker['pos'] = event.xdata
                marker['marker'] = mks
                self.markers[str(self.currentEventId)][str(subPlotNr)][self.modeFlag] = marker

            else:
                QMessageBox.warning(self,
                                "Warning",
                                "For each microseismic event, there should only one P-wave arrival time and one S-wave arrival time be picked.\nPlease firstly clear the existing one and then re-pick the new one",
                                QMessageBox.Ok)
            self.fig.canvas.draw()        

        
        elif event.button == 3 and mode != 'zoom rect': # right clicked
            
            self.deleteMarker(event)
        # else:			
        #     # Start a dragFrom
        #     self.dragFrom = event.xdata
        
    def onKey(self, event):
        
        """
        Handle a keypress event. The plot is closed without return value on
        enter. Other keys are used to add a comment.
        
        Arguments:
        event -- a KeyEvent
        """
    
        # if event.key == 'enter':
        #     self.fig.close()
        #     return
            
        # if event.key == 'escape':
        #     self.clearMarker()
        #     return
            
        # if event.key == 'backspace':
        #     self.comment = self.comment[:-1]
        # elif len(event.key) == 1:			
        #     self.comment += event.key
        
        # event.canvas.draw()
        pass
            
    def onRelease(self, event):
    
        """
        Handles a mouse release, which causes a move
        
        Arguments:
        event -- a mouse event
        """
    
        if self.dragFrom == None or event.button != 3:
            return			
        dragTo = event.xdata
        dx = self.dragFrom - dragTo
        for i in range(self.nSubPlots):
            subPlot = self.selectSubPlot(i)			
            xmin, xmax = subPlot.get_xlim()
            xmin += dx
            xmax += dx				
            subPlot.set_xlim(xmin, xmax)
        event.canvas.draw()
                                            
    def onScroll(self, event):
    
        """
        Process scroll events. All subplots are scrolled simultaneously
        
        Arguments:
        event -- a MouseEvent
        """
    
        for i in range(self.nSubPlots):
            subPlot = self.selectSubPlot(i)		
            xmin, xmax = subPlot.get_xlim()
            dx = xmax - xmin
            cx = (xmax+xmin)/2
            if event.button == 'down':
                dx *= 1.1
            else:
                dx /= 1.1
            _xmin = cx - dx/2
            _xmax = cx + dx/2	
            subPlot.set_xlim(_xmin, _xmax)
        event.canvas.draw()


        
    def updateXLim(self, lim):
        '''
        lim: a tuple, (x1, x2)
        '''

        x1 = lim[0]
        x2 = lim[1]
        for axis in self.fig.axes:
                    axis.set_xlim(x1, x2)
                
        self.fig.canvas.draw()	
Esempio n. 8
0
class TextEditWidget(PWidget):
    alert = pyqtSignal(str, str, object, object)
    syncRequest = pyqtSignal(object)
    editorTypeChanged = pyqtSignal(object)
    saveDataDone = pyqtSignal(str)

    def __init__(self,
                 editType: EditorType = EditorType.Manual,
                 save: bool = True,
                 sync: bool = True):
        super().__init__()
        self.editor = TextEditor()
        self.editor.keyEvent.connect(self.editorEvent)

        tool = QHBoxLayout()

        if save:
            iconSize = 36
        else:
            iconSize = 24

        if save:
            self.title = PLabelEdit()
            self.title.setMaximumWidth(300)
            self.title.setFixedHeight(iconSize)
            self.title.setMaximumHeight(iconSize)
            self.title.setStyleSheet("QLabel{color:#424242; font-size:16px}")
            self.title.setText("Untitled")
            tool.addWidget(self.title)

        tool.addStretch()

        if editType == EditorType.Manual:
            self.editorTypeBox = PComboBox()
            self.editorTypeBox.setView(MiniView.listView())
            self.editorTypeBox.addItems(["Text", "JSON", "XML", "HTML"])
            self.editorTypeBox.currentIndexChanged.connect(
                self.editorTypeChange)
            tool.addWidget(self.editorTypeBox)

        self.wrapButton = QToolButton()
        self.wrapButton.setCheckable(True)
        self.wrapButton.setText("Wrap")
        self.wrapButton.setToolTip("Wrap/Unwrap (Ctrl+W)")
        self.wrapButton.setIcon(
            PResource.defaultIcon(Parapluie.Icon_Wrap_Text_Svg))
        self.wrapButton.setFixedSize(iconSize, iconSize)
        self.wrapButton.pressed.connect(self.wrapText)
        tool.addWidget(self.wrapButton)

        formatButton = QToolButton()
        formatButton.setText("Format")
        formatButton.setToolTip("Format Code (Ctrl+F)")
        formatButton.setIcon(
            PResource.defaultIcon(Parapluie.Icon_Clean_Code_Svg))
        formatButton.setFixedSize(iconSize, iconSize)
        formatButton.pressed.connect(self.formatText)
        tool.addWidget(formatButton)

        if save:
            saveButton = QToolButton()
            saveButton.setText("Save")
            saveButton.setToolTip("Save (Ctrl+S)")
            saveButton.setIcon(PResource.defaultIcon(Parapluie.Icon_Save_Svg))
            saveButton.setFixedSize(iconSize, iconSize)
            saveButton.pressed.connect(self.saveData)
            tool.addWidget(saveButton)

        if sync:
            syncButton = QToolButton()
            syncButton.setText("Sync")
            syncButton.setToolTip("Sync (Ctrl+B)")
            syncButton.setIcon(
                PResource.defaultIcon(Parapluie.Icon_Double_Right_Chevron_Svg))
            syncButton.setFixedSize(iconSize, iconSize)
            syncButton.pressed.connect(self.syncJson)
            tool.addWidget(syncButton)

        widget = QWidget()
        widget.setLayout(tool)
        widget.layout().setContentsMargins(8, 0, 8, 0)
        widget.setObjectName(Parapluie.Object_Editor_Header)
        widget.setMaximumHeight(iconSize)

        layout = QVBoxLayout()
        layout.addWidget(widget)
        layout.addWidget(self.editor)

        self.setLayout(layout)
        self.layout().setContentsMargins(5, 5, 5, 5)
        self.setObjectName(Parapluie.Object_Editor)

        self.currentFile = None

        self.editType = EditorType.Text
        self.setEditorType(EditorType.Text)

    def formatText(self, key: bool = False, sync=True):
        text = self.editor.text()
        if text != "":
            new_text = Formatter.dumps(text, self.editType,
                                       self.pushAlert if not key else None)
            if new_text:
                self.editor.setText(new_text)
                if sync:
                    self.syncJson(key)

    def syncJson(self, key: bool = False):
        obj = self.getData(key)
        if self.editType == EditorType.JSON or self.editType == EditorType.XML:
            self.syncRequest.emit(obj)
            self.formatText(key, False)

    def pushAlert(self, text, tpe=Parapluie.Alert_Error):
        self.alert.emit(text, tpe, None, None)

    def setData(self, obj):
        text = Formatter.dumps(obj, self.editType,
                               self.pushAlert if obj is None else None)
        self.editor.setText(text)

    def getData(self, key: bool = False):
        text = self.editor.text()
        if text != "":
            if self.editType == EditorType.JSON:
                try:
                    obj = json.loads(text)
                    return obj
                except Exception as ex:
                    logging.exception(ex)
                    if not key:
                        self.pushAlert(str(ex))
                    return None
            elif self.editType == EditorType.XML:
                try:
                    obj = Et.fromstring(text)
                    return obj
                except Exception as ex:
                    logging.exception(ex)
                    if not key:
                        self.pushAlert(str(ex))
                    return None
        else:
            if self.editType == EditorType.JSON:
                return {}
            elif self.editType == EditorType.XML:
                return None
        return text

    def setText(self, text):
        self.editor.setText(text)

    def text(self):
        return self.editor.text()

    def wrapText(self):
        if self.wrapButton.isChecked():
            self.editor.setWrapMode(Qsci.QsciScintilla.WrapNone)
        else:
            self.editor.setWrapMode(Qsci.QsciScintilla.WrapWord)

    def editorEvent(self, key):
        if key == "ENTER":
            self.syncJson(True)
        elif key == "B":
            self.syncJson()
        elif key == "F":
            self.formatText()

    def setTitle(self, title):
        self.title.setText(title)

    def setEditorType(self, tpe: EditorType, inner=False):
        self.editType = tpe
        if not inner:
            self.editorTypeBox.setCurrentIndex(tpe.value)

        if tpe == EditorType.JSON:
            self.editor.changeLexer(Qsci.QsciLexerJSON(self.editor), 'JSON')
        elif tpe == EditorType.XML:
            self.editor.changeLexer(Qsci.QsciLexerXML(self.editor), 'XML')
        elif tpe == EditorType.HTML:
            self.editor.changeLexer(Qsci.QsciLexerHTML(self.editor), 'HTML')
        elif tpe == EditorType.Javascript:
            self.editor.changeLexer(Qsci.QsciLexerJavaScript(self.editor),
                                    'Javascript')
        else:
            self.editor.changeLexer(Qsci.QsciLexerMarkdown(self.editor),
                                    'Text<')

        self.editorTypeChanged.emit(tpe.value)

    def blockEditorType(self, block):
        self.editorTypeBox.setVisible(not block)

    # ["Text", "JSON", "XML", "HTML"]
    def editorTypeChange(self, index):
        if index == 0:
            self.setEditorType(EditorType.Text, True)
        elif index == 1:
            self.setEditorType(EditorType.JSON, True)
        elif index == 2:
            self.setEditorType(EditorType.XML, True)
        elif index == 3:
            self.setEditorType(EditorType.HTML, True)

    def setFile(self, file: XFile):
        # save data cũ
        if self.currentFile is not None:
            self.currentFile.unsavedData = self.text()
        # load data moi
        self.currentFile = file
        self.setTitle(file.name()[0])

        if file.name()[1].lower() == '.json':
            self.setEditorType(EditorType.JSON)
        elif file.name()[1].lower() == '.xml':
            self.setEditorType(EditorType.XML)
        elif file.name()[1].lower() == '.html':
            self.setEditorType(EditorType.HTML)
        elif file.name()[1].lower() == '.js':
            self.setEditorType(EditorType.Javascript)
        else:
            self.setEditorType(EditorType.Text)

        self.title.setEditable(not os.path.isfile(file.getPath()))
        if file.unsavedData != "":
            self.setText(file.unsavedData)
        else:
            if os.path.isfile(file.getPath()):
                d = open(file.getPath(), "r", encoding="utf-8").read()
                self.setText(d)
            else:
                self.setText("")
        self.syncJson()

    def saveData(self):
        if self.currentFile is None:
            init_dir = Config.getViewerConfig_LastOpen()
            file = os.path.join(init_dir, self.title.text())
            name = QFileDialog.getSaveFileName(self, 'Save file', file,
                                               self.getFileExtension())
            if name[0] != "":
                config = Config.getConfig()
                config["viewer"]["last_open"] = os.path.dirname(name[0])
                Config.updateConfig(config)
                self.currentFile = XFile(name[0])
                self.save(self.currentFile)
        else:
            if not os.path.isfile(self.currentFile.getPath()):
                name = QFileDialog.getSaveFileName(self, 'Save file',
                                                   self.currentFile.getPath(),
                                                   self.getFileExtension())
                if name[0] != "":
                    self.currentFile.setPath(name[0])
                    if self.save(self.currentFile) is not None:
                        self.saveDataDone.emit(name[0])
            else:
                if self.save(self.currentFile) is not None:
                    self.saveDataDone.emit(self.currentFile.getPath())

    def save(self, f: XFile):
        try:
            file = open(f.getPath(), "w", encoding="utf-8")
            file.write(self.text())
            file.close()
            f.unsavedData = ""
            self.pushAlert("Saved: " + f.getPath(),
                           Parapluie.Alert_Information)
            return f.getPath()
        except Exception as ex:
            logging.exception(ex)
            self.pushAlert(str(ex))

    def getFileExtension(self):
        if self.editType == EditorType.JSON:
            return "JSON files (*.json);; All files (*)"
        elif self.editType == EditorType.XML:
            return "XML files (*.xml);; All files (*)"
        elif self.editType == EditorType.HTML:
            return "HTML files (*.html);; All files (*)"
        elif self.editType == EditorType.Javascript:
            return "Javascript files (*.js);; All files (*)"
        else:
            return "All files (*)"
Esempio n. 9
0
class QRectangleCreator:
    def __init__(self, iface):
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'qrectanglecreator_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.actions = []
        self.menu = self.tr(u'&QRectangleCreator')
        self.toolsToolbar = self.iface.addToolBar(u'QRectangle Creator')
        self.toolsToolbar.setObjectName(u'QRectangle Creator')
        self.settingsDlg = SettingsDialog()
        self.settingsDlg.width.valueChanged.connect(self.settingsChanged)
        self.settingsDlg.height.valueChanged.connect(self.settingsChanged)
        self.settingsDlg.angle.valueChanged.connect(self.settingsChanged)
        self.first_start = None

    def tr(self, message):
        return QCoreApplication.translate('QRectangleCreator', message)

    def add_action(self,
                   icon_path,
                   text,
                   callback,
                   enabled_flag=True,
                   add_to_menu=True,
                   add_to_toolbar=True,
                   status_tip=None,
                   whats_this=None,
                   parent=None,
                   checkable=False,
                   checked=False,
                   shortcut=None):

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolsToolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        if checkable:
            action.setCheckable(True)

        if checked:
            action.setChecked(1)

        if shortcut:
            action.setShortcut(shortcut)

        self.actions.append(action)

        return action

    def initGui(self):

        icon_path = ':/plugins/QRectangleCreator/icons/'

        #LoginButton
        self.mainButton = QToolButton()
        self.mainButton.setIcon(QIcon(icon_path + 'addRectangle.png'))
        self.mainButton.setPopupMode(QToolButton.MenuButtonPopup)
        self.mainButton.clicked.connect(self.run)
        self.mainButton.setToolTip('Add Rectangle')
        self.mainButton.setEnabled(True)
        self.mainButton.setCheckable(True)
        self.mainButton.setMenu(QMenu())
        self.toolsToolbar.addWidget(self.mainButton)

        #SettingsButton
        self.SettingsButton = self.add_action(icon_path + 'addRectangle.png',
                                              text=self.tr(u'Settings'),
                                              callback=self.settings,
                                              parent=self.iface.mainWindow(),
                                              add_to_menu=False,
                                              enabled_flag=False,
                                              add_to_toolbar=False)
        m = self.mainButton.menu()
        m.addAction(self.SettingsButton)

        self.first_start = True

    def unload(self):
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&QRectangleCreator'), action)
            self.iface.removeToolBarIcon(action)

    def run(self):
        if self.first_start == True:
            self.first_start = False

        if self.mainButton.isChecked() == 1:
            self.drawingObject = StartDrawing(self.iface.mapCanvas(),
                                              self.iface)
            self.drawingObject.setConfiguration(
                self.settingsDlg.width.value(),
                self.settingsDlg.height.value(),
                self.settingsDlg.angle.value())
            self.iface.mapCanvas().setMapTool(self.drawingObject)
            self.SettingsButton.setEnabled(True)
        else:
            self.iface.mapCanvas().unsetMapTool(self.drawingObject)
            self.drawingObject.reset()
            self.SettingsButton.setEnabled(False)

    def settings(self):
        self.settingsDlg.show()
        current_width = self.settingsDlg.width.value()
        current_height = self.settingsDlg.height.value()
        current_angle = self.settingsDlg.angle.value()

        if self.settingsDlg.exec_() != 1:
            self.settingsDlg.width.setValue(current_width)
            self.settingsDlg.height.setValue(current_height)
            self.settingsDlg.angle.setValue(current_angle)

    def settingsChanged(self):
        self.drawingObject.setConfiguration(self.settingsDlg.width.value(),
                                            self.settingsDlg.height.value(),
                                            self.settingsDlg.angle.value())
Esempio n. 10
0
class View(QFrame):
    def __init__(self, name, parent=None):
        super().__init__(parent)

        self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel)
        self.graphicsView = GraphicsView(self)
        self.graphicsView.setRenderHint(QPainter.Antialiasing, False)
        self.graphicsView.setDragMode(QGraphicsView.RubberBandDrag)
        self.graphicsView.setOptimizationFlags(
            QGraphicsView.DontSavePainterState)
        self.graphicsView.setViewportUpdateMode(
            QGraphicsView.SmartViewportUpdate)
        self.graphicsView.setTransformationAnchor(
            QGraphicsView.AnchorUnderMouse)

        size = self.style().pixelMetric(QStyle.PM_ToolBarIconSize)
        iconSize = QSize(size, size)

        zoomInIcon = QToolButton()
        zoomInIcon.setAutoRepeat(True)
        zoomInIcon.setAutoRepeatInterval(33)
        zoomInIcon.setAutoRepeatDelay(0)
        zoomInIcon.setIcon(QIcon(QPixmap(':/images/zoomin.png')))
        zoomInIcon.setIconSize(iconSize)
        zoomOutIcon = QToolButton()
        zoomOutIcon.setAutoRepeat(True)
        zoomOutIcon.setAutoRepeatInterval(33)
        zoomOutIcon.setAutoRepeatDelay(0)
        zoomOutIcon.setIcon(QIcon(QPixmap(':/images/zoomout.png')))
        zoomOutIcon.setIconSize(iconSize)
        self.zoomSlider = QSlider()
        self.zoomSlider.setMinimum(0)
        self.zoomSlider.setMaximum(500)
        self.zoomSlider.setValue(250)
        self.zoomSlider.setTickPosition(QSlider.TicksRight)

        zoomSliderLayout = QVBoxLayout()
        zoomSliderLayout.addWidget(zoomInIcon)
        zoomSliderLayout.addWidget(self.zoomSlider)
        zoomSliderLayout.addWidget(zoomOutIcon)

        rotateLeftIcon = QToolButton()
        rotateLeftIcon.setIcon(QIcon(QPixmap(':/images/rotateleft.png')))
        rotateLeftIcon.setIconSize(iconSize)
        rotateRightIcon = QToolButton()
        rotateRightIcon.setIcon(QIcon(QPixmap(':/images/rotateright.png')))
        rotateRightIcon.setIconSize(iconSize)
        self.rotateSlider = QSlider()
        self.rotateSlider.setOrientation(Qt.Horizontal)
        self.rotateSlider.setMinimum(-360)
        self.rotateSlider.setMaximum(360)
        self.rotateSlider.setValue(0)
        self.rotateSlider.setTickPosition(QSlider.TicksBelow)

        rotateSliderLayout = QHBoxLayout()
        rotateSliderLayout.addWidget(rotateLeftIcon)
        rotateSliderLayout.addWidget(self.rotateSlider)
        rotateSliderLayout.addWidget(rotateRightIcon)

        self.resetButton = QToolButton()
        self.resetButton.setText('0')
        self.resetButton.setEnabled(False)

        labelLayout = QHBoxLayout()
        self.label = QLabel(name)
        self.label2 = QLabel("Pointer Mode")
        self.selectModeButton = QToolButton()
        self.selectModeButton.setText("Select")
        self.selectModeButton.setCheckable(True)
        self.selectModeButton.setChecked(True)
        self.dragModeButton = QToolButton()
        self.dragModeButton.setText("Drag")
        self.dragModeButton.setCheckable(True)
        self.dragModeButton.setChecked(False)
        self.openGlButton = QToolButton()
        self.openGlButton.setText("OpenGL")
        self.openGlButton.setCheckable(True)
        self.openGlButton.setEnabled(QGLFormat.hasOpenGL())
        self.antialiasButton = QToolButton()
        self.antialiasButton.setText("Antialiasing")
        self.antialiasButton.setCheckable(True)
        self.antialiasButton.setChecked(False)

        self.printButton = QToolButton()
        self.printButton.setIcon(QIcon(QPixmap(":/images/fileprint.png")))

        pointerModeGroup = QButtonGroup(self)
        pointerModeGroup.setExclusive(True)
        pointerModeGroup.addButton(self.selectModeButton)
        pointerModeGroup.addButton(self.dragModeButton)

        labelLayout.addWidget(self.label)
        labelLayout.addStretch()
        labelLayout.addWidget(self.label2)
        labelLayout.addWidget(self.selectModeButton)
        labelLayout.addWidget(self.dragModeButton)
        labelLayout.addStretch()
        labelLayout.addWidget(self.antialiasButton)
        labelLayout.addWidget(self.openGlButton)
        labelLayout.addWidget(self.printButton)

        topLayout = QGridLayout()
        topLayout.addLayout(labelLayout, 0, 0)
        topLayout.addWidget(self.graphicsView, 1, 0)
        topLayout.addLayout(zoomSliderLayout, 1, 1)
        topLayout.addLayout(rotateSliderLayout, 2, 0)
        topLayout.addWidget(self.resetButton, 2, 1)
        self.setLayout(topLayout)

        self.resetButton.clicked.connect(self.resetView)
        self.zoomSlider.valueChanged.connect(self.setupMatrix)
        self.rotateSlider.valueChanged.connect(self.setupMatrix)
        self.graphicsView.verticalScrollBar().valueChanged.connect(
            self.setResetButtonEnabled)
        self.graphicsView.horizontalScrollBar().valueChanged.connect(
            self.setResetButtonEnabled)
        self.selectModeButton.toggled.connect(self.togglePointerMode)
        self.dragModeButton.toggled.connect(self.togglePointerMode)
        self.antialiasButton.toggled.connect(self.toggleAntialiasing)
        self.openGlButton.toggled.connect(self.toggleOpenGL)
        rotateLeftIcon.clicked.connect(self.rotateLeft)
        rotateRightIcon.clicked.connect(self.rotateRight)
        zoomInIcon.clicked.connect(self.zoomIn)
        zoomOutIcon.clicked.connect(self.zoomOut)
        self.printButton.clicked.connect(self.print)

        self.setupMatrix()

    def view(self):
        return self.graphicsView

    def resetView(self):
        self.zoomSlider.setValue(250)
        self.rotateSlider.setValue(0)
        self.setupMatrix()
        self.graphicsView.ensureVisible(QRectF(0, 0, 0, 0))

        self.resetButton.setEnabled(False)

    def setResetButtonEnabled(self):
        self.resetButton.setEnabled(True)

    def setupMatrix(self):
        scale = pow(2.0, (self.zoomSlider.value() - 250) / 50)
        matrix = QTransform()
        matrix.scale(scale, scale)
        matrix.rotate(self.rotateSlider.value())

        self.graphicsView.setTransform(matrix)
        self.setResetButtonEnabled()

    def togglePointerMode(self):

        self.graphicsView.setDragMode(
            QGraphicsView.RubberBandDrag if self.selectModeButton.isChecked(
            ) else QGraphicsView.ScrollHandDrag)
        self.graphicsView.setInteractive(self.selectModeButton.isChecked())

    def toggleOpenGL(self):
        vp = QWidget()

        if self.openGlButton.isChecked():
            fmt = QSurfaceFormat()
            fmt.setSamples(8)
            vp = QOpenGLWidget()
            vp.setFormat(fmt)

        self.graphicsView.setViewport(vp)

    def toggleAntialiasing(self):
        self.graphicsView.setRenderHint(QPainter.Antialiasing,
                                        self.antialiasButton.isChecked())

    def print(self):
        pass

    def zoomIn(self, level=1):
        self.zoomSlider.setValue(self.zoomSlider.value() + level)

    def zoomOut(self, level=1):
        self.zoomSlider.setValue(self.zoomSlider.value() - level)

    def rotateLeft(self):
        self.rotateSlider.setValue(self.rotateSlider.value() - 10)

    def rotateRight(self):
        self.rotateSlider.setValue(self.rotateSlider.value() + 10)
Esempio n. 11
0
class kstImageViewer(QWidget):

	def __init__(self, sourceFile, data, type, image, mode):
		""" Class constructor.
		"""
		QWidget.__init__(self)

		# Initialize image panel:
		self.imagePanel = _kstImagePanel()

		# Set original mode:
		self.__originalMode = mode

		# Set the type of image with respect of the lightfield pipeline:        
		self.__imageType = type      # 'raw', 'pre-processed', 'reconstructed', 'post-processed'

		# The actual object handled by the image viewer:
		self.__data = data

		# Properties:
		self.__sourceFile = sourceFile		
		
		# Current view index:
		self.__view = 0	
		
		# Top toolbar:
		self.topToolBar = QToolBar()
		self._createTopToolbar()

		# Bottom toolbar:
		self.bottomToolBar = QToolBar()
		self._createBottomToolbar()	

		# Handle mouse hover with custom slot:
		self.imagePanel.mouseHoverEvent.connect(self._handleMouseHover)

		# Compose layout of the whole widget:
		layout = QVBoxLayout()	
		layout.addWidget(self.topToolBar)
		layout.addWidget(self.imagePanel)
		layout.addWidget(self.bottomToolBar)	
		layout.setContentsMargins(0,0,0,0)	
		self.setLayout(layout)
		self.setContentsMargins(0,0,0,0)	

		# Set image:
		self.__setImage(image)



	def _createTopToolbar(self):
		"""
        """
		topToolbarSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)        
		self.topToolBar.setSizePolicy(topToolbarSizePolicy)

		#pan_zoom = QAction(QIcon(dir + "/resources/btnDrag.png"),"Pan (Mouse
		#Left)",self)
		#self.toolBar.addAction(pan_zoom)
		#zoomSelect = QAction(QIcon(dir + "/resources/btnZoomSelect.png"),"ROI Zoom
		#(Mouse Left)",self)
		#self.toolBar.addAction(zoomSelect)
		exitAct = QAction('Exit', self)
		exitAct.setShortcut('Ctrl+Q')

		self._panZoom = QToolButton(self)
		self._panZoom.setIcon(QIcon(PAN_ZOOM_ICON))
		self._panZoom.setToolTip(PAN_ZOOM_TOOLTIP)
		self._panZoom.setCheckable(True)
		self._panZoom.setChecked(True)
		self._panZoom.clicked.connect(self._panZoomSwitch)
		self.topToolBar.addWidget(self._panZoom)

		self._zoomSelect = QToolButton(self)
		self._zoomSelect.setIcon(QIcon(ZOOM_SELECT_ICON))
		self._zoomSelect.setToolTip(ZOOM_SELECT_TOOLTIP)
		self._zoomSelect.setCheckable(True)
		self._zoomSelect.setChecked(False)
		self._zoomSelect.clicked.connect(self._zoomSelectSwitch)
		self.topToolBar.addWidget(self._zoomSelect)

		self.topToolBar.addSeparator()

		zoomIn = QAction(QIcon(ZOOM_IN_ICON),ZOOM_IN_TOOLTIP,self)        
		self.topToolBar.addAction(zoomIn)
		zoomOut = QAction(QIcon(ZOOM_OUT_ICON),ZOOM_OUT_TOOLTIP,self)        
		self.topToolBar.addAction(zoomOut)
		zoomReset = QAction(QIcon(ZOOM_RESET_ICON),ZOOM_RESET_TOOLTIP,self)        
		self.topToolBar.addAction(zoomReset)

		self.topToolBar.addSeparator()

		# Separator:
		#self.fooWidget = QWidget()
		#self.fooWidget.setFixedWidth(6)
		#self.fooWidgetAction = self.topToolBar.addWidget(self.fooWidget)

		#self.extraSeparatorAction = self.topToolBar.addSeparator()

		export = QAction(QIcon(EXPORT_ICON),EXPORT_TOOLTIP,self)        
		self.topToolBar.addAction(export)

		exportAll = QAction(QIcon(EXPORTALL_ICON),EXPORTALL_TOOLTIP,self)        
		self.topToolBar.addAction(exportAll)
								
		# Spacer:
		spacer = QWidget()
		spacerSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)   
		spacer.setSizePolicy(spacerSizePolicy)
		self.topToolBar.addWidget(spacer)
		
		# Label on the right:
		self.hoverLabel = QLabel(self)
		self.hoverLabel.setText("")
		self.topToolBar.addWidget(self.hoverLabel) 
			

		# Connect handler for toolbar buttons:
		self.topToolBar.actionTriggered[QAction].connect(self._toolBarBtnPressed)




	def _createBottomToolbar(self):
		"""
		"""
		
		bottomToolbarSizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)        
		self.bottomToolBar.setSizePolicy(bottomToolbarSizePolicy)	
	
		# Combo box for the 4 "views" of a dataset:
		self.lblView = QLabel(" View: ")   # Use spaces		
		self.lblViewAction = self.bottomToolBar.addWidget(self.lblView)			

		self.cbxView = QComboBox()
		self.cbxView.addItems(["Projection/Axial", "Sinogram/Sagittal", "Lateral/Frontal"])
		self.cbxView.currentIndexChanged.connect(self.changeView)
		self.cbxViewAction = self.bottomToolBar.addWidget(self.cbxView)	
		
	
		self.indexLabel = QLabel(self)
		self.indexLabel.setText("")
		self.indexLabel.setFixedWidth(70)
		self.indexLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
		self.bottomToolBar.addWidget(self.indexLabel)


		# Slider for the projection/slices:
		self.lblImageSlider = QLabel(" Image: ") # Use spaces
		self.lblImageSliderAction = self.bottomToolBar.addWidget(self.lblImageSlider)
		
		self.sldDataset = QSlider(Qt.Horizontal) 
		self.sldDataset.setFixedWidth(250)
		self.sldDataset.setFocusPolicy(Qt.StrongFocus)
		self.sldDataset.setTickPosition(QSlider.TicksBelow)
		self.sldDataset.valueChanged.connect(self.changeDatasetView)		
		self.sldDatasetAction = self.bottomToolBar.addWidget(self.sldDataset)		
		
		# Slider for the repetitions:
		self.lblRepetitionIndex = QLabel(self)
		self.lblRepetitionIndex.setText("")
		self.lblRepetitionIndex.setFixedWidth(50)
		self.lblRepetitionIndex.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
		self.bottomToolBar.addWidget(self.lblRepetitionIndex)

		self.lblRepetitionSlider = QLabel(" Repetition: ") # Use spaces
		self.lblRepetitionSlider.setFixedWidth(80)
		self.lblRepetitionSlider.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
		self.lblRepetitionSliderAction = self.bottomToolBar.addWidget(self.lblRepetitionSlider)		
		
		self.sldRepetition = QSlider(Qt.Horizontal) 
		self.sldRepetition.setFixedWidth(150)
		self.sldRepetition.setFocusPolicy(Qt.StrongFocus)
		self.sldRepetition.setTickPosition(QSlider.TicksBelow)
		self.sldRepetition.valueChanged.connect(self.changeRepetitionView)
		self.sldRepetitionAction = self.bottomToolBar.addWidget(self.sldRepetition)		
			

		if self.__data.ndim == 4:
			self.lblRepetitionSliderAction.setVisible(True)
			self.sldRepetitionAction.setVisible(True)
		else:
			self.lblRepetitionSliderAction.setVisible(False)
			self.sldRepetitionAction.setVisible(False)
			

	#def drawBackground(self, painter, rect):

	#	color = self.palette().color(QPalette.Background)
	#	background_brush = QBrush( color, Qt.SolidPattern)
	#	painter.fillRect(rect, background_brush)

	def _panZoomSwitch(self):

		self._zoomSelect.setChecked(not self._panZoom.isChecked())
		self.imagePanel.togglePanZoom = self._zoomSelect.isChecked()

	def _zoomSelectSwitch(self):

		self._panZoom.setChecked(not self._zoomSelect.isChecked())
		self.imagePanel.togglePanZoom = self._zoomSelect.isChecked()
		
	def _toolBarBtnPressed(self, button):

		if button.text() == ZOOM_IN_TOOLTIP:
			self.imagePanel.performZoom(min(400.0,self.imagePanel.zoomFactor*1.15))
		elif button.text() == ZOOM_OUT_TOOLTIP:
			self.imagePanel.performZoom(max(1.0,self.imagePanel.zoomFactor/1.15))
		elif button.text() == ZOOM_RESET_TOOLTIP:
			self.imagePanel.performZoom(1.0)
		elif button.text() == EXPORT_TOOLTIP:

			# Open a Save As dialog:
			try:
				options = QFileDialog.Options()
				options |= QFileDialog.DontUseNativeDialog
				filename, _ = QFileDialog.getSaveFileName(self,"Save as TIFF", 
							  "","TIFF Files (*.tif);;All Files (*)", options=options)
				if filename:
				
					# Call the method to save the current displayed image:
					self.imagePanel.saveAsTIFF(filename)

			except Exception as e:
				eprint(str(e))

		elif button.text() == EXPORTALL_TOOLTIP:

			# Open a Save As dialog:
			try:
				options = QFileDialog.Options()
				options |= QFileDialog.DontUseNativeDialog
				options |= QFileDialog.DirectoryOnly
				folder = QFileDialog.getExistingDirectory(self, "Select Folder for TIFF sequence")

				if folder: 			
				
					for i in range(0,self.__data.shape[2]):
		
						# Prepare filename:
						filename = os.path.join(folder, "image_" + "{:04d}".format(i) + ".tif")

						# Save as TIFF with tiffile library:
						tifffile.imsave(filename, data=self.__data[:,:,i])

			except Exception as e:
				eprint(str(e))
			



	def _handleMouseHover(self, x, y, z, type):

		if (x == -1):
			self.hoverLabel.setText("")
		else:
			if (type == 'float'):
				s = "{:0.4f}".format(z) if (z > 1e-2) else "{:.4E}".format(z)
			else:
				s = "{:d}".format(round(z))
			self.hoverLabel.setText("[" + str(x) + "," + str(y) + "]=" + s + " " )


	def __setImage(self, npImage):
		""" Set the scene's current image pixmap to the input image as a numpy array.
		:type npImage: numpy array
		"""
		# Set the new numpy image:
		self.imagePanel.setImage(npImage)  

		# Enable/disable UI widgets:
		if (self.__imageType == 'raw'):
			self.lblViewAction.setVisible(True)
			self.cbxViewAction.setVisible(True)
			self.lblImageSliderAction.setVisible(True)
			self.sldDatasetAction.setVisible(True)
			if self.__data.ndim == 4:
				self.lblRepetitionSliderAction.setVisible(True)
				self.lblRepetitionIndex.setVisible(True)
				self.sldRepetitionAction.setVisible(True)
			else:
				self.lblRepetitionSliderAction.setVisible(False)
				self.lblRepetitionIndex.setVisible(False)
				self.sldRepetitionAction.setVisible(False)

		elif (self.__imageType == 'pre-processed'):
			self.lblViewAction.setVisible(True)
			self.cbxViewAction.setVisible(True)
			self.lblImageSliderAction.setVisible(True)
			self.sldDatasetAction.setVisible(True)
			self.sldRepetitionAction.setVisible(False)
			self.lblRepetitionIndex.setVisible(False)
			self.lblRepetitionSliderAction.setVisible(False)

		elif (self.__imageType == 'reconstructed'):
			self.lblViewAction.setVisible(True)
			self.cbxViewAction.setVisible(True)
			self.lblImageSliderAction.setVisible(True)
			self.sldDatasetAction.setVisible(True)
			self.sldRepetitionAction.setVisible(False)
			self.lblRepetitionIndex.setVisible(False)
			self.lblRepetitionSliderAction.setVisible(False)

		# Set dimension of the slider and default:
		self.sldDataset.setMinimum(0)
		self.sldDataset.setMaximum(self.__data.shape[2]-1)
		self.sldDataset.setValue(round(self.__data.shape[2]/2))

		self.indexLabel.setText(str(round(self.__data.shape[2]/2)) \
			+ "/" + str(round(self.__data.shape[2])))


	def changeView(self, idx):
		""" Called when the combo box index is changed.
		"""
		# Reset sliders:
		self.sldDataset.setValue(0)
		if self.__data.ndim == 4:
			self.sldRepetition.setValue(0)
	
		# Transpose datasets:
		if idx == 0: # Axial or projection view:
			if self.__data.ndim == 4:
				if self.__view == 1:
					self.__data = numpy.transpose(self.__data, (2,1,0,3)) # OK
				if self.__view == 2:
					self.__data = numpy.transpose(self.__data, (1,2,0,3)) # OK
			else:
				if self.__view == 1:				    
					self.__data = numpy.transpose(self.__data, (2,1,0))   # OK
				if self.__view == 2:
					self.__data = numpy.transpose(self.__data, (1,2,0))   # OK

		elif idx == 1: # Sinogram of sagittal view:
			if self.__data.ndim == 4:
				if self.__view == 0:
					self.__data = numpy.transpose(self.__data, (2,1,0,3)) # OK
				if self.__view == 2:
					self.__data = numpy.transpose(self.__data, (0,2,1,3)) # OK
			else:
				if self.__view == 0:				    
					self.__data = numpy.transpose(self.__data, (2,1,0))   # OK
				if self.__view == 2:
					self.__data = numpy.transpose(self.__data, (0,2,1))   # OK

		else: # Lateral or coronal view:
			if self.__data.ndim == 4:
				if self.__view == 0:
					self.__data = numpy.transpose(self.__data, (2,0,1,3)) # OK
				if self.__view == 1:
					self.__data = numpy.transpose(self.__data, (0,2,1,3)) # OK
			else:
				if self.__view == 0:				    
					self.__data = numpy.transpose(self.__data, (2,0,1))   # OK
				if self.__view == 1:
					self.__data = numpy.transpose(self.__data, (0,2,1))   # OK

		# Set new view:
		self.__view = idx


		# Change to the new numpy image:
		if self.__data.ndim == 4:
			self.imagePanel.changeImage(self.__data[:,:,round(self.__data.shape[2]/2),round(self.__data.shape[3]/2)])
		else:
			self.imagePanel.changeImage(self.__data[:,:,round(self.__data.shape[2]/2)])

		# Set the index:
		self.sldDataset.setMinimum(0)
		self.sldDataset.setMaximum(self.__data.shape[2]-1)
		self.sldDataset.setValue(round(self.__data.shape[2]/2))
	
		# Reset zoom:
		self.imagePanel.performZoom(1.0)

	def changeDatasetView(self):
		""" Called when the slider is moved, so user wants to see a different 
            projection or slice.
		"""
		val = int(self.sldDataset.value())		

		# Change to the new numpy image:
		if self.__data.ndim == 4:
			rep = int(self.sldRepetition.value())
			self.imagePanel.changeImage(self.__data[:,:,val,rep])            
			#self.sldRepetition.setValue(round(self.__data.shape[3]/2))
		else:
			self.imagePanel.changeImage(self.__data[:,:,val])

		# Set the index:
		self.indexLabel.setText(str(val + 1) + "/" + str(round(self.__data.shape[2])))


	def changeRepetitionView(self):
		""" Called when the slider is moved, so user wants to see a different
			repetition of the same projection.
		"""
		img = int(self.sldDataset.value())
		val = int(self.sldRepetition.value())

		# Change to the new numpy image:
		self.imagePanel.changeImage(self.__data[:,:,img,val])

		# Set the index:
		self.lblRepetitionIndex.setText(str(val+1) + "/" + str(round(self.__data.shape[3])))
			

	def getType(self):
		""" Get the type of current image viewer.
		"""

		# Set the new numpy image:
		return self.__imageType


	def getOriginalMode(self):
		""" Get the original mode (2COL or 1COL).
		"""

		# Set the new numpy image:
		return self.__originalMode


	def getSourceFile(self):
		""" Get the source file of current image viewer.
		"""

		# Set the new numpy image:
		return self.__sourceFile


	def getImage(self):
		""" Get the scene's current image pixmap as a numpy array.
		"""

		# Set the new numpy image:
		return self.imagePanel.npImage


	def getData(self):
		""" Get the data connected to this image viewer.
		"""
		
		return self.__data
Esempio n. 12
0
class View(QFrame):
    graphicsView = None
    label = None
    label2 = None
    selectModeButton = None
    dragModeButton = None
    openGlButton = None
    antialiasButton = None
    resetButton = None
    zoomSlider = None
    rotateSlider = None

    def __init__(self, name, parent=None):
        super(View, self).__init__(parent)
        self.init_ui(name)

    def init_ui(self, name):
        self.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel)
        self.graphicsView = GraphicsView(self)
        self.graphicsView.setRenderHint(QPainter.Antialiasing, False)
        self.graphicsView.setDragMode(QGraphicsView.RubberBandDrag)
        self.graphicsView.setOptimizationFlags(
            QGraphicsView.DontSavePainterState)
        self.graphicsView.setViewportUpdateMode(
            QGraphicsView.SmartViewportUpdate)
        self.graphicsView.setTransformationAnchor(
            QGraphicsView.AnchorUnderMouse)

        size = self.style().pixelMetric(QStyle.PM_ToolBarIconSize)
        iconSize = QSize(size, size)

        zoomInIcon = QToolButton()
        zoomInIcon.setAutoRepeat(True)
        zoomInIcon.setAutoRepeatInterval(33)
        zoomInIcon.setAutoRepeatDelay(0)
        zoomInIcon.setIcon(QIcon(":/zoomin.png"))
        zoomInIcon.setIconSize(iconSize)
        zoomOutIcon = QToolButton()
        zoomOutIcon.setAutoRepeat(True)
        zoomOutIcon.setAutoRepeatInterval(33)
        zoomOutIcon.setAutoRepeatDelay(0)
        zoomOutIcon.setIcon(QIcon(":/zoomout.png"))
        zoomOutIcon.setIconSize(iconSize)
        self.zoomSlider = QSlider()
        self.zoomSlider.setMinimum(0)
        self.zoomSlider.setMaximum(500)
        self.zoomSlider.setValue(250)
        self.zoomSlider.setTickPosition(QSlider.TicksRight)

        # Zoom slider layout
        zoomSliderLayout = QVBoxLayout()
        zoomSliderLayout.addWidget(zoomInIcon)
        zoomSliderLayout.addWidget(self.zoomSlider)
        zoomSliderLayout.addWidget(zoomOutIcon)

        rotateLeftIcon = QToolButton()
        rotateLeftIcon.setIcon(QIcon(":/rotateleft.png"))
        rotateLeftIcon.setIconSize(iconSize)
        rotateRightIcon = QToolButton()
        rotateRightIcon.setIcon(QIcon(":/rotateright.png"))
        rotateRightIcon.setIconSize(iconSize)
        self.rotateSlider = QSlider()
        self.rotateSlider.setOrientation(Qt.Horizontal)
        self.rotateSlider.setMinimum(-360)
        self.rotateSlider.setMaximum(360)
        self.rotateSlider.setValue(0)
        self.rotateSlider.setTickPosition(QSlider.TicksBelow)

        # Rotate slider layout
        rotateSliderLayout = QHBoxLayout()
        rotateSliderLayout.addWidget(rotateLeftIcon)
        rotateSliderLayout.addWidget(self.rotateSlider)
        rotateSliderLayout.addWidget(rotateRightIcon)

        self.resetButton = QToolButton()
        self.resetButton.setText("0")
        self.resetButton.setEnabled(False)

        # Label layout
        labelLayout = QHBoxLayout()
        self.label = QLabel(name)
        self.label2 = QLabel("Pointer Mode")
        self.selectModeButton = QToolButton()
        self.selectModeButton.setText("Select")
        self.selectModeButton.setCheckable(True)
        self.selectModeButton.setChecked(True)
        self.dragModeButton = QToolButton()
        self.dragModeButton.setText("Drag")
        self.dragModeButton.setCheckable(True)
        self.dragModeButton.setChecked(False)
        self.antialiasButton = QToolButton()
        self.antialiasButton.setText("Antialiasing")
        self.antialiasButton.setCheckable(True)
        self.antialiasButton.setChecked(False)
        self.openGlButton = QToolButton()
        self.openGlButton.setText("OpenGL")
        self.openGlButton.setCheckable(True)
        self.openGlButton.setEnabled(QGLFormat.hasOpenGL())

        pointerModeGroup = QButtonGroup()
        pointerModeGroup.setExclusive(True)
        pointerModeGroup.addButton(self.selectModeButton)
        pointerModeGroup.addButton(self.dragModeButton)

        labelLayout.addWidget(self.label)
        labelLayout.addStretch()
        labelLayout.addWidget(self.label2)
        labelLayout.addWidget(self.selectModeButton)
        labelLayout.addWidget(self.dragModeButton)
        labelLayout.addStretch()
        labelLayout.addWidget(self.antialiasButton)
        labelLayout.addWidget(self.openGlButton)

        topLayout = QGridLayout()
        topLayout.addLayout(labelLayout, 0, 0)
        topLayout.addWidget(self.graphicsView, 1, 0)
        topLayout.addLayout(zoomSliderLayout, 1, 1)
        topLayout.addLayout(rotateSliderLayout, 2, 0)
        topLayout.addWidget(self.resetButton, 2, 1)
        self.setLayout(topLayout)

        self.resetButton.clicked.connect(self.resetView)
        self.zoomSlider.valueChanged.connect(self.setupTransform)
        self.rotateSlider.valueChanged.connect(self.setupTransform)

        self.graphicsView.verticalScrollBar().valueChanged.connect(
            self.setResetButtonEnabled)
        self.graphicsView.horizontalScrollBar().valueChanged.connect(
            self.setResetButtonEnabled)
        self.selectModeButton.toggled.connect(self.togglePointerMode)
        self.dragModeButton.toggled.connect(self.togglePointerMode)
        self.antialiasButton.toggled.connect(self.toggleAntialiasing)
        self.openGlButton.toggled.connect(self.toggleOpenGL)
        rotateLeftIcon.clicked.connect(self.rotateLeft)
        rotateRightIcon.clicked.connect(self.rotateRight)
        zoomInIcon.clicked.connect(self.zoomIn)
        zoomOutIcon.clicked.connect(self.zoomOut)

        self.setupTransform()

    def view(self):
        return self.graphicsView

    @pyqtSlot()
    def zoomIn(self):
        self.zoomSlider.setValue(self.zoomSlider.value() + 1)

    @pyqtSlot()
    def zoomOut(self):
        self.zoomSlider.setValue(self.zoomSlider.value() - 1)

    @pyqtSlot()
    def resetView(self):
        self.zoomSlider.setValue(250)
        self.rotateSlider.setValue(0)
        self.setupTransform()
        self.graphicsView.ensureVisible(QRectF(0, 0, 0, 0))

        self.resetButton.setEnabled(False)

    @pyqtSlot()
    def setResetButtonEnabled(self):
        self.resetButton.setEnabled(True)

    @pyqtSlot()
    def setupTransform(self):
        scale = pow(2.0, (self.zoomSlider.value() - 250) / 50.0)
        trans = QTransform()
        trans.scale(scale, scale)
        trans.rotate(self.rotateSlider.value())

        self.graphicsView.setTransform(trans)
        self.setResetButtonEnabled()

    @pyqtSlot()
    def togglePointerMode(self):
        self.graphicsView.setDragMode(
            QGraphicsView.RubberBandDrag if self.selectModeButton.isChecked(
            ) else QGraphicsView.ScrollHandDrag)
        self.graphicsView.setInteractive(self.selectModeButton.isChecked())

    @pyqtSlot()
    def toggleOpenGL(self):
        self.graphicsView.setViewport(
            QGLWidget(QGLFormat(QGL.SampleBuffers)) if self.openGlButton.
            isChecked() else QWidget())

    @pyqtSlot()
    def toggleAntialiasing(self):
        self.graphicsView.setRenderHint(QPainter.Antialiasing,
                                        self.antialiasButton.isChecked())

    @pyqtSlot()
    def rotateLeft(self):
        self.rotateSlider.setValue(self.rotateSlider.value() - 10)

    @pyqtSlot()
    def rotateRight(self):
        self.rotateSlider.setValue(self.rotateSlider.value() + 10)
Esempio n. 13
0
class CollapsibleMessageBox(QWidget):
    ''' docstring: 消息显示类,按钮触发折叠 '''
    def __init__(self,
                 Title="",
                 parent=None,
                 defaultLayout=False,
                 Message=None):
        super().__init__(parent)

        self.toggle_button = QToolButton(text=Title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)
        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

        lay = QVBoxLayout(self)
        lay.setSpacing(0)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.addWidget(self.toggle_button)
        lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

        if defaultLayout:
            lay = QVBoxLayout()
            self.text = QLabel()
            pa = QPalette()
            pa.setColor(pa.Background, Qt.white)
            pa.setColor(pa.Foreground, Qt.black)
            self.text.setAutoFillBackground(True)
            self.text.setPalette(pa)
            self.text.setTextInteractionFlags(Qt.TextSelectableByMouse)
            self.text.setTextFormat(Qt.MarkdownText)
            self.text.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
            self.text.setWordWrap(True)
            if not Message:
                Message = '空'
            self.text.setText(Message.replace('\n', '\n\n') + '\n')
            lay.addWidget(self.text)
            self.setContentLayout(lay)

    @pyqtSlot()
    def on_pressed(self):
        ''' docstring: 按钮函数,设置动画参数并触发 '''
        checked = self.toggle_button.isChecked()
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()

    def setContentLayout(self, layout):
        ''' docstring: 重新设置布局,并计算按钮动画参数 '''
        lay = self.content_area.layout()
        del lay
        self.content_area.setLayout(layout)
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)
        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)
Esempio n. 14
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):

        self.current_dir = 'F:/Desktop2020.1.17/AutoCut/'
        self.font = cv2.FONT_HERSHEY_SIMPLEX

        self.mouse_pos_initial()

        exitAct = QAction(QIcon('quit.jpg'), '&Quit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.triggered.connect(qApp.quit)

        help_contact = QAction('Contact', self)
        help_contact.triggered.connect(self.contact)

        self.menubar = self.menuBar()

        FileMenu = self.menubar.addMenu('&File')
        FileMenu.addAction(exitAct)

        HelpMenu = self.menubar.addMenu('&Help')
        HelpMenu.addAction(help_contact)

        self.read_button = QToolButton()
        self.read_button.setIcon(QIcon(self.current_dir + 'read.png'))
        self.read_button.setToolTip('Read Ctrl+R')
        self.read_button.clicked.connect(self.read)
        self.read_button.setShortcut('Ctrl+R')

        self.draw_shape_action_list = []
        self.draw_shape_list = []
        self.draw_shape_action_list_for_redo = []
        self.draw_shape_count = 1

        self.line_button = QToolButton()
        self.line_button.setIcon(QIcon(self.current_dir + 'line.png'))
        self.line_button.setToolTip('Draw line')
        self.line_button.clicked.connect(self.draw_line)
        self.line_button.setCheckable(True)
        self.draw_shape_line = False
        self.drawing_shape_line = False
        self.show_distance = False

        #        line = Line(0,0,100,100)

        self.eraser_button = QToolButton()
        self.eraser_button.setIcon(QIcon(self.current_dir + 'eraser.png'))
        self.eraser_button.setToolTip('eraser')
        self.eraser_button.clicked.connect(self.erase_shape)
        self.eraser_button.setCheckable(True)
        self.erase = False
        self.drawing_eraser = False

        self.undo_button = QToolButton()
        self.undo_button.setIcon(
            QIcon(self.current_dir + 'undo_gray_opacity.png'))
        self.undo_button.setToolTip('undo  Ctrl+Z')
        self.undo_button.clicked.connect(self.undo_draw)
        self.undo_button.setShortcut('Ctrl+Z')

        self.redo_button = QToolButton()
        self.redo_button.setIcon(
            QIcon(self.current_dir + 'redo_gray_opacity.png'))
        self.redo_button.setToolTip('redo  Ctrl+Y')
        self.redo_button.clicked.connect(self.redo_draw)
        self.redo_button.setShortcut('Ctrl+Y')

        self.clear_button = QToolButton()
        self.clear_button.setIcon(QIcon(self.current_dir + 'clear.png'))
        self.clear_button.setToolTip('clear drawing')
        self.clear_button.clicked.connect(self.clear_draw)

        self.run_button = QToolButton()
        self.run_button.setIcon(QIcon(self.current_dir + 'run.png'))
        self.run_button.setToolTip('Run F5')
        self.run_button.clicked.connect(self.run_cut)
        self.run_button.setShortcut('F5')

        self.repeat_button = QToolButton()
        self.repeat_button.setIcon(QIcon(self.current_dir + 'repeat.png'))
        self.repeat_button.setToolTip('Repeat')
        self.repeat_button.clicked.connect(self.repeat_cut)

        self.toolbar1 = self.addToolBar('Read')
        self.toolbar1.addWidget(self.read_button)

        self.toolbar2 = self.addToolBar('draw')
        self.toolbar2.addWidget(self.line_button)
        self.toolbar2.addWidget(self.undo_button)
        self.toolbar2.addWidget(self.redo_button)
        self.toolbar2.addWidget(self.eraser_button)
        self.toolbar2.addWidget(self.clear_button)

        self.toolbar3 = self.addToolBar('run')
        self.toolbar3.addWidget(self.run_button)
        self.toolbar3.addWidget(self.repeat_button)

        self.toolbar = self.addToolBar(' ')

        self.pixmap = QPixmap()
        self.lbl_main = QLabel(self)
        self.lbl_main.setAlignment(Qt.AlignTop)
        #        self.lbl_main.setAlignment(Qt.AlignCenter)
        self.lbl_main.setPixmap(self.pixmap)

        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.lbl_main)

        self.central_widget = QWidget()

        self.layout = QVBoxLayout(self.central_widget)
        self.setCentralWidget(self.central_widget)
        self.layout.addLayout(self.vbox)

        self.refresh_timer = QTimer()
        self.refresh_timer.timeout.connect(self.refresh_show)

        self.setWindowTitle('Auto Cut')
        self.show()

    def read(self):
        window_name = 'Scanning control'

        self.scan_control_hwnd = win32gui.FindWindow(None, window_name)
        if self.scan_control_hwnd == 0:
            window_name = 'Scanning control ( Lift Mode )'
            self.scan_control_hwnd = win32gui.FindWindow(None, window_name)
#        win32gui.ShowWindow(scan_control_hwnd, win32con.SW_MAXIMIZE)

        win32gui.SendMessage(self.scan_control_hwnd, win32con.WM_SYSCOMMAND,
                             win32con.SC_RESTORE, 0)
        win32gui.SetForegroundWindow(self.scan_control_hwnd)
        time.sleep(0.5)
        hwnd = self.scan_control_hwnd
        hwndChildList = []
        win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd),
                                  hwndChildList)
        for hwnd_child in hwndChildList:
            name = win32gui.GetWindowText(hwnd_child)
            if 'Scan Area' in name:
                self.frame_hwnd = hwnd_child
                break
#        run_hwnd = hwndChildList[3]
#        self.frame_hwnd = hwndChildList[54]

#        self.frame_hwnd = self.scan_control_hwnd

        self.left, self.top, self.right, self.bottom = win32gui.GetWindowRect(
            self.frame_hwnd)
        print(self.left, self.top, self.right, self.bottom)
        self.screenshot = pyautogui.screenshot(region=[self.left,self.top,\
                                                       self.right-self.left,\
                                                       self.bottom-self.top])
        self.screenshot = np.asarray(self.screenshot)
        #self.screenshot = cv2.imread('F:/Desktop2020.1.17/AutoCut/screenshot2.bmp')
        #self.screenshot = cv2.cvtColor(self.screenshot, cv2.COLOR_BGR2RGB)
        self.crop_left, self.crop_top, self.crop_right, self.crop_bottom = find_region(
            self.screenshot)
        self.screenshot = self.screenshot[self.crop_top: self.crop_bottom, \
                                          self.crop_left: self.crop_right]
        #        self.img = cv2.cvtColor(np.asarray(self.img),cv2.COLOR_RGB2BGR)

        self.start_refresh()

        print('Read')

    def contact(self):
        print('contact')

    def mouse_pos_initial(self):
        self.mouse_x1, self.mouse_y1 = 0, 0
        self.mouse_x2, self.mouse_y2 = 0, 0

    def mousePressEvent(self, event):
        self.mouse_x1_raw = max(0, event.pos().x())
        self.mouse_y1_raw = max(0, event.pos().y())
        self.mouse_x2_raw, self.mouse_y2_raw = self.mouse_x1_raw, self.mouse_y1_raw
        self.mouse_pos_correct()
        if event.buttons() == Qt.LeftButton and self.draw_shape_line:

            self.draw_shape_action_list.append(Line(self.mouse_x1, self.mouse_y1, \
                                                    self.mouse_x2, self.mouse_y2, \
                                                    color = (0,255,0),\
                                                    num = self.draw_shape_count,\
                                                    show_distance = self.show_distance))
            self.draw_shape_count += 1
            self.drawing_shape_line = True
            self.undo_redo_setting()
        elif event.buttons() == Qt.LeftButton and self.erase:
            self.draw_shape_action_list.append(Eraser(self.mouse_x1, \
                                                      self.mouse_y1, num = [0]))
            self.drawing_eraser = True

            print(self.mouse_x1, self.mouse_y1)

    def mouseMoveEvent(self, event):
        self.mouse_x2_raw = max(0, event.pos().x())
        self.mouse_y2_raw = max(0, event.pos().y())
        self.mouse_pos_correct()
        if self.drawing_shape_line:

            self.draw_shape_action_list[-1].x2 = self.mouse_x2
            self.draw_shape_action_list[-1].y2 = self.mouse_y2
            self.draw_shape_action_list[-1].pos_refresh()
        if self.drawing_eraser:
            self.draw_shape_action_list[-1].x1 = self.mouse_x2
            self.draw_shape_action_list[-1].y1 = self.mouse_y2
            self.draw_shape_action_list[-1].pos_refresh()

    def mouseReleaseEvent(self, event):
        if self.mouse_x1_raw == self.mouse_x2_raw and self.mouse_y1_raw == self.mouse_y2_raw:
            if self.drawing_shape_line:
                self.draw_shape_action_list.pop()
        if event.button() == Qt.LeftButton and self.drawing_eraser:
            self.drawing_eraser = False
            if len(self.draw_shape_action_list[-1].num) == 1:
                self.draw_shape_action_list.pop()

    def mouse_pos_correct(self):
        lbl_main_x = self.lbl_main.pos().x()
        lbl_main_y = self.lbl_main.pos().y() + self.menubar.height(
        ) + self.toolbar.height()

        self.mouse_x1 = self.mouse_x1_raw - lbl_main_x
        self.mouse_x2 = self.mouse_x2_raw - lbl_main_x

        self.mouse_y1 = self.mouse_y1_raw - lbl_main_y
        self.mouse_y2 = self.mouse_y2_raw - lbl_main_y

    def refresh_show(self):
        self.img = self.screenshot.copy()
        if len(self.draw_shape_action_list) > 0:
            self.generate_draw_shape_list()
            self.draw_shape_canvas()
        if self.drawing_eraser:
            eraser_temp = self.draw_shape_action_list[-1]
            cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \
                       eraser_temp.color, eraser_temp.width)
            cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \
                       (0,0,0), 1)


#            self.find_eraser_num()
        self.show_on_screen()

    def generate_draw_shape_list(self):
        self.draw_shape_list = []
        for action in self.draw_shape_action_list:
            if action.prop != 'eraser' and action.prop != 'clear':
                self.draw_shape_list.append(action)
            elif action.prop == 'eraser':
                i = 0
                while i < len(self.draw_shape_list):
                    if self.draw_shape_list[i].num in action.num:
                        #print(action.num)
                        self.draw_shape_list.pop(i)
                        i -= 1
                    i += 1
                    if i == len(self.draw_shape_list):
                        break
            elif action.prop == 'clear':
                self.draw_shape_list = []

    def draw_shape_canvas(self):
        #目前canvas还没什么用,均可用img_show代替,但也可以先留着
        self.canvas = np.zeros(self.img.shape, dtype=np.uint8)
        self.canvas_blank = np.zeros((self.img.shape[0], self.img.shape[1]),
                                     dtype=int)
        count = 1
        if len(self.draw_shape_list) == 0:
            pass
        for shape in self.draw_shape_list:
            #            shape.x1, shape.y1 = self.mouse_pos_ratio_change_line(shape.x1, shape.y1)
            #            shape.x2, shape.y2 = self.mouse_pos_ratio_change_line(shape.x2, shape.y2)
            #            shape.pos_refresh()
            if shape.prop == 'line' or shape.prop == 'base line':
                x_temp, y_temp = Pos_of_Line(*list(shape.pos[0]),
                                             *list(shape.pos[1]))
                self.canvas_blank = record_draw_shape(self.canvas_blank, \
                                                      np.array(x_temp), np.array(y_temp), \
                                                      shape.num)
                cv2.circle(self.img, shape.pos[0], 5, shape.color, 1)
                cv2.line(self.img, *shape.pos, shape.color, shape.width)
                cv2.putText(self.img, str(count), shape.pos[1], self.font, 0.7, \
                            shape.color, 1, cv2.LINE_AA)
                count += 1
                if shape.show_distance:
                    distance = self.calculate_distance(shape.x1, shape.y1,
                                                       shape.x2, shape.y2)
                    pos = (round((shape.x1 + shape.x2) / 2),
                           round((shape.y1 + shape.y2) / 2))
                    cv2.putText(self.img, str(round(distance, 2)), pos, \
                                self.font, 0.7, (255,0,0), 1, cv2.LINE_AA)

    def start_refresh(self):
        self.refresh_timer.start(30)

    def show_on_screen(self):
        self.img_qi = QImage(self.img[:], self.img.shape[1], self.img.shape[0],\
                          self.img.shape[1] * 3, QImage.Format_RGB888)
        self.pixmap = QPixmap(self.img_qi)
        self.lbl_main.setPixmap(self.pixmap)

    def draw_line(self):
        if self.line_button.isChecked():
            self.draw_shape_initial()
            self.draw_shape_line = True
            self.line_button.setChecked(True)
        else:
            self.draw_shape_line = False
            self.drawing_shape_line = False
            self.line_button.setChecked(False)
        print('draw line')

    def erase_shape(self):
        if self.eraser_button.isChecked():
            self.draw_shape_initial()
            self.erase = True
            self.eraser_button.setChecked(True)
        else:
            self.erase = False
            self.eraser_button.setChecked(False)

    def undo_redo_setting(self):
        self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png'))
        self.draw_shape_action_list_for_redo = []
        self.redo_button.setIcon(
            QIcon(self.current_dir + 'redo_gray_opacity.png'))

    def undo_draw(self):
        if len(self.draw_shape_action_list) > 0:
            self.draw_shape_action_list_for_redo.append(
                self.draw_shape_action_list[-1])
            self.redo_button.setIcon(QIcon(self.current_dir + 'redo.png'))
            self.draw_shape_action_list.pop()
            if len(self.draw_shape_action_list) == 0:
                self.undo_button.setIcon(
                    QIcon(self.current_dir + 'undo_gray_opacity.png'))

    def redo_draw(self):
        if len(self.draw_shape_action_list_for_redo) > 0:
            self.draw_shape_action_list.append(
                self.draw_shape_action_list_for_redo[-1])
            self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png'))
            self.draw_shape_action_list_for_redo.pop()
            if len(self.draw_shape_action_list_for_redo) == 0:
                self.redo_button.setIcon(
                    QIcon(self.current_dir + 'redo_gray_opacity.png'))

    def clear_draw(self):
        self.draw_shape_initial()
        self.draw_shape_action_list.append(Clear_All())

    def draw_shape_initial(self):
        self.line_button.setChecked(False)
        self.draw_shape_line = False
        self.drawing_shape_line = False

        self.eraser_button.setChecked(False)
        self.erase = False
        self.drawing_eraser = False

    def run_cut(self):
        if len(self.draw_shape_list) > 0:
            win32gui.SetForegroundWindow(self.scan_control_hwnd)
            #self.left, self.top, self.right, self.bottom = win32gui.GetWindowRect(self.frame_hwnd)
            #screenshot_temp = pyautogui.screenshot(region=[self.left,self.top,\
            #                                           self.right-self.left,\
            #                                           self.bottom-self.top])
            #screenshot_temp  = np.asarray(screenshot_temp)
            #self.crop_left, self.crop_top, self.crop_right, self.crop_bottom = find_region(screenshot_temp)
            a = pyautogui.locateCenterOnScreen('G:/1.png')
            for shape in self.draw_shape_list:
                pyautogui.moveTo(self.left + self.crop_left,
                                 self.top + self.crop_top)
                pyautogui.moveRel(list(shape.pos[0])[0], list(shape.pos[0])[1])
                pyautogui.dragRel(list(shape.pos[1])[0] - list(shape.pos[0])[0], \
                                  list(shape.pos[1])[1] - list(shape.pos[0])[1], duration=0.25)
                try:
                    pyautogui.moveTo(a[0], a[1])
                except:
                    a = pyautogui.locateCenterOnScreen('G:/1.png')
                    time.sleep(0.5)
                    pyautogui.moveTo(a[0], a[1])
                pyautogui.click()
                time.sleep(1)
                pyautogui.moveRel(300, 300)
                self.wait_cut()
                #time.sleep(15)

    def wait_cut(self):
        for i in range(30):
            a = pyautogui.locateCenterOnScreen('G:/1.png')
            if a == None:
                time.sleep(1)
            else:
                break

    def repeat_cut(self):
        print('repeat cut')
Esempio n. 15
0
class MainWindow(QMainWindow):
    def __init__(self, gui):  # noqa: max-complexity
        super().__init__()
        self.gui = gui
        self.gateways = []
        self.welcome_dialog = None
        self.recovery_key_exporter = None

        self.setWindowTitle(APP_NAME)
        self.setMinimumSize(QSize(600, 400))
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.setContextMenuPolicy(Qt.NoContextMenu)

        if sys.platform == "darwin":
            # To disable the broken/buggy "full screen" mode on macOS.
            # See https://github.com/gridsync/gridsync/issues/241
            self.setWindowFlags(Qt.Dialog)

        grid_invites_enabled = True
        invites_enabled = True
        multiple_grids_enabled = True
        features_settings = settings.get("features")
        if features_settings:
            grid_invites = features_settings.get("grid_invites")
            if grid_invites and grid_invites.lower() == "false":
                grid_invites_enabled = False
            invites = features_settings.get("invites")
            if invites and invites.lower() == "false":
                invites_enabled = False
            multiple_grids = features_settings.get("multiple_grids")
            if multiple_grids and multiple_grids.lower() == "false":
                multiple_grids_enabled = False

        if multiple_grids_enabled:
            self.shortcut_new = QShortcut(QKeySequence.New, self)
            self.shortcut_new.activated.connect(self.show_welcome_dialog)

        self.shortcut_open = QShortcut(QKeySequence.Open, self)
        self.shortcut_open.activated.connect(self.select_folder)

        self.shortcut_preferences = QShortcut(QKeySequence.Preferences, self)
        self.shortcut_preferences.activated.connect(
            self.gui.show_preferences_window)

        self.shortcut_close = QShortcut(QKeySequence.Close, self)
        self.shortcut_close.activated.connect(self.close)

        self.shortcut_quit = QShortcut(QKeySequence.Quit, self)
        self.shortcut_quit.activated.connect(self.confirm_quit)

        self.central_widget = CentralWidget(self.gui)
        self.setCentralWidget(self.central_widget)

        font = Font(8)

        folder_icon_default = QFileIconProvider().icon(QFileInfo(config_dir))
        folder_icon_composite = CompositePixmap(
            folder_icon_default.pixmap(256, 256), resource("green-plus.png"))
        folder_icon = QIcon(folder_icon_composite)

        folder_action = QAction(folder_icon, "Add Folder", self)
        folder_action.setToolTip("Add a Folder...")
        folder_action.setFont(font)
        folder_action.triggered.connect(self.select_folder)

        if grid_invites_enabled:
            invites_action = QAction(QIcon(resource("invite.png")), "Invites",
                                     self)
            invites_action.setToolTip("Enter or Create an Invite Code")
            invites_action.setFont(font)

            enter_invite_action = QAction(QIcon(), "Enter Invite Code...",
                                          self)
            enter_invite_action.setToolTip("Enter an Invite Code...")
            enter_invite_action.triggered.connect(self.open_invite_receiver)

            create_invite_action = QAction(QIcon(), "Create Invite Code...",
                                           self)
            create_invite_action.setToolTip("Create on Invite Code...")
            create_invite_action.triggered.connect(
                self.open_invite_sender_dialog)

            invites_menu = QMenu(self)
            invites_menu.addAction(enter_invite_action)
            invites_menu.addAction(create_invite_action)

            invites_button = QToolButton(self)
            invites_button.setDefaultAction(invites_action)
            invites_button.setMenu(invites_menu)
            invites_button.setPopupMode(2)
            invites_button.setStyleSheet(
                "QToolButton::menu-indicator { image: none }")
            invites_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        elif invites_enabled:
            invite_action = QAction(QIcon(resource("invite.png")),
                                    "Enter Code", self)
            invite_action.setToolTip("Enter an Invite Code...")
            invite_action.setFont(font)
            invite_action.triggered.connect(self.open_invite_receiver)

        spacer_left = QWidget()
        spacer_left.setSizePolicy(QSizePolicy.Expanding, 0)

        self.combo_box = ComboBox()
        self.combo_box.currentIndexChanged.connect(self.on_grid_selected)
        if not multiple_grids_enabled:
            self.combo_box.hide()

        spacer_right = QWidget()
        spacer_right.setSizePolicy(QSizePolicy.Expanding, 0)

        history_action = QAction(QIcon(resource("time.png")), "History", self)
        history_action.setToolTip("Show/Hide History")
        history_action.setFont(font)
        history_action.triggered.connect(self.on_history_button_clicked)

        self.history_button = QToolButton(self)
        self.history_button.setDefaultAction(history_action)
        self.history_button.setCheckable(True)
        self.history_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        recovery_action = QAction(QIcon(resource("key.png")), "Recovery", self)
        recovery_action.setToolTip("Import or Export a Recovery Key")
        recovery_action.setFont(font)

        import_action = QAction(QIcon(), "Import Recovery Key...", self)
        import_action.setToolTip("Import Recovery Key...")
        import_action.triggered.connect(self.import_recovery_key)

        export_action = QAction(QIcon(), "Export Recovery Key...", self)
        export_action.setToolTip("Export Recovery Key...")
        export_action.setShortcut(QKeySequence.Save)
        export_action.triggered.connect(self.export_recovery_key)

        recovery_menu = QMenu(self)
        recovery_menu.addAction(import_action)
        recovery_menu.addAction(export_action)

        recovery_button = QToolButton(self)
        recovery_button.setDefaultAction(recovery_action)
        recovery_button.setMenu(recovery_menu)
        recovery_button.setPopupMode(2)
        recovery_button.setStyleSheet(
            "QToolButton::menu-indicator { image: none }")
        recovery_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        self.toolbar = self.addToolBar("")
        p = self.palette()
        dimmer_grey = BlendedColor(p.windowText().color(),
                                   p.window().color(), 0.7).name()
        if sys.platform != "darwin":
            self.toolbar.setStyleSheet("""
                QToolBar {{ border: 0px }}
                QToolButton {{ color: {} }}
            """.format(dimmer_grey))
        else:
            self.toolbar.setStyleSheet(
                "QToolButton {{ color: {} }}".format(dimmer_grey))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.toolbar.setIconSize(QSize(24, 24))
        self.toolbar.setMovable(False)
        self.toolbar.addAction(folder_action)
        if grid_invites_enabled:
            self.toolbar.addWidget(invites_button)
        elif invites_enabled:
            self.toolbar.addAction(invite_action)
        self.toolbar.addWidget(spacer_left)
        self.toolbar.addWidget(self.combo_box)
        self.toolbar.addWidget(spacer_right)
        self.toolbar.addWidget(self.history_button)
        self.toolbar.addWidget(recovery_button)

        if sys.platform != "win32":  # Text is getting clipped on Windows 10
            for action in self.toolbar.actions():
                widget = self.toolbar.widgetForAction(action)
                if isinstance(widget, QToolButton):
                    widget.setMaximumWidth(68)

        self.active_invite_sender_dialogs = []
        self.active_invite_receiver_dialogs = []

        self.pending_news_message = ()

    def populate(self, gateways):
        for gateway in gateways:
            if gateway not in self.gateways:
                self.central_widget.add_folders_view(gateway)
                self.central_widget.add_history_view(gateway)
                self.combo_box.add_gateway(gateway)
                self.gateways.append(gateway)
                gateway.newscap_checker.message_received.connect(
                    self.on_message_received)
                gateway.newscap_checker.upgrade_required.connect(
                    self.on_upgrade_required)

    def show_news_message(self, gateway, title, message):
        msgbox = QMessageBox(self)
        msgbox.setWindowModality(Qt.WindowModal)
        icon_filepath = os.path.join(gateway.nodedir, "icon")
        if os.path.exists(icon_filepath):
            msgbox.setIconPixmap(QIcon(icon_filepath).pixmap(64, 64))
        elif os.path.exists(resource("tahoe-lafs.png")):
            msgbox.setIconPixmap(
                QIcon(resource("tahoe-lafs.png")).pixmap(64, 64))
        else:
            msgbox.setIcon(QMessageBox.Information)
        if sys.platform == "darwin":
            msgbox.setText(title)
            msgbox.setInformativeText(message)
        else:
            msgbox.setWindowTitle(title)
            msgbox.setText(message)
        msgbox.show()
        try:
            self.gui.unread_messages.remove((gateway, title, message))
        except ValueError:
            return
        self.gui.systray.update()

    def _maybe_show_news_message(self, gateway, title, message):
        self.gui.unread_messages.append((gateway, title, message))
        self.gui.systray.update()
        if self.isVisible():
            self.show_news_message(gateway, title, message)
        else:
            self.pending_news_message = (gateway, title, message)

    def on_message_received(self, gateway, message):
        title = "New message from {}".format(gateway.name)
        self.gui.show_message(title,
                              strip_html_tags(message.replace("<p>", "\n\n")))
        self._maybe_show_news_message(gateway, title, message)

    def on_upgrade_required(self, gateway):
        title = "Upgrade required"
        message = (
            "A message was received from {} in an unsupported format. This "
            "suggests that you are running an out-of-date version of {}.\n\n"
            "To avoid seeing this warning, please upgrade to the latest "
            "version.".format(gateway.name, APP_NAME))
        self._maybe_show_news_message(gateway, title, message)

    def current_view(self):
        try:
            w = self.central_widget.folders_views[self.combo_box.currentData()]
        except KeyError:
            return None
        return w.layout().itemAt(0).widget()

    def select_folder(self):
        self.show_folders_view()
        view = self.current_view()
        if view:
            view.select_folder()

    def set_current_grid_status(self):
        current_view = self.current_view()
        if not current_view:
            return
        self.gui.systray.update()

    def show_folders_view(self):
        try:
            self.central_widget.setCurrentWidget(
                self.central_widget.folders_views[
                    self.combo_box.currentData()])
        except KeyError:
            pass
        self.set_current_grid_status()

    def show_history_view(self):
        try:
            self.central_widget.setCurrentWidget(
                self.central_widget.history_views[
                    self.combo_box.currentData()])
        except KeyError:
            pass
        self.set_current_grid_status()

    def show_welcome_dialog(self):
        if self.welcome_dialog:
            self.welcome_dialog.close()
        self.welcome_dialog = WelcomeDialog(self.gui, self.gateways)
        self.welcome_dialog.show()
        self.welcome_dialog.raise_()

    def on_grid_selected(self, index):
        if index == self.combo_box.count() - 1:
            self.show_welcome_dialog()
        if not self.combo_box.currentData():
            return
        if self.history_button.isChecked():
            self.show_history_view()
        else:
            self.show_folders_view()
        self.setWindowTitle("{} - {}".format(
            APP_NAME,
            self.combo_box.currentData().name))

    def confirm_export(self, path):
        if os.path.isfile(path):
            logging.info("Recovery Key successfully exported")
            info(
                self,
                "Export successful",
                "Recovery Key successfully exported to {}".format(path),
            )
        else:
            logging.error("Error exporting Recovery Key; file not found.")
            error(
                self,
                "Error exporting Recovery Key",
                "Destination file not found after export: {}".format(path),
            )

    def export_recovery_key(self, gateway=None):
        self.show_folders_view()
        if not gateway:
            gateway = self.combo_box.currentData()
        self.recovery_key_exporter = RecoveryKeyExporter(self)
        self.recovery_key_exporter.done.connect(self.confirm_export)
        self.recovery_key_exporter.do_export(gateway)

    def import_recovery_key(self):
        # XXX Quick hack for user-testing; change later
        self.welcome_dialog = WelcomeDialog(self.gui, self.gateways)
        self.welcome_dialog.on_restore_link_activated()

    def on_history_button_clicked(self):
        if not self.history_button.isChecked():
            self.history_button.setChecked(True)
            self.show_history_view()
        else:
            self.history_button.setChecked(False)
            self.show_folders_view()

    def on_invite_received(self, gateway):
        self.populate([gateway])
        for view in self.central_widget.views:
            view.model().monitor.scan_rootcap("star.png")

    def on_invite_closed(self, obj):
        try:
            self.active_invite_receiver_dialogs.remove(obj)
        except ValueError:
            pass

    def open_invite_receiver(self):
        invite_receiver_dialog = InviteReceiverDialog(self.gateways)
        invite_receiver_dialog.done.connect(self.on_invite_received)
        invite_receiver_dialog.closed.connect(self.on_invite_closed)
        invite_receiver_dialog.show()
        self.active_invite_receiver_dialogs.append(invite_receiver_dialog)

    def open_invite_sender_dialog(self):
        gateway = self.combo_box.currentData()
        if gateway:
            view = self.current_view()
            if view:
                invite_sender_dialog = InviteSenderDialog(
                    gateway, self.gui, view.get_selected_folders())
            else:
                invite_sender_dialog = InviteSenderDialog(gateway, self.gui)
            invite_sender_dialog.closed.connect(
                self.active_invite_sender_dialogs.remove)
            invite_sender_dialog.show()
            self.active_invite_sender_dialogs.append(invite_sender_dialog)

    def confirm_quit(self):
        folder_loading = False
        folder_syncing = False
        for model in [view.model() for view in self.central_widget.views]:
            for row in range(model.rowCount()):
                status = model.item(row, 1).data(Qt.UserRole)
                mtime = model.item(row, 2).data(Qt.UserRole)
                if not status and not mtime:  # "Loading..." and not yet synced
                    folder_loading = True
                    break
                if status == 1:  # "Syncing"
                    folder_syncing = True
                    break
        msg = QMessageBox(self)
        if folder_loading:
            msg.setIcon(QMessageBox.Warning)
            informative_text = (
                "One or more folders have not finished loading. If these "
                "folders were recently added, you may need to add them again.")
        elif folder_syncing:
            msg.setIcon(QMessageBox.Warning)
            informative_text = (
                "One or more folders are currently syncing. If you quit, any "
                "pending upload or download operations will be cancelled "
                "until you launch {} again.".format(APP_NAME))
        else:
            msg.setIcon(QMessageBox.Question)
            informative_text = (
                "If you quit, {} will stop synchronizing your folders until "
                "you launch it again.".format(APP_NAME))
        if sys.platform == "darwin":
            msg.setText("Are you sure you wish to quit?")
            msg.setInformativeText(informative_text)
        else:
            msg.setWindowTitle("Exit {}?".format(APP_NAME))
            msg.setText(
                "Are you sure you wish to quit? {}".format(informative_text))
        msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg.setDefaultButton(QMessageBox.No)
        if msg.exec_() == QMessageBox.Yes:
            if sys.platform == "win32":
                self.gui.systray.hide()
            reactor.stop()

    def keyPressEvent(self, event):
        key = event.key()
        if key in (Qt.Key_Backspace, Qt.Key_Delete):
            view = self.current_view()
            selected = view.selectedIndexes() if view else None
            if selected:
                view.confirm_stop_syncing(view.get_selected_folders())
        if key == Qt.Key_Escape:
            view = self.current_view()
            selected = view.selectedIndexes() if view else None
            if selected:
                for index in selected:
                    view.selectionModel().select(index,
                                                 QItemSelectionModel.Deselect)
            elif self.gui.systray.isSystemTrayAvailable():
                self.hide()

    def closeEvent(self, event):
        if self.gui.systray.isSystemTrayAvailable():
            event.accept()
        else:
            event.ignore()
            self.confirm_quit()

    def showEvent(self, _):
        if self.pending_news_message:
            gateway, title, message = self.pending_news_message
            self.pending_news_message = ()
            QTimer.singleShot(
                0, lambda: self.show_news_message(gateway, title, message))
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):

        self.current_dir = os.path.abspath(__file__).replace('\\', '/')
        self.current_dir = get_folder_from_file(self.current_dir)
        self.current_dir += 'support_files/'

        #self.afp_dir, self.afp, self.bfp_dir, self.bfp = load_known()
        print(self.current_dir)
        self.get_hwnd()
        self.scan_speed = 1
        self.total_range = 20

        self.font = cv2.FONT_HERSHEY_SIMPLEX

        self.mouse_pos_initial()

        self.canvas_blank = np.zeros((512, 512), dtype=np.int8)

        exitAct = QAction(QIcon(self.current_dir + 'quit.png'), '&Quit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.triggered.connect(qApp.quit)

        help_contact = QAction(QIcon(self.current_dir + 'email.png'),
                               'Contact', self)
        help_contact.triggered.connect(self.contact)

        help_about = QAction('About', self)
        help_about.triggered.connect(self.about)

        self.menubar = self.menuBar()

        FileMenu = self.menubar.addMenu('&File')
        FileMenu.addAction(exitAct)

        HelpMenu = self.menubar.addMenu('&Help')
        HelpMenu.addAction(help_contact)
        HelpMenu.addAction(help_about)

        self.read_button = QToolButton()
        self.read_button.setIcon(QIcon(self.current_dir + 'read.png'))
        self.read_button.setToolTip('Read Ctrl+R')
        self.read_button.clicked.connect(self.read)
        self.read_button.setShortcut('Ctrl+R')

        self.select_button = QToolButton()
        self.select_button.setIcon(QIcon(self.current_dir + 'select.png'))
        self.select_button.setToolTip('Select')
        self.select_button.clicked.connect(self.select_move_shape)
        self.select_button.setCheckable(True)
        self.select = False
        self.selecting = False
        self.select_rec = Rectangle()
        self.cursor_on_select = False
        self.moving = False
        self.move_start = [0, 0]
        self.move_end = [0, 0]

        self.drag_button = QToolButton()
        self.drag_button.setIcon(QIcon(self.current_dir + 'drag.png'))
        self.drag_button.setToolTip('Move')
        self.drag_button.clicked.connect(self.drag_shape)

        self.draw_shape_action_list = []
        self.draw_shape_list = []
        self.draw_shape_action_list_for_redo = []
        self.draw_shape_count = 1

        self.line_button = QToolButton()
        self.line_button.setIcon(QIcon(self.current_dir + 'line.png'))
        self.line_button.setToolTip('Draw line')
        self.line_button.clicked.connect(self.draw_line)
        self.line_button.setCheckable(True)
        self.draw_shape_line = False
        self.drawing_shape_line = False
        self.show_distance = False

        self.grating_button = QToolButton()
        self.grating_button.setIcon(QIcon(self.current_dir + 'grating.png'))
        self.grating_button.setToolTip('Grating')
        self.grating_button.clicked.connect(self.draw_grating)

        #        line = Line(0,0,100,100)

        self.eraser_button = QToolButton()
        self.eraser_button.setIcon(QIcon(self.current_dir + 'eraser.png'))
        self.eraser_button.setToolTip('eraser')
        self.eraser_button.clicked.connect(self.erase_shape)
        self.eraser_button.setCheckable(True)
        self.erase = False
        self.drawing_eraser = False

        self.undo_button = QToolButton()
        self.undo_button.setIcon(
            QIcon(self.current_dir + 'undo_gray_opacity.png'))
        self.undo_button.setToolTip('undo  Ctrl+Z')
        self.undo_button.clicked.connect(self.undo_draw)
        self.undo_button.setShortcut('Ctrl+Z')

        self.redo_button = QToolButton()
        self.redo_button.setIcon(
            QIcon(self.current_dir + 'redo_gray_opacity.png'))
        self.redo_button.setToolTip('redo  Ctrl+Y')
        self.redo_button.clicked.connect(self.redo_draw)
        self.redo_button.setShortcut('Ctrl+Y')

        self.clear_button = QToolButton()
        self.clear_button.setIcon(QIcon(self.current_dir + 'clear.png'))
        self.clear_button.setToolTip('clear drawing')
        self.clear_button.clicked.connect(self.clear_draw)

        self.run_button = QToolButton()
        self.run_button.setIcon(QIcon(self.current_dir + 'run.png'))
        self.run_button.setToolTip('Run F5')
        self.run_button.clicked.connect(self.run_cut)
        self.run_button.setShortcut('F5')

        self.repeat_button = QToolButton()
        self.repeat_button.setIcon(QIcon(self.current_dir + 'repeat.png'))
        self.repeat_button.setToolTip('Repeat')
        self.repeat_button.clicked.connect(self.repeat_cut)

        self.stop_button = QToolButton()
        self.stop_button.setIcon(QIcon(self.current_dir + 'stop.png'))
        self.stop_button.setToolTip('Stop')
        self.stop_button.clicked.connect(self.stop_cut)

        self.toolbar1 = self.addToolBar('Read')
        self.toolbar1.addWidget(self.read_button)

        self.toolbar2 = self.addToolBar('Select')
        self.toolbar2.addWidget(self.select_button)
        self.toolbar2.addWidget(self.drag_button)

        self.toolbar3 = self.addToolBar('Draw')
        self.toolbar3.addWidget(self.line_button)
        self.toolbar3.addWidget(self.grating_button)
        self.toolbar3.addWidget(self.undo_button)
        self.toolbar3.addWidget(self.redo_button)
        self.toolbar3.addWidget(self.eraser_button)
        self.toolbar3.addWidget(self.clear_button)

        self.toolbar4 = self.addToolBar('Run')
        self.toolbar4.addWidget(self.run_button)
        self.toolbar4.addWidget(self.repeat_button)
        self.toolbar4.addWidget(self.stop_button)

        self.toolbar = self.addToolBar(' ')

        self.pixmap = QPixmap()
        self.lbl_main = QLabel(self)
        self.lbl_main.setAlignment(Qt.AlignTop)
        #        self.lbl_main.setAlignment(Qt.AlignCenter)
        self.lbl_main.setPixmap(self.pixmap)
        self.lbl_main.setMouseTracking(True)

        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.lbl_main)

        self.central_widget = QWidget()
        self.central_widget.setMouseTracking(True)

        self.layout = QVBoxLayout(self.central_widget)
        self.setCentralWidget(self.central_widget)
        self.layout.addLayout(self.vbox)

        self.refresh_timer = QTimer()
        self.refresh_timer.timeout.connect(self.refresh_show)

        self.setMouseTracking(True)
        self.setWindowTitle('Auto Cut')
        self.show()

    def read(self):
        window_name = 'Scanning control'

        self.scan_control_hwnd = win32gui.FindWindow(None, window_name)
        if self.scan_control_hwnd == 0:
            window_name = 'Scanning control ( Lift Mode )'
            self.scan_control_hwnd = win32gui.FindWindow(None, window_name)
#        win32gui.ShowWindow(scan_control_hwnd, win32con.SW_MAXIMIZE)
        try:
            win32gui.SendMessage(self.scan_control_hwnd,
                                 win32con.WM_SYSCOMMAND, win32con.SC_RESTORE,
                                 0)
            win32gui.SetForegroundWindow(self.scan_control_hwnd)
        except:
            print('Can not set foreground window ')
        time.sleep(0.5)
        hwnd = self.scan_control_hwnd
        hwndChildList = []
        win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd),
                                  hwndChildList)
        self.frame_hwnd = 0
        probe_position_hwnd = 0
        for hwnd_child in hwndChildList:
            name = win32gui.GetWindowText(hwnd_child)
            if 'Scan Area' in name:
                self.frame_hwnd = hwnd_child
                self.total_range = float(name[11:-3])
                print(self.total_range)
            elif name == 'probe_position':
                probe_position_hwnd = hwnd_child

        hwnd = probe_position_hwnd
        hwndChildList = []
        win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd),
                                  hwndChildList)
        self.move_time_hwnd = hwndChildList[0]
        self.new_x_hwnd = hwndChildList[3]
        self.new_y_hwnd = hwndChildList[2]

        self.move_time_Edit = EditWrapper(self.move_time_hwnd)
        self.x_Edit = EditWrapper(self.new_x_hwnd)
        self.y_Edit = EditWrapper(self.new_y_hwnd)

        #        run_hwnd = hwndChildList[3]
        #        self.frame_hwnd = hwndChildList[54]

        #        self.frame_hwnd = self.scan_control_hwnd
        '''
        self.left, self.top, self.right, self.bottom = win32gui.GetWindowRect(self.frame_hwnd)
        print(self.left, self.top, self.right, self.bottom)
        self.screenshot = pyautogui.screenshot(region=[self.left,self.top,\
                                                       self.right-self.left,\
                                                       self.bottom-self.top])
        self.screenshot = np.asarray(self.screenshot)
        '''
        self.screenshot = cv2.imread(
            'F:/Desktop2020.1.17/AutoCut/screenshot2.bmp')
        self.screenshot = cv2.cvtColor(self.screenshot, cv2.COLOR_BGR2RGB)
        self.crop_left, self.crop_top, self.crop_right, self.crop_bottom = find_region(
            self.screenshot)
        self.screenshot = self.screenshot[self.crop_top: self.crop_bottom, \
                                          self.crop_left: self.crop_right]

        #        self.img = cv2.cvtColor(np.asarray(self.img),cv2.COLOR_RGB2BGR)
        #self.read_z_pos()

        self.start_refresh()

        print('Read')

    def contact(self):
        QMessageBox.information(self, 'contact','Please contact [email protected] '+\
                                'for support. Thanks!')

    def about(self):
        QMessageBox.information(self, 'About', 'AFM Auto Cut v1.0. '+ \
                                'Proudly designed and created by Jingxu Xie(谢京旭).\n \n'
                                'Copyright © 2020 Jingxu Xie. All Rights Reserved.')

    def draw_shape_initial(self):
        self.line_button.setChecked(False)
        self.draw_shape_line = False
        self.drawing_shape_line = False

        self.select_button.setChecked(False)
        self.select = False
        self.selecting = False
        self.select_rec = Rectangle()
        self.cursor_on_select = False
        self.moving = False

        self.eraser_button.setChecked(False)
        self.erase = False
        self.drawing_eraser = False

    def draw_line(self):
        if self.line_button.isChecked():
            self.draw_shape_initial()
            self.draw_shape_line = True
            self.line_button.setChecked(True)
        else:
            self.draw_shape_line = False
            self.drawing_shape_line = False
            self.line_button.setChecked(False)
        print('draw line')

    def select_move_shape(self):
        if self.select_button.isChecked():
            self.draw_shape_initial()
            self.select = True
            self.select_button.setChecked(True)
        else:
            self.draw_shape_line = False
            self.select = False
            self.select_button.setChecked(False)
        print('select')

    def drag_shape(self):
        print('drag')

    def draw_grating(self):
        self.grating_property_widget = GratingProperty()
        self.grating_property_widget.confirmed.connect(self.creat_grating)
        self.grating_property_widget.show()
        print('grating')

    def creat_grating(self, s):
        if s == 'confirmed':
            total_width = float(self.grating_property_widget.total_width)
            total_height = float(self.grating_property_widget.total_height)
            lines = int(self.grating_property_widget.lines)

            standard_distance = self.img.shape[0] / self.total_range

            x1 = int((self.total_range - total_width) / 2 * standard_distance)
            y1 = int((self.total_range - total_height) / 2 * standard_distance)
            x2 = x1 + int(total_width / self.total_range * self.img.shape[0])
            y2 = y1 + int(total_height / self.total_range * self.img.shape[1])

            grating_temp = Grating(x1, y1, x2, y2, total_width = total_width, \
                                   total_height = total_height, \
                                   standard_distance = standard_distance,\
                                   lines = lines, color = (0,255,0),\
                                   num = self.draw_shape_count)
            self.draw_shape_count += 1
            self.draw_shape_action_list.append(grating_temp)
            print('confirmed')
            self.grating_property_widget.close()

    def erase_shape(self):
        if self.eraser_button.isChecked():
            self.draw_shape_initial()
            self.erase = True
            self.eraser_button.setChecked(True)
        else:
            self.erase = False
            self.eraser_button.setChecked(False)

    def undo_redo_setting(self):
        self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png'))
        self.draw_shape_action_list_for_redo = []
        self.redo_button.setIcon(
            QIcon(self.current_dir + 'redo_gray_opacity.png'))

    def undo_draw(self):
        if len(self.draw_shape_action_list) > 0:
            self.draw_shape_action_list_for_redo.append(
                self.draw_shape_action_list[-1])
            self.redo_button.setIcon(QIcon(self.current_dir + 'redo.png'))
            self.draw_shape_action_list.pop()
            if len(self.draw_shape_action_list) == 0:
                self.undo_button.setIcon(
                    QIcon(self.current_dir + 'undo_gray_opacity.png'))

    def redo_draw(self):
        if len(self.draw_shape_action_list_for_redo) > 0:
            self.draw_shape_action_list.append(
                self.draw_shape_action_list_for_redo[-1])
            self.undo_button.setIcon(QIcon(self.current_dir + 'undo.png'))
            self.draw_shape_action_list_for_redo.pop()
            if len(self.draw_shape_action_list_for_redo) == 0:
                self.redo_button.setIcon(
                    QIcon(self.current_dir + 'redo_gray_opacity.png'))

    def clear_draw(self):
        self.draw_shape_initial()
        self.draw_shape_action_list.append(Clear_All())

    def mouse_pos_initial(self):
        self.mouse_x1, self.mouse_y1 = 0, 0
        self.mouse_x2, self.mouse_y2 = 0, 0
        self.mouse_x1_raw, self.mouse_y1_raw = 0, 0
        self.mouse_x2_raw, self.mouse_y2_raw = 0, 0
        self.mouse_pos_right = True

    def mousePressEvent(self, event):
        self.mouse_x1_raw = max(0, event.pos().x())
        self.mouse_y1_raw = max(0, event.pos().y())
        self.mouse_x2_raw, self.mouse_y2_raw = self.mouse_x1_raw, self.mouse_y1_raw
        self.mouse_pos_correct()
        if event.buttons() == Qt.LeftButton and self.draw_shape_line:
            if self.check_mouse_valid():
                self.draw_shape_action_list.append(Line(self.mouse_x1, self.mouse_y1, \
                                                        self.mouse_x2, self.mouse_y2, \
                                                        color = (0,255,0),\
                                                        num = self.draw_shape_count,\
                                                        show_distance = self.show_distance))
                self.draw_shape_count += 1
                self.drawing_shape_line = True
                self.undo_redo_setting()
        elif event.buttons() == Qt.LeftButton and self.erase:
            if self.check_mouse_valid():
                self.draw_shape_action_list.append(Eraser(self.mouse_x1, \
                                                          self.mouse_y1, num = [0]))
                self.drawing_eraser = True
        elif event.buttons(
        ) == Qt.LeftButton and self.select and not self.cursor_on_select:
            if self.check_mouse_valid():
                self.select_rec = Rectangle(self.mouse_x1, self.mouse_y1,\
                                            self.mouse_x2, self.mouse_y2,\
                                            num = -1, color = (0,0,0), width = 2)
                self.selecting = True
        elif event.buttons() == Qt.LeftButton and self.cursor_on_select:
            self.move_start = [self.mouse_x1, self.mouse_y1]
            self.moving = True

            print(self.mouse_x1, self.mouse_y1)
        #print(self.get_pos_on_screen(769, 769))

    def mouseMoveEvent(self, event):
        self.mouse_x2_raw = max(0, event.pos().x())
        self.mouse_y2_raw = max(0, event.pos().y())
        self.mouse_pos_correct()
        if self.drawing_shape_line and len(self.draw_shape_action_list) > 0:
            if self.check_mouse_valid():
                self.draw_shape_action_list[-1].x2 = self.mouse_x2
                self.draw_shape_action_list[-1].y2 = self.mouse_y2
                self.draw_shape_action_list[-1].pos_refresh()
        elif self.drawing_eraser and len(self.draw_shape_action_list) > 0:
            if self.check_mouse_valid():
                self.draw_shape_action_list[-1].x1 = self.mouse_x2
                self.draw_shape_action_list[-1].y1 = self.mouse_y2
                self.draw_shape_action_list[-1].pos_refresh()
        elif self.selecting:
            if self.check_mouse_valid():
                self.select_rec.x2 = self.mouse_x2
                self.select_rec.y2 = self.mouse_y2
                self.select_rec.pos_refresh()
        elif self.select and not self.moving:
            x_temp, y_temp = Pos_in_Circle(self.mouse_x2, self.mouse_y2, 20)
            self.cursor_on_select = False
            for i in range(len(x_temp)):
                if x_temp[i] < self.canvas_blank.shape[1] and y_temp[
                        i] < self.canvas_blank.shape[0]:
                    num = self.canvas_blank[y_temp[i], x_temp[i]]
                    if num == -1:
                        self.setCursor(Qt.SizeAllCursor)
                        self.cursor_on_select = True
                        break
            if not self.cursor_on_select:
                self.setCursor(Qt.ArrowCursor)
        if self.moving:
            self.move_end = [self.mouse_x2, self.mouse_y2]
            move_x = self.move_end[0] - self.move_start[0]
            move_y = self.move_end[1] - self.move_start[1]
            self.select_rec.x1 += move_x
            self.select_rec.x2 += move_x
            self.select_rec.y1 += move_y
            self.select_rec.y2 += move_y
            self.select_rec.pos_refresh()
            self.move_start = [self.mouse_x2, self.mouse_y2]

    def mouseReleaseEvent(self, event):
        #        if self.mouse_x1_raw == self.mouse_x2_raw and self.mouse_y1_raw == self.mouse_y2_raw:
        #            if self.drawing_shape_line:
        #                self.draw_shape_action_list.pop()
        if event.button() == Qt.RightButton and self.drawing_shape_line:
            self.drawing_shape_line = False
            if len(self.draw_shape_action_list) > 0:
                self.draw_shape_action_list.pop()
        if event.button() == Qt.LeftButton and self.drawing_eraser:
            self.drawing_eraser = False
            if len(self.draw_shape_action_list[-1].num) == 1:
                self.draw_shape_action_list.pop()
        if event.button() == Qt.LeftButton and self.selecting:
            self.selecting = False
        elif event.button() == Qt.LeftButton and self.moving:
            self.moving = False

    def mouse_pos_correct(self):
        lbl_main_x = self.lbl_main.pos().x()
        lbl_main_y = self.lbl_main.pos().y() + self.menubar.height(
        ) + self.toolbar.height()

        self.mouse_x1 = self.mouse_x1_raw - lbl_main_x
        self.mouse_x2 = self.mouse_x2_raw - lbl_main_x

        self.mouse_y1 = self.mouse_y1_raw - lbl_main_y
        self.mouse_y2 = self.mouse_y2_raw - lbl_main_y

    def check_mouse_valid(self):
        if 1 <= self.mouse_x2 < self.img.shape[1] - 1 and \
           1 <= self.mouse_x2 < self.img.shape[1] - 1 and \
           1 <= self.mouse_y2 < self.img.shape[0] - 1 and \
           1 <= self.mouse_y2 < self.img.shape[0] - 1:
            return True
        else:
            return False

    def refresh_show(self):
        self.img = self.screenshot.copy()
        #self.canvas_blank = np.zeros((self.img.shape[0], self.img.shape[1]), dtype = int)
        if self.drawing_eraser:
            eraser_temp = self.draw_shape_action_list[-1]
            cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \
                       eraser_temp.color, eraser_temp.width)
            cv2.circle(self.img, *eraser_temp.pos, eraser_temp.size, \
                       (0,0,0), 1)
            self.find_eraser_num()
        if len(self.draw_shape_action_list) > 0:
            self.generate_draw_shape_list()
            self.draw_shape_canvas()
        if self.select:
            cv2.rectangle(self.img, *self.select_rec.pos,\
                          self.select_rec.color, self.select_rec.width)
            x_temp, y_temp = Pos_of_Rec(*list(self.select_rec.pos[0]), \
                                        *list(self.select_rec.pos[1]))
            self.canvas_blank = record_draw_shape(self.canvas_blank, \
                                                  np.array(x_temp), np.array(y_temp), \
                                                  self.select_rec.num)
            if not self.selecting:
                pass
#                x_temp, y_temp = Pos_in_Circle(self.mouse_x2, self.mouse_y2, 10)
#                on_rec = False
#                for i in range(len(x_temp)):
#                    if x_temp[i] < self.canvas_blank.shape[1] and y_temp[i] < self.canvas_blank.shape[0]:
#                        num = self.canvas_blank[y_temp[i], x_temp[i]]
#                        if num == -1:
#                            self.setCursor(Qt.SizeAllCursor)
#                            on_rec = True
#                            break
#                if not on_rec:
#                    self.setCursor(Qt.ArrowCursor)
        self.show_on_screen()

    def generate_draw_shape_list(self):
        self.draw_shape_list = []
        for action in self.draw_shape_action_list:
            if action.prop != 'eraser' and action.prop != 'clear':
                self.draw_shape_list.append(action)
            elif action.prop == 'eraser':
                i = 0
                while i < len(self.draw_shape_list):
                    if self.draw_shape_list[i].num in action.num:
                        #print(action.num)
                        self.draw_shape_list.pop(i)
                        i -= 1
                    i += 1
                    if i == len(self.draw_shape_list):
                        break
            elif action.prop == 'clear':
                self.draw_shape_list = []

    def draw_shape_canvas(self):
        #目前canvas还没什么用,均可用img_show代替,但也可以先留着
        self.canvas = np.zeros(self.img.shape, dtype=np.uint8)
        self.canvas_blank = np.zeros((self.img.shape[0], self.img.shape[1]),
                                     dtype=int)
        count = 1
        if len(self.draw_shape_list) == 0:
            pass
        for shape in self.draw_shape_list:
            #            shape.x1, shape.y1 = self.mouse_pos_ratio_change_line(shape.x1, shape.y1)
            #            shape.x2, shape.y2 = self.mouse_pos_ratio_change_line(shape.x2, shape.y2)
            #            shape.pos_refresh()
            if shape.prop == 'line' or shape.prop == 'base line':
                x_temp, y_temp = Pos_of_Line(*list(shape.pos[0]),
                                             *list(shape.pos[1]))
                self.canvas_blank = record_draw_shape(self.canvas_blank, \
                                                      np.array(x_temp), np.array(y_temp), \
                                                      shape.num)
                cv2.circle(self.img, shape.pos[0], 5, shape.color, 1)
                cv2.line(self.img, *shape.pos, shape.color, shape.width)
                cv2.putText(self.img, str(count), shape.pos[1], self.font, 0.7, \
                            shape.color, 1, cv2.LINE_AA)
                #print(self.get_distance(shape.pos[0][0], shape.pos[0][1],\
                #                        shape.pos[1][0], shape.pos[1][1]))

                count += 1
                if shape.show_distance:
                    distance = self.calculate_distance(shape.x1, shape.y1,
                                                       shape.x2, shape.y2)
                    pos = (round((shape.x1 + shape.x2) / 2),
                           round((shape.y1 + shape.y2) / 2))
                    cv2.putText(self.img, str(round(distance, 2)), pos, \
                                self.font, 0.7, (255,0,0), 1, cv2.LINE_AA)
            elif shape.prop == 'grating':
                cv2.putText(self.img, str(count), (shape.x2, shape.y2), self.font, 0.7, \
                            shape.color, 1, cv2.LINE_AA)
                count += 1
                for grating in shape.grating_list:
                    x_temp, y_temp = Pos_of_Line(*list(grating.pos[0]),
                                                 *list(grating.pos[1]))
                    self.canvas_blank = record_draw_shape(self.canvas_blank, \
                                                          np.array(x_temp), np.array(y_temp), \
                                                          shape.num)
                    cv2.circle(self.img, grating.pos[0], 5, grating.color, 1)
                    cv2.line(self.img, *grating.pos, grating.color,
                             grating.width)

    def find_eraser_num(self):
        x_temp, y_temp = Pos_in_Circle(*list(self.draw_shape_action_list[-1].pos[0]), \
                                       self.draw_shape_action_list[-1].size)
        for i in range(len(x_temp)):
            if x_temp[i] < self.canvas_blank.shape[1] and y_temp[
                    i] < self.canvas_blank.shape[0]:
                num = self.canvas_blank[y_temp[i], x_temp[i]]
                if num != 0:
                    self.draw_shape_action_list[-1].num.append(num)
                    break

    def start_refresh(self):
        self.refresh_timer.start(30)

    def show_on_screen(self):
        self.img_qi = QImage(self.img[:], self.img.shape[1], self.img.shape[0],\
                          self.img.shape[1] * 3, QImage.Format_RGB888)
        self.pixmap = QPixmap(self.img_qi)
        self.lbl_main.setPixmap(self.pixmap)

    def stop_cut(self):
        print('stop')

    def run_cut(self):
        draw_list_length = len(self.draw_shape_list)
        i = 0
        while i < draw_list_length:
            shape = self.draw_shape_list[i]
            if shape.prop == 'grating':
                for grating in shape:
                    shape_list = [shape]
                    self.cutting(shape_list)
            else:
                shape_list = [shape]
                #            shape_points = self.get_read_list(shape.pos[0][0], shape.pos[0][1],\
                #                                              shape.pos[1][0], shape.pos[1][1])

                for j in range(i, draw_list_length - 1):
                    shape_current = self.draw_shape_list[j]
                    shape_next = self.draw_shape_list[j + 1]
                    if shape_current.pos[1][0] == shape_next.pos[0][0] and \
                       shape_current.pos[1][1] == shape_next.pos[0][1]:
                        #                        shape_points += self.get_read_list(shape_next.pos[0][0], shape_next.pos[0][1],\
                        #                                                           shape_next.pos[1][0], shape_next.pos[1][1])
                        shape_list.append(shape_next)
                        i = j + 1
                    else:
                        break

            #z_pos_read = self.read_z_on_line(shape_points)
                self.cutting(shape_list)  #, z_pos_read)
            i += 1

#                z_pos_read = self.read_z_on_line(shape.pos[0][0], shape.pos[0][1],\
#                                                 shape.pos[1][0], shape.pos[1][1])
#
#                self.cutting(shape.pos[0][0], shape.pos[0][1],\
#                             shape.pos[1][0], shape.pos[1][1],\
#                             z_pos_read)

    def get_hwnd(self):
        window_name = 'NanoDrive Innova Tapping'
        innova_hwnd = win32gui.FindWindow(None, window_name)

        hwnd = innova_hwnd
        hwndChildList = []
        win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd),
                                  hwndChildList)
        z_position_hwnd = 0
        z_offset_hwnd = 0
        for hwnd_child in hwndChildList:
            name = win32gui.GetWindowText(hwnd_child)
            if name == 'z_position':
                z_position_hwnd = hwnd_child
            elif name == 'z_offset':
                z_offset_hwnd = hwnd_child

        hwnd = z_position_hwnd
        hwndChildList = []
        win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd),
                                  hwndChildList)
        self.z_position_hwnd = hwndChildList[3]

        hwnd = z_offset_hwnd
        hwndChildList = []
        win32gui.EnumChildWindows(hwnd, lambda hwnd, param: param.append(hwnd),
                                  hwndChildList)
        self.z_offset_button_hwnd = hwndChildList[0]
        self.z_offset_text_hwnd = hwndChildList[2]

        self.z_offset_Button = ButtonWrapper(self.z_offset_button_hwnd)
        self.z_Edit = EditWrapper(self.z_offset_text_hwnd)

    def drag_prob(self, x, y):
        self.x_Edit.set_text(str(x))
        self.y_Edit.set_text(str(y))
        win32api.SendMessage(self.new_y_hwnd, win32con.WM_CHAR, 13, 0)

    def read_z_pos(self):
        left, top, right, bottom = win32gui.GetWindowRect(self.z_position_hwnd)
        for i in range(5):
            screenshot = pyautogui.screenshot(region=[left+1,top+1,\
                                                   right-left-2,\
                                                   bottom-top-2])
            screenshot = np.asarray(screenshot)
            ret, num = identify_num(screenshot, self.afp_dir, self.afp,
                                    self.bfp_dir, self.bfp)
            if ret:
                return True, num

        return False, num

    def set_offset(self, offset_number):
        self.z_Edit.set_text(str(round(offset_number, 4)))
        win32api.SendMessage(self.z_offset_text_hwnd, win32con.WM_CHAR, 13, 0)

    def cutting(self, shape_list, z_pos_read=[]):
        self.move_time_Edit.set_text(str(0.5))
        win32api.SendMessage(self.move_time_hwnd, win32con.WM_CHAR, 13, 0)
        time.sleep(0.2)
        pos_x, pos_y  = self.get_pos_on_screen(shape_list[0].pos[0][0], \
                                               shape_list[0].pos[0][1])
        self.drag_prob(pos_x, pos_y)
        time.sleep(0.6)

        for i in range(10):
            try:
                self.z_offset_Button.click()
                break
            except:
                time.sleep(0.1)
        time.sleep(0.5)
        text = 0
        for i in range(26):
            text += 0.01
            self.set_offset(text)
            time.sleep(0.2)


#        points = self.get_read_list(x1, y1, x2, y2)
        for shape in shape_list:

            distance = self.get_distance(shape.pos[0][0], shape.pos[0][1],\
                                         shape.pos[1][0], shape.pos[1][1])
            time_cut = self.scan_speed * distance
            #time_interval = time_cut/len(z_pos_read)
            time_cut = round(time_cut, 3)
            self.move_time_Edit.set_text(str(time_cut))
            win32api.SendMessage(self.move_time_hwnd, win32con.WM_CHAR, 13, 0)
            #time.sleep(0.1)
            pos_x, pos_y = self.get_pos_on_screen(shape.pos[1][0],
                                                  shape.pos[1][1])
            self.drag_prob(pos_x, pos_y)
            #time.sleep(0.1)

            #self.z_offset_Button.click()
            #time.sleep(0.2)
            #time.sleep(time_cut-2)
        '''
        for i in range(1, len(z_pos_read) + 1):
            if i < len(z_pos_read):
                diff = (int(z_pos_read[-i + -1]) - int(z_pos_read[-i]))/10000
            else:
                diff = 0
            text += diff
            print(text)
            self.set_offset(text)
            time.sleep(round(time_interval - 0.05, 6))
        '''
        '''
        for i in range(1,len(points)+1):
            pos_x, pos_y = self.get_pos_on_screen(points[-i][0], points[-i][1])
            
            self.drag_prob(pos_x, pos_y)
            time.sleep(0.4)
            if i < len(points):
             #   if z_pos_read[i + 1] > z_pos_read[i]:
                diff = (int(z_pos_read[-i + -1]) - int(z_pos_read[-i]))/10000
            else:
                diff = 0
            text += diff
            print(text)
            #self.set_offset(text)
            #time.sleep(0.2)
        '''
        for i in range(10):
            try:
                self.z_offset_Button.click()
                break
            except:
                time.sleep(0.1)
        time.sleep(0.2)
        self.move_time_Edit.set_text(str(0.5))
        win32api.SendMessage(self.move_time_hwnd, win32con.WM_CHAR, 13, 0)
        time.sleep(0.5)

    def read_z_on_line(self, points):
        #        points = self.get_read_list(x1, y1, x2, y2)
        z_pos_read = []
        for point in points:
            pos_x, pos_y = self.get_pos_on_screen(point[0], point[1])
            self.drag_prob(pos_x, pos_y)
            time.sleep(0.6)
            ret, z_temp = self.read_z_pos()
            print(z_temp)
            if ret:
                z_pos_read.append(z_temp)
            else:
                if len(z_pos_read) > 0:
                    z_pos_read.append(z_pos_read[-1])

        for i in range(len(points) - len(z_pos_read)):
            z_pos_read.append(z_pos_read[-1])
        return z_pos_read

    def get_distance(self, x1, y1, x2, y2):
        total_pixel = self.img.shape[0]
        total_distance = self.total_range

        pixel = np.sqrt((x2 - x1)**2 + (y2 - y1)**2)

        distance = pixel / total_pixel * total_distance
        distance = round(distance, 2)
        return distance

    def get_pos_on_screen(self, x, y):
        x -= int((self.img.shape[1] / 2))
        x_pos = self.get_distance(0, 0, x, 0)
        x_pos = round(x_pos, 4)
        if x < 0:
            x_pos = -x_pos

        y = -y
        y += int((self.img.shape[0]) / 2)
        y_pos = self.get_distance(0, 0, 0, y)
        y_pos = round(y_pos, 4)
        if y < 0:
            y_pos = -y_pos
        return x_pos, y_pos

    def get_read_list(self, x1, y1, x2, y2):
        x_temp, y_temp = Pos_of_Line(x1, y1, x2, y2)
        points = [[x1, y1]]
        x_start, y_start = x1, y1
        for i in range(len(x_temp)):
            if self.get_distance(x_temp[i], y_temp[i], x_start, y_start) > 2:
                points.append([x_temp[i], y_temp[i]])
                x_start, y_start = x_temp[i], y_temp[i]
        if points[-1][0] != x2 or points[-1][1] != y2:
            points.append([x2, y2])
        return points

    def wait_cut(self):
        pass

    def repeat_cut(self):
        print('repeat cut')
Esempio n. 17
0
class ImageViewerTab(GalacteekTab):
    def __init__(self, mainW):
        super().__init__(mainW)

        self.pinButton = QToolButton(self)
        self.pinButton.setIcon(getIcon('pin.png'))
        self.pinButton.setEnabled(True)

        self.zoomIn = QToolButton(self)
        self.zoomIn.setIcon(getIcon('zoom-in.png'))
        self.zoomIn.setShortcut(QKeySequence('Ctrl++'))
        self.zoomIn.setToolTip(iZoomIn())
        self.zoomOut = QToolButton(self)
        self.zoomOut.setIcon(getIcon('zoom-out.png'))
        self.zoomOut.setShortcut(QKeySequence('Ctrl+-'))
        self.zoomOut.setToolTip(iZoomOut())

        self.fitWindow = QToolButton(self)
        self.fitWindow.setCheckable(True)
        self.fitWindow.setToolTip('Fit to window')
        self.fitWindow.setIcon(getIcon('expand.png'))

        self.pathLabel = IPFSUrlLabel(None)
        self.pathClipB = IPFSPathClipboardButton(None)

        layout = QHBoxLayout()
        layout.addWidget(self.pathLabel, 0, Qt.AlignLeft)
        layout.addWidget(self.pathClipB, 0, Qt.AlignLeft)
        layout.addItem(
            QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum))
        layout.addWidget(self.pinButton, 0, Qt.AlignLeft)
        layout.addItem(
            QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum))
        layout.addWidget(self.zoomOut, 0, Qt.AlignLeft)
        layout.addWidget(self.zoomIn, 0, Qt.AlignLeft)
        layout.addWidget(self.fitWindow, 0, Qt.AlignLeft)

        self.vLayout.addLayout(layout)

        self.view = ImageView(self)
        self.view.imageLoaded.connect(self.onImageLoaded)
        self.view.qrCodesPresent.connect(self.onQrCodesListed)
        self.vLayout.addWidget(self.view)

        self.zoomIn.clicked.connect(self.view.zoomInClicked)
        self.zoomOut.clicked.connect(self.view.zoomOutClicked)
        self.fitWindow.clicked.connect(
            lambda: self.view.fitWindow(self.fitWindow.isChecked()))
        self.pinButton.clicked.connect(self.view.pinImage)

    def onImageLoaded(self, path, mimeType):
        self.pinButton.setEnabled(True)
        self.pathLabel.path = path
        self.pathClipB.path = path

    def onQrCodesListed(self, urls):
        # Create the scroll area and fix maximum height
        # TODO: set maximum size on resize as well
        scrollArea = QScrollArea()
        scrollArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        scrollArea.setWidgetResizable(True)
        scrollArea.setMaximumHeight(self.height() / 3)

        frame = QFrame(scrollArea)
        frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        layout = QVBoxLayout()
        layout.setSizeConstraint(QLayout.SetMinAndMaxSize)

        scrollArea.setWidget(frame)

        iconOpen = getIcon('open.png')
        lbl = QLabel()
        lbl.setText(iImageGotQrCodes(len(urls)))
        lbl.setObjectName('qrCodeCountLabel')
        lbl.setStyleSheet('QLabel { font-size: 14pt; text-align: center; }')
        layout.addWidget(lbl)
        layout.addItem(
            QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum))

        def onOpenItem(url):
            ensure(self.app.resourceOpener.open(url))

        for url in urls:
            hLayout = QHBoxLayout()
            hLayout.setSizeConstraint(QLayout.SetMinAndMaxSize)
            urlString = str(url)

            if len(urlString) > 92:
                urlText = urlString[0:92] + '...'
            else:
                urlText = urlString

            lbl = QLabel()
            lbl.setText('<b>{}</b>'.format(urlText))
            lbl.setToolTip(urlString)
            lbl.setStyleSheet('QLabel { font-size: 12pt }')

            clipBtn = QToolButton(self)
            clipBtn.setIcon(getIcon('clipboard.png'))
            clipBtn.setToolTip(iCopyToClipboard())
            clipBtn.clicked.connect(
                functools.partial(self.app.setClipboardText, str(url)))

            openBtn = QToolButton(self)
            openBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
            openBtn.setIcon(iconOpen)
            openBtn.setText(iOpen())
            openBtn.clicked.connect(functools.partial(onOpenItem, url))

            hLayout.addWidget(lbl)
            hLayout.addWidget(openBtn)
            hLayout.addWidget(clipBtn)
            layout.addLayout(hLayout)

        frame.setLayout(layout)
        self.vLayout.addWidget(scrollArea)
Esempio n. 18
0
class CollapsibleWidget(QWidget):
    """
    This widget defines a customized widget to hold information and can collapse on click.
    """

    def __init__(self, title: str = ""):
        super().__init__()
        logging.debug("Creating CollapsibleWidget - %s", title)
        self.title = title

        layout_main = QVBoxLayout(self)
        layout_main.setContentsMargins(0, 0, 0, 0)
        layout_main.setSpacing(0)

        self.btn_toggle = QToolButton()
        self.btn_toggle.setStyleSheet("QToolButton { padding-left: 5px; }")
        self.btn_toggle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.btn_toggle.setText(title)
        self.btn_toggle.setCheckable(True)
        self.btn_toggle.setChecked(False)
        self.btn_toggle.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.btn_toggle.setArrowType(Qt.RightArrow)
        self.btn_toggle.setIconSize(QSize(8, 8))
        self.btn_toggle.pressed.connect(self.toggle)

        self.content = QWidget()
        self.content.hide()
        self.layout_content = QVBoxLayout(self.content)
        self.layout_content.setContentsMargins(13, 2, 13, 5)
        self.layout_content.setSpacing(2)

        layout_main.addWidget(self.btn_toggle)
        layout_main.addWidget(self.content)

    def toggle(self):
        """
        this changes whether or not the QWidget is collapsed or not.
        :return: Returns nothing.
        """
        logging.info("Toggling - %s", self.title)
        checked = self.btn_toggle.isChecked()
        self.btn_toggle.setArrowType(Qt.RightArrow if checked else Qt.DownArrow)
        self.content.setVisible(not checked)

    def collapse(self):
        """
        this collapses the widget.
        :return: Returns nothing.
        """
        logging.info("Collapsing - %s", self.title)
        self.btn_toggle.setChecked(True)
        self.toggle()

    def expand(self):
        """
        this expands the widget.
        :return: Returns nothing.
        """
        logging.info("Expanding - %s", self.title)
        self.btn_toggle.setChecked(False)
        self.toggle()

    def addElement(self, widget: QWidget):
        """
        this adds a QWidget to the collapsible widget
        :param widget: Widget to add
        """
        self.layout_content.addWidget(widget)

    def deleteElement(self, widget: QWidget):
        """
        Removes an element from the layout
        :param widget: Widget to remove
        """
        widget.setParent(None)
        self.layout_content.removeWidget(widget)
class CollapsibleBox(QWidget):
    def __init__(self, title="", parent=None):
        super(CollapsibleBox, self).__init__(parent)

        self.toggle_button = QToolButton(text=title,
                                         checkable=True,
                                         checked=False)
        self.toggle_button.setStyleSheet("QToolButton { border: none; }")
        self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toggle_button.setArrowType(Qt.RightArrow)
        self.toggle_button.pressed.connect(self.on_pressed)

        self.toggle_animation = QParallelAnimationGroup(self)

        self.content_area = QScrollArea(maximumHeight=0, minimumHeight=0)

        self.content_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.content_area.setFrameShape(QFrame.NoFrame)

        self.content_area.setVisible(False)

        self.lay = QVBoxLayout(self)
        self.lay.setSpacing(0)
        self.lay.setContentsMargins(0, 0, 0, 0)
        self.lay.addWidget(self.toggle_button)
        self.lay.addWidget(self.content_area)

        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"minimumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self, b"maximumHeight"))
        self.toggle_animation.addAnimation(
            QPropertyAnimation(self.content_area, b"maximumHeight"))

    @pyqtSlot()
    def on_pressed(self):
        checked = self.toggle_button.isChecked()
        self.content_area.setVisible(not checked)
        self.toggle_button.setArrowType(
            Qt.DownArrow if not checked else Qt.RightArrow)
        self.toggle_animation.setDirection(
            QAbstractAnimation.Forward if not checked else QAbstractAnimation.
            Backward)
        self.toggle_animation.start()
        self.toggle_button.setChecked(not checked)

    def setContentLayout(self, layout):
        lay = self.content_area.layout()
        del lay
        self.content_area.setLayout(layout)
        self.content_area.setStyleSheet("background-color:transparent;")
        collapsed_height = (self.sizeHint().height() -
                            self.content_area.maximumHeight())
        content_height = layout.sizeHint().height()
        for i in range(self.toggle_animation.animationCount()):
            animation = self.toggle_animation.animationAt(i)
            animation.setDuration(500)
            animation.setStartValue(collapsed_height)
            animation.setEndValue(collapsed_height + content_height)

        content_animation = self.toggle_animation.animationAt(
            self.toggle_animation.animationCount() - 1)
        content_animation.setDuration(500)
        content_animation.setStartValue(0)
        content_animation.setEndValue(content_height)