Ejemplo n.º 1
0
class ZoomAndDropableGraphicView(ZoomableGraphicView):
    signal_loaded = pyqtSignal(ProtocolAnalyzer)

    def __init__(self, parent=None):
        self.scene_creator = None
        """:type: SignalSceneManager """
        self.signal_tree_root = None
        """type signal_tree_root: ProtocolTreeItem"""

        self.signal = None
        self.proto_analyzer = None

        super().__init__(parent)

    def dragEnterEvent(self, QDragEnterEvent):
        QDragEnterEvent.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        mimedata = event.mimeData()
        data_str = str(mimedata.text())
        indexes = list(data_str.split("/")[:-1])

        signal = None
        proto_analyzer = None
        for index in indexes:
            row, column, parent = map(int, index.split(","))
            if parent == -1:
                parent = self.signal_tree_root
            else:
                parent = self.signal_tree_root.child(parent)
            node = parent.child(row)
            if node.protocol is not None and node.protocol.signal is not None:
                signal = node.protocol.signal
                proto_analyzer = node.protocol
                break

        if signal is None:
            return

        self.draw_signal(signal, proto_analyzer)

    def draw_signal(self, signal, proto_analyzer):
        if signal is None:
            return

        self.horizontalScrollBar().blockSignals(True)

        self.scene_creator = SignalSceneManager(signal, self)
        self.scene_creator.init_scene()
        self.setScene(self.scene_creator.scene)
        self.scene_creator.show_full_scene()
        self.fitInView(self.sceneRect())
        self.signal_loaded.emit(proto_analyzer)
        self.signal = signal
        self.proto_analyzer = proto_analyzer

        self.horizontalScrollBar().blockSignals(False)

    def handle_signal_zoomed_or_scrolled(self):
        if self.scene_creator is not None:
            x1 = self.view_rect().x()
            x2 = x1 + self.view_rect().width()
            self.scene_creator.show_scene_section(x1, x2)
