예제 #1
0
파일: delegates.py 프로젝트: Mymei2/calibre
 def createEditor(self, parent, option, index):
     sb = QSpinBox(parent)
     sb.setMinimum(0)
     sb.setMaximum(5)
     sb.setSuffix(' ' + _('stars'))
     sb.setSpecialValueText(_('Not rated'))
     return sb
예제 #2
0
파일: delegates.py 프로젝트: qunxyz/calibre
 def createEditor(self, parent, option, index):
     sb = QSpinBox(parent)
     sb.setMinimum(0)
     sb.setMaximum(5)
     sb.setSuffix(' ' + _('stars'))
     sb.setSpecialValueText(_('Not rated'))
     return sb
예제 #3
0
 def __mkSpinBox(self, value, min, max, options={}):
     spBox = QSpinBox()
     spBox.setValue(value)
     spBox.setMinimum(min)
     spBox.setMaximum(max)
     valueChangedSlot = options.get("valueChangedSlot", None)
     if valueChangedSlot is not None:
         spBox.valueChanged.connect(valueChangedSlot)
     return spBox
예제 #4
0
    def _setup_ui(self):
        layout = QHBoxLayout()

        layout.addWidget(QLabel(self._parm.get_name()))

        # IntParameter
        if isinstance(self._parm, IntParameter):
            spin_box = QSpinBox()
            spin_box.setMaximum(99999)
            spin_box.setValue(self._parm.get_value())
            spin_box.valueChanged.connect(self._update)
            layout.addWidget(spin_box)
        # RangeParameter
        elif isinstance(self._parm, RangeParameter):
            range_slider = RangeSlider()
            range_slider.setRangeLimit(0, 255)
            range_slider.setRange(*self._parm.get_value())
            range_slider.valueChanged.connect(self._update)

            range_label = RangeLabel(range_slider)

            layout.addWidget(range_slider)
            layout.addWidget(range_label)
        # ColorParameter
        elif isinstance(self._parm, ColorParameter):
            color_picker = ColorPicker(self._parm.get_value())
            color_picker.valueChanged.connect(self._update)

            layout.addWidget(color_picker)
        # FileParameter
        elif isinstance(self._parm, FileParameter):
            file_picker = FilePicker()
            file_picker.valueChanged.connect(self._update)

            layout.addWidget(file_picker)

        self.setLayout(layout)
