Пример #1
0
class ReferenceDialog(QDialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setWindowTitle("Set reference")
        vbox = QVBoxLayout(self)
        grid = QGridLayout()
        self.average = QRadioButton("Average")
        self.channels = QRadioButton("Channel(s):")
        self.average.toggled.connect(self.toggle)
        self.channellist = QLineEdit()
        self.channellist.setEnabled(False)
        self.average.setChecked(True)
        grid.addWidget(self.average, 0, 0)
        grid.addWidget(self.channels, 1, 0)
        grid.addWidget(self.channellist, 1, 1)
        vbox.addLayout(grid)
        buttonbox = QDialogButtonBox(QDialogButtonBox.Ok
                                     | QDialogButtonBox.Cancel)
        vbox.addWidget(buttonbox)
        buttonbox.accepted.connect(self.accept)
        buttonbox.rejected.connect(self.reject)
        vbox.setSizeConstraint(QVBoxLayout.SetFixedSize)

    def toggle(self):
        if self.average.isChecked():
            self.channellist.setEnabled(False)
        else:
            self.channellist.setEnabled(True)
Пример #2
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)

        vert_layout = QVBoxLayout()

        # Type frame
        type_layout = QHBoxLayout()
        type_label = QLabel(_("Import as"))
        type_layout.addWidget(type_label)

        self.array_btn = array_btn = QRadioButton(_("array"))
        array_btn.setEnabled(ndarray is not FakeObject)
        array_btn.setChecked(ndarray is not FakeObject)
        type_layout.addWidget(array_btn)

        list_btn = QRadioButton(_("list"))
        list_btn.setChecked(not array_btn.isChecked())
        type_layout.addWidget(list_btn)

        if pd:
            self.df_btn = df_btn = QRadioButton(_("DataFrame"))
            df_btn.setChecked(False)
            type_layout.addWidget(df_btn)

        h_spacer = QSpacerItem(40, 20,
                               QSizePolicy.Expanding, QSizePolicy.Minimum)
        type_layout.addItem(h_spacer)
        type_frame = QFrame()
        type_frame.setLayout(type_layout)

        self._table_view = PreviewTable(self)
        vert_layout.addWidget(type_frame)
        vert_layout.addWidget(self._table_view)
        self.setLayout(vert_layout)
Пример #3
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)

        vert_layout = QVBoxLayout()

        # Type frame
        type_layout = QHBoxLayout()
        type_label = QLabel(_("Import as"))
        type_layout.addWidget(type_label)

        self.array_btn = array_btn = QRadioButton(_("array"))
        array_btn.setEnabled(ndarray is not FakeObject)
        array_btn.setChecked(ndarray is not FakeObject)
        type_layout.addWidget(array_btn)

        list_btn = QRadioButton(_("list"))
        list_btn.setChecked(not array_btn.isChecked())
        type_layout.addWidget(list_btn)

        if pd:
            self.df_btn = df_btn = QRadioButton(_("DataFrame"))
            df_btn.setChecked(False)
            type_layout.addWidget(df_btn)

        h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                               QSizePolicy.Minimum)
        type_layout.addItem(h_spacer)
        type_frame = QFrame()
        type_frame.setLayout(type_layout)

        self._table_view = PreviewTable(self)
        vert_layout.addWidget(type_frame)
        vert_layout.addWidget(self._table_view)
        self.setLayout(vert_layout)
Пример #4
0
class LabelShow(QWidget):
    """Present single label color scheme"""

    remove_labels = Signal(str)
    edit_labels = Signal([str, list], [list])
    selected = Signal(str)

    def __init__(self, name: str, label: list, removable, parent=None):
        super().__init__(parent)
        self.label = label
        self.name = name
        self.removable = removable

        self.radio_btn = QRadioButton()

        self.label_show = _LabelShow(np.array(label, dtype=np.uint8))

        self.remove_btn = QToolButton()
        self.remove_btn.setIcon(_icon_selector.close_icon)

        self.edit_btn = QToolButton()
        self.edit_btn.setIcon(_icon_selector.edit_icon)

        if removable:
            self.remove_btn.setToolTip("Remove colormap")
        else:
            self.remove_btn.setToolTip("This colormap is protected")

        self.edit_btn.setToolTip("Create new label schema base on this")

        layout = QHBoxLayout()
        layout.addWidget(self.radio_btn)
        layout.addWidget(self.label_show, 1)
        layout.addWidget(self.remove_btn)
        layout.addWidget(self.edit_btn)
        self.remove_btn.setEnabled(removable)
        self.setLayout(layout)
        self.remove_btn.clicked.connect(self.remove_fun)
        self.edit_btn.clicked.connect(self.edit_fun)
        self.radio_btn.clicked.connect(self.selected_fun)

    def set_checked(self, val):
        self.radio_btn.setChecked(val)
        if self.removable:
            self.remove_btn.setDisabled(val)

    @Slot()
    def remove_fun(self):
        if self.remove_btn.isEnabled():
            self.remove_labels.emit(self.name)

    @Slot()
    def edit_fun(self):
        self.edit_labels.emit(self.name, deepcopy(self.label))
        self.edit_labels[list].emit(deepcopy(self.label))

    @Slot(bool)
    def selected_fun(self):
        self.selected.emit(self.name)
Пример #5
0
class TaskOptionsGroupBox(QGroupBox):
    def __init__(self, parent):
        super(TaskOptionsGroupBox, self).__init__(parent)
        self.widget_layout = QFormLayout(self)
        self.setLayout(self.widget_layout)
        self.setTitle("Time")

        self.time_label = QLabel(self)
        self.time_label.setText("Execute: ")

        self.time_now = QRadioButton(self)
        self.time_now.setText("Immediately")
        self.time_now.setChecked(True)

        self.time_schedule = QRadioButton(self)
        self.time_schedule.setText("Schedule")

        self.schedule_select = QDateTimeEdit(self)
        self.schedule_select.setDateTime(QDateTime.currentDateTime())
        self.schedule_select.setEnabled(False)

        self.user_activity_label = QLabel(self)
        self.user_activity_label.setText("User activity")

        self.user_activity_combo = QComboBox(self)
        self.user_activity_combo.addItems([
            "0 - Disabled", "1 - Low", "2 - Normal", "3 - Medium", "4 - High",
            "5 - Very high"
        ])

        self.widget_layout.addRow(self.time_label, None)
        self.widget_layout.addRow(self.time_now, None)
        self.widget_layout.addRow(self.time_schedule, self.schedule_select)
        self.widget_layout.addRow(self.user_activity_label,
                                  self.user_activity_combo)

        self.time_schedule.toggled.connect(self.on_time_schedule_toggled)

    @Slot(bool)
    def on_time_schedule_toggled(self, state):
        if state:
            self.schedule_select.setEnabled(True)
        else:
            self.schedule_select.setEnabled(False)

    def get_options(self):
        resp = {
            "user_activity":
            self.user_activity_combo.currentText().split(" - ")[0]
        }

        if self.time_now.isChecked():
            resp["time"] = "now"

        elif self.time_schedule.isChecked():
            resp["time"] = self.schedule_select.dateTime().toString()
        return resp
Пример #6
0
    def __init__(self, theme='dark', emphasized=False):
        super().__init__(None)
        self.setProperty('emphasized', emphasized)
        self.setStyleSheet(template(raw_stylesheet, **palettes[theme]))
        lay = QVBoxLayout()
        self.setLayout(lay)
        lay.addWidget(QPushButton('push button'))
        box = QComboBox()
        box.addItems(['a', 'b', 'c', 'cd'])
        lay.addWidget(box)
        lay.addWidget(QFontComboBox())

        hbox = QHBoxLayout()
        chk = QCheckBox('tristate')
        chk.setToolTip('I am a tooltip')
        chk.setTristate(True)
        chk.setCheckState(Qt.PartiallyChecked)
        chk3 = QCheckBox('checked')
        chk3.setChecked(True)
        hbox.addWidget(QCheckBox('unchecked'))
        hbox.addWidget(chk)
        hbox.addWidget(chk3)
        lay.addLayout(hbox)

        lay.addWidget(TabDemo(emphasized=emphasized))

        sld = QSlider(Qt.Horizontal)
        sld.setValue(50)
        lay.addWidget(sld)
        scroll = QScrollBar(Qt.Horizontal)
        scroll.setValue(50)
        lay.addWidget(scroll)
        lay.addWidget(QHRangeSlider(parent=self))
        text = QTextEdit()
        text.setMaximumHeight(100)
        text.setHtml(blurb)
        lay.addWidget(text)
        lay.addWidget(QTimeEdit())
        edit = QLineEdit()
        edit.setPlaceholderText('LineEdit placeholder...')
        lay.addWidget(edit)
        lay.addWidget(QLabel('label'))
        prog = QProgressBar()
        prog.setValue(50)
        lay.addWidget(prog)
        groupBox = QGroupBox("Exclusive Radio Buttons")
        radio1 = QRadioButton("&Radio button 1")
        radio2 = QRadioButton("R&adio button 2")
        radio3 = QRadioButton("Ra&dio button 3")
        radio1.setChecked(True)
        hbox = QHBoxLayout()
        hbox.addWidget(radio1)
        hbox.addWidget(radio2)
        hbox.addWidget(radio3)
        hbox.addStretch(1)
        groupBox.setLayout(hbox)
        lay.addWidget(groupBox)
Пример #7
0
 def showListOfCollections(self):
     self.collectionsList.clear()
     if len(config.bibleCollections) > 0:
         for collection in sorted(config.bibleCollections.keys()):
             showBibleSelection = QRadioButton()
             showBibleSelection.setChecked(False)
             self.collectionsList.itemClicked.connect(self.selectCollection)
             self.collectionsList.addItem(collection)
     else:
         self.collectionsList.addItem("[No collection defined]")
Пример #8
0
    def _add_tab(self, json=None):
        """will look at the json and will display the values in conflicts in a new tab to allow the user
        to fix the conflicts"""

        number_of_tabs = self.ui.tabWidget.count()

        _table = QTableWidget()

        # initialize each table
        columns_width = self._calculate_columns_width(json=json)
        for _col in np.arange(len(json[0])):
            _table.insertColumn(_col)
            _table.setColumnWidth(_col, columns_width[_col])
        for _row in np.arange(len(json)):
            _table.insertRow(_row)
        self.list_table.append(_table)

        _table.setHorizontalHeaderLabels(self.columns_label)

        for _row in np.arange(len(json)):

            # run number
            _col = 0
            list_runs = json[_row]["Run Number"]
            o_parser = ListRunsParser()
            checkbox = QRadioButton(o_parser.new_runs(list_runs=list_runs))
            if _row == 0:
                checkbox.setChecked(True)
            # QtCore.QObject.connect(checkbox, QtCore.SIGNAL("clicked(bool)"),
            #                        lambda bool, row=_row, table_id=_table:
            #                        self._changed_conflict_checkbox(bool, row, table_id))
            _table.setCellWidget(_row, _col, checkbox)

            _col += 1
            # chemical formula
            item = QTableWidgetItem(json[_row]["chemical_formula"])
            _table.setItem(_row, _col, item)

            _col += 1
            # geometry
            item = QTableWidgetItem(json[_row]["geometry"])
            _table.setItem(_row, _col, item)

            _col += 1
            # mass_density
            item = QTableWidgetItem(json[_row]["mass_density"])
            _table.setItem(_row, _col, item)

            _col += 1
            # sample_env_device
            item = QTableWidgetItem(json[_row]["sample_env_device"])
            _table.setItem(_row, _col, item)

        self.ui.tabWidget.insertTab(number_of_tabs, _table, "Conflict #{}".format(number_of_tabs))
Пример #9
0
class ModuleCard(QGroupBox):
    """
    Widget used inside Selection to display information about an API or Player
    as a selectable card.
    """
    def __init__(self, module: BaseModuleData, selected: bool = False) -> None:
        """
        A card with the cards's basic info.
        """

        super().__init__(module.short_name)

        self.module = module
        self.setFont(Fonts.smalltext)
        self.setMinimumHeight(270)
        self.setMaximumHeight(400)
        self.setMinimumWidth(220)
        self.setMaximumWidth(300)
        self.layout = QVBoxLayout(self)
        self.setup_icon(module.icon)
        self.setup_text(module.description)
        self.setup_button(module.installed, selected)

    def setup_icon(self, icon: str) -> None:
        self.icon = QPixmap(icon)
        self.icon_label = QLabel()
        self.icon_label.setPixmap(self.icon)
        self.icon_label.setAlignment(Qt.AlignHCenter)
        self.layout.addWidget(self.icon_label)

    def setup_text(self, description: str) -> None:
        self.text = QLabel(description)
        self.text.setStyleSheet("padding: 10px 3px")
        self.text.setWordWrap(True)
        self.text.setFont(Fonts.smalltext)
        self.text.setAlignment(Qt.AlignHCenter)
        self.text.setTextFormat(Qt.RichText)
        self.text.setTextInteractionFlags(Qt.TextBrowserInteraction)
        self.text.setOpenExternalLinks(True)
        self.layout.addWidget(self.text)

    def setup_button(self, enabled: bool, selected: bool) -> None:
        """
        The button will be disabled but still shown if `enabled` is false.
        """

        self.button = QRadioButton("USE" if enabled else "Not Installed")
        self.button.setEnabled(enabled)
        self.button.setChecked(selected)
        font = Fonts.text
        font.setItalic(True)
        self.button.setFont(font)
        self.layout.addWidget(self.button)
Пример #10
0
    def setupui(self):
        vbl = QVBoxLayout(self)
        self.stack = QStackedWidget(self)
        vbl.addWidget(self.stack)

        rbA = QRadioButton('Antennas', self)
        rbP = QRadioButton('Positions', self)
        rbA.toggled.connect(_part(self.toggle_button, 0))
        rbP.toggled.connect(_part(self.toggle_button, 1))
        self.radio_buttons.append(rbA)
        self.radio_buttons.append(rbP)
        rbA.setChecked(True)
        hbl = QHBoxLayout()
        hbl.addStretch()
        hbl.addWidget(rbA)
        hbl.addStretch()
        hbl.addWidget(rbP)
        hbl.addStretch()
        vbl.addItem(hbl)

        # ##### Antennas Widget ######
        stack1 = QWidget(self.stack)
        self.stack.addWidget(stack1)
        vbl = QVBoxLayout(stack1)

        graph = self.create_graph(stack1, 'ant')
        vbl.addWidget(graph)
        stats = self.create_statistics(stack1, 'ant')
        vbl.addWidget(stats)

        # ##### Position and Amplitudes Widget ######
        stack2 = QWidget(self.stack)
        self.stack.addWidget(stack2)
        vbl = QVBoxLayout(stack2)

        graph = self.create_graph(stack2, 'pos')
        vbl.addWidget(graph)
        graph = self.create_graph(stack2, 'amp')
        vbl.addWidget(graph)

        self.setStyleSheet("""
            #SinglePassDataGraph{
                min-width:48em;
                min-height:24em;
            }
            QLabel{
                min-width:6em; max-width:6em;
                min-height:1.5em; max-height:1.5em;
            }""")
Пример #11
0
    def createTopLeftGroupBox(self):
        self.topLeftGroupBox = QGroupBox("Group 1")

        radioButton1 = QRadioButton("Radio button 1")
        radioButton2 = QRadioButton("Radio button 2")
        radioButton3 = QRadioButton("Radio button 3")
        radioButton1.setChecked(True)

        checkBox = QCheckBox("Tri-state check box")
        checkBox.setTristate(True)
        checkBox.setCheckState(Qt.PartiallyChecked)

        layout = QVBoxLayout()
        layout.addWidget(radioButton1)
        layout.addWidget(radioButton2)
        layout.addWidget(radioButton3)
        layout.addWidget(checkBox)
        layout.addStretch(1)
        self.topLeftGroupBox.setLayout(layout)
Пример #12
0
    def _dock_add_radio_buttons(self,
                                value,
                                rng,
                                callback,
                                *,
                                vertical=True,
                                layout=None):
        layout = self._dock_layout if layout is None else layout
        group_layout = QVBoxLayout() if vertical else QHBoxLayout()
        group = QButtonGroup()
        for val in rng:
            button = QRadioButton(val)
            if val == value:
                button.setChecked(True)
            group.addButton(button)
            self._layout_add_widget(group_layout, button)

        def func(button):
            callback(button.text())

        group.buttonClicked.connect(func)
        self._layout_add_widget(layout, group_layout)
        return _QtWidgetList(group)
Пример #13
0
 def create_control_panel(self):
     # Create control panel
     # +/- range
     cntrl_layout = QHBoxLayout()
     cntrl_layout.addWidget(QLabel("+/-"))
     self.range_edit = QLineEdit("{:.2f}".format(YRANGE))
     self.range_edit.editingFinished.connect(
         self.on_range_edit_editingFinished)
     cntrl_layout.addWidget(self.range_edit)
     # buttons for audio monitoring
     cntrl_layout.addStretch(1)
     cntrl_layout.addWidget(QLabel("Monitor: "))
     monitor_group = QButtonGroup(parent=self)
     none_button = QRadioButton("None")
     none_button.setChecked(True)
     monitor_group.addButton(none_button)
     monitor_group.setId(none_button, 0)
     cntrl_layout.addWidget(none_button)
     for chan_ix in range(len(self.group_info)):
         new_button = QRadioButton(self.group_info[chan_ix]['label'])
         monitor_group.addButton(new_button)
         monitor_group.setId(new_button, chan_ix + 1)
         cntrl_layout.addWidget(new_button)
     monitor_group.buttonClicked[int].connect(self.on_monitor_group_clicked)
     # Checkbox for HP filter
     filter_checkbox = QCheckBox("HP")
     filter_checkbox.stateChanged.connect(self.on_hp_filter_changed)
     filter_checkbox.setChecked(True)
     cntrl_layout.addWidget(filter_checkbox)
     # Checkbox for Comb filter
     filter_checkbox = QCheckBox("LN")
     filter_checkbox.setEnabled(False)
     filter_checkbox.stateChanged.connect(self.on_ln_filter_changed)
     filter_checkbox.setChecked(False)
     cntrl_layout.addWidget(filter_checkbox)
     # Finish
     self.layout().addLayout(cntrl_layout)
Пример #14
0
class FindOptions(QWidget):
    """Find widget with options"""
    REGEX_INVALID = "background-color:rgb(255, 175, 90);"
    find = Signal()
    stop = Signal()
    redirect_stdio = Signal(bool)

    def __init__(self, parent, search_text, search_text_regexp, search_path,
                 exclude, exclude_idx, exclude_regexp, supported_encodings,
                 in_python_path, more_options):
        QWidget.__init__(self, parent)

        if search_path is None:
            search_path = getcwd()

        self.path = ''
        self.project_path = None
        self.file_path = None

        if not isinstance(search_text, (list, tuple)):
            search_text = [search_text]
        if not isinstance(search_path, (list, tuple)):
            search_path = [search_path]
        if not isinstance(exclude, (list, tuple)):
            exclude = [exclude]

        self.supported_encodings = supported_encodings

        # Layout 1
        hlayout1 = QHBoxLayout()
        self.search_text = PatternComboBox(self, search_text,
                                           _("Search pattern"))
        self.edit_regexp = create_toolbutton(self,
                                             icon=ima.icon('advanced'),
                                             tip=_('Regular expression'))
        self.edit_regexp.setCheckable(True)
        self.edit_regexp.setChecked(search_text_regexp)
        self.more_widgets = ()
        self.more_options = create_toolbutton(self,
                                              toggled=self.toggle_more_options)
        self.more_options.setCheckable(True)
        self.more_options.setChecked(more_options)

        self.ok_button = create_toolbutton(self,
                                           text=_("Search"),
                                           icon=ima.icon('find'),
                                           triggered=lambda: self.find.emit(),
                                           tip=_("Start search"),
                                           text_beside_icon=True)
        self.ok_button.clicked.connect(self.update_combos)
        self.stop_button = create_toolbutton(
            self,
            text=_("Stop"),
            icon=ima.icon('editclear'),
            triggered=lambda: self.stop.emit(),
            tip=_("Stop search"),
            text_beside_icon=True)
        self.stop_button.setEnabled(False)
        for widget in [
                self.search_text, self.edit_regexp, self.ok_button,
                self.stop_button, self.more_options
        ]:
            hlayout1.addWidget(widget)

        # Layout 2
        hlayout2 = QHBoxLayout()
        self.exclude_pattern = PatternComboBox(self, exclude,
                                               _("Excluded filenames pattern"))
        if exclude_idx is not None and exclude_idx >= 0 \
           and exclude_idx < self.exclude_pattern.count():
            self.exclude_pattern.setCurrentIndex(exclude_idx)
        self.exclude_regexp = create_toolbutton(self,
                                                icon=ima.icon('advanced'),
                                                tip=_('Regular expression'))
        self.exclude_regexp.setCheckable(True)
        self.exclude_regexp.setChecked(exclude_regexp)
        exclude_label = QLabel(_("Exclude:"))
        exclude_label.setBuddy(self.exclude_pattern)
        for widget in [
                exclude_label, self.exclude_pattern, self.exclude_regexp
        ]:
            hlayout2.addWidget(widget)

        # Layout 3
        hlayout3 = QHBoxLayout()

        self.global_path_search = QRadioButton(
            _("Current working "
              "directory"), self)
        self.global_path_search.setChecked(True)
        self.global_path_search.setToolTip(
            _("Search in all files and "
              "directories present on the"
              "current Spyder path"))

        self.project_search = QRadioButton(_("Project"), self)
        self.project_search.setToolTip(
            _("Search in all files and "
              "directories present on the"
              "current project path (If opened)"))

        self.project_search.setEnabled(False)

        self.file_search = QRadioButton(_("File"), self)
        self.file_search.setToolTip(_("Search in current opened file"))

        for wid in [
                self.global_path_search, self.project_search, self.file_search
        ]:
            hlayout3.addWidget(wid)

        hlayout3.addStretch(1)

        self.search_text.valid.connect(lambda valid: self.find.emit())
        self.exclude_pattern.valid.connect(lambda valid: self.find.emit())

        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.addLayout(hlayout1)
        vlayout.addLayout(hlayout2)
        vlayout.addLayout(hlayout3)
        self.more_widgets = (hlayout2, )
        self.toggle_more_options(more_options)
        self.setLayout(vlayout)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)

    @Slot(bool)
    def toggle_more_options(self, state):
        for layout in self.more_widgets:
            for index in range(layout.count()):
                if state and self.isVisible() or not state:
                    layout.itemAt(index).widget().setVisible(state)
        if state:
            icon = ima.icon('options_less')
            tip = _('Hide advanced options')
        else:
            icon = ima.icon('options_more')
            tip = _('Show advanced options')
        self.more_options.setIcon(icon)
        self.more_options.setToolTip(tip)

    def update_combos(self):
        self.search_text.lineEdit().returnPressed.emit()
        self.exclude_pattern.lineEdit().returnPressed.emit()

    def set_search_text(self, text):
        if text:
            self.search_text.add_text(text)
            self.search_text.lineEdit().selectAll()
        self.search_text.setFocus()

    def get_options(self, all=False):
        # Getting options
        self.search_text.lineEdit().setStyleSheet("")
        self.exclude_pattern.lineEdit().setStyleSheet("")

        utext = to_text_string(self.search_text.currentText())
        if not utext:
            return
        try:
            texts = [(utext.encode('utf-8'), 'utf-8')]
        except UnicodeEncodeError:
            texts = []
            for enc in self.supported_encodings:
                try:
                    texts.append((utext.encode(enc), enc))
                except UnicodeDecodeError:
                    pass
        text_re = self.edit_regexp.isChecked()
        exclude = to_text_string(self.exclude_pattern.currentText())
        exclude_re = self.exclude_regexp.isChecked()
        python_path = False

        global_path_search = self.global_path_search.isChecked()
        project_search = self.project_search.isChecked()
        file_search = self.file_search.isChecked()

        if global_path_search:
            path = self.path
        elif project_search:
            path = self.project_path
        else:
            path = self.file_path

        # Finding text occurrences
        if not exclude_re:
            exclude = fnmatch.translate(exclude)
        else:
            try:
                exclude = re.compile(exclude)
            except Exception:
                exclude_edit = self.exclude_pattern.lineEdit()
                exclude_edit.setStyleSheet(self.REGEX_INVALID)
                return None

        if text_re:
            try:
                texts = [(re.compile(x[0]), x[1]) for x in texts]
            except Exception:
                self.search_text.lineEdit().setStyleSheet(self.REGEX_INVALID)
                return None

        if all:
            search_text = [
                to_text_string(self.search_text.itemText(index))
                for index in range(self.search_text.count())
            ]
            exclude = [
                to_text_string(self.exclude_pattern.itemText(index))
                for index in range(self.exclude_pattern.count())
            ]
            exclude_idx = self.exclude_pattern.currentIndex()
            more_options = self.more_options.isChecked()
            return (search_text, text_re, [], exclude, exclude_idx, exclude_re,
                    python_path, more_options)
        else:
            return (path, file_search, exclude, texts, text_re)

    @Slot()
    def select_directory(self):
        """Select directory"""
        self.redirect_stdio.emit(False)
        directory = getexistingdirectory(self, _("Select directory"),
                                         self.dir_combo.currentText())
        if directory:
            self.set_directory(directory)
        self.redirect_stdio.emit(True)

    def set_directory(self, directory):
        self.path = to_text_string(osp.abspath(to_text_string(directory)))

    def set_project_path(self, path):
        self.project_path = to_text_string(osp.abspath(to_text_string(path)))
        self.project_search.setEnabled(True)

    def disable_project_search(self):
        self.project_search.setEnabled(False)
        self.project_search.setChecked(False)
        self.project_path = None

    def set_file_path(self, path):
        self.file_path = path

    def keyPressEvent(self, event):
        """Reimplemented to handle key events"""
        ctrl = event.modifiers() & Qt.ControlModifier
        shift = event.modifiers() & Qt.ShiftModifier
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            self.find.emit()
        elif event.key() == Qt.Key_F and ctrl and shift:
            # Toggle find widgets
            self.parent().toggle_visibility.emit(not self.isVisible())
        else:
            QWidget.keyPressEvent(self, event)
Пример #15
0
    def __init__(self, parent, text):
        QWidget.__init__(self, parent)

        self.text_editor = QTextEdit(self)
        self.text_editor.setText(text)
        self.text_editor.setReadOnly(True)

        # Type frame
        type_layout = QHBoxLayout()
        type_label = QLabel(_("Import as"))
        type_layout.addWidget(type_label)
        data_btn = QRadioButton(_("data"))
        data_btn.setChecked(True)
        self._as_data = True
        type_layout.addWidget(data_btn)
        code_btn = QRadioButton(_("code"))
        self._as_code = False
        type_layout.addWidget(code_btn)
        txt_btn = QRadioButton(_("text"))
        type_layout.addWidget(txt_btn)

        h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                               QSizePolicy.Minimum)
        type_layout.addItem(h_spacer)
        type_frame = QFrame()
        type_frame.setLayout(type_layout)

        # Opts frame
        grid_layout = QGridLayout()
        grid_layout.setSpacing(0)

        col_label = QLabel(_("Column separator:"))
        grid_layout.addWidget(col_label, 0, 0)
        col_w = QWidget()
        col_btn_layout = QHBoxLayout()
        self.tab_btn = QRadioButton(_("Tab"))
        self.tab_btn.setChecked(False)
        col_btn_layout.addWidget(self.tab_btn)
        self.ws_btn = QRadioButton(_("Whitespace"))
        self.ws_btn.setChecked(False)
        col_btn_layout.addWidget(self.ws_btn)
        other_btn_col = QRadioButton(_("other"))
        other_btn_col.setChecked(True)
        col_btn_layout.addWidget(other_btn_col)
        col_w.setLayout(col_btn_layout)
        grid_layout.addWidget(col_w, 0, 1)
        self.line_edt = QLineEdit(",")
        self.line_edt.setMaximumWidth(30)
        self.line_edt.setEnabled(True)
        other_btn_col.toggled.connect(self.line_edt.setEnabled)
        grid_layout.addWidget(self.line_edt, 0, 2)

        row_label = QLabel(_("Row separator:"))
        grid_layout.addWidget(row_label, 1, 0)
        row_w = QWidget()
        row_btn_layout = QHBoxLayout()
        self.eol_btn = QRadioButton(_("EOL"))
        self.eol_btn.setChecked(True)
        row_btn_layout.addWidget(self.eol_btn)
        other_btn_row = QRadioButton(_("other"))
        row_btn_layout.addWidget(other_btn_row)
        row_w.setLayout(row_btn_layout)
        grid_layout.addWidget(row_w, 1, 1)
        self.line_edt_row = QLineEdit(";")
        self.line_edt_row.setMaximumWidth(30)
        self.line_edt_row.setEnabled(False)
        other_btn_row.toggled.connect(self.line_edt_row.setEnabled)
        grid_layout.addWidget(self.line_edt_row, 1, 2)

        grid_layout.setRowMinimumHeight(2, 15)

        other_group = QGroupBox(_("Additional options"))
        other_layout = QGridLayout()
        other_group.setLayout(other_layout)

        skiprows_label = QLabel(_("Skip rows:"))
        other_layout.addWidget(skiprows_label, 0, 0)
        self.skiprows_edt = QLineEdit('0')
        self.skiprows_edt.setMaximumWidth(30)
        intvalid = QIntValidator(0, len(to_text_string(text).splitlines()),
                                 self.skiprows_edt)
        self.skiprows_edt.setValidator(intvalid)
        other_layout.addWidget(self.skiprows_edt, 0, 1)

        other_layout.setColumnMinimumWidth(2, 5)

        comments_label = QLabel(_("Comments:"))
        other_layout.addWidget(comments_label, 0, 3)
        self.comments_edt = QLineEdit('#')
        self.comments_edt.setMaximumWidth(30)
        other_layout.addWidget(self.comments_edt, 0, 4)

        self.trnsp_box = QCheckBox(_("Transpose"))
        #self.trnsp_box.setEnabled(False)
        other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0)

        grid_layout.addWidget(other_group, 3, 0, 2, 0)

        opts_frame = QFrame()
        opts_frame.setLayout(grid_layout)

        data_btn.toggled.connect(opts_frame.setEnabled)
        data_btn.toggled.connect(self.set_as_data)
        code_btn.toggled.connect(self.set_as_code)
        #        self.connect(txt_btn, SIGNAL("toggled(bool)"),
        #                     self, SLOT("is_text(bool)"))

        # Final layout
        layout = QVBoxLayout()
        layout.addWidget(type_frame)
        layout.addWidget(self.text_editor)
        layout.addWidget(opts_frame)
        self.setLayout(layout)
Пример #16
0
    def __init__(self, import_dict, local_dict, viewer, parent=None):
        """
        :type import_dict: dict[str, object]
        :type local_dict: dict[str, object]
        :param import_dict:
        :param local_dict:
        :param viewer:
        """
        super().__init__(parent=parent)
        self.setWindowTitle("Import")
        self.viewer = viewer()
        self.local_viewer = viewer()
        self.import_dict = import_dict
        self.local_dict = local_dict
        conflicts = set(local_dict.keys()) & set(import_dict.keys())
        # print(conflicts)

        self.list_view = QTreeWidget()
        self.list_view.setColumnCount(4)
        self.radio_group_list = []
        self.checked_num = len(import_dict)

        def rename_func(ob_name, new_name_field, rename_radio):
            end_reg = re.compile(r"(.*) \((\d+)\)$")

            def in_func():
                if not rename_radio.isChecked() or str(new_name_field.text()).strip() != "":
                    return

                match = end_reg.match(ob_name)
                if match:
                    new_name_format = match.group(1) + " ({})"
                    i = int(match.group(2)) + 1
                else:
                    new_name_format = ob_name + " ({})"
                    i = 1
                while new_name_format.format(i) in self.local_dict:
                    i += 1
                new_name_field.setText(new_name_format.format(i))

            return in_func

        def block_import(radio_btn, name_field):
            def inner_func():
                text = str(name_field.text()).strip()
                if text == "" and radio_btn.isChecked():
                    self.import_btn.setDisabled(True)
                else:
                    self.import_btn.setEnabled(True)

            return inner_func

        for name in sorted(import_dict.keys()):
            item = QTreeWidgetItem()
            item.setText(0, name)
            # noinspection PyTypeChecker
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(0, Qt.Checked)
            self.list_view.addTopLevelItem(item)
            if name in conflicts:
                group = QButtonGroup()
                overwrite = QRadioButton("Overwrite")
                overwrite.setChecked(True)
                rename = QRadioButton("Rename")
                new_name = QLineEdit()
                new_name.textChanged.connect(block_import(rename, new_name))
                rename.toggled.connect(block_import(rename, new_name))
                overwrite.toggled.connect(block_import(rename, new_name))

                rename.toggled.connect(rename_func(name, new_name, rename))
                group.addButton(overwrite)
                group.addButton(rename)
                self.radio_group_list.append(group)
                self.list_view.setItemWidget(item, 1, overwrite)
                self.list_view.setItemWidget(item, 2, rename)
                self.list_view.setItemWidget(item, 3, new_name)

        self.import_btn = QPushButton("Import")
        self.cancel_btn = QPushButton("Cancel")
        self.check_btn = QPushButton("Check all")
        self.uncheck_btn = QPushButton("Uncheck all")

        self.cancel_btn.clicked.connect(self.close)
        self.import_btn.clicked.connect(self.accept)
        self.check_btn.clicked.connect(self.check_all)
        self.uncheck_btn.clicked.connect(self.uncheck_all)

        self.list_view.itemSelectionChanged.connect(self.preview)
        self.list_view.itemChanged.connect(self.checked_change)

        layout = QVBoxLayout()
        info_layout = QHBoxLayout()
        info_layout.addWidget(self.list_view, 2)
        v1_lay = QVBoxLayout()
        v1_lay.addWidget(QLabel("Import:"))
        v1_lay.addWidget(self.viewer)
        info_layout.addLayout(v1_lay, 1)
        # info_layout.addWidget(self.local_viewer, 1)
        v2_lay = QVBoxLayout()
        v2_lay.addWidget(QLabel("Local:"))
        v2_lay.addWidget(self.local_viewer)
        info_layout.addLayout(v2_lay, 1)
        layout.addLayout(info_layout)
        btn_layout = QHBoxLayout()
        btn_layout.addWidget(self.check_btn)
        btn_layout.addWidget(self.uncheck_btn)
        btn_layout.addStretch()
        btn_layout.addWidget(self.import_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)
        self.setLayout(layout)
Пример #17
0
class LegendPropertiesWindow(PyDialog):
    """
    +-------------------+
    | Legend Properties |
    +-----------------------+
    | Title  ______ Default |
    | Min    ______ Default |
    | Max    ______ Default |
    | Format ______ Default |
    | Scale  ______ Default |
    | Phase  ______ Default |
    | Number of Colors ____ |
    | Number of Labels ____ |
    | Label Size       ____ | (TODO)
    | ColorMap         ____ | (TODO)
    |                       |
    | x Min/Max (Blue->Red) |
    | o Max/Min (Red->Blue) |
    |                       |
    | x Vertical/Horizontal |
    | x Show/Hide           |
    |                       |
    |        Animate        |
    |    Apply OK Cancel    |
    +-----------------------+
    """
    def __init__(self, data, win_parent=None, show_animation_button=True):
        PyDialog.__init__(self, data, win_parent)
        self.is_gui = win_parent is not None

        self._updated_legend = False
        self.external_call = True

        #if win_parent is None:
        self._icase_fringe = data['icase_fringe']
        self._icase_disp = data['icase_disp']
        self._icase_vector = data['icase_vector']
        #else:
        #self._icase_fringe = data['icase']
        #self._icase_disp = data['icase']
        #self._icase_vector = data['icase']

        self._default_icase_fringe = self._icase_fringe
        self._default_icase_disp = self._icase_disp
        self._default_icase_vector = self._icase_vector
        #print('*icase_fringe=%s icase_disp=%s icase_vector=%s' % (
        #self._default_icase_fringe, self._default_icase_disp, self._default_icase_vector))

        self._default_title = data['title']
        self._default_min = data['min_value']
        self._default_max = data['max_value']

        self._default_scale = data['default_scale']
        self._scale = data['scale']

        #if win_parent is None:
        self._default_arrow_scale = data['default_arrow_scale']
        self._arrow_scale = data['arrow_scale']
        #else:
        #self._default_arrow_scale = data['default_scale']
        #self._arrow_scale = data['scale']

        self._default_phase = data['default_phase']
        self._phase = data['phase']

        self._default_format = data['default_format']
        self._format = data['format']

        self._default_labelsize = data['default_labelsize']
        self._labelsize = data['labelsize']

        self._default_nlabels = data['default_nlabels']
        self._nlabels = data['nlabels']

        self._default_ncolors = data['default_ncolors']
        self._ncolors = data['ncolors']

        self._default_colormap = data['default_colormap']
        self._colormap = data['colormap']

        self._default_is_low_to_high = data['is_low_to_high']

        self._default_is_discrete = data['is_discrete']
        self._default_is_horizontal = data['is_horizontal']
        self._default_is_shown = data['is_shown']
        self._is_fringe = data['is_fringe']

        self._update_defaults_to_blank()

        self.setWindowTitle('Legend Properties')
        self.create_widgets(show_animation_button=show_animation_button)
        self.create_layout()
        self.set_connections()
        self.set_font_size(data['font_size'])

    def _update_defaults_to_blank(self):
        """Changes the default (None) to a blank string"""
        if self._default_colormap is None:
            self._default_colormap = 'jet'
        if self._default_labelsize is None:
            self._default_labelsize = ''
        if self._default_ncolors is None:
            self._default_ncolors = ''
        if self._default_nlabels is None:
            self._default_nlabels = ''

        if self._colormap is None:
            self._colormap = 'jet'
        if self._labelsize is None:
            self._labelsize = ''
        if self._ncolors is None:
            self._ncolors = ''
        if self._nlabels is None:
            self._nlabels = ''

    def update_legend(self,
                      icase_fringe,
                      icase_disp,
                      icase_vector,
                      title,
                      min_value,
                      max_value,
                      data_format,
                      nlabels,
                      labelsize,
                      ncolors,
                      colormap,
                      is_fringe,
                      scale,
                      phase,
                      arrow_scale,
                      default_title,
                      default_min_value,
                      default_max_value,
                      default_data_format,
                      default_nlabels,
                      default_labelsize,
                      default_ncolors,
                      default_colormap,
                      default_scale,
                      default_phase,
                      default_arrow_scale,
                      font_size=8,
                      external_call=False):
        """
        We need to update the legend if there's been a result change request
        """
        self.external_call = external_call
        self.set_font_size(font_size)

        update_fringe = False
        update_disp = False
        update_vector = False
        #print('update_legend; fringe=%s disp=%s vector=%s' % (
        #icase_fringe, icase_disp, icase_vector))
        #print('update_legend; default: fringe=%s disp=%s vector=%s' % (
        #    self._default_icase_fringe, self._default_icase_disp, self._default_icase_vector))
        if icase_fringe != self._default_icase_fringe:
            self._icase_fringe = icase_fringe
            self._default_icase_fringe = icase_fringe
            update_fringe = True

        #is_fringe = icase_fringe is not None
        is_disp = icase_disp is not None
        is_vector = icase_vector is not None

        if icase_disp != self._default_icase_disp:
            assert isinstance(
                scale, float_types), 'scale=%r type=%s' % (scale, type(scale))
            #assert isinstance(default_scale, float), 'default_scale=%r' % default_scale
            self._icase_disp = icase_disp
            self._default_icase_disp = icase_disp
            self._default_scale = default_scale
            self._default_phase = default_phase
            update_disp = True

        if icase_vector != self._default_icase_vector:
            assert isinstance(
                arrow_scale,
                float_types), 'arrow_scale=%r type=%s' % (arrow_scale,
                                                          type(scale))
            #assert isinstance(default_arrow_scale, float), 'default_arrow_scale=%r' % default_arrow_scale
            self._icase_vector = icase_vector
            self._default_icase_vector = icase_vector
            self._default_arrow_scale = default_arrow_scale
            update_vector = True

        #print('*update_legend; default: fringe=%s disp=%s vector=%s' % (
        #    self._default_icase_fringe, self._default_icase_disp, self._default_icase_vector))
        #print('update_fringe=%s update_disp=%s update_vector=%s' % (
        #    update_fringe, update_disp, update_vector))
        #print('is_fringe=%s is_disp=%s is_vector=%s' % (
        #    is_fringe, is_disp, is_vector))

        if update_fringe:
            self._icase_fringe = icase_fringe
            self._default_icase_fringe = icase_fringe

            self._default_title = default_title
            self._default_min = default_min_value
            self._default_max = default_max_value
            self._default_format = default_data_format
            #self._default_is_low_to_high = is_low_to_high
            self._default_is_discrete = True
            #self._default_is_horizontal = is_horizontal_scalar_bar
            self._default_nlabels = default_nlabels
            self._default_labelsize = default_labelsize
            self._default_ncolors = default_ncolors
            self._default_colormap = default_colormap
            self._is_fringe = is_fringe

            if colormap is None:
                colormap = 'jet'
            if labelsize is None:
                labelsize = ''
            if ncolors is None:
                ncolors = ''
            if nlabels is None:
                nlabels = ''

        self._update_defaults_to_blank()

        #-----------------------------------------------------------------------
        update = update_fringe or update_disp or update_vector
        if update:
            #self.scale_label.setEnabled(is_disp)
            #self.scale_edit.setEnabled(is_disp)
            #self.scale_button.setEnabled(is_disp)
            self.scale_label.setVisible(is_disp)
            self.scale_edit.setVisible(is_disp)
            self.scale_button.setVisible(is_disp)

            is_complex_disp = self._default_phase is not None
            self.phase_label.setVisible(is_complex_disp)
            self.phase_edit.setVisible(is_complex_disp)
            self.phase_button.setVisible(is_complex_disp)

            self._scale = set_cell_to_blank_if_value_is_none(
                self.scale_edit, scale)
            self._phase = set_cell_to_blank_if_value_is_none(
                self.phase_edit, phase)

        if self._default_icase_disp is None:  # or self._default_icase_vector is None:
            self.animate_button.setEnabled(False)
            self.animate_button.setToolTip(ANIMATE_TOOLTIP_OFF)
        else:
            self.animate_button.setEnabled(True)
            self.animate_button.setToolTip(ANIMATE_TOOLTIP_ON)

        #-----------------------------------------------------------------------
        if update:
            #self.arrow_scale_label.setEnabled(is_vector)
            #self.arrow_scale_edit.setEnabled(is_vector)
            #self.arrow_scale_button.setEnabled(is_vector)
            self.arrow_scale_label.setVisible(is_vector)
            self.arrow_scale_edit.setVisible(is_vector)
            self.arrow_scale_button.setVisible(is_vector)
            self._arrow_scale = set_cell_to_blank_if_value_is_none(
                self.arrow_scale_edit, arrow_scale)

        #-----------------------------------------------------------------------
        if update_fringe:
            #self.on_default_title()
            #self.on_default_min()
            #self.on_default_max()
            #self.on_default_format()
            #self.on_default_scale()
            # reset defaults
            self.title_edit.setText(title)
            self.title_edit.setStyleSheet("QLineEdit{background: white;}")

            self.min_edit.setText(str(min_value))
            self.min_edit.setStyleSheet("QLineEdit{background: white;}")

            self.max_edit.setText(str(max_value))
            self.max_edit.setStyleSheet("QLineEdit{background: white;}")

            self.format_edit.setText(str(data_format))
            self.format_edit.setStyleSheet("QLineEdit{background: white;}")

            self.nlabels_edit.setText(str(nlabels))
            self.nlabels_edit.setStyleSheet("QLineEdit{background: white;}")

            self.labelsize_edit.setText(str(labelsize))
            self.labelsize_edit.setStyleSheet("QLineEdit{background: white;}")

            self.ncolors_edit.setText(str(ncolors))
            self.ncolors_edit.setStyleSheet("QLineEdit{background: white;}")

            self.colormap_edit.setCurrentIndex(
                colormap_keys.index(str(colormap)))

            self._set_legend_fringe(self._is_fringe)

        if update:
            self.on_apply()
            self.external_call = True
        #print('---------------------------------')

    def clear_disp(self):
        """hides dispacement blocks"""
        self._icase_disp = None
        self._default_icase_disp = None
        self.scale_label.setVisible(False)
        self.scale_edit.setVisible(False)
        self.scale_button.setVisible(False)
        self.phase_label.setVisible(False)
        self.phase_edit.setVisible(False)
        self.phase_button.setVisible(False)

    def clear_vector(self):
        """hides vector blocks"""
        self._icase_vector = None
        self._default_icase_vector = None
        self.arrow_scale_label.setVisible(False)
        self.arrow_scale_edit.setVisible(False)
        self.arrow_scale_button.setVisible(False)

    def clear(self):
        """hides fringe, displacemnt, and vector blocks"""
        self._icase_fringe = None
        self._default_icase_fringe = None
        self._set_legend_fringe(False)
        self.clear_disp()
        self.clear_vector()

    def _set_legend_fringe(self, is_fringe):
        """
        Show/hide buttons if we dont have a result.  This is used for normals.
        A result can still exist (i.e., icase_fringe is not None).
        """
        # lots of hacking for the Normal vectors
        self._is_fringe = is_fringe
        #self._default_icase_fringe = None
        enable = True
        if not is_fringe:
            enable = False

        show_title = self._icase_fringe is not None
        self.title_label.setVisible(show_title)
        self.title_edit.setVisible(show_title)
        self.title_button.setVisible(show_title)

        self.max_label.setVisible(enable)
        self.min_label.setVisible(enable)
        self.max_edit.setVisible(enable)
        self.min_edit.setVisible(enable)
        self.max_button.setVisible(enable)
        self.min_button.setVisible(enable)

        self.show_radio.setVisible(enable)
        self.hide_radio.setVisible(enable)
        self.low_to_high_radio.setVisible(enable)
        self.high_to_low_radio.setVisible(enable)

        self.format_label.setVisible(enable)
        self.format_edit.setVisible(enable)
        self.format_edit.setVisible(enable)
        self.format_button.setVisible(enable)

        self.nlabels_label.setVisible(enable)
        self.nlabels_edit.setVisible(enable)
        self.nlabels_button.setVisible(enable)

        self.ncolors_label.setVisible(enable)
        self.ncolors_edit.setVisible(enable)
        self.ncolors_button.setVisible(enable)

        self.grid2_title.setVisible(enable)
        self.vertical_radio.setVisible(enable)
        self.horizontal_radio.setVisible(enable)

        self.colormap_label.setVisible(enable)
        self.colormap_edit.setVisible(enable)
        self.colormap_button.setVisible(enable)

    def create_widgets(self, show_animation_button=True):
        """creates the menu objects"""
        # title
        self.title_label = QLabel("Title:")
        self.title_edit = QLineEdit(str(self._default_title))
        self.title_button = QPushButton("Default")

        # Min
        self.min_label = QLabel("Min:")
        self.min_edit = QLineEdit(str(self._default_min))
        self.min_button = QPushButton("Default")

        # Max
        self.max_label = QLabel("Max:")
        self.max_edit = QLineEdit(str(self._default_max))
        self.max_button = QPushButton("Default")

        #---------------------------------------
        # Format
        self.format_label = QLabel("Format (e.g. %.3f, %g, %.6e):")
        self.format_edit = QLineEdit(str(self._format))
        self.format_button = QPushButton("Default")

        #---------------------------------------
        # Scale
        self.scale_label = QLabel("True Scale:")
        self.scale_edit = QLineEdit(str(self._scale))
        self.scale_button = QPushButton("Default")
        if self._icase_disp is None:
            self.scale_label.setVisible(False)
            self.scale_edit.setVisible(False)
            self.scale_button.setVisible(False)

        # Phase
        self.phase_label = QLabel("Phase (deg):")
        self.phase_edit = QLineEdit(str(self._phase))
        self.phase_button = QPushButton("Default")
        if self._icase_disp is None or self._default_phase is None:
            self.phase_label.setVisible(False)
            self.phase_edit.setVisible(False)
            self.phase_button.setVisible(False)
            self.phase_edit.setText('0.0')

        #---------------------------------------
        self.arrow_scale_label = QLabel("Arrow Scale:")
        self.arrow_scale_edit = QLineEdit(str(self._arrow_scale))
        self.arrow_scale_button = QPushButton("Default")
        if self._icase_vector is None:
            self.arrow_scale_label.setVisible(False)
            self.arrow_scale_edit.setVisible(False)
            self.arrow_scale_button.setVisible(False)

        #tip = QtGui.QToolTip()
        #tip.setTe
        #self.format_edit.toolTip(tip)

        #---------------------------------------
        # nlabels
        self.nlabels_label = QLabel("Number of Labels:")
        self.nlabels_edit = QLineEdit(str(self._nlabels))
        self.nlabels_button = QPushButton("Default")

        self.labelsize_label = QLabel("Label Size:")
        self.labelsize_edit = QLineEdit(str(self._labelsize))
        self.labelsize_button = QPushButton("Default")

        self.ncolors_label = QLabel("Number of Colors:")
        self.ncolors_edit = QLineEdit(str(self._ncolors))
        self.ncolors_button = QPushButton("Default")

        self.colormap_label = QLabel("Color Map:")
        self.colormap_edit = QComboBox(self)
        self.colormap_button = QPushButton("Default")
        for key in colormap_keys:
            self.colormap_edit.addItem(key)
        self.colormap_edit.setCurrentIndex(colormap_keys.index(self._colormap))

        # --------------------------------------------------------------
        # the header
        self.grid2_title = QLabel("Color Scale:")

        # red/blue or blue/red
        self.low_to_high_radio = QRadioButton('Low -> High')
        self.high_to_low_radio = QRadioButton('High -> Low')
        widget = QWidget(self)
        low_to_high_group = QButtonGroup(widget)
        low_to_high_group.addButton(self.low_to_high_radio)
        low_to_high_group.addButton(self.high_to_low_radio)
        self.low_to_high_radio.setChecked(self._default_is_low_to_high)
        self.high_to_low_radio.setChecked(not self._default_is_low_to_high)

        # horizontal / vertical
        self.horizontal_radio = QRadioButton("Horizontal")
        self.vertical_radio = QRadioButton("Vertical")
        widget = QWidget(self)
        horizontal_vertical_group = QButtonGroup(widget)
        horizontal_vertical_group.addButton(self.horizontal_radio)
        horizontal_vertical_group.addButton(self.vertical_radio)
        self.horizontal_radio.setChecked(self._default_is_horizontal)
        self.vertical_radio.setChecked(not self._default_is_horizontal)

        # on / off
        self.show_radio = QRadioButton("Show")
        self.hide_radio = QRadioButton("Hide")
        widget = QWidget(self)
        show_hide_group = QButtonGroup(widget)
        show_hide_group.addButton(self.show_radio)
        show_hide_group.addButton(self.hide_radio)
        self.show_radio.setChecked(self._default_is_shown)
        self.hide_radio.setChecked(not self._default_is_shown)

        # --------------------------------------------------------------

        if self._icase_fringe is None:
            self.title_label.setVisible(False)
            self.title_edit.setVisible(False)
            self.title_button.setVisible(False)

        if not self._is_fringe:
            self.max_label.hide()
            self.min_label.hide()
            self.max_edit.hide()
            self.min_edit.hide()
            self.max_button.hide()
            self.min_button.hide()

            self.format_label.hide()
            self.format_edit.hide()
            self.format_button.hide()

            self.nlabels_label.hide()
            self.nlabels_edit.hide()
            self.nlabels_button.hide()

            self.ncolors_label.hide()
            self.ncolors_edit.hide()
            self.ncolors_button.hide()

            self.grid2_title.hide()
            self.vertical_radio.hide()
            self.horizontal_radio.hide()
            self.show_radio.hide()
            self.hide_radio.hide()
            self.low_to_high_radio.hide()
            self.high_to_low_radio.hide()

            self.colormap_label.hide()
            self.colormap_edit.hide()
            self.colormap_button.hide()

        self.animate_button = QPushButton('Create Animation')
        self.animate_button.setVisible(show_animation_button)
        #self.advanced_button = QPushButton('Advanced')

        if self._default_icase_disp is None:  # or self._default_icase_vector is None:
            self.animate_button.setEnabled(False)
            self.animate_button.setToolTip(ANIMATE_TOOLTIP_OFF)
        else:
            self.animate_button.setEnabled(True)
            self.animate_button.setToolTip(ANIMATE_TOOLTIP_ON)

        # closing
        self.apply_button = QPushButton("Apply")
        self.ok_button = QPushButton("OK")
        self.cancel_button = QPushButton("Cancel")

    def create_layout(self):
        """displays the menu objects"""
        grid = QGridLayout()
        grid.addWidget(self.title_label, 0, 0)
        grid.addWidget(self.title_edit, 0, 1)
        grid.addWidget(self.title_button, 0, 2)

        grid.addWidget(self.min_label, 1, 0)
        grid.addWidget(self.min_edit, 1, 1)
        grid.addWidget(self.min_button, 1, 2)

        grid.addWidget(self.max_label, 2, 0)
        grid.addWidget(self.max_edit, 2, 1)
        grid.addWidget(self.max_button, 2, 2)

        grid.addWidget(self.format_label, 3, 0)
        grid.addWidget(self.format_edit, 3, 1)
        grid.addWidget(self.format_button, 3, 2)

        grid.addWidget(self.scale_label, 4, 0)
        grid.addWidget(self.scale_edit, 4, 1)
        grid.addWidget(self.scale_button, 4, 2)

        grid.addWidget(self.phase_label, 6, 0)
        grid.addWidget(self.phase_edit, 6, 1)
        grid.addWidget(self.phase_button, 6, 2)

        grid.addWidget(self.arrow_scale_label, 5, 0)
        grid.addWidget(self.arrow_scale_edit, 5, 1)
        grid.addWidget(self.arrow_scale_button, 5, 2)

        grid.addWidget(self.nlabels_label, 7, 0)
        grid.addWidget(self.nlabels_edit, 7, 1)
        grid.addWidget(self.nlabels_button, 7, 2)

        #grid.addWidget(self.labelsize_label, 6, 0)
        #grid.addWidget(self.labelsize_edit, 6, 1)
        #grid.addWidget(self.labelsize_button, 6, 2)

        grid.addWidget(self.ncolors_label, 8, 0)
        grid.addWidget(self.ncolors_edit, 8, 1)
        grid.addWidget(self.ncolors_button, 8, 2)

        grid.addWidget(self.colormap_label, 9, 0)
        grid.addWidget(self.colormap_edit, 9, 1)
        grid.addWidget(self.colormap_button, 9, 2)

        ok_cancel_box = QHBoxLayout()
        ok_cancel_box.addWidget(self.apply_button)
        ok_cancel_box.addWidget(self.ok_button)
        ok_cancel_box.addWidget(self.cancel_button)

        grid2 = QGridLayout()
        grid2.addWidget(self.grid2_title, 0, 0)
        grid2.addWidget(self.low_to_high_radio, 1, 0)
        grid2.addWidget(self.high_to_low_radio, 2, 0)

        grid2.addWidget(self.vertical_radio, 1, 1)
        grid2.addWidget(self.horizontal_radio, 2, 1)

        grid2.addWidget(self.show_radio, 1, 2)
        grid2.addWidget(self.hide_radio, 2, 2)

        grid2.addWidget(self.animate_button, 3, 1)

        #grid2.setSpacing(0)

        vbox = QVBoxLayout()
        vbox.addLayout(grid)
        #vbox.addLayout(checkboxes)
        vbox.addLayout(grid2)
        vbox.addStretch()
        vbox.addLayout(ok_cancel_box)

        self.setLayout(vbox)

    def set_connections(self):
        """creates the actions for the menu"""
        self.title_button.clicked.connect(self.on_default_title)
        self.min_button.clicked.connect(self.on_default_min)
        self.max_button.clicked.connect(self.on_default_max)
        self.format_button.clicked.connect(self.on_default_format)
        self.scale_button.clicked.connect(self.on_default_scale)
        self.arrow_scale_button.clicked.connect(self.on_default_arrow_scale)
        self.phase_button.clicked.connect(self.on_default_phase)

        self.nlabels_button.clicked.connect(self.on_default_nlabels)
        self.labelsize_button.clicked.connect(self.on_default_labelsize)
        self.ncolors_button.clicked.connect(self.on_default_ncolors)
        self.colormap_button.clicked.connect(self.on_default_colormap)

        self.animate_button.clicked.connect(self.on_animate)

        self.show_radio.clicked.connect(self.on_show_hide)
        self.hide_radio.clicked.connect(self.on_show_hide)

        self.apply_button.clicked.connect(self.on_apply)
        self.ok_button.clicked.connect(self.on_ok)
        self.cancel_button.clicked.connect(self.on_cancel)

    def set_font_size(self, font_size):
        """
        Updates the font size of the objects

        Parameters
        ----------
        font_size : int
            the font size
        """
        if self.font_size == font_size:
            return
        self.font_size = font_size
        font = QFont()
        font.setPointSize(font_size)
        self.setFont(font)
        self.title_edit.setFont(font)
        self.min_edit.setFont(font)
        self.max_edit.setFont(font)
        self.format_edit.setFont(font)
        self.scale_edit.setFont(font)
        self.phase_edit.setFont(font)
        self.nlabels_edit.setFont(font)
        self.labelsize_edit.setFont(font)
        self.ncolors_edit.setFont(font)

    def on_animate(self):
        """opens the animation window"""
        title, flag0 = check_name_str(self.title_edit)
        if not flag0:
            return

        scale, flag1 = check_float(self.scale_edit)
        if not flag1:
            scale = self._scale

        data = {
            'font_size': self.out_data['font_size'],
            'icase_fringe': self._icase_fringe,
            'icase_disp': self._icase_disp,
            'icase_vector': self._icase_vector,
            'title': title,
            'time': 2,
            'frames/sec': 30,
            'resolution': 1,
            'iframe': 0,
            'scale': scale,
            'default_scale': self._default_scale,
            'arrow_scale': scale,
            'default_arrow_scale': self._default_arrow_scale,
            'is_scale': self._default_phase is None,
            'phase': self._phase,
            'default_phase': self._default_phase,
            'dirname': os.path.abspath(os.getcwd()),
            'clicked_ok': False,
            'close': False,
        }
        self.win_parent.legend_obj.set_animation_window(data)

    def on_default_title(self):
        """action when user clicks 'Default' for title"""
        title = str(self._default_title)
        self.title_edit.setText(title)
        self.title_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_min(self):
        """action when user clicks 'Default' for min value"""
        self.min_edit.setText(str(self._default_min))
        self.min_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_max(self):
        """action when user clicks 'Default' for max value"""
        self.max_edit.setText(str(self._default_max))
        self.max_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_format(self):
        """action when user clicks 'Default' for the number format"""
        self.format_edit.setText(str(self._default_format))
        self.format_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_scale(self):
        """action when user clicks 'Default' for scale factor"""
        self.scale_edit.setText(str(self._default_scale))
        self.scale_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_arrow_scale(self):
        """action when user clicks 'Default' for arrow_scale factor"""
        self.arrow_scale_edit.setText(str(self._default_arrow_scale))
        self.arrow_scale_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_phase(self):
        """action when user clicks 'Default' for phase angle"""
        self.phase_edit.setText(str(self._default_phase))
        self.phase_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_ncolors(self):
        """action when user clicks 'Default' for number of colors"""
        self.ncolors_edit.setText(str(self._default_ncolors))
        self.ncolors_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_colormap(self):
        """action when user clicks 'Default' for the color map"""
        self.colormap_edit.setCurrentIndex(
            colormap_keys.index(self._default_colormap))

    def on_default_nlabels(self):
        """action when user clicks 'Default' for number of labels"""
        self.nlabels_edit.setStyleSheet("QLineEdit{background: white;}")
        self.nlabels_edit.setText(str(self._default_nlabels))

    def on_default_labelsize(self):
        """action when user clicks 'Default' for number of labelsize"""
        self.labelsize_edit.setText(str(self._default_labelsize))
        self.labelsize_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_show_hide(self):
        """action when user clicks the 'Show/Hide' radio button"""
        #self.colormap_edit.setCurrentIndex(colormap_keys.index(self._default_colormap))
        is_shown = self.show_radio.isChecked()
        self.nlabels_edit.setEnabled(is_shown)
        self.nlabels_button.setEnabled(is_shown)
        self.ncolors_edit.setEnabled(is_shown)
        self.ncolors_button.setEnabled(is_shown)
        self.high_to_low_radio.setEnabled(is_shown)
        self.low_to_high_radio.setEnabled(is_shown)
        self.colormap_edit.setEnabled(is_shown)
        self.colormap_button.setEnabled(is_shown)
        self.vertical_radio.setEnabled(is_shown)
        self.horizontal_radio.setEnabled(is_shown)

    def show_legend(self):
        """shows the legend"""
        self._set_legend(True)

    def hide_legend(self):
        """hides the legend"""
        self._set_legend(False)

    def _set_legend(self, is_shown):
        """shows/hides the legend"""
        self.show_radio.setChecked(is_shown)
        self.hide_radio.setChecked(not is_shown)
        #if self.is_gui:
        #self.win_parent.scalar_bar_actor.SetVisibility(is_shown)

    def on_validate(self):
        """checks to see if the ``on_apply`` method can be called"""
        show_title = self._icase_fringe is not None
        flag_title = True
        title_value = ''
        if show_title:
            title_value, flag_title = check_name_str(self.title_edit)

        flag_fringe = True
        min_value = max_value = format_value = nlabels = ncolors = labelsize = colormap = None
        if self._icase_fringe is not None:
            min_value, flag1 = check_float(self.min_edit)
            max_value, flag2 = check_float(self.max_edit)
            format_value, flag3 = check_format(self.format_edit)
            nlabels, flag4 = check_positive_int_or_blank(self.nlabels_edit)
            ncolors, flag5 = check_positive_int_or_blank(self.ncolors_edit)
            labelsize, flag6 = check_positive_int_or_blank(self.labelsize_edit)
            colormap = str(self.colormap_edit.currentText())
            if flag3 and 'i' in format_value:
                format_value = '%i'
            flag_fringe = all([flag1, flag2, flag3, flag4, flag5, flag6])

        flag_disp = True
        scale = phase = None
        if self._icase_disp is not None:
            scale, flag1 = check_float(self.scale_edit)
            phase, flag2 = check_float(self.phase_edit)
            assert isinstance(scale, float), scale
            flag_disp = all([flag1, flag2])

        flag_vector = True
        arrow_scale = None
        if self._icase_vector is not None:
            arrow_scale, flag_vector = check_float(self.arrow_scale_edit)

        if all([flag_title, flag_fringe, flag_disp, flag_vector]):
            self.out_data['title'] = title_value
            self.out_data['min_value'] = min_value
            self.out_data['max_value'] = max_value
            self.out_data['format'] = format_value
            self.out_data['scale'] = scale
            self.out_data['phase'] = phase

            self.out_data['arrow_scale'] = arrow_scale

            self.out_data['nlabels'] = nlabels
            self.out_data['ncolors'] = ncolors
            self.out_data['labelsize'] = labelsize
            self.out_data['colormap'] = colormap

            self.out_data['is_low_to_high'] = self.low_to_high_radio.isChecked(
            )
            self.out_data['is_horizontal'] = self.horizontal_radio.isChecked()
            self.out_data['is_shown'] = self.show_radio.isChecked()

            self.out_data['clicked_ok'] = True
            self.out_data['close'] = True
            #print('self.out_data = ', self.out_data)
            #print("title = %r" % self.title_edit.text())
            #print("min = %r" % self.min_edit.text())
            #print("max = %r" % self.max_edit.text())
            #print("format = %r" % self.format_edit.text())
            return True
        return False

    def on_apply(self):
        """applies the current values"""
        passed = self.on_validate()
        if passed and self.external_call:
            self.win_parent.legend_obj._apply_legend(self.out_data)
        self.external_call = True
        return passed

    def on_ok(self):
        """applies the current values and closes the window"""
        passed = self.on_apply()
        if passed:
            self.close()
            #self.destroy()

    def on_cancel(self):
        """closes the windows and reverts the legend"""
        self.out_data['close'] = True
        self.close()
Пример #18
0
class ProjectDialog(QDialog):
    """Project creation dialog."""

    sig_project_creation_requested = Signal(str, str, object)
    """
    This signal is emitted to request the Projects plugin the creation of a
    project.

    Parameters
    ----------
    project_path: str
        Location of project.
    project_type: str	
        Type of project as defined by project types.	
    project_packages: object	
        Package to install. Currently not in use.	
    """

    def __init__(self, parent, project_types):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)
        self.plugin = parent
        self._project_types = project_types
        self.project_data = {}

        # Variables
        current_python_version = '.'.join([to_text_string(sys.version_info[0]),
                                           to_text_string(sys.version_info[1])])
        python_versions = ['2.7', '3.4', '3.5']
        if current_python_version not in python_versions:
            python_versions.append(current_python_version)
            python_versions = sorted(python_versions)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))
        self.label_python_version = QLabel(_('Python version'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()
        self.combo_python_version = QComboBox()

        self.label_information = QLabel("")

        self.button_select_location = QToolButton()
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.combo_python_version.addItems(python_versions)
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_select_location.setIcon(get_std_icon('DirOpenIcon'))
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        for (id_, name) in [(pt_id, pt.get_name()) for pt_id, pt
                            in project_types.items()]:
            self.combo_project_type.addItem(name, id_)

        self.combo_python_version.setCurrentIndex(
            python_versions.index(current_python_version))
        self.setWindowTitle(_('Create new project'))
        self.setFixedWidth(500)
        self.label_python_version.setVisible(False)
        self.combo_python_version.setVisible(False)

        # Layouts
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addStretch(1)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_python_version, 3, 0)
        layout_grid.addWidget(self.combo_python_version, 3, 1, 1, 2)
        layout_grid.addWidget(self.label_information, 4, 0, 1, 3)

        layout = QVBoxLayout()
        layout.addWidget(self.groupbox)
        layout.addSpacing(10)
        layout.addLayout(layout_grid)
        layout.addStretch()
        layout.addSpacing(20)
        layout.addWidget(self.bbox)

        self.setLayout(layout)

        # Signals and slots
        self.button_select_location.clicked.connect(self.select_location)
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def select_location(self):
        """Select directory."""
        location = osp.normpath(
            getexistingdirectory(
                self,
                _("Select directory"),
                self.location,
            )
        )

        if location:
            if is_writable(location):
                self.location = location
                self.update_location()

    def update_location(self, text=''):
        """Update text of location."""
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        name = self.text_project_name.text().strip()

        if name and self.radio_new_dir.isChecked():
            path = osp.join(self.location, name)
            self.button_create.setDisabled(os.path.isdir(path))
        elif self.radio_from_dir.isChecked():
            self.button_create.setEnabled(True)
            path = self.location
        else:
            self.button_create.setEnabled(False)
            path = self.location

        self.text_location.setText(path)

        # Validate name with the method from the currently selected project
        project_type_id = self.combo_project_type.currentData()
        validate_func = self._project_types[project_type_id].validate_name
        validated, msg = validate_func(path, name)
        msg = "" if validated else msg
        self.label_information.setText(msg)
        self.button_create.setEnabled(validated)

    def create_project(self):
        """Create project."""
        self.project_data = {
            "root_path": self.text_location.text(),
            "project_type": self.combo_project_type.currentData(),
        }
        self.sig_project_creation_requested.emit(
            self.text_location.text(),
            self.combo_project_type.currentData(),
            [],
        )
        self.accept()
Пример #19
0
class FindOptions(QWidget):
    """Find widget with options"""
    find = Signal()
    stop = Signal()
    
    def __init__(self, parent, search_text, search_text_regexp, search_path,
                 include, include_idx, include_regexp,
                 exclude, exclude_idx, exclude_regexp,
                 supported_encodings, in_python_path, more_options):
        QWidget.__init__(self, parent)
        
        if search_path is None:
            search_path = getcwd()
        
        if not isinstance(search_text, (list, tuple)):
            search_text = [search_text]
        if not isinstance(search_path, (list, tuple)):
            search_path = [search_path]
        if not isinstance(include, (list, tuple)):
            include = [include]
        if not isinstance(exclude, (list, tuple)):
            exclude = [exclude]

        self.supported_encodings = supported_encodings

        # Layout 1
        hlayout1 = QHBoxLayout()
        self.search_text = PatternComboBox(self, search_text,
                                           _("Search pattern"))
        self.edit_regexp = create_toolbutton(self,
                                             icon=ima.icon('advanced'),
                                             tip=_('Regular expression'))
        self.edit_regexp.setCheckable(True)
        self.edit_regexp.setChecked(search_text_regexp)
        self.more_widgets = ()
        self.more_options = create_toolbutton(self,
                                              toggled=self.toggle_more_options)
        self.more_options.setCheckable(True)
        self.more_options.setChecked(more_options)
        
        self.ok_button = create_toolbutton(self, text=_("Search"),
                                icon=ima.icon('DialogApplyButton'),
                                triggered=lambda: self.find.emit(),
                                tip=_("Start search"),
                                text_beside_icon=True)
        self.ok_button.clicked.connect(self.update_combos)
        self.stop_button = create_toolbutton(self, text=_("Stop"),
                                icon=ima.icon('stop'),
                                triggered=lambda: self.stop.emit(),
                                tip=_("Stop search"),
                                text_beside_icon=True)
        self.stop_button.setEnabled(False)
        for widget in [self.search_text, self.edit_regexp,
                       self.ok_button, self.stop_button, self.more_options]:
            hlayout1.addWidget(widget)

        # Layout 2
        hlayout2 = QHBoxLayout()
        self.include_pattern = PatternComboBox(self, include,
                                               _("Included filenames pattern"))
        if include_idx is not None and include_idx >= 0 \
           and include_idx < self.include_pattern.count():
            self.include_pattern.setCurrentIndex(include_idx)
        self.include_regexp = create_toolbutton(self,
                                            icon=ima.icon('advanced'),
                                            tip=_('Regular expression'))
        self.include_regexp.setCheckable(True)
        self.include_regexp.setChecked(include_regexp)
        include_label = QLabel(_("Include:"))
        include_label.setBuddy(self.include_pattern)
        self.exclude_pattern = PatternComboBox(self, exclude,
                                               _("Excluded filenames pattern"))
        if exclude_idx is not None and exclude_idx >= 0 \
           and exclude_idx < self.exclude_pattern.count():
            self.exclude_pattern.setCurrentIndex(exclude_idx)
        self.exclude_regexp = create_toolbutton(self,
                                            icon=ima.icon('advanced'),
                                            tip=_('Regular expression'))
        self.exclude_regexp.setCheckable(True)
        self.exclude_regexp.setChecked(exclude_regexp)
        exclude_label = QLabel(_("Exclude:"))
        exclude_label.setBuddy(self.exclude_pattern)
        for widget in [include_label, self.include_pattern,
                       self.include_regexp,
                       exclude_label, self.exclude_pattern,
                       self.exclude_regexp]:
            hlayout2.addWidget(widget)

        # Layout 3
        hlayout3 = QHBoxLayout()
        self.python_path = QRadioButton(_("PYTHONPATH"), self)
        self.python_path.setChecked(in_python_path)
        self.python_path.setToolTip(_(
                          "Search in all directories listed in sys.path which"
                          " are outside the Python installation directory"))        
        self.hg_manifest = QRadioButton(_("Hg repository"), self)
        self.detect_hg_repository()
        self.hg_manifest.setToolTip(
                                _("Search in current directory hg repository"))
        self.custom_dir = QRadioButton(_("Here:"), self)
        self.custom_dir.setChecked(not in_python_path)
        self.dir_combo = PathComboBox(self)
        self.dir_combo.addItems(search_path)
        self.dir_combo.setToolTip(_("Search recursively in this directory"))
        self.dir_combo.open_dir.connect(self.set_directory)
        self.python_path.toggled.connect(self.dir_combo.setDisabled)
        self.hg_manifest.toggled.connect(self.dir_combo.setDisabled)
        browse = create_toolbutton(self, icon=ima.icon('DirOpenIcon'),
                                   tip=_('Browse a search directory'),
                                   triggered=self.select_directory)
        for widget in [self.python_path, self.hg_manifest, self.custom_dir,
                       self.dir_combo, browse]:
            hlayout3.addWidget(widget)
            
        self.search_text.valid.connect(lambda valid: self.find.emit())
        self.include_pattern.valid.connect(lambda valid: self.find.emit())
        self.exclude_pattern.valid.connect(lambda valid: self.find.emit())
        self.dir_combo.valid.connect(lambda valid: self.find.emit())
            
        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.addLayout(hlayout1)
        vlayout.addLayout(hlayout2)
        vlayout.addLayout(hlayout3)
        self.more_widgets = (hlayout2, hlayout3)
        self.toggle_more_options(more_options)
        self.setLayout(vlayout)
                
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)

    @Slot(bool)
    def toggle_more_options(self, state):
        for layout in self.more_widgets:
            for index in range(layout.count()):
                if state and self.isVisible() or not state:
                    layout.itemAt(index).widget().setVisible(state)
        if state:
            icon = ima.icon('options_less')
            tip = _('Hide advanced options')
        else:
            icon = ima.icon('options_more')
            tip = _('Show advanced options')
        self.more_options.setIcon(icon)
        self.more_options.setToolTip(tip)
        
    def update_combos(self):
        self.search_text.lineEdit().returnPressed.emit()
        self.include_pattern.lineEdit().returnPressed.emit()
        self.exclude_pattern.lineEdit().returnPressed.emit()
        
    def detect_hg_repository(self, path=None):
        if path is None:
            path = getcwd()
        hg_repository = is_hg_installed() and get_vcs_root(path) is not None
        self.hg_manifest.setEnabled(hg_repository)
        if not hg_repository and self.hg_manifest.isChecked():
            self.custom_dir.setChecked(True)
        
    def set_search_text(self, text):
        if text:
            self.search_text.add_text(text)
            self.search_text.lineEdit().selectAll()
        self.search_text.setFocus()
        
    def get_options(self, all=False):
        # Getting options
        utext = to_text_string(self.search_text.currentText())
        if not utext:
            return
        try:
            texts = [(utext.encode('ascii'), 'ascii')]
        except UnicodeEncodeError:
            texts = []
            for enc in self.supported_encodings:
                try:
                    texts.append((utext.encode(enc), enc))
                except UnicodeDecodeError:
                    pass
        text_re = self.edit_regexp.isChecked()
        include = to_text_string(self.include_pattern.currentText())
        include_re = self.include_regexp.isChecked()
        exclude = to_text_string(self.exclude_pattern.currentText())
        exclude_re = self.exclude_regexp.isChecked()
        python_path = self.python_path.isChecked()
        hg_manifest = self.hg_manifest.isChecked()
        path = osp.abspath( to_text_string( self.dir_combo.currentText() ) )
        
        # Finding text occurrences
        if not include_re:
            include = fnmatch.translate(include)
        if not exclude_re:
            exclude = fnmatch.translate(exclude)
            
        if all:
            search_text = [to_text_string(self.search_text.itemText(index)) \
                           for index in range(self.search_text.count())]
            search_path = [to_text_string(self.dir_combo.itemText(index)) \
                           for index in range(self.dir_combo.count())]
            include = [to_text_string(self.include_pattern.itemText(index)) \
                       for index in range(self.include_pattern.count())]
            include_idx = self.include_pattern.currentIndex()
            exclude = [to_text_string(self.exclude_pattern.itemText(index)) \
                       for index in range(self.exclude_pattern.count())]
            exclude_idx = self.exclude_pattern.currentIndex()
            more_options = self.more_options.isChecked()
            return (search_text, text_re, search_path,
                    include, include_idx, include_re,
                    exclude, exclude_idx, exclude_re,
                    python_path, more_options)
        else:
            return (path, python_path, hg_manifest,
                    include, exclude, texts, text_re)

    @Slot()
    def select_directory(self):
        """Select directory"""
        self.parent().redirect_stdio.emit(False)
        directory = getexistingdirectory(self, _("Select directory"),
                                         self.dir_combo.currentText())
        if directory:
            self.set_directory(directory)
        self.parent().redirect_stdio.emit(True)
        
    def set_directory(self, directory):
        path = to_text_string(osp.abspath(to_text_string(directory)))
        self.dir_combo.setEditText(path)
        self.detect_hg_repository(path)
        
    def keyPressEvent(self, event):
        """Reimplemented to handle key events"""
        ctrl = event.modifiers() & Qt.ControlModifier
        shift = event.modifiers() & Qt.ShiftModifier
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            self.find.emit()
        elif event.key() == Qt.Key_F and ctrl and shift:
            # Toggle find widgets
            self.parent().toggle_visibility.emit(not self.isVisible())
        else:
            QWidget.keyPressEvent(self, event)
Пример #20
0
class RunConfigOptions(QWidget):
    """Run configuration options"""
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.current_radio = None
        self.dedicated_radio = None
        self.systerm_radio = None

        self.runconf = RunConfiguration()

        firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False)

        # --- General settings ----
        common_group = QGroupBox(_("General settings"))
        common_layout = QGridLayout()
        common_group.setLayout(common_layout)
        self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES)
        common_layout.addWidget(self.clear_var_cb, 0, 0)
        self.clo_cb = QCheckBox(_("Command line options:"))
        common_layout.addWidget(self.clo_cb, 1, 0)
        self.clo_edit = QLineEdit()
        self.clo_cb.toggled.connect(self.clo_edit.setEnabled)
        self.clo_edit.setEnabled(False)
        common_layout.addWidget(self.clo_edit, 1, 1)
        self.wd_cb = QCheckBox(_("Working directory:"))
        common_layout.addWidget(self.wd_cb, 2, 0)
        wd_layout = QHBoxLayout()
        self.wd_edit = QLineEdit()
        self.wd_cb.toggled.connect(self.wd_edit.setEnabled)
        self.wd_edit.setEnabled(False)
        wd_layout.addWidget(self.wd_edit)
        browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self)
        browse_btn.setToolTip(_("Select directory"))
        browse_btn.clicked.connect(self.select_directory)
        wd_layout.addWidget(browse_btn)
        common_layout.addLayout(wd_layout, 2, 1)
        self.post_mortem_cb = QCheckBox(
            _("Enter debugging mode when "
              "errors appear during execution"))
        common_layout.addWidget(self.post_mortem_cb)

        # --- Interpreter ---
        interpreter_group = QGroupBox(_("Console"))
        interpreter_layout = QVBoxLayout()
        interpreter_group.setLayout(interpreter_layout)
        self.current_radio = QRadioButton(CURRENT_INTERPRETER)
        interpreter_layout.addWidget(self.current_radio)
        self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER)
        interpreter_layout.addWidget(self.dedicated_radio)
        self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER)
        interpreter_layout.addWidget(self.systerm_radio)

        # --- Dedicated interpreter ---
        new_group = QGroupBox(_("Dedicated Python console"))
        self.current_radio.toggled.connect(new_group.setDisabled)
        new_layout = QGridLayout()
        new_group.setLayout(new_layout)
        self.interact_cb = QCheckBox(
            _("Interact with the Python "
              "console after execution"))
        new_layout.addWidget(self.interact_cb, 1, 0, 1, -1)

        self.show_kill_warning_cb = QCheckBox(
            _("Show warning when killing"
              " running process"))

        new_layout.addWidget(self.show_kill_warning_cb, 2, 0, 1, -1)
        self.pclo_cb = QCheckBox(_("Command line options:"))
        new_layout.addWidget(self.pclo_cb, 3, 0)
        self.pclo_edit = QLineEdit()
        self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled)
        self.pclo_edit.setEnabled(False)
        self.pclo_edit.setToolTip(
            _("<b>-u</b> is added to the "
              "other options you set here"))
        new_layout.addWidget(self.pclo_edit, 3, 1)

        # Checkbox to preserve the old behavior, i.e. always open the dialog
        # on first run
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog"))
        self.firstrun_cb.clicked.connect(self.set_firstrun_o)
        self.firstrun_cb.setChecked(firstrun_o)

        layout = QVBoxLayout()
        layout.addWidget(interpreter_group)
        layout.addWidget(common_group)
        layout.addWidget(new_group)
        layout.addWidget(hline)
        layout.addWidget(self.firstrun_cb)
        self.setLayout(layout)

    def select_directory(self):
        """Select directory"""
        basedir = to_text_string(self.wd_edit.text())
        if not osp.isdir(basedir):
            basedir = getcwd()
        directory = getexistingdirectory(self, _("Select directory"), basedir)
        if directory:
            self.wd_edit.setText(directory)
            self.wd_cb.setChecked(True)

    def set(self, options):
        self.runconf.set(options)
        self.clo_cb.setChecked(self.runconf.args_enabled)
        self.clo_edit.setText(self.runconf.args)
        self.wd_cb.setChecked(self.runconf.wdir_enabled)
        self.wd_edit.setText(self.runconf.wdir)
        if self.runconf.current:
            self.current_radio.setChecked(True)
        elif self.runconf.systerm:
            self.systerm_radio.setChecked(True)
        else:
            self.dedicated_radio.setChecked(True)
        self.interact_cb.setChecked(self.runconf.interact)
        self.show_kill_warning_cb.setChecked(self.runconf.show_kill_warning)
        self.post_mortem_cb.setChecked(self.runconf.post_mortem)
        self.pclo_cb.setChecked(self.runconf.python_args_enabled)
        self.pclo_edit.setText(self.runconf.python_args)
        self.clear_var_cb.setChecked(self.runconf.clear_namespace)

    def get(self):
        self.runconf.args_enabled = self.clo_cb.isChecked()
        self.runconf.args = to_text_string(self.clo_edit.text())
        self.runconf.wdir_enabled = self.wd_cb.isChecked()
        self.runconf.wdir = to_text_string(self.wd_edit.text())
        self.runconf.current = self.current_radio.isChecked()
        self.runconf.systerm = self.systerm_radio.isChecked()
        self.runconf.interact = self.interact_cb.isChecked()
        self.runconf.show_kill_warning = self.show_kill_warning_cb.isChecked()
        self.runconf.post_mortem = self.post_mortem_cb.isChecked()
        self.runconf.python_args_enabled = self.pclo_cb.isChecked()
        self.runconf.python_args = to_text_string(self.pclo_edit.text())
        self.runconf.clear_namespace = self.clear_var_cb.isChecked()
        return self.runconf.get()

    def is_valid(self):
        wdir = to_text_string(self.wd_edit.text())
        if not self.wd_cb.isChecked() or osp.isdir(wdir):
            return True
        else:
            QMessageBox.critical(
                self, _("Run configuration"),
                _("The following working directory is "
                  "not valid:<br><b>%s</b>") % wdir)
            return False

    def set_firstrun_o(self):
        CONF.set('run', ALWAYS_OPEN_FIRST_RUN_OPTION,
                 self.firstrun_cb.isChecked())
Пример #21
0
    def __init__(self, parent, text):
        QWidget.__init__(self, parent)

        self.text_editor = QTextEdit(self)
        self.text_editor.setText(text)
        self.text_editor.setReadOnly(True)

        # Type frame
        type_layout = QHBoxLayout()
        type_label = QLabel(_("Import as"))
        type_layout.addWidget(type_label)
        data_btn = QRadioButton(_("data"))
        data_btn.setChecked(True)
        self._as_data= True
        type_layout.addWidget(data_btn)
        code_btn = QRadioButton(_("code"))
        self._as_code = False
        type_layout.addWidget(code_btn)
        txt_btn = QRadioButton(_("text"))
        type_layout.addWidget(txt_btn)

        h_spacer = QSpacerItem(40, 20,
                               QSizePolicy.Expanding, QSizePolicy.Minimum)
        type_layout.addItem(h_spacer)
        type_frame = QFrame()
        type_frame.setLayout(type_layout)

        # Opts frame
        grid_layout = QGridLayout()
        grid_layout.setSpacing(0)

        col_label = QLabel(_("Column separator:"))
        grid_layout.addWidget(col_label, 0, 0)
        col_w = QWidget()
        col_btn_layout = QHBoxLayout()
        self.tab_btn = QRadioButton(_("Tab"))
        self.tab_btn.setChecked(False)
        col_btn_layout.addWidget(self.tab_btn)
        other_btn_col = QRadioButton(_("other"))
        other_btn_col.setChecked(True)
        col_btn_layout.addWidget(other_btn_col)
        col_w.setLayout(col_btn_layout)
        grid_layout.addWidget(col_w, 0, 1)
        self.line_edt = QLineEdit(",")
        self.line_edt.setMaximumWidth(30)
        self.line_edt.setEnabled(True)
        other_btn_col.toggled.connect(self.line_edt.setEnabled)
        grid_layout.addWidget(self.line_edt, 0, 2)

        row_label = QLabel(_("Row separator:"))
        grid_layout.addWidget(row_label, 1, 0)
        row_w = QWidget()
        row_btn_layout = QHBoxLayout()
        self.eol_btn = QRadioButton(_("EOL"))
        self.eol_btn.setChecked(True)
        row_btn_layout.addWidget(self.eol_btn)
        other_btn_row = QRadioButton(_("other"))
        row_btn_layout.addWidget(other_btn_row)
        row_w.setLayout(row_btn_layout)
        grid_layout.addWidget(row_w, 1, 1)
        self.line_edt_row = QLineEdit(";")
        self.line_edt_row.setMaximumWidth(30)
        self.line_edt_row.setEnabled(False)
        other_btn_row.toggled.connect(self.line_edt_row.setEnabled)
        grid_layout.addWidget(self.line_edt_row, 1, 2)

        grid_layout.setRowMinimumHeight(2, 15)

        other_group = QGroupBox(_("Additional options"))
        other_layout = QGridLayout()
        other_group.setLayout(other_layout)

        skiprows_label = QLabel(_("Skip rows:"))
        other_layout.addWidget(skiprows_label, 0, 0)
        self.skiprows_edt = QLineEdit('0')
        self.skiprows_edt.setMaximumWidth(30)
        intvalid = QIntValidator(0, len(to_text_string(text).splitlines()),
                                 self.skiprows_edt)
        self.skiprows_edt.setValidator(intvalid)
        other_layout.addWidget(self.skiprows_edt, 0, 1)

        other_layout.setColumnMinimumWidth(2, 5)

        comments_label = QLabel(_("Comments:"))
        other_layout.addWidget(comments_label, 0, 3)
        self.comments_edt = QLineEdit('#')
        self.comments_edt.setMaximumWidth(30)
        other_layout.addWidget(self.comments_edt, 0, 4)

        self.trnsp_box = QCheckBox(_("Transpose"))
        #self.trnsp_box.setEnabled(False)
        other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0)

        grid_layout.addWidget(other_group, 3, 0, 2, 0)

        opts_frame = QFrame()
        opts_frame.setLayout(grid_layout)

        data_btn.toggled.connect(opts_frame.setEnabled)
        data_btn.toggled.connect(self.set_as_data)
        code_btn.toggled.connect(self.set_as_code)
#        self.connect(txt_btn, SIGNAL("toggled(bool)"),
#                     self, SLOT("is_text(bool)"))

        # Final layout
        layout = QVBoxLayout()
        layout.addWidget(type_frame)
        layout.addWidget(self.text_editor)
        layout.addWidget(opts_frame)
        self.setLayout(layout)
Пример #22
0
class ContentsWidget(QWidget):
    """Import wizard contents widget"""
    asDataChanged = Signal(bool)
    
    def __init__(self, parent, text):
        QWidget.__init__(self, parent)

        self.text_editor = QTextEdit(self)
        self.text_editor.setText(text)
        self.text_editor.setReadOnly(True)

        # Type frame
        type_layout = QHBoxLayout()
        type_label = QLabel(_("Import as"))
        type_layout.addWidget(type_label)
        data_btn = QRadioButton(_("data"))
        data_btn.setChecked(True)
        self._as_data= True
        type_layout.addWidget(data_btn)
        code_btn = QRadioButton(_("code"))
        self._as_code = False
        type_layout.addWidget(code_btn)
        txt_btn = QRadioButton(_("text"))
        type_layout.addWidget(txt_btn)

        h_spacer = QSpacerItem(40, 20,
                               QSizePolicy.Expanding, QSizePolicy.Minimum)
        type_layout.addItem(h_spacer)
        type_frame = QFrame()
        type_frame.setLayout(type_layout)

        # Opts frame
        grid_layout = QGridLayout()
        grid_layout.setSpacing(0)

        col_label = QLabel(_("Column separator:"))
        grid_layout.addWidget(col_label, 0, 0)
        col_w = QWidget()
        col_btn_layout = QHBoxLayout()
        self.tab_btn = QRadioButton(_("Tab"))
        self.tab_btn.setChecked(False)
        col_btn_layout.addWidget(self.tab_btn)
        other_btn_col = QRadioButton(_("other"))
        other_btn_col.setChecked(True)
        col_btn_layout.addWidget(other_btn_col)
        col_w.setLayout(col_btn_layout)
        grid_layout.addWidget(col_w, 0, 1)
        self.line_edt = QLineEdit(",")
        self.line_edt.setMaximumWidth(30)
        self.line_edt.setEnabled(True)
        other_btn_col.toggled.connect(self.line_edt.setEnabled)
        grid_layout.addWidget(self.line_edt, 0, 2)

        row_label = QLabel(_("Row separator:"))
        grid_layout.addWidget(row_label, 1, 0)
        row_w = QWidget()
        row_btn_layout = QHBoxLayout()
        self.eol_btn = QRadioButton(_("EOL"))
        self.eol_btn.setChecked(True)
        row_btn_layout.addWidget(self.eol_btn)
        other_btn_row = QRadioButton(_("other"))
        row_btn_layout.addWidget(other_btn_row)
        row_w.setLayout(row_btn_layout)
        grid_layout.addWidget(row_w, 1, 1)
        self.line_edt_row = QLineEdit(";")
        self.line_edt_row.setMaximumWidth(30)
        self.line_edt_row.setEnabled(False)
        other_btn_row.toggled.connect(self.line_edt_row.setEnabled)
        grid_layout.addWidget(self.line_edt_row, 1, 2)

        grid_layout.setRowMinimumHeight(2, 15)

        other_group = QGroupBox(_("Additional options"))
        other_layout = QGridLayout()
        other_group.setLayout(other_layout)

        skiprows_label = QLabel(_("Skip rows:"))
        other_layout.addWidget(skiprows_label, 0, 0)
        self.skiprows_edt = QLineEdit('0')
        self.skiprows_edt.setMaximumWidth(30)
        intvalid = QIntValidator(0, len(to_text_string(text).splitlines()),
                                 self.skiprows_edt)
        self.skiprows_edt.setValidator(intvalid)
        other_layout.addWidget(self.skiprows_edt, 0, 1)

        other_layout.setColumnMinimumWidth(2, 5)

        comments_label = QLabel(_("Comments:"))
        other_layout.addWidget(comments_label, 0, 3)
        self.comments_edt = QLineEdit('#')
        self.comments_edt.setMaximumWidth(30)
        other_layout.addWidget(self.comments_edt, 0, 4)

        self.trnsp_box = QCheckBox(_("Transpose"))
        #self.trnsp_box.setEnabled(False)
        other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0)

        grid_layout.addWidget(other_group, 3, 0, 2, 0)

        opts_frame = QFrame()
        opts_frame.setLayout(grid_layout)

        data_btn.toggled.connect(opts_frame.setEnabled)
        data_btn.toggled.connect(self.set_as_data)
        code_btn.toggled.connect(self.set_as_code)
#        self.connect(txt_btn, SIGNAL("toggled(bool)"),
#                     self, SLOT("is_text(bool)"))

        # Final layout
        layout = QVBoxLayout()
        layout.addWidget(type_frame)
        layout.addWidget(self.text_editor)
        layout.addWidget(opts_frame)
        self.setLayout(layout)

    def get_as_data(self):
        """Return if data type conversion"""
        return self._as_data

    def get_as_code(self):
        """Return if code type conversion"""
        return self._as_code

    def get_as_num(self):
        """Return if numeric type conversion"""
        return self._as_num

    def get_col_sep(self):
        """Return the column separator"""
        if self.tab_btn.isChecked():
            return u"\t"
        return to_text_string(self.line_edt.text())

    def get_row_sep(self):
        """Return the row separator"""
        if self.eol_btn.isChecked():
            return u"\n"
        return to_text_string(self.line_edt_row.text())

    def get_skiprows(self):
        """Return number of lines to be skipped"""
        return int(to_text_string(self.skiprows_edt.text()))

    def get_comments(self):
        """Return comment string"""
        return to_text_string(self.comments_edt.text())

    @Slot(bool)
    def set_as_data(self, as_data):
        """Set if data type conversion"""
        self._as_data = as_data
        self.asDataChanged.emit(as_data)

    @Slot(bool)
    def set_as_code(self, as_code):
        """Set if code type conversion"""
        self._as_code = as_code
Пример #23
0
class _ImageRaster2DSpectralWidget(_DatumWidget):

    MODE_SUM = 'sum'
    MODE_MAX = 'max'
    MODE_SINGLE = 'single'
    MODE_RANGE = 'range'

    def __init__(self, controller, datum=None, parent=None):
        self._datum = datum
        _DatumWidget.__init__(self, ImageRaster2DSpectral, controller,
                              datum, parent)

    def _init_ui(self):
        # Widgets
        self._rdb_sum = QRadioButton("Sum")
        self._rdb_sum.setChecked(True)
        self._rdb_max = QRadioButton("Maximum")
        self._rdb_single = QRadioButton("Single")
        self._rdb_range = QRadioButton("Range")

        self._sld_start = QSlider(Qt.Horizontal)
        self._sld_start.setTickPosition(QSlider.TicksBelow)
        self._sld_start.setEnabled(False)

        self._sld_end = QSlider(Qt.Horizontal)
        self._sld_end.setTickPosition(QSlider.TicksBelow)
        self._sld_end.setEnabled(False)

        self._wdg_imageraster2d = self._create_imageraster2d_widget()
        self._wdg_analysis = self._create_analysis1d_widget()

        # Layouts
        layout = _DatumWidget._init_ui(self)

        sublayout = QHBoxLayout()
        sublayout.addWidget(self._rdb_sum)
        sublayout.addWidget(self._rdb_max)
        sublayout.addWidget(self._rdb_single)
        sublayout.addWidget(self._rdb_range)
        layout.addLayout(sublayout)

        sublayout = QFormLayout()
        sublayout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) # Fix for Mac OS
        sublayout.addRow('Channels (Start)', self._sld_start)
        sublayout.addRow('Channels (End)', self._sld_end)
        layout.addLayout(sublayout)

        splitter = QSplitter()
        splitter.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        splitter.addWidget(self._wdg_imageraster2d)
        splitter.addWidget(self._wdg_analysis)
        layout.addWidget(splitter)

        # Signals
        self._rdb_sum.toggled.connect(self._on_mode_sum)
        self._rdb_max.toggled.connect(self._on_mode_max)
        self._rdb_single.toggled.connect(self._on_mode_single)
        self._rdb_range.toggled.connect(self._on_mode_range)

        self._sld_start.valueChanged.connect(self._on_slide_start)
        self._sld_end.valueChanged.connect(self._on_slide_end)

        self._wdg_imageraster2d.valueSelected.connect(self._on_value_selected)

        # Defaults
        self.setMode(self.MODE_SUM)

        return layout

    def _create_analysis1d_widget(self):
        raise NotImplementedError

    def _create_imageraster2d_widget(self):
        raise NotImplementedError

    def _on_mode_sum(self, checked):
        if checked:
            self.setMode(self.MODE_SUM)

    def _on_mode_max(self, checked):
        if checked:
            self.setMode(self.MODE_MAX)

    def _on_mode_single(self, checked):
        if checked:
            self.setMode(self.MODE_SINGLE)

    def _on_mode_range(self, checked):
        if checked:
            self.setMode(self.MODE_RANGE)

    def _update_data(self, mode=None):
        if mode is None:
            mode = self.mode()

        if mode == self.MODE_SUM:
            self._update_mode_sum()
        elif mode == self.MODE_MAX:
            self._update_mode_max()
        elif mode == self.MODE_SINGLE:
            self._update_mode_single()
        elif mode == self.MODE_RANGE:
            self._update_mode_range()

    def _update_mode_sum(self):
        if self._datum is None:
            return
        subdatum = np.sum(self._datum, 2)
        self._wdg_imageraster2d.setDatum(subdatum)

    def _update_mode_max(self):
        if self._datum is None:
            return
        subdatum = np.amax(self._datum, 2)
        self._wdg_imageraster2d.setDatum(subdatum)

    def _update_mode_single(self):
        if self._datum is None:
            return
        channel = self._sld_start.value()
        subdatum = self._datum[:, :, channel]
        self._wdg_imageraster2d.setDatum(subdatum)

    def _update_mode_range(self):
        if self._datum is None:
            return
        start = self._sld_start.value()
        end = self._sld_end.value()
        start2 = min(start, end)
        end2 = max(start, end)
        subdatum = np.sum(self._datum[:, :, start2:end2 + 1], 2)
        self._wdg_imageraster2d.setDatum(subdatum)

    def _on_slide_start(self, channel):
        if self._rdb_single.isChecked():
            self._update_mode_single()
        elif self._rdb_range.isChecked():
            self._update_mode_range()

    def _on_slide_end(self, channel):
        self._update_mode_range()

    def _on_value_selected(self, x, y):
        if self._datum is None:
            return
        subdatum = self._datum[x, y]
        self._wdg_analysis.setDatum(subdatum.view(Analysis1D))

    def setDatum(self, datum):
        _DatumWidget.setDatum(self, datum)
        self._datum = datum

        maximum = datum.channels - 1 if datum is not None else 0
        self._sld_start.setMaximum(maximum)
        self._sld_end.setMaximum(maximum)

        self._update_data()

    def setMode(self, mode):
        rsum = rmax = rsingle = rrange = False
        sstart = send = False
        if mode == self.MODE_SUM:
            rsum = True
        elif mode == self.MODE_MAX:
            rmax = True
        elif mode == self.MODE_SINGLE:
            rsingle = True
            sstart = True
        elif mode == self.MODE_RANGE:
            rrange = True
            sstart = send = True
        else:
            raise ValueError('Unknown mode')

        self._rdb_sum.setChecked(rsum)
        self._rdb_max.setChecked(rmax)
        self._rdb_single.setChecked(rsingle)
        self._rdb_range.setChecked(rrange)
        self._sld_start.setEnabled(sstart)
        self._sld_end.setEnabled(send)

        self._update_data(mode)

    def mode(self):
        if self._rdb_sum.isChecked():
            return self.MODE_SUM
        elif self._rdb_max.isChecked():
            return self.MODE_MAX
        elif self._rdb_single.isChecked():
            return self.MODE_SINGLE
        elif self._rdb_range.isChecked():
            return self.MODE_RANGE
        else:
            raise ValueError('Unknown mode')
Пример #24
0
class RunConfigOptions(QWidget):
    """Run configuration options"""

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.current_radio = None
        self.dedicated_radio = None
        self.systerm_radio = None

        self.runconf = RunConfiguration()

        firstrun_o = CONF.get("run", ALWAYS_OPEN_FIRST_RUN_OPTION, False)

        # --- General settings ----
        common_group = QGroupBox(_("General settings"))
        common_layout = QGridLayout()
        common_group.setLayout(common_layout)
        self.clo_cb = QCheckBox(_("Command line options:"))
        common_layout.addWidget(self.clo_cb, 0, 0)
        self.clo_edit = QLineEdit()
        self.clo_cb.toggled.connect(self.clo_edit.setEnabled)
        self.clo_edit.setEnabled(False)
        common_layout.addWidget(self.clo_edit, 0, 1)
        self.wd_cb = QCheckBox(_("Working directory:"))
        common_layout.addWidget(self.wd_cb, 1, 0)
        wd_layout = QHBoxLayout()
        self.wd_edit = QLineEdit()
        self.wd_cb.toggled.connect(self.wd_edit.setEnabled)
        self.wd_edit.setEnabled(False)
        wd_layout.addWidget(self.wd_edit)
        browse_btn = QPushButton(ima.icon("DirOpenIcon"), "", self)
        browse_btn.setToolTip(_("Select directory"))
        browse_btn.clicked.connect(self.select_directory)
        wd_layout.addWidget(browse_btn)
        common_layout.addLayout(wd_layout, 1, 1)
        self.post_mortem_cb = QCheckBox(_("Enter debugging mode when " "errors appear during execution"))
        common_layout.addWidget(self.post_mortem_cb)

        # --- Interpreter ---
        interpreter_group = QGroupBox(_("Console"))
        interpreter_layout = QVBoxLayout()
        interpreter_group.setLayout(interpreter_layout)
        self.current_radio = QRadioButton(CURRENT_INTERPRETER)
        interpreter_layout.addWidget(self.current_radio)
        self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER)
        interpreter_layout.addWidget(self.dedicated_radio)
        self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER)
        interpreter_layout.addWidget(self.systerm_radio)

        # --- Dedicated interpreter ---
        new_group = QGroupBox(_("Dedicated Python console"))
        self.current_radio.toggled.connect(new_group.setDisabled)
        new_layout = QGridLayout()
        new_group.setLayout(new_layout)
        self.interact_cb = QCheckBox(_("Interact with the Python " "console after execution"))
        new_layout.addWidget(self.interact_cb, 1, 0, 1, -1)

        self.show_kill_warning_cb = QCheckBox(_("Show warning when killing" " running process"))

        new_layout.addWidget(self.show_kill_warning_cb, 2, 0, 1, -1)
        self.pclo_cb = QCheckBox(_("Command line options:"))
        new_layout.addWidget(self.pclo_cb, 3, 0)
        self.pclo_edit = QLineEdit()
        self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled)
        self.pclo_edit.setEnabled(False)
        self.pclo_edit.setToolTip(_("<b>-u</b> is added to the " "other options you set here"))
        new_layout.addWidget(self.pclo_edit, 3, 1)

        # Checkbox to preserve the old behavior, i.e. always open the dialog
        # on first run
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog"))
        self.firstrun_cb.clicked.connect(self.set_firstrun_o)
        self.firstrun_cb.setChecked(firstrun_o)

        layout = QVBoxLayout()
        layout.addWidget(interpreter_group)
        layout.addWidget(common_group)
        layout.addWidget(new_group)
        layout.addWidget(hline)
        layout.addWidget(self.firstrun_cb)
        self.setLayout(layout)

    def select_directory(self):
        """Select directory"""
        basedir = to_text_string(self.wd_edit.text())
        if not osp.isdir(basedir):
            basedir = getcwd()
        directory = getexistingdirectory(self, _("Select directory"), basedir)
        if directory:
            self.wd_edit.setText(directory)
            self.wd_cb.setChecked(True)

    def set(self, options):
        self.runconf.set(options)
        self.clo_cb.setChecked(self.runconf.args_enabled)
        self.clo_edit.setText(self.runconf.args)
        self.wd_cb.setChecked(self.runconf.wdir_enabled)
        self.wd_edit.setText(self.runconf.wdir)
        if self.runconf.current:
            self.current_radio.setChecked(True)
        elif self.runconf.systerm:
            self.systerm_radio.setChecked(True)
        else:
            self.dedicated_radio.setChecked(True)
        self.interact_cb.setChecked(self.runconf.interact)
        self.show_kill_warning_cb.setChecked(self.runconf.show_kill_warning)
        self.post_mortem_cb.setChecked(self.runconf.post_mortem)
        self.pclo_cb.setChecked(self.runconf.python_args_enabled)
        self.pclo_edit.setText(self.runconf.python_args)

    def get(self):
        self.runconf.args_enabled = self.clo_cb.isChecked()
        self.runconf.args = to_text_string(self.clo_edit.text())
        self.runconf.wdir_enabled = self.wd_cb.isChecked()
        self.runconf.wdir = to_text_string(self.wd_edit.text())
        self.runconf.current = self.current_radio.isChecked()
        self.runconf.systerm = self.systerm_radio.isChecked()
        self.runconf.interact = self.interact_cb.isChecked()
        self.runconf.show_kill_warning = self.show_kill_warning_cb.isChecked()
        self.runconf.post_mortem = self.post_mortem_cb.isChecked()
        self.runconf.python_args_enabled = self.pclo_cb.isChecked()
        self.runconf.python_args = to_text_string(self.pclo_edit.text())
        return self.runconf.get()

    def is_valid(self):
        wdir = to_text_string(self.wd_edit.text())
        if not self.wd_cb.isChecked() or osp.isdir(wdir):
            return True
        else:
            QMessageBox.critical(
                self, _("Run configuration"), _("The following working directory is " "not valid:<br><b>%s</b>") % wdir
            )
            return False

    def set_firstrun_o(self):
        CONF.set("run", ALWAYS_OPEN_FIRST_RUN_OPTION, self.firstrun_cb.isChecked())
Пример #25
0
class LegendPropertiesWindow(PyDialog):
    """
    +-------------------+
    | Legend Properties |
    +-----------------------+
    | Title  ______ Default |
    | Min    ______ Default |
    | Max    ______ Default |
    | Format ______ Default |
    | Scale  ______ Default |
    | Phase  ______ Default |
    | Number of Colors ____ |
    | Number of Labels ____ |
    | Label Size       ____ | (TODO)
    | ColorMap         ____ | (TODO)
    |                       |
    | x Min/Max (Blue->Red) |
    | o Max/Min (Red->Blue) |
    |                       |
    | x Vertical/Horizontal |
    | x Show/Hide           |
    |                       |
    |        Animate        |
    |    Apply OK Cancel    |
    +-----------------------+
    """
    def __init__(self, data, win_parent=None):
        PyDialog.__init__(self, data, win_parent)

        self._updated_legend = False
        self._animation_window_shown = False

        self._icase = data['icase']
        self._default_icase = self._icase

        self._default_name = data['name']
        self._default_min = data['min']
        self._default_max = data['max']

        self._default_scale = data['default_scale']
        self._scale = data['scale']

        self._default_phase = data['default_phase']
        self._phase = data['phase']

        self._default_format = data['default_format']
        self._format = data['format']

        self._default_labelsize = data['default_labelsize']
        self._labelsize = data['labelsize']

        self._default_nlabels = data['default_nlabels']
        self._nlabels = data['nlabels']

        self._default_ncolors = data['default_ncolors']
        self._ncolors = data['ncolors']

        self._default_colormap = data['default_colormap']
        self._colormap = data['colormap']

        self._default_is_low_to_high = data['is_low_to_high']

        self._default_is_discrete = data['is_discrete']
        self._default_is_horizontal = data['is_horizontal']
        self._default_is_shown = data['is_shown']
        self._is_normals = data['is_normals']

        self._update_defaults_to_blank()

        #self.setupUi(self)
        self.setWindowTitle('Legend Properties')
        self.create_widgets()
        self.create_layout()
        self.set_connections()
        self.set_font_size(data['font_size'])

    def _update_defaults_to_blank(self):
        """Changes the default (None) to a blank string"""
        if self._default_colormap is None:
            self._default_colormap = 'jet'
        if self._default_labelsize is None:
            self._default_labelsize = ''
        if self._default_ncolors is None:
            self._default_ncolors = ''
        if self._default_nlabels is None:
            self._default_nlabels = ''

        if self._colormap is None:
            self._colormap = 'jet'
        if self._labelsize is None:
            self._labelsize = ''
        if self._ncolors is None:
            self._ncolors = ''
        if self._nlabels is None:
            self._nlabels = ''

    def update_legend(self,
                      icase,
                      name,
                      min_value,
                      max_value,
                      data_format,
                      scale,
                      phase,
                      nlabels,
                      labelsize,
                      ncolors,
                      colormap,
                      default_title,
                      default_min_value,
                      default_max_value,
                      default_data_format,
                      default_scale,
                      default_phase,
                      default_nlabels,
                      default_labelsize,
                      default_ncolors,
                      default_colormap,
                      is_low_to_high,
                      is_horizontal_scalar_bar,
                      is_normals,
                      font_size=8):
        """
        We need to update the legend if there's been a result change request
        """
        self.set_font_size(font_size)
        if icase != self._default_icase:
            self._icase = icase
            self._default_icase = icase
            self._default_name = default_title
            self._default_min = default_min_value
            self._default_max = default_max_value
            self._default_format = default_data_format
            self._default_is_low_to_high = is_low_to_high
            self._default_is_discrete = True
            self._default_is_horizontal = is_horizontal_scalar_bar
            self._default_scale = default_scale
            self._default_phase = default_phase
            self._default_nlabels = default_nlabels
            self._default_labelsize = default_labelsize
            self._default_ncolors = default_ncolors
            self._default_colormap = default_colormap
            self._is_normals = is_normals

            if colormap is None:
                colormap = 'jet'
            if labelsize is None:
                labelsize = ''
            if ncolors is None:
                ncolors = ''
            if nlabels is None:
                nlabels = ''

            self._update_defaults_to_blank()

            assert isinstance(scale, float), 'scale=%r' % scale
            assert isinstance(default_scale,
                              float), 'default_scale=%r' % default_scale
            if self._default_scale == 0.0:
                self.scale.setEnabled(False)
                self.scale_edit.setEnabled(False)
                self.scale_button.setEnabled(False)
            else:
                self.scale.setEnabled(True)
                self.scale_edit.setEnabled(True)
                self.scale_button.setEnabled(True)

            if self._default_phase is None:
                self._phase = None
                self.phase.setEnabled(False)
                self.phase_edit.setEnabled(False)
                self.phase_button.setEnabled(False)
                self.phase_edit.setText('0.0')
                self.phase_edit.setStyleSheet("QLineEdit{background: white;}")
            else:
                self._phase = phase
                self.phase.setEnabled(True)
                self.phase_edit.setEnabled(True)
                self.phase_button.setEnabled(True)
                self.phase_edit.setText(str(phase))
                self.phase_edit.setStyleSheet("QLineEdit{background: white;}")

            #self.on_default_name()
            #self.on_default_min()
            #self.on_default_max()
            #self.on_default_format()
            #self.on_default_scale()
            # reset defaults
            self._name = name
            self.name_edit.setText(name)
            self.name_edit.setStyleSheet("QLineEdit{background: white;}")

            self.min_edit.setText(str(min_value))
            self.min_edit.setStyleSheet("QLineEdit{background: white;}")

            self.max_edit.setText(str(max_value))
            self.max_edit.setStyleSheet("QLineEdit{background: white;}")

            self.format_edit.setText(str(data_format))
            self.format_edit.setStyleSheet("QLineEdit{background: white;}")

            self._scale = scale
            self.scale_edit.setText(str(scale))
            self.scale_edit.setStyleSheet("QLineEdit{background: white;}")

            self.nlabels_edit.setText(str(nlabels))
            self.nlabels_edit.setStyleSheet("QLineEdit{background: white;}")

            self.labelsize_edit.setText(str(labelsize))
            self.labelsize_edit.setStyleSheet("QLineEdit{background: white;}")

            self.ncolors_edit.setText(str(ncolors))
            self.ncolors_edit.setStyleSheet("QLineEdit{background: white;}")

            self.colormap_edit.setCurrentIndex(
                colormap_keys.index(str(colormap)))

            # lots of hacking for the Normal vectors
            enable = True
            if self._is_normals:
                enable = False

            self.max.setVisible(enable)
            self.min.setVisible(enable)
            self.max_edit.setVisible(enable)
            self.min_edit.setVisible(enable)
            self.max_button.setVisible(enable)
            self.min_button.setVisible(enable)

            self.show_radio.setVisible(enable)
            self.hide_radio.setVisible(enable)
            self.low_to_high_radio.setVisible(enable)
            self.high_to_low_radio.setVisible(enable)

            self.format.setVisible(enable)
            self.format_edit.setVisible(enable)
            self.format_edit.setVisible(enable)
            self.format_button.setVisible(enable)

            self.nlabels.setVisible(enable)
            self.nlabels_edit.setVisible(enable)
            self.nlabels_button.setVisible(enable)

            self.ncolors.setVisible(enable)
            self.ncolors_edit.setVisible(enable)
            self.ncolors_button.setVisible(enable)

            self.grid2_title.setVisible(enable)
            self.vertical_radio.setVisible(enable)
            self.horizontal_radio.setVisible(enable)

            self.colormap.setVisible(enable)
            self.colormap_edit.setVisible(enable)
            self.colormap_button.setVisible(enable)

            self.on_apply()

    def create_widgets(self):
        """creates the menu objects"""
        # Name
        self.name = QLabel("Title:")
        self.name_edit = QLineEdit(str(self._default_name))
        self.name_button = QPushButton("Default")

        # Min
        self.min = QLabel("Min:")
        self.min_edit = QLineEdit(str(self._default_min))
        self.min_button = QPushButton("Default")

        # Max
        self.max = QLabel("Max:")
        self.max_edit = QLineEdit(str(self._default_max))
        self.max_button = QPushButton("Default")

        #---------------------------------------
        # Format
        self.format = QLabel("Format (e.g. %.3f, %g, %.6e):")
        self.format_edit = QLineEdit(str(self._format))
        self.format_button = QPushButton("Default")

        #---------------------------------------
        # Scale
        self.scale = QLabel("Scale:")
        self.scale_edit = QLineEdit(str(self._scale))
        self.scale_button = QPushButton("Default")
        if self._default_scale == 0.0:
            self.scale.setVisible(False)
            self.scale_edit.setVisible(False)
            self.scale_button.setVisible(False)

        # Phase
        self.phase = QLabel("Phase (deg):")
        self.phase_edit = QLineEdit(str(self._phase))
        self.phase_button = QPushButton("Default")
        if self._default_phase is None:
            self.phase.setVisible(False)
            self.phase_edit.setVisible(False)
            self.phase_button.setVisible(False)
            self.phase_edit.setText('0.0')
        #tip = QtGui.QToolTip()
        #tip.setTe
        #self.format_edit.toolTip(tip)

        #---------------------------------------
        # nlabels
        self.nlabels = QLabel("Number of Labels:")
        self.nlabels_edit = QLineEdit(str(self._nlabels))
        self.nlabels_button = QPushButton("Default")

        self.labelsize = QLabel("Label Size:")
        self.labelsize_edit = QLineEdit(str(self._labelsize))
        self.labelsize_button = QPushButton("Default")

        self.ncolors = QLabel("Number of Colors:")
        self.ncolors_edit = QLineEdit(str(self._ncolors))
        self.ncolors_button = QPushButton("Default")

        self.colormap = QLabel("Color Map:")
        self.colormap_edit = QComboBox(self)
        self.colormap_button = QPushButton("Default")
        for key in colormap_keys:
            self.colormap_edit.addItem(key)
        self.colormap_edit.setCurrentIndex(colormap_keys.index(self._colormap))

        # --------------------------------------------------------------
        # the header
        self.grid2_title = QLabel("Color Scale:")

        # red/blue or blue/red
        self.low_to_high_radio = QRadioButton('Low -> High')
        self.high_to_low_radio = QRadioButton('High -> Low')
        widget = QWidget(self)
        low_to_high_group = QButtonGroup(widget)
        low_to_high_group.addButton(self.low_to_high_radio)
        low_to_high_group.addButton(self.high_to_low_radio)
        self.low_to_high_radio.setChecked(self._default_is_low_to_high)
        self.high_to_low_radio.setChecked(not self._default_is_low_to_high)

        # horizontal / vertical
        self.horizontal_radio = QRadioButton("Horizontal")
        self.vertical_radio = QRadioButton("Vertical")
        widget = QWidget(self)
        horizontal_vertical_group = QButtonGroup(widget)
        horizontal_vertical_group.addButton(self.horizontal_radio)
        horizontal_vertical_group.addButton(self.vertical_radio)
        self.horizontal_radio.setChecked(self._default_is_horizontal)
        self.vertical_radio.setChecked(not self._default_is_horizontal)

        # on / off
        self.show_radio = QRadioButton("Show")
        self.hide_radio = QRadioButton("Hide")
        widget = QWidget(self)
        show_hide_group = QButtonGroup(widget)
        show_hide_group.addButton(self.show_radio)
        show_hide_group.addButton(self.hide_radio)
        self.show_radio.setChecked(self._default_is_shown)
        self.hide_radio.setChecked(not self._default_is_shown)

        # --------------------------------------------------------------

        if self._is_normals:
            self.max.hide()
            self.min.hide()
            self.max_edit.hide()
            self.min_edit.hide()
            self.max_button.hide()
            self.min_button.hide()

            self.format.hide()
            self.format_edit.hide()
            self.format_button.hide()

            self.nlabels.hide()
            self.nlabels_edit.hide()
            self.nlabels_button.hide()

            self.ncolors.hide()
            self.ncolors_edit.hide()
            self.ncolors_button.hide()

            self.grid2_title.hide()
            self.vertical_radio.hide()
            self.horizontal_radio.hide()
            self.show_radio.hide()
            self.hide_radio.hide()
            self.low_to_high_radio.hide()
            self.high_to_low_radio.hide()

            self.colormap.hide()
            self.colormap_edit.hide()
            self.colormap_button.hide()

        self.animate_button = QPushButton('Create Animation')

        if self._default_scale == 0.0:
            self.animate_button.setEnabled(False)
            self.animate_button.setToolTip(
                'This must be a displacement-like result to animate')

        # closing
        self.apply_button = QPushButton("Apply")
        self.ok_button = QPushButton("OK")
        self.cancel_button = QPushButton("Cancel")

    def create_layout(self):
        """displays the menu objects"""
        grid = QGridLayout()
        grid.addWidget(self.name, 0, 0)
        grid.addWidget(self.name_edit, 0, 1)
        grid.addWidget(self.name_button, 0, 2)

        grid.addWidget(self.min, 1, 0)
        grid.addWidget(self.min_edit, 1, 1)
        grid.addWidget(self.min_button, 1, 2)

        grid.addWidget(self.max, 2, 0)
        grid.addWidget(self.max_edit, 2, 1)
        grid.addWidget(self.max_button, 2, 2)

        grid.addWidget(self.format, 3, 0)
        grid.addWidget(self.format_edit, 3, 1)
        grid.addWidget(self.format_button, 3, 2)

        grid.addWidget(self.scale, 4, 0)
        grid.addWidget(self.scale_edit, 4, 1)
        grid.addWidget(self.scale_button, 4, 2)

        grid.addWidget(self.phase, 5, 0)
        grid.addWidget(self.phase_edit, 5, 1)
        grid.addWidget(self.phase_button, 5, 2)

        grid.addWidget(self.nlabels, 6, 0)
        grid.addWidget(self.nlabels_edit, 6, 1)
        grid.addWidget(self.nlabels_button, 6, 2)

        #grid.addWidget(self.labelsize, 6, 0)
        #grid.addWidget(self.labelsize_edit, 6, 1)
        #grid.addWidget(self.labelsize_button, 6, 2)

        grid.addWidget(self.ncolors, 7, 0)
        grid.addWidget(self.ncolors_edit, 7, 1)
        grid.addWidget(self.ncolors_button, 7, 2)

        grid.addWidget(self.colormap, 8, 0)
        grid.addWidget(self.colormap_edit, 8, 1)
        grid.addWidget(self.colormap_button, 8, 2)

        ok_cancel_box = QHBoxLayout()
        ok_cancel_box.addWidget(self.apply_button)
        ok_cancel_box.addWidget(self.ok_button)
        ok_cancel_box.addWidget(self.cancel_button)

        grid2 = QGridLayout()
        grid2.addWidget(self.grid2_title, 0, 0)
        grid2.addWidget(self.low_to_high_radio, 1, 0)
        grid2.addWidget(self.high_to_low_radio, 2, 0)

        grid2.addWidget(self.vertical_radio, 1, 1)
        grid2.addWidget(self.horizontal_radio, 2, 1)

        grid2.addWidget(self.show_radio, 1, 2)
        grid2.addWidget(self.hide_radio, 2, 2)

        grid2.addWidget(self.animate_button, 3, 1)

        #grid2.setSpacing(0)

        vbox = QVBoxLayout()
        vbox.addLayout(grid)
        #vbox.addLayout(checkboxes)
        vbox.addLayout(grid2)
        vbox.addStretch()
        vbox.addLayout(ok_cancel_box)

        #Create central widget, add layout and set
        #central_widget = QtGui.QWidget()
        #central_widget.setLayout(vbox)
        #self.setCentralWidget(central_widget)
        self.setLayout(vbox)

    def set_connections(self):
        """creates the actions for the buttons"""
        self.name_button.clicked.connect(self.on_default_name)
        self.min_button.clicked.connect(self.on_default_min)
        self.max_button.clicked.connect(self.on_default_max)
        self.format_button.clicked.connect(self.on_default_format)
        self.scale_button.clicked.connect(self.on_default_scale)
        self.phase_button.clicked.connect(self.on_default_phase)

        self.nlabels_button.clicked.connect(self.on_default_nlabels)
        self.labelsize_button.clicked.connect(self.on_default_labelsize)
        self.ncolors_button.clicked.connect(self.on_default_ncolors)
        self.colormap_button.clicked.connect(self.on_default_colormap)

        self.animate_button.clicked.connect(self.on_animate)

        self.show_radio.clicked.connect(self.on_show_hide)
        self.hide_radio.clicked.connect(self.on_show_hide)

        self.apply_button.clicked.connect(self.on_apply)
        self.ok_button.clicked.connect(self.on_ok)
        self.cancel_button.clicked.connect(self.on_cancel)

        if qt_version == 4:
            self.connect(self, QtCore.SIGNAL('triggered()'), self.closeEvent)
            #self.colormap_edit.activated[str].connect(self.onActivated)
        #else:
        # closeEvent???

    def set_font_size(self, font_size):
        """
        Updates the font size of the objects

        Parameters
        ----------
        font_size : int
            the font size
        """
        if self.font_size == font_size:
            return
        self.font_size = font_size
        font = QFont()
        font.setPointSize(font_size)
        self.setFont(font)
        self.name_edit.setFont(font)
        self.min_edit.setFont(font)
        self.max_edit.setFont(font)
        self.format_edit.setFont(font)
        self.scale_edit.setFont(font)
        self.phase_edit.setFont(font)
        self.nlabels_edit.setFont(font)
        self.labelsize_edit.setFont(font)
        self.ncolors_edit.setFont(font)

    def on_animate(self):
        """opens the animation window"""
        name, flag0 = self.check_name(self.name_edit)
        if not flag0:
            return

        scale, flag1 = self.check_float(self.scale_edit)
        if not flag1:
            scale = self._scale

        data = {
            'font_size': self.out_data['font_size'],
            'icase': self._icase,
            'name': name,
            'time': 2,
            'frames/sec': 30,
            'resolution': 1,
            'iframe': 0,
            'scale': scale,
            'default_scale': self._default_scale,
            'is_scale': self._default_phase is None,
            'phase': self._phase,
            'default_phase': self._default_phase,
            'dirname': os.path.abspath(os.getcwd()),
            'clicked_ok': False,
            'close': False,
        }
        if not self._animation_window_shown:
            self._animation_window = AnimationWindow(data, win_parent=self)
            self._animation_window.show()
            self._animation_window_shown = True
            self._animation_window.exec_()
        else:
            self._animation_window.activateWindow()

        if data['close']:
            if not self._animation_window._updated_animation:
                #self._apply_animation(data)
                pass
            self._animation_window_shown = False
            del self._animation_window
        else:
            self._animation_window.activateWindow()

    def on_default_name(self):
        """action when user clicks 'Default' for name"""
        name = str(self._default_name)
        self.name_edit.setText(name)
        self.name_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_min(self):
        """action when user clicks 'Default' for min value"""
        self.min_edit.setText(str(self._default_min))
        self.min_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_max(self):
        """action when user clicks 'Default' for max value"""
        self.max_edit.setText(str(self._default_max))
        self.max_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_format(self):
        """action when user clicks 'Default' for the number format"""
        self.format_edit.setText(str(self._default_format))
        self.format_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_scale(self):
        """action when user clicks 'Default' for scale factor"""
        self.scale_edit.setText(str(self._default_scale))
        self.scale_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_phase(self):
        """action when user clicks 'Default' for phase angle"""
        self.phase_edit.setText(str(self._default_phase))
        self.phase_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_ncolors(self):
        """action when user clicks 'Default' for number of colors"""
        self.ncolors_edit.setText(str(self._default_ncolors))
        self.ncolors_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_colormap(self):
        """action when user clicks 'Default' for the color map"""
        self.colormap_edit.setCurrentIndex(
            colormap_keys.index(self._default_colormap))

    def on_default_nlabels(self):
        """action when user clicks 'Default' for number of labels"""
        self.nlabels_edit.setStyleSheet("QLineEdit{background: white;}")
        self.nlabels_edit.setText(str(self._default_nlabels))

    def on_default_labelsize(self):
        """action when user clicks 'Default' for number of labelsize"""
        self.labelsize_edit.setText(str(self._default_labelsize))
        self.labelsize_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_show_hide(self):
        """action when user clicks the 'Show/Hide' radio button"""
        self.colormap_edit.setCurrentIndex(
            colormap_keys.index(self._default_colormap))
        is_shown = self.show_radio.isChecked()
        self.vertical_radio.setEnabled(is_shown)
        self.horizontal_radio.setEnabled(is_shown)

    @staticmethod
    def check_name(cell):
        cell_value = cell.text()
        try:
            text = str(cell_value).strip()
        except UnicodeEncodeError:
            cell.setStyleSheet("QLineEdit{background: red;}")
            return None, False

        if len(text):
            cell.setStyleSheet("QLineEdit{background: white;}")
            return text, True
        else:
            cell.setStyleSheet("QLineEdit{background: red;}")
            return None, False

    @staticmethod
    def check_colormap(cell):
        text = str(cell.text()).strip()
        if text in colormap_keys:
            cell.setStyleSheet("QLineEdit{background: white;}")
            return text, True
        else:
            cell.setStyleSheet("QLineEdit{background: red;}")
            return None, False

    def on_validate(self):
        name_value, flag0 = self.check_name(self.name_edit)
        min_value, flag1 = self.check_float(self.min_edit)
        max_value, flag2 = self.check_float(self.max_edit)
        format_value, flag3 = self.check_format(self.format_edit)
        scale, flag4 = self.check_float(self.scale_edit)
        phase, flag5 = self.check_float(self.phase_edit)

        nlabels, flag6 = self.check_positive_int_or_blank(self.nlabels_edit)
        ncolors, flag7 = self.check_positive_int_or_blank(self.ncolors_edit)
        labelsize, flag8 = self.check_positive_int_or_blank(
            self.labelsize_edit)
        colormap = str(self.colormap_edit.currentText())

        if all([flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7,
                flag8]):
            if 'i' in format_value:
                format_value = '%i'

            assert isinstance(scale, float), scale
            self.out_data['name'] = name_value
            self.out_data['min'] = min_value
            self.out_data['max'] = max_value
            self.out_data['format'] = format_value
            self.out_data['scale'] = scale
            self.out_data['phase'] = phase

            self.out_data['nlabels'] = nlabels
            self.out_data['ncolors'] = ncolors
            self.out_data['labelsize'] = labelsize
            self.out_data['colormap'] = colormap

            self.out_data['is_low_to_high'] = self.low_to_high_radio.isChecked(
            )
            self.out_data['is_horizontal'] = self.horizontal_radio.isChecked()
            self.out_data['is_shown'] = self.show_radio.isChecked()

            self.out_data['clicked_ok'] = True
            self.out_data['close'] = True
            #print('self.out_data = ', self.out_data)
            #print("name = %r" % self.name_edit.text())
            #print("min = %r" % self.min_edit.text())
            #print("max = %r" % self.max_edit.text())
            #print("format = %r" % self.format_edit.text())
            return True
        return False

    def on_apply(self):
        passed = self.on_validate()
        if passed:
            self.win_parent._apply_legend(self.out_data)
        return passed

    def on_ok(self):
        passed = self.on_apply()
        if passed:
            self.close()
            #self.destroy()

    def on_cancel(self):
        self.out_data['close'] = True
        self.close()
Пример #26
0
class KernelConnectionDialog(QDialog):
    """Dialog to connect to existing kernels (either local or remote)."""

    def __init__(self, parent=None):
        super(KernelConnectionDialog, self).__init__(parent)
        self.setWindowTitle(_('Connect to an existing kernel'))

        main_label = QLabel(_(
            "<p>Please select the JSON connection file (<i>e.g.</i> "
            "<tt>kernel-1234.json</tt>) of the existing kernel, and enter "
            "the SSH information if connecting to a remote machine. "
            "To learn more about starting external kernels and connecting "
            "to them, see <a href=\"https://docs.spyder-ide.org/"
            "ipythonconsole.html#connect-to-an-external-kernel\">"
            "our documentation</a>.</p>"))
        main_label.setWordWrap(True)
        main_label.setAlignment(Qt.AlignJustify)
        main_label.setOpenExternalLinks(True)

        # Connection file
        cf_label = QLabel(_('Connection file:'))
        self.cf = QLineEdit()
        self.cf.setPlaceholderText(_('Kernel connection file path'))
        self.cf.setMinimumWidth(350)
        cf_open_btn = QPushButton(_('Browse'))
        cf_open_btn.clicked.connect(self.select_connection_file)

        cf_layout = QHBoxLayout()
        cf_layout.addWidget(cf_label)
        cf_layout.addWidget(self.cf)
        cf_layout.addWidget(cf_open_btn)

        # Remote kernel groupbox
        self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)"))

        # SSH connection
        hn_label = QLabel(_('Hostname:'))
        self.hn = QLineEdit()
        pn_label = QLabel(_('Port:'))
        self.pn = QLineEdit()
        self.pn.setMaximumWidth(75)

        un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:'))

        self.pw = QLineEdit()
        self.pw.setEchoMode(QLineEdit.Password)
        self.pw_radio.toggled.connect(self.pw.setEnabled)
        self.kf_radio.toggled.connect(self.pw.setDisabled)

        self.kf = QLineEdit()
        kf_open_btn = QPushButton(_('Browse'))
        kf_open_btn.clicked.connect(self.select_ssh_key)
        kf_layout = QHBoxLayout()
        kf_layout.addWidget(self.kf)
        kf_layout.addWidget(kf_open_btn)

        kfp_label = QLabel(_('Passphase:'))
        self.kfp = QLineEdit()
        self.kfp.setPlaceholderText(_('Optional'))
        self.kfp.setEchoMode(QLineEdit.Password)

        self.kf_radio.toggled.connect(self.kf.setEnabled)
        self.kf_radio.toggled.connect(self.kfp.setEnabled)
        self.kf_radio.toggled.connect(kf_open_btn.setEnabled)
        self.kf_radio.toggled.connect(kfp_label.setEnabled)
        self.pw_radio.toggled.connect(self.kf.setDisabled)
        self.pw_radio.toggled.connect(self.kfp.setDisabled)
        self.pw_radio.toggled.connect(kf_open_btn.setDisabled)
        self.pw_radio.toggled.connect(kfp_label.setDisabled)

        # SSH layout
        ssh_layout = QGridLayout()
        ssh_layout.addWidget(hn_label, 0, 0, 1, 2)
        ssh_layout.addWidget(self.hn, 0, 2)
        ssh_layout.addWidget(pn_label, 0, 3)
        ssh_layout.addWidget(self.pn, 0, 4)
        ssh_layout.addWidget(un_label, 1, 0, 1, 2)
        ssh_layout.addWidget(self.un, 1, 2, 1, 3)

        # SSH authentication layout
        auth_layout = QGridLayout()
        auth_layout.addWidget(self.pw_radio, 1, 0)
        auth_layout.addWidget(pw_label, 1, 1)
        auth_layout.addWidget(self.pw, 1, 2)
        auth_layout.addWidget(self.kf_radio, 2, 0)
        auth_layout.addWidget(kf_label, 2, 1)
        auth_layout.addLayout(kf_layout, 2, 2)
        auth_layout.addWidget(kfp_label, 3, 1)
        auth_layout.addWidget(self.kfp, 3, 2)
        auth_group.setLayout(auth_layout)

        # Remote kernel layout
        rm_layout = QVBoxLayout()
        rm_layout.addLayout(ssh_layout)
        rm_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        rm_layout.addWidget(auth_group)
        self.rm_group.setLayout(rm_layout)
        self.rm_group.setCheckable(True)
        self.rm_group.toggled.connect(self.pw_radio.setChecked)

        # Ok and Cancel buttons
        self.accept_btns = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel,
            Qt.Horizontal, self)

        self.accept_btns.accepted.connect(self.save_connection_settings)
        self.accept_btns.accepted.connect(self.accept)
        self.accept_btns.rejected.connect(self.reject)

        # Save connection settings checkbox
        self.save_layout = QCheckBox(self)
        self.save_layout.setText(_("Save connection settings"))

        btns_layout = QHBoxLayout()
        btns_layout.addWidget(self.save_layout)
        btns_layout.addWidget(self.accept_btns)

        # Dialog layout
        layout = QVBoxLayout(self)
        layout.addWidget(main_label)
        layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        layout.addLayout(cf_layout)
        layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12)))
        layout.addWidget(self.rm_group)
        layout.addLayout(btns_layout)

        self.load_connection_settings()

    def load_connection_settings(self):
        """Load the user's previously-saved kernel connection settings."""
        existing_kernel = CONF.get("existing-kernel", "settings", {})

        connection_file_path = existing_kernel.get("json_file_path", "")
        is_remote = existing_kernel.get("is_remote", False)
        username = existing_kernel.get("username", "")
        hostname = existing_kernel.get("hostname", "")
        port = str(existing_kernel.get("port", 22))
        is_ssh_kf = existing_kernel.get("is_ssh_keyfile", False)
        ssh_kf = existing_kernel.get("ssh_key_file_path", "")

        if connection_file_path != "":
            self.cf.setText(connection_file_path)
        if username != "":
            self.un.setText(username)
        if hostname != "":
            self.hn.setText(hostname)
        if ssh_kf != "":
            self.kf.setText(ssh_kf)
        self.rm_group.setChecked(is_remote)
        self.pn.setText(port)
        self.kf_radio.setChecked(is_ssh_kf)
        self.pw_radio.setChecked(not is_ssh_kf)

        try:
            import keyring
            ssh_passphrase = keyring.get_password("spyder_remote_kernel",
                                                  "ssh_key_passphrase")
            ssh_password = keyring.get_password("spyder_remote_kernel",
                                                "ssh_password")
            if ssh_passphrase:
                self.kfp.setText(ssh_passphrase)
            if ssh_password:
                self.pw.setText(ssh_password)
        except Exception:
            pass

    def save_connection_settings(self):
        """Save user's kernel connection settings."""

        if not self.save_layout.isChecked():
            return

        is_ssh_key = bool(self.kf_radio.isChecked())
        connection_settings = {
            "json_file_path": self.cf.text(),
            "is_remote": self.rm_group.isChecked(),
            "username": self.un.text(),
            "hostname": self.hn.text(),
            "port": self.pn.text(),
            "is_ssh_keyfile": is_ssh_key,
            "ssh_key_file_path": self.kf.text()
        }
        CONF.set("existing-kernel", "settings", connection_settings)

        try:
            import keyring
            if is_ssh_key:
                keyring.set_password("spyder_remote_kernel",
                                     "ssh_key_passphrase",
                                     self.kfp.text())
            else:
                keyring.set_password("spyder_remote_kernel",
                                     "ssh_password",
                                     self.pw.text())
        except Exception:
            pass

    def select_connection_file(self):
        cf = getopenfilename(self, _('Select kernel connection file'),
                             jupyter_runtime_dir(), '*.json;;*.*')[0]
        self.cf.setText(cf)

    def select_ssh_key(self):
        kf = getopenfilename(self, _('Select SSH keyfile'),
                             get_home_dir(), '*.pem;;*')[0]
        self.kf.setText(kf)

    @staticmethod
    def get_connection_parameters(parent=None, dialog=None):
        if not dialog:
            dialog = KernelConnectionDialog(parent)
        result = dialog.exec_()
        is_remote = bool(dialog.rm_group.isChecked())
        accepted = result == QDialog.Accepted

        if is_remote:
            def falsy_to_none(arg):
                return arg if arg else None
            if dialog.hn.text() and dialog.un.text():
                port = dialog.pn.text() if dialog.pn.text() else '22'
                hostname = "{0}@{1}:{2}".format(dialog.un.text(),
                                                dialog.hn.text(),
                                                port)
            else:
                hostname = None
            if dialog.pw_radio.isChecked():
                password = falsy_to_none(dialog.pw.text())
                keyfile = None
            elif dialog.kf_radio.isChecked():
                keyfile = falsy_to_none(dialog.kf.text())
                password = falsy_to_none(dialog.kfp.text())
            else:  # imposible?
                keyfile = None
                password = None
            return (dialog.cf.text(), hostname, keyfile, password, accepted)
        else:
            path = dialog.cf.text()
            _dir, filename = osp.dirname(path), osp.basename(path)
            if _dir == '' and not filename.endswith('.json'):
                path = osp.join(jupyter_runtime_dir(), 'kernel-'+path+'.json')
            return (path, None, None, None, accepted)
Пример #27
0
class ImageRotationDialog(ExToolWindow):

    def __init__(self, signal, axes, parent, plugin):
        super(ImageRotationDialog, self).__init__(parent)
        self.ui = parent
        self.create_controls()
        self.accepted.connect(self.ok)
        self.rejected.connect(self.close_new)
        self.signal = signal
        self.plugin = plugin
        self.new_out = None
        self._connected_updates = False
        if isinstance(axes, str):
            axm = signal.signal.axes_manager
            if axes.startswith("nav"):
                axes = (axm._axes.index(axm.navigation_axes[0]),
                        axm._axes.index(axm.navigation_axes[1]))
            elif axes.startswith("sig"):
                axes = (axm._axes.index(axm.signal_axes[0]),
                        axm._axes.index(axm.signal_axes[1]))
        self.axes = axes
        self.setWindowTitle(tr("Rotate"))

        # TODO: TAG: Functionality check
        if not hasattr(signal.signal, 'events'):
            self.gbo_preview.setVisible(False)

        # TODO: Add dynamic rotation, e.g. one that rotates when source
        # signal's data_changed event triggers

    def connect(self):
        # TODO: Don't have to con/dis those in gbo
        self.opt_new.toggled.connect(self.close_new)
        self.num_angle.valueChanged.connect(self.update)
        self.chk_grid.toggled.connect(self.update)
        self.num_grid.valueChanged.connect(self.update)
        self.chk_reshape.toggled.connect(self.update)
        self.opt_new.toggled.connect(self.update)
        self.opt_replace.toggled.connect(self.update)

    def disconnect(self):
        self.num_angle.valueChanged.disconnect(self.update)
        self.chk_grid.toggled.disconnect(self.update)
        self.num_grid.valueChanged.disconnect(self.update)
        self.chk_reshape.toggled.disconnect(self.update)
        self.opt_new.toggled.disconnect(self.update)
        self.opt_replace.toggled.disconnect(self.update)

    def ok(self):
        # Draw figure if not already done
        # TODO: TAG: Functionality check
        if not hasattr(self.signal.signal, 'events') or \
                not self.gbo_preview.isChecked():
            self.update()
        angle = self.num_angle.value()
        reshape = self.chk_reshape.isChecked()
        self.plugin.record_code(
            r"<p>.rotate_signal({0}, reshape={1}, axes={2})".format(
                angle, reshape, self.axes))
        # Clean up event connections
        if self.new_out is not None:
            self.connect_update_plot(self.new_out.signal, disconnect=True)

    def close_new(self, value=False):
        if self.new_out is not None and not value:
            self.new_out.close()
            self.new_out = None
            self._connected_updates = False

    def set_preview(self, value):
        if not hasattr(self.signal.signal, 'events'):
            return
        if value:
            self.connect()
            self.update()
        else:
            self.disconnect()
            self.close_new()

    def _axes_in_nav(self):
        axm = self.signal.signal.axes_manager
        navidx = [axm._axes.index(ax) for ax in axm.navigation_axes]
        if self.axes[0] in navidx:
            return True
        return False

    def connect_update_plot(self, signal, disconnect=False):
        if self._connected_updates != disconnect:
            return  # Nothing to do, prevent double connections
        if self._axes_in_nav():
            f = signal._plot.navigator_plot.update
        else:
            f = signal._plot.signal_plot.update

        # TODO: TAG: Functionality check
        if hasattr(signal, 'events') and hasattr(
                signal.events, 'data_changed'):
            if disconnect:
                signal.events.data_changed.disconnect(f)
            else:
                signal.events.data_changed.connect(f, [])
        self._connected_updates = not disconnect

    def update(self):
        angle = self.num_angle.value()
        reshape = self.chk_reshape.isChecked()
        if self.opt_new.isChecked():
            if self.new_out is None:
                out = None
            else:
                out = self.new_out.signal
        elif self.opt_replace.isChecked():
            out = self.signal.signal
        else:
            return  # Indeterminate state, do nothing

        s = self.plugin.rotate_signal(angle, self.signal.signal, record=False,
                                      reshape=reshape, out=out, axes=self.axes)

        if out is None:
            s.metadata.General.title = self.signal.name + "[Rotated]"
            s.plot()
            self.connect_update_plot(s)
            if (self.gbo_preview.isChecked() and self.opt_new.isChecked() and
                                                         self.new_out is None):
                self.new_out = self.ui.lut_signalwrapper[s]
        else:
            s = out

        if self.chk_grid.isChecked() is True:
            pass    # TODO: Draw grid

    def create_controls(self):
        """
        Create UI controls.
        """
        vbox = QVBoxLayout()

        form = QFormLayout()
        self.num_angle = QDoubleSpinBox()
        self.num_angle.setValue(0.0)
        self.num_angle.setMinimum(-360)
        self.num_angle.setMaximum(360)
        form.addRow(tr("Angle:"), self.num_angle)
        vbox.addLayout(form)

        self.gbo_preview = QGroupBox(tr("Preview"))
        self.gbo_preview.setCheckable(True)
        self.gbo_preview.setChecked(False)
        gbo_vbox = QVBoxLayout()
        self.chk_grid = QCheckBox(tr("Grid"))
        self.chk_grid.setChecked(False)
        self.num_grid = QSpinBox()
        self.num_grid.setValue(4)
        self.num_grid.setMinimum(1)
        self.num_grid.setEnabled(False)
        self.chk_grid.toggled[bool].connect(self.num_grid.setEnabled)
        gbo_vbox.addWidget(self.chk_grid)
        gbo_vbox.addWidget(self.num_grid)
        self.gbo_preview.setLayout(gbo_vbox)
        vbox.addWidget(self.gbo_preview)

        self.gbo_preview.toggled[bool].connect(self.set_preview)

        self.gbo_output = QGroupBox(tr("Output"))
        self.opt_new = QRadioButton(tr("New signal"))
        self.opt_replace = QRadioButton(tr("In place"))
        self.opt_new.setChecked(True)
        gbo_vbox2 = QVBoxLayout()
        gbo_vbox2.addWidget(self.opt_new)
        gbo_vbox2.addWidget(self.opt_replace)
        self.gbo_output.setLayout(gbo_vbox2)
        vbox.addWidget(self.gbo_output)

        self.chk_reshape = QCheckBox(tr("Resize to fit"))
        self.chk_reshape.setChecked(False)
        vbox.addWidget(self.chk_reshape)

        self.btn_ok = QPushButton(tr("&OK"))
        self.btn_ok.setDefault(True)
        self.btn_ok.clicked.connect(self.accept)
        self.btn_cancel = QPushButton(tr("&Cancel"))
        self.btn_cancel.clicked.connect(self.reject)
        hbox = QHBoxLayout()
        hbox.addWidget(self.btn_ok)
        hbox.addWidget(self.btn_cancel)
        vbox.addLayout(hbox)

        vbox.addStretch(1)
        self.setLayout(vbox)
Пример #28
0
class MCSDialog(QDialog):
    """A dialog to perform minimal cut set computation"""

    def __init__(self, appdata: CnaData, centralwidget):
        QDialog.__init__(self)
        self.setWindowTitle("Minimal Cut Sets Computation")

        self.appdata = appdata
        self.centralwidget = centralwidget
        self.eng = appdata.engine
        self.out = io.StringIO()
        self.err = io.StringIO()

        self.layout = QVBoxLayout()
        l1 = QLabel("Target Region(s)")
        self.layout.addWidget(l1)
        s1 = QHBoxLayout()

        completer = QCompleter(
            self.appdata.project.cobra_py_model.reactions.list_attr("id"), self)
        completer.setCaseSensitivity(Qt.CaseInsensitive)

        self.target_list = QTableWidget(1, 4)
        self.target_list.setHorizontalHeaderLabels(
            ["region no", "T", "≥/≤", "t"])
        self.target_list.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.target_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed)
        self.target_list.horizontalHeader().resizeSection(0, 100)
        self.target_list.horizontalHeader().setSectionResizeMode(2, QHeaderView.Fixed)
        self.target_list.horizontalHeader().resizeSection(2, 50)
        item = QLineEdit("1")
        self.target_list.setCellWidget(0, 0, item)
        item2 = QLineEdit("")
        item2.setCompleter(completer)
        self.target_list.setCellWidget(0, 1, item2)
        combo = QComboBox(self.target_list)
        combo.insertItem(1, "≤")
        combo.insertItem(2, "≥")
        self.target_list.setCellWidget(0, 2, combo)
        item = QLineEdit("0")
        self.target_list.setCellWidget(0, 3, item)

        s1.addWidget(self.target_list)

        s11 = QVBoxLayout()
        self.add_target = QPushButton("+")
        self.add_target.clicked.connect(self.add_target_region)
        self.rem_target = QPushButton("-")
        self.rem_target.clicked.connect(self.rem_target_region)
        s11.addWidget(self.add_target)
        s11.addWidget(self.rem_target)
        s1.addItem(s11)
        self.layout.addItem(s1)

        l2 = QLabel("Desired Region(s)")
        self.layout.addWidget(l2)
        s2 = QHBoxLayout()
        self.desired_list = QTableWidget(1, 4)
        self.desired_list.setHorizontalHeaderLabels(
            ["region no", "D", "≥/≤", "d"])
        self.desired_list.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.desired_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed)
        self.desired_list.horizontalHeader().resizeSection(0, 100)
        self.desired_list.horizontalHeader().setSectionResizeMode(2, QHeaderView.Fixed)
        self.desired_list.horizontalHeader().resizeSection(2, 50)
        item = QLineEdit("1")
        self.desired_list.setCellWidget(0, 0, item)
        item2 = QLineEdit("")
        item2.setCompleter(completer)
        self.desired_list.setCellWidget(0, 1, item2)
        combo = QComboBox(self.desired_list)
        combo.insertItem(1, "≤")
        combo.insertItem(2, "≥")
        self.desired_list.setCellWidget(0, 2, combo)
        item = QLineEdit("0")
        self.desired_list.setCellWidget(0, 3, item)
        s2.addWidget(self.desired_list)

        s21 = QVBoxLayout()
        self.add_desire = QPushButton("+")
        self.add_desire.clicked.connect(self.add_desired_region)
        self.rem_desire = QPushButton("-")
        self.rem_desire.clicked.connect(self.rem_desired_region)
        s21.addWidget(self.add_desire)
        s21.addWidget(self.rem_desire)
        s2.addItem(s21)
        self.layout.addItem(s2)

        s3 = QHBoxLayout()

        sgx = QVBoxLayout()
        self.gen_kos = QCheckBox("Gene KOs")
        self.exclude_boundary = QCheckBox(
            "Exclude boundary\nreactions as cuts")
        sg1 = QHBoxLayout()
        s31 = QVBoxLayout()
        l = QLabel("Max. Solutions")
        s31.addWidget(l)
        l = QLabel("Max. Size")
        s31.addWidget(l)
        l = QLabel("Time Limit [sec]")
        s31.addWidget(l)

        sg1.addItem(s31)

        s32 = QVBoxLayout()
        self.max_solu = QLineEdit("inf")
        self.max_solu.setMaximumWidth(50)
        s32.addWidget(self.max_solu)
        self.max_size = QLineEdit("7")
        self.max_size.setMaximumWidth(50)
        s32.addWidget(self.max_size)
        self.time_limit = QLineEdit("inf")
        self.time_limit.setMaximumWidth(50)
        s32.addWidget(self.time_limit)

        sg1.addItem(s32)
        sgx.addWidget(self.gen_kos)
        sgx.addWidget(self.exclude_boundary)
        sgx.addItem(sg1)
        s3.addItem(sgx)

        g3 = QGroupBox("Solver")
        s33 = QVBoxLayout()
        self.bg1 = QButtonGroup()
        optlang_solver_name = interface_to_str(
            appdata.project.cobra_py_model.problem)
        self.solver_optlang = QRadioButton(f"{optlang_solver_name} (optlang)")
        self.solver_optlang.setToolTip(
            "Uses the solver specified by the current model.")
        s33.addWidget(self.solver_optlang)
        self.bg1.addButton(self.solver_optlang)
        self.solver_cplex_matlab = QRadioButton("CPLEX (MATLAB)")
        self.solver_cplex_matlab.setToolTip(
            "Only enabled with MATLAB and CPLEX")
        s33.addWidget(self.solver_cplex_matlab)
        self.bg1.addButton(self.solver_cplex_matlab)
        self.solver_cplex_java = QRadioButton("CPLEX (Octave)")
        self.solver_cplex_java.setToolTip("Only enabled with Octave and CPLEX")
        s33.addWidget(self.solver_cplex_java)
        self.bg1.addButton(self.solver_cplex_java)
        self.solver_intlinprog = QRadioButton("intlinprog (MATLAB)")
        self.solver_intlinprog.setToolTip("Only enabled with MATLAB")
        s33.addWidget(self.solver_intlinprog)
        self.bg1.addButton(self.solver_intlinprog)
        self.solver_glpk = QRadioButton("GLPK (Octave/MATLAB)")
        s33.addWidget(self.solver_glpk)
        self.bg1.addButton(self.solver_glpk)
        self.bg1.buttonClicked.connect(self.configure_solver_options)
        g3.setLayout(s33)
        s3.addWidget(g3)

        g4 = QGroupBox("MCS search")
        s34 = QVBoxLayout()
        self.bg2 = QButtonGroup()
        self.any_mcs = QRadioButton("any MCS (fast)")
        self.any_mcs.setChecked(True)
        s34.addWidget(self.any_mcs)
        self.bg2.addButton(self.any_mcs)

        # Search type: by cardinality only with CPLEX possible
        self.mcs_by_cardinality = QRadioButton("by cardinality")
        s34.addWidget(self.mcs_by_cardinality)
        self.bg2.addButton(self.mcs_by_cardinality)

        self.smalles_mcs_first = QRadioButton("smallest MCS first")
        s34.addWidget(self.smalles_mcs_first)
        self.bg2.addButton(self.smalles_mcs_first)
        g4.setLayout(s34)

        s3.addWidget(g4)
        self.layout.addItem(s3)

        # Disable incompatible combinations
        if appdata.selected_engine == 'None':
            self.solver_optlang.setChecked(True)
            self.solver_cplex_matlab.setEnabled(False)
            self.solver_cplex_java.setEnabled(False)
            self.solver_glpk.setEnabled(False)
            self.solver_intlinprog.setEnabled(False)
            if optlang_solver_name != 'cplex':
                self.mcs_by_cardinality.setEnabled(False)
        else:
            self.solver_glpk.setChecked(True)
            if not self.eng.is_cplex_matlab_ready():
                self.solver_cplex_matlab.setEnabled(False)
            if not self.eng.is_cplex_java_ready():
                self.solver_cplex_java.setEnabled(False)
            if self.appdata.is_matlab_set():
                self.solver_cplex_java.setEnabled(False)
            if not self.appdata.is_matlab_set():
                self.solver_cplex_matlab.setEnabled(False)
                self.solver_intlinprog.setEnabled(False)
        self.configure_solver_options()

        s4 = QVBoxLayout()
        self.consider_scenario = QCheckBox(
            "Consider constraint given by scenario")
        s4.addWidget(self.consider_scenario)
        self.advanced = QCheckBox(
            "Advanced: Define knockout/addition costs for genes/reactions")
        self.advanced.setEnabled(False)
        s4.addWidget(self.advanced)
        self.layout.addItem(s4)

        buttons = QHBoxLayout()
        # self.save = QPushButton("save")
        # buttons.addWidget(self.save)
        # self.load = QPushButton("load")
        # buttons.addWidget(self.load)
        self.compute_mcs = QPushButton("Compute MCS")
        buttons.addWidget(self.compute_mcs)
        # self.compute_mcs2 = QPushButton("Compute MCS2")
        # buttons.addWidget(self.compute_mcs2)
        self.cancel = QPushButton("Close")
        buttons.addWidget(self.cancel)
        self.layout.addItem(buttons)

        # max width for buttons
        self.add_target.setMaximumWidth(20)
        self.rem_target.setMaximumWidth(20)
        self.add_desire.setMaximumWidth(20)
        self.rem_desire.setMaximumWidth(20)

        self.setLayout(self.layout)

        # Connecting the signal
        self.cancel.clicked.connect(self.reject)
        self.compute_mcs.clicked.connect(self.compute)

    @Slot()
    def configure_solver_options(self):
        optlang_solver_name = interface_to_str(
            self.appdata.project.cobra_py_model.problem)
        if self.solver_optlang.isChecked():
            self.gen_kos.setChecked(False)
            self.gen_kos.setEnabled(False)
            self.exclude_boundary.setEnabled(True)
            if optlang_solver_name != 'cplex':
                if self.mcs_by_cardinality.isChecked():
                    self.mcs_by_cardinality.setChecked(False)
                    self.any_mcs.setChecked(True)
                self.mcs_by_cardinality.setEnabled(False)
                self.mcs_by_cardinality.setChecked(False)

        else:
            self.gen_kos.setEnabled(True)
            self.exclude_boundary.setChecked(False)
            self.exclude_boundary.setEnabled(False)
            self.mcs_by_cardinality.setEnabled(True)

    def add_target_region(self):
        i = self.target_list.rowCount()
        self.target_list.insertRow(i)

        completer = QCompleter(
            self.appdata.project.cobra_py_model.reactions.list_attr("id"), self)
        completer.setCaseSensitivity(Qt.CaseInsensitive)

        item = QLineEdit("1")
        self.target_list.setCellWidget(i, 0, item)
        item2 = QLineEdit("")
        item2.setCompleter(completer)
        self.target_list.setCellWidget(i, 1, item2)
        combo = QComboBox(self.target_list)
        combo.insertItem(1, "≤")
        combo.insertItem(2, "≥")
        self.target_list.setCellWidget(i, 2, combo)
        item = QLineEdit("0")
        self.target_list.setCellWidget(i, 3, item)

    def add_desired_region(self):
        i = self.desired_list.rowCount()
        self.desired_list.insertRow(i)

        completer = QCompleter(
            self.appdata.project.cobra_py_model.reactions.list_attr("id"), self)
        completer.setCaseSensitivity(Qt.CaseInsensitive)

        item = QLineEdit("1")
        self.desired_list.setCellWidget(i, 0, item)
        item2 = QLineEdit("")
        item2.setCompleter(completer)
        self.desired_list.setCellWidget(i, 1, item2)
        combo = QComboBox(self.desired_list)
        combo.insertItem(1, "≤")
        combo.insertItem(2, "≥")
        self.desired_list.setCellWidget(i, 2, combo)
        item = QLineEdit("0")
        self.desired_list.setCellWidget(i, 3, item)

    def rem_target_region(self):
        i = self.target_list.rowCount()
        self.target_list.removeRow(i-1)

    def rem_desired_region(self):
        i = self.desired_list.rowCount()
        self.desired_list.removeRow(i-1)

    def compute(self):
        if self.solver_optlang.isChecked():
            self.compute_optlang()
        else:
            self.compute_legacy()

    def compute_legacy(self):
        self.setCursor(Qt.BusyCursor)
        # create CobraModel for matlab
        with self.appdata.project.cobra_py_model as model:
            if self.consider_scenario.isChecked():  # integrate scenario into model bounds
                for r in self.appdata.project.scen_values.keys():
                    model.reactions.get_by_id(
                        r).bounds = self.appdata.project.scen_values[r]
            cobra.io.save_matlab_model(model, os.path.join(
                self.appdata.cna_path, "cobra_model.mat"), varname="cbmodel")
        self.eng.eval("load('cobra_model.mat')",
                      nargout=0)

        try:
            self.eng.eval("cnap = CNAcobra2cna(cbmodel);",
                          nargout=0,
                          stdout=self.out, stderr=self.err)
        except Exception:
            output = io.StringIO()
            traceback.print_exc(file=output)
            exstr = output.getvalue()
            print(exstr)
            QMessageBox.warning(self, 'Unknown exception occured!',
                                exstr+'\nPlease report the problem to:\n\
                                    \nhttps://github.com/cnapy-org/CNApy/issues')
            return

        self.eng.eval("genes = [];", nargout=0,
                      stdout=self.out, stderr=self.err)
        cmd = "maxSolutions = " + str(float(self.max_solu.text())) + ";"
        self.eng.eval(cmd, nargout=0, stdout=self.out, stderr=self.err)

        cmd = "maxSize = " + str(int(self.max_size.text())) + ";"
        self.eng.eval(cmd, nargout=0, stdout=self.out, stderr=self.err)

        cmd = "milp_time_limit = " + str(float(self.time_limit.text())) + ";"
        self.eng.eval(cmd, nargout=0, stdout=self.out, stderr=self.err)

        if self.gen_kos.isChecked():
            self.eng.eval("gKOs = 1;", nargout=0)
        else:
            self.eng.eval("gKOs = 0;", nargout=0)
        if self.advanced.isChecked():
            self.eng.eval("advanced_on = 1;", nargout=0)
        else:
            self.eng.eval("advanced_on = 0;", nargout=0)

        if self.solver_intlinprog.isChecked():
            self.eng.eval("solver = 'intlinprog';", nargout=0)
        if self.solver_cplex_java.isChecked():
            self.eng.eval("solver = 'java_cplex_new';", nargout=0)
        if self.solver_cplex_matlab.isChecked():
            self.eng.eval("solver = 'matlab_cplex';", nargout=0)
        if self.solver_glpk.isChecked():
            self.eng.eval("solver = 'glpk';", nargout=0)
        if self.any_mcs.isChecked():
            self.eng.eval("mcs_search_mode = 'search_1';", nargout=0)
        elif self.mcs_by_cardinality.isChecked():
            self.eng.eval("mcs_search_mode = 'search_2';", nargout=0)
        elif self.smalles_mcs_first.isChecked():
            self.eng.eval("mcs_search_mode = 'search_3';", nargout=0)

        rows = self.target_list.rowCount()
        for i in range(0, rows):
            p1 = self.target_list.cellWidget(i, 0).text()
            p2 = self.target_list.cellWidget(i, 1).text()
            if self.target_list.cellWidget(i, 2).currentText() == '≤':
                p3 = "<="
            else:
                p3 = ">="
            p4 = self.target_list.cellWidget(i, 3).text()
            cmd = "dg_T = {[" + p1+"], '" + p2 + \
                "', '" + p3 + "', [" + p4 + "']};"
            self.eng.eval(cmd, nargout=0,
                          stdout=self.out, stderr=self.err)

        rows = self.desired_list.rowCount()
        for i in range(0, rows):
            p1 = self.desired_list.cellWidget(i, 0).text()
            p2 = self.desired_list.cellWidget(i, 1).text()
            if self.desired_list.cellWidget(i, 2).currentText() == '≤':
                p3 = "<="
            else:
                p3 = ">="
            p4 = self.desired_list.cellWidget(i, 3).text()
            cmd = "dg_D = {[" + p1+"], '" + p2 + \
                "', '" + p3 + "', [" + p4 + "']};"
            self.eng.eval(cmd, nargout=0)

        # get some data
        self.eng.eval("reac_id = cellstr(cnap.reacID).';",
                      nargout=0, stdout=self.out, stderr=self.err)

        mcs = []
        values = []
        reactions = []
        reac_id = []
        if self.appdata.is_matlab_set():
            reac_id = self.eng.workspace['reac_id']
            try:
                self.eng.eval("[mcs] = cnapy_compute_mcs(cnap, genes, maxSolutions, maxSize, milp_time_limit, gKOs, advanced_on, solver, mcs_search_mode, dg_T,dg_D);",
                              nargout=0)
            except Exception:
                output = io.StringIO()
                traceback.print_exc(file=output)
                exstr = output.getvalue()
                print(exstr)
                QMessageBox.warning(self, 'Unknown exception occured!',
                                    exstr+'\nPlease report the problem to:\n\
                                    \nhttps://github.com/cnapy-org/CNApy/issues')
                return
            else:
                self.eng.eval("[reaction, mcs, value] = find(mcs);", nargout=0,
                              stdout=self.out, stderr=self.err)
                reactions = self.eng.workspace['reaction']
                mcs = self.eng.workspace['mcs']
                values = self.eng.workspace['value']
        elif self.appdata.is_octave_ready():
            reac_id = self.eng.pull('reac_id')
            reac_id = reac_id[0]
            try:
                self.eng.eval("[mcs] = cnapy_compute_mcs(cnap, genes, maxSolutions, maxSize, milp_time_limit, gKOs, advanced_on, solver, mcs_search_mode, dg_T,dg_D);",
                              nargout=0)
            except Exception:
                output = io.StringIO()
                traceback.print_exc(file=output)
                exstr = output.getvalue()
                print(exstr)
                QMessageBox.warning(self, 'Unknown exception occured!',
                                    exstr+'\nPlease report the problem to:\n\
                                    \nhttps://github.com/cnapy-org/CNApy/issues')
                return
            else:
                self.eng.eval("[reaction, mcs, value] = find(mcs);", nargout=0,
                              stdout=self.out, stderr=self.err)
                reactions = self.eng.pull('reaction')
                mcs = self.eng.pull('mcs')
                values = self.eng.pull('value')

        if len(mcs) == 0:
            QMessageBox.information(self, 'No cut sets',
                                          'Cut sets have not been calculated or do not exist.')
        else:
            last_mcs = 1
            omcs = []
            current_mcs = {}
            for i in range(0, len(reactions)):
                reacid = int(reactions[i][0])
                reaction = reac_id[reacid-1]
                c_mcs = int(mcs[i][0])
                c_value = int(values[i][0])
                if c_value == -1:  # -1 stands for removed which is 0 in the ui
                    c_value = 0
                if c_mcs > last_mcs:
                    omcs.append(current_mcs)
                    last_mcs = c_mcs
                    current_mcs = {}
                current_mcs[reaction] = c_value
            omcs.append(current_mcs)
            self.appdata.project.modes = omcs
            self.centralwidget.mode_navigator.current = 0
            QMessageBox.information(self, 'Cut sets found',
                                          str(len(omcs))+' Cut sets have been calculated.')

        self.centralwidget.update_mode()
        self.centralwidget.mode_navigator.title.setText("MCS Navigation")

        self.setCursor(Qt.ArrowCursor)

    def compute_optlang(self):

        self.setCursor(Qt.BusyCursor)
        max_mcs_num = float(self.max_solu.text())
        max_mcs_size = int(self.max_size.text())
        timeout = float(self.time_limit.text())
        if timeout is float('inf'):
            timeout = None

        # if self.gen_kos.isChecked():
        #     self.eng.eval("gKOs = 1;", nargout=0)
        # else:
        #     self.eng.eval("gKOs = 0;", nargout=0)
        # if self.advanced.isChecked():
        #     self.eng.eval("advanced_on = 1;", nargout=0)
        # else:
        #     self.eng.eval("advanced_on = 0;", nargout=0)

        if self.smalles_mcs_first.isChecked():
            enum_method = 1
        elif self.mcs_by_cardinality.isChecked():
            enum_method = 2
        elif self.any_mcs.isChecked():
            enum_method = 3

        with self.appdata.project.cobra_py_model as model:
            if self.consider_scenario.isChecked():  # integrate scenario into model bounds
                for r in self.appdata.project.scen_values.keys():
                    model.reactions.get_by_id(
                        r).bounds = self.appdata.project.scen_values[r]
            reac_id = model.reactions.list_attr("id")
            reac_id_symbols = cMCS_enumerator.get_reac_id_symbols(reac_id)
            rows = self.target_list.rowCount()
            targets = dict()
            for i in range(0, rows):
                p1 = self.target_list.cellWidget(i, 0).text()
                p2 = self.target_list.cellWidget(i, 1).text()
                if len(p1) > 0 and len(p2) > 0:
                    if self.target_list.cellWidget(i, 2).currentText() == '≤':
                        p3 = "<="
                    else:
                        p3 = ">="
                    p4 = float(self.target_list.cellWidget(i, 3).text())
                    targets.setdefault(p1, []).append((p2, p3, p4))
            targets = list(targets.values())
            targets = [cMCS_enumerator.relations2leq_matrix(cMCS_enumerator.parse_relations(
                t, reac_id_symbols=reac_id_symbols), reac_id) for t in targets]

            rows = self.desired_list.rowCount()
            desired = dict()
            for i in range(0, rows):
                p1 = self.desired_list.cellWidget(i, 0).text()
                p2 = self.desired_list.cellWidget(i, 1).text()
                if len(p1) > 0 and len(p2) > 0:
                    if self.desired_list.cellWidget(i, 2).currentText() == '≤':
                        p3 = "<="
                    else:
                        p3 = ">="
                    p4 = float(self.desired_list.cellWidget(i, 3).text())
                    desired.setdefault(p1, []).append((p2, p3, p4))

            desired = list(desired.values())
            desired = [cMCS_enumerator.relations2leq_matrix(cMCS_enumerator.parse_relations(
                d, reac_id_symbols=reac_id_symbols), reac_id) for d in desired]

            try:
                mcs = cMCS_enumerator.compute_mcs(model,
                                                  targets=targets,
                                                  desired=desired,
                                                  enum_method=enum_method,
                                                  max_mcs_size=max_mcs_size,
                                                  max_mcs_num=max_mcs_num,
                                                  timeout=timeout,
                                                  exclude_boundary_reactions_as_cuts=self.exclude_boundary.isChecked())
            except cMCS_enumerator.InfeasibleRegion as e:
                QMessageBox.warning(self, 'Cannot calculate MCS', str(e))
                return targets, desired
            except Exception:
                output = io.StringIO()
                traceback.print_exc(file=output)
                exstr = output.getvalue()
                print(exstr)
                QMessageBox.warning(self, 'An exception has occured!',
                                    exstr+'\nPlease report the problem to:\n\
                                    \nhttps://github.com/cnapy-org/CNApy/issues')
                return targets, desired
            finally:
                self.setCursor(Qt.ArrowCursor)

        if len(mcs) == 0:
            QMessageBox.information(self, 'No cut sets',
                                          'Cut sets have not been calculated or do not exist.')
            return targets, desired

        omcs = [{reac_id[i]: 0 for i in m} for m in mcs]
        self.appdata.project.modes = omcs
        self.centralwidget.mode_navigator.current = 0
        QMessageBox.information(self, 'Cut sets found',
                                      str(len(omcs))+' Cut sets have been calculated.')

        self.centralwidget.update_mode()
        self.centralwidget.mode_navigator.title.setText("MCS Navigation")
Пример #29
0
class RotateLabelDlg(QDialog):

    rotateSelectedPolygon = QtCore.Signal(bool, int)

    def __init__(self,
                 parent=None,
                 rotation_connection=None,
                 clockwise=True,
                 angle=0):
        super(RotateLabelDlg, self).__init__(parent)
        self.setWindowTitle(self.tr("Rotate the selected polygon"))
        if rotation_connection is not None:
            self.rotateSelectedPolygon.connect(rotation_connection)
        self.clockwise = clockwise
        self.angle = angle
        self.setLayout(self.createLayout())
        self.setFixedSize(400, 80)

    def resetRotateDlg(self, parent_topright):
        self.clockwise = True
        self.angle = 0
        self.radio_clockwise.setChecked(self.clockwise)
        self.angle_editor.setValue(self.angle)
        self.rotate_bar.updateRotationInfo(self.clockwise, self.angle)
        size = self.size()
        self.move(parent_topright.x() - size.width(), parent_topright.y())

    def createLayout(self):
        hbox = QHBoxLayout()
        self.radio_clockwise = QRadioButton(self.tr("clockwise"), self)
        self.radio_clockwise.clockwise = True
        self.radio_clockwise.setChecked(self.clockwise)
        self.radio_clockwise.toggled.connect(self.rotationDirectionChanged)

        self.radio_anticlockwise = QRadioButton(self.tr("anticlockwise"), self)
        self.radio_anticlockwise.clockwise = False
        self.radio_anticlockwise.setChecked(not self.clockwise)
        self.radio_anticlockwise.toggled.connect(self.rotationDirectionChanged)

        self.angle_editor = QSpinBox(self)
        self.angle_editor.setButtonSymbols(
            QtWidgets.QAbstractSpinBox.NoButtons)
        self.angle_editor.setRange(0, 360)
        self.angle_editor.setSuffix(" °")
        self.angle_editor.setValue(self.angle)
        self.angle_editor.setToolTip("rotation angle")
        self.angle_editor.setStatusTip(self.toolTip())
        self.angle_editor.setAlignment(QtCore.Qt.AlignCenter)
        self.angle_editor.valueChanged.connect(self.rotationAngleChanged)

        hbox.addWidget(self.radio_anticlockwise)
        hbox.addWidget(self.radio_clockwise)
        hbox.addWidget(self.angle_editor)

        self.rotate_bar = AngleBar(self, self.clockwise, self.angle,
                                   self.angleBarChanged)

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.rotate_bar)
        return vbox

    def rotationDirectionChanged(self, value):
        # radio button
        rbtn = self.sender()
        if rbtn.isChecked():
            self.clockwise = rbtn.clockwise
            self.rotate_bar.updateRotationInfo(self.clockwise, self.angle)
            self.appleRotateInfo()

    def rotationAngleChanged(self, value):
        # spinbox
        if value != self.angle:
            self.angle = value
            self.rotate_bar.updateRotationInfo(self.clockwise, self.angle)
            self.appleRotateInfo()

    def angleBarChanged(self, clockwise, angle):
        if self.clockwise == clockwise and self.angle == angle:
            return
        self.clockwise = clockwise
        self.angle = angle

        self.angle_editor.setValue(self.angle)
        if self.clockwise and not self.radio_clockwise.isChecked():
            self.radio_clockwise.setChecked(True)
        elif not self.clockwise and not self.radio_anticlockwise.isChecked():
            self.radio_anticlockwise.setChecked(True)
        else:
            self.appleRotateInfo()

    def appleRotateInfo(self):
        self.rotateSelectedPolygon.emit(self.clockwise, self.angle)
Пример #30
0
class ImageRotationDialog(ExToolWindow):
    def __init__(self, signal, axes, parent, plugin):
        super(ImageRotationDialog, self).__init__(parent)
        self.ui = parent
        self.create_controls()
        self.accepted.connect(self.ok)
        self.rejected.connect(self.close_new)
        self.signal = signal
        self.plugin = plugin
        self.new_out = None
        self._connected_updates = False
        if isinstance(axes, str):
            axm = signal.signal.axes_manager
            if axes.startswith("nav"):
                axes = (axm._axes.index(axm.navigation_axes[0]),
                        axm._axes.index(axm.navigation_axes[1]))
            elif axes.startswith("sig"):
                axes = (axm._axes.index(axm.signal_axes[0]),
                        axm._axes.index(axm.signal_axes[1]))
        self.axes = axes
        self.setWindowTitle(tr("Rotate"))

        # TODO: TAG: Functionality check
        if not hasattr(signal.signal, 'events'):
            self.gbo_preview.setVisible(False)

        # TODO: Add dynamic rotation, e.g. one that rotates when source
        # signal's data_changed event triggers

    def connect(self):
        # TODO: Don't have to con/dis those in gbo
        self.opt_new.toggled.connect(self.close_new)
        self.num_angle.valueChanged.connect(self.update)
        self.chk_grid.toggled.connect(self.update)
        self.num_grid.valueChanged.connect(self.update)
        self.chk_reshape.toggled.connect(self.update)
        self.opt_new.toggled.connect(self.update)
        self.opt_replace.toggled.connect(self.update)

    def disconnect(self):
        self.num_angle.valueChanged.disconnect(self.update)
        self.chk_grid.toggled.disconnect(self.update)
        self.num_grid.valueChanged.disconnect(self.update)
        self.chk_reshape.toggled.disconnect(self.update)
        self.opt_new.toggled.disconnect(self.update)
        self.opt_replace.toggled.disconnect(self.update)

    def ok(self):
        # Draw figure if not already done
        # TODO: TAG: Functionality check
        if not hasattr(self.signal.signal, 'events') or \
                not self.gbo_preview.isChecked():
            self.update()
        angle = self.num_angle.value()
        reshape = self.chk_reshape.isChecked()
        self.plugin.record_code(
            r"<p>.rotate_signal({0}, reshape={1}, axes={2})".format(
                angle, reshape, self.axes))
        # Clean up event connections
        if self.new_out is not None:
            self.connect_update_plot(self.new_out.signal, disconnect=True)

    def close_new(self, value=False):
        if self.new_out is not None and not value:
            self.new_out.close()
            self.new_out = None
            self._connected_updates = False

    def set_preview(self, value):
        if not hasattr(self.signal.signal, 'events'):
            return
        if value:
            self.connect()
            self.update()
        else:
            self.disconnect()
            self.close_new()

    def _axes_in_nav(self):
        axm = self.signal.signal.axes_manager
        navidx = [axm._axes.index(ax) for ax in axm.navigation_axes]
        if self.axes[0] in navidx:
            return True
        return False

    def connect_update_plot(self, signal, disconnect=False):
        if self._connected_updates != disconnect:
            return  # Nothing to do, prevent double connections
        if self._axes_in_nav():
            f = signal._plot.navigator_plot.update
        else:
            f = signal._plot.signal_plot.update

        # TODO: TAG: Functionality check
        if hasattr(signal, 'events') and hasattr(signal.events,
                                                 'data_changed'):
            if disconnect:
                signal.events.data_changed.disconnect(f)
            else:
                signal.events.data_changed.connect(f, [])
        self._connected_updates = not disconnect

    def update(self):
        angle = self.num_angle.value()
        reshape = self.chk_reshape.isChecked()
        if self.opt_new.isChecked():
            if self.new_out is None:
                out = None
            else:
                out = self.new_out.signal
        elif self.opt_replace.isChecked():
            out = self.signal.signal
        else:
            return  # Indeterminate state, do nothing

        s = self.plugin.rotate_signal(angle,
                                      self.signal.signal,
                                      record=False,
                                      reshape=reshape,
                                      out=out,
                                      axes=self.axes)

        if out is None:
            s.metadata.General.title = self.signal.name + "[Rotated]"
            s.plot()
            self.connect_update_plot(s)
            if (self.gbo_preview.isChecked() and self.opt_new.isChecked()
                    and self.new_out is None):
                self.new_out = self.ui.lut_signalwrapper[s]
        else:
            s = out

        if self.chk_grid.isChecked() is True:
            pass  # TODO: Draw grid

    def create_controls(self):
        """
        Create UI controls.
        """
        vbox = QVBoxLayout()

        form = QFormLayout()
        self.num_angle = QDoubleSpinBox()
        self.num_angle.setValue(0.0)
        self.num_angle.setMinimum(-360)
        self.num_angle.setMaximum(360)
        form.addRow(tr("Angle:"), self.num_angle)
        vbox.addLayout(form)

        self.gbo_preview = QGroupBox(tr("Preview"))
        self.gbo_preview.setCheckable(True)
        self.gbo_preview.setChecked(False)
        gbo_vbox = QVBoxLayout()
        self.chk_grid = QCheckBox(tr("Grid"))
        self.chk_grid.setChecked(False)
        self.num_grid = QSpinBox()
        self.num_grid.setValue(4)
        self.num_grid.setMinimum(1)
        self.num_grid.setEnabled(False)
        self.chk_grid.toggled[bool].connect(self.num_grid.setEnabled)
        gbo_vbox.addWidget(self.chk_grid)
        gbo_vbox.addWidget(self.num_grid)
        self.gbo_preview.setLayout(gbo_vbox)
        vbox.addWidget(self.gbo_preview)

        self.gbo_preview.toggled[bool].connect(self.set_preview)

        self.gbo_output = QGroupBox(tr("Output"))
        self.opt_new = QRadioButton(tr("New signal"))
        self.opt_replace = QRadioButton(tr("In place"))
        self.opt_new.setChecked(True)
        gbo_vbox2 = QVBoxLayout()
        gbo_vbox2.addWidget(self.opt_new)
        gbo_vbox2.addWidget(self.opt_replace)
        self.gbo_output.setLayout(gbo_vbox2)
        vbox.addWidget(self.gbo_output)

        self.chk_reshape = QCheckBox(tr("Resize to fit"))
        self.chk_reshape.setChecked(False)
        vbox.addWidget(self.chk_reshape)

        self.btn_ok = QPushButton(tr("&OK"))
        self.btn_ok.setDefault(True)
        self.btn_ok.clicked.connect(self.accept)
        self.btn_cancel = QPushButton(tr("&Cancel"))
        self.btn_cancel.clicked.connect(self.reject)
        hbox = QHBoxLayout()
        hbox.addWidget(self.btn_ok)
        hbox.addWidget(self.btn_cancel)
        vbox.addLayout(hbox)

        vbox.addStretch(1)
        self.setLayout(vbox)
Пример #31
0
class RunConfigOptions(QWidget):
    """Run configuration options"""
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.dir = None
        self.runconf = RunConfiguration()
        firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False)

        # --- Interpreter ---
        interpreter_group = QGroupBox(_("Console"))
        interpreter_layout = QVBoxLayout()
        interpreter_group.setLayout(interpreter_layout)

        self.current_radio = QRadioButton(CURRENT_INTERPRETER)
        interpreter_layout.addWidget(self.current_radio)

        self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER)
        interpreter_layout.addWidget(self.dedicated_radio)

        self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER)
        interpreter_layout.addWidget(self.systerm_radio)

        # --- General settings ----
        common_group = QGroupBox(_("General settings"))
        common_layout = QGridLayout()
        common_group.setLayout(common_layout)

        self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES)
        common_layout.addWidget(self.clear_var_cb, 0, 0)

        self.post_mortem_cb = QCheckBox(POST_MORTEM)
        common_layout.addWidget(self.post_mortem_cb, 1, 0)

        self.clo_cb = QCheckBox(_("Command line options:"))
        common_layout.addWidget(self.clo_cb, 2, 0)
        self.clo_edit = QLineEdit()
        self.clo_cb.toggled.connect(self.clo_edit.setEnabled)
        self.clo_edit.setEnabled(False)
        common_layout.addWidget(self.clo_edit, 2, 1)

        # --- Working directory ---
        wdir_group = QGroupBox(_("Working Directory settings"))
        wdir_layout = QVBoxLayout()
        wdir_group.setLayout(wdir_layout)

        self.file_dir_radio = QRadioButton(FILE_DIR)
        wdir_layout.addWidget(self.file_dir_radio)

        self.cwd_radio = QRadioButton(CW_DIR)
        wdir_layout.addWidget(self.cwd_radio)

        fixed_dir_layout = QHBoxLayout()
        self.fixed_dir_radio = QRadioButton(FIXED_DIR)
        fixed_dir_layout.addWidget(self.fixed_dir_radio)
        self.wd_edit = QLineEdit()
        self.fixed_dir_radio.toggled.connect(self.wd_edit.setEnabled)
        self.wd_edit.setEnabled(False)
        fixed_dir_layout.addWidget(self.wd_edit)
        browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self)
        browse_btn.setToolTip(_("Select directory"))
        browse_btn.clicked.connect(self.select_directory)
        fixed_dir_layout.addWidget(browse_btn)
        wdir_layout.addLayout(fixed_dir_layout)

        # --- System terminal ---
        external_group = QGroupBox(_("External system terminal"))
        external_group.setDisabled(True)

        self.systerm_radio.toggled.connect(external_group.setEnabled)

        external_layout = QGridLayout()
        external_group.setLayout(external_layout)
        self.interact_cb = QCheckBox(INTERACT)
        external_layout.addWidget(self.interact_cb, 1, 0, 1, -1)

        self.pclo_cb = QCheckBox(_("Command line options:"))
        external_layout.addWidget(self.pclo_cb, 3, 0)
        self.pclo_edit = QLineEdit()
        self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled)
        self.pclo_edit.setEnabled(False)
        self.pclo_edit.setToolTip(_("<b>-u</b> is added to the "
                                    "other options you set here"))
        external_layout.addWidget(self.pclo_edit, 3, 1)

        # Checkbox to preserve the old behavior, i.e. always open the dialog
        # on first run
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog"))
        self.firstrun_cb.clicked.connect(self.set_firstrun_o)
        self.firstrun_cb.setChecked(firstrun_o)

        layout = QVBoxLayout()
        layout.addWidget(interpreter_group)
        layout.addWidget(common_group)
        layout.addWidget(wdir_group)
        layout.addWidget(external_group)
        layout.addWidget(hline)
        layout.addWidget(self.firstrun_cb)
        self.setLayout(layout)

    def select_directory(self):
        """Select directory"""
        basedir = to_text_string(self.wd_edit.text())
        if not osp.isdir(basedir):
            basedir = getcwd_or_home()
        directory = getexistingdirectory(self, _("Select directory"), basedir)
        if directory:
            self.wd_edit.setText(directory)
            self.dir = directory

    def set(self, options):
        self.runconf.set(options)
        self.clo_cb.setChecked(self.runconf.args_enabled)
        self.clo_edit.setText(self.runconf.args)
        if self.runconf.current:
            self.current_radio.setChecked(True)
        elif self.runconf.systerm:
            self.systerm_radio.setChecked(True)
        else:
            self.dedicated_radio.setChecked(True)
        self.interact_cb.setChecked(self.runconf.interact)
        self.post_mortem_cb.setChecked(self.runconf.post_mortem)
        self.pclo_cb.setChecked(self.runconf.python_args_enabled)
        self.pclo_edit.setText(self.runconf.python_args)
        self.clear_var_cb.setChecked(self.runconf.clear_namespace)
        self.file_dir_radio.setChecked(self.runconf.file_dir)
        self.cwd_radio.setChecked(self.runconf.cw_dir)
        self.fixed_dir_radio.setChecked(self.runconf.fixed_dir)
        self.dir = self.runconf.dir
        self.wd_edit.setText(self.dir)

    def get(self):
        self.runconf.args_enabled = self.clo_cb.isChecked()
        self.runconf.args = to_text_string(self.clo_edit.text())
        self.runconf.current = self.current_radio.isChecked()
        self.runconf.systerm = self.systerm_radio.isChecked()
        self.runconf.interact = self.interact_cb.isChecked()
        self.runconf.post_mortem = self.post_mortem_cb.isChecked()
        self.runconf.python_args_enabled = self.pclo_cb.isChecked()
        self.runconf.python_args = to_text_string(self.pclo_edit.text())
        self.runconf.clear_namespace = self.clear_var_cb.isChecked()
        self.runconf.file_dir = self.file_dir_radio.isChecked()
        self.runconf.cw_dir = self.cwd_radio.isChecked()
        self.runconf.fixed_dir = self.fixed_dir_radio.isChecked()
        self.runconf.dir = self.wd_edit.text()
        return self.runconf.get()

    def is_valid(self):
        wdir = to_text_string(self.wd_edit.text())
        if not self.fixed_dir_radio.isChecked() or osp.isdir(wdir):
            return True
        else:
            QMessageBox.critical(self, _("Run configuration"),
                                 _("The following working directory is "
                                   "not valid:<br><b>%s</b>") % wdir)
            return False

    def set_firstrun_o(self):
        CONF.set('run', ALWAYS_OPEN_FIRST_RUN_OPTION,
                 self.firstrun_cb.isChecked())
Пример #32
0
class RunConfigOptions(QWidget):
    """Run configuration options"""
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.dir = None
        self.runconf = RunConfiguration()
        firstrun_o = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION, False)

        # --- Interpreter ---
        interpreter_group = QGroupBox(_("Console"))
        interpreter_layout = QVBoxLayout()
        interpreter_group.setLayout(interpreter_layout)

        self.current_radio = QRadioButton(CURRENT_INTERPRETER)
        interpreter_layout.addWidget(self.current_radio)

        self.dedicated_radio = QRadioButton(DEDICATED_INTERPRETER)
        interpreter_layout.addWidget(self.dedicated_radio)

        self.systerm_radio = QRadioButton(SYSTERM_INTERPRETER)
        interpreter_layout.addWidget(self.systerm_radio)

        # --- General settings ----
        common_group = QGroupBox(_("General settings"))
        common_layout = QGridLayout()
        common_group.setLayout(common_layout)

        self.clear_var_cb = QCheckBox(CLEAR_ALL_VARIABLES)
        common_layout.addWidget(self.clear_var_cb, 0, 0)

        self.console_ns_cb = QCheckBox(CONSOLE_NAMESPACE)
        common_layout.addWidget(self.console_ns_cb, 1, 0)

        self.post_mortem_cb = QCheckBox(POST_MORTEM)
        common_layout.addWidget(self.post_mortem_cb, 2, 0)

        self.clo_cb = QCheckBox(_("Command line options:"))
        common_layout.addWidget(self.clo_cb, 3, 0)
        self.clo_edit = QLineEdit()
        self.clo_cb.toggled.connect(self.clo_edit.setEnabled)
        self.clo_edit.setEnabled(False)
        common_layout.addWidget(self.clo_edit, 3, 1)

        # --- Working directory ---
        wdir_group = QGroupBox(_("Working directory settings"))
        wdir_layout = QVBoxLayout()
        wdir_group.setLayout(wdir_layout)

        self.file_dir_radio = QRadioButton(FILE_DIR)
        wdir_layout.addWidget(self.file_dir_radio)

        self.cwd_radio = QRadioButton(CW_DIR)
        wdir_layout.addWidget(self.cwd_radio)

        fixed_dir_layout = QHBoxLayout()
        self.fixed_dir_radio = QRadioButton(FIXED_DIR)
        fixed_dir_layout.addWidget(self.fixed_dir_radio)
        self.wd_edit = QLineEdit()
        self.fixed_dir_radio.toggled.connect(self.wd_edit.setEnabled)
        self.wd_edit.setEnabled(False)
        fixed_dir_layout.addWidget(self.wd_edit)
        browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self)
        browse_btn.setToolTip(_("Select directory"))
        browse_btn.clicked.connect(self.select_directory)
        fixed_dir_layout.addWidget(browse_btn)
        wdir_layout.addLayout(fixed_dir_layout)

        # --- System terminal ---
        external_group = QGroupBox(_("External system terminal"))
        external_group.setDisabled(True)

        self.systerm_radio.toggled.connect(external_group.setEnabled)

        external_layout = QGridLayout()
        external_group.setLayout(external_layout)
        self.interact_cb = QCheckBox(INTERACT)
        external_layout.addWidget(self.interact_cb, 1, 0, 1, -1)

        self.pclo_cb = QCheckBox(_("Command line options:"))
        external_layout.addWidget(self.pclo_cb, 3, 0)
        self.pclo_edit = QLineEdit()
        self.pclo_cb.toggled.connect(self.pclo_edit.setEnabled)
        self.pclo_edit.setEnabled(False)
        self.pclo_edit.setToolTip(_("<b>-u</b> is added to the "
                                    "other options you set here"))
        external_layout.addWidget(self.pclo_edit, 3, 1)

        # Checkbox to preserve the old behavior, i.e. always open the dialog
        # on first run
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        self.firstrun_cb = QCheckBox(ALWAYS_OPEN_FIRST_RUN % _("this dialog"))
        self.firstrun_cb.clicked.connect(self.set_firstrun_o)
        self.firstrun_cb.setChecked(firstrun_o)

        layout = QVBoxLayout()
        layout.addWidget(interpreter_group)
        layout.addWidget(common_group)
        layout.addWidget(wdir_group)
        layout.addWidget(external_group)
        layout.addWidget(hline)
        layout.addWidget(self.firstrun_cb)
        self.setLayout(layout)

    def select_directory(self):
        """Select directory"""
        basedir = to_text_string(self.wd_edit.text())
        if not osp.isdir(basedir):
            basedir = getcwd_or_home()
        directory = getexistingdirectory(self, _("Select directory"), basedir)
        if directory:
            self.wd_edit.setText(directory)
            self.dir = directory

    def set(self, options):
        self.runconf.set(options)
        self.clo_cb.setChecked(self.runconf.args_enabled)
        self.clo_edit.setText(self.runconf.args)
        if self.runconf.current:
            self.current_radio.setChecked(True)
        elif self.runconf.systerm:
            self.systerm_radio.setChecked(True)
        else:
            self.dedicated_radio.setChecked(True)
        self.interact_cb.setChecked(self.runconf.interact)
        self.post_mortem_cb.setChecked(self.runconf.post_mortem)
        self.pclo_cb.setChecked(self.runconf.python_args_enabled)
        self.pclo_edit.setText(self.runconf.python_args)
        self.clear_var_cb.setChecked(self.runconf.clear_namespace)
        self.console_ns_cb.setChecked(self.runconf.console_namespace)
        self.file_dir_radio.setChecked(self.runconf.file_dir)
        self.cwd_radio.setChecked(self.runconf.cw_dir)
        self.fixed_dir_radio.setChecked(self.runconf.fixed_dir)
        self.dir = self.runconf.dir
        self.wd_edit.setText(self.dir)

    def get(self):
        self.runconf.args_enabled = self.clo_cb.isChecked()
        self.runconf.args = to_text_string(self.clo_edit.text())
        self.runconf.current = self.current_radio.isChecked()
        self.runconf.systerm = self.systerm_radio.isChecked()
        self.runconf.interact = self.interact_cb.isChecked()
        self.runconf.post_mortem = self.post_mortem_cb.isChecked()
        self.runconf.python_args_enabled = self.pclo_cb.isChecked()
        self.runconf.python_args = to_text_string(self.pclo_edit.text())
        self.runconf.clear_namespace = self.clear_var_cb.isChecked()
        self.runconf.console_namespace = self.console_ns_cb.isChecked()
        self.runconf.file_dir = self.file_dir_radio.isChecked()
        self.runconf.cw_dir = self.cwd_radio.isChecked()
        self.runconf.fixed_dir = self.fixed_dir_radio.isChecked()
        self.runconf.dir = self.wd_edit.text()
        return self.runconf.get()

    def is_valid(self):
        wdir = to_text_string(self.wd_edit.text())
        if not self.fixed_dir_radio.isChecked() or osp.isdir(wdir):
            return True
        else:
            QMessageBox.critical(self, _("Run configuration"),
                                 _("The following working directory is "
                                   "not valid:<br><b>%s</b>") % wdir)
            return False

    def set_firstrun_o(self):
        CONF.set('run', ALWAYS_OPEN_FIRST_RUN_OPTION,
                 self.firstrun_cb.isChecked())
Пример #33
0
class ProjectDialog(QDialog):
    """Project creation dialog."""

    # path, type, packages
    sig_project_creation_requested = Signal(object, object, object)

    def __init__(self, parent):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)

        # Variables
        current_python_version = '.'.join([to_text_string(sys.version_info[0]),
                                           to_text_string(sys.version_info[1])])
        python_versions = ['2.7', '3.4', '3.5']
        if current_python_version not in python_versions:
            python_versions.append(current_python_version)
            python_versions = sorted(python_versions)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))
        self.label_python_version = QLabel(_('Python version'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()
        self.combo_python_version = QComboBox()

        self.button_select_location = QToolButton()
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.combo_python_version.addItems(python_versions)
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_select_location.setIcon(get_std_icon('DirOpenIcon'))
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        self.combo_project_type.addItems(self._get_project_types())
        self.combo_python_version.setCurrentIndex(
            python_versions.index(current_python_version))
        self.setWindowTitle(_('Create new project'))
        self.setFixedWidth(500)
        self.label_python_version.setVisible(False)
        self.combo_python_version.setVisible(False)

        # Layouts        
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addStretch(1)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_python_version, 3, 0)
        layout_grid.addWidget(self.combo_python_version, 3, 1, 1, 2)

        layout = QVBoxLayout()
        layout.addWidget(self.groupbox)
        layout.addSpacing(10)
        layout.addLayout(layout_grid)
        layout.addStretch()
        layout.addSpacing(20)
        layout.addWidget(self.bbox)

        self.setLayout(layout)

        # Signals and slots
        self.button_select_location.clicked.connect(self.select_location)
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def _get_project_types(self):
        """Get all available project types."""
        project_types = get_available_project_types()
        projects = []

        for project in project_types:
            projects.append(project.PROJECT_TYPE_NAME)

        return projects

    def select_location(self):
        """Select directory."""
        location = osp.normpath(getexistingdirectory(self,
                                                     _("Select directory"),
                                                     self.location))

        if location:
            if is_writable(location):
                self.location = location
                self.update_location()

    def update_location(self, text=''):
        """Update text of location."""
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        name = self.text_project_name.text().strip()

        if name and self.radio_new_dir.isChecked():
            path = osp.join(self.location, name)
            self.button_create.setDisabled(os.path.isdir(path))
        elif self.radio_from_dir.isChecked():
            self.button_create.setEnabled(True)
            path = self.location
        else:
            self.button_create.setEnabled(False)
            path = self.location
        
        self.text_location.setText(path)
        
    def create_project(self):
        """Create project."""
        packages = ['python={0}'.format(self.combo_python_version.currentText())]
        self.sig_project_creation_requested.emit(
            self.text_location.text(),
            self.combo_project_type.currentText(),
            packages)
        self.accept()
Пример #34
0
class LibraryCatalogDialog(QDialog):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.setWindowTitle(config.thisTranslation["libraryCatalog"])
        self.setMinimumSize(700, 500)
        self.setupVariables()
        self.setupUI()

    def setupVariables(self):
        self.isUpdating = False
        self.catalogEntryId = None
        self.localCatalog = CatalogUtil.loadLocalCatalog()
        self.remoteCatalog = gitHubRepoCacheData
        self.localCatalogData = self.getLocalCatalogItems()
        self.remoteCatalogData = self.getRemoteCatalogItems()
        self.location = "local"
        self.textButtonStyle = "QPushButton {background-color: #333972; color: white;} QPushButton:hover {background-color: #333972;} QPushButton:pressed { background-color: #515790;}"

    def setupUI(self):
        mainLayout = QVBoxLayout()

        filterLayout = QHBoxLayout()
        filterLayout.addWidget(QLabel(config.thisTranslation["menu5_search"]))
        self.filterEntry = QLineEdit()
        self.filterEntry.setClearButtonEnabled(True)
        self.filterEntry.textChanged.connect(self.resetItems)
        filterLayout.addWidget(self.filterEntry)
        mainLayout.addLayout(filterLayout)

        self.searchTypeBox = QGroupBox("")
        locationLayout = QHBoxLayout()
        self.localRadioButton = QRadioButton("Local")
        self.localRadioButton.setChecked(True)
        self.localRadioButton.toggled.connect(
            lambda: self.setLocation("local"))
        locationLayout.addWidget(self.localRadioButton)
        self.remoteRadioButton = QRadioButton("Remote")
        self.remoteRadioButton.toggled.connect(
            lambda: self.setLocation("remote"))
        locationLayout.addWidget(self.remoteRadioButton)
        self.searchTypeBox.setLayout(locationLayout)
        mainLayout.addWidget(self.searchTypeBox)

        typesLayout = QHBoxLayout()
        button = QPushButton("All")
        button.setStyleSheet(self.textButtonStyle)
        button.clicked.connect(lambda: self.selectAllTypes(True))
        typesLayout.addWidget(button)
        button = QPushButton("None")
        button.setStyleSheet(self.textButtonStyle)
        button.clicked.connect(lambda: self.selectAllTypes(False))
        typesLayout.addWidget(button)
        self.bookCheckbox = QCheckBox("BOOK")
        self.bookCheckbox.setChecked(True)
        self.bookCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.bookCheckbox)
        self.pdfCheckbox = QCheckBox("PDF")
        self.pdfCheckbox.setChecked(True)
        self.pdfCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.pdfCheckbox)
        self.docxCheckbox = QCheckBox("DOCX")
        self.docxCheckbox.setChecked(True)
        self.docxCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.docxCheckbox)
        self.devotionalCheckbox = QCheckBox("DEVOTIONAL")
        self.devotionalCheckbox.setChecked(True)
        self.devotionalCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.devotionalCheckbox)
        self.commCheckbox = QCheckBox("COMM")
        self.commCheckbox.setChecked(True)
        self.commCheckbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.commCheckbox)
        self.mp3Checkbox = QCheckBox("MP3")
        self.mp3Checkbox.setChecked(True)
        self.mp3Checkbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.mp3Checkbox)
        self.mp4Checkbox = QCheckBox("MP4")
        self.mp4Checkbox.setChecked(True)
        self.mp4Checkbox.stateChanged.connect(self.resetItems)
        typesLayout.addWidget(self.mp4Checkbox)
        mainLayout.addLayout(typesLayout)

        self.dataView = QTableView()
        self.dataView.clicked.connect(self.itemClicked)
        self.dataView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.dataView.setSortingEnabled(True)
        self.dataViewModel = QStandardItemModel(self.dataView)
        self.dataView.setModel(self.dataViewModel)
        self.resetItems()
        mainLayout.addWidget(self.dataView)

        buttonLayout = QHBoxLayout()
        self.openButton = QPushButton(config.thisTranslation["open"])
        self.openButton.setEnabled(True)
        self.openButton.setStyleSheet(self.textButtonStyle)
        self.openButton.clicked.connect(self.open)
        buttonLayout.addWidget(self.openButton)
        self.downloadButton = QPushButton(config.thisTranslation["download"])
        self.downloadButton.setEnabled(False)
        self.downloadButton.clicked.connect(self.download)
        buttonLayout.addWidget(self.downloadButton)
        button = QPushButton(config.thisTranslation["close"])
        button.setStyleSheet(self.textButtonStyle)
        button.clicked.connect(self.close)
        buttonLayout.addWidget(button)
        mainLayout.addLayout(buttonLayout)

        self.setLayout(mainLayout)

    def setLocation(self, location):
        self.location = location
        self.resetItems()
        if location == "local":
            self.openButton.setEnabled(True)
            self.openButton.setStyleSheet(self.textButtonStyle)
            self.downloadButton.setEnabled(False)
        else:
            self.openButton.setEnabled(False)
            self.openButton.setStyleSheet("")
            self.downloadButton.setEnabled(True)

    def selectAllTypes(self, value):
        self.pdfCheckbox.setChecked(value)
        self.mp3Checkbox.setChecked(value)
        self.mp4Checkbox.setChecked(value)
        self.bookCheckbox.setChecked(value)
        self.docxCheckbox.setChecked(value)
        self.devotionalCheckbox.setChecked(value)
        self.commCheckbox.setChecked(value)

    def getLocalCatalogItems(self):
        return self.getCatalogItems(self.localCatalog)

    def getRemoteCatalogItems(self):
        return self.getCatalogItems(self.remoteCatalog)

    def getCatalogItems(self, catalog):
        data = {}
        pdfCount = 0
        mp3Count = 0
        mp4Count = 0
        bookCount = 0
        docxCount = 0
        commCount = 0
        lexCount = 0
        devotionalCount = 0
        for filename, type, directory, file, description, repo, installDirectory, sha in catalog:
            id = "UNKNOWN"
            if type == "PDF":
                pdfCount += 1
                id = "{0}-{1}".format(type, pdfCount)
            elif type == "MP3":
                mp3Count += 1
                id = "{0}-{1}".format(type, mp3Count)
            elif type == "MP4":
                mp4Count += 1
                id = "{0}-{1}".format(type, mp4Count)
            elif type == "BOOK":
                bookCount += 1
                id = "{0}-{1}".format(type, bookCount)
            elif type == "DOCX":
                docxCount += 1
                id = "{0}-{1}".format(type, docxCount)
            elif type == "COMM":
                commCount += 1
                id = "{0}-{1}".format(type, commCount)
            elif type == "LEX":
                lexCount += 1
                id = "{0}-{1}".format(type, lexCount)
            elif type == "DEVOTIONAL":
                devotionalCount += 1
                id = "{0}-{1}".format(type, devotionalCount)
            data[id] = [
                id, filename, type, directory, file, description, repo,
                installDirectory, sha
            ]
        return data

    def resetItems(self):
        self.isUpdating = True
        self.dataViewModel.clear()
        filterEntry = self.filterEntry.text().lower()
        rowCount = 0
        colCount = 0
        catalogData = self.localCatalogData
        if self.location == "remote":
            catalogData = self.remoteCatalogData
        for id, value in catalogData.items():
            id2, filename, type, directory, file, description, repo, installDirectory, sha = value
            if (filterEntry == "" or filterEntry in filename.lower()
                    or filterEntry in description.lower()):
                if (not self.pdfCheckbox.isChecked() and type == "PDF") or \
                        (not self.mp3Checkbox.isChecked() and type == "MP3") or \
                        (not self.mp4Checkbox.isChecked() and type == "MP4") or \
                        (not self.bookCheckbox.isChecked() and type == "BOOK") or \
                        (not self.docxCheckbox.isChecked() and type == "DOCX") or \
                        (not self.devotionalCheckbox.isChecked() and type == "DEVOTIONAL") or \
                        (not self.commCheckbox.isChecked() and type == "COMM"):
                    continue
                enable = True
                if self.location == "remote":
                    installDirectory = os.path.join(config.marvelData,
                                                    installDirectory)
                    if FileUtil.regexFileExists(
                            "{0}.*".format(GithubUtil.getShortname(filename)),
                            installDirectory):
                        enable = False
                item = QStandardItem(id)
                item.setEnabled(enable)
                self.dataViewModel.setItem(rowCount, colCount, item)
                colCount += 1
                item = QStandardItem(file)
                item.setEnabled(enable)
                self.dataViewModel.setItem(rowCount, colCount, item)
                colCount += 1
                item = QStandardItem(directory)
                item.setEnabled(enable)
                self.dataViewModel.setItem(rowCount, colCount, item)
                colCount += 1
                # item = QStandardItem(description)
                # self.dataViewModel.setItem(rowCount, colCount, item)
                # colCount += 1
                # add row count
                rowCount += 1
                colCount = 0
        self.dataViewModel.setHorizontalHeaderLabels([
            "#",
            config.thisTranslation["file"],
            config.thisTranslation["directory"],
            # config.thisTranslation["description"]
        ])
        self.dataView.resizeColumnsToContents()
        self.isUpdating = False

    def itemClicked(self, index):
        selectedRow = index.row()
        self.catalogEntryId = self.dataViewModel.item(selectedRow, 0).text()
        if self.location == "remote":
            item = self.remoteCatalogData[self.catalogEntryId]
            id, filename, type, directory, file, description, repo, installDirectory, sha = item
            installDirectory = os.path.join(config.marvelData,
                                            installDirectory)
            if FileUtil.regexFileExists(
                    "{0}.*".format(GithubUtil.getShortname(filename)),
                    installDirectory):
                self.downloadButton.setEnabled(False)
                self.downloadButton.setStyleSheet("")
            else:
                self.downloadButton.setEnabled(True)
                self.downloadButton.setStyleSheet(self.textButtonStyle)

    def displayMessage(self, message="", title="UniqueBible"):
        QMessageBox.information(self, title, message)

    def saveRemoteCatalogToCache(self):
        data = CatalogUtil.loadRemoteCatalog()
        with open("util/GitHubRepoCache.py", "w", encoding="utf-8") as fileObj:
            fileObj.write("gitHubRepoCacheData = {0}\n".format(
                pprint.pformat(data)))

    def fixDirectory(self, directory, type):
        if type == "PDF":
            directory = directory.replace(config.marvelData, "")
            directory = directory.replace("/pdf", "")
        if len(directory) > 0 and not directory.endswith("/"):
            directory += "/"
        if len(directory) > 0 and directory.startswith("/"):
            directory = directory[1:]
        return directory

    def open(self):
        item = self.localCatalogData[self.catalogEntryId]
        id, filename, type, directory, file, description, repo, installDirectory, sha = item
        directory = self.fixDirectory(directory, type)
        command = ""
        if type == "PDF":
            command = "PDF:::{0}{1}".format(directory, file)
        elif type == "MP3":
            command = "VLC:::{0}{1}".format(directory, file)
        elif type == "MP4":
            command = "VLC:::{0}{1}".format(directory, file)
        elif type == "BOOK":
            if file.endswith(".book"):
                file = file.replace(".book", "")
            config.booksFolder = directory
            command = "BOOK:::{0}".format(file)
        elif type == "COMM":
            file = file.replace(".commentary", "")
            file = file[1:]
            config.commentariesFolder = directory
            command = "COMMENTARY:::{0}:::{1} {2}".format(
                file, BibleBooks.eng[str(config.mainB)][0], config.mainC)
        elif type == "DOCX":
            command = "DOCX:::{0}".format(file)
        elif type == "DEVOTIONAL":
            file = file.replace(".devotional", "")
            command = "DEVOTIONAL:::{0}".format(file)
        self.parent.runTextCommand(command)

    def download(self):
        self.downloadButton.setEnabled(False)
        self.downloadButton.setStyleSheet("")
        item = self.remoteCatalogData[self.catalogEntryId]
        id, filename, type, directory, file, description, repo, installDirectory, sha = item
        github = GithubUtil(repo)
        installDirectory = os.path.join(config.marvelData, installDirectory)
        file = os.path.join(installDirectory, filename + ".zip")
        github.downloadFile(file, sha)
        with zipfile.ZipFile(file, 'r') as zipped:
            zipped.extractall(installDirectory)
        os.remove(file)
        self.displayMessage(filename + " " +
                            config.thisTranslation["message_installed"])
        self.localCatalog = CatalogUtil.reloadLocalCatalog()
        self.localCatalogData = self.getLocalCatalogItems()
        self.resetItems()
Пример #35
0
class MixerPanel(QFrame):
    '''A color mixer to hook up to an image.
    You pass the image you the panel to operate on
    and it operates on that image in place. You also
    pass a callback to be called to trigger a refresh.
    This callback is called every time the mixer modifies
    your image.'''
    def __init__(self, img):
        QFrame.__init__(self)
        # self.setFrameStyle(QFrame.Box | QFrame.Sunken)

        self.img = img
        self.mixer = ColorMixer(self.img)
        self.callback = None

        #---------------------------------------------------------------
        # ComboBox
        #---------------------------------------------------------------

        self.combo_box_entries = [
            'RGB Color', 'HSV Color', 'Brightness/Contrast', 'Gamma',
            'Gamma (Sigmoidal)'
        ]
        self.combo_box = QComboBox()
        for entry in self.combo_box_entries:
            self.combo_box.addItem(entry)
        self.combo_box.currentIndexChanged.connect(self.combo_box_changed)

        #---------------------------------------------------------------
        # RGB color sliders
        #---------------------------------------------------------------

        # radio buttons
        self.rgb_add = QRadioButton('Additive')
        self.rgb_mul = QRadioButton('Multiplicative')
        self.rgb_mul.toggled.connect(self.rgb_radio_changed)
        self.rgb_add.toggled.connect(self.rgb_radio_changed)

        # sliders
        rs = IntelligentSlider('R', 0.51, -255, self.rgb_changed)
        gs = IntelligentSlider('G', 0.51, -255, self.rgb_changed)
        bs = IntelligentSlider('B', 0.51, -255, self.rgb_changed)
        self.rs = rs
        self.gs = gs
        self.bs = bs

        self.rgb_widget = QWidget()
        self.rgb_widget.layout = QGridLayout(self.rgb_widget)
        self.rgb_widget.layout.addWidget(self.rgb_add, 0, 0, 1, 3)
        self.rgb_widget.layout.addWidget(self.rgb_mul, 1, 0, 1, 3)
        self.rgb_widget.layout.addWidget(self.rs, 2, 0)
        self.rgb_widget.layout.addWidget(self.gs, 2, 1)
        self.rgb_widget.layout.addWidget(self.bs, 2, 2)

        #---------------------------------------------------------------
        # HSV sliders
        #---------------------------------------------------------------
        # radio buttons
        self.hsv_add = QRadioButton('Additive')
        self.hsv_mul = QRadioButton('Multiplicative')
        self.hsv_mul.toggled.connect(self.hsv_radio_changed)
        self.hsv_mul.toggled.connect(self.hsv_radio_changed)

        # sliders
        hs = IntelligentSlider('H', 0.36, -180, self.hsv_changed)
        ss = IntelligentSlider('S', 0.002, 0, self.hsv_changed)
        vs = IntelligentSlider('V', 0.002, 0, self.hsv_changed)
        self.hs = hs
        self.ss = ss
        self.vs = vs

        self.hsv_widget = QWidget()
        self.hsv_widget.layout = QGridLayout(self.hsv_widget)
        self.hsv_widget.layout.addWidget(self.hsv_add, 0, 0, 1, 3)
        self.hsv_widget.layout.addWidget(self.hsv_mul, 1, 0, 1, 3)
        self.hsv_widget.layout.addWidget(self.hs, 2, 0)
        self.hsv_widget.layout.addWidget(self.ss, 2, 1)
        self.hsv_widget.layout.addWidget(self.vs, 2, 2)

        #---------------------------------------------------------------
        # Brightness/Contrast sliders
        #---------------------------------------------------------------
        # sliders
        cont = IntelligentSlider('x', 0.002, 0, self.bright_changed)
        bright = IntelligentSlider('+', 0.51, -255, self.bright_changed)
        self.cont = cont
        self.bright = bright

        # layout
        self.bright_widget = QWidget()
        self.bright_widget.layout = QGridLayout(self.bright_widget)
        self.bright_widget.layout.addWidget(self.cont, 0, 0)
        self.bright_widget.layout.addWidget(self.bright, 0, 1)

        #----------------------------------------------------------------------
        # Gamma Slider
        #----------------------------------------------------------------------
        gamma = IntelligentSlider('gamma', 0.005, 0, self.gamma_changed)
        self.gamma = gamma

        # layout
        self.gamma_widget = QWidget()
        self.gamma_widget.layout = QGridLayout(self.gamma_widget)
        self.gamma_widget.layout.addWidget(self.gamma, 0, 0)

        #---------------------------------------------------------------
        # Sigmoid Gamma sliders
        #---------------------------------------------------------------
        # sliders
        alpha = IntelligentSlider('alpha', 0.011, 1, self.sig_gamma_changed)
        beta = IntelligentSlider('beta', 0.012, 0, self.sig_gamma_changed)
        self.a_gamma = alpha
        self.b_gamma = beta

        # layout
        self.sig_gamma_widget = QWidget()
        self.sig_gamma_widget.layout = QGridLayout(self.sig_gamma_widget)
        self.sig_gamma_widget.layout.addWidget(self.a_gamma, 0, 0)
        self.sig_gamma_widget.layout.addWidget(self.b_gamma, 0, 1)

        #---------------------------------------------------------------
        # Buttons
        #---------------------------------------------------------------
        self.commit_button = QPushButton('Commit')
        self.commit_button.clicked.connect(self.commit_changes)
        self.revert_button = QPushButton('Revert')
        self.revert_button.clicked.connect(self.revert_changes)

        #---------------------------------------------------------------
        # Mixer Layout
        #---------------------------------------------------------------
        self.sliders = QStackedWidget()
        self.sliders.addWidget(self.rgb_widget)
        self.sliders.addWidget(self.hsv_widget)
        self.sliders.addWidget(self.bright_widget)
        self.sliders.addWidget(self.gamma_widget)
        self.sliders.addWidget(self.sig_gamma_widget)

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.combo_box, 0, 0)
        self.layout.addWidget(self.sliders, 1, 0)
        self.layout.addWidget(self.commit_button, 2, 0)
        self.layout.addWidget(self.revert_button, 3, 0)

        #---------------------------------------------------------------
        # State Initialization
        #---------------------------------------------------------------

        self.combo_box.setCurrentIndex(0)
        self.rgb_mul.setChecked(True)
        self.hsv_mul.setChecked(True)

    def set_callback(self, callback):
        self.callback = callback

    def combo_box_changed(self, index):
        self.sliders.setCurrentIndex(index)
        self.reset()

    def rgb_radio_changed(self):
        self.reset()

    def hsv_radio_changed(self):
        self.reset()

    def reset(self):
        self.reset_sliders()
        self.mixer.set_to_stateimg()
        if self.callback:
            self.callback()

    def reset_sliders(self):
        # handle changing the conversion factors necessary
        if self.rgb_add.isChecked():
            self.rs.set_conv_fac(0.51, -255)
            self.rs.set_value(0)
            self.gs.set_conv_fac(0.51, -255)
            self.gs.set_value(0)
            self.bs.set_conv_fac(0.51, -255)
            self.bs.set_value(0)
        else:
            self.rs.set_conv_fac(0.002, 0)
            self.rs.set_value(1.)
            self.gs.set_conv_fac(0.002, 0)
            self.gs.set_value(1.)
            self.bs.set_conv_fac(0.002, 0)
            self.bs.set_value(1.)

        self.hs.set_value(0)
        if self.hsv_add.isChecked():
            self.ss.set_conv_fac(0.002, -1)
            self.ss.set_value(0)
            self.vs.set_conv_fac(0.002, -1)
            self.vs.set_value(0)
        else:
            self.ss.set_conv_fac(0.002, 0)
            self.ss.set_value(1.)
            self.vs.set_conv_fac(0.002, 0)
            self.vs.set_value(1.)

        self.bright.set_value(0)
        self.cont.set_value(1.)

        self.gamma.set_value(1)
        self.a_gamma.set_value(1)
        self.b_gamma.set_value(0.5)

    def rgb_changed(self, name, val):
        if name == 'R':
            channel = self.mixer.RED
        elif name == 'G':
            channel = self.mixer.GREEN
        else:
            channel = self.mixer.BLUE

        if self.rgb_mul.isChecked():
            self.mixer.multiply(channel, val)
        elif self.rgb_add.isChecked():
            self.mixer.add(channel, val)
        else:
            pass

        if self.callback:
            self.callback()

    def hsv_changed(self, name, val):
        h = self.hs.val()
        s = self.ss.val()
        v = self.vs.val()

        if self.hsv_mul.isChecked():
            self.mixer.hsv_multiply(h, s, v)
        elif self.hsv_add.isChecked():
            self.mixer.hsv_add(h, s, v)
        else:
            pass

        if self.callback:
            self.callback()

    def bright_changed(self, name, val):
        b = self.bright.val()
        c = self.cont.val()
        self.mixer.brightness(c, b)

        if self.callback:
            self.callback()

    def gamma_changed(self, name, val):
        self.mixer.gamma(val)

        if self.callback:
            self.callback()

    def sig_gamma_changed(self, name, val):
        ag = self.a_gamma.val()
        bg = self.b_gamma.val()
        self.mixer.sigmoid_gamma(ag, bg)

        if self.callback:
            self.callback()

    def commit_changes(self):
        self.mixer.commit_changes()
        self.reset_sliders()

    def revert_changes(self):
        self.mixer.revert()
        self.reset_sliders()

        if self.callback:
            self.callback()
Пример #36
0
class ContentsWidget(QWidget):
    """Import wizard contents widget"""
    asDataChanged = Signal(bool)

    def __init__(self, parent, text):
        QWidget.__init__(self, parent)

        self.text_editor = QTextEdit(self)
        self.text_editor.setText(text)
        self.text_editor.setReadOnly(True)

        # Type frame
        type_layout = QHBoxLayout()
        type_label = QLabel(_("Import as"))
        type_layout.addWidget(type_label)
        data_btn = QRadioButton(_("data"))
        data_btn.setChecked(True)
        self._as_data = True
        type_layout.addWidget(data_btn)
        code_btn = QRadioButton(_("code"))
        self._as_code = False
        type_layout.addWidget(code_btn)
        txt_btn = QRadioButton(_("text"))
        type_layout.addWidget(txt_btn)

        h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                               QSizePolicy.Minimum)
        type_layout.addItem(h_spacer)
        type_frame = QFrame()
        type_frame.setLayout(type_layout)

        # Opts frame
        grid_layout = QGridLayout()
        grid_layout.setSpacing(0)

        col_label = QLabel(_("Column separator:"))
        grid_layout.addWidget(col_label, 0, 0)
        col_w = QWidget()
        col_btn_layout = QHBoxLayout()
        self.tab_btn = QRadioButton(_("Tab"))
        self.tab_btn.setChecked(False)
        col_btn_layout.addWidget(self.tab_btn)
        self.ws_btn = QRadioButton(_("Whitespace"))
        self.ws_btn.setChecked(False)
        col_btn_layout.addWidget(self.ws_btn)
        other_btn_col = QRadioButton(_("other"))
        other_btn_col.setChecked(True)
        col_btn_layout.addWidget(other_btn_col)
        col_w.setLayout(col_btn_layout)
        grid_layout.addWidget(col_w, 0, 1)
        self.line_edt = QLineEdit(",")
        self.line_edt.setMaximumWidth(30)
        self.line_edt.setEnabled(True)
        other_btn_col.toggled.connect(self.line_edt.setEnabled)
        grid_layout.addWidget(self.line_edt, 0, 2)

        row_label = QLabel(_("Row separator:"))
        grid_layout.addWidget(row_label, 1, 0)
        row_w = QWidget()
        row_btn_layout = QHBoxLayout()
        self.eol_btn = QRadioButton(_("EOL"))
        self.eol_btn.setChecked(True)
        row_btn_layout.addWidget(self.eol_btn)
        other_btn_row = QRadioButton(_("other"))
        row_btn_layout.addWidget(other_btn_row)
        row_w.setLayout(row_btn_layout)
        grid_layout.addWidget(row_w, 1, 1)
        self.line_edt_row = QLineEdit(";")
        self.line_edt_row.setMaximumWidth(30)
        self.line_edt_row.setEnabled(False)
        other_btn_row.toggled.connect(self.line_edt_row.setEnabled)
        grid_layout.addWidget(self.line_edt_row, 1, 2)

        grid_layout.setRowMinimumHeight(2, 15)

        other_group = QGroupBox(_("Additional options"))
        other_layout = QGridLayout()
        other_group.setLayout(other_layout)

        skiprows_label = QLabel(_("Skip rows:"))
        other_layout.addWidget(skiprows_label, 0, 0)
        self.skiprows_edt = QLineEdit('0')
        self.skiprows_edt.setMaximumWidth(30)
        intvalid = QIntValidator(0, len(to_text_string(text).splitlines()),
                                 self.skiprows_edt)
        self.skiprows_edt.setValidator(intvalid)
        other_layout.addWidget(self.skiprows_edt, 0, 1)

        other_layout.setColumnMinimumWidth(2, 5)

        comments_label = QLabel(_("Comments:"))
        other_layout.addWidget(comments_label, 0, 3)
        self.comments_edt = QLineEdit('#')
        self.comments_edt.setMaximumWidth(30)
        other_layout.addWidget(self.comments_edt, 0, 4)

        self.trnsp_box = QCheckBox(_("Transpose"))
        #self.trnsp_box.setEnabled(False)
        other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0)

        grid_layout.addWidget(other_group, 3, 0, 2, 0)

        opts_frame = QFrame()
        opts_frame.setLayout(grid_layout)

        data_btn.toggled.connect(opts_frame.setEnabled)
        data_btn.toggled.connect(self.set_as_data)
        code_btn.toggled.connect(self.set_as_code)
        #        self.connect(txt_btn, SIGNAL("toggled(bool)"),
        #                     self, SLOT("is_text(bool)"))

        # Final layout
        layout = QVBoxLayout()
        layout.addWidget(type_frame)
        layout.addWidget(self.text_editor)
        layout.addWidget(opts_frame)
        self.setLayout(layout)

    def get_as_data(self):
        """Return if data type conversion"""
        return self._as_data

    def get_as_code(self):
        """Return if code type conversion"""
        return self._as_code

    def get_as_num(self):
        """Return if numeric type conversion"""
        return self._as_num

    def get_col_sep(self):
        """Return the column separator"""
        if self.tab_btn.isChecked():
            return u"\t"
        elif self.ws_btn.isChecked():
            return None
        return to_text_string(self.line_edt.text())

    def get_row_sep(self):
        """Return the row separator"""
        if self.eol_btn.isChecked():
            return u"\n"
        return to_text_string(self.line_edt_row.text())

    def get_skiprows(self):
        """Return number of lines to be skipped"""
        return int(to_text_string(self.skiprows_edt.text()))

    def get_comments(self):
        """Return comment string"""
        return to_text_string(self.comments_edt.text())

    @Slot(bool)
    def set_as_data(self, as_data):
        """Set if data type conversion"""
        self._as_data = as_data
        self.asDataChanged.emit(as_data)

    @Slot(bool)
    def set_as_code(self, as_code):
        """Set if code type conversion"""
        self._as_code = as_code
Пример #37
0
class SelectSmoothing(QDialog):
    """
    SelectSmoothing launches a GUI and executes smoothing.
    Any output is added to the input data as a new component.
    """
    def __init__(self,
                 data,
                 parent=None,
                 smooth_cube=None,
                 allow_preview=False,
                 allow_spectral_axes=False):
        super(SelectSmoothing, self).__init__(parent)
        self.setWindowFlags(self.windowFlags() | Qt.Tool)
        self.parent = parent
        self.title = "Smoothing Selection"

        self.data = data  # Glue data to be smoothed

        # Check if smooth object is the caller
        if smooth_cube is None:
            self.smooth_cube = SmoothCube(data=self.data)
        else:
            self.smooth_cube = smooth_cube

        self.allow_spectral_axes = allow_spectral_axes

        self.allow_preview = allow_preview
        self.is_preview_active = False  # Flag to show if smoothing preview is active

        self.abort_window = None  # Small window pop up when smoothing.

        self.component_id = None  # Glue data component to smooth over
        self.current_axis = None  # Selected smoothing_axis
        self.current_kernel_type = None  # Selected kernel type, a key in SmoothCube.kernel_registry
        self.current_kernel_name = None  # Name of selected kernel

        self._init_selection_ui()  # Format and show gui

    def _init_selection_ui(self):
        # LINE 1: Radio box spatial vs spectral axis
        self.axes_prompt = QLabel("Smoothing Axis:")
        self.axes_prompt.setMinimumWidth(150)

        self.spatial_radio = QRadioButton("Spatial")
        self.spatial_radio.setChecked(True)
        self.current_axis = "spatial"
        self.spatial_radio.toggled.connect(self.spatial_radio_checked)

        self.spectral_radio = QRadioButton("Spectral")
        self.spectral_radio.toggled.connect(self.spectral_radio_checked)

        # hbl is short for Horizontal Box Layout
        hbl1 = QHBoxLayout()
        hbl1.addWidget(self.axes_prompt)
        hbl1.addWidget(self.spatial_radio)
        hbl1.addWidget(self.spectral_radio)

        # LINE 2: Kernel Type prompt
        self.k_type_prompt = QLabel("Kernel Type:")
        self.k_type_prompt.setMinimumWidth(150)
        # Load kernel types + names and add to drop down
        self._load_options()
        self.combo = QComboBox()
        self.combo.setMinimumWidth(150)
        self.combo.addItems(self.options[self.current_axis])

        hbl2 = QHBoxLayout()
        hbl2.addWidget(self.k_type_prompt)
        hbl2.addWidget(self.combo)

        # LINE 3: Kernel size
        self.size_prompt = QLabel(
            self.smooth_cube.get_kernel_size_prompt(self.current_kernel_type))
        self.size_prompt.setWordWrap(True)
        self.size_prompt.setMinimumWidth(150)
        self.unit_label = QLabel(
            self.smooth_cube.get_kernel_unit(self.current_kernel_type))
        self.k_size = QLineEdit("1")  # Default Kernel size set here

        hbl3 = QHBoxLayout()
        hbl3.addWidget(self.size_prompt)
        hbl3.addWidget(self.k_size)
        hbl3.addWidget(self.unit_label)

        # LINE 4: Data component drop down
        self.component_prompt = QLabel("Data Component:")
        self.component_prompt.setWordWrap(True)
        self.component_prompt.setMinimumWidth(150)
        # Load component_ids and add to drop down

        # Add the data component labels to the drop down, with the ComponentID
        # set as the userData:

        if self.parent is not None and hasattr(self.parent, 'data_components'):
            labeldata = [(str(cid), cid)
                         for cid in self.parent.data_components]
        else:
            labeldata = [(str(cid), cid)
                         for cid in self.data.main_components()]

        self.component_combo = QComboBox()
        update_combobox(self.component_combo, labeldata)

        self.component_combo.setMaximumWidth(150)
        self.component_combo.setCurrentIndex(0)
        if self.allow_preview:
            self.component_combo.currentIndexChanged.connect(
                self.update_preview_button)

        hbl4 = QHBoxLayout()
        hbl4.addWidget(self.component_prompt)
        hbl4.addWidget(self.component_combo)

        # Line 5: Preview Message
        message = "Info: Smoothing previews are displayed on " \
                  "CubeViz's left and single image viewers."
        self.preview_message = QLabel(message)
        self.preview_message.setWordWrap(True)
        self.preview_message.hide()
        hbl5 = QHBoxLayout()
        hbl5.addWidget(self.preview_message)

        # LINE 6: preview ok cancel buttons
        self.previewButton = QPushButton("Preview")
        self.previewButton.clicked.connect(self.call_preview)

        self.okButton = QPushButton("OK")
        self.okButton.clicked.connect(self.call_main)
        self.okButton.setDefault(True)

        self.cancelButton = QPushButton("Cancel")
        self.cancelButton.clicked.connect(self.cancel)

        hbl6 = QHBoxLayout()
        hbl6.addStretch(1)
        if self.allow_preview:
            hbl6.addWidget(self.previewButton)
        hbl6.addWidget(self.cancelButton)
        hbl6.addWidget(self.okButton)

        # Add Lines to Vertical Layout
        # vbl is short for Vertical Box Layout
        vbl = QVBoxLayout()
        if self.allow_spectral_axes:
            vbl.addLayout(hbl1)
        vbl.addLayout(hbl2)
        vbl.addLayout(hbl3)
        vbl.addLayout(hbl4)
        vbl.addLayout(hbl5)
        vbl.addLayout(hbl6)

        self.setLayout(vbl)
        self.setMaximumWidth(330)

        # Connect kernel combo box to event handler
        self.combo.currentIndexChanged.connect(self.selection_changed)
        self.selection_changed(0)

        self.show()

    def _load_options(self):
        """Extract names + types of kernels from SmoothCube.kernel_registry"""
        kernel_registry = self.smooth_cube.get_kernel_registry()

        self.options = {"spatial": [], "spectral": []}
        for k in kernel_registry:
            axis = kernel_registry[k]["axis"]
            for a in axis:
                if "spatial" == a:
                    self.options["spatial"].append(kernel_registry[k]["name"])
                elif "spectral" == a:
                    self.options["spectral"].append(kernel_registry[k]["name"])
        self.options["spectral"].sort()
        self.options["spatial"].sort()
        self.current_kernel_name = self.options[self.current_axis][0]
        self.current_kernel_type = self.smooth_cube.name_to_kernel_type(
            self.options[self.current_axis][0])

    def selection_changed(self, i):
        """
        Update kernel type, units, etc... when
        kernel name changes in combo box.
        """
        keys = self.options[self.current_axis]
        name = keys[i]
        self.current_kernel_name = name
        self.current_kernel_type = self.smooth_cube.name_to_kernel_type(name)
        self.unit_label.setText(
            self.smooth_cube.get_kernel_unit(self.current_kernel_type))
        self.size_prompt.setText(
            self.smooth_cube.get_kernel_size_prompt(self.current_kernel_type))

    def spatial_radio_checked(self):
        self.current_axis = "spatial"
        self.update_preview_button()
        self.combo.clear()
        self.combo.addItems(self.options[self.current_axis])

    def spectral_radio_checked(self):
        self.current_axis = "spectral"
        self.update_preview_button()
        self.combo.clear()
        self.combo.addItems(self.options[self.current_axis])

    def input_validation(self):
        """
        Check if input will break Smoothing
        :return: bool: True if no errors
        """
        red = "background-color: rgba(255, 0, 0, 128);"
        success = True

        # Check 1: k_size
        if self.k_size == "":
            self.k_size.setStyleSheet(red)
            success = False
        else:
            try:
                if self.current_kernel_type == "median":
                    k_size = int(self.k_size.text())
                else:
                    k_size = float(self.k_size.text())
                if k_size <= 0:
                    self.k_size.setStyleSheet(red)
                    success = False
                else:
                    self.k_size.setStyleSheet("")
            except ValueError:
                if self.current_kernel_type == "median":
                    info = QMessageBox.critical(
                        self, "Error",
                        "Kernel size must be integer for median")
                self.k_size.setStyleSheet(red)
                success = False

        return success

    def call_main(self):
        try:
            self.main()
        except Exception as e:
            info = QMessageBox.critical(self, "Error", str(e))
            self.cancel()
            raise

    def main(self):
        """
        Main function to process input and call smoothing function
        """
        success = self.input_validation()

        if not success:
            return

        self.hide()
        self.abort_window = AbortWindow(self)
        QApplication.processEvents()

        # Add smoothing parameters

        self.smooth_cube.abort_window = self.abort_window
        if self.smooth_cube.parent is None and self.parent is not self.smooth_cube:
            self.smooth_cube.parent = self.parent
        if self.parent is not self.smooth_cube:
            self.smooth_cube.data = self.data
        self.smooth_cube.smoothing_axis = self.current_axis
        self.smooth_cube.kernel_type = self.current_kernel_type
        if self.current_kernel_type == "median":
            self.smooth_cube.kernel_size = int(self.k_size.text())
        else:
            self.smooth_cube.kernel_size = float(self.k_size.text())
        self.smooth_cube.component_id = str(self.component_combo.currentText())
        self.smooth_cube.output_as_component = True

        if self.is_preview_active:
            self.parent.end_smoothing_preview()
            self.is_preview_active = False
        self.smooth_cube.multi_threading_smooth()
        return

    def update_preview_button(self):
        if self.parent is None or "spatial" != self.current_axis:
            self.previewButton.setDisabled(True)
            return
        self.previewButton.setDisabled(False)
        return

    def call_preview(self):
        try:
            self.preview()
        except Exception as e:
            info = QMessageBox.critical(self, "Error", str(e))
            self.cancel()
            raise

    def preview(self):
        """Preview current options"""
        success = self.input_validation()

        if not success:
            return

        if self.smooth_cube.parent is None and self.parent is not self.smooth_cube:
            self.smooth_cube.parent = self.parent
        self.smooth_cube.smoothing_axis = self.current_axis
        self.smooth_cube.kernel_type = self.current_kernel_type
        if self.current_kernel_type == "median":
            self.smooth_cube.kernel_size = int(self.k_size.text())
        else:
            self.smooth_cube.kernel_size = float(self.k_size.text())

        preview_function = self.smooth_cube.preview_smoothing
        preview_title = self.smooth_cube.get_preview_title()
        component_id = self.component_combo.currentData()
        self.parent.start_smoothing_preview(preview_function, component_id,
                                            preview_title)

        self.is_preview_active = True
        self.preview_message.show()

    def cancel(self):
        self.clean_up()

    def clean_up(self):
        self.close()
        if self.abort_window is not None:
            self.abort_window.close()
        if self.is_preview_active:
            self.parent.end_smoothing_preview()
            self.is_preview_active = False

    def closeEvent(self, event):
        if self.is_preview_active:
            self.parent.end_smoothing_preview()
            self.is_preview_active = False

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.clean_up()
Пример #38
0
class AnimationWindow(PyDialog):
    """
    +-------------------+
    | Animation         |
    +-------------------------+
    | icase   ______          |
    | scale   ______  Default |
    | time    ______  Default |
    |                         |
    | nframes ______  Default |
    | resolu. ______  Default |
    | Dir     ______  Browse  |
    | iFrame  ______          |
    |                         |
    | Animations:             |
    | o Scale, Phase, Time    |
    |                         |
    | x delete images         |
    | x repeat                |  # TODO: change to an integer
    | x make gif              |
    |                         |
    |      Step, RunAll       |
    |         Close           |
    +-------------------------+

    TODO: add key-frame support
    """
    def __init__(self, data, win_parent=None):
        PyDialog.__init__(self, data, win_parent)
        self.set_font_size(data['font_size'])
        self.istep = 0
        self._animate_type = 'time'

        self._updated_animation = False
        self._active_deformation = 0.
        self._icase_fringe = data['icase_fringe']
        self._icase_disp = data['icase_disp']
        self._icase_vector = data['icase_vector']

        self._default_name = data['name']
        self._default_time = data['time']
        self._default_fps = data['frames/sec']
        self._default_resolution = data['resolution']

        self._scale = data['scale']
        self._default_scale = data['default_scale']
        self._default_is_scale = data['is_scale']

        self._arrow_scale = data['arrow_scale']
        self._default_arrow_scale = data['default_arrow_scale']

        self._phase = data['phase']
        self._default_phase = data['default_phase']

        self._default_dirname = data['dirname']
        self._default_gif_name = os.path.join(self._default_dirname,
                                              data['name'] + '.gif')

        self.animation_types = [
            'Animate Scale',
        ]
        #'Animate Phase',
        #'Animate Time',
        #'Animate Frequency Sweep'
        #]

        self.setWindowTitle('Animate Model')
        self.create_widgets()
        self.create_layout()
        self.set_connections()

        self.is_gui = False
        if hasattr(self.win_parent, '_updated_legend'):
            self.win_parent.is_animate_open = True
            self.is_gui = True
        self.on_update_min_max_defaults()

    def create_widgets(self):
        """creates the menu objects"""
        self.box_scale = QGroupBox('Animate Scale')
        self.box_time = QGroupBox('Animate Time')

        icase_max = 1000  # TODO: update 1000

        self.checkbox_fringe = QCheckBox('Animate')
        self.checkbox_fringe.setToolTip(
            'Animate the fringe in addition to the deflection')
        #self.checkbox_disp = QCheckBox('Animate')
        self.checkbox_fringe.setEnabled(False)

        self.icase_fringe_label = QLabel("iCase (Fringe):")
        self.icase_fringe_edit = QSpinBox(self)
        self.icase_fringe_edit.setRange(0, icase_max)
        self.icase_fringe_edit.setSingleStep(1)
        if self._icase_fringe is not None:
            self.icase_fringe_edit.setValue(self._icase_fringe)
        self.icase_fringe_edit.setToolTip(
            'Case Number for the Scale/Phase Animation Type.\n'
            'Defaults to the result you had shown when you clicked "Create Animation".\n'
            'iCase can be seen by clicking "Apply" on a result.')

        self.icase_disp_label = QLabel("iCase (Disp):")
        self.icase_disp_edit = QSpinBox(self)
        self.icase_disp_edit.setRange(1, icase_max)
        self.icase_disp_edit.setSingleStep(1)
        if self._icase_disp is not None:
            self.icase_disp_edit.setValue(self._icase_disp)

        self.checkbox_vector = QCheckBox('Animate')
        self.checkbox_vector.setToolTip(
            'Animate the vector in addition to the deflection')
        self.checkbox_vector.hide()
        #self.checkbox_disp = QCheckBox('Animate')

        self.icase_vector_label = QLabel("iCase (Vector):")
        self.icase_vector_edit = QSpinBox(self)
        self.icase_vector_edit.setRange(1, icase_max)
        self.icase_vector_edit.setSingleStep(1)
        if self._icase_vector is not None:
            self.icase_vector_edit.setValue(self._icase_vector)

        self.scale_label = QLabel("True Scale:")
        self.scale_edit = QLineEdit(str(self._scale))
        self.scale_button = QPushButton("Default")
        self.scale_edit.setToolTip('Scale factor of the "deflection"')
        self.scale_button.setToolTip('Sets the scale factor of the gif to %s' %
                                     self._scale)

        self.arrow_scale_label = QLabel("Arrow Scale:")
        self.arrow_scale_edit = QLineEdit(str(self._scale))
        self.arrow_scale_button = QPushButton("Default")
        self.arrow_scale_edit.setToolTip('Scale factor of the "arrows"')
        self.arrow_scale_button.setToolTip(
            'Sets the arrow scale factor of the gif to %s' % self._arrow_scale)

        self.arrow_scale_label.setVisible(False)
        self.arrow_scale_edit.setVisible(False)
        self.arrow_scale_button.setVisible(False)

        self.time_label = QLabel("Total Time (sec):")
        self.time_edit = QDoubleSpinBox(self)
        self.time_edit.setValue(self._default_time)
        self.time_edit.setRange(0.1, 5. * 60.)
        self.time_edit.setDecimals(2)
        self.time_edit.setSingleStep(0.1)
        self.time_button = QPushButton("Default")
        self.time_edit.setToolTip("Total time of the gif")
        self.time_button.setToolTip('Sets the total time of the gif to %.2f' %
                                    self._default_time)

        self.fps_label = QLabel("Frames/Second:")
        self.fps_edit = QSpinBox(self)
        self.fps_edit.setRange(1, 60)
        self.fps_edit.setSingleStep(1)
        self.fps_edit.setValue(self._default_fps)
        self.fps_button = QPushButton("Default")
        self.fps_edit.setToolTip(
            "A higher FPS is smoother, but may not play well for large gifs")
        self.fps_button.setToolTip('Sets the FPS to %s' % self._default_fps)

        self.resolution_label = QLabel("Resolution Scale:")
        self.resolution_edit = QSpinBox(self)
        self.resolution_edit.setRange(1, 5)
        self.resolution_edit.setSingleStep(1)
        self.resolution_edit.setValue(self._default_resolution)
        self.resolution_button = QPushButton("Default")
        self.resolution_edit.setToolTip(
            'Scales the window resolution by an integer factor')
        self.resolution_button.setToolTip('Sets the resolution to %s' %
                                          self._default_resolution)

        #-----------------
        # Time plot
        self.fringe_label = QLabel("Fringe")

        self.icase_fringe_start_edit = QSpinBox(self)
        self.icase_fringe_start_edit.setRange(0, icase_max)
        self.icase_fringe_start_edit.setSingleStep(1)
        self.icase_fringe_start_edit.setValue(self._icase_fringe)
        self.icase_fringe_start_button = QPushButton("Default")

        self.icase_fringe_end_edit = QSpinBox(self)
        self.icase_fringe_end_edit.setRange(0, icase_max)
        self.icase_fringe_end_edit.setSingleStep(1)
        self.icase_fringe_end_edit.setValue(self._icase_fringe)
        self.icase_fringe_end_button = QPushButton("Default")

        self.icase_fringe_delta_edit = QSpinBox(self)
        self.icase_fringe_delta_edit.setRange(1, icase_max)
        self.icase_fringe_delta_edit.setSingleStep(1)
        self.icase_fringe_delta_edit.setValue(1)
        self.icase_fringe_delta_button = QPushButton("Default")

        self.displacement_label = QLabel("Displacement")
        self.icase_start = QLabel("iCase Start:")
        self.icase_disp_start_edit = QSpinBox(self)
        self.icase_disp_start_edit.setRange(0, icase_max)
        self.icase_disp_start_edit.setSingleStep(1)
        self.icase_disp_start_edit.setValue(self._icase_fringe)
        self.icase_disp_start_button = QPushButton("Default")

        self.icase_end_label = QLabel("iCase End:")
        self.icase_disp_end_edit = QSpinBox(self)
        self.icase_disp_end_edit.setRange(0, icase_max)
        self.icase_disp_end_edit.setSingleStep(1)
        self.icase_disp_end_edit.setValue(self._icase_fringe)
        self.icase_disp_end_button = QPushButton("Default")

        self.icase_delta_label = QLabel("iCase Delta:")
        self.icase_disp_delta_edit = QSpinBox(self)
        self.icase_disp_delta_edit.setRange(1, icase_max)
        self.icase_disp_delta_edit.setSingleStep(1)
        self.icase_disp_delta_edit.setValue(1)
        self.icase_disp_delta_button = QPushButton("Default")

        self.min_value_enable = QCheckBox()
        self.min_value_label = QLabel("Min Value:")
        self.min_value_edit = QLineEdit('')
        #self.min_value_edit.setRange(1, 1000)
        #self.min_value_edit.setSingleStep(1)
        #self.min_value_edit.setValue(1)
        self.min_value_button = QPushButton("Default")

        self.max_value_enable = QCheckBox()
        self.max_value_label = QLabel("Max Value:")
        self.max_value_edit = QLineEdit('')
        #self.min_value_edit.setRange(1, 1000)  # TODO: update 1000
        #self.min_value_edit.setSingleStep(1)
        #self.min_value_edit.setValue(1)
        self.max_value_button = QPushButton("Default")

        # TODO: enable this (uncomment) ------------------------------------------
        #self.min_value_enable.hide()
        #self.min_value.hide()
        #self.min_value_edit.hide()
        #self.min_value_button.hide()

        #self.max_value_enable.hide()
        #self.max_value.hide()
        #self.max_value_edit.hide()
        #self.max_value_button.hide()
        # TODO: enable this (uncomment) ------------------------------------------

        self.icase_disp_start_edit.setToolTip(
            'The first frame of the animation')
        self.icase_disp_end_edit.setToolTip(
            'The last frame of the animation\n'
            'Assumes icase_start + nframes * icase_delta = icase_end')
        self.icase_disp_delta_edit.setToolTip(
            'The frame step size (to skip non-consecutive results).\n'
            'Frame skipping can be used to:\n'
            "  - skip across results that you don't want to plot\n"
            '  - adjust the FPS')

        self.min_value_edit.setToolTip(
            'Min value of the legend (not supported)')
        self.max_value_edit.setToolTip(
            'Max value of the legend (not supported)')
        #'time' : 0.,
        #'default_time' : 0,
        #'icase_start' : 10,
        #'icase_delta' : 3,
        #'min_value' : 0.,
        #'max_value' : 1000.,

        self.browse_folder_label = QLabel('Output Directory:')
        self.browse_folder_edit = QLineEdit(str(self._default_dirname))
        self.browse_folder_button = QPushButton('Browse')
        self.browse_folder_edit.setToolTip(
            'Location to save the png/gif files')

        self.gif_label = QLabel("Gif Filename:")
        self.gif_edit = QLineEdit(str(self._default_name + '.gif'))
        self.gif_button = QPushButton('Default')
        self.gif_edit.setToolTip('Name of the gif')
        self.gif_button.setToolTip('Sets the name of the gif to %s.gif' %
                                   self._default_name)

        # scale / phase
        if 1:  # pragma: no cover
            self.animate_scale_radio = QRadioButton("Animate Scale")
            self.animate_phase_radio = QRadioButton("Animate Phase")
            self.animate_time_radio = QRadioButton("Animate Time")
            self.animate_freq_sweeep_radio = QRadioButton(
                "Animate Frequency Sweep")
            self.animate_scale_radio.setToolTip(
                'Animates the scale factor based on the "Animation Type"')
            self.animate_time_radio.setToolTip(
                'Animates the time/load/mode step')

            self.animate_scale_radio.setChecked(self._default_is_scale)
            self.animate_phase_radio.setChecked(not self._default_is_scale)
            self.animate_time_radio.setChecked(False)

            msg = 'Scale : Animates the scale factor based on the "Animation Profile"\n'
            if self._default_phase is None:
                self.animate_phase_radio.setDisabled(True)
                self.animate_phase_radio.setToolTip(
                    'Animates the phase angle '
                    '(only for complex results)')
                msg += 'Phase : Animates the phase angle (only for complex results)\n'
            else:
                self.animate_phase_radio.setToolTip("Animates the phase angle")
                msg += 'Phase : Animates the phase angle\n'
            msg += (
                'Time : Animates the time/load/mode step\n'
                'Freq Sweep : Animates a complex result across a range of frequencies '
                '(not supported)\n')

            self.animate_freq_sweeep_radio.setDisabled(True)
            self.animate_freq_sweeep_radio.setToolTip(
                'Animates a complex result across a range of frequencies (not supported)'
            )
        else:
            msg = 'Scale : Animates the scale factor based on the "Animation Profile"\n'
            if self._default_phase is None:
                #self.animate_phase_radio.setDisabled(True)
                #self.animate_phase_radio.setToolTip('Animates the phase angle '
                #'(only for complex results)')
                msg += 'Phase : Animates the phase angle (only for complex results)\n'
            else:
                #self.animate_phase_radio.setToolTip("Animates the phase angle")
                msg += 'Phase : Animates the phase angle\n'
            msg += (
                'Time : Animates the time/load/mode step\n'
                'Freq Sweep : Animates a complex result across a range of frequencies '
                '(not supported)\n')

        self.animation_type = QLabel("Animation Type:")
        animation_type = OrderedDict()
        #scale_msg = 'Scale\n'
        #phase_msg = 'Phase\n'
        #time_msg = 'Time\n'
        #animation_types = [
        #('Animate Scale', scale_msg),
        #('Animate Phase', phase_msg),
        #('Animate Time', time_msg),
        ##'Animate Frequency Sweep'
        #]

        if self._phase is not None:
            self.animation_types.append('Animate Phase')
        self.animation_types.append('Animate Time')

        self.animation_profile_label = QLabel("Animation Profile:")

        self.animation_profile_edit = QComboBox()
        for animation_profile in ANIMATION_PROFILES:
            self.animation_profile_edit.addItem(animation_profile)
        self.animation_profile_edit.setToolTip('The profile for a scaled GIF')

        self.animation_type_edit = QComboBox()
        # TODO: add a tooltip for each item
        for animation_type in self.animation_types:
            self.animation_type_edit.addItem(animation_type)
        #self.animation_type_edit.setToolTip('The profile for a scaled GIF')
        self.animation_type_edit.setToolTip(msg.rstrip())

        self.csv_profile_label = QLabel("CSV profile:")
        self.csv_profile_edit = QLineEdit()
        self.csv_profile_browse_button = QPushButton('Browse')
        self.csv_profile_edit.setToolTip(
            'The path to the CSV file of (Scale1, Scale2, Scale3, ...)')

        #widget = QWidget(self)
        #horizontal_vertical_group = QButtonGroup(widget)
        #horizontal_vertical_group.addButton(self.animate_scale_radio)
        #horizontal_vertical_group.addButton(self.animate_phase_radio)
        #horizontal_vertical_group.addButton(self.animate_time_radio)
        #horizontal_vertical_group.addButton(self.animate_freq_sweeep_radio)

        # animate in gui
        self.animate_in_gui_checkbox = QCheckBox("Animate In GUI?")
        self.animate_in_gui_checkbox.setChecked(True)

        # make images
        self.make_images_checkbox = QCheckBox("Make images?")
        self.make_images_checkbox.setChecked(True)

        # make images
        self.overwrite_images_checkbox = QCheckBox("Overwrite images?")
        self.overwrite_images_checkbox.setChecked(True)

        # delete images when finished
        self.delete_images_checkbox = QCheckBox("Delete images when finished?")
        self.delete_images_checkbox.setChecked(True)

        # endless loop
        self.repeat_checkbox = QCheckBox("Repeat?")
        self.repeat_checkbox.setChecked(True)
        self.repeat_checkbox.setToolTip(
            "Repeating creates an infinitely looping gif")

        # endless loop
        self.make_gif_checkbox = QCheckBox("Make Gif?")
        if IS_IMAGEIO:
            self.make_gif_checkbox.setChecked(True)
        else:
            self.make_gif_checkbox.setChecked(False)
            self.make_gif_checkbox.setEnabled(False)
            self.make_gif_checkbox.setToolTip(
                'imageio is not available; install it')

        # bottom buttons
        self.step_button = QPushButton("Step")
        self.wipe_button = QPushButton("Wipe Deformed Shape")
        self.stop_button = QPushButton("Stop")
        self.run_button = QPushButton("Run")

        self.step_button.setToolTip(
            'Steps through the animation (for testing)')
        self.wipe_button.setToolTip(
            'Removes the existing "deflecton" from the animation')
        self.stop_button.setToolTip('Stops the animation')
        self.run_button.setToolTip('Creates the animation')
        self.step_button.hide()
        self.wipe_button.hide()

        self.wipe_button.setEnabled(False)
        #self.wipe_button.hide()
        self.stop_button.setEnabled(False)

        self.cancel_button = QPushButton("Close")

        #self.set_grid_time(enabled=False)
        #self.set_grid_scale(enabled=self._default_is_scale)
        if self._default_phase:
            self.on_animate_phase(force=True)
            set_combo_box_text(self.animation_type_edit, 'Animate Phase')
        else:
            self.on_animate_scale(force=True)

    def set_connections(self):
        """creates button actions"""
        self.checkbox_vector.clicked.connect(self.on_checkbox_vector)

        self.scale_button.clicked.connect(self.on_default_scale)
        self.arrow_scale_button.clicked.connect(self.on_default_arrow_scale)
        self.time_button.clicked.connect(self.on_default_time)

        self.fps_button.clicked.connect(self.on_default_fps)
        self.resolution_button.clicked.connect(self.on_default_resolution)
        self.browse_folder_button.clicked.connect(self.on_browse_folder)
        self.csv_profile_browse_button.clicked.connect(self.on_browse_csv)
        self.gif_button.clicked.connect(self.on_default_name)

        self.step_button.clicked.connect(self.on_step)
        self.wipe_button.clicked.connect(self.on_wipe)
        self.stop_button.clicked.connect(self.on_stop)
        self.run_button.clicked.connect(self.on_run)
        self.min_value_enable.clicked.connect(self.on_min_value_enable)
        self.max_value_enable.clicked.connect(self.on_max_value_enable)

        self.min_value_button.clicked.connect(self.on_min_value_default)
        self.max_value_button.clicked.connect(self.on_max_value_default)
        self.icase_disp_start_button.clicked.connect(
            self.on_update_min_max_defaults)

        #self.animate_scale_radio.clicked.connect(self.on_animate_scale)
        #self.animate_phase_radio.clicked.connect(self.on_animate_phase)
        #self.animate_time_radio.clicked.connect(self.on_animate_time)
        self.animation_type_edit.currentIndexChanged.connect(self.on_animate)
        #self.animate_freq_sweeep_radio

        self.cancel_button.clicked.connect(self.on_cancel)

        self.animate_in_gui_checkbox.clicked.connect(self.on_animate_in_gui)
        self.animate_in_gui_checkbox.setChecked(True)
        self.on_animate_in_gui()

    def on_checkbox_vector(self):
        is_enabled = self.checkbox_vector.isEnabled()
        is_checked = self.checkbox_vector.isChecked()
        enable_edit = is_enabled and is_checked
        self.icase_vector_label.setEnabled(is_checked)
        self.icase_vector_edit.setEnabled(enable_edit)

    def on_animate_in_gui(self):
        animate_in_gui = self.animate_in_gui_checkbox.isChecked()
        enable = not animate_in_gui
        if HIDE_WHEN_INACTIVE:
            self.make_images_checkbox.setVisible(enable)
            self.delete_images_checkbox.setVisible(enable)
            self.make_gif_checkbox.setVisible(enable)
            self.repeat_checkbox.setVisible(enable)
            self.resolution_button.setVisible(enable)
            self.resolution_label.setVisible(enable)
            self.resolution_edit.setVisible(enable)
            self.gif_label.setVisible(enable)
            self.gif_edit.setVisible(enable)
            self.gif_button.setVisible(enable)
            self.browse_folder_label.setVisible(enable)
            self.browse_folder_button.setVisible(enable)
            self.browse_folder_edit.setVisible(enable)
            self.step_button.setEnabled(enable)

        self.make_images_checkbox.setEnabled(enable)
        self.delete_images_checkbox.setEnabled(enable)
        self.make_gif_checkbox.setEnabled(enable)
        self.repeat_checkbox.setEnabled(enable)
        self.resolution_button.setEnabled(enable)
        self.resolution_edit.setEnabled(enable)
        self.gif_edit.setEnabled(enable)
        self.gif_button.setEnabled(enable)
        self.browse_folder_button.setEnabled(enable)
        self.browse_folder_edit.setEnabled(enable)
        self.step_button.setEnabled(enable)
        #wipe_button

    def on_animate(self, value):
        """
        animate pulldown

        Parameters
        ----------
        value : int
            index in animation_types
        """
        #animation_types = ['Animate Scale', 'Animate Phase', 'Animate Time',
        #'Animate Frequency Sweep']
        animation_type = self.animation_types[value]
        if animation_type == 'Animate Scale':
            self.on_animate_scale()
        elif animation_type == 'Animate Phase':
            self.on_animate_phase()
        elif animation_type == 'Animate Time':
            self.on_animate_time()
        else:
            raise NotImplementedError('value = ', value)

    def on_animate_time(self, force=False):
        """enables the secondary input"""
        #print('on_animate_time')
        if self._animate_type == 'scale' or force:
            self.set_grid_scale(False, 'time')
        self.set_grid_time(True, 'time')
        self._animate_type = 'time'

    def on_animate_scale(self, force=False):
        """enables the secondary input"""
        #print('on_animate_scale')
        self.set_grid_scale(True, 'scale')
        if self._animate_type == 'time' or force:
            self.set_grid_time(False, 'scale')
        self._animate_type = 'scale'

    def on_animate_phase(self, force=False):
        """enables the secondary input"""
        #print('on_animate_phase')
        if self._animate_type == 'scale' or force:
            self.set_grid_scale(False, 'phase')
        if self._animate_type == 'time' or force:
            self.set_grid_time(False, 'phase')
        self._animate_type = 'phase'

    def set_grid_scale(self, enabled=True, word=''):
        """enables/disables the secondary input"""
        #print('%s-set_grid_scale; enabled = %r' % (word, enabled))
        if HIDE_WHEN_INACTIVE:
            self.box_scale.setVisible(enabled)
            self.animation_profile_label.setVisible(enabled)
            self.animation_profile_edit.setVisible(enabled)
            #self.min_value_enable.setVisible(enabled)
            #self.max_value_enable.setVisible(enabled)

        self.animation_profile_label.setEnabled(enabled)
        self.animation_profile_edit.setEnabled(enabled)

        # TODO: doesn't work...
        #self.csv_profile.setEnabled(enabled)
        #self.csv_profile_edit.setEnabled(enabled)
        #self.csv_profile_button.setEnabled(enabled)

        self.min_value_enable.setEnabled(enabled)
        self.max_value_enable.setEnabled(enabled)
        self.on_min_value_enable()
        self.on_max_value_enable()

    def set_grid_time(self, enabled=True, word=''):
        """enables/disables the secondary input"""
        #print('%s-set_grid_time; enabled = %r' % (word, enabled))
        if HIDE_WHEN_INACTIVE:
            self.box_time.setVisible(enabled)
            self.checkbox_fringe.setVisible(not enabled)
            self.icase_fringe_label.setVisible(not enabled)
            self.icase_fringe_edit.setVisible(not enabled)
            self.icase_disp_label.setVisible(not enabled)
            self.icase_disp_edit.setVisible(not enabled)
            self.icase_vector_label.setVisible(not enabled)
            self.icase_vector_edit.setVisible(not enabled)

            #self.icase_fringe_delta_edit.setVisible(enabled)
            self.icase_disp_delta_edit.setVisible(enabled)
            self.icase_disp_delta_edit.setVisible(enabled)
            self.fps_label.setVisible(enabled)
            self.fps_edit.setVisible(enabled)
            self.fps_button.setVisible(enabled)

        self.displacement_label.setEnabled(enabled)
        self.fringe_label.setEnabled(enabled)

        self.icase_start.setEnabled(enabled)
        self.icase_disp_start_edit.setEnabled(enabled)
        self.icase_disp_start_button.setEnabled(enabled)
        self.icase_fringe_start_edit.setEnabled(enabled)
        self.icase_fringe_start_button.setEnabled(enabled)

        self.icase_end_label.setEnabled(enabled)
        self.icase_disp_end_edit.setEnabled(enabled)
        self.icase_disp_end_button.setEnabled(enabled)
        self.icase_fringe_end_edit.setEnabled(enabled)
        self.icase_fringe_end_button.setEnabled(enabled)

        self.icase_delta_label.setEnabled(enabled)
        self.icase_disp_delta_edit.setEnabled(enabled)
        self.icase_disp_delta_button.setEnabled(enabled)
        self.icase_fringe_delta_edit.setEnabled(enabled)
        self.icase_fringe_delta_button.setEnabled(enabled)

        #-----------------------------------------------------------------------
        is_min_enabled = self.min_value_enable.isChecked()
        self.min_value_label.setEnabled(is_min_enabled)
        self.min_value_edit.setEnabled(is_min_enabled)
        self.min_value_button.setEnabled(is_min_enabled)

        is_max_enabled = self.max_value_enable.isChecked()
        self.max_value_label.setEnabled(is_max_enabled)
        self.max_value_edit.setEnabled(is_max_enabled)
        self.max_value_button.setEnabled(is_max_enabled)

        self.min_value_enable.setEnabled(enabled)
        self.on_min_value_enable()
        #self.min_value.setEnabled(enabled)
        #self.min_value_edit.setEnabled(enabled)
        #self.min_value_button.setEnabled(enabled)

        self.max_value_enable.setEnabled(enabled)
        self.on_max_value_enable()
        #self.max_value.setEnabled(enabled)
        #self.max_value_edit.setEnabled(enabled)
        #self.max_value_button.setEnabled(enabled)

        self.icase_fringe_label.setEnabled(not enabled)
        self.icase_fringe_edit.setEnabled(not enabled)
        self.checkbox_fringe.setEnabled(not enabled)

        self.icase_disp_label.setEnabled(not enabled)
        self.icase_disp_edit.setEnabled(not enabled)

        self.icase_vector_label.setEnabled(not enabled)
        self.icase_vector_edit.setEnabled(not enabled)
        self.checkbox_vector.setEnabled(not enabled)
        self.on_checkbox_vector()

        self.fps_label.setEnabled(not enabled)
        self.fps_edit.setEnabled(not enabled)
        self.fps_button.setEnabled(not enabled)

    def on_min_value_enable(self):
        """
        The min edit value box is enabled when we switch to time
        and the box is checked
        """
        is_min_enabled = self.min_value_enable.isChecked(
        ) and self.min_value_enable.isEnabled()
        self.min_value_label.setEnabled(is_min_enabled)
        self.min_value_edit.setEnabled(is_min_enabled)
        self.min_value_button.setEnabled(is_min_enabled)

    def on_max_value_enable(self):
        """
        The max edit value box is enabled when we switch to time
        and the box is checked
        """
        is_max_enabled = self.max_value_enable.isChecked(
        ) and self.max_value_enable.isEnabled()
        self.max_value_label.setEnabled(is_max_enabled)
        self.max_value_edit.setEnabled(is_max_enabled)
        self.max_value_button.setEnabled(is_max_enabled)

    def on_update_min_max_defaults(self):
        """
        When the icase is changed, the min/max value default message is changed
        """
        icase = self.icase_disp_start_edit.value()
        min_value, max_value = self.get_min_max(icase)
        self.min_value_button.setToolTip('Sets the min value to %g' %
                                         min_value)
        self.max_value_button.setToolTip('Sets the max value to %g' %
                                         max_value)

    def on_min_value_default(self):
        """When min default icase is pressued, update the value"""
        icase = self.icase_disp_start_edit.value()
        min_value = self.get_min_max(icase)[0]
        self.min_value_edit.setText(str(min_value))
        self.min_value_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_max_value_default(self):
        """When max default icase is pressued, update the value"""
        icase = self.icase_disp_start_edit.value()
        max_value = self.get_min_max(icase)[1]
        self.max_value_edit.setText(str(max_value))
        self.max_value_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_browse_folder(self):
        """opens a folder dialog"""
        dirname = getexistingdirectory(parent=self,
                                       caption='Select a Directory',
                                       basedir='',
                                       options=QFileDialog.ShowDirsOnly)
        if not dirname:
            return
        self.browse_folder_edit.setText(dirname)

    def on_browse_csv(self):
        """opens a file dialog"""
        default_filename = ''
        file_types = 'Delimited Text (*.txt; *.dat; *.csv)'
        dirname = open_file_dialog(self, 'Select a CSV File', default_filename,
                                   file_types)
        if not dirname:
            return
        self.csv_profile_browse_button.setText(dirname)

    def on_default_name(self):
        """sets the default gif name"""
        self.gif_edit.setText(self._default_name + '.gif')

    def on_default_scale(self):
        """sets the default displacement scale factor"""
        self.scale_edit.setText(str(self._default_scale))
        self.scale_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_arrow_scale(self):
        """sets the default arrow scale factor"""
        self.arrow_scale_edit.setText(str(self._default_arrow_scale))
        self.arrow_scale_edit.setStyleSheet("QLineEdit{background: white;}")

    def on_default_time(self):
        """sets the default gif time"""
        self.time_edit.setValue(self._default_time)

    def on_default_fps(self):
        """sets the default FPS"""
        self.fps_edit.setValue(self._default_fps)

    def on_default_resolution(self):
        """sets the default image resolution scale factor"""
        self.resolution_edit.setValue(self._default_resolution)

    def create_layout(self):
        """displays the menu objects"""

        grid = QGridLayout()
        irow = 0
        grid.addWidget(self.icase_fringe_label, irow, 0)
        grid.addWidget(self.icase_fringe_edit, irow, 1)
        grid.addWidget(self.checkbox_fringe, irow, 2)
        irow += 1

        grid.addWidget(self.icase_disp_label, irow, 0)
        grid.addWidget(self.icase_disp_edit, irow, 1)
        #grid.addWidget(self.checkbox_disp, irow, 2)
        irow += 1

        grid.addWidget(self.icase_vector_label, irow, 0)
        grid.addWidget(self.icase_vector_edit, irow, 1)
        grid.addWidget(self.checkbox_vector, irow, 2)
        irow += 1

        grid.addWidget(self.scale_label, irow, 0)
        grid.addWidget(self.scale_edit, irow, 1)
        grid.addWidget(self.scale_button, irow, 2)
        irow += 1

        grid.addWidget(self.arrow_scale_label, irow, 0)
        grid.addWidget(self.arrow_scale_edit, irow, 1)
        grid.addWidget(self.arrow_scale_button, irow, 2)
        irow += 1

        grid.addWidget(self.time_label, irow, 0)
        grid.addWidget(self.time_edit, irow, 1)
        grid.addWidget(self.time_button, irow, 2)
        irow += 1

        # spacer
        spacer = QLabel('')

        grid.addWidget(self.fps_label, irow, 0)
        grid.addWidget(self.fps_edit, irow, 1)
        grid.addWidget(self.fps_button, irow, 2)
        irow += 1

        grid.addWidget(self.animation_type, irow, 0)
        grid.addWidget(self.animation_type_edit, irow, 1)
        irow += 1

        grid.addWidget(spacer, irow, 0)
        irow += 1

        #----------
        #Time
        grid_time = QGridLayout()
        jrow = 0

        self.fringe_label.setAlignment(Qt.AlignCenter)
        self.displacement_label.setAlignment(Qt.AlignCenter)

        if not IS_TIME_FRINGE:
            self.fringe_label.hide()
            self.icase_fringe_delta_edit.hide()
            self.icase_fringe_start_edit.hide()
            self.icase_fringe_end_edit.hide()
            self.icase_fringe_delta_button.hide()

        grid_time.addWidget(self.displacement_label, jrow, 1)
        grid_time.addWidget(self.fringe_label, jrow, 2)
        jrow += 1

        grid_time.addWidget(self.icase_start, jrow, 0)
        grid_time.addWidget(self.icase_disp_start_edit, jrow, 1)
        grid_time.addWidget(self.icase_fringe_start_edit, jrow, 2)
        #grid_time.addWidget(self.icase_disp_start_button, jrow, 2)
        jrow += 1

        grid_time.addWidget(self.icase_end_label, jrow, 0)
        grid_time.addWidget(self.icase_disp_end_edit, jrow, 1)
        grid_time.addWidget(self.icase_fringe_end_edit, jrow, 2)
        #grid_time.addWidget(self.icase_end_button, jrow, 2)
        jrow += 1

        grid_time.addWidget(self.icase_delta_label, jrow, 0)
        grid_time.addWidget(self.icase_disp_delta_edit, jrow, 1)
        grid_time.addWidget(self.icase_fringe_delta_edit, jrow, 2)
        #grid_time.addWidget(self.icase_delta_button, jrow, 2)
        jrow += 1

        hbox_min = QHBoxLayout()
        hbox_min.addWidget(self.min_value_enable)
        hbox_min.addWidget(self.min_value_label)
        grid_time.addLayout(hbox_min, jrow, 0)
        grid_time.addWidget(self.min_value_edit, jrow, 1)
        grid_time.addWidget(self.min_value_button, jrow, 2)
        jrow += 1

        hbox_max = QHBoxLayout()
        hbox_max.addWidget(self.max_value_enable)
        hbox_max.addWidget(self.max_value_label)
        grid_time.addLayout(hbox_max, jrow, 0)
        grid_time.addWidget(self.max_value_edit, jrow, 1)
        grid_time.addWidget(self.max_value_button, jrow, 2)
        jrow += 1

        grid_time.addWidget(spacer, jrow, 0)
        jrow += 1

        #--------------
        grid_scale = QGridLayout()
        grid_scale.addWidget(self.animation_profile_label, 0, 0)
        grid_scale.addWidget(self.animation_profile_edit, 0, 1)

        #grid_scale.addWidget(self.csv_profile, 1, 0)
        #grid_scale.addWidget(self.csv_profile_edit, 1, 1)
        #grid_scale.addWidget(self.csv_profile_browse_button, 1, 2)

        self.csv_profile = QLabel("CSV profile:")
        self.csv_profile_edit = QLineEdit()
        self.csv_profile_button = QPushButton('Browse')

        #box_time = QVBoxLayout()
        # TODO: It's super annoying that the animate time box doesn't
        #       line up with the previous box
        self.box_scale.setLayout(grid_scale)

        self.box_time.setLayout(grid_time)
        #----------

        grid2 = QGridLayout()
        irow = 0
        #grid2.addWidget(self.animate_scale_radio, 8, 0)
        #grid2.addWidget(self.animate_phase_radio, 8, 1)
        #grid2.addWidget(self.animate_time_radio, 8, 2)
        #grid2.addWidget(self.animate_freq_sweeep_radio, 8, 3)

        grid2.addWidget(self.animate_in_gui_checkbox, irow, 0)
        irow += 1

        grid2.addWidget(self.resolution_label, irow, 0)
        grid2.addWidget(self.resolution_edit, irow, 1)
        grid2.addWidget(self.resolution_button, irow, 2)
        irow += 1

        grid2.addWidget(self.browse_folder_label, irow, 0)
        grid2.addWidget(self.browse_folder_edit, irow, 1)
        grid2.addWidget(self.browse_folder_button, irow, 2)
        irow += 1

        grid2.addWidget(self.gif_label, irow, 0)
        grid2.addWidget(self.gif_edit, irow, 1)
        grid2.addWidget(self.gif_button, irow, 2)
        irow += 1

        grid2.addWidget(self.make_images_checkbox, irow, 0)
        #grid2.addWidget(self.overwrite_images_checkbox, irow, 0)
        grid2.addWidget(self.delete_images_checkbox, irow, 1)
        grid2.addWidget(self.make_gif_checkbox, irow, 2)
        irow += 1
        grid2.addWidget(self.repeat_checkbox, irow, 0)
        irow += 1
        grid2.addWidget(spacer, irow, 0)

        grid_hbox = QHBoxLayout()
        grid_hbox.addWidget(spacer)
        grid_hbox.addLayout(grid2)
        grid_hbox.addWidget(spacer)

        # bottom buttons
        step_run_box = QHBoxLayout()
        step_run_box.addWidget(self.step_button)
        step_run_box.addWidget(self.wipe_button)
        step_run_box.addWidget(self.stop_button)
        step_run_box.addWidget(self.run_button)

        ok_cancel_box = QHBoxLayout()
        ok_cancel_box.addWidget(self.cancel_button)

        vbox = QVBoxLayout()
        vbox.addLayout(grid)
        vbox.addWidget(self.box_scale)
        vbox.addWidget(self.box_time)
        #vbox.addLayout(checkboxes)
        vbox.addLayout(grid_hbox)
        vbox.addStretch()
        vbox.addLayout(step_run_box)
        vbox.addLayout(ok_cancel_box)
        self.setLayout(vbox)

    def on_step(self):
        """click the Step button"""
        passed, validate_out = self.on_validate()
        if passed:
            try:
                self._make_gif(validate_out, istep=self.istep)
                self.istep += 1
            except IndexError:
                self._make_gif(validate_out, istep=0)
                self.istep += 1
            self.wipe_button.setEnabled(True)

    def on_wipe(self):
        """click the Wipe button"""
        passed, validate_out = self.on_validate(wipe=True)
        if passed:
            self.istep = 0
            self._make_gif(validate_out, istep=self.istep)
            self.wipe_button.setEnabled(False)
            self.stop_button.setEnabled(False)

    def on_stop(self):
        """click the Stop button"""
        #passed, validate_out = self.on_validate()
        #if passed:
        #self._make_gif(validate_out, stop_animation=True)
        if self.is_gui:
            self.win_parent.win_parent.stop_animation()

        self.wipe_button.setEnabled(True)
        self.stop_button.setEnabled(False)

    def on_run(self):
        """click the Run button"""
        self.istep = 0
        self.wipe_button.setEnabled(False)
        self.stop_button.setEnabled(True)

        passed, validate_out = self.on_validate()
        if passed:
            self._make_gif(validate_out, istep=None)
        return passed

    def _make_gif(self, validate_out, istep=None, stop_animation=False):
        """interface for making the gif"""
        (icase_fringe, icase_disp, icase_vector, scale, time, fps,
         animate_in_gui, magnify, output_dir, gifbase, min_value,
         max_value) = validate_out
        fps = int(fps)

        gif_filename = None
        if not stop_animation and not animate_in_gui and gifbase is not None:
            if gifbase.lower().endswith('.gif'):
                gifbase = gifbase[:-4]
            gif_filename = os.path.join(output_dir, gifbase + '.gif')

        animate_fringe = self.checkbox_fringe.isChecked()
        animate_vector = self.checkbox_vector.isChecked()

        animate_scale = self.animate_scale_radio.isChecked()
        animate_phase = self.animate_phase_radio.isChecked()
        animate_time = self.animate_time_radio.isChecked()

        if not self.checkbox_vector.isEnabled():
            icase_vector = None

        animate_scale = False
        animate_phase = False
        animate_time = False
        if self._animate_type == 'scale':
            animate_scale = True
        elif self._animate_type == 'phase':
            animate_phase = True
        elif self._animate_type == 'time':
            animate_time = True
        else:
            raise NotImplementedError(self._animate_type)

        make_images = self.make_images_checkbox.isChecked()
        delete_images = self.delete_images_checkbox.isChecked()
        make_gif = self.make_gif_checkbox.isChecked()
        animation_profile = str(self.animation_profile_edit.currentText())

        icase_disp_start = self.icase_disp_start_edit.value()
        icase_disp_end = self.icase_disp_end_edit.value()
        icase_disp_delta = self.icase_disp_delta_edit.value()

        bool_repeat = self.repeat_checkbox.isChecked(
        )  # TODO: change this to an integer
        if bool_repeat:
            nrepeat = 0
        else:
            nrepeat = 1
        #self.out_data['is_shown'] = self.show_radio.isChecked()
        #icase = self._icase

        if self.is_gui:
            self.win_parent.win_parent.make_gif(
                gif_filename,
                scale,
                istep=istep,
                animate_scale=animate_scale,
                animate_phase=animate_phase,
                animate_time=animate_time,
                icase_fringe=icase_fringe,
                icase_disp=icase_disp,
                icase_vector=icase_vector,
                animate_fringe=animate_fringe,
                animate_vector=animate_vector,
                icase_start=icase_disp_start,
                icase_end=icase_disp_end,
                icase_delta=icase_disp_delta,
                time=time,
                animation_profile=animation_profile,
                nrepeat=nrepeat,
                fps=fps,
                magnify=magnify,
                make_images=make_images,
                delete_images=delete_images,
                make_gif=make_gif,
                stop_animation=stop_animation,
                animate_in_gui=animate_in_gui,
                min_value=min_value,
                max_value=max_value,
            )

        self.out_data['clicked_ok'] = True
        self.out_data['close'] = True

    def get_min_max(self, icase):
        if self.is_gui:
            (obj, (i, name)) = self.win_parent.win_parent.result_cases[icase]
            min_value, max_value = obj.get_min_max(i, name)
        else:
            return 0., 1.0
        return min_value, max_value

    def on_validate(self, wipe=False):
        """checks to see if the input is valid"""
        # requires no special validation
        icase_fringe, flag0 = check_int(self.icase_fringe_edit)
        icase_disp, unused_flaga = check_int(self.icase_disp_edit)
        icase_vector, unused_flagb = check_int(self.icase_vector_edit)
        #icase_disp = self._icase_disp
        #icase_vector = self._icase_vector

        scale, flag1 = check_float(self.scale_edit)
        time, flag2 = check_float(self.time_edit)
        fps, flag3 = check_float(self.fps_edit)

        min_value = max_value = None
        flag4 = flag5 = True
        if self.min_value_edit.isEnabled():
            min_value, flag4 = check_float(self.min_value_edit)
        if self.max_value_edit.isEnabled():
            max_value, flag5 = check_float(self.max_value_edit)

        if wipe:
            animate_in_gui = False
            scale = 0.
            flag1 = True
        else:
            animate_in_gui = self.animate_in_gui_checkbox.isChecked()

        if animate_in_gui or wipe:
            passed = all([flag0, flag1, flag2, flag3, flag4, flag5])
            magnify, output_dir, gifbase = None, None, None
        else:
            magnify, flag6 = check_int(self.resolution_edit)
            output_dir, flag7 = self.check_path(self.browse_folder_edit)
            gifbase, flag8 = self.check_name(self.gif_edit)
            passed = all([
                flag0, flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8
            ])
        return passed, (icase_fringe, icase_disp, icase_vector, scale, time,
                        fps, animate_in_gui, magnify, output_dir, gifbase,
                        min_value, max_value)

    @staticmethod
    def check_name(cell):
        """verifies that the data is string-able"""
        cell_value = cell.text()
        try:
            text = str(cell_value).strip()
        except UnicodeEncodeError:
            cell.setStyleSheet("QLineEdit{background: red;}")
            return None, False

        if len(text):
            cell.setStyleSheet("QLineEdit{background: white;}")
            return text, True
        else:
            cell.setStyleSheet("QLineEdit{background: red;}")
            return None, False

    def check_path(self, cell):
        """verifies that the path exists"""
        text, passed = self.check_name(cell)
        if not passed:
            return None, False

        if os.path.exists(text):
            cell.setStyleSheet("QLineEdit{background: white;}")
            return text, True
        else:
            cell.setStyleSheet("QLineEdit{background: red;}")
            return None, False

    #def on_ok(self):
    #"""click the OK button"""
    #passed = self.on_apply()
    #if passed:
    #self.win_parent._animation_window_shown = False
    #self.close()
    ##self.destroy()

    def on_cancel(self):
        """click the Cancel button"""
        self.on_stop()
        self.out_data['close'] = True
        self.close()
Пример #39
0
class SelectSmoothing(QDialog):
    """
    SelectSmoothing launches a GUI and executes smoothing.
    Any output is added to the input data as a new component.
    """

    def __init__(self, data, parent=None, smooth_cube=None,
                 allow_preview=False, allow_spectral_axes=False):
        super(SelectSmoothing, self).__init__(parent)
        self.setWindowFlags(self.windowFlags() | Qt.Tool)
        self.parent = parent
        self.title = "Smoothing Selection"

        self.data = data  # Glue data to be smoothed

        # Check if smooth object is the caller
        if smooth_cube is None:
            self.smooth_cube = SmoothCube(data=self.data)
        else:
            self.smooth_cube = smooth_cube

        self.allow_spectral_axes = allow_spectral_axes

        self.allow_preview = allow_preview
        self.is_preview_active = False  # Flag to show if smoothing preview is active

        self.abort_window = None  # Small window pop up when smoothing.

        self.component_id = None  # Glue data component to smooth over
        self.current_axis = None  # Selected smoothing_axis
        self.current_kernel_type = None  # Selected kernel type, a key in SmoothCube.kernel_registry
        self.current_kernel_name = None  # Name of selected kernel

        self._init_selection_ui()  # Format and show gui

    def _init_selection_ui(self):
        # LINE 1: Radio box spatial vs spectral axis
        self.axes_prompt = QLabel("Smoothing Axis:")
        self.axes_prompt.setMinimumWidth(150)

        self.spatial_radio = QRadioButton("Spatial")
        self.spatial_radio.setChecked(True)
        self.current_axis = "spatial"
        self.spatial_radio.toggled.connect(self.spatial_radio_checked)

        self.spectral_radio = QRadioButton("Spectral")
        self.spectral_radio.toggled.connect(self.spectral_radio_checked)

        # hbl is short for Horizontal Box Layout
        hbl1 = QHBoxLayout()
        hbl1.addWidget(self.axes_prompt)
        hbl1.addWidget(self.spatial_radio)
        hbl1.addWidget(self.spectral_radio)

        # LINE 2: Kernel Type prompt
        self.k_type_prompt = QLabel("Kernel Type:")
        self.k_type_prompt.setMinimumWidth(150)
        # Load kernel types + names and add to drop down
        self._load_options()
        self.combo = QComboBox()
        self.combo.setMinimumWidth(150)
        self.combo.addItems(self.options[self.current_axis])

        hbl2 = QHBoxLayout()
        hbl2.addWidget(self.k_type_prompt)
        hbl2.addWidget(self.combo)

        # LINE 3: Kernel size
        self.size_prompt = QLabel(self.smooth_cube.get_kernel_size_prompt(self.current_kernel_type))
        self.size_prompt.setWordWrap(True)
        self.size_prompt.setMinimumWidth(150)
        self.unit_label = QLabel(self.smooth_cube.get_kernel_unit(self.current_kernel_type))
        self.k_size = QLineEdit("1")  # Default Kernel size set here

        hbl3 = QHBoxLayout()
        hbl3.addWidget(self.size_prompt)
        hbl3.addWidget(self.k_size)
        hbl3.addWidget(self.unit_label)

        # LINE 4: Data component drop down
        self.component_prompt = QLabel("Data Component:")
        self.component_prompt.setWordWrap(True)
        self.component_prompt.setMinimumWidth(150)
        # Load component_ids and add to drop down

        # Add the data component labels to the drop down, with the ComponentID
        # set as the userData:

        if self.parent is not None and hasattr(self.parent, 'data_components'):
            labeldata = [(str(cid), cid) for cid in self.parent.data_components]
        else:
            labeldata = [(str(cid), cid) for cid in self.data.main_components()]

        self.component_combo = QComboBox()
        update_combobox(self.component_combo, labeldata)

        self.component_combo.setMaximumWidth(150)
        self.component_combo.setCurrentIndex(0)
        if self.allow_preview:
            self.component_combo.currentIndexChanged.connect(self.update_preview_button)

        hbl4 = QHBoxLayout()
        hbl4.addWidget(self.component_prompt)
        hbl4.addWidget(self.component_combo)

        # Line 5: Preview Message
        message = "Info: Smoothing previews are displayed on " \
                  "CubeViz's left and single image viewers."
        self.preview_message = QLabel(message)
        self.preview_message.setWordWrap(True)
        self.preview_message.hide()
        hbl5 = QHBoxLayout()
        hbl5.addWidget(self.preview_message)

        # LINE 6: preview ok cancel buttons
        self.previewButton = QPushButton("Preview Slice")
        self.previewButton.clicked.connect(self.call_preview)

        self.okButton = QPushButton("Smooth Cube")
        self.okButton.clicked.connect(self.call_main)
        self.okButton.setDefault(True)

        self.cancelButton = QPushButton("Cancel")
        self.cancelButton.clicked.connect(self.cancel)

        hbl6 = QHBoxLayout()
        hbl6.addStretch(1)
        if self.allow_preview:
            hbl6.addWidget(self.previewButton)
        hbl6.addWidget(self.cancelButton)
        hbl6.addWidget(self.okButton)

        # Add Lines to Vertical Layout
        # vbl is short for Vertical Box Layout
        vbl = QVBoxLayout()
        if self.allow_spectral_axes:
            vbl.addLayout(hbl1)
        vbl.addLayout(hbl2)
        vbl.addLayout(hbl3)
        vbl.addLayout(hbl4)
        vbl.addLayout(hbl5)
        vbl.addLayout(hbl6)

        self.setLayout(vbl)
        self.setMaximumWidth(330)

        # Connect kernel combo box to event handler
        self.combo.currentIndexChanged.connect(self.selection_changed)
        self.selection_changed(0)

        self.show()

    def _load_options(self):
        """Extract names + types of kernels from SmoothCube.kernel_registry"""
        kernel_registry = self.smooth_cube.get_kernel_registry()

        self.options = {"spatial": [], "spectral": []}
        for k in kernel_registry:
            axis = kernel_registry[k]["axis"]
            for a in axis:
                if "spatial" == a:
                    self.options["spatial"].append(kernel_registry[k]["name"])
                elif "spectral" == a:
                    self.options["spectral"].append(kernel_registry[k]["name"])
        self.options["spectral"].sort()
        self.options["spatial"].sort()
        self.current_kernel_name = self.options[self.current_axis][0]
        self.current_kernel_type = self.smooth_cube.name_to_kernel_type(self.options[self.current_axis][0])

    def selection_changed(self, i):
        """
        Update kernel type, units, etc... when
        kernel name changes in combo box.
        """
        keys = self.options[self.current_axis]
        name = keys[i]
        self.current_kernel_name = name
        self.current_kernel_type = self.smooth_cube.name_to_kernel_type(name)
        self.unit_label.setText(self.smooth_cube.get_kernel_unit(self.current_kernel_type))
        self.size_prompt.setText(self.smooth_cube.get_kernel_size_prompt(self.current_kernel_type))

    def spatial_radio_checked(self):
        self.current_axis = "spatial"
        self.update_preview_button()
        self.combo.clear()
        self.combo.addItems(self.options[self.current_axis])

    def spectral_radio_checked(self):
        self.current_axis = "spectral"
        self.update_preview_button()
        self.combo.clear()
        self.combo.addItems(self.options[self.current_axis])

    def input_validation(self):
        """
        Check if input will break Smoothing
        :return: bool: True if no errors
        """
        red = "background-color: rgba(255, 0, 0, 128);"
        success = True

        # Check 1: k_size
        if self.k_size == "":
            self.k_size.setStyleSheet(red)
            success = False
        else:
            try:
                if self.current_kernel_type == "median":
                    k_size = int(self.k_size.text())
                else:
                    k_size = float(self.k_size.text())
                if k_size <= 0:
                    self.k_size.setStyleSheet(red)
                    success = False
                else:
                    self.k_size.setStyleSheet("")
            except ValueError:
                if self.current_kernel_type == "median":
                    info = QMessageBox.critical(self, "Error",
                                                "Kernel size must be integer for median")
                self.k_size.setStyleSheet(red)
                success = False

        return success

    def call_main(self):
        try:
            self.main()
        except Exception as e:
            info = QMessageBox.critical(self, "Error", str(e))
            self.cancel()
            raise

    def main(self):
        """
        Main function to process input and call smoothing function
        """
        success = self.input_validation()

        if not success:
            return

        self.hide()
        self.abort_window = AbortWindow(self)
        QApplication.processEvents()

        # Add smoothing parameters

        self.smooth_cube.abort_window = self.abort_window
        if self.smooth_cube.parent is None and self.parent is not self.smooth_cube:
            self.smooth_cube.parent = self.parent
        if self.parent is not self.smooth_cube:
            self.smooth_cube.data = self.data
        self.smooth_cube.smoothing_axis = self.current_axis
        self.smooth_cube.kernel_type = self.current_kernel_type
        if self.current_kernel_type == "median":
            self.smooth_cube.kernel_size = int(self.k_size.text())
        else:
            self.smooth_cube.kernel_size = float(self.k_size.text())
        self.smooth_cube.component_id = str(self.component_combo.currentText())
        self.smooth_cube.output_as_component = True

        if self.is_preview_active:
            self.parent.end_smoothing_preview()
            self.is_preview_active = False
        self.smooth_cube.multi_threading_smooth()
        return

    def update_preview_button(self):
        if self.parent is None or "spatial" != self.current_axis:
            self.previewButton.setDisabled(True)
            return
        self.previewButton.setDisabled(False)
        return

    def call_preview(self):
        try:
            self.preview()
        except Exception as e:
            info = QMessageBox.critical(self, "Error", str(e))
            self.cancel()
            raise

    def preview(self):
        """Preview current options"""
        success = self.input_validation()

        if not success:
            return

        if self.smooth_cube.parent is None and self.parent is not self.smooth_cube:
            self.smooth_cube.parent = self.parent
        self.smooth_cube.smoothing_axis = self.current_axis
        self.smooth_cube.kernel_type = self.current_kernel_type
        if self.current_kernel_type == "median":
            self.smooth_cube.kernel_size = int(self.k_size.text())
        else:
            self.smooth_cube.kernel_size = float(self.k_size.text())

        preview_function = self.smooth_cube.preview_smoothing
        preview_title = self.smooth_cube.get_preview_title()
        component_id = self.component_combo.currentData()
        self.parent.start_smoothing_preview(preview_function, component_id, preview_title)

        self.is_preview_active = True
        self.preview_message.show()

    def cancel(self):
        self.clean_up()

    def clean_up(self):
        self.close()
        if self.abort_window is not None:
            self.abort_window.close()
        if self.is_preview_active:
            self.parent.end_smoothing_preview()
            self.is_preview_active = False

    def closeEvent(self, event):
        if self.is_preview_active:
            self.parent.end_smoothing_preview()
            self.is_preview_active = False

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.clean_up()
Пример #40
0
class PreviewPlotSpectrum(QWidget):
    def __init__(self, *, gpc, gui_vars):
        super().__init__()

        # Global processing classes
        self.gpc = gpc
        # Global GUI variables (used for control of GUI state)
        self.gui_vars = gui_vars

        self.cb_plot_type = QComboBox()
        self.cb_plot_type.addItems(["LinLog", "Linear"])
        self.cb_plot_type.setCurrentIndex(self.gpc.get_preview_plot_type())
        self.cb_plot_type.currentIndexChanged.connect(self.cb_plot_type_current_index_changed)

        self.rb_selected_region = QRadioButton("Selected region")
        self.rb_selected_region.setChecked(True)
        self.rb_full_spectrum = QRadioButton("Full spectrum")
        if self.gpc.get_preview_energy_range() == EnergyRangePresets.SELECTED_RANGE:
            self.rb_selected_region.setChecked(True)
        elif self.gpc.get_preview_energy_range() == EnergyRangePresets.FULL_SPECTRUM:
            self.rb_full_spectrum.setChecked(True)
        else:
            logger.error(
                "Spectrum preview: incorrect Enum value for energy range was used:\n"
                "    Report the error to the development team."
            )

        self.btn_group_region = QButtonGroup()
        self.btn_group_region.addButton(self.rb_selected_region)
        self.btn_group_region.addButton(self.rb_full_spectrum)
        self.btn_group_region.buttonToggled.connect(self.btn_group_region_button_toggled)

        self.mpl_canvas = FigureCanvas(self.gpc.plot_model._fig_preview)
        self.mpl_toolbar = NavigationToolbar(self.mpl_canvas, self)

        # Keep layout without change when canvas is hidden (invisible)
        sp_retain = self.mpl_canvas.sizePolicy()
        sp_retain.setRetainSizeWhenHidden(True)
        self.mpl_canvas.setSizePolicy(sp_retain)

        vbox = QVBoxLayout()

        hbox = QHBoxLayout()
        hbox.addWidget(self.cb_plot_type)
        hbox.addStretch(1)
        hbox.addWidget(self.rb_selected_region)
        hbox.addWidget(self.rb_full_spectrum)
        vbox.addLayout(hbox)

        vbox.addWidget(self.mpl_toolbar)
        vbox.addWidget(self.mpl_canvas)
        self.setLayout(vbox)

        self._set_tooltips()

    def _set_tooltips(self):
        set_tooltip(self.cb_plot_type, "Use <b>Linear</b> or <b>LinLog</b> axes to plot spectra")
        set_tooltip(
            self.rb_selected_region,
            "Plot spectrum in the <b>selected range</b> of energies. The range may be set "
            "in the 'Model' tab. Click the button <b>'Find Automatically ...'</b> "
            "to set the range of energies before finding the emission lines. The range "
            "may be changed in General Settings dialog (button <b>'General ...'</b>) at any time.",
        )
        set_tooltip(self.rb_full_spectrum, "Plot full spectrum over <b>all available eneriges</b>.")

    def update_widget_state(self, condition=None):
        if condition == "tooltips":
            self._set_tooltips()
        self.mpl_toolbar.setVisible(self.gui_vars["show_matplotlib_toolbar"])

        # Hide Matplotlib canvas during computations
        state_compute = global_gui_variables["gui_state"]["running_computations"]
        self.mpl_canvas.setVisible(not state_compute)

    @Slot()
    @Slot(bool)
    def redraw_preview_plot(self):
        # It is assumed that the plot is visible
        self.gpc.update_preview_spectrum_plot()

    def btn_group_region_button_toggled(self, button, checked):
        if checked:
            if button == self.rb_selected_region:
                self.gpc.set_preview_energy_range(EnergyRangePresets.SELECTED_RANGE)
                self.gpc.update_preview_spectrum_plot()
                logger.debug("GUI: Display only selected region")
            elif button == self.rb_full_spectrum:
                self.gpc.set_preview_energy_range(EnergyRangePresets.FULL_SPECTRUM)
                self.gpc.update_preview_spectrum_plot()
                logger.debug("GUI: Display full spectrum")
            else:
                logger.error(
                    "Spectrum preview: unknown button was toggled. "
                    "Please, report the error to the development team."
                )

    def cb_plot_type_current_index_changed(self, index):
        try:
            self.gpc.set_preview_plot_type(PlotTypes(index))
            self.gpc.plot_model.update_preview_spectrum_plot()
        except ValueError:
            logger.error(
                "Spectrum preview: incorrect index for energy range preset was detected.\n"
                "Please report the error to the development team."
            )
Пример #41
0
class ProjectDialog(QDialog):
    """Project creation dialog."""

    # path, type, packages
    sig_project_creation_requested = Signal(object, object, object)

    def __init__(self, parent):
        """Project creation dialog."""
        super(ProjectDialog, self).__init__(parent=parent)

        # Variables
        current_python_version = '.'.join([
            to_text_string(sys.version_info[0]),
            to_text_string(sys.version_info[1])
        ])
        python_versions = ['2.7', '3.4', '3.5']
        if current_python_version not in python_versions:
            python_versions.append(current_python_version)
            python_versions = sorted(python_versions)

        self.project_name = None
        self.location = get_home_dir()

        # Widgets
        self.groupbox = QGroupBox()
        self.radio_new_dir = QRadioButton(_("New directory"))
        self.radio_from_dir = QRadioButton(_("Existing directory"))

        self.label_project_name = QLabel(_('Project name'))
        self.label_location = QLabel(_('Location'))
        self.label_project_type = QLabel(_('Project type'))
        self.label_python_version = QLabel(_('Python version'))

        self.text_project_name = QLineEdit()
        self.text_location = QLineEdit(get_home_dir())
        self.combo_project_type = QComboBox()
        self.combo_python_version = QComboBox()

        self.button_select_location = QToolButton()
        self.button_cancel = QPushButton(_('Cancel'))
        self.button_create = QPushButton(_('Create'))

        self.bbox = QDialogButtonBox(Qt.Horizontal)
        self.bbox.addButton(self.button_cancel, QDialogButtonBox.ActionRole)
        self.bbox.addButton(self.button_create, QDialogButtonBox.ActionRole)

        # Widget setup
        self.combo_python_version.addItems(python_versions)
        self.radio_new_dir.setChecked(True)
        self.text_location.setEnabled(True)
        self.text_location.setReadOnly(True)
        self.button_select_location.setIcon(get_std_icon('DirOpenIcon'))
        self.button_cancel.setDefault(True)
        self.button_cancel.setAutoDefault(True)
        self.button_create.setEnabled(False)
        self.combo_project_type.addItems(self._get_project_types())
        self.combo_python_version.setCurrentIndex(
            python_versions.index(current_python_version))
        self.setWindowTitle(_('Create new project'))
        self.setFixedWidth(500)
        self.label_python_version.setVisible(False)
        self.combo_python_version.setVisible(False)

        # Layouts
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.radio_new_dir)
        layout_top.addWidget(self.radio_from_dir)
        layout_top.addStretch(1)
        self.groupbox.setLayout(layout_top)

        layout_grid = QGridLayout()
        layout_grid.addWidget(self.label_project_name, 0, 0)
        layout_grid.addWidget(self.text_project_name, 0, 1, 1, 2)
        layout_grid.addWidget(self.label_location, 1, 0)
        layout_grid.addWidget(self.text_location, 1, 1)
        layout_grid.addWidget(self.button_select_location, 1, 2)
        layout_grid.addWidget(self.label_project_type, 2, 0)
        layout_grid.addWidget(self.combo_project_type, 2, 1, 1, 2)
        layout_grid.addWidget(self.label_python_version, 3, 0)
        layout_grid.addWidget(self.combo_python_version, 3, 1, 1, 2)

        layout = QVBoxLayout()
        layout.addWidget(self.groupbox)
        layout.addSpacing(10)
        layout.addLayout(layout_grid)
        layout.addStretch()
        layout.addSpacing(20)
        layout.addWidget(self.bbox)

        self.setLayout(layout)

        # Signals and slots
        self.button_select_location.clicked.connect(self.select_location)
        self.button_create.clicked.connect(self.create_project)
        self.button_cancel.clicked.connect(self.close)
        self.radio_from_dir.clicked.connect(self.update_location)
        self.radio_new_dir.clicked.connect(self.update_location)
        self.text_project_name.textChanged.connect(self.update_location)

    def _get_project_types(self):
        """Get all available project types."""
        project_types = get_available_project_types()
        projects = []

        for project in project_types:
            projects.append(project.PROJECT_TYPE_NAME)

        return projects

    def select_location(self):
        """Select directory."""
        location = getexistingdirectory(self, _("Select directory"),
                                        self.location)
        if location:
            if is_writable(location):
                self.location = location
                self.update_location()

    def update_location(self, text=''):
        """Update text of location."""
        self.text_project_name.setEnabled(self.radio_new_dir.isChecked())
        name = self.text_project_name.text().strip()

        if name and self.radio_new_dir.isChecked():
            path = osp.join(self.location, name)
            self.button_create.setDisabled(os.path.isdir(path))
        elif self.radio_from_dir.isChecked():
            self.button_create.setEnabled(True)
            path = self.location
        else:
            self.button_create.setEnabled(False)
            path = self.location

        self.text_location.setText(path)

    def create_project(self):
        """Create project."""
        packages = [
            'python={0}'.format(self.combo_python_version.currentText())
        ]
        self.sig_project_creation_requested.emit(
            self.text_location.text(), self.combo_project_type.currentText(),
            packages)
        self.accept()
Пример #42
0
class PyDMChartingDisplay(Display):
    def __init__(self, parent=None, args=[], macros=None):
        """
        Create all the widgets, including any child dialogs.

        Parameters
        ----------
        parent : QWidget
            The parent widget of the charting display
        args : list
            The command parameters
        macros : str
            Macros to modify the UI parameters at runtime
        """
        super(PyDMChartingDisplay, self).__init__(parent=parent,
                                                  args=args,
                                                  macros=macros)

        self.channel_map = dict()
        self.setWindowTitle("PyDM Charting Tool")

        self.main_layout = QVBoxLayout()
        self.body_layout = QVBoxLayout()

        self.pv_layout = QHBoxLayout()
        self.pv_name_line_edt = QLineEdit()
        self.pv_name_line_edt.setAcceptDrops(True)
        self.pv_name_line_edt.installEventFilter(self)

        self.pv_protocol_cmb = QComboBox()
        self.pv_protocol_cmb.addItems(["ca://", "archive://"])

        self.pv_connect_push_btn = QPushButton("Connect")
        self.pv_connect_push_btn.clicked.connect(self.add_curve)

        self.tab_panel = QTabWidget()
        self.tab_panel.setMaximumWidth(450)
        self.curve_settings_tab = QWidget()
        self.chart_settings_tab = QWidget()

        self.charting_layout = QHBoxLayout()
        self.chart = PyDMTimePlot(plot_by_timestamps=False, plot_display=self)
        self.chart.setPlotTitle("Time Plot")

        self.splitter = QSplitter()

        self.curve_settings_layout = QVBoxLayout()
        self.curve_settings_layout.setAlignment(Qt.AlignTop)
        self.curve_settings_layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
        self.curve_settings_layout.setSpacing(5)

        self.crosshair_settings_layout = QVBoxLayout()
        self.crosshair_settings_layout.setAlignment(Qt.AlignTop)
        self.crosshair_settings_layout.setSpacing(5)

        self.enable_crosshair_chk = QCheckBox("Enable Crosshair")
        self.cross_hair_coord_lbl = QLabel()

        self.curve_settings_inner_frame = QFrame()
        self.curve_settings_inner_frame.setLayout(self.curve_settings_layout)

        self.curve_settings_scroll = QScrollArea()
        self.curve_settings_scroll.setVerticalScrollBarPolicy(
            Qt.ScrollBarAsNeeded)
        self.curve_settings_scroll.setWidget(self.curve_settings_inner_frame)

        self.curves_tab_layout = QHBoxLayout()
        self.curves_tab_layout.addWidget(self.curve_settings_scroll)

        self.enable_crosshair_chk.setChecked(False)
        self.enable_crosshair_chk.clicked.connect(
            self.handle_enable_crosshair_checkbox_clicked)
        self.enable_crosshair_chk.clicked.emit(False)

        self.chart_settings_layout = QVBoxLayout()
        self.chart_settings_layout.setAlignment(Qt.AlignTop)

        self.chart_layout = QVBoxLayout()
        self.chart_panel = QWidget()

        self.chart_control_layout = QHBoxLayout()
        self.chart_control_layout.setAlignment(Qt.AlignHCenter)
        self.chart_control_layout.setSpacing(10)

        self.view_all_btn = QPushButton("View All")
        self.view_all_btn.clicked.connect(self.handle_view_all_button_clicked)
        self.view_all_btn.setEnabled(False)

        self.auto_scale_btn = QPushButton("Auto Scale")
        self.auto_scale_btn.clicked.connect(self.handle_auto_scale_btn_clicked)
        self.auto_scale_btn.setEnabled(False)

        self.reset_chart_btn = QPushButton("Reset")
        self.reset_chart_btn.clicked.connect(
            self.handle_reset_chart_btn_clicked)
        self.reset_chart_btn.setEnabled(False)

        self.resume_chart_text = "Resume"
        self.pause_chart_text = "Pause"
        self.pause_chart_btn = QPushButton(self.pause_chart_text)
        self.pause_chart_btn.clicked.connect(
            self.handle_pause_chart_btn_clicked)

        self.title_settings_layout = QVBoxLayout()
        self.title_settings_layout.setSpacing(10)

        self.title_settings_grpbx = QGroupBox()
        self.title_settings_grpbx.setFixedHeight(150)

        self.import_data_btn = QPushButton("Import Data...")
        self.import_data_btn.clicked.connect(
            self.handle_import_data_btn_clicked)

        self.export_data_btn = QPushButton("Export Data...")
        self.export_data_btn.clicked.connect(
            self.handle_export_data_btn_clicked)

        self.chart_title_lbl = QLabel(text="Chart Title")
        self.chart_title_line_edt = QLineEdit()
        self.chart_title_line_edt.setText(self.chart.getPlotTitle())
        self.chart_title_line_edt.textChanged.connect(
            self.handle_title_text_changed)

        self.chart_change_axis_settings_btn = QPushButton(
            text="Change Axis Settings...")
        self.chart_change_axis_settings_btn.clicked.connect(
            self.handle_change_axis_settings_clicked)

        self.update_datetime_timer = QTimer(self)
        self.update_datetime_timer.timeout.connect(
            self.handle_update_datetime_timer_timeout)

        self.chart_sync_mode_layout = QVBoxLayout()
        self.chart_sync_mode_layout.setSpacing(5)

        self.chart_sync_mode_grpbx = QGroupBox("Data Sampling Mode")
        self.chart_sync_mode_grpbx.setFixedHeight(80)

        self.chart_sync_mode_sync_radio = QRadioButton("Synchronous")
        self.chart_sync_mode_async_radio = QRadioButton("Asynchronous")
        self.chart_sync_mode_async_radio.setChecked(True)

        self.graph_drawing_settings_layout = QVBoxLayout()

        self.chart_redraw_rate_lbl = QLabel("Redraw Rate (Hz)")
        self.chart_redraw_rate_spin = QSpinBox()
        self.chart_redraw_rate_spin.setRange(MIN_REDRAW_RATE_HZ,
                                             MAX_REDRAW_RATE_HZ)
        self.chart_redraw_rate_spin.setValue(DEFAULT_REDRAW_RATE_HZ)
        self.chart_redraw_rate_spin.valueChanged.connect(
            self.handle_redraw_rate_changed)

        self.chart_data_sampling_rate_lbl = QLabel(
            "Asynchronous Data Sampling Rate (Hz)")
        self.chart_data_async_sampling_rate_spin = QSpinBox()
        self.chart_data_async_sampling_rate_spin.setRange(
            MIN_DATA_SAMPLING_RATE_HZ, MAX_DATA_SAMPLING_RATE_HZ)
        self.chart_data_async_sampling_rate_spin.setValue(
            DEFAULT_DATA_SAMPLING_RATE_HZ)
        self.chart_data_async_sampling_rate_spin.valueChanged.connect(
            self.handle_data_sampling_rate_changed)
        self.chart_data_sampling_rate_lbl.hide()
        self.chart_data_async_sampling_rate_spin.hide()

        self.chart_limit_time_span_layout = QHBoxLayout()
        self.chart_limit_time_span_layout.setSpacing(5)

        self.limit_time_plan_text = "Limit Time Span"
        self.chart_limit_time_span_chk = QCheckBox(self.limit_time_plan_text)
        self.chart_limit_time_span_chk.hide()
        self.chart_limit_time_span_lbl = QLabel("Hours : Minutes : Seconds")
        self.chart_limit_time_span_hours_line_edt = QLineEdit()
        self.chart_limit_time_span_minutes_line_edt = QLineEdit()
        self.chart_limit_time_span_seconds_line_edt = QLineEdit()
        self.chart_limit_time_span_activate_btn = QPushButton("Apply")
        self.chart_limit_time_span_activate_btn.setDisabled(True)

        self.chart_ring_buffer_size_lbl = QLabel("Ring Buffer Size")
        self.chart_ring_buffer_size_edt = QLineEdit()
        self.chart_ring_buffer_size_edt.installEventFilter(self)
        self.chart_ring_buffer_size_edt.textChanged.connect(
            self.handle_buffer_size_changed)
        self.chart_ring_buffer_size_edt.setText(str(DEFAULT_BUFFER_SIZE))

        self.show_legend_chk = QCheckBox("Show Legend")
        self.show_legend_chk.setChecked(self.chart.showLegend)
        self.show_legend_chk.clicked.connect(
            self.handle_show_legend_checkbox_clicked)

        self.graph_background_color_layout = QFormLayout()

        self.background_color_lbl = QLabel("Graph Background Color ")
        self.background_color_btn = QPushButton()
        self.background_color_btn.setStyleSheet(
            "background-color: " + self.chart.getBackgroundColor().name())
        self.background_color_btn.setContentsMargins(10, 0, 5, 5)
        self.background_color_btn.setMaximumWidth(20)
        self.background_color_btn.clicked.connect(
            self.handle_background_color_button_clicked)

        self.axis_settings_layout = QVBoxLayout()
        self.axis_settings_layout.setSpacing(5)

        self.show_x_grid_chk = QCheckBox("Show x Grid")
        self.show_x_grid_chk.setChecked(self.chart.showXGrid)
        self.show_x_grid_chk.clicked.connect(
            self.handle_show_x_grid_checkbox_clicked)

        self.show_y_grid_chk = QCheckBox("Show y Grid")
        self.show_y_grid_chk.setChecked(self.chart.showYGrid)
        self.show_y_grid_chk.clicked.connect(
            self.handle_show_y_grid_checkbox_clicked)

        self.axis_color_lbl = QLabel("Axis and Grid Color")
        self.axis_color_lbl.setEnabled(False)

        self.axis_color_btn = QPushButton()
        self.axis_color_btn.setStyleSheet("background-color: " +
                                          DEFAULT_CHART_AXIS_COLOR.name())
        self.axis_color_btn.setContentsMargins(10, 0, 5, 5)
        self.axis_color_btn.setMaximumWidth(20)
        self.axis_color_btn.clicked.connect(
            self.handle_axis_color_button_clicked)
        self.axis_color_btn.setEnabled(False)

        self.grid_opacity_lbl = QLabel("Grid Opacity")
        self.grid_opacity_lbl.setEnabled(False)

        self.grid_opacity_slr = QSlider(Qt.Horizontal)
        self.grid_opacity_slr.setFocusPolicy(Qt.StrongFocus)
        self.grid_opacity_slr.setRange(0, 10)
        self.grid_opacity_slr.setValue(5)
        self.grid_opacity_slr.setTickInterval(1)
        self.grid_opacity_slr.setSingleStep(1)
        self.grid_opacity_slr.setTickPosition(QSlider.TicksBelow)
        self.grid_opacity_slr.valueChanged.connect(
            self.handle_grid_opacity_slider_mouse_release)
        self.grid_opacity_slr.setEnabled(False)

        self.reset_chart_settings_btn = QPushButton("Reset Chart Settings")
        self.reset_chart_settings_btn.clicked.connect(
            self.handle_reset_chart_settings_btn_clicked)

        self.curve_checkbox_panel = QWidget()

        self.graph_drawing_settings_grpbx = QGroupBox()
        self.graph_drawing_settings_grpbx.setFixedHeight(270)

        self.axis_settings_grpbx = QGroupBox()
        self.axis_settings_grpbx.setFixedHeight(180)

        self.app = QApplication.instance()
        self.setup_ui()

        self.curve_settings_disp = None
        self.axis_settings_disp = None
        self.chart_data_export_disp = None
        self.chart_data_import_disp = None
        self.grid_alpha = 5
        self.time_span_limit_hours = None
        self.time_span_limit_minutes = None
        self.time_span_limit_seconds = None
        self.data_sampling_mode = ASYNC_DATA_SAMPLING

    def minimumSizeHint(self):
        """
        The minimum recommended size of the main window.
        """
        return QSize(1490, 800)

    def ui_filepath(self):
        """
        The path to the UI file created by Qt Designer, if applicable.
        """
        # No UI file is being used
        return None

    def ui_filename(self):
        """
        The name the UI file created by Qt Designer, if applicable.
        """
        # No UI file is being used
        return None

    def setup_ui(self):
        """
        Initialize the widgets and layouts.
        """
        self.setLayout(self.main_layout)

        self.pv_layout.addWidget(self.pv_protocol_cmb)
        self.pv_layout.addWidget(self.pv_name_line_edt)
        self.pv_layout.addWidget(self.pv_connect_push_btn)
        QTimer.singleShot(0, self.pv_name_line_edt.setFocus)

        self.curve_settings_tab.setLayout(self.curves_tab_layout)
        self.chart_settings_tab.setLayout(self.chart_settings_layout)
        self.setup_chart_settings_layout()

        self.tab_panel.addTab(self.curve_settings_tab, "Curves")
        self.tab_panel.addTab(self.chart_settings_tab, "Chart")
        self.tab_panel.hide()

        self.crosshair_settings_layout.addWidget(self.enable_crosshair_chk)
        self.crosshair_settings_layout.addWidget(self.cross_hair_coord_lbl)

        self.chart_control_layout.addWidget(self.auto_scale_btn)
        self.chart_control_layout.addWidget(self.view_all_btn)
        self.chart_control_layout.addWidget(self.reset_chart_btn)
        self.chart_control_layout.addWidget(self.pause_chart_btn)
        self.chart_control_layout.addLayout(self.crosshair_settings_layout)
        self.chart_control_layout.addWidget(self.import_data_btn)
        self.chart_control_layout.addWidget(self.export_data_btn)

        self.chart_control_layout.setStretch(4, 15)
        self.chart_control_layout.insertSpacing(5, 350)

        self.chart_layout.addWidget(self.chart)
        self.chart_layout.addLayout(self.chart_control_layout)

        self.chart_panel.setLayout(self.chart_layout)

        self.splitter.addWidget(self.chart_panel)
        self.splitter.addWidget(self.tab_panel)
        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)

        self.charting_layout.addWidget(self.splitter)

        self.body_layout.addLayout(self.pv_layout)
        self.body_layout.addLayout(self.charting_layout)
        self.body_layout.addLayout(self.chart_control_layout)
        self.main_layout.addLayout(self.body_layout)

        self.enable_chart_control_buttons(False)

    def setup_chart_settings_layout(self):
        self.chart_sync_mode_sync_radio.toggled.connect(
            partial(self.handle_sync_mode_radio_toggle,
                    self.chart_sync_mode_sync_radio))
        self.chart_sync_mode_async_radio.toggled.connect(
            partial(self.handle_sync_mode_radio_toggle,
                    self.chart_sync_mode_async_radio))

        self.title_settings_layout.addWidget(self.chart_title_lbl)
        self.title_settings_layout.addWidget(self.chart_title_line_edt)
        self.title_settings_layout.addWidget(self.show_legend_chk)
        self.title_settings_layout.addWidget(
            self.chart_change_axis_settings_btn)
        self.title_settings_grpbx.setLayout(self.title_settings_layout)
        self.chart_settings_layout.addWidget(self.title_settings_grpbx)

        self.chart_sync_mode_layout.addWidget(self.chart_sync_mode_sync_radio)
        self.chart_sync_mode_layout.addWidget(self.chart_sync_mode_async_radio)
        self.chart_sync_mode_grpbx.setLayout(self.chart_sync_mode_layout)
        self.chart_settings_layout.addWidget(self.chart_sync_mode_grpbx)

        self.chart_settings_layout.addWidget(self.chart_sync_mode_grpbx)

        self.chart_limit_time_span_layout.addWidget(
            self.chart_limit_time_span_lbl)
        self.chart_limit_time_span_layout.addWidget(
            self.chart_limit_time_span_hours_line_edt)

        self.chart_limit_time_span_layout.addWidget(
            self.chart_limit_time_span_minutes_line_edt)
        self.chart_limit_time_span_layout.addWidget(
            self.chart_limit_time_span_seconds_line_edt)
        self.chart_limit_time_span_layout.addWidget(
            self.chart_limit_time_span_activate_btn)

        self.chart_limit_time_span_lbl.hide()
        self.chart_limit_time_span_hours_line_edt.hide()
        self.chart_limit_time_span_minutes_line_edt.hide()
        self.chart_limit_time_span_seconds_line_edt.hide()
        self.chart_limit_time_span_activate_btn.hide()

        self.chart_limit_time_span_hours_line_edt.textChanged.connect(
            self.handle_time_span_edt_text_changed)
        self.chart_limit_time_span_minutes_line_edt.textChanged.connect(
            self.handle_time_span_edt_text_changed)
        self.chart_limit_time_span_seconds_line_edt.textChanged.connect(
            self.handle_time_span_edt_text_changed)

        self.chart_limit_time_span_chk.clicked.connect(
            self.handle_limit_time_span_checkbox_clicked)
        self.chart_limit_time_span_activate_btn.clicked.connect(
            self.handle_chart_limit_time_span_activate_btn_clicked)
        self.chart_limit_time_span_activate_btn.installEventFilter(self)

        self.graph_background_color_layout.addRow(self.background_color_lbl,
                                                  self.background_color_btn)

        self.graph_drawing_settings_layout.addLayout(
            self.graph_background_color_layout)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_redraw_rate_lbl)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_redraw_rate_spin)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_data_sampling_rate_lbl)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_data_async_sampling_rate_spin)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_limit_time_span_chk)
        self.graph_drawing_settings_layout.addLayout(
            self.chart_limit_time_span_layout)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_ring_buffer_size_lbl)
        self.graph_drawing_settings_layout.addWidget(
            self.chart_ring_buffer_size_edt)
        self.graph_drawing_settings_grpbx.setLayout(
            self.graph_drawing_settings_layout)

        self.axis_settings_layout.addWidget(self.show_x_grid_chk)
        self.axis_settings_layout.addWidget(self.show_y_grid_chk)
        self.axis_settings_layout.addWidget(self.axis_color_lbl)
        self.axis_settings_layout.addWidget(self.axis_color_btn)
        self.axis_settings_layout.addWidget(self.grid_opacity_lbl)
        self.axis_settings_layout.addWidget(self.grid_opacity_slr)
        self.axis_settings_grpbx.setLayout(self.axis_settings_layout)

        self.chart_settings_layout.addWidget(self.graph_drawing_settings_grpbx)
        self.chart_settings_layout.addWidget(self.axis_settings_grpbx)
        self.chart_settings_layout.addWidget(self.reset_chart_settings_btn)

        self.chart_sync_mode_async_radio.toggled.emit(True)
        self.update_datetime_timer.start(1000)

    def eventFilter(self, obj, event):
        """
        Handle key and mouse events for any applicable widget.

        Parameters
        ----------
        obj : QWidget
            The current widget that accepts the event
        event : QEvent
            The key or mouse event to handle

        Returns
        -------
            True if the event was handled successfully; False otherwise
        """
        if obj == self.pv_name_line_edt and event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
                self.add_curve()
                return True
        elif obj == self.chart_limit_time_span_activate_btn and event.type(
        ) == QEvent.KeyPress:
            if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
                self.handle_chart_limit_time_span_activate_btn_clicked()
                return True
        elif obj == self.chart_ring_buffer_size_edt:
            if event.type() == QEvent.KeyPress and (event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return) or \
                    event.type() == QEvent.FocusOut:
                try:
                    buffer_size = int(self.chart_ring_buffer_size_edt.text())
                    if buffer_size < MINIMUM_BUFFER_SIZE:
                        self.chart_ring_buffer_size_edt.setText(
                            str(MINIMUM_BUFFER_SIZE))
                except ValueError:
                    display_message_box(QMessageBox.Critical, "Invalid Values",
                                        "Only integer values are accepted.")
                return True
        return super(PyDMChartingDisplay, self).eventFilter(obj, event)

    def add_curve(self):
        """
        Add a new curve to the chart.
        """
        pv_name = self._get_full_pv_name(self.pv_name_line_edt.text())
        color = random_color()
        for k, v in self.channel_map.items():
            if color == v.color:
                color = random_color()

        self.add_y_channel(pv_name=pv_name, curve_name=pv_name, color=color)

    def handle_enable_crosshair_checkbox_clicked(self, is_checked):
        self.chart.enableCrosshair(is_checked)
        self.cross_hair_coord_lbl.setVisible(is_checked)

    def add_y_channel(self,
                      pv_name,
                      curve_name,
                      color,
                      line_style=Qt.SolidLine,
                      line_width=2,
                      symbol=None,
                      symbol_size=None):
        if pv_name in self.channel_map:
            logger.error("'{0}' has already been added.".format(pv_name))
            return

        curve = self.chart.addYChannel(y_channel=pv_name,
                                       name=curve_name,
                                       color=color,
                                       lineStyle=line_style,
                                       lineWidth=line_width,
                                       symbol=symbol,
                                       symbolSize=symbol_size)
        self.channel_map[pv_name] = curve
        self.generate_pv_controls(pv_name, color)

        self.enable_chart_control_buttons()
        self.app.establish_widget_connections(self)

    def generate_pv_controls(self, pv_name, curve_color):
        """
        Generate a set of widgets to manage the appearance of a curve. The set of widgets includes:
            1. A checkbox which shows the curve on the chart if checked, and hide the curve if not checked
            2. Two buttons -- Modify... and Remove. Modify... will bring up the Curve Settings dialog. Remove will
               delete the curve from the chart
        This set of widgets will be hidden initially, until the first curve is plotted.

        Parameters
        ----------
        pv_name: str
            The name of the PV the current curve is being plotted for

        curve_color : QColor
            The color of the curve to paint for the checkbox label to help the user track the curve to the checkbox
        """
        checkbox = QCheckBox()
        checkbox.setObjectName(pv_name)

        palette = checkbox.palette()
        palette.setColor(QPalette.Active, QPalette.WindowText, curve_color)
        checkbox.setPalette(palette)

        display_name = pv_name.split("://")[1]
        if len(display_name) > MAX_DISPLAY_PV_NAME_LENGTH:
            # Only display max allowed number of characters of the PV Name
            display_name = display_name[:int(MAX_DISPLAY_PV_NAME_LENGTH / 2) - 1] + "..." + \
                           display_name[-int(MAX_DISPLAY_PV_NAME_LENGTH / 2) + 2:]

        checkbox.setText(display_name)

        data_text = QLabel()
        data_text.setObjectName(pv_name)
        data_text.setPalette(palette)

        checkbox.setChecked(True)
        checkbox.clicked.connect(
            partial(self.handle_curve_chkbox_toggled, checkbox))

        curve_btn_layout = QHBoxLayout()

        modify_curve_btn = QPushButton("Modify...")
        modify_curve_btn.setObjectName(pv_name)
        modify_curve_btn.setMaximumWidth(100)
        modify_curve_btn.clicked.connect(
            partial(self.display_curve_settings_dialog, pv_name))

        focus_curve_btn = QPushButton("Focus")
        focus_curve_btn.setObjectName(pv_name)
        focus_curve_btn.setMaximumWidth(100)
        focus_curve_btn.clicked.connect(partial(self.focus_curve, pv_name))

        annotate_curve_btn = QPushButton("Annotate...")
        annotate_curve_btn.setObjectName(pv_name)
        annotate_curve_btn.setMaximumWidth(100)
        annotate_curve_btn.clicked.connect(
            partial(self.annotate_curve, pv_name))

        remove_curve_btn = QPushButton("Remove")
        remove_curve_btn.setObjectName(pv_name)
        remove_curve_btn.setMaximumWidth(100)
        remove_curve_btn.clicked.connect(partial(self.remove_curve, pv_name))

        curve_btn_layout.addWidget(modify_curve_btn)
        curve_btn_layout.addWidget(focus_curve_btn)
        curve_btn_layout.addWidget(annotate_curve_btn)
        curve_btn_layout.addWidget(remove_curve_btn)

        individual_curve_layout = QVBoxLayout()
        individual_curve_layout.addWidget(checkbox)
        individual_curve_layout.addWidget(data_text)
        individual_curve_layout.addLayout(curve_btn_layout)

        size_policy = QSizePolicy()
        size_policy.setVerticalPolicy(QSizePolicy.Fixed)
        individual_curve_grpbx = QGroupBox()
        individual_curve_grpbx.setSizePolicy(size_policy)

        individual_curve_grpbx.setObjectName(pv_name)
        individual_curve_grpbx.setLayout(individual_curve_layout)

        self.curve_settings_layout.addWidget(individual_curve_grpbx)
        self.tab_panel.show()

    def handle_curve_chkbox_toggled(self, checkbox):
        """
        Handle a checkbox's checked and unchecked events.

        If a checkbox is checked, find the curve from the channel map. If found, re-draw the curve with its previous
        appearance settings.

        If a checkbox is unchecked, remove the curve from the chart, but keep the cached data in the channel map.

        Parameters
        ----------
        checkbox : QCheckBox
            The current checkbox being toggled
        """
        pv_name = self._get_full_pv_name(checkbox.text())

        if checkbox.isChecked():
            curve = self.channel_map.get(pv_name, None)
            if curve:
                self.chart.addLegendItem(curve, pv_name,
                                         self.show_legend_chk.isChecked())
                curve.show()
        else:
            curve = self.chart.findCurve(pv_name)
            if curve:
                curve.hide()
                self.chart.removeLegendItem(pv_name)

    def display_curve_settings_dialog(self, pv_name):
        """
        Bring up the Curve Settings dialog to modify the appearance of a curve.

        Parameters
        ----------
        pv_name : str
            The name of the PV the curve is being plotted for

        """
        self.curve_settings_disp = CurveSettingsDisplay(self, pv_name)
        self.curve_settings_disp.show()

    def focus_curve(self, pv_name):
        curve = self.chart.findCurve(pv_name)
        if curve:
            self.chart.plotItem.setYRange(curve.minY, curve.maxY, padding=0)

    def annotate_curve(self, pv_name):
        curve = self.chart.findCurve(pv_name)
        if curve:
            annot = TextItem(
                html=
                '<div style="text-align: center"><span style="color: #FFF;">This is the'
                '</span><br><span style="color: #FF0; font-size: 16pt;">PEAK</span></div>',
                anchor=(-0.3, 0.5),
                border='w',
                fill=(0, 0, 255, 100))
            annot = TextItem("test", anchor=(-0.3, 0.5))
            self.chart.annotateCurve(curve, annot)

    def remove_curve(self, pv_name):
        """
        Remove a curve from the chart permanently. This will also clear the channel map cache from retaining the
        removed curve's appearance settings.

        Parameters
        ----------
        pv_name : str
            The name of the PV the curve is being plotted for
        """
        curve = self.chart.findCurve(pv_name)
        if curve:
            self.chart.removeYChannel(curve)
            del self.channel_map[pv_name]
            self.chart.removeLegendItem(pv_name)

            widgets = self.findChildren(
                (QCheckBox, QLabel, QPushButton, QGroupBox), pv_name)
            for w in widgets:
                w.deleteLater()

        if len(self.chart.getCurves()) < 1:
            self.enable_chart_control_buttons(False)
            self.show_legend_chk.setChecked(False)

    def handle_title_text_changed(self, new_text):
        self.chart.setPlotTitle(new_text)

    def handle_change_axis_settings_clicked(self):
        self.axis_settings_disp = AxisSettingsDisplay(self)
        self.axis_settings_disp.show()

    def handle_limit_time_span_checkbox_clicked(self, is_checked):
        self.chart_limit_time_span_lbl.setVisible(is_checked)
        self.chart_limit_time_span_hours_line_edt.setVisible(is_checked)
        self.chart_limit_time_span_minutes_line_edt.setVisible(is_checked)
        self.chart_limit_time_span_seconds_line_edt.setVisible(is_checked)
        self.chart_limit_time_span_activate_btn.setVisible(is_checked)

        self.chart_ring_buffer_size_lbl.setDisabled(is_checked)
        self.chart_ring_buffer_size_edt.setDisabled(is_checked)

        if not is_checked:
            self.chart_limit_time_span_chk.setText(self.limit_time_plan_text)

    def handle_time_span_edt_text_changed(self, new_text):
        try:
            self.time_span_limit_hours = int(
                self.chart_limit_time_span_hours_line_edt.text())
            self.time_span_limit_minutes = int(
                self.chart_limit_time_span_minutes_line_edt.text())
            self.time_span_limit_seconds = int(
                self.chart_limit_time_span_seconds_line_edt.text())
        except ValueError as e:
            self.time_span_limit_hours = None
            self.time_span_limit_minutes = None
            self.time_span_limit_seconds = None

        if self.time_span_limit_hours is not None and self.time_span_limit_minutes is not None and \
                self.time_span_limit_seconds is not None:
            self.chart_limit_time_span_activate_btn.setEnabled(True)
        else:
            self.chart_limit_time_span_activate_btn.setEnabled(False)

    def handle_chart_limit_time_span_activate_btn_clicked(self):
        if self.time_span_limit_hours is None or self.time_span_limit_minutes is None or \
                self.time_span_limit_seconds is None:
            display_message_box(
                QMessageBox.Critical, "Invalid Values",
                "Hours, minutes, and seconds expect only integer values.")
        else:
            timeout_milliseconds = (self.time_span_limit_hours * 3600 +
                                    self.time_span_limit_minutes * 60 +
                                    self.time_span_limit_seconds) * 1000
            self.chart.setTimeSpan(timeout_milliseconds / 1000.0)
            self.chart_ring_buffer_size_edt.setText(
                str(self.chart.getBufferSize()))

    def handle_buffer_size_changed(self, new_buffer_size):
        try:
            if new_buffer_size and int(new_buffer_size) > MINIMUM_BUFFER_SIZE:
                self.chart.setBufferSize(new_buffer_size)
        except ValueError:
            display_message_box(QMessageBox.Critical, "Invalid Values",
                                "Only integer values are accepted.")

    def handle_redraw_rate_changed(self, new_redraw_rate):
        self.chart.maxRedrawRate = new_redraw_rate

    def handle_data_sampling_rate_changed(self, new_data_sampling_rate):
        # The chart expects the value in milliseconds
        sampling_rate_seconds = 1 / new_data_sampling_rate
        self.chart.setUpdateInterval(sampling_rate_seconds)

    def handle_background_color_button_clicked(self):
        selected_color = QColorDialog.getColor()
        self.chart.setBackgroundColor(selected_color)
        self.background_color_btn.setStyleSheet("background-color: " +
                                                selected_color.name())

    def handle_axis_color_button_clicked(self):
        selected_color = QColorDialog.getColor()
        self.chart.setAxisColor(selected_color)
        self.axis_color_btn.setStyleSheet("background-color: " +
                                          selected_color.name())

    def handle_grid_opacity_slider_mouse_release(self):
        self.grid_alpha = float(self.grid_opacity_slr.value()) / 10.0
        self.chart.setShowXGrid(self.show_x_grid_chk.isChecked(),
                                self.grid_alpha)
        self.chart.setShowYGrid(self.show_y_grid_chk.isChecked(),
                                self.grid_alpha)

    def handle_show_x_grid_checkbox_clicked(self, is_checked):
        self.chart.setShowXGrid(is_checked, self.grid_alpha)

        self.axis_color_lbl.setEnabled(is_checked
                                       or self.show_y_grid_chk.isChecked())
        self.axis_color_btn.setEnabled(is_checked
                                       or self.show_y_grid_chk.isChecked())
        self.grid_opacity_lbl.setEnabled(is_checked
                                         or self.show_y_grid_chk.isChecked())
        self.grid_opacity_slr.setEnabled(is_checked
                                         or self.show_y_grid_chk.isChecked())

    def handle_show_y_grid_checkbox_clicked(self, is_checked):
        self.chart.setShowYGrid(is_checked, self.grid_alpha)

        self.axis_color_lbl.setEnabled(is_checked
                                       or self.show_x_grid_chk.isChecked())
        self.axis_color_btn.setEnabled(is_checked
                                       or self.show_x_grid_chk.isChecked())
        self.grid_opacity_lbl.setEnabled(is_checked
                                         or self.show_x_grid_chk.isChecked())
        self.grid_opacity_slr.setEnabled(is_checked
                                         or self.show_x_grid_chk.isChecked())

    def handle_show_legend_checkbox_clicked(self, is_checked):
        self.chart.setShowLegend(is_checked)

    def handle_export_data_btn_clicked(self):
        self.chart_data_export_disp = ChartDataExportDisplay(self)
        self.chart_data_export_disp.show()

    def handle_import_data_btn_clicked(self):
        open_file_info = QFileDialog.getOpenFileName(self,
                                                     caption="Save File",
                                                     filter="*." +
                                                     IMPORT_FILE_FORMAT)
        open_file_name = open_file_info[0]
        if open_file_name:
            importer = SettingsImporter(self)
            importer.import_settings(open_file_name)

    def handle_sync_mode_radio_toggle(self, radio_btn):
        if radio_btn.isChecked():
            if radio_btn.text() == "Synchronous":
                self.data_sampling_mode = SYNC_DATA_SAMPLING

                self.chart_data_sampling_rate_lbl.hide()
                self.chart_data_async_sampling_rate_spin.hide()

                self.chart.resetTimeSpan()
                self.chart_limit_time_span_chk.setChecked(False)
                self.chart_limit_time_span_chk.clicked.emit(False)
                self.chart_limit_time_span_chk.hide()
                self.graph_drawing_settings_grpbx.setFixedHeight(180)

                self.chart.setUpdatesAsynchronously(False)
            elif radio_btn.text() == "Asynchronous":
                self.data_sampling_mode = ASYNC_DATA_SAMPLING

                self.chart_data_sampling_rate_lbl.show()
                self.chart_data_async_sampling_rate_spin.show()
                self.chart_limit_time_span_chk.show()
                self.graph_drawing_settings_grpbx.setFixedHeight(270)

                self.chart.setUpdatesAsynchronously(True)
        self.app.establish_widget_connections(self)

    def handle_auto_scale_btn_clicked(self):
        self.chart.resetAutoRangeX()
        self.chart.resetAutoRangeY()

    def handle_view_all_button_clicked(self):
        self.chart.getViewBox().autoRange()

    def handle_pause_chart_btn_clicked(self):
        if self.chart.pausePlotting():
            self.pause_chart_btn.setText(self.pause_chart_text)
        else:
            self.pause_chart_btn.setText(self.resume_chart_text)

    def handle_reset_chart_btn_clicked(self):
        self.chart.getViewBox().setXRange(DEFAULT_X_MIN, 0)
        self.chart.resetAutoRangeY()

    @Slot()
    def handle_reset_chart_settings_btn_clicked(self):
        self.chart_ring_buffer_size_edt.setText(str(DEFAULT_BUFFER_SIZE))

        self.chart_redraw_rate_spin.setValue(DEFAULT_REDRAW_RATE_HZ)
        self.chart_data_async_sampling_rate_spin.setValue(
            DEFAULT_DATA_SAMPLING_RATE_HZ)
        self.chart_data_sampling_rate_lbl.hide()
        self.chart_data_async_sampling_rate_spin.hide()

        self.chart_sync_mode_async_radio.setChecked(True)
        self.chart_sync_mode_async_radio.toggled.emit(True)

        self.chart_limit_time_span_chk.setChecked(False)
        self.chart_limit_time_span_chk.setText(self.limit_time_plan_text)
        self.chart_limit_time_span_chk.clicked.emit(False)

        self.chart.setUpdatesAsynchronously(True)
        self.chart.resetTimeSpan()
        self.chart.resetUpdateInterval()
        self.chart.setBufferSize(DEFAULT_BUFFER_SIZE)

        self.chart.setBackgroundColor(DEFAULT_CHART_BACKGROUND_COLOR)
        self.background_color_btn.setStyleSheet(
            "background-color: " + DEFAULT_CHART_BACKGROUND_COLOR.name())

        self.chart.setAxisColor(DEFAULT_CHART_AXIS_COLOR)
        self.axis_color_btn.setStyleSheet("background-color: " +
                                          DEFAULT_CHART_AXIS_COLOR.name())

        self.grid_opacity_slr.setValue(5)

        self.show_x_grid_chk.setChecked(False)
        self.show_x_grid_chk.clicked.emit(False)

        self.show_y_grid_chk.setChecked(False)
        self.show_y_grid_chk.clicked.emit(False)

        self.show_legend_chk.setChecked(False)

        self.chart.setShowXGrid(False)
        self.chart.setShowYGrid(False)
        self.chart.setShowLegend(False)

    def enable_chart_control_buttons(self, enabled=True):
        self.auto_scale_btn.setEnabled(enabled)
        self.view_all_btn.setEnabled(enabled)
        self.reset_chart_btn.setEnabled(enabled)
        self.pause_chart_btn.setText(self.pause_chart_text)
        self.pause_chart_btn.setEnabled(enabled)
        self.export_data_btn.setEnabled(enabled)

    def _get_full_pv_name(self, pv_name):
        """
        Append the protocol to the PV Name.

        Parameters
        ----------
        pv_name : str
            The name of the PV the curve is being plotted for
        """
        if pv_name and "://" not in pv_name:
            pv_name = ''.join([self.pv_protocol_cmb.currentText(), pv_name])
        return pv_name

    def handle_update_datetime_timer_timeout(self):
        current_label = self.chart.getBottomAxisLabel()
        new_label = "Current Time: " + PyDMChartingDisplay.get_current_datetime(
        )

        if X_AXIS_LABEL_SEPARATOR in current_label:
            current_label = current_label[current_label.
                                          find(X_AXIS_LABEL_SEPARATOR) +
                                          len(X_AXIS_LABEL_SEPARATOR):]
            new_label += X_AXIS_LABEL_SEPARATOR + current_label

        self.chart.setLabel("bottom", text=new_label)

    def update_curve_data(self, curve):
        """
        Determine if the PV is active. If not, disable the related PV controls. If the PV is active, update the PV
        controls' states.

        Parameters
        ----------
        curve : PlotItem
           A PlotItem, i.e. a plot, to draw on the chart.
        """
        pv_name = curve.name()
        max_x = self.chart.getViewBox().viewRange()[1][0]
        max_y = self.chart.getViewBox().viewRange()[1][1]
        current_y = curve.data_buffer[1, -1]

        widgets = self.findChildren((QCheckBox, QLabel, QPushButton), pv_name)
        for w in widgets:
            if np.isnan(current_y):
                if isinstance(w, QCheckBox):
                    w.setChecked(False)
            else:
                if isinstance(w, QCheckBox) and not w.isEnabled():
                    w.setChecked(True)
                if isinstance(w, QLabel):
                    w.clear()
                    w.setText(
                        "(yMin = {0:.3f}, yMax = {1:.3f}) y = {2:.3f}".format(
                            max_x, max_y, current_y))
                    w.show()
            w.setEnabled(not np.isnan(current_y))

            if isinstance(w, QPushButton) and w.text() == "Remove":
                # Enable the Remove button to make removing inactive PVs possible anytime
                w.setEnabled(True)

    def show_mouse_coordinates(self, x, y):
        self.cross_hair_coord_lbl.clear()
        self.cross_hair_coord_lbl.setText("x = {0:.3f}, y = {1:.3f}".format(
            x, y))

    @staticmethod
    def get_current_datetime():
        current_date = datetime.datetime.now().strftime("%b %d, %Y")
        current_time = datetime.datetime.now().strftime("%H:%M:%S")
        current_datetime = current_time + ' (' + current_date + ')'

        return current_datetime

    @property
    def gridAlpha(self):
        return self.grid_alpha
Пример #43
0
class MixerPanel(QFrame):
    '''A color mixer to hook up to an image.
    You pass the image you the panel to operate on
    and it operates on that image in place. You also
    pass a callback to be called to trigger a refresh.
    This callback is called every time the mixer modifies
    your image.'''
    def __init__(self, img):
        QFrame.__init__(self)
        # self.setFrameStyle(QFrame.Box | QFrame.Sunken)

        self.img = img
        self.mixer = ColorMixer(self.img)
        self.callback = None

        #---------------------------------------------------------------
        # ComboBox
        #---------------------------------------------------------------

        self.combo_box_entries = ['RGB Color', 'HSV Color',
                                  'Brightness/Contrast',
                                  'Gamma',
                                  'Gamma (Sigmoidal)']
        self.combo_box = QComboBox()
        for entry in self.combo_box_entries:
            self.combo_box.addItem(entry)
        self.combo_box.currentIndexChanged.connect(self.combo_box_changed)

        #---------------------------------------------------------------
        # RGB color sliders
        #---------------------------------------------------------------

        # radio buttons
        self.rgb_add = QRadioButton('Additive')
        self.rgb_mul = QRadioButton('Multiplicative')
        self.rgb_mul.toggled.connect(self.rgb_radio_changed)
        self.rgb_add.toggled.connect(self.rgb_radio_changed)

        # sliders
        rs = IntelligentSlider('R', 0.51, -255, self.rgb_changed)
        gs = IntelligentSlider('G', 0.51, -255, self.rgb_changed)
        bs = IntelligentSlider('B', 0.51, -255, self.rgb_changed)
        self.rs = rs
        self.gs = gs
        self.bs = bs

        self.rgb_widget = QWidget()
        self.rgb_widget.layout = QGridLayout(self.rgb_widget)
        self.rgb_widget.layout.addWidget(self.rgb_add, 0, 0, 1, 3)
        self.rgb_widget.layout.addWidget(self.rgb_mul, 1, 0, 1, 3)
        self.rgb_widget.layout.addWidget(self.rs, 2, 0)
        self.rgb_widget.layout.addWidget(self.gs, 2, 1)
        self.rgb_widget.layout.addWidget(self.bs, 2, 2)

        #---------------------------------------------------------------
        # HSV sliders
        #---------------------------------------------------------------
        # radio buttons
        self.hsv_add = QRadioButton('Additive')
        self.hsv_mul = QRadioButton('Multiplicative')
        self.hsv_mul.toggled.connect(self.hsv_radio_changed)
        self.hsv_mul.toggled.connect(self.hsv_radio_changed)

        # sliders
        hs = IntelligentSlider('H', 0.36, -180, self.hsv_changed)
        ss = IntelligentSlider('S', 0.002, 0, self.hsv_changed)
        vs = IntelligentSlider('V', 0.002, 0, self.hsv_changed)
        self.hs = hs
        self.ss = ss
        self.vs = vs

        self.hsv_widget = QWidget()
        self.hsv_widget.layout = QGridLayout(self.hsv_widget)
        self.hsv_widget.layout.addWidget(self.hsv_add, 0, 0, 1, 3)
        self.hsv_widget.layout.addWidget(self.hsv_mul, 1, 0, 1, 3)
        self.hsv_widget.layout.addWidget(self.hs, 2, 0)
        self.hsv_widget.layout.addWidget(self.ss, 2, 1)
        self.hsv_widget.layout.addWidget(self.vs, 2, 2)

        #---------------------------------------------------------------
        # Brightness/Contrast sliders
        #---------------------------------------------------------------
        # sliders
        cont = IntelligentSlider('x', 0.002, 0, self.bright_changed)
        bright = IntelligentSlider('+', 0.51, -255, self.bright_changed)
        self.cont = cont
        self.bright = bright

        # layout
        self.bright_widget = QWidget()
        self.bright_widget.layout = QGridLayout(self.bright_widget)
        self.bright_widget.layout.addWidget(self.cont, 0, 0)
        self.bright_widget.layout.addWidget(self.bright, 0, 1)

        #----------------------------------------------------------------------
        # Gamma Slider
        #----------------------------------------------------------------------
        gamma = IntelligentSlider('gamma', 0.005, 0, self.gamma_changed)
        self.gamma = gamma

        # layout
        self.gamma_widget = QWidget()
        self.gamma_widget.layout = QGridLayout(self.gamma_widget)
        self.gamma_widget.layout.addWidget(self.gamma, 0, 0)

        #---------------------------------------------------------------
        # Sigmoid Gamma sliders
        #---------------------------------------------------------------
        # sliders
        alpha = IntelligentSlider('alpha', 0.011, 1, self.sig_gamma_changed)
        beta = IntelligentSlider('beta', 0.012, 0, self.sig_gamma_changed)
        self.a_gamma = alpha
        self.b_gamma = beta

        # layout
        self.sig_gamma_widget = QWidget()
        self.sig_gamma_widget.layout = QGridLayout(self.sig_gamma_widget)
        self.sig_gamma_widget.layout.addWidget(self.a_gamma, 0, 0)
        self.sig_gamma_widget.layout.addWidget(self.b_gamma, 0, 1)

        #---------------------------------------------------------------
        # Buttons
        #---------------------------------------------------------------
        self.commit_button = QPushButton('Commit')
        self.commit_button.clicked.connect(self.commit_changes)
        self.revert_button = QPushButton('Revert')
        self.revert_button.clicked.connect(self.revert_changes)

        #---------------------------------------------------------------
        # Mixer Layout
        #---------------------------------------------------------------
        self.sliders = QStackedWidget()
        self.sliders.addWidget(self.rgb_widget)
        self.sliders.addWidget(self.hsv_widget)
        self.sliders.addWidget(self.bright_widget)
        self.sliders.addWidget(self.gamma_widget)
        self.sliders.addWidget(self.sig_gamma_widget)

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.combo_box, 0, 0)
        self.layout.addWidget(self.sliders, 1, 0)
        self.layout.addWidget(self.commit_button, 2, 0)
        self.layout.addWidget(self.revert_button, 3, 0)

        #---------------------------------------------------------------
        # State Initialization
        #---------------------------------------------------------------

        self.combo_box.setCurrentIndex(0)
        self.rgb_mul.setChecked(True)
        self.hsv_mul.setChecked(True)

    def set_callback(self, callback):
        self.callback = callback

    def combo_box_changed(self, index):
        self.sliders.setCurrentIndex(index)
        self.reset()

    def rgb_radio_changed(self):
        self.reset()

    def hsv_radio_changed(self):
        self.reset()

    def reset(self):
        self.reset_sliders()
        self.mixer.set_to_stateimg()
        if self.callback:
            self.callback()

    def reset_sliders(self):
        # handle changing the conversion factors necessary
        if self.rgb_add.isChecked():
            self.rs.set_conv_fac(0.51, -255)
            self.rs.set_value(0)
            self.gs.set_conv_fac(0.51, -255)
            self.gs.set_value(0)
            self.bs.set_conv_fac(0.51, -255)
            self.bs.set_value(0)
        else:
            self.rs.set_conv_fac(0.002, 0)
            self.rs.set_value(1.)
            self.gs.set_conv_fac(0.002, 0)
            self.gs.set_value(1.)
            self.bs.set_conv_fac(0.002, 0)
            self.bs.set_value(1.)

        self.hs.set_value(0)
        if self.hsv_add.isChecked():
            self.ss.set_conv_fac(0.002, -1)
            self.ss.set_value(0)
            self.vs.set_conv_fac(0.002, -1)
            self.vs.set_value(0)
        else:
            self.ss.set_conv_fac(0.002, 0)
            self.ss.set_value(1.)
            self.vs.set_conv_fac(0.002, 0)
            self.vs.set_value(1.)

        self.bright.set_value(0)
        self.cont.set_value(1.)

        self.gamma.set_value(1)
        self.a_gamma.set_value(1)
        self.b_gamma.set_value(0.5)

    def rgb_changed(self, name, val):
        if name == 'R':
            channel = self.mixer.RED
        elif name == 'G':
            channel = self.mixer.GREEN
        else:
            channel = self.mixer.BLUE

        if self.rgb_mul.isChecked():
            self.mixer.multiply(channel, val)
        elif self.rgb_add.isChecked():
            self.mixer.add(channel, val)
        else:
            pass

        if self.callback:
            self.callback()

    def hsv_changed(self, name, val):
        h = self.hs.val()
        s = self.ss.val()
        v = self.vs.val()

        if self.hsv_mul.isChecked():
            self.mixer.hsv_multiply(h, s, v)
        elif self.hsv_add.isChecked():
            self.mixer.hsv_add(h, s, v)
        else:
            pass

        if self.callback:
            self.callback()

    def bright_changed(self, name, val):
        b = self.bright.val()
        c = self.cont.val()
        self.mixer.brightness(c, b)

        if self.callback:
            self.callback()

    def gamma_changed(self, name, val):
        self.mixer.gamma(val)

        if self.callback:
            self.callback()

    def sig_gamma_changed(self, name, val):
        ag = self.a_gamma.val()
        bg = self.b_gamma.val()
        self.mixer.sigmoid_gamma(ag, bg)

        if self.callback:
            self.callback()

    def commit_changes(self):
        self.mixer.commit_changes()
        self.reset_sliders()

    def revert_changes(self):
        self.mixer.revert()
        self.reset_sliders()

        if self.callback:
            self.callback()