Ejemplo n.º 2
0
class SignalFrameController(QFrame):
    closed = pyqtSignal(QWidget)
    signal_created = pyqtSignal(Signal)
    drag_started = pyqtSignal(QPoint)
    frame_dropped = pyqtSignal(QPoint)
    files_dropped = pyqtSignal(list)
    not_show_again_changed = pyqtSignal()
    signal_drawing_finished = pyqtSignal()
    apply_to_all_clicked = pyqtSignal(Signal)
    sort_action_clicked = pyqtSignal()

    def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack,
                 project_manager, proto_bits=None, parent=None):
        super().__init__(parent)
        self.ui = Ui_SignalFrame()
        self.ui.setupUi(self)

        self.ui.txtEdProto.setFont(FontHelper.getMonospaceFont())

        self.ui.btnMinimize.setIcon(QIcon(":/icons/data/icons/downarrow.png"))
        self.is_minimized = False
        self.common_zoom = False
        self.undo_stack = undo_stack
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.project_manager = project_manager

        self.proto_analyzer = proto_analyzer
        self.signal = proto_analyzer.signal if self.proto_analyzer is not None else None
        """:type: Signal """

        self.redraw_timer = QTimer()
        self.redraw_timer.setSingleShot(True)
        self.redraw_timer.setInterval(100)

        self.proto_selection_timer = QTimer()  # For Update Proto Selection from ROI
        self.proto_selection_timer.setSingleShot(True)
        self.proto_selection_timer.setInterval(1)

        if self.signal is not None:
            if self.signal.qad_demod_file_loaded:
                self.ui.lSignalTyp.setText("Quad-Demod Signal (*.wav)")
            elif self.signal.wav_mode:
                self.ui.lSignalTyp.setText("Realpart Signal (*.wav)")
            else:
                self.ui.lSignalTyp.setText("Complex Signal")

            self.ui.gvLegend.hide()
            self.ui.lineEditSignalName.setText(self.signal.name)
            self.ui.lSamplesInView.setText("{0:,}".format(self.signal.num_samples))
            self.ui.lSamplesTotal.setText("{0:,}".format(self.signal.num_samples))
            self.sync_protocol = self.ui.chkBoxSyncSelection.isChecked()
            self.ui.chkBoxSyncSelection.hide()

            self.ui.splitter.setSizes([self.ui.splitter.height(), 0])

            self.protocol_selection_is_updateable = True

            self.scene_creator = SignalSceneManager(self.signal, self)
            self.ui.gvSignal.setScene(self.scene_creator.scene)

            self.jump_sync = True
            self.handle_show_hide_start_end_clicked()

            self.refresh_signal_informations(block=True)
            self.create_connects()
            self.set_protocol_visibilty()

            self.ui.chkBoxShowProtocol.setChecked(True)
            self.set_qad_tooltip(self.signal.noise_treshold)
            self.ui.btnSaveSignal.hide()

            self.show_protocol(refresh=False)

        else:
            self.ui.lSignalTyp.setText("Protocol (*.txt)")

            scene, nsamples = SignalSceneManager.create_rectangle(proto_bits)

            self.ui.lSamplesInView.setText("{0:n}".format(int(nsamples)))
            self.ui.lSamplesTotal.setText("{0:n}".format(int(nsamples)))
            self.ui.gvSignal.setScene(scene)
            self.ui.btnReplay.hide()

            self.create_connects()
            self.ui.btnSaveSignal.hide()
            self.minimize_maximize()

    @property
    def spectrogram_is_active(self) -> bool:
        return self.ui.stackedWidget.currentWidget() == self.ui.pageSpectrogram

    def create_connects(self):
        self.ui.spinBoxSelectionStart.valueChanged.connect(self.set_selection_start)
        self.ui.spinBoxSelectionEnd.valueChanged.connect(self.set_selection_end)
        self.ui.gvSignal.set_noise_clicked.connect(self.update_noise_min_max)
        self.ui.btnCloseSignal.clicked.connect(self.my_close)

        self.ui.btnAutoDetect.clicked.connect(self.on_btn_autodetect_clicked)

        if self.signal is not None:
            self.ui.gvSignal.save_clicked.connect(self.save_signal)

            self.signal.bit_len_changed.connect(self.ui.spinBoxInfoLen.setValue)
            self.signal.qad_center_changed.connect(self.update_qad_center_view)
            self.signal.qad_center_changed.connect(self.ui.spinBoxCenterOffset.setValue)
            self.signal.noise_treshold_changed.connect(self.redraw_noise)
            self.signal.modulation_type_changed.connect(self.show_modulation_type)
            self.signal.tolerance_changed.connect(self.ui.spinBoxTolerance.setValue)
            self.signal.protocol_needs_update.connect(self.refresh_protocol)
            self.signal.full_refresh_needed.connect(self.refresh)
            self.signal.sample_rate_changed.connect(self.__set_duration)
            self.signal.sample_rate_changed.connect(self.show_protocol)  # Update times

            self.ui.gvSignal.horizontalScrollBar().valueChanged.connect(self.on_signal_scrolled)

            self.signal.saved_status_changed.connect(self.handle_signal_data_changed_before_save)
            self.ui.btnSaveSignal.clicked.connect(self.save_signal)
            self.signal.name_changed.connect(self.ui.lineEditSignalName.setText)
            self.ui.gvLegend.resized.connect(self.handle_gv_legend_resized)

            self.ui.gvSignal.selection_width_changed.connect(self.start_proto_selection_timer)
            self.ui.gvSignal.sel_area_start_end_changed.connect(self.start_proto_selection_timer)
            self.proto_selection_timer.timeout.connect(self.update_protocol_selection_from_roi)
            self.spectrogram_update_timer.timeout.connect(self.on_spectrogram_update_timer_timeout)

            self.ui.lineEditSignalName.editingFinished.connect(self.change_signal_name)
            self.proto_analyzer.qt_signals.protocol_updated.connect(self.on_protocol_updated)
            self.redraw_timer.timeout.connect(self.redraw_signal)

        self.ui.btnReplay.clicked.connect(self.on_btn_replay_clicked)
        self.ui.gvSignal.save_as_clicked.connect(self.save_signal_as)
        self.ui.gvSignal.create_clicked.connect(self.create_new_signal)
        self.ui.gvSignal.show_crop_range_clicked.connect(self.show_autocrop_range)
        self.ui.gvSignal.crop_clicked.connect(self.crop_signal)
        self.ui.gvSignal.zoomed.connect(self.handle_signal_zoomed)
        self.ui.sliderYScale.valueChanged.connect(self.handle_slideryscale_value_changed)
        self.ui.spinBoxXZoom.valueChanged.connect(self.handle_spinbox_xzoom_value_changed)



        self.ui.btnInfo.clicked.connect(self.on_info_btn_clicked)

        self.proto_selection_timer.timeout.connect(self.update_nselected_samples)
        self.ui.gvSignal.sel_area_start_end_changed.connect(self.update_selection_area)
        self.ui.cbSignalView.currentIndexChanged.connect(self.on_cb_signal_view_index_changed)

        self.ui.chkBoxShowProtocol.stateChanged.connect(self.set_protocol_visibilty)
        self.ui.gvSignal.sep_area_changed.connect(self.set_qad_center)
        self.ui.txtEdProto.proto_view_changed.connect(self.show_protocol)
        self.ui.txtEdProto.show_proto_clicked.connect(self.update_roi_from_protocol_selection)
        self.ui.txtEdProto.show_proto_clicked.connect(self.zoom_to_roi)
        self.ui.gvSignal.sep_area_moving.connect(self.update_legend)
        self.ui.txtEdProto.selectionChanged.connect(self.update_roi_from_protocol_selection)
        self.ui.chkBoxSyncSelection.stateChanged.connect(self.handle_protocol_sync_changed)
        self.ui.gvSignal.deletion_wanted.connect(self.delete_selection)
        self.ui.gvSignal.mute_wanted.connect(self.mute_selection)

        self.ui.spinBoxCenterOffset.editingFinished.connect(self.on_spinBoxCenter_editingFinished)
        self.ui.spinBoxTolerance.editingFinished.connect(self.on_spinBoxTolerance_editingFinished)
        self.ui.spinBoxNoiseTreshold.editingFinished.connect(self.on_spinBoxNoiseTreshold_editingFinished)
        self.ui.spinBoxInfoLen.editingFinished.connect(self.on_spinBoxInfoLen_editingFinished)

        self.ui.btnShowHideStartEnd.clicked.connect(self.handle_show_hide_start_end_clicked)
        self.ui.cbProtoView.currentIndexChanged.connect(self.handle_proto_infos_index_changed)
        self.ui.txtEdProto.deletion_wanted.connect(self.delete_from_protocol_selection)

        self.ui.btnMinimize.clicked.connect(self.minimize_maximize)

    @property
    def proto_view(self):
        return self.ui.txtEdProto.cur_view

    @property
    def signal_widgets(self):
        splitter = self.parent()
        for i in range(splitter.count() - 1):
            yield (splitter.widget(i))

    def refresh_signal_informations(self, block=True):
        self.ui.spinBoxTolerance.blockSignals(block)
        self.ui.spinBoxCenterOffset.blockSignals(block)
        self.ui.spinBoxInfoLen.blockSignals(block)
        self.ui.spinBoxNoiseTreshold.blockSignals(block)
        self.ui.btnAutoDetect.blockSignals(block)

        self.ui.spinBoxTolerance.setValue(self.signal.tolerance)
        self.ui.spinBoxCenterOffset.setValue(self.signal.qad_center)
        self.ui.spinBoxInfoLen.setValue(self.signal.bit_len)
        self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_treshold)
        self.ui.btnAutoDetect.setChecked(self.signal.auto_detect_on_modulation_changed)
        self.show_modulation_type()

        self.ui.spinBoxTolerance.blockSignals(False)
        self.ui.spinBoxCenterOffset.blockSignals(False)
        self.ui.spinBoxInfoLen.blockSignals(False)
        self.ui.spinBoxNoiseTreshold.blockSignals(False)
        self.ui.btnAutoDetect.blockSignals(False)

    def set_empty_frame_visibilities(self):
        self.ui.lInfoLenText.hide()
        self.ui.spinBoxInfoLen.hide()
        self.ui.spinBoxCenterOffset.hide()
        self.ui.spinBoxTolerance.hide()
        self.ui.chkBoxShowProtocol.hide()
        self.ui.cbProtoView.hide()
        self.ui.lErrorTolerance.hide()
        self.ui.lSignalViewText.hide()
        self.ui.chkBoxSyncSelection.hide()
        self.ui.txtEdProto.hide()
        self.ui.gvLegend.hide()
        self.ui.cbSignalView.hide()
        #self.ui.btnCloseSignal.hide()
        self.ui.btnSaveSignal.hide()
        self.ui.btnMinimize.hide()

    @pyqtSlot(float)
    def update_legend(self, y_sep):
        if self.ui.gvLegend.isVisible():
            self.ui.gvLegend.ysep = y_sep
            self.ui.gvLegend.refresh()
        self.ui.spinBoxCenterOffset.blockSignals(True)
        self.ui.spinBoxCenterOffset.setValue(-y_sep)
        self.ui.spinBoxCenterOffset.blockSignals(False)

    def emit_signal_drawing_finished(self):
        self.signal_drawing_finished.emit()

    @pyqtSlot()
    def handle_protocol_sync_changed(self):
        self.sync_protocol = self.ui.chkBoxSyncSelection.isChecked()

    @pyqtSlot()
    def set_protocol_visibilty(self):
        checked = self.ui.chkBoxShowProtocol.isChecked()

        if checked:
            self.show_protocol()
            self.ui.cbProtoView.setEnabled(True)
            self.ui.chkBoxSyncSelection.show()
            self.ui.txtEdProto.show()
        else:
            self.ui.txtEdProto.hide()
            self.ui.chkBoxSyncSelection.hide()
            self.ui.cbProtoView.setEnabled(False)

    @pyqtSlot()
    def on_cb_signal_view_index_changed(self):
        self.setCursor(Qt.WaitCursor)

        ind = self.ui.cbSignalView.currentIndex()
        self.scene_creator.scene_type = ind
        gvs = self.ui.gvSignal

        if ind > 0:
            self.signal.modulation_type = ind - 1

        vr = self.ui.gvSignal.view_rect()
        self.scene_creator.init_scene()
        self.scene_creator.show_scene_section(vr.x(), vr.x() + vr.width())

        if ind > 0:
            self.ui.gvLegend.y_scene = self.scene_creator.scene.sceneRect().y()
            self.ui.gvLegend.scene_height = self.scene_creator.scene.sceneRect().height()
            self.ui.gvLegend.refresh()
        else:
            self.ui.gvLegend.hide()

        QApplication.processEvents()
        gvs.autofit_view()
        self.handle_slideryscale_value_changed()  # YScale auf neue Sicht übertragen
        self.unsetCursor()

    @pyqtSlot()
    def on_btn_autodetect_clicked(self):
        self.signal.auto_detect_on_modulation_changed = bool(self.ui.btnAutoDetect.isChecked())
        if self.ui.btnAutoDetect.isChecked():
            self.signal.auto_detect()

    @pyqtSlot()
    def on_btn_replay_clicked(self):
        pmngr = self.project_manager
        dialog = SendRecvDialogController(pmngr.frequency, pmngr.sample_rate,
                                          pmngr.bandwidth, pmngr.gain, pmngr.device,
                                          Mode.send, modulated_data=self.signal.data, parent=self)
        if dialog.has_empty_device_list:
            Errors.no_device()
            dialog.close()
            return

        dialog.recording_parameters.connect(pmngr.set_recording_parameters)
        dialog.show()

    def update_nselected_samples(self):
        self.ui.lNumSelectedSamples.setText(str(abs(int(self.ui.gvSignal.selection_area.width))))
        self.__set_duration()


    @pyqtSlot(int, int)
    def update_selection_area(self, start, end):
        # if start > end:
        #     start, end = end, start

        self.ui.lNumSelectedSamples.setText(str(end - start))
        self.__set_duration()
        self.ui.spinBoxSelectionStart.blockSignals(True)
        self.ui.spinBoxSelectionStart.setValue(start)
        self.ui.spinBoxSelectionStart.blockSignals(False)
        self.ui.spinBoxSelectionEnd.blockSignals(True)
        self.ui.spinBoxSelectionEnd.setValue(end)
        self.ui.spinBoxSelectionEnd.blockSignals(False)

    def change_signal_name(self):
        self.signal.name = self.ui.lineEditSignalName.text()