예제 #5
0
class BulkSeries(BulkBase):
    def setup_ui(self, parent):
        self.make_widgets(parent, EditWithComplete)
        values = self.all_values = list(self.db.all_custom(num=self.col_id))
        values.sort(key=sort_key)
        self.main_widget.setSizeAdjustPolicy(
            self.main_widget.AdjustToMinimumContentsLengthWithIcon)
        self.main_widget.setMinimumContentsLength(25)
        self.widgets.append(QLabel('', parent))
        w = QWidget(parent)
        layout = QHBoxLayout(w)
        layout.setContentsMargins(0, 0, 0, 0)
        self.remove_series = QCheckBox(parent)
        self.remove_series.setText(_('Remove series'))
        layout.addWidget(self.remove_series)
        self.idx_widget = QCheckBox(parent)
        self.idx_widget.setText(_('Automatically number books'))
        layout.addWidget(self.idx_widget)
        self.force_number = QCheckBox(parent)
        self.force_number.setText(_('Force numbers to start with '))
        layout.addWidget(self.force_number)
        self.series_start_number = QSpinBox(parent)
        self.series_start_number.setMinimum(1)
        self.series_start_number.setMaximum(9999999)
        self.series_start_number.setProperty("value", 1)
        layout.addWidget(self.series_start_number)
        layout.addItem(
            QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.widgets.append(w)
        self.idx_widget.stateChanged.connect(self.check_changed_checkbox)
        self.force_number.stateChanged.connect(self.check_changed_checkbox)
        self.series_start_number.valueChanged.connect(
            self.check_changed_checkbox)
        self.remove_series.stateChanged.connect(self.check_changed_checkbox)
        self.ignore_change_signals = False

    def check_changed_checkbox(self):
        self.a_c_checkbox.setChecked(True)

    def initialize(self, book_id):
        self.idx_widget.setChecked(False)
        self.main_widget.set_separator(None)
        self.main_widget.update_items_cache(self.all_values)
        self.main_widget.setEditText('')
        self.a_c_checkbox.setChecked(False)

    def getter(self):
        n = unicode(self.main_widget.currentText()).strip()
        i = self.idx_widget.checkState()
        f = self.force_number.checkState()
        s = self.series_start_number.value()
        r = self.remove_series.checkState()
        return n, i, f, s, r

    def commit(self, book_ids, notify=False):
        if not self.a_c_checkbox.isChecked():
            return
        val, update_indices, force_start, at_value, clear = self.gui_val
        val = None if clear else self.normalize_ui_val(val)
        if clear or val != '':
            extras = []
            for book_id in book_ids:
                if clear:
                    extras.append(None)
                    continue
                if update_indices:
                    if force_start:
                        s_index = at_value
                        at_value += 1
                    elif tweaks['series_index_auto_increment'] != 'const':
                        s_index = self.db.get_next_cc_series_num_for(
                            val, num=self.col_id)
                    else:
                        s_index = 1.0
                else:
                    s_index = self.db.get_custom_extra(book_id,
                                                       num=self.col_id,
                                                       index_is_id=True)
                extras.append(s_index)
            self.db.set_custom_bulk(book_ids,
                                    val,
                                    extras=extras,
                                    num=self.col_id,
                                    notify=notify)
예제 #6
0
파일: covers.py 프로젝트: GRiker/calibre
 def create_sz(label):
     ans = QSpinBox(self)
     ans.setSuffix(' px'), ans.setMinimum(100), ans.setMaximum(10000)
     l.addRow(label, ans)
     ans.valueChanged.connect(self.changed_timer.start)
     return ans
예제 #7
0
파일: covers.py 프로젝트: GRiker/calibre
    def __init__(self,
                 mi=None,
                 prefs=None,
                 parent=None,
                 for_global_prefs=False):
        QWidget.__init__(self, parent)
        self.ignore_changed = False
        self.for_global_prefs = for_global_prefs

        self.l = l = QHBoxLayout(self)
        l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(l)
        self.settings_tabs = st = QTabWidget(self)
        l.addWidget(st)
        self.preview_label = la = Preview(self)
        l.addWidget(la)

        if prefs is None:
            prefs = cprefs
        self.original_prefs = prefs
        self.mi = mi or self.default_mi()

        self.colors_page = cp = QWidget(st)
        st.addTab(cp, _('&Colors'))
        cp.l = l = QGridLayout()
        cp.setLayout(l)
        if for_global_prefs:
            msg = _(
                'When generating covers, a color scheme for the cover is chosen at random from the'
                ' color schemes below. You can prevent an individual scheme from being selected by'
                ' unchecking it. The preview on the right shows the currently selected color scheme.'
            )
        else:
            msg = _(
                'Choose a color scheme to be used for this generated cover.'
            ) + '<p>' + _(
                'In normal cover generation, the color scheme is chosen at random from the list of color schemes below. You'
                ' can prevent an individual color scheme from being chosen by unchecking it here.'
            )
        cp.la = la = QLabel('<p>' + msg)
        la.setWordWrap(True)
        l.addWidget(la, 0, 0, 1, -1)
        self.colors_list = cl = QListWidget(cp)
        l.addWidget(cl, 1, 0, 1, -1)
        self.colors_map = OrderedDict()
        self.ncs = ncs = QPushButton(
            QIcon(I('plus.png')), _('&New color scheme'), cp)
        ncs.clicked.connect(self.create_color_scheme)
        l.addWidget(ncs)
        self.ecs = ecs = QPushButton(
            QIcon(I('format-fill-color.png')), _('&Edit color scheme'), cp)
        ecs.clicked.connect(self.edit_color_scheme)
        l.addWidget(ecs, l.rowCount() - 1, 1)
        self.rcs = rcs = QPushButton(
            QIcon(I('minus.png')), _('&Remove color scheme'), cp)
        rcs.clicked.connect(self.remove_color_scheme)
        l.addWidget(rcs, l.rowCount() - 1, 2)

        self.styles_page = sp = QWidget(st)
        st.addTab(sp, _('&Styles'))
        sp.l = l = QVBoxLayout()
        sp.setLayout(l)
        if for_global_prefs:
            msg = _(
                'When generating covers, a style for the cover is chosen at random from the'
                ' styles below. You can prevent an individual style from being selected by'
                ' unchecking it. The preview on the right shows the currently selected style.'
            )
        else:
            msg = _(
                'Choose a style to be used for this generated cover.'
            ) + '<p>' + _(
                'In normal cover generation, the style is chosen at random from the list of styles below. You'
                ' can prevent an individual style from being chosen by unchecking it here.'
            )
        sp.la = la = QLabel('<p>' + msg)
        la.setWordWrap(True)
        l.addWidget(la)
        self.styles_list = sl = QListWidget(sp)
        l.addWidget(sl)
        self.style_map = OrderedDict()

        self.font_page = fp = QWidget(st)
        st.addTab(fp, _('&Fonts and Sizes'))
        fp.l = l = QFormLayout()
        fp.setLayout(l)
        fp.f = []

        def add_hline():
            f = QFrame()
            fp.f.append(f)
            f.setFrameShape(f.HLine)
            l.addRow(f)

        for x, label, size_label in (
            ('title', _('&Title font family:'), _('&Title font size:')),
            ('subtitle', _('&Subtitle font family'),
             _('&Subtitle font size:')),
            ('footer', _('&Footer font family'), _('&Footer font size')),
        ):
            attr = '%s_font_family' % x
            ff = FontFamilyChooser(fp)
            setattr(self, attr, ff)
            l.addRow(label, ff)
            ff.family_changed.connect(self.emit_changed)
            attr = '%s_font_size' % x
            fs = QSpinBox(fp)
            setattr(self, attr, fs)
            fs.setMinimum(8), fs.setMaximum(200), fs.setSuffix(' px')
            fs.setValue(prefs[attr])
            fs.valueChanged.connect(self.emit_changed)
            l.addRow(size_label, fs)
            add_hline()
        self.changed_timer = t = QTimer(self)
        t.setSingleShot(True), t.setInterval(500), t.timeout.connect(
            self.emit_changed)

        def create_sz(label):
            ans = QSpinBox(self)
            ans.setSuffix(' px'), ans.setMinimum(100), ans.setMaximum(10000)
            l.addRow(label, ans)
            ans.valueChanged.connect(self.changed_timer.start)
            return ans

        self.cover_width = create_sz(_('Cover &width:'))
        self.cover_height = create_sz(_('Cover &height:'))
        fp.cla = la = QLabel(
            _('Note that the preview to the side is of fixed aspect ratio, so changing the cover'
              ' width above will not have any effect. If you change the height, you should also change the width nevertheless'
              ' as it will be used in actual cover generation.'))
        la.setWordWrap(True)
        l.addRow(la)

        self.templates_page = tp = QWidget(st)
        st.addTab(tp, _('&Text'))
        tp.l = l = QVBoxLayout()
        tp.setLayout(l)
        tp.la = la = QLabel(
            _('The text on the generated cover is taken from the metadata of the book.'
              ' This is controlled via templates. You can use the <b>, <i> and <br> tags'
              ' in the templates for bold, italic and line breaks, respectively. The'
              ' default templates use the title, series and authors. You can change them to use'
              ' whatever metadata you like.'))
        la.setWordWrap(True), la.setTextFormat(Qt.PlainText)
        l.addWidget(la)

        def create_template_widget(title, which, button):
            attr = which + '_template'
            heading = QLabel('<h2>' + title)
            setattr(tp, attr + '_heading', heading)
            l.addWidget(heading)
            la = QLabel()
            setattr(self, attr, la)
            l.addWidget(la), la.setTextFormat(Qt.PlainText), la.setStyleSheet(
                'QLabel {font-family: monospace}')
            la.setWordWrap(True)
            b = QPushButton(button)
            b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            b.clicked.connect(partial(self.change_template, which))
            setattr(self, attr + '_button', b)
            l.addWidget(b)
            if which != 'footer':
                f = QFrame(tp)
                setattr(tp, attr + '_sep', f), f.setFrameShape(QFrame.HLine)
                l.addWidget(f)
            l.addSpacing(10)

        create_template_widget(
            _('The title template'), 'title', _('Change the &title template'))
        create_template_widget(
            _('The sub-title template'), 'subtitle',
            _('Change the &sub-title template'))
        create_template_widget(
            _('The footer template'), 'footer',
            _('Change the &footer template'))
        l.addStretch(2)

        self.apply_prefs(prefs)
        self.changed.connect(self.update_preview)
        self.styles_list.itemSelectionChanged.connect(self.update_preview)
        self.colors_list.itemSelectionChanged.connect(self.update_preview)
        self.update_preview()
예제 #8
0
class ConfigWidget(QWidget):
    """Configuration widget for managing calibre-comicvine config."""

    def __init__(self):
        QWidget.__init__(self)
        self.layout = QGridLayout()
        self.layout.setSpacing(10)
        self.setLayout(self.layout)

        self.index = 0

        self.api_key = QLineEdit(self)
        self.api_key.setText(PREFS['api_key'])
        self.add_labeled_widget('&API key:', self.api_key)

        # Worker threads is the maximum number of worker threads to spawn.
        # Restricted to 1+
        self.worker_threads = QSpinBox(self)
        self.worker_threads.setMinimum(1)
        self.worker_threads.setValue(PREFS['worker_threads'])
        self.add_labeled_widget('&Worker threads:', self.worker_threads)

        # Request interval represents wait time between batches of requests.
        self.request_interval = QSpinBox(self)
        self.request_interval.setMinimum(0)
        self.request_interval.setValue(PREFS['request_interval'])
        self.add_labeled_widget('&Request interval (seconds):',
                                self.request_interval)

        # Request batch is the maximum number of requests to run at a time.
        # Restricted to 1+
        self.request_batch_size = QSpinBox(self)
        self.request_batch_size.setMinimum(1)
        self.request_batch_size.setValue(PREFS['request_batch_size'])
        self.add_labeled_widget('&Request batch size:', self.request_batch_size)

        # Retries is the number of times to retry if we get any error
        # from comicvine besides a rate limit error.
        self.retries = QSpinBox(self)
        self.retries.setMinimum(0)
        self.retries.setValue(PREFS['retries'])
        self.add_labeled_widget('&Retries:', self.retries)

        # Search volume limit is the max number of volumes to return from
        # a volume search.
        self.search_volume_limit = QSpinBox(self)
        self.search_volume_limit.setMinimum(10)
        self.search_volume_limit.setMaximum(10000)
        self.search_volume_limit.setSingleStep(10)
        self.search_volume_limit.setValue(PREFS['search_volume_limit'])
        self.add_labeled_widget('&search_volume_limit:',
                                self.search_volume_limit)

    def add_labeled_widget(self, label_text, widget):
        """
        Add a configuration widget, incrementing the index for the next widget.
        """
        self.index += 1
        label = QLabel(label_text)
        label.setBuddy(widget)
        self.layout.addWidget(label, self.index, 0)
        self.layout.addWidget(widget, self.index, 1)

    def save_settings(self):
        """Apply new settings value."""
        PREFS['api_key'] = unicode(self.api_key.text())
        PREFS['worker_threads'] = self.worker_threads.value()
        PREFS['request_interval'] = self.request_interval.value()
        PREFS['request_batch_size'] = self.request_batch_size.value()
        PREFS['retries'] = self.retries.value()
        PREFS['search_volume_limit'] = self.search_volume_limit.value()
예제 #9
0
파일: covers.py 프로젝트: zwpaper/calibre
 def create_sz(label):
     ans = QSpinBox(self)
     ans.setSuffix(' px'), ans.setMinimum(100), ans.setMaximum(10000)
     l.addRow(label, ans)
     ans.valueChanged.connect(self.changed_timer.start)
     return ans
예제 #10
0
class XArmUI(object):
    def __init__(self, ui, layout):
        self.main_ui = ui
        self.layout = layout
        super(XArmUI, self).__init__()
        self.handler = XArmHandler(self)
        self.lang = self.main_ui.lang
        self.set_ui()
        self.set_disable(True)

    def set_ui(self):
        self._set_common_top_ui()
        self._set_tab()
        self._set_common_down_ui()
        self.connect_slot()

    def _set_common_top_ui(self):
        top_frame = QFrame()
        top_frame.setMaximumHeight(60)
        top_layout = QVBoxLayout(top_frame)
        self.layout.addWidget(top_frame)

        common_top_frame = QFrame()
        common_top_frame.setMinimumHeight(50)
        common_top_layout = QHBoxLayout(common_top_frame)
        top_layout.addWidget(common_top_frame)

        label_1 = QLabel(i18n[self.lang]['Connected'] + ':')
        self.label_connected = QLabel()
        img = QImage()
        self.label_connected.setMaximumHeight(20)
        self.label_connected.setMaximumWidth(20)
        self.label_connected.setScaledContents(True)
        if img.load(disconnect_icon_path):
            self.label_connected.setPixmap(QPixmap.fromImage(img))

        label_2 = QLabel(i18n[self.lang]['Reported'] + ':')
        self.label_reported = QLabel()
        img = QImage()
        self.label_reported.setMaximumHeight(20)
        self.label_reported.setMaximumWidth(20)
        self.label_reported.setScaledContents(True)
        if img.load(disconnect_icon_path):
            self.label_reported.setPixmap(QPixmap.fromImage(img))

        self.lnt_addr = QLineEdit('192.168.1.182')
        self.lnt_addr.setMaximumWidth(100)
        self.lnt_addr.setMinimumWidth(60)
        self.btn_connect = QPushButton(i18n[self.lang]['Connect'])
        # self.btn_connect.setMaximumWidth(50)

        # common_top_layout.addStretch(0)
        common_top_layout.setSpacing(10)
        common_top_layout.addWidget(label_1)
        common_top_layout.addWidget(self.label_connected)
        common_top_layout.addWidget(label_2)
        common_top_layout.addWidget(self.label_reported)
        common_top_layout.addWidget(self.lnt_addr)
        common_top_layout.addWidget(self.btn_connect)

        # common_down_frame = QFrame()
        # common_down_layout = QHBoxLayout(common_down_frame)
        # common_down_layout.setSpacing(0)
        # top_layout.addWidget(common_down_frame)
        common_down_layout = common_top_layout

        label = QLabel(i18n[self.lang]['WarnCode'] + ':')
        self.label_warn_code = QLabel('0')
        self.label_warn_code.setStyleSheet('''color: gray;font:bold;''')
        common_down_layout.addWidget(label)
        common_down_layout.addWidget(self.label_warn_code)

        label = QLabel(i18n[self.lang]['ErrorCode'] + ':')
        self.label_error_code = QLabel('0')
        self.label_error_code.setStyleSheet('''color: gray;font:bold;''')
        common_down_layout.addWidget(label)
        common_down_layout.addWidget(self.label_error_code)

        label = QLabel(i18n[self.lang]['CmdCount'] + ':')
        self.label_cmd_count = QLabel('0')
        self.label_cmd_count.setStyleSheet('''color: gray;font:bold;''')
        common_down_layout.addWidget(label)
        common_down_layout.addWidget(self.label_cmd_count)

        label = QLabel(i18n[self.lang]['State'] + ':')
        self.label_state = QLabel('4')
        self.label_state.setStyleSheet('''color: gray;font:bold;''')
        common_down_layout.addWidget(label)
        common_down_layout.addWidget(self.label_state)

        label = QLabel(i18n[self.lang]['Maable'] + ':')
        self.label_maable = QLabel('128')
        self.label_maable.setStyleSheet('''color: gray;font:bold;''')
        common_down_layout.addWidget(label)
        common_down_layout.addWidget(self.label_maable)

        label = QLabel(i18n[self.lang]['Mtbrake'] + ':')
        self.label_mtbrake = QLabel('128')
        self.label_mtbrake.setStyleSheet('''color: gray;font:bold;''')
        common_down_layout.addWidget(label)
        common_down_layout.addWidget(self.label_mtbrake)

    def _set_tab(self):
        tab_widget = QTabWidget()
        tab_widget.setMaximumHeight(self.main_ui.window.geometry().height() //
                                    2)
        self.layout.addWidget(tab_widget)

        toolBox1 = QToolBox()
        toolBox2 = QToolBox()

        groupBox1 = QGroupBox()
        groupBox2 = QGroupBox()

        toolBox1.addItem(groupBox1, "")
        toolBox2.addItem(groupBox2, "")

        tab_widget.addTab(toolBox1, i18n[self.lang]['Joint'])
        tab_widget.addTab(toolBox2, i18n[self.lang]['Cartesian'])

        joint_layout = QVBoxLayout(groupBox1)
        cartesian_layout = QVBoxLayout(groupBox2)

        self.cartesian_ui = CartesianUI(self, cartesian_layout)
        self.axis_ui = JointUI(self, joint_layout)

    def _set_common_down_ui(self):
        slider_frame = QFrame()
        slider_layout = QGridLayout(slider_frame)
        self.layout.addWidget(slider_frame)

        label = QLabel(i18n[self.lang]['Speed'] + ':')
        self.slider_speed = QSlider(Qt.Horizontal)
        self.spinbox_speed = QSpinBox()
        self.slider_speed.setMinimum(1)
        self.slider_speed.setMaximum(1000)
        self.slider_speed.setValue(50)
        self.spinbox_speed.setSingleStep(1)
        self.spinbox_speed.setMinimum(1)
        self.spinbox_speed.setMaximum(1000)
        self.spinbox_speed.setValue(50)
        slider_layout.addWidget(label, 0, 0)
        slider_layout.addWidget(self.slider_speed, 0, 1)
        slider_layout.addWidget(self.spinbox_speed, 0, 2)

        label = QLabel(i18n[self.lang]['Acc'] + ':')
        self.slider_acc = QSlider(Qt.Horizontal)
        self.spinbox_acc = QSpinBox()
        self.slider_acc.setMinimum(1)
        self.slider_acc.setMaximum(100000)
        self.slider_acc.setValue(5000)
        self.spinbox_acc.setSingleStep(1)
        self.spinbox_acc.setMinimum(1)
        self.spinbox_acc.setMaximum(100000)
        self.spinbox_acc.setValue(5000)
        slider_layout.addWidget(label, 0, 3)
        slider_layout.addWidget(self.slider_acc, 0, 4)
        slider_layout.addWidget(self.spinbox_acc, 0, 5)

        common_frame = QFrame()
        common_layout = QGridLayout(common_frame)
        self.layout.addWidget(common_frame)

        self.btn_stop = QPushButton(i18n[self.lang]['Stop'])
        self.btn_clean = QPushButton(i18n[self.lang]['CleanErrorWarn'])
        self.btn_reset = QPushButton(i18n[self.lang]['Reset'])
        self.btn_get_servo_dbmsg = QPushButton(
            i18n[self.lang]['GetServoDebugMsg'])

        common_layout.addWidget(self.btn_stop, 0, 0)
        common_layout.addWidget(self.btn_clean, 0, 2)
        common_layout.addWidget(self.btn_reset, 0, 3)
        common_layout.addWidget(self.btn_get_servo_dbmsg, 0, 4)

        btn_frame = QFrame()
        btn_layout = QGridLayout(btn_frame)
        self.layout.addWidget(btn_frame)

        self.combobox_servo = QComboBox()
        self.combobox_servo.setStyleSheet('''color: blue;''')
        for item in [
                'axis-all', 'axis-1', 'axis-2', 'axis-3', 'axis-4', 'axis-5',
                'axis-6', 'axis-7'
        ]:
            self.combobox_servo.addItem(item)
        self.combobox_servo.setCurrentIndex(1)
        btn_layout.addWidget(self.combobox_servo, 0, 0)

        self.btn_motion_enable = QPushButton(i18n[self.lang]['MotionEnable'])
        self.btn_motion_disable = QPushButton(i18n[self.lang]['MotionDisable'])
        self.btn_servo_attach = QPushButton(i18n[self.lang]['ServoAttach'])
        self.btn_servo_detach = QPushButton(i18n[self.lang]['ServoDetach'])

        self.combobox_state = QComboBox()
        self.combobox_state.setStyleSheet('''color: blue;''')
        for item in ['sport', 'pause', 'stop']:
            self.combobox_state.addItem(item)
            self.combobox_state.setCurrentIndex(0)
        self.btn_set_state = QPushButton(i18n[self.lang]['SetState'])

        btn_layout.addWidget(self.btn_motion_enable, 0, 1)
        btn_layout.addWidget(self.btn_motion_disable, 0, 2)
        btn_layout.addWidget(self.btn_servo_attach, 0, 3)
        btn_layout.addWidget(self.btn_servo_detach, 0, 4)
        btn_layout.addWidget(self.combobox_state, 0, 5)
        btn_layout.addWidget(self.btn_set_state, 0, 6)

        self.lnt_servo_addr = QLineEdit('servo_addr')
        self.lnt_servo_addr_value = QLineEdit('value')
        self.btn_get_servo_addr16 = QPushButton(
            i18n[self.lang]['GetServoAddr16'])
        self.btn_set_servo_addr16 = QPushButton(
            i18n[self.lang]['SetServoAddr16'])
        self.btn_get_servo_addr32 = QPushButton(
            i18n[self.lang]['GetServoAddr32'])
        self.btn_set_servo_addr32 = QPushButton(
            i18n[self.lang]['SetServoAddr32'])
        self.btn_set_servo_zero = QPushButton(i18n[self.lang]['SetServoZero'])

        btn_layout.addWidget(self.lnt_servo_addr, 1, 0)
        btn_layout.addWidget(self.lnt_servo_addr_value, 1, 1)
        btn_layout.addWidget(self.btn_get_servo_addr16, 1, 2)
        btn_layout.addWidget(self.btn_set_servo_addr16, 1, 3)
        btn_layout.addWidget(self.btn_get_servo_addr32, 1, 4)
        btn_layout.addWidget(self.btn_set_servo_addr32, 1, 5)
        btn_layout.addWidget(self.btn_set_servo_zero, 1, 6)

    def connect_slot(self):
        self.btn_connect.clicked.connect(self.connect)
        self.slider_speed.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_speed,
                              scale=1))
        self.spinbox_speed.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_speed,
                              scale=1))
        self.slider_acc.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_acc,
                              scale=1))
        self.spinbox_acc.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_acc,
                              scale=1))
        self.btn_stop.clicked.connect(self.stop)
        self.btn_clean.clicked.connect(self.clean)
        self.btn_reset.clicked.connect(self.reset)
        self.btn_get_servo_dbmsg.clicked.connect(
            functools.partial(self.handler.get_servo_debug_msg,
                              only_log_error_servo=False))
        self.btn_motion_enable.clicked.connect(self.motion_enable)
        self.btn_motion_disable.clicked.connect(self.motion_disable)
        self.btn_servo_attach.clicked.connect(self.set_servo_attach)
        self.btn_servo_detach.clicked.connect(self.set_servo_detach)
        self.btn_set_state.clicked.connect(self.set_state)
        self.btn_get_servo_addr16.clicked.connect(self.get_servo_addr_16)
        self.btn_set_servo_addr16.clicked.connect(self.set_servo_addr_16)
        self.btn_get_servo_addr32.clicked.connect(self.get_servo_addr_32)
        self.btn_set_servo_addr32.clicked.connect(self.set_servo_addr_32)
        self.btn_set_servo_zero.clicked.connect(self.set_servo_zero)

    @staticmethod
    def slider_spinbox_related(value, master=None, slave=None, scale=1):
        try:
            slave.setValue(value * scale)
        except Exception as e:
            print(e)

    def reset_flag(self):
        self.cartesian_ui.reset_flag()
        self.axis_ui.reset_flag()

    def update_maable_mtbrake(self, maable, mtbrake):
        try:
            self.label_maable.setText(str(maable))
            self.label_mtbrake.setText(str(mtbrake))
            self.label_maable.setStyleSheet('''color: green;font:bold;''')
            self.label_mtbrake.setStyleSheet('''color: green;font:bold;''')
        except Exception as e:
            print(e)

    def update_cmd_count(self, cmdnum):
        try:
            self.label_cmd_count.setText(str(cmdnum))
            self.label_cmd_count.setStyleSheet('''color: green;font:bold;''')
        except Exception as e:
            print(e)

    def update_state(self, state):
        try:
            if state == 1:
                state_str = 'sport'
                self.label_state.setText(state_str)
                self.label_state.setStyleSheet('''color: green;font:bold;''')
            elif state == 2:
                state_str = 'sleep'
                self.label_state.setText(state_str)
                self.label_state.setStyleSheet('''color: gray;font:bold;''')
            elif state == 3:
                state_str = 'pause'
                self.label_state.setText(state_str)
                self.label_state.setStyleSheet('''color: orange;font:bold;''')
            elif state == 4:
                state_str = 'stop'
                self.label_state.setText(state_str)
                self.label_state.setStyleSheet('''color: red;font:bold;''')
        except Exception as e:
            print(e)
        # getattr(self, 'label_state').setText(state_str)
        # getattr(self, 'label_state').setText(str(state))
        if state != 1:
            self.reset_flag()

    def update_warn_error(self, item):
        try:
            warn, error = item
            self.label_warn_code.setText(str(warn))
            self.label_error_code.setText(str(error))
            if warn != 0:
                self.label_warn_code.setStyleSheet('''color: red;font:bold;''')
            else:
                self.label_warn_code.setStyleSheet(
                    '''color: green;font:bold;''')
            if error != 0:
                self.label_error_code.setStyleSheet(
                    '''color: red;font:bold;''')
            else:
                self.label_error_code.setStyleSheet(
                    '''color: green;font:bold;''')
        except Exception as e:
            print(e)

    def update_connect_status(self, item):
        try:
            img = QImage()
            if item[0]:
                logger.info('connect to {} success, report: {}'.format(
                    self.handler.addr, self.handler.report_type))
                if img.load(connect_icon_path):
                    self.label_connected.setPixmap(QPixmap.fromImage(img))
                    self.btn_connect.setText(i18n[self.lang]['Disconnect'])
                    self.btn_connect.setStyleSheet('''color: red;font:bold;''')
                self.set_disable(False)
            else:
                logger.info('disconnect from or failed connect {}'.format(
                    self.handler.addr))
                self.handler.cmd_que.queue.clear()
                if img.load(disconnect_icon_path):
                    self.label_connected.setPixmap(QPixmap.fromImage(img))
                    self.btn_connect.setText(i18n[self.lang]['Connect'])
                    self.btn_connect.setStyleSheet(
                        '''color: green;font:bold;''')
                self.set_disable(True)
            if item[1]:
                if img.load(connect_icon_path):
                    self.label_reported.setPixmap(QPixmap.fromImage(img))
            else:
                if img.load(disconnect_icon_path):
                    self.label_reported.setPixmap(QPixmap.fromImage(img))
        except Exception as e:
            print(e)

    def connect(self, event):
        try:
            if str(self.btn_connect.text()) == i18n[self.lang]['Connect']:
                addr = self.lnt_addr.text().strip()
                if addr == '192.168.1.':
                    addr = 'localhost'
                    report_type = 'normal'
                else:
                    tmp = addr.split(':')
                    addr = tmp[0]
                    report_type = tmp[1] if len(tmp) > 1 else 'normal'
                self.btn_connect.setText('Connecting')
                self.btn_connect.setStyleSheet('''color: orange;font:bold;''')
                self.handler.connect(addr, report_type=report_type)
                # if self.window.connect(addr, report_type=report_type):
                #     self.btn_connect.setText(self.disconnect_label)
                #     self.btn_connect.setStyleSheet('''color: red;font:bold;''')
            elif str(self.btn_connect.text()) == i18n[self.lang]['Disconnect']:
                self.handler.disconnect()
                self.btn_connect.setText(i18n[self.lang]['Connect'])
                self.btn_connect.setStyleSheet('''color: green;font:bold;''')
        except Exception as e:
            print(e)

    def stop(self, event):
        try:
            self.handler.cmd_que.queue.clear()
            if self.handler.xarm and self.handler.xarm.warn_code != 0:
                item = {
                    'cmd': 'clean_warn',
                }
                self.handler.put_cmd_que(item)
            if self.handler.xarm and self.handler.xarm.error_code != 0:
                item = {
                    'cmd': 'clean_error',
                }
                self.handler.put_cmd_que(item)
                item = {
                    'cmd': 'motion_enable',
                    'kwargs': {
                        'servo_id': 0,
                        'enable': True
                    }
                }
                self.handler.put_cmd_que(item)
            item = {
                'cmd': 'urgent_stop',
            }
            self.handler.put_cmd_que(item)
            self.reset_flag()
        except Exception as e:
            print(e)

    def clean(self, event):
        try:
            self.handler.cmd_que.queue.clear()
            if self.handler.xarm and self.handler.xarm.warn_code != 0:
                item = {
                    'cmd': 'clean_warn',
                }
                self.handler.put_cmd_que(item)
            if self.handler.xarm and self.handler.xarm.error_code != 0:
                item = {
                    'cmd': 'clean_error',
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def reset(self, event):
        try:
            self.handler.cmd_que.queue.clear()
            if self.handler.xarm and self.handler.xarm.warn_code != 0:
                item = {
                    'cmd': 'clean_warn',
                }
                self.handler.put_cmd_que(item)
            if self.handler.xarm and self.handler.xarm.error_code != 0:
                item = {
                    'cmd': 'clean_error',
                }
                self.handler.put_cmd_que(item)
                item = {
                    'cmd': 'motion_enable',
                    'kwargs': {
                        'servo_id': 0,
                        'enable': True
                    }
                }
                self.handler.put_cmd_que(item)
                item = {'cmd': 'set_state', 'kwargs': {'state': 0}}
                self.handler.put_cmd_que(item)
            item = {
                'cmd': 'move_gohome',
                'kwargs': {
                    'speed': 30,
                    'mvacc': 5000,
                }
            }
            self.handler.put_cmd_que(item)
            self.reset_flag()
        except Exception as e:
            print(e)

    def get_servo_addr_16(self, event):
        try:
            addr = self.lnt_servo_addr.text().strip()
            try:
                if addr.lower().startswith('0x'):
                    addr = int(addr, base=16)
                else:
                    addr = int(addr)
            except:
                QMessageBox.warning(self.main_ui.window, '错误',
                                    '请输入正确的地址, 地址必须是u16类型')
                return
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                QMessageBox.warning(self.main_ui.window, '警告',
                                    '请选择其中一个电机,不能选择所有电机')
                return
            else:
                servo_id = int(text.split('-')[-1])
            tmp = '你确定要获取电机{}的地址{}的值吗?'.format(servo_id, addr)
            if QMessageBox.question(self.main_ui.window, '警告',
                                    tmp) == QMessageBox.Yes:
                item = {
                    'cmd': 'get_servo_addr_16',
                    'kwargs': {
                        'servo_id': servo_id,
                        'addr': addr
                    }
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def get_servo_addr_32(self, event):
        try:
            addr = self.lnt_servo_addr.text().strip()
            try:
                if addr.lower().startswith('0x'):
                    addr = int(addr, base=16)
                else:
                    addr = int(addr)
            except:
                QMessageBox.warning(self.main_ui.window, '错误',
                                    '请输入正确的地址, 地址必须是u16类型')
                return
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                QMessageBox.warning(self.main_ui.window, '警告',
                                    '请选择其中一个电机,不能选择所有电机')
                return
            else:
                servo_id = int(text.split('-')[-1])
            tmp = '你确定要获取电机{}的地址{}的值吗?'.format(servo_id, addr)
            if QMessageBox.question(self.main_ui.window, '警告',
                                    tmp) == QMessageBox.Yes:
                item = {
                    'cmd': 'get_servo_addr_32',
                    'kwargs': {
                        'servo_id': servo_id,
                        'addr': addr
                    }
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_addr_16(self, event):
        try:
            addr = self.lnt_servo_addr.text().strip()
            try:
                if addr.lower().startswith('0x'):
                    addr = int(addr, base=16)
                else:
                    addr = int(addr)
            except:
                QMessageBox.warning(self.main_ui.window, '错误',
                                    '请输入正确的地址, 地址必须是u16类型')
                return
            value = self.lnt_servo_addr_value.text().strip()
            try:
                value = float(value)
            except:
                QMessageBox.warning(self.main_ui.window, '错误',
                                    '请输入正确的值, 值必须是float32类型')
                return
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                QMessageBox.warning(self.main_ui.window, '警告',
                                    '请选择其中一个电机,不能选择所有电机')
                return
            else:
                servo_id = int(text.split('-')[-1])
            tmp = '你确定要设置电机{}的地址{}的值为{}吗?'.format(servo_id, addr, value)
            if QMessageBox.question(self.main_ui.window, '警告',
                                    tmp) == QMessageBox.Yes:
                item = {
                    'cmd': 'set_servo_addr_16',
                    'kwargs': {
                        'servo_id': servo_id,
                        'addr': addr,
                        'value': value
                    }
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_addr_32(self, event):
        try:
            addr = self.lnt_servo_addr.text().strip()
            try:
                if addr.lower().startswith('0x'):
                    addr = int(addr, base=16)
                else:
                    addr = int(addr)
            except:
                QMessageBox.warning(self.main_ui.window, '错误',
                                    '请输入正确的地址, 地址必须是u16类型')
                return
            value = self.lnt_servo_addr_value.text().strip()
            try:
                value = float(value)
            except:
                QMessageBox.warning(self.main_ui.window, '错误',
                                    '请输入正确的值, 值必须是float32类型')
                return
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                QMessageBox.warning(self.main_ui.window, '警告',
                                    '请选择其中一个电机,不能选择所有电机')
                return
            else:
                servo_id = int(text.split('-')[-1])

            tmp = '你确定要设置电机{}的地址{}的值为{}吗?'.format(servo_id, addr, value)
            if QMessageBox.question(self.main_ui.window, '警告',
                                    tmp) == QMessageBox.Yes:
                item = {
                    'cmd': 'set_servo_addr_32',
                    'kwargs': {
                        'servo_id': servo_id,
                        'addr': addr,
                        'value': value
                    }
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_zero(self, event):
        try:
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                servo_id = 8
            else:
                servo_id = int(text.split('-')[-1])
            if servo_id == 8:
                tmp = '你确定要设置所有电机的零点吗?'
            else:
                tmp = '你确定要设置电机{}的零点吗?'.format(servo_id)
            if QMessageBox.question(self.main_ui.window, '警告',
                                    tmp) == QMessageBox.Yes:
                item = {
                    'cmd': 'set_servo_zero',
                    'kwargs': {
                        'servo_id': servo_id
                    }
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_attach(self, event):
        try:
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                servo_id = 8
            else:
                servo_id = int(text.split('-')[-1])

            item = {
                'cmd': 'set_servo_attach',
                'kwargs': {
                    'servo_id': servo_id
                }
            }
            self.handler.put_cmd_que(item)
            item = {
                'cmd': 'motion_enable',
                'kwargs': {
                    'servo_id': servo_id,
                    'enable': True
                }
            }
            self.handler.put_cmd_que(item)
            item = {'cmd': 'set_state', 'kwargs': {'state': 0}}
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_detach(self, event):
        try:
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                servo_id = 8
            else:
                servo_id = int(text.split('-')[-1])

            if servo_id == 8:
                tmp = '你确定要解锁所有电机吗?'
            else:
                tmp = '你确定要解锁电机{}吗?'.format(servo_id)
            if QMessageBox.question(self.main_ui.window, '警告',
                                    tmp) == QMessageBox.Yes:
                item = {
                    'cmd': 'set_servo_detach',
                    'kwargs': {
                        'servo_id': servo_id
                    }
                }
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def motion_enable(self, event):
        self._motion_enable(True)

    def motion_disable(self, event):
        self._motion_enable(False)

    def _motion_enable(self, enable=True):
        try:
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                servo_id = 8
            else:
                servo_id = int(text.split('-')[-1])
            item = {
                'cmd': 'motion_enable',
                'kwargs': {
                    'servo_id': servo_id,
                    'enable': enable
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_state(self, event):
        try:
            text = self.combobox_state.currentText()
            if text == 'sport':
                state = 0
            elif text == 'pause':
                state = 3
            elif text == 'stop':
                state = 4
            else:
                return
            if state in [0, 3, 4]:
                item = {'cmd': 'set_state', 'kwargs': {'state': state}}
                self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_disable(self, disable):
        try:
            self.btn_stop.setDisabled(disable)
            self.btn_clean.setDisabled(disable)
            self.btn_reset.setDisabled(disable)
            self.btn_get_servo_dbmsg.setDisabled(disable)
            self.combobox_servo.setDisabled(disable)
            self.combobox_state.setDisabled(disable)
            self.btn_motion_enable.setDisabled(disable)
            self.btn_motion_disable.setDisabled(disable)
            self.btn_servo_attach.setDisabled(disable)
            self.btn_servo_detach.setDisabled(disable)
            self.btn_set_state.setDisabled(disable)
            self.lnt_servo_addr.setDisabled(disable)
            self.lnt_servo_addr_value.setDisabled(disable)
            self.btn_get_servo_addr16.setDisabled(disable)
            self.btn_set_servo_addr16.setDisabled(disable)
            self.btn_get_servo_addr32.setDisabled(disable)
            self.btn_set_servo_addr32.setDisabled(disable)
            self.btn_set_servo_zero.setDisabled(disable)

            self.slider_speed.setDisabled(disable)
            self.spinbox_speed.setDisabled(disable)
            self.slider_acc.setDisabled(disable)
            self.spinbox_acc.setDisabled(disable)

            self.axis_ui.set_disable(disable)
            self.cartesian_ui.set_disable(disable)
        except Exception as e:
            print(e)
예제 #11
0
class UArmUI(object):
    def __init__(self, ui, layout):
        self.main_ui = ui
        self.layout = layout
        super(UArmUI, self).__init__()
        self.handler = UArmHandler(self)
        self.lang = self.main_ui.lang
        self.status = 0
        self.set_ui()
        self.set_disable(True)

    def set_ui(self):
        self._set_common_top_ui()
        self._set_tab()
        self._set_common_down_ui()
        self.connect_slot()

    def _set_common_top_ui(self):
        top_frame = QFrame()
        top_frame.setMaximumHeight(60)
        top_layout = QVBoxLayout(top_frame)
        self.layout.addWidget(top_frame)

        common_top_frame = QFrame()
        common_top_frame.setMinimumHeight(50)
        common_top_frame.setMaximumHeight(50)
        common_top_layout = QHBoxLayout(common_top_frame)
        top_layout.addWidget(common_top_frame)
        common_top_layout.addStretch(0)

        label = QLabel(i18n[self.lang]['Type'] + ':')
        self.label_type = QLabel('')
        self.label_type.setStyleSheet('''color: gray;font:bold;''')
        common_top_layout.addWidget(label)
        common_top_layout.addWidget(self.label_type)

        label = QLabel(i18n[self.lang]['Mode'] + ':')
        self.label_mode = QLabel('')
        self.label_mode.setStyleSheet('''color: gray;font:bold;''')
        common_top_layout.addWidget(label)
        common_top_layout.addWidget(self.label_mode)

        label = QLabel(i18n[self.lang]['HardwareVersion'] + ':')
        self.label_hard_version = QLabel('')
        self.label_hard_version.setStyleSheet('''color: gray;font:bold;''')
        common_top_layout.addWidget(label)
        common_top_layout.addWidget(self.label_hard_version)

        label = QLabel(i18n[self.lang]['FirmwareVersion'] + ':')
        self.label_firm_version = QLabel('')
        self.label_firm_version.setStyleSheet('''color: gray;font:bold;''')
        common_top_layout.addWidget(label)
        common_top_layout.addWidget(self.label_firm_version)

        label_1 = QLabel(i18n[self.lang]['Connected'] + ':')
        self.label_connected = QLabel()
        img = QImage()
        self.label_connected.setMaximumHeight(20)
        self.label_connected.setMaximumWidth(20)
        self.label_connected.setScaledContents(True)
        if img.load(disconnect_icon_path):
            self.label_connected.setPixmap(QPixmap.fromImage(img))

        self.lnt_addr = QLineEdit('COM12')
        self.lnt_addr.setMaximumWidth(50)
        self.lnt_addr.setMinimumWidth(30)
        self.btn_connect = QPushButton(i18n[self.lang]['Connect'])
        # self.btn_connect.setMaximumWidth(50)

        # common_top_layout.addStretch(0)
        common_top_layout.setSpacing(10)
        common_top_layout.addWidget(label_1)
        common_top_layout.addWidget(self.label_connected)
        common_top_layout.addWidget(self.lnt_addr)
        common_top_layout.addWidget(self.btn_connect)

    def _set_common_down_ui(self):
        slider_frame = QFrame()
        slider_layout = QGridLayout(slider_frame)
        self.layout.addWidget(slider_frame)

        label = QLabel(i18n[self.lang]['Speed'] + ':')
        self.slider_speed = QSlider(Qt.Horizontal)
        self.spinbox_speed = QSpinBox()
        self.slider_speed.setMinimum(1)
        self.slider_speed.setMaximum(100000)
        self.slider_speed.setValue(10000)
        self.spinbox_speed.setSingleStep(1)
        self.spinbox_speed.setMinimum(1)
        self.spinbox_speed.setMaximum(100000)
        self.spinbox_speed.setValue(10000)
        slider_layout.addWidget(label, 0, 0)
        slider_layout.addWidget(self.slider_speed, 0, 1)
        slider_layout.addWidget(self.spinbox_speed, 0, 2)

        # label = QLabel(i18n[self.lang]['Acc'] + ':')
        # self.slider_acc = QSlider(Qt.Horizontal)
        # self.spinbox_acc = QSpinBox()
        # self.slider_acc.setMinimum(1)
        # self.slider_acc.setMaximum(100000)
        # self.slider_acc.setValue(5000)
        # self.spinbox_acc.setSingleStep(1)
        # self.spinbox_acc.setMinimum(1)
        # self.spinbox_acc.setMaximum(100000)
        # self.spinbox_acc.setValue(5000)
        # slider_layout.addWidget(label, 0, 3)
        # slider_layout.addWidget(self.slider_acc, 0, 4)
        # slider_layout.addWidget(self.spinbox_acc, 0, 5)

        btn_frame = QFrame()
        btn_layout = QGridLayout(btn_frame)
        self.layout.addWidget(btn_frame)

        self.btn_get_device_info = QPushButton(i18n[self.lang]['GetDeviceInfo'])
        self.btn_get_position = QPushButton(i18n[self.lang]['GetPosition'])
        self.btn_get_polar = QPushButton(i18n[self.lang]['GetPolar'])
        self.btn_get_servo_angle = QPushButton(i18n[self.lang]['GetServoAngle'])
        self.btn_get_mode = QPushButton(i18n[self.lang]['GetMode'])

        btn_layout.addWidget(self.btn_get_device_info, 0, 0)
        btn_layout.addWidget(self.btn_get_position, 0, 1)
        btn_layout.addWidget(self.btn_get_polar, 0, 2)
        btn_layout.addWidget(self.btn_get_servo_angle, 0, 3)
        btn_layout.addWidget(self.btn_get_mode, 0, 4)

        self.combobox_servo = QComboBox()
        self.combobox_servo.setStyleSheet('''color: blue;''')
        for item in ['axis-1', 'axis-2', 'axis-3', 'axis-all']:
            self.combobox_servo.addItem(item)
        self.combobox_servo.setCurrentIndex(0)
        btn_layout.addWidget(self.combobox_servo, 0, 0)

        self.btn_servo_attach = QPushButton(i18n[self.lang]['ServoAttach'])
        self.btn_servo_detach = QPushButton(i18n[self.lang]['ServoDetach'])
        self.combobox_mode = QComboBox()
        self.combobox_mode.setStyleSheet('''color: blue;''')
        for item in ['normal', 'laser', '3D', 'pen']:
            self.combobox_mode.addItem(item)
            self.combobox_mode.setCurrentIndex(0)
        self.btn_set_mode = QPushButton(i18n[self.lang]['SetMode'])

        btn_layout.addWidget(self.combobox_servo, 1, 0)
        btn_layout.addWidget(self.btn_servo_attach, 1, 1)
        btn_layout.addWidget(self.btn_servo_detach, 1, 2)
        btn_layout.addWidget(self.combobox_mode, 1, 3)
        btn_layout.addWidget(self.btn_set_mode, 1, 4)

        self.btn_reset = QPushButton(i18n[self.lang]['Reset'])
        self.btn_pump_on = QPushButton(i18n[self.lang]['PumpOn'])
        self.btn_pump_off = QPushButton(i18n[self.lang]['PumpOff'])
        self.btn_gripper_catch = QPushButton(i18n[self.lang]['GripperCatch'])
        self.btn_gripper_release = QPushButton(i18n[self.lang]['GripperRelease'])
        btn_layout.addWidget(self.btn_reset, 2, 0)
        btn_layout.addWidget(self.btn_pump_on, 2, 1)
        btn_layout.addWidget(self.btn_pump_off, 2, 2)
        btn_layout.addWidget(self.btn_gripper_catch, 2, 3)
        btn_layout.addWidget(self.btn_gripper_release, 2, 4)

    @staticmethod
    def slider_spinbox_related(value, master=None, slave=None, scale=1):
        try:
            slave.setValue(value * scale)
        except Exception as e:
            print(e)

    def connect_slot(self):
        self.btn_connect.clicked.connect(self.connect)
        self.slider_speed.valueChanged.connect(
            functools.partial(self.slider_spinbox_related, slave=self.spinbox_speed, scale=1))
        self.spinbox_speed.valueChanged.connect(
            functools.partial(self.slider_spinbox_related, slave=self.slider_speed, scale=1))
        # self.slider_acc.valueChanged.connect(
        #     functools.partial(self.slider_spinbox_related, slave=self.spinbox_acc, scale=1))
        # self.spinbox_acc.valueChanged.connect(
        #     functools.partial(self.slider_spinbox_related, slave=self.slider_acc, scale=1))
        self.btn_get_device_info.clicked.connect(self.get_device_info)
        self.btn_get_position.clicked.connect(self.get_position)
        self.btn_get_polar.clicked.connect(self.get_polar)
        self.btn_get_servo_angle.clicked.connect(self.get_servo_angle)
        self.btn_get_mode.clicked.connect(self.get_mode)

        self.btn_servo_attach.clicked.connect(self.set_servo_attach)
        self.btn_servo_detach.clicked.connect(self.set_servo_detach)
        self.btn_set_mode.clicked.connect(self.set_mode)

        self.btn_reset.clicked.connect(self.reset)
        self.btn_pump_on.clicked.connect(self.pump_on)
        self.btn_pump_off.clicked.connect(self.pump_off)
        self.btn_gripper_catch.clicked.connect(self.gripper_catch)
        self.btn_gripper_release.clicked.connect(self.gripper_release)

    def reset_flag(self):
        self.cartesian_ui.reset_flag()
        self.axis_ui.reset_flag()

    def update_connect_status(self, item):
        try:
            img = QImage()
            if item and self.status != 1:
                self.status = 1
                logger.info('connect to {} success'.format(self.handler.port))
                if img.load(connect_icon_path):
                    self.label_connected.setPixmap(QPixmap.fromImage(img))
                    self.btn_connect.setText(i18n[self.lang]['Disconnect'])
                    self.btn_connect.setStyleSheet('''color: red;font:bold;''')
                self.set_disable(False)
            elif not item and self.status != 0:
                self.status = 0
                logger.info('disconnect from {0} or failed connect {0}'.format(self.handler.port))
                self.handler.cmd_que.queue.clear()
                if img.load(disconnect_icon_path):
                    self.label_connected.setPixmap(QPixmap.fromImage(img))
                    self.btn_connect.setText(i18n[self.lang]['Connect'])
                    self.btn_connect.setStyleSheet('''color: green;font:bold;''')
                self.set_disable(True)
        except Exception as e:
            print(e)

    def connect(self):
        try:
            if str(self.btn_connect.text()) == i18n[self.lang]['Connect']:
                addr = self.lnt_addr.text().strip()
                if addr == 'auto':
                    addr = None
                self.btn_connect.setText('Connecting')
                self.status = 2
                self.btn_connect.setStyleSheet('''color: orange;font:bold;''')
                self.handler.connect(addr)
                # if self.window.connect(addr, report_type=report_type):
                #     self.btn_connect.setText(self.disconnect_label)
                #     self.btn_connect.setStyleSheet('''color: red;font:bold;''')
            elif str(self.btn_connect.text()) == i18n[self.lang]['Disconnect']:
                self.handler.disconnect()
                self.btn_connect.setText(i18n[self.lang]['Connect'])
                self.btn_connect.setStyleSheet('''color: green;font:bold;''')
        except Exception as e:
            print(e)

    def get_device_info(self, event):
        try:
            item = {
                'cmd': 'get_device_info',
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def get_mode(self, event):
        try:
            item = {
                'cmd': 'get_mode',
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def get_position(self, event):
        try:
            item = {
                'cmd': 'get_position',
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def get_polar(self, event):
        try:
            item = {
                'cmd': 'get_polar',
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def get_servo_angle(self, event):
        try:
            item = {
                'cmd': 'get_servo_angle',
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_attach(self, event):
        try:
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                servo_id = None
            else:
                servo_id = int(self.combobox_servo.currentIndex())
            item = {
                'cmd': 'set_servo_attach',
                'kwargs': {
                    'servo_id': servo_id
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_servo_detach(self, event):
        try:
            text = self.combobox_servo.currentText()
            if text == 'axis-all':
                servo_id = None
            else:
                servo_id = int(self.combobox_servo.currentIndex())
            item = {
                'cmd': 'set_servo_detach',
                'kwargs': {
                    'servo_id': servo_id
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def pump_on(self, event):
        try:
            item = {
                'cmd': 'set_pump',
                'kwargs': {
                    'on': True
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def pump_off(self, event):
        try:
            item = {
                'cmd': 'set_pump',
                'kwargs': {
                    'on': False
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def gripper_catch(self, event):
        try:
            item = {
                'cmd': 'set_gripper',
                'kwargs': {
                    'catch': True
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def gripper_release(self, event):
        try:
            item = {
                'cmd': 'set_gripper',
                'kwargs': {
                    'catch': False
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def set_mode(self, event):
        try:
            mode = self.combobox_mode.currentIndex()
            item = {
                'cmd': 'set_mode',
                'kwargs': {
                    'mode': int(mode)
                }
            }
            self.handler.put_cmd_que(item)
        except Exception as e:
            print(e)

    def reset(self, event):
        try:
            self.handler.cmd_que.queue.clear()
            item = {
                'cmd': 'reset',
                'kwargs': {
                    'speed': self.spinbox_speed.value(),
                    'wait': False,
                }
            }
            self.handler.put_cmd_que(item)
            self.reset_flag()
        except Exception as e:
            print(e)

    @staticmethod
    def slider_spinbox_related(value, master=None, slave=None, scale=1):
        try:
            slave.setValue(value * scale)
        except Exception as e:
            print(e)

    def _set_tab(self):
        tab_widget = QTabWidget()
        tab_widget.setMaximumHeight(self.main_ui.window.geometry().height() // 2)
        self.layout.addWidget(tab_widget)

        toolBox1 = QToolBox()
        toolBox2 = QToolBox()

        groupBox1 = QGroupBox()
        groupBox2 = QGroupBox()

        toolBox1.addItem(groupBox1, "")
        toolBox2.addItem(groupBox2, "")

        tab_widget.addTab(toolBox1, i18n[self.lang]['Angle'])
        tab_widget.addTab(toolBox2, i18n[self.lang]['Coordinate'])

        joint_layout = QVBoxLayout(groupBox1)
        cartesian_layout = QVBoxLayout(groupBox2)

        self.cartesian_ui = CoordinateUI(self, cartesian_layout)
        self.axis_ui = AngleUI(self, joint_layout)

    def update_device_info(self, device_info):
        if device_info is not None:
            self.label_type.setText(str(device_info.get('device_type', None)))
            self.label_hard_version.setText(str(device_info.get('hardware_version', None)))
            self.label_firm_version.setText(str(device_info.get('firmware_version', None)))

    def update_mode(self, mode):
        if mode is not None:
            if mode == 0:
                mode_str = 'Normal'
            elif mode == 1:
                mode_str = 'Laser'
            elif mode == 2:
                mode_str = '3D'
            elif mode == 3:
                mode_str = 'Pen'
            else:
                mode_str = self.label_mode.text()
            self.label_mode.setText(mode_str)

    def set_disable(self, disable):
        try:
            self.btn_get_device_info.setDisabled(disable)
            self.btn_get_position.setDisabled(disable)
            self.btn_get_polar.setDisabled(disable)
            self.btn_get_servo_angle.setDisabled(disable)
            self.btn_get_mode.setDisabled(disable)
            self.combobox_servo.setDisabled(disable)
            self.combobox_mode.setDisabled(disable)
            self.btn_servo_attach.setDisabled(disable)
            self.btn_servo_detach.setDisabled(disable)
            self.btn_reset.setDisabled(disable)
            self.btn_pump_on.setDisabled(disable)
            self.btn_pump_off.setDisabled(disable)
            self.btn_gripper_catch.setDisabled(disable)
            self.btn_gripper_release.setDisabled(disable)

            self.slider_speed.setDisabled(disable)
            self.spinbox_speed.setDisabled(disable)
            # self.slider_acc.setDisabled(disable)
            # self.spinbox_acc.setDisabled(disable)

            self.axis_ui.set_disable(disable)
            self.cartesian_ui.set_disable(disable)
        except Exception as e:
            print(e)
예제 #12
0
 def createEditor(self, parent, option, index):
     sb = QSpinBox(parent)
     sb.setMinimum(0)
     sb.setMaximum(5)
     sb.setSuffix(' ' + _('stars'))
     return sb
예제 #13
0
class ConfigWidget(QWidget):
    """Configuration widget for managing calibre-comicvine config."""
    def __init__(self):
        QWidget.__init__(self)
        self.layout = QGridLayout()
        self.layout.setSpacing(10)
        self.setLayout(self.layout)

        self.index = 0

        self.api_key = QLineEdit(self)
        self.api_key.setText(PREFS['api_key'])
        self.add_labeled_widget('&API key:', self.api_key)

        # Worker threads is the maximum number of worker threads to spawn.
        # Restricted to 1+
        self.worker_threads = QSpinBox(self)
        self.worker_threads.setMinimum(1)
        self.worker_threads.setValue(PREFS['worker_threads'])
        self.add_labeled_widget('&Worker threads:', self.worker_threads)

        # Request interval represents wait time between batches of requests.
        self.request_interval = QSpinBox(self)
        self.request_interval.setMinimum(0)
        self.request_interval.setValue(PREFS['request_interval'])
        self.add_labeled_widget('&Request interval (seconds):',
                                self.request_interval)

        # Request batch is the maximum number of requests to run at a time.
        # Restricted to 1+
        self.request_batch_size = QSpinBox(self)
        self.request_batch_size.setMinimum(1)
        self.request_batch_size.setValue(PREFS['request_batch_size'])
        self.add_labeled_widget('&Request batch size:',
                                self.request_batch_size)

        # Retries is the number of times to retry if we get any error
        # from comicvine besides a rate limit error.
        self.retries = QSpinBox(self)
        self.retries.setMinimum(0)
        self.retries.setValue(PREFS['retries'])
        self.add_labeled_widget('&Retries:', self.retries)

        # Search volume limit is the max number of volumes to return from
        # a volume search.
        self.search_volume_limit = QSpinBox(self)
        self.search_volume_limit.setMinimum(10)
        self.search_volume_limit.setMaximum(10000)
        self.search_volume_limit.setSingleStep(10)
        self.search_volume_limit.setValue(PREFS['search_volume_limit'])
        self.add_labeled_widget('&search_volume_limit:',
                                self.search_volume_limit)

    def add_labeled_widget(self, label_text, widget):
        """
        Add a configuration widget, incrementing the index for the next widget.
        """
        self.index += 1
        label = QLabel(label_text)
        label.setBuddy(widget)
        self.layout.addWidget(label, self.index, 0)
        self.layout.addWidget(widget, self.index, 1)

    def save_settings(self):
        """Apply new settings value."""
        PREFS['api_key'] = unicode(self.api_key.text())
        PREFS['worker_threads'] = self.worker_threads.value()
        PREFS['request_interval'] = self.request_interval.value()
        PREFS['request_batch_size'] = self.request_batch_size.value()
        PREFS['retries'] = self.retries.value()
        PREFS['search_volume_limit'] = self.search_volume_limit.value()
예제 #14
0
class ImageDisplay(QWidget):

    video_infos     = ['vidéo : {}','nb frames : {}','taille : {}','FPS : {}','durée : {:.2f} sec']
    video_keys      = ['videoname','nframes','size','fps','duration']
    algo_traj       = ['barycentre','minmax']

    def __init__(self, mainWindow):

        # acall the base class constructor:
        super().__init__(mainWindow)

        self.mw = mainWindow

        # Attributs (objets persistants)
        self.img_lbl = QLabel(self)           # to display the current image
        self.img_lbl.installEventFilter(self) # filter to catch evenements
        self.selectTargetRect = None          # display a rectangle to show teh target color selection

        self.rubberBand  = QRubberBand(QRubberBand.Line, self)

        # Boutons pour avancer/reculer
        self.btn_prev  = QPushButton(QIcon("icones/go-prev.png"),  "", self)
        self.btn_next  = QPushButton(QIcon("icones/go-next.png"), "", self)
        self.btn_first = QPushButton(QIcon("icones/go-first.png"),  "", self)
        self.btn_last  = QPushButton(QIcon("icones/go-last.png"), "", self)
        self.btn_traj  = QPushButton(QIcon("icones/extract.png"), "Extraire...", self)
        self.btn_clear = QPushButton(QIcon("icones/clear.png"), "Effacer courbes...", self)
        self.btn_exportCSV = QPushButton(QIcon("icones/exportCSV.png"), "Export CSV", self)
        self.btn_algo      = QComboBox(self)
        self.image_index   = QLabel(self)
        
        # widget QSpinBox
        self.images_step      = QSpinBox(parent=self)
        self.images_firstRank = QSpinBox(parent=self) 
        self.images_lastRank  = QSpinBox(parent=self) 

        # QLabel to display the target color
        self.target_color_label = QLabel("target color",parent=self) 
        self.picked_color       = QLabel(self)
    
        self.video_path     = None  # Chemin de la dernière vidéo
        self.images_dir     = None  # Dossier contenant les images
        self.__img_idx      = None  # Rang de l'image affichée
        self.img_path       = None  # nom du chemin de l'image courante
        self.nb_img         = None  # nombre d'images

        self.video_name     = None  # nom de la video ("aaaaaa.mp4")
        self.video_nframes  = None  # nombre d'images dans la video
        self.video_size     = None  # taille (width, height) des images
        self.video_FPS      = None  # nombre d'images par seconde
        self.video_duration = None  # durée de la video en secondes
        self.videoLabels    = []    # liste de QLabel contenant les infos vidéo
        self.dico_video     = {}    # dictionnaire des méta-données

        self.dico_unit      = {}    # dictionary "pixels", "mm"
        self.scale_pixel    = None  # nombre de pixels pour conversion en mm
        self.scale_mm       = None  # nbre de mm pour scale_pixel
        self.valid_scale    = False # données de l'échelle valides ou pas
        self.pix_to_mm_coeff= 1.    # le coefficient de converion pixels -> mm
        self.dicoScale      = {}    # dictionnaire des QWidget d'info scale

        self.lbl_epsilon    = None  # label epsilon
        self.epsi_spin      = None  # boite de choix de epsilon    

        # créer l'onglet de visualisation image """
        self.__initUI()
        self.scaleInfoVisible(False)
        self.__epsilonVisible(False)

    def __initUI(self):

        # Onglet "Visualisation images"
        vbox = QVBoxLayout()

        # Ligne 1 : extraction trajec
        self.picked_color.setFrameStyle(QFrame.StyledPanel | QFrame.Plain);
        
        line1 = QHBoxLayout()
        line1.addStretch(1)
        line1.addWidget(self.btn_algo)
        line1.addWidget(self.btn_traj)
        line1.addWidget(self.target_color_label)
        line1.addWidget(self.picked_color)
        line1.addWidget(self.btn_clear)
        line1.addWidget(self.btn_exportCSV)
        line1.addStretch(1)

        # Ligne 2 : infos video + visu image
        line2 = QHBoxLayout()

        # boîte d'infos sur la vidéo
        infoVBox = QVBoxLayout()
        for _ in ImageDisplay.video_infos:
            label = QLabel(self)
            label.setFrameStyle(QFrame.StyledPanel | QFrame.Plain);
            infoVBox.addWidget(label)
            self.videoLabels.append(label)
        infoVBox.addStretch()

        widget = QLabel("Conversion pixels -> mm", self)
        self.dicoScale['Pixels-mm'] = widget
        infoVBox.addWidget(widget)

        grid = QGridLayout()
        infoVBox.addLayout(grid)

        widget = QLabel("pixels  ",self)
        self.dicoScale['pixels'] = widget
        grid.addWidget(widget,1,1)

        self.scale_pixel = QLineEdit(self)
        self.dicoScale['pixelsForMM'] = self.scale_pixel
        grid.addWidget(self.scale_pixel,1,2)

        widget = QLabel("millimètres ",self)
        self.dicoScale['millimeters'] = widget
        grid.addWidget(widget,2,1)

        self.scale_mm = QLineEdit(self)
        self.dicoScale['mmForPixels'] = self.scale_mm
        grid.addWidget(self.scale_mm,2,2)

        self.lbl_epsilon = QLabel("Epsilon ",self)
        grid.addWidget(self.lbl_epsilon,5,1)

        self.epsi_spin = QSpinBox(self)
        self.epsi_spin.setRange(1,50)
        self.epsi_spin.setSingleStep(1)
        self.epsi_spin.setValue(10)
        grid.addWidget(self.epsi_spin,5,2)
        
        infoVBox.addStretch()

        line2.addLayout(infoVBox)
        line2.addStretch(1)
        line2.addWidget(self.img_lbl) # le QLabel por afficher l'image
        line2.addStretch(1)

        # line 3 : navigation boutons
        self.image_index.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.image_index.setText("       ")
        line3 = QHBoxLayout()
        line3.addStretch(1)
        line3.addWidget(self.btn_first)
        line3.addWidget(self.btn_prev)
        line3.addWidget(self.image_index)
        line3.addWidget(self.btn_next)
        line3.addWidget(self.btn_last)
        line3.addStretch(1)

        # line 4 : first , step, last image selection
        line4 = QHBoxLayout()
        line4.addStretch(1)
        line4.addWidget(self.images_firstRank)
        line4.addWidget(self.images_step)
        line4.addWidget(self.images_lastRank)
        line4.addStretch(1)

        vbox.addLayout(line1)
        vbox.addStretch(1)
        vbox.addLayout(line2)
        vbox.addStretch(1)
        vbox.addLayout(line3)
        vbox.addLayout(line4)

        self.setLayout(vbox)

        self.buttonsState()
        self.__buttonsConnect()
        self.__setVideoLabelVisible(False)

    def __setVideoLabelVisible(self, state):
        for label in self.videoLabels:
            label.setVisible(state)

    def __buttonsConnect(self):            
        self.btn_traj.clicked.connect(self.extract_trajectoire)
        self.btn_clear.clicked.connect(self.mw.clearPlots)
        self.btn_exportCSV.clicked.connect(self.mw.ExportCSV)
        self.btn_prev.clicked.connect(self.prev_image)
        self.btn_next.clicked.connect(self.next_image)
        self.btn_first.clicked.connect(self.first_image)
        self.btn_last.clicked.connect(self.last_image)
        self.images_step.valueChanged.connect(self.__step_changed)
        self.images_firstRank.valueChanged.connect(self.__first_rank_changed)
        self.images_lastRank.valueChanged.connect(self.__last_rank_changed)

    def buttonsState(self, importCSV=False):

        self.btn_traj.setEnabled(False)
        self.picked_color.setText("X")
        self.picked_color.setEnabled(False)
        
        self.btn_traj.setStatusTip('Extrait la trajectoire de la cible'+
            'dont la couleur a été choisie')

        self.target_color_label.setEnabled(False)
        self.picked_color.setStyleSheet('background-color : rgb(255, 255, 255)')
        
        self.btn_clear.setEnabled(False)
        self.btn_clear.setStatusTip('Nettoye tous les tracés des onglets'+
            '<trajectoire> et <X(t), Y(t)>')

        self.btn_exportCSV.setEnabled(False)
        texte = "Export des données dans un fichier CSV"
        self.btn_exportCSV.setStatusTip(texte)

        if not importCSV: self.btn_algo.addItems(ImageDisplay.algo_traj)
        self.btn_algo.setEnabled(False)

        self.btn_prev.setEnabled(False)
        self.btn_prev.setStatusTip("affiche l'image précédente")

        self.btn_next.setEnabled(False)
        self.btn_next.setStatusTip("affiche l'image suivante")

        self.btn_first.setEnabled(False)
        self.btn_first.setStatusTip("affiche la première image à traiter")

        self.btn_last.setEnabled(False)
        self.btn_last.setStatusTip("affiche la dernière image à traiter")

        # SpinBoxes parameters:
        self.images_step.setRange(1,1000)
        self.images_step.setSingleStep(1)
        self.images_step.setValue(1)
        self.images_step.setPrefix("step: ")
        self.images_step.setEnabled(False)
        self.images_step.setStatusTip("Fixe le pas pour passer d'une image à l'autre")
        
        self.images_firstRank.setRange(1,1000)
        self.images_firstRank.setSingleStep(1)
        self.images_firstRank.setValue(1)
        self.images_firstRank.setPrefix("first: ")
        self.images_firstRank.setEnabled(False)
        self.images_firstRank.setStatusTip("Fixe le rang de la première image à traiter")
        
        self.images_lastRank.setRange(1,10000)
        self.images_lastRank.setSingleStep(1)
        self.images_lastRank.setValue(1)
        self.images_lastRank.setPrefix("last: ")
        self.images_lastRank.setEnabled(False)
        self.images_lastRank.setStatusTip("Fixe le rang de la dernière image à traiter")

    def __first_rank_changed(self, val):
        if self.img_idx is None: return
        if self.img_idx < val:
            self.img_idx = val
            self.show_image()
            
    def __last_rank_changed(self, val):
        if self.img_idx is None: return
        if self.img_idx > val:
            self.img_idx = val
            self.show_image()

    def __step_changed(self, val):
        if self.img_idx is None: return

    def setTextInfoVideoGrid(self):
        
        for field, name, key in zip(self.videoLabels,
                                    ImageDisplay.video_infos,
                                    ImageDisplay.video_keys):
            mess = name.format(self.dico_video.get(key,'?'))
            field.setText(mess)
        self.__setVideoLabelVisible(True)            

    def scaleInfoVisible(self, state):
        for widget in self.dicoScale.values():
            widget.setVisible(state)

    def __epsilonVisible(self, state):
        self.lbl_epsilon.setVisible(state)
        self.epsi_spin.setVisible(state)

    def open_video(self):
        '''Lance un sélecteur de fichier pour choisir la vidéo à traiter.'''
        fname = QFileDialog.getOpenFileName(None,
                                            'Choisir une vidéo',
                                            self.mw.cur_dir,
                                            'Fichier vidéo (*.mp4)')
        if fname[0]  != '' :
            # un fichier vidéo a été chosi :
            vp = fname[0]
            if self.video_path == vp :
                name = os.path.basename(vp)
                rep = QMessageBox.question(self,        # widget parent de QMessageBox
                    'Question',                     # texte du bandeau de la fenêtre
                    'Voulez-vous recharger le fichier video {} ?'.format(name),
                    QMessageBox.Yes | QMessageBox.No,   # afficher les boutons Yes et No
                    QMessageBox.No)                     # bouton No sélectionné par défaut
                if rep == QMessageBox.No: return
            # fichier vidéo à traiter => faire le split des images :
            self.video_path = vp
            self.extract_images_from_video()


    def load_images_from_directory(self):
        '''Charge les images '*.png' contenue dans le répertoire
           des images choisi avec un sélecteur graphique.'''

        # Choix du répertoire avec un sélecteur de fichier :
        dname = QFileDialog.getExistingDirectory(None,
                                                 'Choisir un dossier images',
                                                 self.mw.image_dir)
        if dname != '' :
            # un répertoire valide a été choisi :
            self.video_path = None
            self.images_dir = dname + "/"

            try:
                # Lecture du fichier ascii des méta-données
                with open(self.images_dir + "metaData.txt", "r") as F:
                    data = F.read()
                exec('self.dico_video = '+data)
            except:
                rep = QMessageBox.critical(
                    None,             # widget parent de QMessageBox
                    'Erreur',    # bandeau de la fenêtre
                    'Pas de fichier de méta-données dans le répertoire'+\
                    ' <{}>'.format(os.path.basename(dname)),
                    QMessageBox.Ok)
                return



            print("méta données :", self.dico_video)

            self.parse_meta_data()
            self.setTextInfoVideoGrid()

            # Mettre à jour l'application avec les nouvelles images chargées :
            self.update_images()


    def extract_trajectoire(self):
        '''Méthode utilisée pour extraire la trajectoire du centre de la
           cible pour toutes les images de la vidéo.'''

        # Récupérer l'algorithme de calcul du centre de la cible :
        algo = self.btn_algo.currentText()

        # Définition de la liste dans laquelle on va récupérer les coordonnées
        # du centre cible pour toutes les images :
        target_pos = []

        # Création d'un objet ProgressBar qui va lancer le travail
        # d'extraction de la cible dans les images tout en affichant une
        # barre d'avancement :
        
        first = self.images_firstRank.value()
        last  = self.images_lastRank.value()
        step  = self.images_step.value()
        
        last = last - (last - first) % step
        first_last_step = (first, last, step)
        pg = ProgressBar(self.images_dir, self)
        pg.configure_for_target_extraction(self.mw.target_RGB,
                                           algo,
                                           self.epsi_spin.value(),
                                           target_pos,
                                           first_last_step)
        ret = pg.exec_() # lance la barre et le travail d'extraction...
        print("retour de pg.exec_() :",ret)

        if ret != 0:
            self.mw.target_pos = None
            return

        target_pos = np.array(target_pos)
        width, height = self.video_size
        # l'axe verticale est retourné et decalé:
        target_pos[1] = height - target_pos[1]
        self.scale_XY()

        self.mw.target_pos = target_pos
        self.display_plots()
        
        # remettre le bouton extraire_trajectoire disabled:
        self.btn_exportCSV.setEnabled(True)

    def display_plots(self):
        self.mw.clearPlots()
        
        # Plot trajectory (X(t), Y(t)) :
        self.mw.onePlot.setEnabled(True)
        self.mw.onePlot.Plot()

        # Plot curves X(t) and Y(t)
        self.mw.twoPlots_xy.setEnabled(True)
        self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy)
        self.mw.twoPlots_xy.Plot()

        # Plot curves VX(t) and VY(t)
        self.mw.twoPlots_VxVy.setEnabled(True)
        self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy)
        self.mw.twoPlots_VxVy.Plot()


    def extract_images_from_video(self) :
        # name of the video file without path and suffix:
        videoname = os.path.basename(self.video_path)[:-4]

        # directory where to put extracted iamges:
        self.images_dir = self.mw.image_dir + videoname + "/"

        if os.path.isdir(self.images_dir) :
            print("Effacement de tous les fichiers de '{}'"\
                  .format(self.images_dir))
            for fn in os.listdir(self.images_dir) :
                os.remove(self.images_dir+fn)
        else :
            os.mkdir(self.images_dir)

        video = cv2.VideoCapture(self.video_path)
        
        self.dico_video['nframes']   = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
        self.dico_video['size']      = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),
                                        int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))    
        self.dico_video['fps']       = int(video.get(cv2.CAP_PROP_FPS))
        self.dico_video['duration']  = video.get(cv2.CAP_PROP_FRAME_COUNT)/video.get(cv2.CAP_PROP_FPS)
        self.dico_video['videoname'] = os.path.basename(self.video_path)
                                            
        self.parse_meta_data()
        self.dico_video["videoname"] = videoname+".mp4"
        self.setTextInfoVideoGrid()

        # Création d'un objet ProgressBar qui va lancer le travail
        # d'extraction des images tout en affichant une barre d'avancement :
        pg = ProgressBar(self.images_dir, self)
        pg.configure_for_video_extraction(video, self.mw.image_fmt)
        ret = pg.exec_()
        print("retour de pg.exec_() :", ret)
        if ret != 0: return

        # MAJ de la liste des fichiers images :
        self.update_images()

        # écriture des méta-data dans le fichier 'nom_video'.info
        with open(self.mw.image_dir+videoname+"/metaData.txt", "w") as F:
            F.write(str(self.dico_video))

    def computeTargetColor(self, draw_selection=False):
        col_min,row_min,col_max,row_max = self.selection.getCoords()
        print("Pixels selectionnés : lignes [{},{}] colonnes [{},{}]".\
              format(row_min, row_max, col_min, col_max))

        tab = imread(self.img_path)
        self.target_pix = tab[row_min:row_max+1, col_min:col_max+1, :]
        R = round(self.target_pix[:,:,0].mean())
        G = round(self.target_pix[:,:,1].mean())
        B = round(self.target_pix[:,:,2].mean())
        self.mw.target_RGB = np.array([R, G, B], dtype=int)
        print("RGB sélection dans <{}> :".format(os.path.basename(self.img_path)),
              self.mw.target_RGB)

        draw_selection = self.mw.flags["drawTargetSelection"]
        if draw_selection:
            self.show_image()
            print("drawTargetSelection")
            #if self.selectTargetRect is not None : del self.selectTargetRect
            # create painter instance with pixmap
            self.selectTargetRect = QPainter(self.img_lbl.pixmap())

            # set rectangle color and thickness
            self.penRectangle = QPen(QColor(0,0,0))
            self.penRectangle.setWidth(2)

            # draw rectangle on painter
            self.selectTargetRect.begin(self)
            self.selectTargetRect.setPen(self.penRectangle)
            self.selectTargetRect.drawRect(col_min,row_min,
                                          col_max-col_min,row_max-row_min)
            self.selectTargetRect.setOpacity(0.1)
            self.selectTargetRect.end()
            #self.show_image()

        self.btn_traj.setEnabled(True)
        self.btn_algo.setEnabled(True)
        self.btn_clear.setEnabled(True)
        self.target_color_label.setEnabled(True)
        self.picked_color.setStyleSheet('background-color : rgb({},{},{})'.format(R, G, B))

    @property
    def img_idx(self): return self.__img_idx

    @img_idx.setter
    def img_idx(self, index):
        self.__img_idx = index
        self.image_index.setText(str(index))
                                 
    def update_images(self) :
        '''Méthode à exécuter quand de nouvelles images sont apparues
           après une extraction d'images depuis une vidéo par exemple.
           Cette méthode :
           - met à jour des attributs qui dépendant de la liste des images,
           - met à jour l'état de certains boutons
           - fait afficher la première image et un message d'information.'''

        if self.images_dir is None :
            self.__img_idx = None
            #self.btn_prev.setEnabled(False)
            self.btn_prev.setStatusTip("")
            #self.btn_next.setEnabled(False)
            self.btn_next.setStatusTip("")
            self.images_step.setEnabled(False)
            self.images_firstRank.setEnabled(False)
            self.images_lastRank.setEnabled(False)
            
        else :
            self.buttonsState()
            self.mw.clearPlots()
            self.mw.twoPlots_VxVy.reset()
            
            # liste des noms des fichiers image pour avoir leur nombre :
            file_names = [ f for f in os.listdir(self.images_dir) \
                           if f.endswith('.png')]
            file_names.sort()
            self.nb_img = len(file_names)

              # Update spinBox:
            self.images_step.setEnabled(True)
            self.images_firstRank.setEnabled(True)
            self.images_lastRank.setEnabled(True)

            self.images_firstRank.setValue(1)
            self.images_step.setValue(1)
            self.images_lastRank.setValue(self.nb_img)

            self.images_firstRank.setMaximum(self.nb_img)
            self.images_lastRank.setMaximum(self.nb_img)
            self.images_step.setMaximum(self.nb_img)

            # MAJ des boutons prev et next
            self.img_idx = self.images_firstRank.value()
            self.btn_prev.setEnabled(True)
            self.btn_first.setEnabled(True)

            self.btn_prev.setStatusTip("charge l'image précédente")

            self.btn_next.setEnabled(True)
            self.btn_last.setEnabled(True)
            self.btn_next.setStatusTip("afficher "+self.mw.image_fmt.format(\
                self.img_idx+self.images_step.value()))
          
            self.show_image()
            self.scaleInfoVisible(True)
            self.__epsilonVisible(True)
            self.mw.tabs.setCurrentWidget(self)

            self.scale_mm.clear()
            self.scale_mm.setText("???")
            self.scale_pixel.clear()
            try:
                text = str(self.video_size[1])
            except:
                text = ""
            self.scale_pixel.setText(text)

            self.mw.twoPlots_VxVy.reset()
            

            if self.mw.flags["displayInfo"]:
                rep = QMessageBox.information(
                    None,             # widget parent de QMessageBox
                    'Information',    # bandeau de la fenêtre
                    'Vous pouvez maintenant sélectionner une couleur de cible'+\
                    'avec la souris...',
                    QMessageBox.Ok)
                

    def show_image(self):
        '''Affiche l'image dont le numéro est donné par l'attribut 'img_idx'.'''
        if self.img_idx is None :
            self.img_path = ''
        else :
            self.img_path = self.images_dir+self.mw.image_fmt.format(self.img_idx)
        pixmap = QPixmap(self.img_path)
        self.img_lbl.setPixmap(pixmap)
        self.img_lbl.setStatusTip(os.path.basename(self.img_path))

    def first_image(self) :
        if self.img_idx == None : return
        self.img_idx = self.images_firstRank.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def prev_image(self) :
        if self.img_idx == None : return
        if self.img_idx >= self.images_firstRank.value() + self.images_step.value():
            self.img_idx -= self.images_step.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def last_image(self) :
        if self.img_idx == None : return
        self.img_idx = self.images_lastRank.value() # rank of last image to process
        self.mw.statusBar().showMessage("")
        self.show_image()

    def next_image(self) :
        if self.img_idx == None : return
        if self.img_idx <= self.images_lastRank.value()-self.images_step.value():
            self.img_idx += self.images_step.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def parse_meta_data(self):
        self.video_nframes  = self.dico_video.get('nframes', None)
        self.video_size     = self.dico_video.get('size', None)
        self.video_FPS      = self.dico_video.get('fps', None)
        self.video_duration = self.dico_video.get('duration', None)
        self.video_name     = self.dico_video.get('videoname',"none.mp4")

        if self.mw.flags["debug"]:
            info= " nb images    : {},\n taille image : {},\n FPS : {} image/sec,\n durée : {.2f} sec."
            info = info.format(self.video_nframes,
                               self.video_size,
                               self.video_FPS,
                               self.video_duration)
            QMessageBox.about(None,     # widget parent de QMessageBox
                              'Informations video {}'.format(self.video_name),
                              info)


    def eventFilter(self, object, event):
        if object == self.img_lbl :
            if event.type() == QEvent.MouseButtonPress:
                self.mousePressInLabel(event)
                return True
            elif event.type() == QEvent.MouseButtonRelease:
                self.mouseReleaseInLabel(event)
                return True
            elif event.type() == QEvent.MouseMove:
                self.mouseMoveInLabel(event)
                return True
        return False

    def mousePressInLabel(self, event):
        if event.button() == Qt.LeftButton:
            self.pt1 = event.pos()
            self.pt1_rect = self.img_lbl.mapTo(self, self.pt1)
            print("\nCoord. pt1 image :",self.pt1)
            self.rubberBand.setGeometry(QRect(self.pt1_rect, QSize()))
            self.rubberBand.show()
            self.mw.statusBar().showMessage('sélection en cours....')

    def mouseMoveInLabel(self, event):
        if not self.pt1.isNull():
            pt = self.img_lbl.mapTo(self,event.pos())
            self.rubberBand.setGeometry(QRect(self.pt1_rect, pt).normalized())

    def mouseReleaseInLabel(self, event):
        if event.button() == Qt.LeftButton:
            self.pt2 = event.pos()
            print("Coord. pt2 image :", self.pt2)
            self.rubberBand.hide()
            self.selection = QRect(self.pt1, self.pt2).normalized()
            print(self.selection)
            self.computeTargetColor()

    def scale_XY(self):

        self.valid_scale = False
        self.pix_to_mm_coeff = 1.
        
        try :
            pixels = float(self.scale_pixel.text())
            mm     = float(self.scale_mm.text())
        except :
            if self.mw.flags["displayInfo"]:
                info = 'Les données de conversion Pixels -> mm n\'ont pas été '
                info += 'complétées.. les ordonnées des tracés seront en pixels.'
                rep = QMessageBox.information(None,  # parent de QMessageBox
                        'Info',               # bandeau de la fenêtre
                        info, QMessageBox.Ok)
            return
        self.valid_scale = True
        self.pix_to_mm_coeff = mm/pixels
        print("valid scale : ", self.pix_to_mm_coeff)
예제 #15
0
파일: delegates.py 프로젝트: AEliu/calibre
 def createEditor(self, parent, option, index):
     sb = QSpinBox(parent)
     sb.setMinimum(0)
     sb.setMaximum(5)
     sb.setSuffix(' ' + _('stars'))
     return sb
예제 #16
0
class GcodeUI(object):
    def __init__(self, ui, layout):
        self.main_ui = ui
        self.layout = layout
        super(GcodeUI, self).__init__()
        self.isOutlineMode = True
        self.isLaserMode = True
        self.handler = GcodeHandler(self)
        self.set_ui()
        self.connect_slot()
        self.gcode = ''

    def set_ui(self):
        self._set_up_frame_ui()
        self._set_middle_frame_ui()
        self._set_down_frame_ui()

    def _set_up_frame_ui(self):
        self.up_frame = QFrame()
        self.up_frame.setMinimumHeight(300)
        self.up_frame.setMaximumHeight(500)
        self.up_layout = QHBoxLayout(self.up_frame)
        up_left_frame = QFrame()
        # up_left_frame.setMinimumWidth(self.main_ui.window.geometry().width() / 2)
        # up_left_frame.setMaximumWidth(self.geometry().width() / 2)
        up_right_frame = QFrame()
        # up_right_frame.setMinimumWidth(self.main_ui.window.geometry().width() / 2)
        # up_right_frame.setMaximumWidth(self.geometry().width() / 2)
        self.up_left_layout = QHBoxLayout(up_left_frame)
        self.up_right_layout = QHBoxLayout(up_right_frame)
        self.up_layout.addWidget(up_left_frame)
        # self.up_layout.addWidget(up_right_frame)
        self.layout.addWidget(self.up_frame)

        self.label_img = QLabel()
        # self.label_img.setMaximumHeight(320)
        # self.label_img.setMaximumWidth(480)
        # self.label_img.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        # self.label_img.setScaledContents(True)

        img = QImage()
        if img.load(os.path.join(icon_path, 'tmp.svg')):
            self.label_img.setPixmap(QPixmap.fromImage(img))
            with open(os.path.join(icon_path, 'tmp.svg'), 'rb') as f:
                self.handler.source = f.read()

        self.up_left_layout.addWidget(self.label_img)

        self.label_img_preview = QLabel()
        # self.label_img_preview.setMaximumHeight(320)
        # self.label_img_preview.setMaximumWidth(480)
        self.label_img_preview.setDisabled(True)
        # # self.label_img_preview.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        # # self.label_img_preview.setScaledContents(True)
        # data = np.zeros(320 * 240)
        # img = QImage(data, 320, 240, QImage.Format_RGB888)
        # pixmap = QPixmap.fromImage(img)
        # self.label_img_preview.setPixmap(pixmap)
        self.up_right_layout.addWidget(self.label_img_preview)
        # self.up_frame.hide()

    def _set_middle_frame_ui(self):
        middle_frame = QFrame()
        self.middle_layout = QHBoxLayout(middle_frame)
        middle_left_frame = QFrame()
        # middle_left_frame.setMinimumWidth(self.main_ui.window.geometry().width() / 2 - 20)
        middle_right_frame = QFrame()
        # middle_right_frame.setMinimumWidth(self.main_ui.window.geometry().width() / 2 - 20)
        self.middle_left_layout = QGridLayout(middle_left_frame)
        self.middle_right_layout = QGridLayout(middle_right_frame)

        self.middle_layout.addWidget(middle_left_frame)
        self.middle_layout.addWidget(middle_right_frame)
        self.layout.addWidget(middle_frame)

        row = 0
        self.checkbox_outline = QRadioButton('OutLine')
        self.checkbox_gray = QRadioButton('Gray')
        self.checkbox_gray.hide()
        self.btn_load_img = QPushButton('LoadImage')
        self.checkbox_outline.toggle()
        self.isOutlineMode = True
        self.checkbox_outline.setDisabled(True)
        self.middle_left_layout.addWidget(self.checkbox_outline, row, 0)
        self.middle_left_layout.addWidget(self.checkbox_gray, row, 1)
        self.middle_left_layout.addWidget(self.btn_load_img, row, 2)

        row += 1
        label_x_home = QLabel('x_home:')
        self.slider_x_home = QSlider(QtCore.Qt.Horizontal)
        self.slider_x_home.setMinimum(0)
        self.slider_x_home.setMaximum(2000)
        self.slider_x_home.setValue(1500)
        self.spinbox_x_home = QDoubleSpinBox()
        self.spinbox_x_home.setDecimals(1)
        self.spinbox_x_home.setSingleStep(0.1)
        self.spinbox_x_home.setMinimum(0.0)
        self.spinbox_x_home.setMaximum(200.0)
        self.spinbox_x_home.setValue(150.0)
        self.slider_x_home.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_x_home.mouseReleaseEvent)
        self.spinbox_x_home.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_x_home.focusOutEvent)
        self.middle_left_layout.addWidget(label_x_home, row, 0)
        self.middle_left_layout.addWidget(self.slider_x_home, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_x_home, row, 2)

        row += 1
        label_y_home = QLabel('y_home:')
        self.slider_y_home = QSlider(QtCore.Qt.Horizontal)
        self.slider_y_home.setMinimum(-1500)
        self.slider_y_home.setMaximum(1500)
        self.slider_y_home.setValue(0)
        self.spinbox_y_home = QDoubleSpinBox()
        self.spinbox_y_home.setDecimals(1)
        self.spinbox_y_home.setSingleStep(0.1)
        self.spinbox_y_home.setMinimum(-150.0)
        self.spinbox_y_home.setMaximum(150.0)
        self.spinbox_y_home.setValue(0.0)
        self.slider_y_home.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_y_home.mouseReleaseEvent)
        self.spinbox_y_home.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_y_home.focusOutEvent)
        self.middle_left_layout.addWidget(label_y_home, row, 0)
        self.middle_left_layout.addWidget(self.slider_y_home, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_y_home, row, 2)

        row += 1
        label_z_home = QLabel('z_home:')
        self.slider_z_home = QSlider(QtCore.Qt.Horizontal)
        self.slider_z_home.setMinimum(0)
        self.slider_z_home.setMaximum(1500)
        self.slider_z_home.setValue(900)
        self.spinbox_z_home = QDoubleSpinBox()
        self.spinbox_z_home.setDecimals(1)
        self.spinbox_z_home.setSingleStep(0.1)
        self.spinbox_z_home.setMinimum(0.0)
        self.spinbox_z_home.setMaximum(150.0)
        self.spinbox_z_home.setValue(90.0)
        self.slider_z_home.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_z_home.mouseReleaseEvent)
        self.spinbox_z_home.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_z_home.focusOutEvent)
        self.middle_left_layout.addWidget(label_z_home, row, 0)
        self.middle_left_layout.addWidget(self.slider_z_home, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_z_home, row, 2)

        row += 1
        label_x_offset = QLabel('x_offset:')
        self.slider_x_offset = QSlider(QtCore.Qt.Horizontal)
        self.slider_x_offset.setMinimum(-5000)
        self.slider_x_offset.setMaximum(5000)
        self.slider_x_offset.setValue(0)
        self.spinbox_x_offset = QDoubleSpinBox()
        self.spinbox_x_offset.setSingleStep(0.1)
        self.spinbox_x_offset.setDecimals(1)
        self.spinbox_x_offset.setMinimum(-500.0)
        self.spinbox_x_offset.setMaximum(500.0)
        self.spinbox_x_offset.setValue(0.0)
        self.slider_x_offset.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_x_offset.mouseReleaseEvent)
        self.spinbox_x_offset.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_x_offset.focusOutEvent)
        self.middle_left_layout.addWidget(label_x_offset, row, 0)
        self.middle_left_layout.addWidget(self.slider_x_offset, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_x_offset, row, 2)

        row += 1
        label_y_offset = QLabel('y_offset:')
        self.slider_y_offset = QSlider(QtCore.Qt.Horizontal)
        self.slider_y_offset.setMinimum(-5000)
        self.slider_y_offset.setMaximum(5000)
        self.slider_y_offset.setValue(0)
        self.spinbox_y_offset = QDoubleSpinBox()
        self.spinbox_y_offset.setDecimals(1)
        self.spinbox_y_offset.setSingleStep(0.1)
        self.spinbox_y_offset.setMinimum(-500.0)
        self.spinbox_y_offset.setMaximum(500.0)
        self.spinbox_y_offset.setValue(0.0)
        self.slider_y_offset.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_y_offset.mouseReleaseEvent)
        self.spinbox_y_offset.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_y_offset.focusOutEvent)
        self.middle_left_layout.addWidget(label_y_offset, row, 0)
        self.middle_left_layout.addWidget(self.slider_y_offset, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_y_offset, row, 2)

        row += 1
        label_z_offset = QLabel('z_offset:')
        self.slider_z_offset = QSlider(QtCore.Qt.Horizontal)
        self.slider_z_offset.setMinimum(-1000)
        self.slider_z_offset.setMaximum(1500)
        self.slider_z_offset.setValue(900)
        self.spinbox_z_offset = QDoubleSpinBox()
        self.spinbox_z_offset.setDecimals(1)
        self.spinbox_z_offset.setSingleStep(0.1)
        self.spinbox_z_offset.setMinimum(-100.0)
        self.spinbox_z_offset.setMaximum(150.0)
        self.spinbox_z_offset.setValue(90.0)
        self.slider_z_offset.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_z_offset.mouseReleaseEvent)
        self.spinbox_z_offset.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_z_offset.focusOutEvent)
        self.middle_left_layout.addWidget(label_z_offset, row, 0)
        self.middle_left_layout.addWidget(self.slider_z_offset, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_z_offset, row, 2)

        row += 1
        label_pen_up = QLabel('pen_up:')
        self.slider_pen_up = QSlider(QtCore.Qt.Horizontal)
        self.slider_pen_up.setMinimum(0)
        self.slider_pen_up.setMaximum(500)
        self.slider_pen_up.setValue(200)
        self.spinbox_pen_up = QDoubleSpinBox()
        self.spinbox_pen_up.setDecimals(1)
        self.spinbox_pen_up.setSingleStep(0.1)
        self.spinbox_pen_up.setMinimum(0.0)
        self.spinbox_pen_up.setMaximum(50.0)
        self.spinbox_pen_up.setValue(20.0)
        self.slider_pen_up.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_pen_up.mouseReleaseEvent)
        self.spinbox_pen_up.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_pen_up.focusOutEvent)
        self.slider_pen_up.setDisabled(True)
        self.spinbox_pen_up.setDisabled(True)
        self.middle_left_layout.addWidget(label_pen_up, row, 0)
        self.middle_left_layout.addWidget(self.slider_pen_up, row, 1)
        self.middle_left_layout.addWidget(self.spinbox_pen_up, row, 2)

        row = 0
        self.checkbox_laser = QRadioButton('Laser')
        self.checkbox_pen = QRadioButton('Pen')
        self.checkbox_laser.toggle()
        self.isLaserMode = True
        self.middle_right_layout.addWidget(self.checkbox_laser, row, 0)
        self.middle_right_layout.addWidget(self.checkbox_pen, row, 1)

        row += 1
        label_drawing_feedrate = QLabel('drawing_feedrate:')
        self.slider_drawing_feedrate = QSlider(QtCore.Qt.Horizontal)
        self.slider_drawing_feedrate.setMinimum(5)
        self.slider_drawing_feedrate.setMaximum(1000)
        self.slider_drawing_feedrate.setValue(100)
        self.spinbox_drawing_feedrate = QSpinBox()
        self.spinbox_drawing_feedrate.setMinimum(5)
        self.spinbox_drawing_feedrate.setMaximum(1000)
        self.spinbox_drawing_feedrate.setValue(100)
        self.slider_drawing_feedrate.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_drawing_feedrate.mouseReleaseEvent)
        self.spinbox_drawing_feedrate.focusOutEvent = functools.partial(
            self.focusOutEvent,
            source=self.spinbox_drawing_feedrate.focusOutEvent)
        self.middle_right_layout.addWidget(label_drawing_feedrate, row, 0)
        self.middle_right_layout.addWidget(self.slider_drawing_feedrate, row,
                                           1)
        self.middle_right_layout.addWidget(self.spinbox_drawing_feedrate, row,
                                           2)

        row += 1
        label_moving_feedrate = QLabel('moving_feedrate:')
        self.slider_moving_feedrate = QSlider(QtCore.Qt.Horizontal)
        self.slider_moving_feedrate.setMinimum(5)
        self.slider_moving_feedrate.setMaximum(20000)
        self.slider_moving_feedrate.setValue(100)
        self.spinbox_moving_feedrate = QSpinBox()
        self.spinbox_moving_feedrate.setMinimum(5)
        self.spinbox_moving_feedrate.setMaximum(20000)
        self.spinbox_moving_feedrate.setValue(100)
        self.slider_moving_feedrate.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent,
            source=self.slider_moving_feedrate.mouseReleaseEvent)
        self.spinbox_moving_feedrate.focusOutEvent = functools.partial(
            self.focusOutEvent,
            source=self.spinbox_moving_feedrate.focusOutEvent)
        self.middle_right_layout.addWidget(label_moving_feedrate, row, 0)
        self.middle_right_layout.addWidget(self.slider_moving_feedrate, row, 1)
        self.middle_right_layout.addWidget(self.spinbox_moving_feedrate, row,
                                           2)

        row += 1
        label_scale = QLabel('scale:')
        self.slider_scale = QSlider(QtCore.Qt.Horizontal)
        self.slider_scale.setMinimum(1)
        self.slider_scale.setMaximum(100)
        self.slider_scale.setValue(10)
        self.spinbox_scale = QDoubleSpinBox()
        self.spinbox_scale.setDecimals(1)
        self.spinbox_scale.setSingleStep(0.1)
        self.spinbox_scale.setMinimum(0.1)
        self.spinbox_scale.setMaximum(10.0)
        self.spinbox_scale.setValue(1.0)
        # self.slider_scale.setDisabled(True)
        # self.spinbox_scale.setDisabled(True)
        self.slider_scale.mouseReleaseEvent = functools.partial(
            self.mouseReleaseEvent, source=self.slider_scale.mouseReleaseEvent)
        self.spinbox_scale.focusOutEvent = functools.partial(
            self.focusOutEvent, source=self.spinbox_scale.focusOutEvent)

        self.middle_right_layout.addWidget(label_scale, row, 0)
        self.middle_right_layout.addWidget(self.slider_scale, row, 1)
        self.middle_right_layout.addWidget(self.spinbox_scale, row, 2)

        row += 1
        label_resolution = QLabel('resolution:')
        self.slider_resolution = QSlider(QtCore.Qt.Horizontal)
        self.slider_resolution.setMinimum(1)
        self.slider_resolution.setMaximum(100)
        self.slider_resolution.setValue(10)
        self.spinbox_resolution = QDoubleSpinBox()
        self.spinbox_resolution.setMinimum(0.1)
        self.spinbox_resolution.setMaximum(10.0)
        self.spinbox_resolution.setSingleStep(0.1)
        self.spinbox_resolution.setDecimals(1)
        self.spinbox_resolution.setValue(1.0)
        self.slider_resolution.setDisabled(True)
        self.spinbox_resolution.setDisabled(True)
        self.middle_right_layout.addWidget(label_resolution, row, 0)
        self.middle_right_layout.addWidget(self.slider_resolution, row, 1)
        self.middle_right_layout.addWidget(self.spinbox_resolution, row, 2)

        row += 1
        self.btn_generate_gcode = QPushButton('Generate_Gcode')
        self.middle_right_layout.addWidget(self.btn_generate_gcode, row, 0)

        row += 1
        self.label_x_min = QLabel('')
        self.label_x_max = QLabel('')
        self.middle_right_layout.addWidget(self.label_x_min, row, 0)
        self.middle_right_layout.addWidget(self.label_x_max, row, 1)

        row += 1
        self.label_y_min = QLabel('')
        self.label_y_max = QLabel('')
        self.middle_right_layout.addWidget(self.label_y_min, row, 0)
        self.middle_right_layout.addWidget(self.label_y_max, row, 1)

    def _set_down_frame_ui(self):
        self.down_frame = QFrame()
        self.down_layout = QHBoxLayout(self.down_frame)
        self.layout.addWidget(self.down_frame)

        self.textEdit = QTextEdit()
        self.down_layout.addWidget(self.textEdit)
        # self.down_frame.hide()

    def select_engrave_mode(self, event):
        self.isOutlineMode = event
        # print('outline: {}, laser: {}'.format(self.isOutlineMode, self.isLaserMode))

    def select_end_type(self, event):
        self.isLaserMode = event
        self.slider_pen_up.setDisabled(self.isLaserMode)
        self.spinbox_pen_up.setDisabled(self.isLaserMode)
        self.generate_gcode()
        # print('outline: {}, laser: {}'.format(self.isOutlineMode, self.isLaserMode))

    def connect_slot(self):
        self.checkbox_outline.toggled.connect(self.select_engrave_mode)
        self.checkbox_laser.toggled.connect(self.select_end_type)
        self.btn_load_img.clicked.connect(self.load_image)

        self.slider_x_home.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_x_home,
                              scale=.1))
        self.spinbox_x_home.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_x_home,
                              scale=10))

        self.slider_y_home.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_y_home,
                              scale=.1))
        self.spinbox_y_home.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_y_home,
                              scale=10))

        self.slider_z_home.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_z_home,
                              scale=.1))
        self.spinbox_z_home.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_z_home,
                              scale=10))

        self.slider_x_offset.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_x_offset,
                              scale=.1))
        self.spinbox_x_offset.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_x_offset,
                              scale=10))

        self.slider_y_offset.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_y_offset,
                              scale=.1))
        self.spinbox_y_offset.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_y_offset,
                              scale=10))

        self.slider_z_offset.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_z_offset,
                              scale=.1))
        self.spinbox_z_offset.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_z_offset,
                              scale=10))

        self.slider_pen_up.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_pen_up,
                              scale=.1))
        self.spinbox_pen_up.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_pen_up,
                              scale=10))

        self.slider_scale.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_scale,
                              scale=.1))
        self.spinbox_scale.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_scale,
                              scale=10))

        self.slider_resolution.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_resolution,
                              scale=.1))
        self.spinbox_resolution.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_resolution,
                              scale=10))

        self.slider_drawing_feedrate.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_drawing_feedrate,
                              scale=1))
        self.spinbox_drawing_feedrate.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_drawing_feedrate,
                              scale=1))

        self.slider_moving_feedrate.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.spinbox_moving_feedrate,
                              scale=1))
        self.spinbox_moving_feedrate.valueChanged.connect(
            functools.partial(self.slider_spinbox_related,
                              slave=self.slider_moving_feedrate,
                              scale=1))

        self.btn_generate_gcode.clicked.connect(
            functools.partial(self.generate_gcode, flag=True))

    def slider_spinbox_related(self, value, master=None, slave=None, scale=1):
        try:
            slave.setValue(value * scale)
        except Exception as e:
            print(e)

    def mouseReleaseEvent(self, event, source=None):
        try:
            self.generate_gcode()
        except Exception as e:
            print(e)
        source(event)

    def focusOutEvent(self, event, source=None):
        try:
            self.generate_gcode()
        except Exception as e:
            print(e)
        source(event)

    def generate_gcode(self, flag=False):
        if self.handler.template is None and flag:
            self.handler.svg_to_gcode()
        if self.handler.template:
            pen_up = self.spinbox_pen_up.value() if not self.isLaserMode else 0
            config = {
                'x_home': self.spinbox_x_home.value(),
                'y_home': self.spinbox_y_home.value(),
                'z_home': self.spinbox_z_home.value(),
                'z_offset': self.spinbox_z_offset.value(),
                'pen_up': pen_up,
                'z_offset_pen_up': self.spinbox_z_offset.value() + pen_up,
                'moving_feedrate': self.spinbox_moving_feedrate.value(),
                'drawing_feedrate': self.spinbox_drawing_feedrate.value(),
            }
            self.gcode = self.handler.template.format(**config)
            self.change_gcode()
            # self.textEdit.setText(self.gcode)

    def change_gcode(self):
        if self.gcode:
            x_offset = self.spinbox_x_offset.value()
            y_offset = self.spinbox_y_offset.value()
            z_offset = self.spinbox_z_offset.value()
            moving_feedrate = self.spinbox_moving_feedrate.value()
            drawing_feedrate = self.spinbox_drawing_feedrate.value()
            scale = self.spinbox_scale.value()

            lines = self.gcode.split('\n')
            for i, line in enumerate(lines):
                List = line.strip().split(' ')
                line = ''
                for l in List:
                    if l.startswith('F'):
                        if line.startswith(('G01', 'G1')):
                            l = 'F{}'.format(drawing_feedrate)
                        elif line.startswith(('G00', 'G0')):
                            l = 'F{}'.format(moving_feedrate)
                    elif l.startswith('X'):
                        x = float(l[1:]) * scale + x_offset
                        l = 'X{0:.2f}'.format(x)
                    elif l.startswith('Y'):
                        y = float(l[1:]) * scale + y_offset
                        l = 'Y{0:.2f}'.format(y)
                    # elif l.startswith('Z'):
                    #     z = float(l[1:]) + z_offset
                    #     l = 'Z{0:.2f}'.format(z)
                    line += l + ' '
                line = line.strip()
                lines[i] = line
            self.calc_gcode(lines)
            gcode = '\n'.join(lines)
            self.textEdit.setText(gcode)

    def calc_gcode(self, lines):
        x_list = []
        y_list = []
        for i, line in enumerate(lines):
            if line.startswith(tuple(['G0', 'G1', 'G00', 'G01'])):
                List = line.strip().split(' ')
                for l in List:
                    if l.startswith('X'):
                        x = float(l[1:])
                        x_list.append(x)
                    elif l.startswith('Y'):
                        y = float(l[1:])
                        y_list.append(y)
        if len(x_list) > 0:
            x_min = np.min(x_list)
            x_max = np.max(x_list)
            self.label_x_min.setText('X(min): ' + str(x_min))
            self.label_x_max.setText('X(max): ' + str(x_max))
            # print('x_min: {}, x_max: {}, x_distance: {}'.format(x_min, x_max, x_max - x_min))
        if len(y_list) > 0:
            y_min = np.min(y_list)
            y_max = np.max(y_list)
            self.label_y_min.setText('Y(min): ' + str(y_min))
            self.label_y_max.setText('Y(max): ' + str(y_max))
            # print('y_min: {}, y_max: {}, y_distance: {}'.format(y_min, y_max, y_max - y_min))

    def load_image(self):
        fname = QFileDialog.getOpenFileName(self.main_ui.window, 'Open file',
                                            '', '*.svg')
        if fname and fname[0]:
            img = QImage()
            if img.load(fname[0]):
                self.label_img.setPixmap(QPixmap.fromImage(img))
                with open(fname[0], 'rb') as f:
                    self.handler.source = f.read()
                    self.handler.template = None
                    self.gcode = None
                    self.up_frame.show()
