class SchemeSelector(QWidget): currentChanged = pyqtSignal() changed = pyqtSignal() def __init__(self, parent=None): super(SchemeSelector, self).__init__(parent) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.label = QLabel(_("Scheme:")) self.scheme = QComboBox() self.label.setBuddy(self.scheme) self.add = QPushButton(icons.get('list-add'), '') self.remove = QPushButton(icons.get('list-remove'), '') layout.addWidget(self.label) layout.addWidget(self.scheme) layout.addWidget(self.add) layout.addWidget(self.remove) self.scheme.currentIndexChanged.connect(self.slotSchemeChanged) self.add.clicked.connect(self.addClicked) self.remove.clicked.connect(self.removeClicked) app.translateUI(self) def translateUI(self): self.label.setText(_("Scheme:")) self.add.setText(_("New Scheme", "&New...")) self.remove.setText(_("&Remove")) def slotSchemeChanged(self, index): """Called when the Scheme combobox is changed by the user.""" self.remove.setEnabled(bool(index)) self.currentChanged.emit() self.changed.emit() def schemes(self): """Returns the list with internal names of currently available schemes.""" return self._schemes def currentScheme(self): """Returns the internal name of the currently selected scheme""" return self._schemes[self.scheme.currentIndex()] def removeClicked(self): index = self.scheme.currentIndex() if index == 0: return # default can not be removed self._schemesToRemove.add(self._schemes[index]) del self._schemes[index] del self._schemeNames[index] self.scheme.removeItem(index) def addClicked(self): name, ok = QInputDialog.getText(self, app.caption("Add Scheme"), _("Please enter a name for the new scheme:")) if not ok: return num, key = 1, 'user1' while key in self._schemes or key in self._schemesToRemove: num += 1 key = 'user{0}'.format(num) self._schemes.append(key) self._schemeNames.append(name) self.scheme.addItem(name) self.scheme.setCurrentIndex(self.scheme.count() - 1) def loadSettings(self, currentKey, namesGroup): # dont mark schemes for removal anymore self._schemesToRemove = set() s = QSettings() cur = s.value(currentKey, "default") # load the names for the shortcut schemes s.beginGroup(namesGroup) self._schemes = ["default"] self._schemeNames = [_("Default")] for key in s.childKeys(): self._schemes.append(key) self._schemeNames.append(s.value(key, key)) block = self.scheme.blockSignals(True) self.scheme.clear() self.scheme.addItems(self._schemeNames) # find out index index = self._schemes.index(cur) if cur in self._schemes else 0 self.remove.setEnabled(bool(index)) self.scheme.setCurrentIndex(index) self.scheme.blockSignals(block) self.currentChanged.emit() def saveSettings(self, currentKey, namesGroup, removePrefix=None): # first save new scheme names s = QSettings() s.beginGroup(namesGroup) for scheme, name in zip(self._schemes, self._schemeNames)[1:]: s.setValue(scheme, name) # then remove removed schemes for scheme in self._schemesToRemove: s.remove(scheme) s.endGroup() if removePrefix: for scheme in self._schemesToRemove: s.remove("{0}/{1}".format(removePrefix, scheme)) # then save current scheme = self.currentScheme() s.setValue(currentKey, scheme) # clean up self._schemesToRemove = set()
class ComboChoice(HelpedWidget): """ A combo box widget for choices. List of objects retrieved from model str(item) is used for presentation getValue and setValue uses the same object as from the list """ def __init__(self, model, combo_label="Choice", help_link=""): HelpedWidget.__init__(self, combo_label, help_link) assert model is not None and isinstance(model, ChoiceModelMixin) self.model = model model.observable().attach(ChoiceModelMixin.CURRENT_CHOICE_CHANGED_EVENT, self.getCurrentFromModel) model.observable().attach(ChoiceModelMixin.CHOICE_LIST_CHANGED_EVENT, self.updateChoicesFromModel) self.combo = QComboBox() self.combo.addItem("Fail!") self.addWidget(self.combo) self.addStretch() self.choice_list = None """ @type: list """ self.connect(self.combo, SIGNAL('currentIndexChanged(int)'), self.selectionChanged) self.updateChoicesFromModel() self.getCurrentFromModel() def selectionChanged(self, index): assert 0 <= index < len(self.choice_list), "Should not happen! Index out of range: 0 <= %i < %i" % (index, len(self.choice_list)) item = self.choice_list[index] self.model.setCurrentChoice(item) def getCurrentFromModel(self): new_value = self.model.getCurrentChoice() if self.choice_list is None: self.updateChoicesFromModel() if new_value in self.choice_list: index = self.choice_list.index(new_value) if not index == self.combo.currentIndex(): self.combo.setCurrentIndex(index) else: self.combo.setCurrentIndex(0) #sys.stderr.write("AssertionError: ComboBox can not be set to: " + str(new_value) + "\n") # raise AssertionError("ComboBox can not be set to: " + str(new_value)) def updateChoicesFromModel(self): block = self.combo.signalsBlocked() self.combo.blockSignals(True) self.choice_list = self.model.getChoices() self.combo.clear() for choice in self.choice_list: self.combo.addItem(str(choice)) self.combo.blockSignals(block)
class IndustrialDualAnalogInV2(COMCUPluginBase): def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletIndustrialDualAnalogInV2, *args) self.analog_in = self.device self.cbe_voltage0 = CallbackEmulator(functools.partial(self.analog_in.get_voltage, 0), functools.partial(self.cb_voltage, 0), self.increase_error_count) self.cbe_voltage1 = CallbackEmulator(functools.partial(self.analog_in.get_voltage, 1), functools.partial(self.cb_voltage, 1), self.increase_error_count) self.calibration = None self.sample_rate_label = QLabel('Sample Rate:') self.sample_rate_combo = QComboBox() self.sample_rate_combo.addItem('976 Hz') self.sample_rate_combo.addItem('488 Hz') self.sample_rate_combo.addItem('244 Hz') self.sample_rate_combo.addItem('122 Hz') self.sample_rate_combo.addItem('61 Hz') self.sample_rate_combo.addItem('4 Hz') self.sample_rate_combo.addItem('2 Hz') self.sample_rate_combo.addItem('1 Hz') self.current_voltage = [None, None] # float, V self.calibration_button = QPushButton('Calibration...') self.sample_rate_combo.currentIndexChanged.connect(self.sample_rate_combo_index_changed) self.calibration_button.clicked.connect(self.calibration_button_clicked) plots = [('Channel 0', Qt.red, lambda: self.current_voltage[0], format_voltage), ('Channel 1', Qt.blue, lambda: self.current_voltage[1], format_voltage)] self.plot_widget = PlotWidget('Voltage [V]', plots) # Define lines line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) line1 = QFrame() line1.setFrameShape(QFrame.HLine) line1.setFrameShadow(QFrame.Sunken) line2 = QFrame() line2.setFrameShape(QFrame.HLine) line2.setFrameShadow(QFrame.Sunken) # Define channel LED status config widgets self.led_config_ch0_label = QLabel('Channel 0') self.led_config_ch1_label = QLabel('Channel 1') self.led_config_label = QLabel('LED Config:') self.led_status_config_label = QLabel('LED Status Config:') self.led_status_config_ch0_min_label = QLabel('Min:') self.led_status_config_ch0_max_label = QLabel('Max:') self.led_status_config_ch1_min_label = QLabel('Min:') self.led_status_config_ch1_max_label = QLabel('Max:') self.led_config_ch0_combo = QComboBox() self.led_config_ch0_combo.addItem('Off') self.led_config_ch0_combo.addItem('On') self.led_config_ch0_combo.addItem('Show Heartbeat') self.led_config_ch0_combo.addItem('Show Channel Status') self.led_config_ch0_combo.currentIndexChanged.connect(self.led_config_ch0_combo_changed) self.led_config_ch1_combo = QComboBox() self.led_config_ch1_combo.addItem('Off') self.led_config_ch1_combo.addItem('On') self.led_config_ch1_combo.addItem('Show Heartbeat') self.led_config_ch1_combo.addItem('Show Channel Status') self.led_config_ch1_combo.currentIndexChanged.connect(self.led_config_ch1_combo_changed) self.led_status_config_ch0_combo = QComboBox() self.led_status_config_ch0_combo.addItem('Threshold') self.led_status_config_ch0_combo.addItem('Intensity') self.led_status_config_ch0_combo.currentIndexChanged.connect(self.led_status_config_ch0_combo_changed) self.led_status_config_ch1_combo = QComboBox() self.led_status_config_ch1_combo.addItem('Threshold') self.led_status_config_ch1_combo.addItem('Intensity') self.led_status_config_ch1_combo.currentIndexChanged.connect(self.led_status_config_ch1_combo_changed) self.led_status_config_ch0_min_sbox = QSpinBox() self.led_status_config_ch0_min_sbox.setMinimum(-35000) self.led_status_config_ch0_min_sbox.setMaximum(35000) self.led_status_config_ch0_min_sbox.setValue(0) self.led_status_config_ch0_min_sbox.setSingleStep(1) self.led_status_config_ch0_min_sbox.setSuffix(' mV') self.led_status_config_ch0_min_sbox.valueChanged.connect(self.led_status_config_ch0_min_sbox_changed) self.led_status_config_ch0_max_sbox = QSpinBox() self.led_status_config_ch0_max_sbox.setMinimum(-35000) self.led_status_config_ch0_max_sbox.setMaximum(35000) self.led_status_config_ch0_max_sbox.setValue(0) self.led_status_config_ch0_max_sbox.setSingleStep(1) self.led_status_config_ch0_max_sbox.setSuffix(' mV') self.led_status_config_ch0_max_sbox.valueChanged.connect(self.led_status_config_ch0_max_sbox_changed) self.led_status_config_ch1_min_sbox = QSpinBox() self.led_status_config_ch1_min_sbox.setMinimum(-35000) self.led_status_config_ch1_min_sbox.setMaximum(35000) self.led_status_config_ch1_min_sbox.setValue(0) self.led_status_config_ch1_min_sbox.setSingleStep(1) self.led_status_config_ch1_min_sbox.setSuffix(' mV') self.led_status_config_ch1_min_sbox.valueChanged.connect(self.led_status_config_ch1_min_sbox_changed) self.led_status_config_ch1_max_sbox = QSpinBox() self.led_status_config_ch1_max_sbox.setMinimum(-35000) self.led_status_config_ch1_max_sbox.setMaximum(35000) self.led_status_config_ch1_max_sbox.setValue(0) self.led_status_config_ch1_max_sbox.setSingleStep(1) self.led_status_config_ch1_max_sbox.setSuffix(' mV') self.led_status_config_ch1_max_sbox.valueChanged.connect(self.led_status_config_ch1_max_sbox_changed) # Define size policies h_sp = QSizePolicy() h_sp.setHorizontalPolicy(QSizePolicy.Expanding) # Set size policies self.sample_rate_combo.setSizePolicy(h_sp) self.led_config_ch0_combo.setSizePolicy(h_sp) self.led_config_ch1_combo.setSizePolicy(h_sp) self.led_status_config_ch0_combo.setSizePolicy(h_sp) self.led_status_config_ch1_combo.setSizePolicy(h_sp) self.led_status_config_ch0_min_sbox.setSizePolicy(h_sp) self.led_status_config_ch0_max_sbox.setSizePolicy(h_sp) self.led_status_config_ch1_min_sbox.setSizePolicy(h_sp) self.led_status_config_ch1_max_sbox.setSizePolicy(h_sp) # Define layouts hlayout = QHBoxLayout() vlayout = QVBoxLayout() glayout = QGridLayout() layout = QVBoxLayout(self) hlayout_ch0_min_max = QHBoxLayout() hlayout_ch1_min_max = QHBoxLayout() # Populate layouts vlayout.addWidget(self.calibration_button) hlayout.addWidget(self.sample_rate_label) hlayout.addWidget(self.sample_rate_combo) vlayout.addLayout(hlayout) vlayout.addWidget(line1) hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_min_label) hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_min_sbox) hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_max_label) hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_max_sbox) hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_min_label) hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_min_sbox) hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_max_label) hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_max_sbox) glayout.addWidget(self.led_config_ch0_label, 0, 1, 1, 1) # R, C, RS, CS glayout.addWidget(self.led_config_ch1_label, 0, 2, 1, 1) glayout.addWidget(line2, 1, 0, 1, 3) glayout.addWidget(self.led_config_label, 2, 0, 1, 1) glayout.addWidget(self.led_config_ch0_combo, 2, 1, 1, 1) glayout.addWidget(self.led_config_ch1_combo, 2, 2, 1, 1) glayout.addWidget(self.led_status_config_label, 3, 0, 1, 1) glayout.addWidget(self.led_status_config_ch0_combo, 3, 1, 1, 1) glayout.addWidget(self.led_status_config_ch1_combo, 3, 2, 1, 1) glayout.addLayout(hlayout_ch0_min_max, 4, 1, 1, 1) glayout.addLayout(hlayout_ch1_min_max, 4, 2, 1, 1) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(vlayout) layout.addLayout(glayout) self.ui_group_ch_status_ch0 = [self.led_status_config_ch0_combo, self.led_status_config_ch0_min_sbox, self.led_status_config_ch0_max_sbox] self.ui_group_ch_status_ch1 = [self.led_status_config_ch1_combo, self.led_status_config_ch1_min_sbox, self.led_status_config_ch1_max_sbox] def start(self): async_call(self.analog_in.get_voltage, 0, lambda x: self.cb_voltage(0, x), self.increase_error_count) async_call(self.analog_in.get_voltage, 1, lambda x: self.cb_voltage(1, x), self.increase_error_count) async_call(self.analog_in.get_sample_rate, None, self.get_sample_rate_async, self.increase_error_count) async_call(self.analog_in.get_channel_led_config, CH_0, lambda config: self.get_channel_led_config_async(CH_0, config), self.increase_error_count) async_call(self.analog_in.get_channel_led_status_config, CH_0, lambda config: self.get_channel_led_status_config_async(CH_0, config), self.increase_error_count) async_call(self.analog_in.get_channel_led_config, CH_1, lambda config: self.get_channel_led_config_async(CH_1, config), self.increase_error_count) async_call(self.analog_in.get_channel_led_status_config, CH_1, lambda config: self.get_channel_led_status_config_async(CH_1, config), self.increase_error_count) self.cbe_voltage0.set_period(100) self.cbe_voltage1.set_period(100) self.plot_widget.stop = False def stop(self): self.cbe_voltage0.set_period(0) self.cbe_voltage1.set_period(0) self.plot_widget.stop = True def destroy(self): if self.calibration != None: self.calibration.close() @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletIndustrialDualAnalogInV2.DEVICE_IDENTIFIER def calibration_button_clicked(self): if self.calibration == None: self.calibration = Calibration(self) self.calibration_button.setEnabled(False) self.calibration.show() def sample_rate_combo_index_changed(self, index): async_call(self.analog_in.set_sample_rate, index, None, self.increase_error_count) def led_config_ch0_combo_changed(self, index): if index != self.analog_in.CHANNEL_LED_CONFIG_SHOW_CHANNEL_STATUS: for e in self.ui_group_ch_status_ch0: e.setEnabled(False) else: for e in self.ui_group_ch_status_ch0: e.setEnabled(True) self.analog_in.set_channel_led_config(CH_0, index) def led_config_ch1_combo_changed(self, index): if index != self.analog_in.CHANNEL_LED_CONFIG_SHOW_CHANNEL_STATUS: for e in self.ui_group_ch_status_ch1: e.setEnabled(False) else: for e in self.ui_group_ch_status_ch1: e.setEnabled(True) self.analog_in.set_channel_led_config(CH_1, index) def led_status_config_ch0_combo_changed(self, index): self.analog_in.set_channel_led_status_config(CH_0, self.led_status_config_ch0_min_sbox.value(), self.led_status_config_ch0_max_sbox.value(), index) def led_status_config_ch1_combo_changed(self, index): self.analog_in.set_channel_led_status_config(CH_1, self.led_status_config_ch1_min_sbox.value(), self.led_status_config_ch1_max_sbox.value(), index) def led_status_config_ch0_min_sbox_changed(self, value): QObject.sender(self).blockSignals(True) self.analog_in.set_channel_led_status_config(CH_0, self.led_status_config_ch0_min_sbox.value(), self.led_status_config_ch0_max_sbox.value(), self.led_status_config_ch0_combo.currentIndex()) QObject.sender(self).blockSignals(False) def led_status_config_ch0_max_sbox_changed(self, value): QObject.sender(self).blockSignals(True) self.analog_in.set_channel_led_status_config(CH_0, self.led_status_config_ch0_min_sbox.value(), self.led_status_config_ch0_max_sbox.value(), self.led_status_config_ch0_combo.currentIndex()) QObject.sender(self).blockSignals(False) def led_status_config_ch1_min_sbox_changed(self, value): QObject.sender(self).blockSignals(True) self.analog_in.set_channel_led_status_config(CH_1, self.led_status_config_ch1_min_sbox.value(), self.led_status_config_ch1_max_sbox.value(), self.led_status_config_ch1_combo.currentIndex()) QObject.sender(self).blockSignals(False) def led_status_config_ch1_max_sbox_changed(self, value): QObject.sender(self).blockSignals(True) self.analog_in.set_channel_led_status_config(CH_1, self.led_status_config_ch1_min_sbox.value(), self.led_status_config_ch1_max_sbox.value(), self.led_status_config_ch1_combo.currentIndex()) QObject.sender(self).blockSignals(False) def get_voltage_value0(self): return self.voltage_value[0] def get_voltage_value1(self): return self.voltage_value[1] def get_sample_rate_async(self, rate): self.sample_rate_combo.blockSignals(True) self.sample_rate_combo.setCurrentIndex(rate) self.sample_rate_combo.blockSignals(False) def get_channel_led_config_async(self, channel, config): self.led_config_ch0_combo.blockSignals(True) self.led_config_ch1_combo.blockSignals(True) if channel == CH_0: self.led_config_ch0_combo.setCurrentIndex(config) elif channel == CH_1: self.led_config_ch1_combo.setCurrentIndex(config) self.led_config_ch0_combo.blockSignals(False) self.led_config_ch1_combo.blockSignals(False) def get_channel_led_status_config_async(self, channel, config): self.led_status_config_ch0_combo.blockSignals(True) self.led_status_config_ch1_combo.blockSignals(True) if channel == CH_0: self.led_status_config_ch0_combo.setCurrentIndex(config.config) self.led_status_config_ch0_max_sbox.setValue(config.max) self.led_status_config_ch0_min_sbox.setValue(config.min) elif channel == CH_1: self.led_status_config_ch1_combo.setCurrentIndex(config.config) self.led_status_config_ch1_max_sbox.setValue(config.max) self.led_status_config_ch1_min_sbox.setValue(config.min) self.led_status_config_ch0_combo.blockSignals(False) self.led_status_config_ch1_combo.blockSignals(False) def cb_voltage(self, sensor, voltage): self.current_voltage[sensor] = voltage / 1000.0
class ComboChoice(HelpedWidget): """ A combo box widget for choices. List of objects retrieved from model str(item) is used for presentation getValue and setValue uses the same object as from the list """ def __init__(self, model, combo_label="Choice", help_link=""): HelpedWidget.__init__(self, combo_label, help_link) assert model is not None and isinstance(model, ChoiceModelMixin) self.model = model model.observable().attach( ChoiceModelMixin.CURRENT_CHOICE_CHANGED_EVENT, self.getCurrentFromModel) model.observable().attach(ChoiceModelMixin.CHOICE_LIST_CHANGED_EVENT, self.updateChoicesFromModel) self.combo = QComboBox() self.combo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.combo.addItem("Fail!") self.addWidget(self.combo) self.addStretch() self.choice_list = None """ @type: list """ self.connect(self.combo, SIGNAL('currentIndexChanged(int)'), self.selectionChanged) self.updateChoicesFromModel() self.getCurrentFromModel() def selectionChanged(self, index): assert 0 <= index < len( self.choice_list ), "Should not happen! Index out of range: 0 <= %i < %i" % ( index, len(self.choice_list)) item = self.choice_list[index] self.model.setCurrentChoice(item) def getCurrentFromModel(self): new_value = self.model.getCurrentChoice() if self.choice_list is None: self.updateChoicesFromModel() if new_value in self.choice_list: index = self.choice_list.index(new_value) if not index == self.combo.currentIndex(): self.combo.setCurrentIndex(index) else: self.combo.setCurrentIndex(0) #sys.stderr.write("AssertionError: ComboBox can not be set to: " + str(new_value) + "\n") # raise AssertionError("ComboBox can not be set to: " + str(new_value)) def updateChoicesFromModel(self): block = self.combo.signalsBlocked() self.combo.blockSignals(True) self.choice_list = self.model.getChoices() self.combo.clear() for choice in self.choice_list: self.combo.addItem(str(choice)) self.combo.blockSignals(block) def cleanup(self): self.model.observable().detach( ChoiceModelMixin.CURRENT_CHOICE_CHANGED_EVENT, self.getCurrentFromModel) self.model.observable().detach( ChoiceModelMixin.CHOICE_LIST_CHANGED_EVENT, self.updateChoicesFromModel)
class XViewProfileManager(QWidget): currentProfileChanged = qt.Signal(qt.PyObject) optionsMenuRequested = qt.Signal(QPoint) def __init__( self, parent = None ): super(XViewProfileManager, self).__init__(parent) # define custom properties self._profiles = [] self._optionsMenuPolicy = Qt.DefaultContextMenu self._viewWidget = None # define the interface self._profileCombo = QComboBox(self) self._optionsButton = QToolButton(self) self._optionsButton.setAutoRaise(True) self._optionsButton.setToolTip('Advanced Options') self._optionsButton.setIcon(QIcon(resources.find('img/advanced.png'))) layout = QHBoxLayout() layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._profileCombo) layout.addWidget(self._optionsButton) self.setLayout(layout) # create connections self._profileCombo.currentIndexChanged.connect(self.handleProfileChange) self._optionsButton.clicked.connect(self.showOptionsMenu) def addProfile( self, profile ): """ Adds the inputed profile to the system. :param profile | <XViewProfile> """ if ( profile in self._profiles ): return self._profiles.append(profile) self._profileCombo.blockSignals(True) self._profileCombo.addItem(profile.name()) self._profileCombo.setCurrentIndex(self._profileCombo.count()-1) self._profileCombo.blockSignals(False) def currentProfile( self ): """ Returns the currently selected profile from the system. :return <XViewProfile> """ index = self._profileCombo.currentIndex() if ( 0 <= index and index < len(self._profiles) ): return self._profiles[index] return None def handleProfileChange( self ): """ Emits that the current profile has changed. """ # restore the profile settings prof = self.currentProfile() vwidget = self.viewWidget() if ( vwidget ): prof.restore(vwidget) if ( not self.signalsBlocked() ): self.currentProfileChanged.emit(self.currentProfile()) def optionsMenuPolicy( self ): """ Returns the option menu policy for this widget. :return <Qt.MenuPolicy> """ return self._optionsMenuPolicy def profiles( self ): """ Returns a list of all the profiles for this system. :return [<XViewProfile>, ..] """ return self._profiles def removeProfile( self, profile ): """ Adds the inputed profile to the system. :param profile | <XViewProfile> """ if ( not profile in self._profiles ): return index = self._profiles.index(profile) self._profiles.remove(profile) self._profileCombo.blockSignals(True) self._profileCombo.takeItem(index) self._profileCombo.blockSignals(False) def restoreSettings( self, settings ): """ Restores settings from the application. :param settings | <QSettings> """ settings.beginGroup(self.objectName()) curr_prof = None curr_name = qt.unwrapVariant(settings.value('current')) profiles = [] for prof_name in settings.childGroups(): settings.beginGroup(prof_name) prof_str = qt.unwrapVariant(settings.value('profile')) profile = XViewProfile.fromString(prof_str) profile.setName(prof_name) if ( prof_name == curr_name ): curr_prof = profile profiles.append(profile) settings.endGroup() self.blockSignals(True) self._profileCombo.blockSignals(True) self.setProfiles(profiles) if ( curr_prof ): self.setCurrentProfile(curr_prof) self._profileCombo.blockSignals(False) self.blockSignals(False) settings.endGroup() def saveSettings( self, settings ): """ Saves the settings for this widget to the application :param settings | <QSettings> """ settings.beginGroup(self.objectName()) curr_prof = self.currentProfile() if ( curr_prof ): settings.setValue('current', curr_prof.name()) for profile in self.profiles(): settings.beginGroup(profile.name()) settings.setValue('profile', qt.wrapVariant(profile.toString())) settings.endGroup() settings.endGroup() def setCurrentProfile( self, profile ): """ Sets the current profile to the inputed profile. :param profile | <XViewProfile> """ try: index = self._profiles.index(profile) except ValueError: index = -1 self._profileCombo.setCurrentIndex(index) def setOptionsMenuPolicy( self, menuPolicy ): """ Sets the options menu policy for this item. :param menuPolicy | <Qt.MenuPolicy> """ self._optionsMenuPolicy = menuPolicy def setProfiles( self, profiles ): """ Sets a list of profiles to be the options for the manager. :param profiles | [<XViewProfile>, ..] """ self.blockSignals(True) self._profileCombo.blockSignals(True) self._profiles = profiles[:] self._profileCombo.clear() self._profileCombo.addItems(map(lambda x: x.name(), profiles)) self._profileCombo.blockSignals(False) self.blockSignals(False) def setViewWidget( self, viewWidget ): """ Sets the view widget instance linked with this manager. :param viewWidget | <XViewWidget> """ self._viewWidget = viewWidget def showOptionsMenu( self ): """ Displays the options menu. If the option menu policy is set to CustomContextMenu, then the optionMenuRequested signal will be emitted, otherwise the default context menu will be displayed. """ point = QPoint(0, self._optionsButton.height()) global_point = self._optionsButton.mapToGlobal(point) # prompt the custom context menu if ( self.optionsMenuPolicy() == Qt.CustomContextMenu ): if ( not self.signalsBlocked() ): self.optionsMenuRequested.emit(global_point) return # use the default context menu menu = XViewProfileManagerMenu(self) menu.exec_(global_point) def viewWidget( self ): """ Returns the view widget that is associated with this manager. :return <XViewWidget> """ return self._viewWidget
class Thermocouple(PluginBase): qtcb_error_state = pyqtSignal(bool, bool) def __init__(self, *args): PluginBase.__init__(self, BrickletThermocouple, *args) self.thermo = self.device self.qtcb_error_state.connect(self.cb_error_state) self.thermo.register_callback(self.thermo.CALLBACK_ERROR_STATE, self.qtcb_error_state.emit) self.cbe_temperature = CallbackEmulator(self.thermo.get_temperature, self.cb_temperature, self.increase_error_count) self.current_temperature = None # float, °C self.error_label = QLabel('Current Errors: None') self.error_label.setAlignment(Qt.AlignVCenter | Qt.AlignRight) plots = [('Temperature', Qt.red, lambda: self.current_temperature, u'{:.2f} °C'.format)] self.plot_widget = PlotWidget(u'Temperature [°C]', plots, extra_key_widgets=[self.error_label]) self.averaging_label = QLabel('Averaging:') self.averaging_combo = QComboBox() self.averaging_combo.addItem('1', BrickletThermocouple.AVERAGING_1) self.averaging_combo.addItem('2', BrickletThermocouple.AVERAGING_2) self.averaging_combo.addItem('4', BrickletThermocouple.AVERAGING_4) self.averaging_combo.addItem('8', BrickletThermocouple.AVERAGING_8) self.averaging_combo.addItem('16', BrickletThermocouple.AVERAGING_16) self.type_label = QLabel('Thermocouple Type:') self.type_combo = QComboBox() self.type_combo.addItem('B', BrickletThermocouple.TYPE_B) self.type_combo.addItem('E', BrickletThermocouple.TYPE_E) self.type_combo.addItem('J', BrickletThermocouple.TYPE_J) self.type_combo.addItem('K', BrickletThermocouple.TYPE_K) self.type_combo.addItem('N', BrickletThermocouple.TYPE_N) self.type_combo.addItem('R', BrickletThermocouple.TYPE_R) self.type_combo.addItem('S', BrickletThermocouple.TYPE_S) self.type_combo.addItem('T', BrickletThermocouple.TYPE_T) self.type_combo.addItem('Gain 8', BrickletThermocouple.TYPE_G8) self.type_combo.addItem('Gain 32', BrickletThermocouple.TYPE_G32) self.filter_label = QLabel('Noise Rejection Filter:') self.filter_combo = QComboBox() self.filter_combo.addItem('50 Hz', BrickletThermocouple.FILTER_OPTION_50HZ) self.filter_combo.addItem('60 Hz', BrickletThermocouple.FILTER_OPTION_60HZ) hlayout = QHBoxLayout() hlayout.addWidget(self.averaging_label) hlayout.addWidget(self.averaging_combo) hlayout.addStretch() hlayout.addWidget(self.type_label) hlayout.addWidget(self.type_combo) hlayout.addStretch() hlayout.addWidget(self.filter_label) hlayout.addWidget(self.filter_combo) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(hlayout) self.averaging_combo.currentIndexChanged.connect( self.configuration_changed) self.type_combo.currentIndexChanged.connect(self.configuration_changed) self.filter_combo.currentIndexChanged.connect( self.configuration_changed) def start(self): async_call(self.thermo.get_temperature, None, self.cb_temperature, self.increase_error_count) async_call(self.thermo.get_configuration, None, self.cb_configuration, self.increase_error_count) async_call(self.thermo.get_error_state, None, lambda e: self.cb_error_state(e.over_under, e.open_circuit)) self.cbe_temperature.set_period(100) self.plot_widget.stop = False def stop(self): self.cbe_temperature.set_period(0) self.plot_widget.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletThermocouple.DEVICE_IDENTIFIER def get_current_value(self): return self.current_value def configuration_changed(self, _): conf_averaging = self.averaging_combo.itemData( self.averaging_combo.currentIndex()) conf_type = self.type_combo.itemData(self.type_combo.currentIndex()) conf_filter = self.filter_combo.itemData( self.filter_combo.currentIndex()) self.thermo.set_configuration(conf_averaging, conf_type, conf_filter) def cb_temperature(self, temperature): self.current_temperature = temperature / 100.0 def cb_configuration(self, conf): self.averaging_combo.blockSignals(True) self.averaging_combo.setCurrentIndex( self.averaging_combo.findData(conf.averaging)) self.averaging_combo.blockSignals(False) self.type_combo.blockSignals(True) self.type_combo.setCurrentIndex( self.type_combo.findData(conf.thermocouple_type)) self.type_combo.blockSignals(False) self.filter_combo.blockSignals(True) self.filter_combo.setCurrentIndex( self.filter_combo.findData(conf.filter)) self.filter_combo.blockSignals(False) def cb_error_state(self, over_under, open_circuit): if over_under or open_circuit: text = 'Current Errors: ' if over_under: text += 'Over/Under Voltage' if over_under and open_circuit: text += ' and ' if open_circuit: text += 'Open Circuit\n(defective thermocouple or nothing connected)' self.error_label.setStyleSheet('QLabel { color : red }') self.error_label.setText(text) else: self.error_label.setStyleSheet('') self.error_label.setText('Current Errors: None')
class Thermocouple(PluginBase): AVERAGING = [BrickletThermocouple.AVERAGING_1, BrickletThermocouple.AVERAGING_2, BrickletThermocouple.AVERAGING_4, BrickletThermocouple.AVERAGING_8, BrickletThermocouple.AVERAGING_16] THERMOCOUPLE_TYPE = [BrickletThermocouple.TYPE_B, BrickletThermocouple.TYPE_E, BrickletThermocouple.TYPE_J, BrickletThermocouple.TYPE_K, BrickletThermocouple.TYPE_N, BrickletThermocouple.TYPE_R, BrickletThermocouple.TYPE_S, BrickletThermocouple.TYPE_T, BrickletThermocouple.TYPE_G8, BrickletThermocouple.TYPE_G32] FILTER_TYPE = [BrickletThermocouple.FILTER_OPTION_50HZ, BrickletThermocouple.FILTER_OPTION_60HZ] qtcb_error_state = pyqtSignal(bool, bool) def __init__(self, *args): PluginBase.__init__(self, BrickletThermocouple, *args) self.thermo = self.device self.qtcb_error_state.connect(self.cb_error_state) self.thermo.register_callback(self.thermo.CALLBACK_ERROR_STATE, self.qtcb_error_state.emit) self.cbe_temperature = CallbackEmulator(self.thermo.get_temperature, self.cb_temperature, self.increase_error_count) self.temperature_label = TemperatureLabel() self.current_value = None plot_list = [['', Qt.red, self.get_current_value]] self.plot_widget = PlotWidget('Temperature [%cC]' % 0xB0, plot_list) self.averaging_label = QLabel('Averaging:') self.averaging_combo = QComboBox() self.averaging_combo.addItem('1 sample') self.averaging_combo.addItem('2 samples') self.averaging_combo.addItem('4 samples') self.averaging_combo.addItem('8 samples') self.averaging_combo.addItem('16 samples') self.type_label = QLabel('Thermocouple Type:') self.type_combo = QComboBox() self.type_combo.addItem('B') self.type_combo.addItem('E') self.type_combo.addItem('J') self.type_combo.addItem('K') self.type_combo.addItem('N') self.type_combo.addItem('R') self.type_combo.addItem('S') self.type_combo.addItem('T') self.type_combo.addItem('Gain 8') self.type_combo.addItem('Gain 32') self.filter_label = QLabel('Noise Rejection Filter:') self.filter_combo = QComboBox() self.filter_combo.addItem('50Hz') self.filter_combo.addItem('60Hz') line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.error_label = QLabel('Current errors: None') layout_conf = QHBoxLayout() layout_conf.addWidget(self.averaging_label) layout_conf.addWidget(self.averaging_combo) layout_conf.addStretch() layout_conf.addWidget(self.type_label) layout_conf.addWidget(self.type_combo) layout_conf.addStretch() layout_conf.addWidget(self.filter_label) layout_conf.addWidget(self.filter_combo) layout_error = QHBoxLayout() layout_error.addStretch() layout_error.addWidget(self.error_label) layout_error.addStretch() layout_h = QHBoxLayout() layout_h.addStretch() layout_h.addWidget(self.temperature_label) layout_h.addStretch() layout = QVBoxLayout(self) layout.addLayout(layout_h) layout.addWidget(self.plot_widget) layout.addLayout(layout_conf) layout.addWidget(line) layout.addLayout(layout_error) self.averaging_combo.currentIndexChanged.connect(self.configuration_changed) self.type_combo.currentIndexChanged.connect(self.configuration_changed) self.filter_combo.currentIndexChanged.connect(self.configuration_changed) def start(self): async_call(self.thermo.get_temperature, None, self.cb_temperature, self.increase_error_count) async_call(self.thermo.get_configuration, None, self.cb_configuration, self.increase_error_count) async_call(self.thermo.get_error_state, None, lambda e: self.cb_error_state(e.over_under, e.open_circuit)) self.cbe_temperature.set_period(100) self.plot_widget.stop = False def stop(self): self.cbe_temperature.set_period(0) self.plot_widget.stop = True def destroy(self): pass def get_url_part(self): return 'temperature' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletThermocouple.DEVICE_IDENTIFIER def get_current_value(self): return self.current_value def configuration_changed(self, _): conf_averaging = Thermocouple.AVERAGING[self.averaging_combo.currentIndex()] conf_type = Thermocouple.THERMOCOUPLE_TYPE[self.type_combo.currentIndex()] conf_filter = Thermocouple.FILTER_TYPE[self.filter_combo.currentIndex()] self.thermo.set_configuration(conf_averaging, conf_type, conf_filter) def cb_temperature(self, temperature): self.current_value = temperature/100.0 self.temperature_label.setText(str(temperature/100.0)) def cb_configuration(self, conf): self.averaging_combo.blockSignals(True) if conf.averaging == self.thermo.AVERAGING_1: self.averaging_combo.setCurrentIndex(0) elif conf.averaging == self.thermo.AVERAGING_2: self.averaging_combo.setCurrentIndex(1) elif conf.averaging == self.thermo.AVERAGING_4: self.averaging_combo.setCurrentIndex(2) elif conf.averaging == self.thermo.AVERAGING_8: self.averaging_combo.setCurrentIndex(3) elif conf.averaging == self.thermo.AVERAGING_16: self.averaging_combo.setCurrentIndex(4) self.averaging_combo.blockSignals(False) self.type_combo.blockSignals(True) if conf.thermocouple_type == self.thermo.TYPE_B: self.type_combo.setCurrentIndex(0) elif conf.thermocouple_type == self.thermo.TYPE_E: self.type_combo.setCurrentIndex(1) elif conf.thermocouple_type == self.thermo.TYPE_J: self.type_combo.setCurrentIndex(2) elif conf.thermocouple_type == self.thermo.TYPE_K: self.type_combo.setCurrentIndex(3) elif conf.thermocouple_type == self.thermo.TYPE_N: self.type_combo.setCurrentIndex(4) elif conf.thermocouple_type == self.thermo.TYPE_R: self.type_combo.setCurrentIndex(5) elif conf.thermocouple_type == self.thermo.TYPE_S: self.type_combo.setCurrentIndex(6) elif conf.thermocouple_type == self.thermo.TYPE_T: self.type_combo.setCurrentIndex(7) elif conf.thermocouple_type == self.thermo.TYPE_G8: self.type_combo.setCurrentIndex(8) elif conf.thermocouple_type == self.thermo.TYPE_G32: self.type_combo.setCurrentIndex(9) self.type_combo.blockSignals(False) self.filter_combo.blockSignals(True) if conf.filter == self.thermo.FILTER_OPTION_50HZ: self.filter_combo.setCurrentIndex(0) elif conf.filter == self.thermo.FILTER_OPTION_60HZ: self.filter_combo.setCurrentIndex(1) self.filter_combo.blockSignals(False) def cb_error_state(self, over_under, open_circuit): if over_under or open_circuit: text = 'Current errors: ' if over_under: text += 'Over/Under Voltage' if over_under and open_circuit: text += ' and ' if open_circuit: text += 'Open Circuit (defective thermocouple or nothing connected)' self.error_label.setStyleSheet('QLabel { color : red }') self.error_label.setText(text) else: self.error_label.setStyleSheet('') self.error_label.setText('Current errors: None')
class ScoringDialog(QWidget): """a dialog for entering the scores""" # pylint: disable=R0902 # pylint we need more than 10 instance attributes scoringClosed = pyqtSignal() def __init__(self, game): QWidget.__init__(self, None) self.game = None self.setWindowTitle(m18n('Scoring for this Hand') + ' - Kajongg') self.nameLabels = [None] * 4 self.spValues = [None] * 4 self.windLabels = [None] * 4 self.wonBoxes = [None] * 4 self.detailsLayout = [None] * 4 self.details = [None] * 4 self.__tilePixMaps = [] self.__meldPixMaps = [] grid = QGridLayout(self) pGrid = QGridLayout() grid.addLayout(pGrid, 0, 0, 2, 1) pGrid.addWidget(QLabel(m18nc('kajongg', "Player")), 0, 0) pGrid.addWidget(QLabel(m18nc('kajongg', "Wind")), 0, 1) pGrid.addWidget(QLabel(m18nc('kajongg', 'Score')), 0, 2) pGrid.addWidget(QLabel(m18n("Winner")), 0, 3) self.detailTabs = QTabWidget() self.detailTabs.setDocumentMode(True) pGrid.addWidget(self.detailTabs, 0, 4, 8, 1) for idx in range(4): self.setupUiForPlayer(pGrid, idx) self.draw = QCheckBox(m18nc('kajongg','Draw')) self.draw.clicked.connect(self.wonChanged) btnPenalties = QPushButton(m18n("&Penalties")) btnPenalties.clicked.connect(self.penalty) self.btnSave = QPushButton(m18n('&Save Hand')) self.btnSave.setEnabled(False) self.setupUILastTileMeld(pGrid) pGrid.setRowStretch(87, 10) pGrid.addWidget(self.draw, 7, 3) self.cbLastTile.currentIndexChanged.connect(self.slotLastTile) self.cbLastMeld.currentIndexChanged.connect(self.slotInputChanged) btnBox = QHBoxLayout() btnBox.addWidget(btnPenalties) btnBox.addWidget(self.btnSave) pGrid.addLayout(btnBox, 8, 4) StateSaver(self) self.refresh(game) def setupUILastTileMeld(self, pGrid): """setup UI elements for last tile and last meld""" self.lblLastTile = QLabel(m18n('&Last Tile:')) self.cbLastTile = QComboBox() self.cbLastTile.setMinimumContentsLength(1) vpol = QSizePolicy() vpol.setHorizontalPolicy(QSizePolicy.Fixed) self.cbLastTile.setSizePolicy(vpol) self.cbLastTile.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLengthWithIcon) self.lblLastTile.setBuddy(self.cbLastTile) self.lblLastMeld = QLabel(m18n('L&ast Meld:')) self.prevLastTile = None self.cbLastMeld = QComboBox() self.cbLastMeld.setMinimumContentsLength(1) self.cbLastMeld.setSizePolicy(vpol) self.cbLastMeld.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLengthWithIcon) self.lblLastMeld.setBuddy(self.cbLastMeld) self.comboTilePairs = set() pGrid.setRowStretch(6, 5) pGrid.addWidget(self.lblLastTile, 7, 0, 1, 2) pGrid.addWidget(self.cbLastTile, 7, 2, 1, 1) pGrid.addWidget(self.lblLastMeld, 8, 0, 1, 2) pGrid.addWidget(self.cbLastMeld, 8, 2, 1, 2) def setupUiForPlayer(self, pGrid, idx): """setup UI elements for a player""" self.spValues[idx] = QSpinBox() self.nameLabels[idx] = QLabel() self.nameLabels[idx].setBuddy(self.spValues[idx]) self.windLabels[idx] = WindLabel() pGrid.addWidget(self.nameLabels[idx], idx+2, 0) pGrid.addWidget(self.windLabels[idx], idx+2, 1) pGrid.addWidget(self.spValues[idx], idx+2, 2) self.wonBoxes[idx] = QCheckBox("") pGrid.addWidget(self.wonBoxes[idx], idx+2, 3) self.wonBoxes[idx].clicked.connect(self.wonChanged) self.spValues[idx].valueChanged.connect(self.slotInputChanged) detailTab = QWidget() self.detailTabs.addTab(detailTab,'') self.details[idx] = QWidget() detailTabLayout = QVBoxLayout(detailTab) detailTabLayout.addWidget(self.details[idx]) detailTabLayout.addStretch() self.detailsLayout[idx] = QVBoxLayout(self.details[idx]) def refresh(self, game): """reload game""" if game and not game.isScoringGame(): return self.game = game self.clear() self.setVisible(game is not None and not game.finished()) if game: for idx, player in enumerate(game.players): for child in self.details[idx].children(): if isinstance(child, RuleBox): child.hide() self.detailsLayout[idx].removeWidget(child) del child if game: self.spValues[idx].setRange(0, game.ruleset.limit or 99999) self.nameLabels[idx].setText(player.localName) self.windLabels[idx].wind = player.wind self.windLabels[idx].roundsFinished = game.roundsFinished self.detailTabs.setTabText(idx, player.localName) player.manualRuleBoxes = [RuleBox(x) for x in game.ruleset.allRules if x.hasSelectable] for ruleBox in player.manualRuleBoxes: self.detailsLayout[idx].addWidget(ruleBox) ruleBox.clicked.connect(self.slotInputChanged) player.refreshManualRules() def show(self): """only now compute content""" if self.game and not self.game.finished(): self.slotInputChanged() QWidget.show(self) def penalty(self): """penalty button clicked""" dlg = PenaltyDialog(self.game) dlg.exec_() def slotLastTile(self): """called when the last tile changes""" newLastTile = self.computeLastTile() if not newLastTile: return prevLower, newLower = self.prevLastTile.islower(), newLastTile.islower() if prevLower != newLower: # state of last tile (concealed/exposed) changed: # for all checked boxes check if they still are applicable winner = self.game.winner if winner: for box in winner.manualRuleBoxes: if box.isChecked(): box.setChecked(False) if winner.hand.manualRuleMayApply(box.rule): box.setChecked(True) self.prevLastTile = newLastTile self.fillLastMeldCombo() self.slotInputChanged() def computeLastTile(self): """returns the currently selected last tile""" idx = self.cbLastTile.currentIndex() if idx >= 0: return str(self.cbLastTile.itemData(idx).toString()) def closeEvent(self, event): """the user pressed ALT-F4""" self.hide() event.ignore() self.scoringClosed.emit() def clickedPlayerIdx(self, checkbox): """the player whose box has been clicked""" for idx in range(4): if checkbox == self.wonBoxes[idx]: return idx assert False def wonChanged(self): """if a new winner has been defined, uncheck any previous winner""" newWinner = None if self.sender() != self.draw: clicked = self.clickedPlayerIdx(self.sender()) if self.wonBoxes[clicked].isChecked(): newWinner = self.game.players[clicked] else: newWinner = None self.game.winner = newWinner for idx in range(4): if newWinner != self.game.players[idx]: self.wonBoxes[idx].setChecked(False) if newWinner: self.draw.setChecked(False) self.fillLastTileCombo() self.slotInputChanged() def updateManualRules(self): """enable/disable them""" # if an exclusive rule has been activated, deactivate it for # all other players if isinstance(self.sender(), RuleBox): ruleBox = self.sender() if ruleBox.isChecked() and ruleBox.rule.exclusive(): for idx, player in enumerate(self.game.players): if ruleBox.parentWidget() != self.details[idx]: for pBox in player.manualRuleBoxes: if pBox.rule.name == ruleBox.rule.name: pBox.setChecked(False) try: newState = bool(self.game.winner.handBoard.tiles) except AttributeError: newState = False self.lblLastTile.setEnabled(newState) self.cbLastTile.setEnabled(newState) self.lblLastMeld.setEnabled(newState) self.cbLastMeld.setEnabled(newState) if self.game: for player in self.game.players: player.refreshManualRules(self.sender()) def clear(self): """prepare for next hand""" if self.game: for idx, player in enumerate(self.game.players): self.spValues[idx].clear() self.spValues[idx].setValue(0) self.wonBoxes[idx].setChecked(False) player.payment = 0 player.invalidateHand() for box in self.wonBoxes: box.setVisible(False) self.draw.setChecked(False) self.updateManualRules() if self.game is None: self.hide() else: for idx, player in enumerate(self.game.players): self.windLabels[idx].setPixmap(WINDPIXMAPS[(player.wind, player.wind == WINDS[self.game.roundsFinished % 4])]) self.computeScores() self.spValues[0].setFocus() self.spValues[0].selectAll() def computeScores(self): """if tiles have been selected, compute their value""" # pylint: disable=R0912 # too many branches if not self.game: return if self.game.finished(): self.hide() return for idx, player in enumerate(self.game.players): self.spValues[idx].blockSignals(True) # we do not want that change to call computeScores again self.wonBoxes[idx].blockSignals(True) # we do not want that change to call computeScores again if player.handBoard and player.handBoard.tiles: self.spValues[idx].setEnabled(False) self.nameLabels[idx].setBuddy(self.wonBoxes[idx]) for loop in range(10): prevTotal = player.handTotal handContent = player.computeHand(asWinner=True) self.wonBoxes[idx].setVisible(handContent.won) if not self.wonBoxes[idx].isVisibleTo(self) and self.wonBoxes[idx].isChecked(): self.wonBoxes[idx].setChecked(False) self.game.winner = None elif prevTotal == player.handTotal: break player.refreshManualRules() self.spValues[idx].setValue(player.handTotal) else: if not self.spValues[idx].isEnabled(): self.spValues[idx].clear() self.spValues[idx].setValue(0) self.spValues[idx].setEnabled(True) self.nameLabels[idx].setBuddy(self.spValues[idx]) self.wonBoxes[idx].setVisible(player.handTotal >= self.game.ruleset.minMJTotal()) if not self.wonBoxes[idx].isVisibleTo(self) and self.wonBoxes[idx].isChecked(): self.wonBoxes[idx].setChecked(False) if not self.wonBoxes[idx].isVisibleTo(self) and player is self.game.winner: self.game.winner = None self.spValues[idx].blockSignals(False) self.wonBoxes[idx].blockSignals(False) if Internal.field.explainView: Internal.field.explainView.refresh(self.game) def __lastMeldContent(self): """prepare content for lastmeld combo""" lastTiles = set() winnerTiles = [] if self.game.winner and self.game.winner.handBoard: winnerTiles = self.game.winner.handBoard.tiles pairs = [] for meld in self.game.winner.hand.melds: if len(meld) < 4: pairs.extend(meld.pairs) for tile in winnerTiles: if tile.element in pairs and not tile.isBonus(): lastTiles.add(tile.element) return lastTiles, winnerTiles def __fillLastTileComboWith(self, lastTiles, winnerTiles): """fill last meld combo with prepared content""" self.comboTilePairs = lastTiles idx = self.cbLastTile.currentIndex() if idx < 0: idx = 0 indexedTile = str(self.cbLastTile.itemData(idx).toPyObject()) restoredIdx = None self.cbLastTile.clear() if not winnerTiles: return pmSize = winnerTiles[0].board.tileset.faceSize pmSize = QSize(pmSize.width() * 0.5, pmSize.height() * 0.5) self.cbLastTile.setIconSize(pmSize) QPixmapCache.clear() self.__tilePixMaps = [] shownTiles = set() for tile in winnerTiles: if tile.element in lastTiles and tile.element not in shownTiles: shownTiles.add(tile.element) self.cbLastTile.addItem(QIcon(tile.graphics.pixmapFromSvg(pmSize, withBorders=False)), '', QVariant(tile.element)) if indexedTile == tile.element: restoredIdx = self.cbLastTile.count() - 1 if not restoredIdx and indexedTile: # try again, maybe the tile changed between concealed and exposed indexedTile = indexedTile.lower() for idx in range(self.cbLastTile.count()): if indexedTile == str(self.cbLastTile.itemData(idx).toPyObject()).lower(): restoredIdx = idx break if not restoredIdx: restoredIdx = 0 self.cbLastTile.setCurrentIndex(restoredIdx) self.prevLastTile = self.computeLastTile() def clearLastTileCombo(self): """as the name says""" self.comboTilePairs = None self.cbLastTile.clear() def fillLastTileCombo(self): """fill the drop down list with all possible tiles. If the drop down had content before try to preserve the current index. Even if the tile changed state meanwhile.""" if self.game is None: return lastTiles, winnerTiles = self.__lastMeldContent() if self.comboTilePairs == lastTiles: return self.cbLastTile.blockSignals(True) # we only want to emit the changed signal once try: self.__fillLastTileComboWith(lastTiles, winnerTiles) finally: self.cbLastTile.blockSignals(False) self.cbLastTile.currentIndexChanged.emit(0) def __fillLastMeldComboWith(self, winnerMelds, indexedMeld, lastTile): """fill last meld combo with prepared content""" winner = self.game.winner faceWidth = winner.handBoard.tileset.faceSize.width() * 0.5 faceHeight = winner.handBoard.tileset.faceSize.height() * 0.5 restoredIdx = None for meld in winnerMelds: pixMap = QPixmap(faceWidth * len(meld), faceHeight) pixMap.fill(Qt.transparent) self.__meldPixMaps.append(pixMap) painter = QPainter(pixMap) for element in meld.pairs: painter.drawPixmap(0, 0, winner.handBoard.tilesByElement(element) \ [0].graphics.pixmapFromSvg(QSize(faceWidth, faceHeight), withBorders=False)) painter.translate(QPointF(faceWidth, 0.0)) self.cbLastMeld.addItem(QIcon(pixMap), '', QVariant(meld.joined)) if indexedMeld == meld.joined: restoredIdx = self.cbLastMeld.count() - 1 if not restoredIdx and indexedMeld: # try again, maybe the meld changed between concealed and exposed indexedMeld = indexedMeld.lower() for idx in range(self.cbLastMeld.count()): meldContent = str(self.cbLastMeld.itemData(idx).toPyObject()) if indexedMeld == meldContent.lower(): restoredIdx = idx if lastTile not in meldContent: if lastTile.lower() == lastTile: lastTile = lastTile.capitalize() else: lastTile = lastTile.lower() assert lastTile in meldContent self.cbLastTile.blockSignals(True) # we want to continue right here idx = self.cbLastTile.findData(QVariant(lastTile)) self.cbLastTile.setCurrentIndex(idx) self.cbLastTile.blockSignals(False) break if not restoredIdx: restoredIdx = 0 self.cbLastMeld.setCurrentIndex(restoredIdx) self.cbLastMeld.setIconSize(QSize(faceWidth * 3, faceHeight)) def fillLastMeldCombo(self): """fill the drop down list with all possible melds. If the drop down had content before try to preserve the current index. Even if the meld changed state meanwhile.""" self.cbLastMeld.blockSignals(True) # we only want to emit the changed signal once try: showCombo = False idx = self.cbLastMeld.currentIndex() if idx < 0: idx = 0 indexedMeld = str(self.cbLastMeld.itemData(idx).toPyObject()) self.cbLastMeld.clear() self.__meldPixMaps = [] if not self.game.winner: return if self.cbLastTile.count() == 0: return lastTile = Internal.field.computeLastTile() winnerMelds = [m for m in self.game.winner.hand.melds if len(m) < 4 \ and lastTile in m.pairs] assert len(winnerMelds) if len(winnerMelds) == 1: self.cbLastMeld.addItem(QIcon(), '', QVariant(winnerMelds[0].joined)) self.cbLastMeld.setCurrentIndex(0) return showCombo = True self.__fillLastMeldComboWith(winnerMelds, indexedMeld, lastTile) finally: self.lblLastMeld.setVisible(showCombo) self.cbLastMeld.setVisible(showCombo) self.cbLastMeld.blockSignals(False) self.cbLastMeld.currentIndexChanged.emit(0) def slotInputChanged(self): """some input fields changed: update""" for player in self.game.players: player.invalidateHand() self.updateManualRules() self.computeScores() self.validate() def validate(self): """update the status of the OK button""" game = self.game if game: valid = True if game.winner and game.winner.handTotal < game.ruleset.minMJTotal(): valid = False elif not game.winner and not self.draw.isChecked(): valid = False self.btnSave.setEnabled(valid)
class SchemeSelector(QWidget): currentChanged = pyqtSignal() changed = pyqtSignal() def __init__(self, parent=None): super(SchemeSelector, self).__init__(parent) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.label = QLabel() self.scheme = QComboBox() self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) layout.addWidget(self.label) layout.addWidget(self.scheme) layout.addWidget(self.menuButton) layout.addStretch(1) # action generator def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) icon and a.setIcon(icons.get(icon)) return a # add action a = self.addAction_ = act(self.slotAdd, 'list-add') menu.addAction(a) # remove action a = self.removeAction = act(self.slotRemove, 'list-remove') menu.addAction(a) # rename action a = self.renameAction = act(self.slotRename, 'document-edit') menu.addAction(a) menu.addSeparator() # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) self.scheme.currentIndexChanged.connect(self.slotSchemeChanged) app.translateUI(self) def translateUI(self): self.label.setText(_("Scheme:")) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.removeAction.setText(_("&Remove")) self.renameAction.setText(_("Re&name...")) self.importAction.setText(_("&Import...")) self.exportAction.setText(_("&Export...")) def slotSchemeChanged(self, index): """Called when the Scheme combobox is changed by the user.""" self.disableDefault(self.scheme.itemData(index) == 'default') self.currentChanged.emit() self.changed.emit() def disableDefault(self, val): self.removeAction.setDisabled(val) self.renameAction.setDisabled(val) def schemes(self): """Returns the list with internal names of currently available schemes.""" return [self.scheme.itemData(i) for i in range(self.scheme.count())] def currentScheme(self): """Returns the internal name of the currently selected scheme""" return self.scheme.itemData(self.scheme.currentIndex()) def insertSchemeItem(self, name, scheme): for i in range(1, self.scheme.count()): n = self.scheme.itemText(i) if n.lower() > name.lower(): self.scheme.insertItem(i, name, scheme) break else: self.scheme.addItem(name, scheme) def addScheme(self, name): num, key = 1, 'user1' while key in self.schemes() or key in self._schemesToRemove: num += 1 key = 'user{0}'.format(num) self.insertSchemeItem(name, key) self.scheme.setCurrentIndex(self.scheme.findData(key)) return key def slotAdd(self): name, ok = QInputDialog.getText( self, app.caption(_("Add Scheme")), _("Please enter a name for the new scheme:")) if ok: self.addScheme(name) def slotRemove(self): index = self.scheme.currentIndex() scheme = self.scheme.itemData(index) if scheme == 'default': return # default can not be removed self._schemesToRemove.add(scheme) self.scheme.removeItem(index) def slotRename(self): index = self.scheme.currentIndex() name = self.scheme.itemText(index) scheme = self.scheme.itemData(index) newName, ok = QInputDialog.getText(self, _("Rename"), _("New name:"), text=name) if ok: self.scheme.blockSignals(True) self.scheme.removeItem(index) self.insertSchemeItem(newName, scheme) self.scheme.setCurrentIndex(self.scheme.findData(scheme)) self.scheme.blockSignals(False) self.changed.emit() def slotImport(self): filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import color theme")) filename = QFileDialog.getOpenFileName(self, caption, QDir.homePath(), filetypes) if filename: self.parent().import_(filename) def slotExport(self): name = self.scheme.currentText() filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption( _("dialog title", "Export {name}").format(name=name)) path = os.path.join(QDir.homePath(), name + '.xml') filename = QFileDialog.getSaveFileName(self, caption, path, filetypes) if filename: if os.path.splitext(filename)[1] != '.xml': filename += '.xml' self.parent().export(name, filename) def loadSettings(self, currentKey, namesGroup): # don't mark schemes for removal anymore self._schemesToRemove = set() s = QSettings() cur = s.value(currentKey, "default", type("")) # load the names for the shortcut schemes s.beginGroup(namesGroup) block = self.scheme.blockSignals(True) self.scheme.clear() self.scheme.addItem(_("Default"), "default") lst = [(s.value(key, key, type("")), key) for key in s.childKeys()] for name, key in sorted(lst, key=lambda f: f[0].lower()): self.scheme.addItem(name, key) # find out index index = self.scheme.findData(cur) self.disableDefault(cur == 'default') self.scheme.setCurrentIndex(index) self.scheme.blockSignals(block) self.currentChanged.emit() def saveSettings(self, currentKey, namesGroup, removePrefix=None): # first save new scheme names s = QSettings() s.beginGroup(namesGroup) for i in range(self.scheme.count()): if self.scheme.itemData(i) != 'default': s.setValue(self.scheme.itemData(i), self.scheme.itemText(i)) for scheme in self._schemesToRemove: s.remove(scheme) s.endGroup() if removePrefix: for scheme in self._schemesToRemove: s.remove("{0}/{1}".format(removePrefix, scheme)) # then save current scheme = self.currentScheme() s.setValue(currentKey, scheme) # clean up self._schemesToRemove = set()
class Ui_WidgetReport(QWidget): def __init__(self, parent = None): ''' ''' super(Ui_WidgetReport, self).__init__() self.__parentWidget = parent self.helper = Ui_WidgetReportHelper(self) self.cosmos_cli = CosmosClient() #TODO: these should be in the app configuration tool webhdfs_url = 'http://130.206.80.46:14000/webhdfs/v1' auth_url = 'https://130.206.80.46:13000/cosmos-auth/v1' local_filepath = os.environ['HOME']+os.sep+'.fresh'+os.sep+'history' username = '******' password = '******' cosmos_user = '******' serv = 'NA' servpath = 'NA' #-------------------------- #Tuple(sensor_type, sensor_name) self.sensor_list = [#'sensor', 'sensor_1'), #('sensor', 'sensor_2'), #('sensor', 'sensor_3'), #('sensor', 'sensor_4'), #('sensor', 'sensor_5'), #('sensor', 'sensor_6'), #('sensor', 'sensor_7'), #('sensor', 'sensor_8'), ('sensor', 'sensor_9'), ('sensor', 'sensor_10')] self.entity_list = dict() self.cosmos_cli.username = username self.cosmos_cli.password = password self.cosmos_cli.webhdfs_url = webhdfs_url self.cosmos_cli.auth_url = auth_url self.cosmos_cli.hdfs_username = cosmos_user self.cosmos_cli.hdfs_filepath = '/'+serv+'_serv/'+servpath+'_servpath/' self.cosmos_cli.local_filepath = local_filepath self.rep_template = preppy.getModule('reportTemplate.prep') self.setupUi(self) #---------------------------------------------------------------------------- def setupUi(self, WidgetNetMang): #This view contains a stacked widget with two pages #1st page plots the graphic: layout_plot = QGridLayout() self.widget_page_plot = QWidget() self.widget_page_plot.setLayout(layout_plot) self.axis = DateAxis(orientation='bottom') self.widget_plot = pg.PlotWidget(axisItems={'bottom': self.axis}) self.combo_zone = QComboBox() for (_, sensor) in self.sensor_list: self.combo_zone.addItem(sensor) self.combo_sensor = QComboBox() self.button_refresh = QPushButton() self.button_refresh.setText('Refresh') self.button_report = QPushButton() self.button_report.setText('Report') #(QWidget, row, column, rowSpan, columnSpan) layout_plot.addWidget(self.widget_plot, 0, 0, 1, 5) layout_plot.addWidget(self.combo_zone, 1, 0, 1, 1) layout_plot.addWidget(self.combo_sensor, 1, 1, 1, 1) layout_plot.addWidget(self.button_report, 1, 3, 1, 1) layout_plot.addWidget(self.button_refresh, 1, 4, 1, 1) #2nd page shows the report form: label_requester_name = QLabel('Name:') label_requester_addr = QLabel('Address:') label_requester_mail = QLabel('Email:') self.edit_requester_name = QLineEdit() self.edit_requester_addr = QTextEdit() self.edit_requester_addr.setMaximumHeight(80) self.edit_requester_mail = QLineEdit() layout_requester = QGridLayout() layout_requester.addWidget(label_requester_name, 0, 0, 1, 1) layout_requester.addWidget(self.edit_requester_name, 0, 1, 4, 1) layout_requester.addWidget(label_requester_addr, 4, 0, 1, 1) layout_requester.addWidget(self.edit_requester_addr, 4, 1, 4, 1) layout_requester.addWidget(label_requester_mail, 8, 0, 1, 1) layout_requester.addWidget(self.edit_requester_mail, 8, 1, 4, 1) group_requester = QGroupBox('Requester') group_requester.setLayout(layout_requester) label_expert_name = QLabel('Name:') label_expert_addr = QLabel('Address:') label_expert_mail = QLabel('Email:') self.edit_expert_name = QLineEdit() self.edit_expert_addr = QTextEdit() self.edit_expert_addr.setMaximumHeight(80) self.edit_expert_mail = QLineEdit() layout_expert = QGridLayout() layout_expert.addWidget(label_expert_name, 0, 0, 1, 1) layout_expert.addWidget(self.edit_expert_name, 0, 1, 4, 1) layout_expert.addWidget(label_expert_addr, 4, 0, 1, 1) layout_expert.addWidget(self.edit_expert_addr, 4, 1, 4, 1) layout_expert.addWidget(label_expert_mail, 8, 0, 1, 1) layout_expert.addWidget(self.edit_expert_mail, 8, 1, 4, 1) group_expert = QGroupBox('Expert') group_expert.setLayout(layout_expert) self.edit_observations = QTextEdit() self.edit_observations.setMaximumHeight(80) layout_observations = QGridLayout() layout_observations.addWidget(self.edit_observations, 0, 0, 1, 1) group_observations = QGroupBox('Observations') group_observations.setLayout(layout_observations) self.label_plot = QLabel() self.label_plot.setFixedSize(700, 300) self.label_plot.setScaledContents(True) layout_group_plot = QGridLayout() layout_group_plot.addWidget(self.label_plot, 0, 0, 1, 1) group_plot = QGroupBox('Plot Preview') group_plot.setLayout(layout_group_plot) vertical_line = QFrame() vertical_line.setFrameShape(QFrame().VLine) vertical_line.setFrameShadow(QFrame().Sunken) layout_frame_form = QGridLayout() layout_frame_form.addWidget(group_requester, 0, 0, 1, 1) layout_frame_form.addWidget(vertical_line, 0, 1, 1, 1) layout_frame_form.addWidget(group_expert, 0, 2, 1, 1) layout_frame_form.addWidget(group_observations, 1, 0, 1, 3) layout_frame_form.addWidget(group_plot, 2, 0, 1, 3) frame_form = QFrame() frame_form.setLayout(layout_frame_form) scroll_area = QScrollArea() scroll_area.setWidget(frame_form) self.button_form_back = QPushButton() self.button_form_save = QPushButton() self.button_form_send = QPushButton() self.button_form_back.setText('Back') self.button_form_save.setText('Save') self.button_form_send.setText('Send') layout_form = QGridLayout() layout_form.addWidget(scroll_area, 0, 0, 1, 5) layout_form.addWidget(self.button_form_back, 1, 0, 1, 1) layout_form.addWidget(self.button_form_save, 1, 3, 1, 1) layout_form.addWidget(self.button_form_send, 1, 4, 1, 1) self.widget_page_form = QWidget() self.widget_page_form.setLayout(layout_form) self.widget_stacked = QStackedWidget(self) self.widget_stacked.addWidget(self.widget_page_plot) self.widget_stacked.addWidget(self.widget_page_form) layout_main = QGridLayout() layout_main.addWidget(self.widget_stacked) self.setLayout(layout_main) #--- self.combo_zone.currentIndexChanged['QString'].\ connect(self.handle_combo_zone_changed) self.combo_sensor.currentIndexChanged['QString'].\ connect(self.handle_combo_sensor_changed) self.button_refresh.clicked.\ connect(self.handle_button_refresh_clicked) self.button_report.clicked.\ connect(self.handle_button_report_clicked) self.button_form_back.clicked.\ connect(self.handle_button_form_back_clicked) self.button_form_save.clicked.\ connect(self.handle_button_form_save_clicked) self.button_form_send.clicked.\ connect(self.handle_button_form_send_clicked) #---------------------------------------------------------------------------- @pyqtSlot('QString') def handle_combo_zone_changed(self, text): if str(text) == '': return self.combo_sensor.blockSignals(True) self.combo_sensor.clear() for e in self.entity_list[str(text)]: self.combo_sensor.addItem(e) self.combo_sensor.setCurrentIndex(0) self.combo_sensor.blockSignals(False) self.combo_sensor.currentIndexChanged['QString'].emit(self.combo_sensor.currentText()) #---------------------------------------------------------------------------- @pyqtSlot('QString') def handle_combo_sensor_changed(self, text): if str(text) == '': return print str(text) dates = [] values = [] found = False for (s_type,s_name) in self.sensor_list: if s_name == str(self.combo_zone.currentText()): self.cosmos_cli.local_filename = s_name+'_'+s_type+'.txt' found = True break; if not found: return self.cosmos_cli.readHistoryFromFile() for s in self.cosmos_cli.history.split('\n'): try: j = json.loads(s) try: value = j[str(text)] date = j['recvTime'].split('.')[0] values.append(float(value)) print date print time.mktime(datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S").timetuple()) dates.append(time.mktime(datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S").timetuple())) #dates.append(date.split('T')[0]+'\n'+(date.split('T')[1]).split('.')[0]) except: pass except: pass self.widget_plot.clear() #xdates = dict(zip(range(len(dates)),dates)) #self.axis.set_dict(xdates) #self.widget_plot.plot(x=xdates.keys(), y=values, symbol='o') self.widget_plot.plot(x=dates, y=values, symbol='o') #---------------------------------------------------------------------------- @pyqtSlot() def handle_button_refresh_clicked(self): """get the files from cosmos and stores them locally""" self.entity_list.clear() for (s_type, s_name) in self.sensor_list: self.entity_list[s_name] = dict() self.cosmos_cli.hdfs_filename = s_name+'_'+s_type+'/'+s_name+'_'+s_type+'.txt' self.cosmos_cli.local_filename = s_name+'_'+s_type+'.txt' try: self.cosmos_cli.getFileContent() except NameError as e: print e return try: self.cosmos_cli.writeHistoryToFile() except NameError as e: print e return self.entity_list[s_name].clear() for s in self.cosmos_cli.history.split('\n'): try: for k in json.loads(s).keys(): if 'md' not in k and 'recv' not in k and 'RTC' not in k: self.entity_list[s_name][k] = '' except Exception as e: print e pass self.combo_zone.clear() self.combo_sensor.clear() for e in self.entity_list: self.combo_zone.addItem(e) "print self.entity_list[e]" #self.combo_sensor.clear() #for e in self.entity_list: # self.combo_sensor.addItem(e) print "refresh" #============================================================================ @pyqtSlot() def handle_button_report_clicked(self): try: exporter = pyqtgraph.exporters.ImageExporter(self.widget_plot.plotItem) exporter.export(self.cosmos_cli.local_filepath + '/plot.png') self.label_plot.setPixmap(QPixmap(self.cosmos_cli.local_filepath + '/plot.png')) except Exception as e: print e return self.widget_stacked.setCurrentIndex(1) #============================================================================ @pyqtSlot() def handle_button_form_back_clicked(self): self.widget_stacked.setCurrentIndex(0) #============================================================================ @pyqtSlot() def handle_button_form_save_clicked(self): rmlText = self.rep_template.get(str(self.combo_zone.currentText())+' - '+ str(self.combo_sensor.currentText()), datetime.datetime.now().strftime("%Y-%m-%d"), str(self.edit_requester_name.text()), str(self.edit_requester_addr.toPlainText()), '', str(self.edit_expert_name.text()), str(self.edit_expert_addr.toPlainText()), '', str(self.edit_observations.toPlainText()), self.cosmos_cli.local_filepath+'/plot.png') pdf = rml2pdf.parseString(rmlText) filename = QFileDialog().getSaveFileName() if str(filename == ''): return with open(str(filename), 'w+') as pdfFile: pdfFile.write(pdf.read()) #============================================================================ @pyqtSlot() def handle_button_form_send_clicked(self): rmlText = self.rep_template.get(str(self.combo_zone.currentText())+' - '+ str(self.combo_sensor.currentText()), datetime.datetime.now().strftime("%Y-%m-%d"), str(self.edit_requester_name.text()), str(self.edit_requester_addr.toPlainText()), str(self.edit_requester_mail.text()), str(self.edit_expert_name.text()), str(self.edit_expert_addr.toPlainText()), str(self.edit_expert_mail.text()), str(self.edit_observations.toPlainText()), self.cosmos_cli.local_filepath+'/plot.png') pdf = rml2pdf.parseString(rmlText) with open(self.cosmos_cli.local_filepath+'/rmlReport.pdf', 'w+') as pdfFile: pdfFile.write(pdf.read()) time.sleep(1) (password, ok) = QInputDialog().getText(self, 'password', 'password', mode=QLineEdit.Password) print str(self.edit_requester_mail.text()) print str(password) email_cli = EmailClient(username = str(self.edit_requester_mail.text()), password = str(password)) email_cli.sendEmail(from_addr=str(self.edit_requester_mail.text()), to_addr=str(self.edit_expert_mail.text()), mail_subject='[FRESH Expert Service] Request for Advice', mail_body=str(self.edit_observations.toPlainText()), attachment=self.cosmos_cli.local_filepath+'/rmlReport.pdf')
class Thermocouple(PluginBase): AVERAGING = [ BrickletThermocouple.AVERAGING_1, BrickletThermocouple.AVERAGING_2, BrickletThermocouple.AVERAGING_4, BrickletThermocouple.AVERAGING_8, BrickletThermocouple.AVERAGING_16 ] THERMOCOUPLE_TYPE = [ BrickletThermocouple.TYPE_B, BrickletThermocouple.TYPE_E, BrickletThermocouple.TYPE_J, BrickletThermocouple.TYPE_K, BrickletThermocouple.TYPE_N, BrickletThermocouple.TYPE_R, BrickletThermocouple.TYPE_S, BrickletThermocouple.TYPE_T, BrickletThermocouple.TYPE_G8, BrickletThermocouple.TYPE_G32 ] FILTER_TYPE = [ BrickletThermocouple.FILTER_OPTION_50HZ, BrickletThermocouple.FILTER_OPTION_60HZ ] qtcb_error_state = pyqtSignal(bool, bool) def __init__(self, *args): PluginBase.__init__(self, BrickletThermocouple, *args) self.thermo = self.device self.qtcb_error_state.connect(self.cb_error_state) self.thermo.register_callback(self.thermo.CALLBACK_ERROR_STATE, self.qtcb_error_state.emit) self.cbe_temperature = CallbackEmulator(self.thermo.get_temperature, self.cb_temperature, self.increase_error_count) self.temperature_label = TemperatureLabel() self.current_value = None plot_list = [['', Qt.red, self.get_current_value]] self.plot_widget = PlotWidget('Temperature [%cC]' % 0xB0, plot_list) self.averaging_label = QLabel('Averaging:') self.averaging_combo = QComboBox() self.averaging_combo.addItem('1 sample') self.averaging_combo.addItem('2 samples') self.averaging_combo.addItem('4 samples') self.averaging_combo.addItem('8 samples') self.averaging_combo.addItem('16 samples') self.type_label = QLabel('Thermocouple Type:') self.type_combo = QComboBox() self.type_combo.addItem('B') self.type_combo.addItem('E') self.type_combo.addItem('J') self.type_combo.addItem('K') self.type_combo.addItem('N') self.type_combo.addItem('R') self.type_combo.addItem('S') self.type_combo.addItem('T') self.type_combo.addItem('Gain 8') self.type_combo.addItem('Gain 32') self.filter_label = QLabel('Noise Rejection Filter:') self.filter_combo = QComboBox() self.filter_combo.addItem('50Hz') self.filter_combo.addItem('60Hz') line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.error_label = QLabel('Current errors: None') layout_conf = QHBoxLayout() layout_conf.addWidget(self.averaging_label) layout_conf.addWidget(self.averaging_combo) layout_conf.addStretch() layout_conf.addWidget(self.type_label) layout_conf.addWidget(self.type_combo) layout_conf.addStretch() layout_conf.addWidget(self.filter_label) layout_conf.addWidget(self.filter_combo) layout_error = QHBoxLayout() layout_error.addStretch() layout_error.addWidget(self.error_label) layout_error.addStretch() layout_h = QHBoxLayout() layout_h.addStretch() layout_h.addWidget(self.temperature_label) layout_h.addStretch() layout = QVBoxLayout(self) layout.addLayout(layout_h) layout.addWidget(self.plot_widget) layout.addLayout(layout_conf) layout.addWidget(line) layout.addLayout(layout_error) self.averaging_combo.currentIndexChanged.connect( self.configuration_changed) self.type_combo.currentIndexChanged.connect(self.configuration_changed) self.filter_combo.currentIndexChanged.connect( self.configuration_changed) def start(self): async_call(self.thermo.get_temperature, None, self.cb_temperature, self.increase_error_count) async_call(self.thermo.get_configuration, None, self.cb_configuration, self.increase_error_count) async_call(self.thermo.get_error_state, None, lambda e: self.cb_error_state(e.over_under, e.open_circuit)) self.cbe_temperature.set_period(100) self.plot_widget.stop = False def stop(self): self.cbe_temperature.set_period(0) self.plot_widget.stop = True def destroy(self): pass def get_url_part(self): return 'temperature' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletThermocouple.DEVICE_IDENTIFIER def get_current_value(self): return self.current_value def configuration_changed(self, _): conf_averaging = Thermocouple.AVERAGING[ self.averaging_combo.currentIndex()] conf_type = Thermocouple.THERMOCOUPLE_TYPE[ self.type_combo.currentIndex()] conf_filter = Thermocouple.FILTER_TYPE[ self.filter_combo.currentIndex()] self.thermo.set_configuration(conf_averaging, conf_type, conf_filter) def cb_temperature(self, temperature): self.current_value = temperature / 100.0 self.temperature_label.setText(str(temperature / 100.0)) def cb_configuration(self, conf): self.averaging_combo.blockSignals(True) if conf.averaging == self.thermo.AVERAGING_1: self.averaging_combo.setCurrentIndex(0) elif conf.averaging == self.thermo.AVERAGING_2: self.averaging_combo.setCurrentIndex(1) elif conf.averaging == self.thermo.AVERAGING_4: self.averaging_combo.setCurrentIndex(2) elif conf.averaging == self.thermo.AVERAGING_8: self.averaging_combo.setCurrentIndex(3) elif conf.averaging == self.thermo.AVERAGING_16: self.averaging_combo.setCurrentIndex(4) self.averaging_combo.blockSignals(False) self.type_combo.blockSignals(True) if conf.thermocouple_type == self.thermo.TYPE_B: self.type_combo.setCurrentIndex(0) elif conf.thermocouple_type == self.thermo.TYPE_E: self.type_combo.setCurrentIndex(1) elif conf.thermocouple_type == self.thermo.TYPE_J: self.type_combo.setCurrentIndex(2) elif conf.thermocouple_type == self.thermo.TYPE_K: self.type_combo.setCurrentIndex(3) elif conf.thermocouple_type == self.thermo.TYPE_N: self.type_combo.setCurrentIndex(4) elif conf.thermocouple_type == self.thermo.TYPE_R: self.type_combo.setCurrentIndex(5) elif conf.thermocouple_type == self.thermo.TYPE_S: self.type_combo.setCurrentIndex(6) elif conf.thermocouple_type == self.thermo.TYPE_T: self.type_combo.setCurrentIndex(7) elif conf.thermocouple_type == self.thermo.TYPE_G8: self.type_combo.setCurrentIndex(8) elif conf.thermocouple_type == self.thermo.TYPE_G32: self.type_combo.setCurrentIndex(9) self.type_combo.blockSignals(False) self.filter_combo.blockSignals(True) if conf.filter == self.thermo.FILTER_OPTION_50HZ: self.filter_combo.setCurrentIndex(0) elif conf.filter == self.thermo.FILTER_OPTION_60HZ: self.filter_combo.setCurrentIndex(1) self.filter_combo.blockSignals(False) def cb_error_state(self, over_under, open_circuit): if over_under or open_circuit: text = 'Current errors: ' if over_under: text += 'Over/Under Voltage' if over_under and open_circuit: text += ' and ' if open_circuit: text += 'Open Circuit (defective thermocouple or nothing connected)' self.error_label.setStyleSheet('QLabel { color : red }') self.error_label.setText(text) else: self.error_label.setStyleSheet('') self.error_label.setText('Current errors: None')
class XViewProfileManager(QWidget): currentProfileChanged = qt.Signal(qt.PyObject) optionsMenuRequested = qt.Signal(QPoint) def __init__(self, parent=None): super(XViewProfileManager, self).__init__(parent) # define custom properties self._profiles = [] self._optionsMenuPolicy = Qt.DefaultContextMenu self._viewWidget = None # define the interface self._profileCombo = QComboBox(self) self._optionsButton = QToolButton(self) self._optionsButton.setAutoRaise(True) self._optionsButton.setToolTip('Advanced Options') self._optionsButton.setIcon(QIcon(resources.find('img/advanced.png'))) layout = QHBoxLayout() layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._profileCombo) layout.addWidget(self._optionsButton) self.setLayout(layout) # create connections self._profileCombo.currentIndexChanged.connect( self.handleProfileChange) self._optionsButton.clicked.connect(self.showOptionsMenu) def addProfile(self, profile): """ Adds the inputed profile to the system. :param profile | <XViewProfile> """ if (profile in self._profiles): return self._profiles.append(profile) self._profileCombo.blockSignals(True) self._profileCombo.addItem(profile.name()) self._profileCombo.setCurrentIndex(self._profileCombo.count() - 1) self._profileCombo.blockSignals(False) def currentProfile(self): """ Returns the currently selected profile from the system. :return <XViewProfile> """ index = self._profileCombo.currentIndex() if (0 <= index and index < len(self._profiles)): return self._profiles[index] return None def handleProfileChange(self): """ Emits that the current profile has changed. """ # restore the profile settings prof = self.currentProfile() vwidget = self.viewWidget() if (vwidget): prof.restore(vwidget) if (not self.signalsBlocked()): self.currentProfileChanged.emit(self.currentProfile()) def optionsMenuPolicy(self): """ Returns the option menu policy for this widget. :return <Qt.MenuPolicy> """ return self._optionsMenuPolicy def profiles(self): """ Returns a list of all the profiles for this system. :return [<XViewProfile>, ..] """ return self._profiles def removeProfile(self, profile): """ Adds the inputed profile to the system. :param profile | <XViewProfile> """ if (not profile in self._profiles): return index = self._profiles.index(profile) self._profiles.remove(profile) self._profileCombo.blockSignals(True) self._profileCombo.takeItem(index) self._profileCombo.blockSignals(False) def restoreSettings(self, settings): """ Restores settings from the application. :param settings | <QSettings> """ settings.beginGroup(self.objectName()) curr_prof = None curr_name = qt.unwrapVariant(settings.value('current')) profiles = [] for prof_name in settings.childGroups(): settings.beginGroup(prof_name) prof_str = qt.unwrapVariant(settings.value('profile')) profile = XViewProfile.fromString(prof_str) profile.setName(prof_name) if (prof_name == curr_name): curr_prof = profile profiles.append(profile) settings.endGroup() self.blockSignals(True) self._profileCombo.blockSignals(True) self.setProfiles(profiles) if (curr_prof): self.setCurrentProfile(curr_prof) self._profileCombo.blockSignals(False) self.blockSignals(False) settings.endGroup() def saveSettings(self, settings): """ Saves the settings for this widget to the application :param settings | <QSettings> """ settings.beginGroup(self.objectName()) curr_prof = self.currentProfile() if (curr_prof): settings.setValue('current', curr_prof.name()) for profile in self.profiles(): settings.beginGroup(profile.name()) settings.setValue('profile', qt.wrapVariant(profile.toString())) settings.endGroup() settings.endGroup() def setCurrentProfile(self, profile): """ Sets the current profile to the inputed profile. :param profile | <XViewProfile> """ try: index = self._profiles.index(profile) except ValueError: index = -1 self._profileCombo.setCurrentIndex(index) def setOptionsMenuPolicy(self, menuPolicy): """ Sets the options menu policy for this item. :param menuPolicy | <Qt.MenuPolicy> """ self._optionsMenuPolicy = menuPolicy def setProfiles(self, profiles): """ Sets a list of profiles to be the options for the manager. :param profiles | [<XViewProfile>, ..] """ self.blockSignals(True) self._profileCombo.blockSignals(True) self._profiles = profiles[:] self._profileCombo.clear() self._profileCombo.addItems(map(lambda x: x.name(), profiles)) self._profileCombo.blockSignals(False) self.blockSignals(False) def setViewWidget(self, viewWidget): """ Sets the view widget instance linked with this manager. :param viewWidget | <XViewWidget> """ self._viewWidget = viewWidget def showOptionsMenu(self): """ Displays the options menu. If the option menu policy is set to CustomContextMenu, then the optionMenuRequested signal will be emitted, otherwise the default context menu will be displayed. """ point = QPoint(0, self._optionsButton.height()) global_point = self._optionsButton.mapToGlobal(point) # prompt the custom context menu if (self.optionsMenuPolicy() == Qt.CustomContextMenu): if (not self.signalsBlocked()): self.optionsMenuRequested.emit(global_point) return # use the default context menu menu = XViewProfileManagerMenu(self) menu.exec_(global_point) def viewWidget(self): """ Returns the view widget that is associated with this manager. :return <XViewWidget> """ return self._viewWidget
class Thermocouple(PluginBase): qtcb_error_state = pyqtSignal(bool, bool) def __init__(self, *args): PluginBase.__init__(self, BrickletThermocouple, *args) self.thermo = self.device self.qtcb_error_state.connect(self.cb_error_state) self.thermo.register_callback(self.thermo.CALLBACK_ERROR_STATE, self.qtcb_error_state.emit) self.cbe_temperature = CallbackEmulator(self.thermo.get_temperature, self.cb_temperature, self.increase_error_count) self.current_temperature = None # float, °C self.error_label = QLabel('Current Errors: None') self.error_label.setAlignment(Qt.AlignVCenter | Qt.AlignRight) plots = [('Temperature', Qt.red, lambda: self.current_temperature, u'{:.2f} °C'.format)] self.plot_widget = PlotWidget(u'Temperature [°C]', plots, extra_key_widgets=[self.error_label]) self.averaging_label = QLabel('Averaging:') self.averaging_combo = QComboBox() self.averaging_combo.addItem('1', BrickletThermocouple.AVERAGING_1) self.averaging_combo.addItem('2', BrickletThermocouple.AVERAGING_2) self.averaging_combo.addItem('4', BrickletThermocouple.AVERAGING_4) self.averaging_combo.addItem('8', BrickletThermocouple.AVERAGING_8) self.averaging_combo.addItem('16', BrickletThermocouple.AVERAGING_16) self.type_label = QLabel('Thermocouple Type:') self.type_combo = QComboBox() self.type_combo.addItem('B', BrickletThermocouple.TYPE_B) self.type_combo.addItem('E', BrickletThermocouple.TYPE_E) self.type_combo.addItem('J', BrickletThermocouple.TYPE_J) self.type_combo.addItem('K', BrickletThermocouple.TYPE_K) self.type_combo.addItem('N', BrickletThermocouple.TYPE_N) self.type_combo.addItem('R', BrickletThermocouple.TYPE_R) self.type_combo.addItem('S', BrickletThermocouple.TYPE_S) self.type_combo.addItem('T', BrickletThermocouple.TYPE_T) self.type_combo.addItem('Gain 8', BrickletThermocouple.TYPE_G8) self.type_combo.addItem('Gain 32', BrickletThermocouple.TYPE_G32) self.filter_label = QLabel('Noise Rejection Filter:') self.filter_combo = QComboBox() self.filter_combo.addItem('50 Hz', BrickletThermocouple.FILTER_OPTION_50HZ) self.filter_combo.addItem('60 Hz', BrickletThermocouple.FILTER_OPTION_60HZ) hlayout = QHBoxLayout() hlayout.addWidget(self.averaging_label) hlayout.addWidget(self.averaging_combo) hlayout.addStretch() hlayout.addWidget(self.type_label) hlayout.addWidget(self.type_combo) hlayout.addStretch() hlayout.addWidget(self.filter_label) hlayout.addWidget(self.filter_combo) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(hlayout) self.averaging_combo.currentIndexChanged.connect(self.configuration_changed) self.type_combo.currentIndexChanged.connect(self.configuration_changed) self.filter_combo.currentIndexChanged.connect(self.configuration_changed) def start(self): async_call(self.thermo.get_temperature, None, self.cb_temperature, self.increase_error_count) async_call(self.thermo.get_configuration, None, self.cb_configuration, self.increase_error_count) async_call(self.thermo.get_error_state, None, lambda e: self.cb_error_state(e.over_under, e.open_circuit)) self.cbe_temperature.set_period(100) self.plot_widget.stop = False def stop(self): self.cbe_temperature.set_period(0) self.plot_widget.stop = True def destroy(self): pass def get_url_part(self): return 'thermocouple' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletThermocouple.DEVICE_IDENTIFIER def get_current_value(self): return self.current_value def configuration_changed(self, _): conf_averaging = self.averaging_combo.itemData(self.averaging_combo.currentIndex()) conf_type = self.type_combo.itemData(self.type_combo.currentIndex()) conf_filter = self.filter_combo.itemData(self.filter_combo.currentIndex()) self.thermo.set_configuration(conf_averaging, conf_type, conf_filter) def cb_temperature(self, temperature): self.current_temperature = temperature / 100.0 def cb_configuration(self, conf): self.averaging_combo.blockSignals(True) self.averaging_combo.setCurrentIndex(self.averaging_combo.findData(conf.averaging)) self.averaging_combo.blockSignals(False) self.type_combo.blockSignals(True) self.type_combo.setCurrentIndex(self.type_combo.findData(conf.thermocouple_type)) self.type_combo.blockSignals(False) self.filter_combo.blockSignals(True) self.filter_combo.setCurrentIndex(self.filter_combo.findData(conf.filter)) self.filter_combo.blockSignals(False) def cb_error_state(self, over_under, open_circuit): if over_under or open_circuit: text = 'Current Errors: ' if over_under: text += 'Over/Under Voltage' if over_under and open_circuit: text += ' and ' if open_circuit: text += 'Open Circuit\n(defective thermocouple or nothing connected)' self.error_label.setStyleSheet('QLabel { color : red }') self.error_label.setText(text) else: self.error_label.setStyleSheet('') self.error_label.setText('Current Errors: None')
class PlotConfigPanel(QFrame): """A panel to interact with PlotConfig instances.""" plot_marker_styles = ["", ".", ",", "o", "*", "s", "+", "x", "p", "h", "H", "D", "d"] plot_line_styles = ["", "-", "--", "-.", ":"] def __init__(self, plot_config): QFrame.__init__(self) self.plot_config = plot_config self.connect(plot_config.signal_handler, SIGNAL('plotConfigChanged(PlotConfig)'), self._fetchValues) layout = QFormLayout() layout.setRowWrapPolicy(QFormLayout.WrapLongRows) self.chk_visible = QCheckBox() layout.addRow("Visible:", self.chk_visible) self.connect(self.chk_visible, SIGNAL('stateChanged(int)'), self._setVisibleState) self.plot_linestyle = QComboBox() self.plot_linestyle.addItems(self.plot_line_styles) self.connect(self.plot_linestyle, SIGNAL("currentIndexChanged(QString)"), self._setLineStyle) layout.addRow("Line style:", self.plot_linestyle) self.plot_marker_style = QComboBox() self.plot_marker_style.addItems(self.plot_marker_styles) self.connect(self.plot_marker_style, SIGNAL("currentIndexChanged(QString)"), self._setMarker) layout.addRow("Marker style:", self.plot_marker_style) self.alpha_spinner = QDoubleSpinBox(self) self.alpha_spinner.setMinimum(0.0) self.alpha_spinner.setMaximum(1.0) self.alpha_spinner.setDecimals(3) self.alpha_spinner.setSingleStep(0.01) self.connect(self.alpha_spinner, SIGNAL('valueChanged(double)'), self._setAlpha) layout.addRow("Blend factor:", self.alpha_spinner) self.color_picker = ColorPicker(plot_config) layout.addRow("Color:", self.color_picker) self.setLayout(layout) self._fetchValues(plot_config) def _fetchValues(self, plot_config): """Fetch values from a PlotConfig and insert into the panel.""" self.plot_config = plot_config #block signals to avoid updating the incoming plot_config state = self.plot_linestyle.blockSignals(True) linestyle_index = self.plot_line_styles.index(self.plot_config.linestyle) self.plot_linestyle.setCurrentIndex(linestyle_index) self.plot_linestyle.blockSignals(state) state = self.plot_marker_style.blockSignals(True) marker_index = self.plot_marker_styles.index(self.plot_config.marker) self.plot_marker_style.setCurrentIndex(marker_index) self.plot_marker_style.blockSignals(state) state = self.alpha_spinner.blockSignals(True) self.alpha_spinner.setValue(self.plot_config.alpha) self.alpha_spinner.blockSignals(state) state = self.chk_visible.blockSignals(True) self.chk_visible.setChecked(self.plot_config.is_visible) self.chk_visible.blockSignals(state) self.color_picker.update() #------------------------------------------- # update plot config from widgets #------------------------------------------- def _setLineStyle(self, linestyle): self.plot_config.linestyle = linestyle def _setMarker(self, marker): self.plot_config.marker = marker def _setAlpha(self, alpha): self.plot_config.alpha = alpha def _setVisibleState(self, state): self.plot_config.is_visible = state == 2
class SchemeSelector(QWidget): currentChanged = pyqtSignal() changed = pyqtSignal() def __init__(self, parent=None): super(SchemeSelector, self).__init__(parent) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.label = QLabel() self.scheme = QComboBox() self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) layout.addWidget(self.label) layout.addWidget(self.scheme) layout.addWidget(self.menuButton) layout.addStretch(1) # action generator def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) icon and a.setIcon(icons.get(icon)) return a # add action a = self.addAction_ = act(self.slotAdd, 'list-add') menu.addAction(a) # remove action a = self.removeAction = act(self.slotRemove, 'list-remove') menu.addAction(a) # rename action a = self.renameAction = act(self.slotRename, 'document-edit') menu.addAction(a) menu.addSeparator() # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) self.scheme.currentIndexChanged.connect(self.slotSchemeChanged) app.translateUI(self) def translateUI(self): self.label.setText(_("Scheme:")) self.menuButton.setText(_("&Menu")) self.addAction_.setText(_("&Add...")) self.removeAction.setText(_("&Remove")) self.renameAction.setText(_("Re&name...")) self.importAction.setText(_("&Import...")) self.exportAction.setText(_("&Export...")) def slotSchemeChanged(self, index): """Called when the Scheme combobox is changed by the user.""" self.disableDefault(self.scheme.itemData(index) == 'default') self.currentChanged.emit() self.changed.emit() def disableDefault(self, val): self.removeAction.setDisabled(val) self.renameAction.setDisabled(val) def schemes(self): """Returns the list with internal names of currently available schemes.""" return [self.scheme.itemData(i) for i in range(self.scheme.count())] def currentScheme(self): """Returns the internal name of the currently selected scheme""" return self.scheme.itemData(self.scheme.currentIndex()) def insertSchemeItem(self, name, scheme): for i in range(1, self.scheme.count()): n = self.scheme.itemText(i) if n.lower() > name.lower(): self.scheme.insertItem(i, name, scheme) break else: self.scheme.addItem(name, scheme) def addScheme(self, name): num, key = 1, 'user1' while key in self.schemes() or key in self._schemesToRemove: num += 1 key = 'user{0}'.format(num) self.insertSchemeItem(name, key) self.scheme.setCurrentIndex(self.scheme.findData(key)) return key def slotAdd(self): name, ok = QInputDialog.getText(self, app.caption(_("Add Scheme")), _("Please enter a name for the new scheme:")) if ok: self.addScheme(name) def slotRemove(self): index = self.scheme.currentIndex() scheme = self.scheme.itemData(index) if scheme == 'default': return # default can not be removed self._schemesToRemove.add(scheme) self.scheme.removeItem(index) def slotRename(self): index = self.scheme.currentIndex() name = self.scheme.itemText(index) scheme = self.scheme.itemData(index) newName, ok = QInputDialog.getText(self, _("Rename"), _("New name:"), text=name) if ok: self.scheme.blockSignals(True) self.scheme.removeItem(index) self.insertSchemeItem(newName, scheme) self.scheme.setCurrentIndex(self.scheme.findData(scheme)) self.scheme.blockSignals(False) self.changed.emit() def slotImport(self): filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Import color theme")) filename = QFileDialog.getOpenFileName(self, caption, os.environ['HOME'], filetypes) if filename: self.parent().import_(filename) def slotExport(self): name = self.scheme.currentText() filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files")) caption = app.caption(_("dialog title", "Export {name}").format(name=name)) path = os.path.join(os.environ['HOME'], name+'.xml') filename = QFileDialog.getSaveFileName(self, caption, path, filetypes) if filename: if os.path.splitext(filename)[1] != '.xml': filename += '.xml' self.parent().export(name, filename) def loadSettings(self, currentKey, namesGroup): # dont mark schemes for removal anymore self._schemesToRemove = set() s = QSettings() cur = s.value(currentKey, "default", type("")) # load the names for the shortcut schemes s.beginGroup(namesGroup) self.scheme.clear() self.scheme.addItem(_("Default"), "default") lst = [(s.value(key, key, type("")), key) for key in s.childKeys()] for name, key in sorted(lst, key=lambda f: f[0].lower()): self.scheme.addItem(name, key) block = self.scheme.blockSignals(True) # find out index index = self.scheme.findData(cur) self.disableDefault(cur == 'default') self.scheme.setCurrentIndex(index) self.scheme.blockSignals(block) self.currentChanged.emit() def saveSettings(self, currentKey, namesGroup, removePrefix=None): # first save new scheme names s = QSettings() s.beginGroup(namesGroup) for i in range(self.scheme.count()): if self.scheme.itemData(i) != 'default': s.setValue(self.scheme.itemData(i), self.scheme.itemText(i)) for scheme in self._schemesToRemove: s.remove(scheme) s.endGroup() if removePrefix: for scheme in self._schemesToRemove: s.remove("{0}/{1}".format(removePrefix, scheme)) # then save current scheme = self.currentScheme() s.setValue(currentKey, scheme) # clean up self._schemesToRemove = set()
class MotorizedLinearPoti(COMCUPluginBase): def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletMotorizedLinearPoti, *args) self.mp = self.device self.cbe_position = CallbackEmulator(self.mp.get_position, self.cb_position, self.increase_error_count) self.current_position = None self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, 100) self.slider.setMinimumWidth(200) self.slider.setEnabled(False) plots = [('Potentiometer Position', Qt.red, lambda: self.current_position, str)] self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider], curve_motion_granularity=40, update_interval=0.025) self.motor_slider = QSlider(Qt.Horizontal) self.motor_slider.setRange(0, 100) self.motor_slider.valueChanged.connect(self.motor_slider_value_changed) self.motor_hold_position = QCheckBox("Hold Position") self.motor_drive_mode = QComboBox() self.motor_drive_mode.addItem('Fast') self.motor_drive_mode.addItem('Smooth') def get_motor_slider_value(): return self.motor_slider.value() self.motor_hold_position.stateChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value())) self.motor_drive_mode.currentIndexChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value())) self.motor_position_label = MotorPositionLabel('Motor Target Position:') hlayout = QHBoxLayout() hlayout.addWidget(self.motor_position_label) hlayout.addWidget(self.motor_slider) hlayout.addWidget(self.motor_drive_mode) hlayout.addWidget(self.motor_hold_position) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(hlayout) def start(self): async_call(self.mp.get_position, None, self.cb_position, self.increase_error_count) async_call(self.mp.get_motor_position, None, self.cb_motor_position, self.increase_error_count) self.cbe_position.set_period(25) self.plot_widget.stop = False def stop(self): self.cbe_position.set_period(0) self.plot_widget.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletMotorizedLinearPoti.DEVICE_IDENTIFIER def cb_position(self, position): self.current_position = position self.slider.setValue(position) def cb_motor_position(self, motor): self.motor_slider.blockSignals(True) self.motor_hold_position.blockSignals(True) self.motor_drive_mode.blockSignals(True) self.motor_hold_position.setChecked(motor.hold_position) self.motor_drive_mode.setCurrentIndex(motor.drive_mode) self.motor_position_label.setText(str(motor.position)) self.motor_slider.setValue(motor.position) self.motor_slider.blockSignals(False) self.motor_hold_position.blockSignals(False) self.motor_drive_mode.blockSignals(False) def motor_slider_value_changed(self, position): self.motor_position_label.setText(str(position)) self.mp.set_motor_position(self.motor_slider.value(), self.motor_drive_mode.currentIndex(), self.motor_hold_position.isChecked())
class DistanceIRV2(COMCUPluginBase): NUM_VALUES = 512 DIVIDER = 2**12/NUM_VALUES def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletDistanceIRV2, *args) self.dist = self.device self.cbe_distance = CallbackEmulator(self.dist.get_distance, self.cb_distance, self.increase_error_count) self.cbe_analog_value = CallbackEmulator(self.dist.get_analog_value, self.cb_analog_value, self.increase_error_count) self.analog_label = AnalogLabel('Analog Value:') hlayout = QHBoxLayout() self.average_label = QLabel('Moving Average Length:') self.average_spin = QSpinBox() self.average_spin.setMinimum(1) self.average_spin.setMaximum(1000) self.average_spin.setSingleStep(1) self.average_spin.setValue(25) self.average_spin.editingFinished.connect(self.average_spin_finished) self.sensor_label = QLabel('Sensor Type:') self.sensor_combo = QComboBox() self.sensor_combo.addItem('2Y0A41 (4-30cm)') self.sensor_combo.addItem('2Y0A21 (10-80cm)') self.sensor_combo.addItem('2Y0A02 (20-150cm)') self.sensor_combo.currentIndexChanged.connect(self.sensor_combo_changed) hlayout.addWidget(self.average_label) hlayout.addWidget(self.average_spin) hlayout.addStretch() hlayout.addWidget(self.sensor_label) hlayout.addWidget(self.sensor_combo) self.current_distance = None # float, cm plots = [('Distance', Qt.red, lambda: self.current_distance, '{} cm'.format)] self.plot_widget = PlotWidget('Distance [cm]', plots, extra_key_widgets=[self.analog_label]) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout(self) layout.addWidget(self.plot_widget) layout.addWidget(line) layout.addLayout(hlayout) def sensor_combo_changed(self, index): self.dist.set_sensor_type(index) def average_spin_finished(self): self.dist.set_moving_average_configuration(self.average_spin.value()) def cb_moving_average_configuration(self, average): self.average_spin.blockSignals(True) self.average_spin.setValue(average) self.average_spin.blockSignals(False) def cb_sensor_type(self, sensor): self.sensor_combo.blockSignals(True) self.sensor_combo.setCurrentIndex(sensor) self.sensor_combo.blockSignals(False) def start(self): async_call(self.dist.get_moving_average_configuration, None, self.cb_moving_average_configuration, self.increase_error_count) async_call(self.dist.get_sensor_type, None, self.cb_sensor_type, self.increase_error_count) async_call(self.dist.get_distance, None, self.cb_distance, self.increase_error_count) self.cbe_distance.set_period(10) self.cbe_analog_value.set_period(100) self.plot_widget.stop = False def stop(self): self.cbe_distance.set_period(0) self.cbe_analog_value.set_period(0) self.plot_widget.stop = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletDistanceIRV2.DEVICE_IDENTIFIER def cb_distance(self, distance): self.current_distance = distance / 10.0 def cb_analog_value(self, analog_value): self.analog_label.setText(analog_value)