Ejemplo n.º 3
0
class SignalFrameController(QFrame):
    closed = pyqtSignal(QWidget)
    signal_created = pyqtSignal(Signal)
    drag_started = pyqtSignal(QPoint)
    frame_dropped = pyqtSignal(QPoint)
    files_dropped = pyqtSignal(list)
    not_show_again_changed = pyqtSignal()
    signal_drawing_finished = pyqtSignal()
    apply_to_all_clicked = pyqtSignal(Signal)
    sort_action_clicked = pyqtSignal()

    def __init__(self,
                 proto_analyzer: ProtocolAnalyzer,
                 undo_stack: QUndoStack,
                 project_manager,
                 proto_bits=None,
                 parent=None):
        super().__init__(parent)
        self.ui = Ui_SignalFrame()
        self.ui.setupUi(self)

        self.ui.txtEdProto.setFont(FontHelper.getMonospaceFont())

        self.ui.btnMinimize.setIcon(QIcon(":/icons/data/icons/downarrow.png"))
        self.is_minimized = False
        self.common_zoom = False
        self.undo_stack = undo_stack
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.project_manager = project_manager

        self.proto_analyzer = proto_analyzer
        self.signal = proto_analyzer.signal if self.proto_analyzer is not None else None
        """:type: Signal """

        self.redraw_timer = QTimer()
        self.redraw_timer.setSingleShot(True)
        self.redraw_timer.setInterval(100)

        self.proto_selection_timer = QTimer(
        )  # For Update Proto Selection from ROI
        self.proto_selection_timer.setSingleShot(True)
        self.proto_selection_timer.setInterval(1)

        if self.signal is not None:
            if self.signal.qad_demod_file_loaded:
                self.ui.lSignalTyp.setText("Quad-Demod Signal (*.wav)")
            elif self.signal.wav_mode:
                self.ui.lSignalTyp.setText("Realpart Signal (*.wav)")
            else:
                self.ui.lSignalTyp.setText("Complex Signal")

            self.ui.gvLegend.hide()
            self.ui.lineEditSignalName.setText(self.signal.name)
            self.ui.lSamplesInView.setText("{0:,}".format(
                self.signal.num_samples))
            self.ui.lSamplesTotal.setText("{0:,}".format(
                self.signal.num_samples))
            self.sync_protocol = self.ui.chkBoxSyncSelection.isChecked()
            self.ui.chkBoxSyncSelection.hide()

            self.ui.splitter.setSizes([self.ui.splitter.height(), 0])

            self.protocol_selection_is_updateable = True

            self.scene_creator = SignalSceneManager(self.signal, self)
            self.ui.gvSignal.setScene(self.scene_creator.scene)

            self.jump_sync = True
            self.handle_show_hide_start_end_clicked()

            self.refresh_signal_informations(block=True)
            self.create_connects()
            self.set_protocol_visibilty()

            self.ui.chkBoxShowProtocol.setChecked(True)
            self.set_qad_tooltip(self.signal.noise_treshold)
            self.ui.btnSaveSignal.hide()

            self.show_protocol(refresh=False)

        else:
            self.ui.lSignalTyp.setText("Protocol (*.txt)")

            scene, nsamples = SignalSceneManager.create_rectangle(proto_bits)

            self.ui.lSamplesInView.setText("{0:n}".format(int(nsamples)))
            self.ui.lSamplesTotal.setText("{0:n}".format(int(nsamples)))
            self.ui.gvSignal.setScene(scene)
            self.ui.spinBoxSelectionStart.setMaximum(nsamples)
            self.ui.spinBoxSelectionEnd.setMaximum(nsamples)
            self.ui.btnReplay.hide()

            self.create_connects()

            self.ui.gvSignal.sel_area_active = True

            self.ui.btnSaveSignal.hide()
            self.minimize_maximize()

    def create_connects(self):
        self.ui.spinBoxSelectionStart.valueChanged.connect(
            self.set_selection_start)
        self.ui.spinBoxSelectionEnd.valueChanged.connect(
            self.set_selection_end)
        self.ui.gvSignal.set_noise_clicked.connect(self.update_noise_min_max)
        self.ui.btnCloseSignal.clicked.connect(self.my_close)

        self.ui.btnAutoDetect.clicked.connect(self.on_btn_autodetect_clicked)

        if self.signal is not None:
            self.ui.gvSignal.save_clicked.connect(self.save_signal)

            self.signal.bit_len_changed.connect(
                self.ui.spinBoxInfoLen.setValue)
            self.signal.qad_center_changed.connect(self.update_qad_center_view)
            self.signal.qad_center_changed.connect(
                self.ui.spinBoxCenterOffset.setValue)
            self.signal.noise_treshold_changed.connect(self.redraw_noise)
            self.signal.modulation_type_changed.connect(
                self.show_modulation_type)
            self.signal.tolerance_changed.connect(
                self.ui.spinBoxTolerance.setValue)
            self.signal.protocol_needs_update.connect(self.refresh_protocol)
            self.signal.full_refresh_needed.connect(self.refresh)
            self.signal.sample_rate_changed.connect(self.__set_duration)
            self.signal.sample_rate_changed.connect(
                self.show_protocol)  # Update times

            self.ui.gvSignal.horizontalScrollBar().valueChanged.connect(
                self.on_signal_scrolled)

            self.signal.saved_status_changed.connect(
                self.handle_signal_data_changed_before_save)
            self.ui.btnSaveSignal.clicked.connect(self.save_signal)
            self.signal.name_changed.connect(
                self.ui.lineEditSignalName.setText)
            self.ui.gvLegend.resized.connect(self.handle_gv_legend_resized)

            self.ui.gvSignal.sel_area_width_changed.connect(
                self.start_proto_selection_timer)
            self.ui.gvSignal.sel_area_start_end_changed.connect(
                self.start_proto_selection_timer)
            self.proto_selection_timer.timeout.connect(
                self.update_protocol_selection_from_roi)

            self.ui.lineEditSignalName.editingFinished.connect(
                self.change_signal_name)
            self.proto_analyzer.qt_signals.protocol_updated.connect(
                self.on_protocol_updated)
            self.redraw_timer.timeout.connect(self.redraw_signal)

        self.ui.btnReplay.clicked.connect(self.on_btn_replay_clicked)
        self.ui.gvSignal.save_as_clicked.connect(self.save_signal_as)
        self.ui.gvSignal.create_clicked.connect(self.create_new_signal)
        self.ui.gvSignal.show_crop_range_clicked.connect(
            self.show_autocrop_range)
        self.ui.gvSignal.crop_clicked.connect(self.crop_signal)
        self.ui.gvSignal.zoomed.connect(self.handle_signal_zoomed)
        self.ui.sliderYScale.valueChanged.connect(
            self.handle_slideryscale_value_changed)
        self.ui.spinBoxXZoom.valueChanged.connect(
            self.handle_spinbox_xzoom_value_changed)

        self.ui.btnInfo.clicked.connect(self.on_info_btn_clicked)

        self.proto_selection_timer.timeout.connect(
            self.update_nselected_samples)
        self.ui.gvSignal.sel_area_start_end_changed.connect(
            self.update_selection_area)
        self.ui.cbSignalView.currentIndexChanged.connect(
            self.on_cb_signal_view_index_changed)

        self.ui.chkBoxShowProtocol.stateChanged.connect(
            self.set_protocol_visibilty)
        self.ui.gvSignal.sep_area_changed.connect(self.set_qad_center)
        self.ui.txtEdProto.proto_view_changed.connect(self.show_protocol)
        self.ui.txtEdProto.show_proto_clicked.connect(
            self.update_roi_from_protocol_selection)
        self.ui.txtEdProto.show_proto_clicked.connect(self.zoom_to_roi)
        self.ui.gvSignal.sep_area_moving.connect(self.update_legend)
        self.ui.txtEdProto.selectionChanged.connect(
            self.update_roi_from_protocol_selection)
        self.ui.chkBoxSyncSelection.stateChanged.connect(
            self.handle_protocol_sync_changed)
        self.ui.gvSignal.deletion_wanted.connect(self.delete_selection)
        self.ui.gvSignal.mute_wanted.connect(self.mute_selection)

        self.ui.spinBoxCenterOffset.editingFinished.connect(
            self.on_spinBoxCenter_editingFinished)
        self.ui.spinBoxTolerance.editingFinished.connect(
            self.on_spinBoxTolerance_editingFinished)
        self.ui.spinBoxNoiseTreshold.editingFinished.connect(
            self.on_spinBoxNoiseTreshold_editingFinished)
        self.ui.spinBoxInfoLen.editingFinished.connect(
            self.on_spinBoxInfoLen_editingFinished)

        self.ui.btnShowHideStartEnd.clicked.connect(
            self.handle_show_hide_start_end_clicked)
        self.ui.cbProtoView.currentIndexChanged.connect(
            self.handle_proto_infos_index_changed)
        self.ui.txtEdProto.deletion_wanted.connect(
            self.delete_from_protocol_selection)

        self.ui.btnMinimize.clicked.connect(self.minimize_maximize)

    @property
    def proto_view(self):
        return self.ui.txtEdProto.cur_view

    @property
    def signal_widgets(self):
        splitter = self.parent()
        for i in range(splitter.count() - 1):
            yield (splitter.widget(i))

    def refresh_signal_informations(self, block=True):
        self.ui.spinBoxTolerance.blockSignals(block)
        self.ui.spinBoxCenterOffset.blockSignals(block)
        self.ui.spinBoxInfoLen.blockSignals(block)
        self.ui.spinBoxNoiseTreshold.blockSignals(block)
        self.ui.btnAutoDetect.blockSignals(block)

        self.ui.spinBoxTolerance.setValue(self.signal.tolerance)
        self.ui.spinBoxCenterOffset.setValue(self.signal.qad_center)
        self.ui.spinBoxInfoLen.setValue(self.signal.bit_len)
        self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_treshold)
        self.ui.btnAutoDetect.setChecked(
            self.signal.auto_detect_on_modulation_changed)
        self.show_modulation_type()

        self.ui.spinBoxTolerance.blockSignals(False)
        self.ui.spinBoxCenterOffset.blockSignals(False)
        self.ui.spinBoxInfoLen.blockSignals(False)
        self.ui.spinBoxNoiseTreshold.blockSignals(False)
        self.ui.btnAutoDetect.blockSignals(False)

    def set_empty_frame_visibilities(self):
        self.ui.lInfoLenText.hide()
        self.ui.spinBoxInfoLen.hide()
        self.ui.spinBoxCenterOffset.hide()
        self.ui.spinBoxTolerance.hide()
        self.ui.chkBoxShowProtocol.hide()
        self.ui.cbProtoView.hide()
        self.ui.lErrorTolerance.hide()
        self.ui.lSignalViewText.hide()
        self.ui.chkBoxSyncSelection.hide()
        self.ui.txtEdProto.hide()
        self.ui.gvLegend.hide()
        self.ui.cbSignalView.hide()
        #self.ui.btnCloseSignal.hide()
        self.ui.btnSaveSignal.hide()
        self.ui.btnMinimize.hide()

    @pyqtSlot(float)
    def update_legend(self, y_sep):
        if self.ui.gvLegend.isVisible():
            self.ui.gvLegend.ysep = y_sep
            self.ui.gvLegend.refresh()
        self.ui.spinBoxCenterOffset.blockSignals(True)
        self.ui.spinBoxCenterOffset.setValue(-y_sep)
        self.ui.spinBoxCenterOffset.blockSignals(False)

    def emit_signal_drawing_finished(self):
        self.signal_drawing_finished.emit()

    @pyqtSlot()
    def handle_protocol_sync_changed(self):
        self.sync_protocol = self.ui.chkBoxSyncSelection.isChecked()

    @pyqtSlot()
    def set_protocol_visibilty(self):
        checked = self.ui.chkBoxShowProtocol.isChecked()

        if checked:
            self.show_protocol()
            self.ui.cbProtoView.setEnabled(True)
            self.ui.chkBoxSyncSelection.show()
            self.ui.txtEdProto.show()
        else:
            self.ui.txtEdProto.hide()
            self.ui.chkBoxSyncSelection.hide()
            self.ui.cbProtoView.setEnabled(False)

    @pyqtSlot()
    def on_cb_signal_view_index_changed(self):
        self.setCursor(Qt.WaitCursor)

        ind = self.ui.cbSignalView.currentIndex()
        self.scene_creator.scene_type = ind
        gvs = self.ui.gvSignal

        if ind > 0:
            self.signal.modulation_type = ind - 1

        vr = self.ui.gvSignal.view_rect()
        self.scene_creator.init_scene()
        self.scene_creator.show_scene_section(vr.x(), vr.x() + vr.width())

        if ind > 0:
            self.ui.gvLegend.y_scene = self.scene_creator.scene.sceneRect().y()
            self.ui.gvLegend.scene_height = self.scene_creator.scene.sceneRect(
            ).height()
            self.ui.gvLegend.refresh()
        else:
            self.ui.gvLegend.hide()

        QApplication.processEvents()
        gvs.autofit_view()
        self.handle_slideryscale_value_changed(
        )  # YScale auf neue Sicht übertragen
        self.unsetCursor()

    @pyqtSlot()
    def on_btn_autodetect_clicked(self):
        self.signal.auto_detect_on_modulation_changed = bool(
            self.ui.btnAutoDetect.isChecked())
        if self.ui.btnAutoDetect.isChecked():
            self.signal.auto_detect()

    @pyqtSlot()
    def on_btn_replay_clicked(self):
        pmngr = self.project_manager
        dialog = SendRecvDialogController(pmngr.frequency,
                                          pmngr.sample_rate,
                                          pmngr.bandwidth,
                                          pmngr.gain,
                                          pmngr.device,
                                          Mode.send,
                                          modulated_data=self.signal.data,
                                          parent=self)
        if dialog.has_empty_device_list:
            Errors.no_device()
            dialog.close()
            return

        dialog.recording_parameters.connect(pmngr.set_recording_parameters)
        dialog.show()

    def update_nselected_samples(self):
        self.ui.lNumSelectedSamples.setText(
            str(abs(int(self.ui.gvSignal.selection_area.width))))
        self.__set_duration()

    @pyqtSlot(int, int)
    def update_selection_area(self, start, end):
        # if start > end:
        #     start, end = end, start

        self.ui.lNumSelectedSamples.setText(str(end - start))
        self.__set_duration()
        self.ui.spinBoxSelectionStart.blockSignals(True)
        self.ui.spinBoxSelectionStart.setValue(start)
        self.ui.spinBoxSelectionStart.blockSignals(False)
        self.ui.spinBoxSelectionEnd.blockSignals(True)
        self.ui.spinBoxSelectionEnd.setValue(end)
        self.ui.spinBoxSelectionEnd.blockSignals(False)

    def change_signal_name(self):
        self.signal.name = self.ui.lineEditSignalName.text()

    def __set_duration(self):  # On Signal Sample Rate changed
        try:
            nsamples = int(self.ui.lNumSelectedSamples.text())
        except ValueError:
            return

        if self.signal:
            t = nsamples / self.signal.sample_rate
            self.ui.lDuration.setText(Formatter.science_time(t))

    @pyqtSlot()
    def handle_signal_zoomed(self):
        gvs = self.ui.gvSignal
        self.ui.lSamplesInView.setText("{0:n}".format(
            int(gvs.view_rect().width())))
        self.ui.spinBoxXZoom.blockSignals(True)
        self.ui.spinBoxXZoom.setValue(
            int(gvs.sceneRect().width() / gvs.view_rect().width() * 100))
        self.ui.spinBoxXZoom.blockSignals(False)
        self.redraw_timer.start()

    def handle_spinbox_xzoom_value_changed(self):
        gvs = self.ui.gvSignal
        zoom_factor = self.ui.spinBoxXZoom.value() / 100
        current_factor = gvs.sceneRect().width() / gvs.view_rect().width()
        gvs.zoom(zoom_factor / current_factor)

    def handle_slideryscale_value_changed(self):
        try:
            gvs = self.ui.gvSignal
            yscale = self.ui.sliderYScale.value()
            current_factor = gvs.sceneRect().height() / gvs.view_rect().height(
            )
            gvs.scale(1, yscale / current_factor)
            x, w = self.ui.gvSignal.view_rect().x(
            ), self.ui.gvSignal.view_rect().width()
            gvs.centerOn(x + w / 2, gvs.y_center)
        except ZeroDivisionError:
            pass

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_started.emit(self.mapToParent(event.pos()))
            drag = QDrag(self)
            mimeData = QMimeData()
            mimeData.setText("Move Signal")
            pixmap = QPixmap(self.rect().size())
            self.render(pixmap, QPoint(), QRegion(self.rect()))
            drag.setPixmap(pixmap)

            drag.setMimeData(mimeData)

            drag.exec_()

    def dragMoveEvent(self, event):
        event.accept()

    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        if len(event.mimeData().urls()) == 0:
            self.frame_dropped.emit(self.mapToParent(event.pos()))
        else:
            self.files_dropped.emit(event.mimeData().urls())

    def create_new_signal(self, start, end):
        if start < end:
            new_signal = self.signal.create_new(start, end)
            self.signal_created.emit(new_signal)
        else:
            Errors.empty_selection()

    def my_close(self):
        settings = constants.SETTINGS
        try:
            not_show = settings.value('not_show_close_dialog', type=bool)
        except TypeError:
            not_show = False

        if not not_show:
            #ok, notshowagain = CloseDialog.dialog(self)
            ok, notshowagain = CustomDialog.dialog(self,
                                                   "Do you want to close?",
                                                   "close")
            settings.setValue("not_show_close_dialog", notshowagain)
            self.not_show_again_changed.emit()
            if not ok:
                return

        self.closed.emit(self)
        #self.signal.deleteLater()
        #self.scene_creator.deleteLater()
        #

    @pyqtSlot()
    def update_noise_min_max(self):
        self.setCursor(Qt.WaitCursor)
        start = self.ui.gvSignal.selection_area.x
        end = start + self.ui.gvSignal.selection_area.width

        self.signal.calc_noise_treshold(start, end)
        self.redraw_noise()
        self.unsetCursor()

    def redraw_noise(self):
        self.ui.spinBoxNoiseTreshold.setValue(self.signal.noise_treshold)
        minimum = self.signal.noise_min_plot
        maximum = self.signal.noise_max_plot
        if self.ui.cbSignalView.currentIndex() == 0:
            # Draw Noise only in Analog View
            self.ui.gvSignal.scene().draw_noise_area(minimum,
                                                     maximum - minimum)

    @pyqtSlot()
    def set_selection_start(self):
        if self.ui.gvSignal.sel_area_active:
            self.ui.gvSignal.set_selection_area(
                x=self.ui.spinBoxSelectionStart.value())
            self.ui.gvSignal.selection_area.finished = True
            self.ui.gvSignal.emit_sel_area_width_changed()

    @pyqtSlot()
    def set_selection_end(self):
        if self.ui.gvSignal.sel_area_active:
            self.ui.gvSignal.set_selection_area(
                w=self.ui.spinBoxSelectionEnd.value() -
                self.ui.spinBoxSelectionStart.value())
            self.ui.gvSignal.selection_area.finished = True
            self.ui.gvSignal.emit_sel_area_width_changed()

    def save_signal(self):
        if len(self.signal.filename) > 0:
            self.signal.save()
        else:
            self.save_signal_as()

    def save_signal_as(self):
        filename = FileOperator.get_save_file_name(
            self.signal.filename, wav_only=self.signal.wav_mode, parent=self)
        if filename:
            try:
                self.signal.save_as(filename)
            except Exception as e:
                QMessageBox.critical(self, self.tr("Error saving signal"),
                                     e.args[0])

    def crop_signal(self):
        gvs = self.ui.gvSignal
        if not gvs.selection_area.is_empty:
            w = gvs.sceneRect().width()
            start = gvs.selection_area.x
            end = start + gvs.selection_area.width
            if end < start:
                start, end = end, start

            crop_action = CropSignal(self.signal, start, end)
            self.undo_stack.push(crop_action)
            # self.signal.crop(start, end)
            gvs.zoom((end - start) / w, supress_signal=True
                     )  # Zoomlevel von VorCrop auf NachCrop übertragen

    def show_autocrop_range(self):
        start = self.signal.get_signal_start()
        end = self.signal.get_signal_end()

        self.ui.gvSignal.set_selection_area(start, end - start)
        self.ui.gvSignal.selection_area.finished = True
        self.ui.gvSignal.emit_sel_area_width_changed()

    def draw_signal(self, full_signal=False):
        gvs = self.ui.gvSignal
        gv_legend = self.ui.gvLegend
        gv_legend.ysep = -self.signal.qad_center

        # Save current visible region for restoring it after drawing
        y, h = gvs.sceneRect().y(), gvs.sceneRect().height()
        x, w = gvs.view_rect().x(), gvs.view_rect().width()

        self.scene_creator.scene_type = self.ui.cbSignalView.currentIndex()
        self.scene_creator.init_scene()
        if full_signal:
            gvs.draw_full_signal()
        else:
            self.display_scene()

        legend = LegendScene()
        legend.setBackgroundBrush(constants.BGCOLOR)
        legend.setSceneRect(0,
                            self.scene_creator.scene.sceneRect().y(),
                            gv_legend.width(),
                            self.scene_creator.scene.sceneRect().height())
        legend.draw_one_zero_arrows(-self.signal.qad_center)
        gv_legend.setScene(legend)

        num_samples = self.signal.num_samples
        self.ui.spinBoxSelectionStart.setMaximum(num_samples)
        self.ui.spinBoxSelectionEnd.setMaximum(num_samples)
        gvs.nsamples = num_samples

        gvs.sel_area_active = True
        gvs.y_sep = -self.signal.qad_center

        if not full_signal:
            # Restore Zoom
            w = w if w < self.signal.num_samples else self.signal.num_samples
            gvs.fitInView(QRectF(x, y, w, h))
            gvs.centerOn(x + w / 2, gvs.y_center)

    def restore_protocol_selection(self, sel_start, sel_end, start_block,
                                   end_block, old_protoview):
        if old_protoview == self.proto_view:
            return

        self.protocol_selection_is_updateable = False
        # TODO Temporär Gruppe anlegen und convert index aufrufen? Oder statische methode in ProtocolGroup.
        sel_start = int(
            self.proto_analyzer.convert_index(sel_start, old_protoview,
                                              self.proto_view, True)[0])
        sel_end = int(
            math.ceil(
                self.proto_analyzer.convert_index(sel_end, old_protoview,
                                                  self.proto_view, True)[1]))

        c = self.ui.txtEdProto.textCursor()

        c.setPosition(0)
        cur_block = 0
        i = 0
        text = self.ui.txtEdProto.toPlainText()
        while cur_block < start_block:
            if text[i] == "\n":
                cur_block += 1
            i += 1

        c.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, i)
        c.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, sel_start)
        text = text[i:]
        i = 0
        while cur_block < end_block:
            if text[i] == "\n":
                cur_block += 1
            i += 1

        c.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, i)
        c.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, sel_end)

        self.ui.txtEdProto.setTextCursor(c)

        self.protocol_selection_is_updateable = True

    def update_protocol(self):
        self.ui.txtEdProto.setPlainText("Loading..")
        self.ui.txtEdProto.setEnabled(False)
        QApplication.processEvents()

        self.proto_analyzer.get_protocol_from_signal()

    def on_protocol_updated(self):
        self.ui.txtEdProto.setEnabled(True)
        self.ui.txtEdProto.setPlainText(
            self.proto_analyzer.plain_to_string(self.proto_view))

    def show_protocol(self, old_view=-1, refresh=False):
        if not self.proto_analyzer:
            return

        chkd = self.ui.chkBoxShowProtocol.isChecked()
        if not chkd:
            return

        if old_view == -1:
            old_view = self.ui.cbProtoView.currentIndex()

        if self.proto_analyzer.blocks is None or refresh:
            self.update_protocol()
        else:
            # Keep things synchronized and restore selection
            self.ui.txtEdProto.blockSignals(True)
            self.ui.cbProtoView.blockSignals(True)
            self.ui.cbProtoView.setCurrentIndex(self.proto_view)
            self.ui.cbProtoView.blockSignals(False)

            start_block = 0
            sel_start = self.ui.txtEdProto.textCursor().selectionStart()
            text = self.ui.txtEdProto.toPlainText()[:sel_start]
            sel_start = 0
            read_pause = False
            for t in text:
                if t == "\t":
                    read_pause = True

                if not read_pause:
                    sel_start += 1

                if t == "\n":
                    sel_start = 0
                    start_block += 1
                    read_pause = False

            sel_end = self.ui.txtEdProto.textCursor().selectionEnd()
            text = self.ui.txtEdProto.toPlainText(
            )[self.ui.txtEdProto.textCursor().selectionStart():sel_end]
            end_block = 0
            sel_end = 0
            read_pause = False
            for t in text:
                if t == "\t":
                    read_pause = True

                if not read_pause:
                    sel_end += 1

                if t == "\n":
                    sel_end = 0
                    end_block += 1
                    read_pause = False

            self.ui.txtEdProto.setPlainText(
                self.proto_analyzer.plain_to_string(self.proto_view))
            self.restore_protocol_selection(sel_start, sel_end, start_block,
                                            end_block, old_view)

            self.ui.txtEdProto.blockSignals(False)

    @pyqtSlot()
    def refresh_protocol(self):
        self.show_protocol(refresh=True)

    @pyqtSlot()
    def handle_proto_infos_index_changed(self):
        old_view = self.ui.txtEdProto.cur_view
        self.ui.txtEdProto.cur_view = self.ui.cbProtoView.currentIndex()
        self.show_protocol(old_view=old_view)

    @pyqtSlot(float)
    def set_qad_center(self, th):
        self.ui.gvLegend.ysep = -th

        self.signal.qad_center = th
        self.ui.spinBoxCenterOffset.setValue(th)
        self.proto_analyzer.blocks = None
        if self.ui.cbSignalView.currentIndex() > 0:
            self.scene_creator.scene.draw_sep_area(-self.signal.qad_center)
            self.ui.gvLegend.refresh()
        self.show_protocol()

    @pyqtSlot()
    def set_info_len_from_spinbox(self):
        val = self.ui.spinBoxInfoLen.value()
        if val != self.signal.bit_len:
            self.signal.bit_len = val

    def set_roi_from_protocol_analysis(self, start_block, start_pos, end_block,
                                       end_pos, view_type):
        if not self.proto_analyzer:
            return

        if not self.ui.chkBoxShowProtocol.isChecked():
            self.ui.chkBoxShowProtocol.setChecked(True)
            self.set_protocol_visibilty()

        self.ui.cbProtoView.setCurrentIndex(view_type)

        if view_type == 1:
            # Hex View
            start_pos *= 4
            end_pos *= 4
        elif view_type == 2:
            # ASCII View
            start_pos *= 8
            end_pos *= 8

        samplepos, nsamples = self.proto_analyzer.get_samplepos_of_bitseq(
            start_block, start_pos, end_block, end_pos, True)
        self.protocol_selection_is_updateable = False
        if samplepos != -1:
            if self.jump_sync and self.sync_protocol:
                self.ui.gvSignal.centerOn(samplepos, self.ui.gvSignal.y_center)
                self.ui.gvSignal.set_selection_area(samplepos, nsamples)
                self.ui.gvSignal.centerOn(samplepos + nsamples,
                                          self.ui.gvSignal.y_center)
            else:
                self.ui.gvSignal.set_selection_area(samplepos, nsamples)

            self.ui.gvSignal.zoom_to_selection(samplepos, samplepos + nsamples)
        else:
            self.ui.gvSignal.set_selection_area(0, 0)

        self.protocol_selection_is_updateable = True
        self.update_protocol_selection_from_roi()

    @pyqtSlot()
    def update_roi_from_protocol_selection(self):
        txtEdit = self.ui.txtEdProto
        end_pos = txtEdit.textCursor().selectionEnd()
        start_pos = txtEdit.textCursor().selectionStart()
        forward_selection = txtEdit.textCursor().anchor(
        ) <= txtEdit.textCursor().position()

        if start_pos > end_pos:
            start_pos, end_pos = end_pos, start_pos

        start_block = txtEdit.toPlainText()[:start_pos].count("\n")
        end_block = start_block + txtEdit.toPlainText(
        )[start_pos:end_pos].count("\n")
        newline_pos = txtEdit.toPlainText()[:start_pos].rfind("\n")

        if newline_pos != -1:
            start_pos -= (newline_pos + 1)

        newline_pos = txtEdit.toPlainText()[:end_pos].rfind("\n")
        if newline_pos != -1:
            end_pos -= (newline_pos + 1)

        if txtEdit.cur_view == 1:
            # Hex View
            start_pos *= 4
            end_pos *= 4
        elif txtEdit.cur_view == 2:
            # ASCII View
            start_pos *= 8
            end_pos *= 8

        try:
            include_last_pause = False
            s = txtEdit.textCursor().selectionStart()
            e = txtEdit.textCursor().selectionEnd()
            if s > e:
                s, e = e, s

            selected_text = txtEdit.toPlainText()[s:e]

            last_newline = selected_text.rfind("\n")
            if last_newline == -1:
                last_newline = 0

            if selected_text.endswith(" "):
                end_pos -= 1
            elif selected_text.endswith(" \t"):
                end_pos -= 2

            if "[" in selected_text[last_newline:]:
                include_last_pause = True

            samplepos, nsamples = self.proto_analyzer.get_samplepos_of_bitseq(
                start_block, start_pos, end_block, end_pos, include_last_pause)

        except IndexError:
            return

        self.ui.gvSignal.blockSignals(True)
        if samplepos != -1:
            if self.jump_sync and self.sync_protocol:
                self.ui.gvSignal.centerOn(samplepos, self.ui.gvSignal.y_center)
                self.ui.gvSignal.set_selection_area(samplepos, nsamples)
                if forward_selection:  # Forward Selection --> Center ROI to End of Selection
                    self.ui.gvSignal.centerOn(samplepos + nsamples,
                                              self.ui.gvSignal.y_center)
                else:  # Backward Selection --> Center ROI to Start of Selection
                    self.ui.gvSignal.centerOn(samplepos,
                                              self.ui.gvSignal.y_center)
            else:
                self.ui.gvSignal.set_selection_area(samplepos, nsamples)
        else:
            self.ui.gvSignal.set_selection_area(0, 0)
        self.ui.gvSignal.blockSignals(False)

        self.update_nselected_samples()

    def zoom_to_roi(self):
        roi = self.ui.gvSignal.selection_area
        start, end = roi.x, roi.x + roi.width
        self.ui.gvSignal.zoom_to_selection(start, end)

    @pyqtSlot()
    def start_proto_selection_timer(self):
        self.proto_selection_timer.start()

    @pyqtSlot()
    def update_protocol_selection_from_roi(self):
        protocol = self.proto_analyzer

        if protocol.blocks is None or not self.ui.chkBoxShowProtocol.isChecked(
        ):
            return

        start = self.ui.gvSignal.selection_area.x
        w = self.ui.gvSignal.selection_area.width

        if w < 0:
            start += w
            w = -w

        c = self.ui.txtEdProto.textCursor()
        self.jump_sync = False
        self.ui.txtEdProto.blockSignals(True)

        try:
            startblock, startindex, endblock, endindex = protocol.get_bitseq_from_selection(
                start, w, self.signal.bit_len)
        except IndexError:
            c.clearSelection()
            self.ui.txtEdProto.setTextCursor(c)
            self.jump_sync = True
            self.ui.txtEdProto.blockSignals(False)
            return

        if startblock == -1 or endindex == -1 or startindex == -1 or endblock == -1:
            c.clearSelection()
            self.ui.txtEdProto.setTextCursor(c)
            self.jump_sync = True
            self.ui.txtEdProto.blockSignals(False)
            return

        # TODO: Temporär Gruppe für Convert anlegen? Oder statische Methode in ProtocolGroup hinzufügen
        startindex = int(
            protocol.convert_index(startindex, 0, self.proto_view, True)[0])
        endindex = int(
            math.ceil(
                protocol.convert_index(endindex, 0, self.proto_view, True)[1]))
        text = self.ui.txtEdProto.toPlainText()
        n = 0
        blockpos = 0
        c.setPosition(0)

        for i, t in enumerate(text):
            blockpos += 1
            if t == "\n":
                n += 1
                blockpos = 0

            if n == startblock and blockpos == startindex:
                c.setPosition(i + 1, QTextCursor.MoveAnchor)

            if n == endblock and blockpos == endindex:
                c.setPosition(i, QTextCursor.KeepAnchor)
                break

        self.ui.txtEdProto.setTextCursor(c)
        self.ui.txtEdProto.blockSignals(False)
        self.jump_sync = True

    @pyqtSlot()
    def refresh(self, draw_full_signal=False):
        gvs = self.ui.gvSignal
        gvs.sel_area_active = False
        self.draw_signal(draw_full_signal)

        self.ui.lSamplesInView.setText("{0:n}".format(
            int(gvs.view_rect().width())))
        self.ui.lSamplesTotal.setText("{0:n}".format(self.signal.num_samples))

        selected = 0
        if not self.ui.gvSignal.selection_area.is_empty:
            selected = self.ui.gvSignal.selection_area.width

        self.ui.lNumSelectedSamples.setText(str(selected))
        self.__set_duration()

        self.set_qad_tooltip(self.signal.noise_treshold)
        self.refresh_signal_informations(block=True)

        self.show_protocol(refresh=True)

        gvs.sel_area_active = True

    def delete_selection(self, start, end):
        self.ui.gvSignal.clear_selection()
        del_action = DeleteSignalRange(self.signal, start, end)
        self.undo_stack.push(del_action)
        self.ui.gvSignal.centerOn(start, self.ui.gvSignal.y_center)

    def mute_selection(self, start: int, end: int):
        mute_action = MuteSignalRange(self.signal, start, end)
        self.undo_stack.push(mute_action)

    @pyqtSlot()
    def on_spinBoxCenter_editingFinished(self):
        if self.signal.qad_center != self.ui.spinBoxCenterOffset.value():
            self.ui.spinBoxCenterOffset.blockSignals(True)
            self.signal.qad_center = self.ui.spinBoxCenterOffset.value()
            self.disable_auto_detection()

    def update_qad_center_view(self):
        self.ui.gvSignal.y_sep = -self.signal.qad_center
        self.ui.gvLegend.ysep = -self.signal.qad_center

        if self.ui.cbSignalView.currentIndex() > 0:
            self.scene_creator.scene.draw_sep_area(-self.signal.qad_center)
            self.ui.gvLegend.refresh()
        self.ui.spinBoxCenterOffset.blockSignals(False)

    @pyqtSlot()
    def on_spinBoxTolerance_editingFinished(self):
        if self.signal.tolerance != self.ui.spinBoxTolerance.value():
            self.ui.spinBoxTolerance.blockSignals(True)
            self.signal.tolerance = self.ui.spinBoxTolerance.value()
            self.ui.spinBoxTolerance.blockSignals(False)
            self.disable_auto_detection()

    @pyqtSlot()
    def on_spinBoxInfoLen_editingFinished(self):
        if self.signal.bit_len != self.ui.spinBoxInfoLen.value():
            self.ui.spinBoxInfoLen.blockSignals(True)
            self.signal.bit_len = self.ui.spinBoxInfoLen.value()
            self.ui.spinBoxInfoLen.blockSignals(False)
            self.disable_auto_detection()

    @pyqtSlot()
    def handle_show_hide_start_end_clicked(self):
        if self.ui.btnShowHideStartEnd.text() == "+":
            self.ui.btnShowHideStartEnd.setText("-")
            self.ui.verticalLayout.insertItem(2, self.ui.additionalInfos)
            self.ui.lStart.show()
            self.ui.lEnd.show()
            self.ui.lSamplesInView.show()
            self.ui.lStrich.show()
            self.ui.lSamplesTotal.show()
            self.ui.lSamplesViewText.show()
            self.ui.spinBoxSelectionStart.show()
            self.ui.spinBoxSelectionEnd.show()

        else:
            self.ui.btnShowHideStartEnd.setText("+")
            self.ui.lStart.hide()
            self.ui.lEnd.hide()
            self.ui.lSamplesInView.hide()
            self.ui.lStrich.hide()
            self.ui.lSamplesTotal.hide()
            self.ui.lSamplesViewText.hide()
            self.ui.spinBoxSelectionStart.hide()
            self.ui.spinBoxSelectionEnd.hide()
            self.ui.verticalLayout.removeItem(self.ui.additionalInfos)

    def display_scene(self):
        self.scene_creator.scene_type = self.ui.cbSignalView.currentIndex()
        vr = self.ui.gvSignal.view_rect()
        self.scene_creator.show_scene_section(vr.x(), vr.x() + vr.width())

    def delete_from_protocol_selection(self):
        if not self.ui.gvSignal.selection_area.is_empty:
            start = self.ui.gvSignal.selection_area.x
            end = self.ui.gvSignal.selection_area.end
            self.delete_selection(start, end)

    @pyqtSlot()
    def handle_gv_legend_resized(self):
        if self.ui.gvLegend.isVisible():
            self.ui.gvLegend.y_zoom_factor = self.ui.gvSignal.transform().m22()
            self.ui.gvLegend.refresh()
            self.ui.gvLegend.translate(0, 1)  # Resize verschiebt sonst Pfeile

    def minimize_maximize(self):
        elems = vars(self.ui)

        if not self.is_minimized:
            for name, widget in elems.items():
                if name != "btnMinimize" and type(widget) not in (QHBoxLayout, QVBoxLayout, QGridLayout)\
                        and name not in ("lSignalNr", "lineEditSignalName", "btnCloseSignal", "lSignalTyp", "btnSaveSignal"):
                    widget.hide()

            self.ui.btnMinimize.setIcon(
                QIcon(":/icons/data/icons/uparrow.png"))
            self.is_minimized = True
            self.setFixedHeight(65)
        else:
            show_start_end = self.ui.btnShowHideStartEnd.text() == "-"
            for name, widget in elems.items():
                if type(widget) in (QHBoxLayout, QVBoxLayout, QGridLayout):
                    continue
                if not self.ui.chkBoxShowProtocol.isChecked() and name in (
                        "txtEdProto", "chkBoxSyncSelection"):
                    continue
                if not show_start_end and name in (
                        "lStart", "spinBoxSelectionStart", "lEnd",
                        "spinBoxSelectionEnd", "lSamplesInView", "lStrich",
                        "lSamplesTotal", "lSamplesViewText", "btnSaveSignal"):
                    continue

                if not self.signal.changed and name == "btnSaveSignal":
                    continue

                if name == "gvLegend":
                    continue

                widget.show()

            self.ui.btnMinimize.setIcon(
                QIcon(":/icons/data/icons/downarrow.png"))
            self.is_minimized = False
            self.setMinimumHeight(0)
            self.setMaximumHeight(20000)

            if self.ui.cbSignalView.currentIndex() > 0:
                self.ui.gvLegend.refresh()
            if self.signal is None:
                self.set_empty_frame_visibilities()

    def set_qad_tooltip(self, noise_threshold):
        self.ui.cbSignalView.setToolTip(
            "<html><head/><body><p>Choose the view of your signal.</p><p>The quadrature demodulation uses a <span style=\" text-decoration: underline;\">threshold of magnitude,</span> to <span style=\" font-weight:600;\">supress noise</span>. All samples with a magnitude lower than this threshold will be eliminated (set to <span style=\" font-style:italic;\">-127</span>) after demod.</p><p>Tune this value by selecting a <span style=\" font-style:italic;\">noisy area</span> and mark it as noise using <span style=\" text-decoration: underline;\">context menu</span>.</p><p>Current noise threshold is: <b>"
            + str(noise_threshold) + "</b></p></body></html>")

    @pyqtSlot()
    def handle_signal_data_changed_before_save(self):
        font = self.ui.lineEditSignalName.font()
        """:type: QFont """
        if self.signal.changed:
            font.setBold(True)
            self.ui.btnSaveSignal.show()
        else:
            font.setBold(False)
            self.ui.btnSaveSignal.hide()
        self.ui.lineEditSignalName.setFont(font)

    def redraw_after_resize(self):
        if self.ui.gvSignal.view_rect().width() > self.ui.gvSignal.sceneRect(
        ).width():
            x_factor = self.ui.gvSignal.width() / self.ui.gvSignal.sceneRect(
            ).width()
            self.ui.gvSignal.scale(
                x_factor / self.ui.gvSignal.transform().m11(), 1)

        self.ui.gvSignal.autofit_view()

    def contextMenuEvent(self, event: QContextMenuEvent):
        if self.signal is None:
            return

        menu = QMenu()
        applyToAllAction = menu.addAction(
            self.
            tr("Apply values (BitLen, 0/1-Threshold, Tolerance) to all signals"
               ))
        menu.addSeparator()
        autoDetectAction = menu.addAction(
            self.tr("Auto-Detect signal parameters"))
        #sortAction = menu.addAction("Sort Frames by name")
        action = menu.exec_(self.mapToGlobal(event.pos()))
        if action == applyToAllAction:
            self.setCursor(Qt.WaitCursor)
            self.apply_to_all_clicked.emit(self.signal)
            self.unsetCursor()
        elif action == autoDetectAction:
            self.setCursor(Qt.WaitCursor)
            self.signal.auto_detect()
            self.unsetCursor()
        #elif action == sortAction:
        #    self.sort_action_clicked.emit()

    def zoom_all_signals(self, factor):
        """
        This method is used, when 'common Zoom' is enabled
        :param factor:
        :return:
        """
        for sWidget in self.signal_widgets:
            gvs = sWidget.ui.gvSignal
            gvs.zoom(factor)

        for sWidget in self.signal_widgets:
            if sWidget == self:
                continue

    def on_signal_scrolled(self):
        self.redraw_signal()

    def redraw_signal(self):
        vr = self.ui.gvSignal.view_rect()
        self.scene_creator.show_scene_section(vr.x(), vr.x() + vr.width())

    def on_spinBoxNoiseTreshold_editingFinished(self):
        if self.signal is not None and self.signal.noise_treshold != self.ui.spinBoxNoiseTreshold.value(
        ):
            self.signal.noise_treshold = self.ui.spinBoxNoiseTreshold.value()
            self.disable_auto_detection()

    def on_info_btn_clicked(self):
        sdc = SignalDetailsController(self.signal, self)
        sdc.exec_()

    def show_modulation_type(self):
        mod = self.signal.modulation_type
        if mod == 0:
            self.ui.labelModulation.setText("ASK")
        elif mod == 1:
            self.ui.labelModulation.setText("FSK")
        elif mod == 2:
            self.ui.labelModulation.setText("PSK")
        elif mod == 3:
            self.ui.labelModulation.setText("QAM (ASK+PSK)")

    def disable_auto_detection(self):
        """
        Disable auto detection when user manually edited a value

        :return:
        """
        if self.signal.auto_detect_on_modulation_changed:
            self.signal.auto_detect_on_modulation_changed = False
            self.ui.btnAutoDetect.setChecked(False)