예제 #17
0
파일: covers.py 프로젝트: zwpaper/calibre
    def __init__(self,
                 mi=None,
                 prefs=None,
                 parent=None,
                 for_global_prefs=False):
        QWidget.__init__(self, parent)
        self.ignore_changed = False
        self.for_global_prefs = for_global_prefs

        self.l = l = QHBoxLayout(self)
        l.setContentsMargins(0, 0, 0, 0)
        self.setLayout(l)
        self.settings_tabs = st = QTabWidget(self)
        l.addWidget(st)
        self.preview_label = la = Preview(self)
        l.addWidget(la)

        if prefs is None:
            prefs = cprefs
        self.original_prefs = prefs
        self.mi = mi or self.default_mi()

        self.colors_page = cp = QWidget(st)
        st.addTab(cp, _('&Colors'))
        cp.l = l = QGridLayout()
        cp.setLayout(l)
        if for_global_prefs:
            msg = _(
                'When generating covers, a color scheme for the cover is chosen at random from the'
                ' color schemes below. You can prevent an individual scheme from being selected by'
                ' unchecking it. The preview on the right shows the currently selected color scheme.'
            )
        else:
            msg = _(
                'Choose a color scheme to be used for this generated cover.'
            ) + '<p>' + _(
                'In normal cover generation, the color scheme is chosen at random from the list of color schemes below. You'
                ' can prevent an individual color scheme from being chosen by unchecking it here.'
            )
        cp.la = la = QLabel('<p>' + msg)
        la.setWordWrap(True)
        l.addWidget(la, 0, 0, 1, -1)
        self.colors_list = cl = QListWidget(cp)
        l.addWidget(cl, 1, 0, 1, -1)
        self.colors_map = OrderedDict()
        self.ncs = ncs = QPushButton(QIcon(I('plus.png')),
                                     _('&New color scheme'), cp)
        ncs.clicked.connect(self.create_color_scheme)
        l.addWidget(ncs)
        self.ecs = ecs = QPushButton(QIcon(I('format-fill-color.png')),
                                     _('&Edit color scheme'), cp)
        ecs.clicked.connect(self.edit_color_scheme)
        l.addWidget(ecs, l.rowCount() - 1, 1)
        self.rcs = rcs = QPushButton(QIcon(I('minus.png')),
                                     _('&Remove color scheme'), cp)
        rcs.clicked.connect(self.remove_color_scheme)
        l.addWidget(rcs, l.rowCount() - 1, 2)

        self.styles_page = sp = QWidget(st)
        st.addTab(sp, _('&Styles'))
        sp.l = l = QVBoxLayout()
        sp.setLayout(l)
        if for_global_prefs:
            msg = _(
                'When generating covers, a style for the cover is chosen at random from the'
                ' styles below. You can prevent an individual style from being selected by'
                ' unchecking it. The preview on the right shows the currently selected style.'
            )
        else:
            msg = _(
                'Choose a style to be used for this generated cover.'
            ) + '<p>' + _(
                'In normal cover generation, the style is chosen at random from the list of styles below. You'
                ' can prevent an individual style from being chosen by unchecking it here.'
            )
        sp.la = la = QLabel('<p>' + msg)
        la.setWordWrap(True)
        l.addWidget(la)
        self.styles_list = sl = QListWidget(sp)
        l.addWidget(sl)
        self.style_map = OrderedDict()

        self.font_page = fp = QWidget(st)
        st.addTab(fp, _('&Fonts and sizes'))
        fp.l = l = QFormLayout()
        fp.setLayout(l)
        fp.f = []

        def add_hline():
            f = QFrame()
            fp.f.append(f)
            f.setFrameShape(QFrame.Shape.HLine)
            l.addRow(f)

        for x, label, size_label in (
            ('title', _('&Title font family:'), _('&Title font size:')),
            ('subtitle', _('&Subtitle font family'),
             _('&Subtitle font size:')),
            ('footer', _('&Footer font family'), _('&Footer font size')),
        ):
            attr = '%s_font_family' % x
            ff = FontFamilyChooser(fp)
            setattr(self, attr, ff)
            l.addRow(label, ff)
            ff.family_changed.connect(self.emit_changed)
            attr = '%s_font_size' % x
            fs = QSpinBox(fp)
            setattr(self, attr, fs)
            fs.setMinimum(8), fs.setMaximum(200), fs.setSuffix(' px')
            fs.setValue(prefs[attr])
            fs.valueChanged.connect(self.emit_changed)
            l.addRow(size_label, fs)
            add_hline()
        self.changed_timer = t = QTimer(self)
        t.setSingleShot(True), t.setInterval(500), t.timeout.connect(
            self.emit_changed)

        def create_sz(label):
            ans = QSpinBox(self)
            ans.setSuffix(' px'), ans.setMinimum(100), ans.setMaximum(10000)
            l.addRow(label, ans)
            ans.valueChanged.connect(self.changed_timer.start)
            return ans

        self.cover_width = create_sz(_('Cover &width:'))
        self.cover_height = create_sz(_('Cover &height:'))
        fp.cla = la = QLabel(
            _('Note that the preview to the side is of fixed aspect ratio, so changing the cover'
              ' width above will not have any effect. If you change the height, you should also change the width nevertheless'
              ' as it will be used in actual cover generation.'))
        la.setWordWrap(True)
        l.addRow(la)

        self.templates_page = tp = QWidget(st)
        st.addTab(tp, _('&Text'))
        tp.l = l = QVBoxLayout()
        tp.setLayout(l)
        tp.la = la = QLabel(
            _('The text on the generated cover is taken from the metadata of the book.'
              ' This is controlled via templates. You can use the <b>, <i> and <br> tags'
              ' in the templates for bold, italic and line breaks, respectively. The'
              ' default templates use the title, series and authors. You can change them to use'
              ' whatever metadata you like.'))
        la.setWordWrap(True), la.setTextFormat(Qt.TextFormat.PlainText)
        l.addWidget(la)

        def create_template_widget(title, which, button):
            attr = which + '_template'
            heading = QLabel('<h2>' + title)
            setattr(tp, attr + '_heading', heading)
            l.addWidget(heading)
            la = QLabel()
            setattr(self, attr, la)
            l.addWidget(la), la.setTextFormat(
                Qt.TextFormat.PlainText), la.setStyleSheet(
                    'QLabel {font-family: monospace}')
            la.setWordWrap(True)
            b = QPushButton(button)
            b.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
            connect_lambda(b.clicked, self,
                           lambda self: self.change_template(which))
            setattr(self, attr + '_button', b)
            l.addWidget(b)
            if which != 'footer':
                f = QFrame(tp)
                setattr(tp, attr + '_sep',
                        f), f.setFrameShape(QFrame.Shape.HLine)
                l.addWidget(f)
            l.addSpacing(10)

        create_template_widget(_('The title template'), 'title',
                               _('Change the &title template'))
        create_template_widget(_('The sub-title template'), 'subtitle',
                               _('Change the &sub-title template'))
        create_template_widget(_('The footer template'), 'footer',
                               _('Change the &footer template'))
        l.addStretch(2)

        self.apply_prefs(prefs)
        self.changed.connect(self.update_preview)
        self.styles_list.itemSelectionChanged.connect(self.update_preview)
        self.colors_list.itemSelectionChanged.connect(self.update_preview)
        self.update_preview()
예제 #18
0
class TabRewards_gui(QWidget):
    def __init__(self, imgDir, *args, **kwargs):
        QWidget.__init__(self)
        self.imgDir = imgDir
        self.initRewardsForm()
        mainVertical = QVBoxLayout()
        mainVertical.addWidget(self.rewardsForm)
        buttonbox = QHBoxLayout()
        buttonbox.addStretch(1)
        buttonbox.addWidget(self.btn_Cancel)
        mainVertical.addLayout(buttonbox)
        self.setLayout(mainVertical)

    def initRewardsForm(self):
        self.rewardsForm = QGroupBox()
        self.rewardsForm.setTitle("Transfer UTXOs")
        layout = QFormLayout()
        layout.setContentsMargins(10, 10, 10, 10)
        layout.setSpacing(13)
        layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        ##--- ROW 1
        line1 = QHBoxLayout()
        line1.addWidget(QLabel("Account HW"))
        self.edt_hwAccount = QSpinBox()
        self.edt_hwAccount.setMaximum(9999)
        self.edt_hwAccount.setFixedWidth(50)
        self.edt_hwAccount.setToolTip(
            "account number of the hardware wallet.\nIf unsure put 0")
        self.edt_hwAccount.setValue(0)
        line1.addWidget(self.edt_hwAccount)
        line1.addWidget(QLabel("spath from"))
        self.edt_spathFrom = QSpinBox()
        self.edt_spathFrom.setMaximum(9999)
        self.edt_spathFrom.setFixedWidth(50)
        self.edt_spathFrom.setToolTip("starting address n.")
        self.edt_spathFrom.setValue(0)
        line1.addWidget(self.edt_spathFrom)
        line1.addWidget(QLabel("spath to"))
        self.edt_spathTo = QSpinBox()
        self.edt_spathTo.setMaximum(9999)
        self.edt_spathTo.setFixedWidth(50)
        self.edt_spathTo.setToolTip("ending address n.")
        self.edt_spathTo.setValue(10)
        line1.addWidget(self.edt_spathTo)
        line1.addWidget(QLabel("internal/external"))
        self.edt_internalExternal = QSpinBox()
        self.edt_internalExternal.setFixedWidth(50)
        self.edt_internalExternal.setToolTip("ending address n.")
        self.edt_internalExternal.setValue(0)
        self.edt_internalExternal.setMaximum(1)
        line1.addWidget(self.edt_internalExternal)
        line1.addStretch(1)
        self.btn_reload = QPushButton("Scan Ledger device")
        self.btn_reload.setToolTip("Reload data from ledger device")
        line1.addWidget(self.btn_reload)
        layout.addRow(line1)
        hBox = QHBoxLayout()
        self.addySelect = QComboBox()
        self.addySelect.setToolTip("Select Address")
        hBox.addWidget(self.addySelect)
        layout.addRow(hBox)
        ## --- ROW 2: UTXOs
        self.rewardsList = QVBoxLayout()
        self.rewardsList.statusLabel = QLabel(
            '<b style="color:red">Reload Rewards</b>')
        self.rewardsList.statusLabel.setVisible(True)
        self.rewardsList.addWidget(self.rewardsList.statusLabel)
        self.rewardsList.box = QTableWidget()
        self.rewardsList.box.setMinimumHeight(200)
        #self.rewardsList.box.setMaximumHeight(140)
        self.rewardsList.box.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.rewardsList.box.setSelectionMode(QAbstractItemView.MultiSelection)
        self.rewardsList.box.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.rewardsList.box.setShowGrid(True)
        self.rewardsList.box.setColumnCount(4)
        self.rewardsList.box.setRowCount(0)
        self.rewardsList.box.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.Stretch)
        self.rewardsList.box.verticalHeader().hide()
        item = QTableWidgetItem()
        item.setText("PIVs")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(0, item)
        item = QTableWidgetItem()
        item.setText("Confirmations")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(1, item)
        item = QTableWidgetItem()
        item.setText("TX Hash")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(2, item)
        item = QTableWidgetItem()
        item.setText("TX Output N")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(3, item)
        item = QTableWidgetItem()
        self.rewardsList.addWidget(self.rewardsList.box)
        layout.addRow(self.rewardsList)
        ##--- ROW 3
        hBox2 = QHBoxLayout()
        self.btn_selectAllRewards = QPushButton("Select All")
        self.btn_selectAllRewards.setToolTip("Select all available UTXOs")
        hBox2.addWidget(self.btn_selectAllRewards)
        self.btn_deselectAllRewards = QPushButton("Deselect All")
        self.btn_deselectAllRewards.setToolTip("Deselect current selection")
        hBox2.addWidget(self.btn_deselectAllRewards)
        hBox2.addWidget(QLabel("Selected UTXOs"))
        self.selectedRewardsLine = QLabel()
        self.selectedRewardsLine.setMinimumWidth(200)
        self.selectedRewardsLine.setStyleSheet("color: purple")
        self.selectedRewardsLine.setToolTip("PIVX to move away")
        hBox2.addWidget(self.selectedRewardsLine)
        hBox2.addStretch(1)
        self.swiftxCheck = QCheckBox()
        self.swiftxCheck.setToolTip(
            "check for SwiftX instant transaction (flat fee rate of 0.01 PIV)")
        hBox2.addWidget(QLabel("Use SwiftX"))
        hBox2.addWidget(self.swiftxCheck)
        layout.addRow(hBox2)
        ##--- ROW 4
        hBox3 = QHBoxLayout()
        self.destinationLine = QLineEdit()
        self.destinationLine.setToolTip("PIVX address to send PIV to")
        hBox3.addWidget(self.destinationLine)
        hBox3.addWidget(QLabel("Fee"))
        self.feeLine = QDoubleSpinBox()
        self.feeLine.setDecimals(8)
        self.feeLine.setPrefix("PIV  ")
        self.feeLine.setToolTip("Insert a small fee amount")
        self.feeLine.setFixedWidth(150)
        self.feeLine.setSingleStep(0.001)
        hBox3.addWidget(self.feeLine)
        self.btn_sendRewards = QPushButton("Send")
        hBox3.addWidget(self.btn_sendRewards)
        layout.addRow(QLabel("Destination Address"), hBox3)
        hBox4 = QHBoxLayout()
        hBox4.addStretch(1)
        self.loadingLine = QLabel(
            "<b style='color:red'>Preparing TX.</b> Completed: ")
        self.loadingLinePercent = QProgressBar()
        self.loadingLinePercent.setMaximumWidth(200)
        self.loadingLinePercent.setMaximumHeight(10)
        self.loadingLinePercent.setRange(0, 100)
        hBox4.addWidget(self.loadingLine)
        hBox4.addWidget(self.loadingLinePercent)
        self.loadingLine.hide()
        self.loadingLinePercent.hide()
        layout.addRow(hBox4)
        #--- Set Layout
        self.rewardsForm.setLayout(layout)
        #--- ROW 5
        self.btn_Cancel = QPushButton("Clear")

    def resetStatusLabel(self, message=None):
        if message is None:
            self.rewardsList.statusLabel.setText(
                '<em><b style="color:purple">Checking explorer...</b></em>')
        else:
            self.rewardsList.statusLabel.setText(message)
        self.rewardsList.statusLabel.setVisible(True)
예제 #19
0
class BulkSeries(BulkBase):

    def setup_ui(self, parent):
        self.make_widgets(parent, EditWithComplete)
        values = self.all_values = list(self.db.all_custom(num=self.col_id))
        values.sort(key=sort_key)
        self.main_widget.setSizeAdjustPolicy(self.main_widget.AdjustToMinimumContentsLengthWithIcon)
        self.main_widget.setMinimumContentsLength(25)
        self.widgets.append(QLabel('', parent))
        w = QWidget(parent)
        layout = QHBoxLayout(w)
        layout.setContentsMargins(0, 0, 0, 0)
        self.remove_series = QCheckBox(parent)
        self.remove_series.setText(_('Remove series'))
        layout.addWidget(self.remove_series)
        self.idx_widget = QCheckBox(parent)
        self.idx_widget.setText(_('Automatically number books'))
        layout.addWidget(self.idx_widget)
        self.force_number = QCheckBox(parent)
        self.force_number.setText(_('Force numbers to start with '))
        layout.addWidget(self.force_number)
        self.series_start_number = QSpinBox(parent)
        self.series_start_number.setMinimum(1)
        self.series_start_number.setMaximum(9999999)
        self.series_start_number.setProperty("value", 1)
        layout.addWidget(self.series_start_number)
        layout.addItem(QSpacerItem(20, 10, QSizePolicy.Expanding, QSizePolicy.Minimum))
        self.widgets.append(w)
        self.idx_widget.stateChanged.connect(self.check_changed_checkbox)
        self.force_number.stateChanged.connect(self.check_changed_checkbox)
        self.series_start_number.valueChanged.connect(self.check_changed_checkbox)
        self.remove_series.stateChanged.connect(self.check_changed_checkbox)
        self.ignore_change_signals = False

    def check_changed_checkbox(self):
        self.a_c_checkbox.setChecked(True)

    def initialize(self, book_id):
        self.idx_widget.setChecked(False)
        self.main_widget.set_separator(None)
        self.main_widget.update_items_cache(self.all_values)
        self.main_widget.setEditText('')
        self.a_c_checkbox.setChecked(False)

    def getter(self):
        n = unicode(self.main_widget.currentText()).strip()
        i = self.idx_widget.checkState()
        f = self.force_number.checkState()
        s = self.series_start_number.value()
        r = self.remove_series.checkState()
        return n, i, f, s, r

    def commit(self, book_ids, notify=False):
        if not self.a_c_checkbox.isChecked():
            return
        val, update_indices, force_start, at_value, clear = self.gui_val
        val = None if clear else self.normalize_ui_val(val)
        if clear or val != '':
            extras = []
            for book_id in book_ids:
                if clear:
                    extras.append(None)
                    continue
                if update_indices:
                    if force_start:
                        s_index = at_value
                        at_value += 1
                    elif tweaks['series_index_auto_increment'] != 'const':
                        s_index = self.db.get_next_cc_series_num_for(val, num=self.col_id)
                    else:
                        s_index = 1.0
                else:
                    s_index = self.db.get_custom_extra(book_id, num=self.col_id,
                                                       index_is_id=True)
                extras.append(s_index)
            self.db.set_custom_bulk(book_ids, val, extras=extras,
                                   num=self.col_id, notify=notify)
예제 #20
0
class LibraryCodesTab(QWidget):
    def __init__(self, mygui, myguidb, mymainprefs, myparam_dict, myuiexit,
                 mysavedialoggeometry):
        super(LibraryCodesTab, self).__init__()
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.gui = mygui
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.guidb = myguidb
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.lib_path = self.gui.library_view.model().db.library_path
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.mytabprefs = mymainprefs
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.param_dict = myparam_dict
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.ui_exit = myuiexit
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.save_dialog_geometry = mysavedialoggeometry
        #-----------------------------------------------------
        #-----------------------------------------------------
        font = QFont()
        font.setBold(False)
        font.setPointSize(10)
        #-----------------------------------------------------
        self.layout_top = QVBoxLayout()
        self.layout_top.setSpacing(0)
        self.layout_top.setAlignment(Qt.AlignLeft)
        self.setLayout(self.layout_top)
        #-----------------------------------------------------
        self.scroll_area_frame = QScrollArea()
        self.scroll_area_frame.setAlignment(Qt.AlignLeft)
        self.scroll_area_frame.setWidgetResizable(True)
        self.scroll_area_frame.ensureVisible(400, 400)

        self.layout_top.addWidget(
            self.scroll_area_frame
        )  # the scroll area is now the child of the parent of self.layout_top

        # NOTE: the self.scroll_area_frame.setWidget(self.scroll_widget) is at the end of the init() AFTER all children have been created and assigned to a layout...

        #-----------------------------------------------------
        self.scroll_widget = QWidget()
        self.layout_top.addWidget(
            self.scroll_widget
        )  # causes automatic reparenting of QWidget to the parent of self.layout_top, which is:  self .
        #-----------------------------------------------------
        self.layout_frame = QVBoxLayout()
        self.layout_frame.setSpacing(0)
        self.layout_frame.setAlignment(Qt.AlignLeft)

        self.scroll_widget.setLayout(
            self.layout_frame
        )  # causes automatic reparenting of any widget later added to self.layout_frame to the parent of self.layout_frame, which is:  QWidget .

        #-----------------------------------------------------
        self.lc_groupbox = QGroupBox('Settings:')
        self.lc_groupbox.setMaximumWidth(400)
        self.lc_groupbox.setToolTip(
            "<p style='white-space:wrap'>The settings that control 'Library Codes'.  Using only ISBN or ISSN or Author/Title, Library Codes for selected books will be derived using the Current Settings."
        )
        self.layout_frame.addWidget(self.lc_groupbox)

        self.lc_layout = QGridLayout()
        self.lc_groupbox.setLayout(self.lc_layout)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.spacing0 = QLabel()
        self.layout_frame.addWidget(self.spacing0)
        self.spacing0.setMaximumHeight(20)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.button_box = QDialogButtonBox()
        self.button_box.setOrientation(Qt.Horizontal)
        self.button_box.setCenterButtons(True)

        self.layout_frame.addWidget(self.button_box)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.push_button_save_only = QPushButton("Save")
        self.push_button_save_only.clicked.connect(self.save_settings)
        self.push_button_save_only.setDefault(True)
        self.push_button_save_only.setFont(font)
        self.push_button_save_only.setToolTip(
            "<p style='white-space:wrap'>Save all user settings.")
        self.button_box.addButton(self.push_button_save_only, 0)

        self.push_button_exit_only = QPushButton("Exit")
        self.push_button_exit_only.clicked.connect(self.exit_only)
        self.push_button_exit_only.setDefault(False)
        self.push_button_exit_only.setFont(font)
        self.push_button_exit_only.setToolTip(
            "<p style='white-space:wrap'>Exit immediately without saving anything."
        )
        self.button_box.addButton(self.push_button_exit_only, 0)
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------

        r = 4

        self.ddc_labelname = QLineEdit(self)
        self.ddc_labelname.setText(self.mytabprefs['DDC'])
        self.ddc_labelname.setFont(font)
        self.ddc_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for DDC.<br><br>See:  https://www.oclc.org/dewey/features/summaries.en.html"
        )
        self.ddc_labelname.setMaximumWidth(100)
        self.lc_layout.addWidget(self.ddc_labelname, r, 0)

        self.ddc_activate_checkbox = QCheckBox(
            "Activate 'Dewey Decimal Code' Classification?")
        self.ddc_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive DDC?")
        r = r + 1
        self.lc_layout.addWidget(self.ddc_activate_checkbox, r, 0)
        if prefs['DDC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.ddc_activate_checkbox.setChecked(True)
        else:
            self.ddc_activate_checkbox.setChecked(False)
        #-----------------------------------------------------
        self.spacing1 = QLabel()
        r = r + 1
        self.lc_layout.addWidget(self.spacing1, r, 0)
        self.spacing1.setMaximumHeight(10)
        #-----------------------------------------------------
        self.lcc_labelname = QLineEdit(self)
        self.lcc_labelname.setText(self.mytabprefs['LCC'])
        self.lcc_labelname.setFont(font)
        self.lcc_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for LCC.<br><br>See: http://www.loc.gov/catdir/cpso/lcco/ "
        )
        self.lcc_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.lcc_labelname, r, 0)

        self.lcc_activate_checkbox = QCheckBox(
            "Activate 'Library of Congress Code' Classification?")
        self.lcc_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive LCC?")
        r = r + 1
        self.lc_layout.addWidget(self.lcc_activate_checkbox, r, 0)
        if prefs['LCC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.lcc_activate_checkbox.setChecked(True)
        else:
            self.lcc_activate_checkbox.setChecked(False)
        #-----------------------------------------------------
        self.spacing2 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing2, r, 0)
        self.spacing2.setMaximumHeight(10)
        #-----------------------------------------------------

        self.fast_labelname = QLineEdit(self)
        self.fast_labelname.setText(self.mytabprefs['FAST'])
        self.fast_labelname.setFont(font)
        self.fast_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for FAST Tag Values. "
        )
        self.fast_labelname.setMinimumWidth(100)
        self.fast_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.fast_labelname, r, 0)

        self.fast_activate_checkbox = QCheckBox("Activate 'FAST' Tags?")
        self.fast_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive FAST Tags?\
                                                                                                                    <br><br>Text.  Behaves like Tags. Not Names.<br><br>"
        )
        r = r + 1
        self.lc_layout.addWidget(self.fast_activate_checkbox, r, 0)
        if prefs['FAST_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.fast_activate_checkbox.setChecked(True)
        else:
            self.fast_activate_checkbox.setChecked(False)

        #-----------------------------------------------------
        self.spacing6 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing6, r, 0)
        self.spacing6.setMaximumHeight(10)
        #-----------------------------------------------------

        self.oclc_labelname = QLineEdit(self)
        self.oclc_labelname.setText(self.mytabprefs['OCLC'])
        self.oclc_labelname.setFont(font)
        self.oclc_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for OCLC-OWI.<br><br>See: #http://classify.oclc.org/classify2/   "
        )
        self.oclc_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.oclc_labelname, r, 0)

        self.oclc_activate_checkbox = QCheckBox(
            "Activate 'Online Computer Library Center' Work ID Code?")
        self.oclc_activate_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to derive OCLC-OWI?")
        r = r + 1
        self.lc_layout.addWidget(self.oclc_activate_checkbox, r, 0)
        if self.mytabprefs['OCLC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.oclc_activate_checkbox.setChecked(True)
        else:
            self.oclc_activate_checkbox.setChecked(False)
        #-----------------------------------------------------
        self.spacing5 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing5, r, 0)
        self.spacing5.setMaximumHeight(10)
        #-----------------------------------------------------
        self.lc_author_details_labelname = QLineEdit(self)
        self.lc_author_details_labelname.setText(
            self.mytabprefs['EXTRA_AUTHOR_DETAILS'])
        self.lc_author_details_labelname.setFont(font)
        self.lc_author_details_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for 'LC Extra Author Details'.\
                                                                                                                              <br><br>Text.  Behaves like Tags. Not Names.<br><br>"
        )
        self.lc_author_details_labelname.setMaximumWidth(100)
        r = r + 4
        self.lc_layout.addWidget(self.lc_author_details_labelname, r, 0)

        self.lc_author_details_checkbox = QCheckBox(
            "Activate 'Library Codes Extra Author Details'?")
        self.lc_author_details_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to add (never delete or replace) any available Tag-like values to this Custom Column if they are associated with the OCLC-OWI Identifier?"
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_author_details_checkbox, r, 0)
        if self.mytabprefs['EXTRA_AUTHOR_DETAILS_IS_ACTIVE'] == unicode_type(
                S_TRUE):
            self.lc_author_details_checkbox.setChecked(True)
        else:
            self.lc_author_details_checkbox.setChecked(False)
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.spacing4 = QLabel()
        r = r + 1
        self.lc_layout.addWidget(self.spacing4, r, 0)
        self.spacing4.setMaximumHeight(10)
        #-----------------------------------------------------
        font.setBold(False)
        font.setPointSize(7)
        #-----------------------------------------------------
        self.push_button_autoadd_custom_columns = QPushButton(
            "Automatically Add Activated Custom Columns?")
        self.push_button_autoadd_custom_columns.clicked.connect(
            self.autoadd_custom_columns)
        self.push_button_autoadd_custom_columns.setDefault(False)
        self.push_button_autoadd_custom_columns.setFont(font)
        self.push_button_autoadd_custom_columns.setToolTip(
            "<p style='white-space:wrap'>Do you want to automatically add the Custom Columns selected above?<br><br>If you have any issues, please add them manually."
        )
        r = r + 4
        self.lc_layout.addWidget(self.push_button_autoadd_custom_columns, r, 0)
        self.push_button_autoadd_custom_columns.setMaximumWidth(250)
        #-----------------------------------------------------
        self.lc_custom_columns_generation_label = QLabel()
        r = r + 1
        self.lc_layout.addWidget(self.lc_custom_columns_generation_label, r, 0)
        self.lc_custom_columns_generation_label.setText(
            "                                                              ")
        self.lc_custom_columns_generation_label.setMaximumHeight(10)
        self.lc_custom_columns_generation_label.setFont(font)

        self.oclc_identifier_only_checkbox = QCheckBox(
            "Always Create OCLC-OWI as an 'Identifier' (à la ISBN)?")
        self.oclc_identifier_only_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want to update Calibre's Identifiers for an Identifier of 'OCLC-OWI',\
                                                                                                                                 regardless of whether you want its own Custom Column updated?\
                                                                                                                                <br><br>REQUIRED to derive DDC/LCC using Author/Title."
        )
        r = r + 2
        self.lc_layout.addWidget(self.oclc_identifier_only_checkbox, r, 0)
        if prefs['OCLC_IDENTIFIER'] == unicode_type(S_TRUE):
            self.oclc_identifier_only_checkbox.setChecked(True)
        else:
            self.oclc_identifier_only_checkbox.setChecked(False)

        #-----------------------------------------------------
        self.spacing3 = QLabel("")
        r = r + 1
        self.lc_layout.addWidget(self.spacing3, r, 0)
        self.spacing3.setMaximumHeight(10)
        #-----------------------------------------------------
        font.setBold(False)
        font.setPointSize(10)
        #-----------------------------------------------------
        self.lc_genre_labelname = QLineEdit(self)
        self.lc_genre_labelname.setText(self.mytabprefs['GENRE'])
        self.lc_genre_labelname.setFont(font)
        self.lc_genre_labelname.setToolTip(
            "<p style='white-space:wrap'>Custom Column Search/Lookup #name for 'Genre'.\
                                                                                                                              <br><br>Text.  Behaves like Tags.<br><br>"
        )
        self.lc_genre_labelname.setMaximumWidth(100)
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_labelname, r, 0)

        self.lc_checkbox_buttongroup = QButtonGroup()
        self.lc_checkbox_buttongroup.setExclusive(True)

        self.lc_genre_ddc_checkbox = QCheckBox(
            "Update 'Genre' using DDC-to-Genre Mappings?")
        self.lc_genre_ddc_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want LC to update 'Genre' using the DDC-to-Genre mapping in Table _lc_genre_mapping?"
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_ddc_checkbox, r, 0)

        self.lc_genre_lcc_checkbox = QCheckBox(
            "Update 'Genre' using LCC-to-Genre Mappings?")
        self.lc_genre_lcc_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do you want LC to update 'Genre' using the LCC-to-Genre mapping in Table _lc_genre_mapping?"
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_lcc_checkbox, r, 0)

        self.lc_genre_inactive_checkbox = QCheckBox(
            "Do not update 'Genre' at all")
        self.lc_genre_inactive_checkbox.setToolTip(
            "<p style='white-space:wrap'>Do no 'Genre' processing at all?")
        r = r + 1
        self.lc_layout.addWidget(self.lc_genre_inactive_checkbox, r, 0)

        self.lc_checkbox_buttongroup.addButton(self.lc_genre_ddc_checkbox)
        self.lc_checkbox_buttongroup.addButton(self.lc_genre_lcc_checkbox)
        self.lc_checkbox_buttongroup.addButton(self.lc_genre_inactive_checkbox)

        if self.mytabprefs['GENRE_DDC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.lc_genre_ddc_checkbox.setChecked(True)
        elif self.mytabprefs['GENRE_LCC_IS_ACTIVE'] == unicode_type(S_TRUE):
            self.lc_genre_lcc_checkbox.setChecked(True)
        elif self.mytabprefs['GENRE_IS_INACTIVE'] == unicode_type(S_TRUE):
            self.lc_genre_inactive_checkbox.setChecked(True)

        self.lc_exact_match_checkbox = QCheckBox(
            "DDC: Require an 'Exact Match', not a 'Best Match'?")
        self.lc_exact_match_checkbox.setToolTip(
            "<p style='white-space:wrap'>Check this checkbox if you want an exact DDC match to be required in Table _lc_genre_mapping.  Otherwise, a 'best match' will be used via progressive shortening from right to left, but not past any decimal point.  If there is no decimal point in a book's DDC, then no progressive shortening will be performed at all."
        )
        r = r + 1
        self.lc_layout.addWidget(self.lc_exact_match_checkbox, r, 0)

        if self.mytabprefs['GENRE_EXACT_MATCH'] == unicode_type(S_TRUE):
            self.lc_exact_match_checkbox.setChecked(True)

        self.spin_lcc = QSpinBox(self)
        self.spin_lcc.setMinimum(1)
        self.spin_lcc.setMaximum(50)
        self.spin_lcc.setProperty('value', prefs['GENRE_LCC_MATCH_LENGTH'])
        self.spin_lcc.setMaximumWidth(250)
        self.spin_lcc.setSuffix("    LCC: Maximum Length to Match")
        self.spin_lcc.setToolTip(
            "<p style='white-space:nowrap'>Maximum number of characters in the LCC that should be used to map to the 'Genre', starting from the left.  A maximum of 1 guarantees a (broad) match.\
                                                                                                   <br><br>LCCs are structured with either 1 or 2 beginning letters, so 2-character LCCs have special matching logic.\
                                                                                                   <br><br>Example:   Assume maximum = 2 for a LCC of 'Q1':  Q1 would be attempted.  If it failed, because the 2nd digit is a number, 'Q' would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 2 for a LCC of 'PN1969.C65':  PN would be attempted.  If it failed, nothing else would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 4 for a LCC of 'PN1969.C65':  PN19 would be attempted.  If it failed, nothing else would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 4 for a LCC of 'Q1':  Q1 would be attempted.  If it failed, because the 2nd digit is a number, 'Q' would be attempted.\
                                                                                                   <br><br>Example:   Assume maximum = 4 for a LCC of 'Q389':  Q389 would be attempted.  If it failed, nothing else would be attempted."
        )
        r = r + 2
        self.lc_layout.addWidget(self.spin_lcc, r, 0)

        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.scroll_widget.resize(self.sizeHint())
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.scroll_area_frame.setWidget(
            self.scroll_widget
        )  # now that all widgets have been created and assigned to a layout...
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.scroll_area_frame.resize(self.sizeHint())
        #-----------------------------------------------------
        #-----------------------------------------------------
        self.resize(self.sizeHint())

    #-----------------------------------------------------------------------------------------
    def validate(self):
        return True

    #-----------------------------------------------------------------------------------------
    def autoadd_custom_columns(self):
        number_active = self.save_settings()
        if number_active == 0:
            return error_dialog(
                self.gui,
                _('Automatically Add Custom Columns'),
                _('No Activated Library Codes Custom Columns Found.  Nothing to Add.'
                  ),
                show=True)
        self.cli_param_list = self.create_cli_parameters()
        is_valid, restart_required = self.create_new_lc_custom_columns(
            self.cli_param_list)
        if is_valid:
            if restart_required:
                self.lc_custom_columns_generation_label.setText(
                    "Addition of Custom Columns Complete.  Restart Calibre Now."
                )
                self.repaint()
                info_dialog(
                    self.gui, 'Automatically Add Custom Columns',
                    'All Selected Custom Customs Were Added If They Did Not Already Exist.  Please Restart Calibre now.'
                ).show()
            else:
                self.lc_custom_columns_generation_label.setText(
                    "Selected Custom Columns Already Exist.  Nothing Done.")
                self.repaint()
        else:
            self.lc_custom_columns_generation_label.setText(
                "Not Completed.  Please Restart Calibre, then Add Manually.")
            self.repaint()
            msg = "Fatal error experienced in adding new Custom Columns."
            error_dialog(self.gui,
                         _('Automatically Add Custom Columns'),
                         _(msg),
                         show=True)

    #-----------------------------------------------------------------------------------------
    def create_cli_parameters(self):

        try:
            del self.cli_param_list
        except:
            pass

        self.cli_param_list = []
        temp_list = []
        cc_taglike_list = []
        cc_fast_name = ""

        if self.mytabprefs['DDC_IS_ACTIVE'] == unicode_type(S_TRUE):
            cc = self.mytabprefs['DDC']
            if cc > '#':
                cc = cc.replace('#', "").strip()
                cc = unicode_type(cc)
                temp_list.append(cc)
            else:
                error_dialog(self.gui,
                             _('Automatically Add Custom Columns'),
                             _('Illogical DDC Settings.  Please Correct.'),
                             show=True)
                return self.cli_param_list

        if self.mytabprefs['LCC_IS_ACTIVE'] == unicode_type(S_TRUE):
            cc = self.mytabprefs['LCC']
            if cc > '#':
                cc = cc.replace('#', "").strip()
                cc = unicode_type(cc)
                temp_list.append(cc)
            else:
                error_dialog(self.gui,
                             _('Automatically Add Custom Columns'),
                             _('Illogical LCC Settings.  Please Correct.'),
                             show=True)
                return self.cli_param_list

        if self.mytabprefs['FAST_IS_ACTIVE'] == unicode_type(S_TRUE):
            cc = self.mytabprefs['FAST']
            if cc > '#':
                cc = cc.replace('#', "").strip()
                cc = unicode_type(cc)
                temp_list.append(cc)
                cc_taglike_list.append(cc)
                cc_fast_name = cc
            else:
                error_dialog(self.gui,
                             _('Automatically Add Custom Columns'),
                             _('Illogical FAST Settings.  Please Correct.'),
                             show=True)
                return self.cli_param_list

        if self.mytabprefs['OCLC_IS_ACTIVE'] == unicode_type(S_TRUE):
            cc = self.mytabprefs['OCLC']
            if cc > '#':
                cc = cc.replace('#', "").strip()
                cc = unicode_type(cc)
                temp_list.append(cc)
            else:
                error_dialog(self.gui,
                             _('Automatically Add Custom Columns'),
                             _('Illogical OCLC Settings.  Please Correct.'),
                             show=True)
                return self.cli_param_list

        if self.mytabprefs['EXTRA_AUTHOR_DETAILS_IS_ACTIVE'] == unicode_type(
                S_TRUE):
            cc = self.mytabprefs['EXTRA_AUTHOR_DETAILS']
            if cc > '#':
                cc = cc.replace('#', "").strip()
                cc = unicode_type(cc)
                temp_list.append(cc)
                cc_taglike_list.append(cc)
            else:
                error_dialog(
                    self.gui,
                    _('Automatically Add Custom Columns'),
                    _('Illogical LC Extra Author Details Settings.  Please Correct.'
                      ),
                    show=True)
                return self.cli_param_list
        else:
            pass

        if len(temp_list) == 0:
            del temp_list
            error_dialog(self.gui,
                         _('Automatically Add Custom Columns'),
                         _('Nothing to do.  Please Review Settings.'),
                         show=True)
            return self.cli_param_list

        cc_to_add_list = []

        # for each cc currently set to active, create a parameter...but only if the cc does NOT already exist...
        my_db, my_cursor, is_valid = self.apsw_connect_to_library()
        if not is_valid:
            error_dialog(self.gui,
                         _('Automatically Add Custom Columns'),
                         _('Database Connection Error.  Restart Calibre.'),
                         show=True)
            return

        self.lc_custom_columns_generation_label.setText(
            "...Adding Custom Columns...")
        self.repaint()

        mysql = "SELECT label,name FROM custom_columns"
        my_cursor.execute(mysql)
        tmp_rows = my_cursor.fetchall()
        if not tmp_rows:
            for cc in temp_list:
                cc_to_add_list.append(cc)
            #END FOR
        else:
            if len(tmp_rows) == 0:
                for cc in temp_list:
                    cc_to_add_list.append(cc)
                #END FOR
            else:
                for cc in temp_list:
                    label_already_exists = False
                    for row in tmp_rows:
                        label, name = row
                        if unicode_type(label) == unicode_type(cc):
                            label_already_exists = True
                            break
                        else:
                            continue
                    #END FOR
                    if not label_already_exists:
                        cc_to_add_list.append(cc)
                #END FOR
                del tmp_rows
                del temp_list

        if len(cc_to_add_list) == 0:
            return self.cli_param_list

        cc_to_add_list.sort()

        for label in cc_to_add_list:
            label = unicodedata.normalize('NFKD',
                                          label).encode('ascii', 'ignore')
            label = unicode_type(label)
            label = label.lower()
            name = label.upper()
            datatype = 'text'
            if label in cc_taglike_list:
                is_multiple = "--is-multiple"
                if label == cc_fast_name:
                    name = "FAST Tags"
                else:
                    name = '"LC Extra Author Details"'
                param = is_multiple + '|||' + label + '|||' + name + '|||' + datatype
            else:
                param = label + '|||' + name + '|||' + datatype
            param = param.replace("[LIBRARY]", self.lib_path)
            self.cli_param_list.append(param)
        #END FOR

        del cc_to_add_list

        return self.cli_param_list

    #-----------------------------------------------------------------------------------------
    #-----------------------------------------------------------------------------------------
    def apsw_connect_to_library(self):

        my_db = self.gui.library_view.model().db

        self.lib_path = my_db.library_path
        self.lib_path = self.lib_path.replace(os.sep, '/')
        if isbytestring(self.lib_path):
            self.lib_path = self.lib_path.decode(filesystem_encoding)

        path = my_db.library_path
        if isbytestring(path):
            path = path.decode(filesystem_encoding)
        path = path.replace(os.sep, '/')
        path = os.path.join(path, 'metadata.db')
        path = path.replace(os.sep, '/')

        if isbytestring(path):
            path = path.decode(filesystem_encoding)

        if path.endswith("/"):
            path = path[0:-1]

        if path.count("metadata.db") == 0:
            path = path + "/metadata.db"

        try:
            my_db = apsw.Connection(path)
            is_valid = True
        except Exception as e:
            if DEBUG: print("path to metadata.db is: ", path)
            if DEBUG: print("error: ", as_unicode(e))
            is_valid = False
            return None, None, is_valid

        my_cursor = my_db.cursor()

        mysql = "PRAGMA main.busy_timeout = 5000;"  #PRAGMA busy_timeout = milliseconds;
        my_cursor.execute(mysql)

        return my_db, my_cursor, is_valid

    #-----------------------------------------------------------------------------------------
    def exit_only(self):
        self.save_dialog_geometry()  #  inherited from SizePersistedDialog
        self.ui_exit()

    #-----------------------------------------------------------------------------------------
    def save_settings(self):

        self.save_dialog_geometry()  #  inherited from SizePersistedDialog

        self.mytabprefs['DDC'] = self.ddc_labelname.text()
        self.mytabprefs['LCC'] = self.lcc_labelname.text()
        self.mytabprefs['FAST'] = self.fast_labelname.text()
        self.mytabprefs['OCLC'] = self.oclc_labelname.text()

        self.mytabprefs['DDC_IS_ACTIVE'] = unicode_type(
            self.ddc_activate_checkbox.isChecked())
        self.mytabprefs['LCC_IS_ACTIVE'] = unicode_type(
            self.lcc_activate_checkbox.isChecked())
        self.mytabprefs['FAST_IS_ACTIVE'] = unicode_type(
            self.fast_activate_checkbox.isChecked())
        self.mytabprefs['OCLC_IS_ACTIVE'] = unicode_type(
            self.oclc_activate_checkbox.isChecked())
        self.mytabprefs['OCLC_IDENTIFIER'] = unicode_type(
            self.oclc_identifier_only_checkbox.isChecked())

        label = self.mytabprefs['DDC']
        label = unicode_type(label)
        label = unicodedata.normalize('NFKD', label).encode('ascii', 'ignore')
        label = label.lower().strip()
        if not label.startswith("#"):
            label = "#" + label
        if label == "#":
            label = ""
            self.ddc_activate_checkbox.setChecked(False)
        self.mytabprefs['DDC'] = unicode_type(label)

        label = self.mytabprefs['LCC']
        label = unicode_type(label)
        label = unicodedata.normalize('NFKD', label).encode('ascii', 'ignore')
        label = label.lower().strip()
        if not label.startswith("#"):
            label = "#" + label
        if label == "#":
            label = ""
            self.lcc_activate_checkbox.setChecked(False)
        self.mytabprefs['LCC'] = unicode_type(label)

        label = self.mytabprefs['FAST']
        label = unicode_type(label)
        label = unicodedata.normalize('NFKD', label).encode('ascii', 'ignore')
        label = label.lower().strip()
        if not label.startswith("#"):
            label = "#" + label
        if label == "#":
            label = ""
            self.fast_activate_checkbox.setChecked(False)
        self.mytabprefs['FAST'] = unicode_type(label)

        label = self.mytabprefs['OCLC']
        label = unicode_type(label)
        label = unicodedata.normalize('NFKD', label).encode('ascii', 'ignore')
        label = label.lower().strip()
        if not label.startswith("#"):
            label = "#" + label
        if label == "#":
            label = ""
            self.oclc_activate_checkbox.setChecked(False)
        self.mytabprefs['OCLC'] = unicode_type(label)

        if self.mytabprefs['DDC'] == unicode_type(
                "") and self.mytabprefs['LCC'] == unicode_type(
                    "") and self.mytabprefs['FAST'] == unicode_type(
                        "") and self.mytabprefs['OCLC'] == unicode_type(""):
            self.mytabprefs['DDC'] = unicode_type("#ddc")
            self.mytabprefs['LCC'] = unicode_type("#lcc")
            self.mytabprefs['FAST'] = unicode_type("#fast")
            self.mytabprefs['OCLC'] = unicode_type("#oclc_owi")
        else:
            if self.mytabprefs['DDC'] == unicode_type(
                    "") and self.mytabprefs['LCC'] == unicode_type(""):
                self.oclc_identifier_only_checkbox.setChecked(False)
        #---------------------------------------

        s = unicode_type(self.lc_genre_labelname.text())
        s = s.strip()
        if s.startswith("#") and len(s) > 1:
            self.mytabprefs['GENRE'] = unicode_type(s)
            self.mytabprefs['GENRE_DDC_IS_ACTIVE'] = unicode_type(
                self.lc_genre_ddc_checkbox.isChecked())
            self.mytabprefs['GENRE_LCC_IS_ACTIVE'] = unicode_type(
                self.lc_genre_lcc_checkbox.isChecked())
            self.mytabprefs['GENRE_IS_INACTIVE'] = unicode_type(
                self.lc_genre_inactive_checkbox.isChecked())
            self.mytabprefs['GENRE_EXACT_MATCH'] = unicode_type(
                self.lc_exact_match_checkbox.isChecked())
            self.mytabprefs['GENRE_LCC_MATCH_LENGTH'] = self.spin_lcc.value()
        else:
            self.mytabprefs['GENRE'] = unicode_type("#genre")
            self.lc_genre_labelname.setText(unicode_type("#genre"))
            self.lc_genre_ddc_checkbox.setChecked(False)
            self.lc_genre_lcc_checkbox.setChecked(False)
            self.lc_genre_inactive_checkbox.setChecked(True)
            self.mytabprefs['GENRE_DDC_IS_ACTIVE'] = unicode_type(S_FALSE)
            self.mytabprefs['GENRE_LCC_IS_ACTIVE'] = unicode_type(S_FALSE)
            self.mytabprefs['GENRE_IS_INACTIVE'] = unicode_type(S_TRUE)
            self.mytabprefs['GENRE_EXACT_MATCH'] = unicode_type(S_TRUE)
            self.mytabprefs['GENRE_LCC_MATCH_LENGTH'] = 2
            self.repaint()
            sleep(2)

        #---------------------------------------
        #~ for k,v in self.mytabprefs.iteritems():
        for k, v in iteritems(self.mytabprefs):
            v = unicode_type(v)
            v = v.strip()
            prefs[k] = v
        #END FOR
        prefs

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

        self.ddc_labelname.setText(self.mytabprefs['DDC'])
        self.lcc_labelname.setText(self.mytabprefs['LCC'])
        self.fast_labelname.setText(self.mytabprefs['FAST'])
        self.oclc_labelname.setText(self.mytabprefs['OCLC'])
        self.repaint()
        sleep(0)

        #~ for k,v in self.mytabprefs.iteritems():
        for k, v in iteritems(self.mytabprefs):
            self.param_dict[k] = v
        #END FOR

        number_active = 0

        if self.mytabprefs['DDC_IS_ACTIVE'] == unicode_type(S_TRUE):
            number_active = number_active + 1
        if self.mytabprefs['LCC_IS_ACTIVE'] == unicode_type(S_TRUE):
            number_active = number_active + 1
        if self.mytabprefs['FAST_IS_ACTIVE'] == unicode_type(S_TRUE):
            number_active = number_active + 1
        if self.mytabprefs['OCLC_IS_ACTIVE'] == unicode_type(S_TRUE):
            number_active = number_active + 1

        self.ddc_name = self.mytabprefs['DDC'].replace("#", "").strip()
        self.lcc_name = self.mytabprefs['LCC'].replace("#", "").strip()
        self.fast_name = self.mytabprefs['FAST'].replace("#", "").strip()
        self.oclc_name = self.mytabprefs['OCLC'].replace("#", "").strip()

        if self.oclc_identifier_only_checkbox.isChecked():
            self.oclc_identifier_is_desired = True
        else:
            self.oclc_identifier_is_desired = False

        return number_active

    #-----------------------------------------------------------------------------------------
    #-----------------------------------------------------------------------------------------
    def create_new_lc_custom_columns(self, execution_param_list):

        if len(self.cli_param_list) == 0:
            return True, False  # successful since the labels already exist; no restart is required.

        dbpath = self.lib_path

        was_successful = True
        restart_required = True

        for param in execution_param_list:
            try:
                lc_cli_add_custom_column(self.guidb, param, dbpath)
            except Exception as e:
                if DEBUG: print("Exception: ", as_unicode(e))
                was_successful = False
                break
        #END FOR

        return was_successful, restart_required

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


#END of library_codes_dialog.py