예제 #1
0
    def setup_ui(self):
        loader = QUiLoader()
        file = QFile('./media/main_window.ui')
        file.open(QFile.ReadOnly)
        self._window = loader.load(file)
        file.close()

        self.set_title()
        self.set_buttons()

        # Setup combobox
        self._window.transportation_combo.addItem('HSR', 'HighSpeedRail')
        self._window.transportation_combo.addItem('Taxi', 'Uber,Taxi')
        self._window.transportation_combo.addItem('Drive', 'Car')
        self._window.transportation_combo.addItem('Scooter', 'Motorcycle')

        # Setup RadioButton / CheckBox
        self._window.yes_radio.setChecked(False)
        self._window.no_radio.setChecked(True)
        vegetarian_group = QButtonGroup(self._window)
        vegetarian_group.setExclusive(True)
        vegetarian_group.addButton(self._window.yes_radio)
        vegetarian_group.addButton(self._window.no_radio)

        self._window.absolutly_check.setChecked(True)
        self._window.maybe_check.setChecked(False)
        self._window.sorry_check.setChecked(False)
        participate_group = QButtonGroup(self._window)
        participate_group.setExclusive(True)
        participate_group.addButton(self._window.absolutly_check)
        participate_group.addButton(self._window.maybe_check)
        participate_group.addButton(self._window.sorry_check)

        # Setup SpinBox
        self._window.members_spin.setRange(1, 10)
예제 #2
0
class ChannelSelector(QWidget):
    channelSelected = Signal(str)
    channelDeselected = Signal(str)

    def __init__(self):
        QWidget.__init__(self)
        self.setLayout(QGridLayout())

        self.control_group = QButtonGroup()
        self.control_group.setExclusive(False)
        self.control_group.idToggled.connect(self.notifyChannel)
        self.ids_to_channels = {}  # {id: channel_name (str)}
        self.checkboxes = {}  # {channel_name: QCheckBox}

        self.next_id = 0

        # TODO(jacob): 4 columns is mostly an arbitrary choice; 5 seemed
        # too crowded, 3 seemed too empty. Ideally we'd change this
        # dynamically based on the column width.
        self.num_cols = 4

    def add_checkbox(self, channel_name):
        if channel_name in self.checkboxes:
            warnings.warn('attempted to add a duplicate checkbox to the DAQ channel selector')
            return
        checkbox = QCheckBox(channel_name)
        self.checkboxes[channel_name] = checkbox

        num_widgets = len(self.checkboxes)
        row = (num_widgets - 1) // self.num_cols
        col = (num_widgets - 1) % self.num_cols
        self.layout().addWidget(checkbox, row, col)

        self.control_group.addButton(checkbox, self.next_id)
        self.ids_to_channels[self.next_id] = channel_name
        self.next_id += 1

    def clear_checkboxes(self):
        for checkbox in self.checkboxes.values():
            self.control_group.removeButton(checkbox)
            self.layout().removeWidget(checkbox)
            checkbox.deleteLater()
        self.checkboxes = {}
        self.ids_to_channels = {}

    @Slot(top.PlumbingEngine)
    def updateNodeList(self, plumb):
        self.clear_checkboxes()
        for node in plumb.nodes(data=False):
            self.add_checkbox(node)

    @Slot(int)
    def notifyChannel(self, checkbox_id, is_checked):
        channel = self.ids_to_channels[checkbox_id]
        if is_checked:
            self.channelSelected.emit(channel)
        else:
            self.channelDeselected.emit(channel)
예제 #3
0
    def __init__(self):

        self.widget = QWidget()

        layout = QVBoxLayout()
        self.widget.setLayout(layout)

        # Section Buttons
        load_image_button = QPushButton("Load Section")
        layout.addWidget(load_image_button)
        load_image_button.clicked.connect(self.show_load_image_dialog)

        load_image_button2 = QPushButton("Quick Load Section")
        layout.addWidget(load_image_button2)
        load_image_button2.clicked.connect(lambda: self.load_section(
            "data/RA_10X_scans/MeA/S1_07032020.ome.tiff"))

        # Scale Slider (Set Section Resolution)
        self.resample_widget = LabelledSliderWidget(min=15,
                                                    max=200,
                                                    label="Scale")
        layout.addLayout(self.resample_widget.layout)
        self.resample_widget.connect(
            lambda val: self.set_section_image_resolution(val))

        self.dim_widgets = []
        for dim in [
                'right', 'superior', 'anterior', 'rot_lateral', 'rot_axial',
                'rot_median'
        ]:
            widget = LabelledSliderWidget(
                min=-10000 if not dim.startswith('rot_') else -180,
                max=10000 if not dim.startswith('rot_') else 180,
                label=dim)
            layout.addLayout(widget.layout)
            fun = lambda d, value: self.transform_section(**{d: value})
            widget.connect(partial(fun, dim))
            self.dim_widgets.append((widget, fun))

        # Atlas BUttons
        button_hbox = QHBoxLayout()
        layout.addLayout(button_hbox)

        atlas_buttons = QButtonGroup(self.widget)
        atlas_buttons.setExclusive(True)
        atlas_buttons.buttonToggled.connect(self.atlas_button_toggled)

        for resolution in [100, 25, 10]:
            atlas_button = QPushButton(f"{resolution}um")
            atlas_button.setCheckable(True)
            button_hbox.addWidget(atlas_button)
            atlas_buttons.addButton(atlas_button)

            # The 10um atlas takes way too long to download at the moment.
            # It needs some kind of progress bar or async download feature to be useful.
            # The disabled button here shows it as an option for the future, but keeps it from being used.
            if resolution == 10:
                atlas_button.setDisabled(True)
예제 #4
0
class View(QMainWindow, Ui_DsManager):
    def __init__(self, *args, **kwargs):
        super(View, self).__init__(*args, **kwargs)
        self.setupUi(self)

    def setupUi(self, DsManager):
        super(View, self).setupUi(DsManager)
        self.source_btn_group = QButtonGroup(self)
        self.reversed_entry_btn_group = QButtonGroup(self)
        self.source_btn_group.setExclusive(True)
        self.reversed_entry_btn_group.setExclusive(True)
        self.source_btn_group.addButton(self.cash_radio, 1)
        self.source_btn_group.addButton(self.main_radio, 2)
        self.source_btn_group.addButton(self.building_radio, 3)
        self.reversed_entry_btn_group.addButton(self.reversed_entry_increase,
                                                1)
        self.reversed_entry_btn_group.addButton(self.reversed_entry_decrease,
                                                2)
        self.cheque_label.hide()
        self.cheque_number.hide()

    def view_pdf(self, pdf_js, pdf_file_name):
        new_window = QMainWindow(self)
        pdf_viewer = Ui_PDFViewer()
        pdf_viewer.setupUi(new_window)
        pdf_url = QUrl.fromLocalFile(pdf_js)
        pdf_url.setQuery("file=" + pdf_file_name)
        pdf_viewer.webView.load(pdf_url)
        new_window.show()

    @classmethod
    def show_about_ds(cls):
        dialog = QDialog()
        about = Ui_About()
        about.setupUi(dialog)
        dialog.exec_()

    @classmethod
    def show_message(cls, message: str, logo: str):
        msg = QMessageBox()
        icon = QIcon()
        icon.addFile(u"inc/icon.ico", QSize(), QIcon.Normal, QIcon.Off)
        msg.setWindowIcon(icon)
        if logo == "error":
            msg.setIcon(QMessageBox.Critical)
        elif logo == "info":
            msg.setIcon(QMessageBox.Information)
        msg.setText(message)
        msg.setWindowTitle(logo)
        msg.exec_()

    def closeEvent(self, event):
        model = Model()
        model.close_connection()
        event.accept()
예제 #5
0
class ElchPlotMenu(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        controls = ['Start', 'Clear', 'Export']
        self.buttons = {
            key: QPushButton(parent=self, text=key, objectName=key)
            for key in controls
        }
        self.buttons['Start'].setCheckable(True)
        self.checks = {
            key: QCheckBox(parent=self, text=key, objectName=key)
            for key in ['Sensor PV', 'Controller PV', 'Setpoint', 'Power']
        }
        self.check_group = QButtonGroup()
        self.check_group.setExclusive(False)

        vbox = QVBoxLayout()
        vbox.addWidget(QLabel(text='Plotting', objectName='Header'))
        for key in controls:
            vbox.addWidget(self.buttons[key])
            self.buttons[key].clicked.connect({
                'Start':
                functools.partial(self.start_stop_plotting),
                'Clear':
                self.clear_pplot,
                'Export':
                self.export_data
            }[key])
        vbox.addSpacing(20)
        vbox.addWidget(QLabel(text='Data sources', objectName='Header'))
        for key, button in self.checks.items():
            button.setChecked(True)
            self.check_group.addButton(button)
            vbox.addWidget(button)
        vbox.addStretch()
        vbox.setSpacing(10)
        vbox.setContentsMargins(10, 10, 10, 10)
        self.setLayout(vbox)

    def start_stop_plotting(self):
        pubsub.pub.sendMessage('gui.plot.start' if self.buttons['Start'].
                               isChecked() else 'gui.plot.stop')

    def clear_pplot(self):
        pubsub.pub.sendMessage('gui.plot.clear')
        if self.buttons['Start'].isChecked():
            self.buttons['Start'].click()

    def export_data(self):
        if (file_path := QFileDialog.getSaveFileName(
                self, 'Save as...', 'Logs/Log.csv', 'CSV (*.csv)')[0]) != '':
            pubsub.pub.sendMessage('gui.plot.export', filepath=file_path)
예제 #6
0
    def _init(self):
        print("Building...")

        self.win = QMainWindow()
        self._default_window_title = self.title

        widget = QWidget()
        self.win.setCentralWidget(widget)

        main_layout = QHBoxLayout()
        widget.setLayout(main_layout)

        main_layout.addWidget(self.slice_widget)
        main_layout.addWidget(self.volume_widget)

        side_layout = QVBoxLayout()
        main_layout.addLayout(side_layout)

        load_image_button = QPushButton("Load Section")
        side_layout.addWidget(load_image_button)
        load_image_button.clicked.connect(self.show_load_image_dialog)

        # Atlas BUttons
        button_hbox = QHBoxLayout()
        side_layout.addLayout(button_hbox)

        atlas_buttons = QButtonGroup(self.win)
        atlas_buttons.setExclusive(True)
        atlas_buttons.buttonToggled.connect(self.atlas_button_toggled)

        for resolution in [100, 25, 10]:
            atlas_button = QPushButton(f"{resolution}um")
            atlas_button.setCheckable(True)
            button_hbox.addWidget(atlas_button)
            atlas_buttons.addButton(atlas_button)

            # The 10um atlas takes way too long to download at the moment.
            # It needs some kind of progress bar or async download feature to be useful.
            # The disabled button here shows it as an option for the future, but keeps it from being used.
            if resolution == 10:
                atlas_button.setDisabled(True)

        self.title_reset_timer = Timer(interval=2, connect=lambda e: self._show_default_window_title(), iterations=1,
                                       start=False)
        self._show_default_window_title()

        self.statusbar = self.win.statusBar()

        self.image_coord_label = QLabel(text="Image Coords")
        self.statusbar.addPermanentWidget(self.image_coord_label)

        self.win.show()
class StartMineSchedDialog(QDialog):
    # 定义选择信号
    start_minesched_signal = Signal(str)

    # 初始化
    def __init__(self, config: ConfigFactory, logger: LoggerFactory,
                 title: str):
        super(StartMineSchedDialog, self).__init__()
        self.config = config
        self.logger = logger
        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        self.start_minesched_button_group = QButtonGroup()
        self.start_minesched_button_group.setExclusive(True)
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.minescheds = []
        self.minesched_id = -1

    # 设置MineSched不同版本列表
    def set_minescheds(self, minescheds: list):
        self.minescheds = minescheds
        for _id, minesched in enumerate(self.minescheds):
            minesched_item = QRadioButton(minesched)
            self.start_minesched_button_group.addButton(minesched_item)
            self.start_minesched_button_group.setId(minesched_item, _id)
            if _id == 0:
                minesched_item.setChecked(True)
                self.minesched_id = 0
            self.layout.addWidget(minesched_item)
        self.start_minesched_button_group.buttonClicked.connect(
            self.start_minesched_change)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        self.layout.addWidget(self.buttons)

    # 如果单击ok按钮
    def accept(self):
        # 先关闭对话框,然后发送消息
        super(StartMineSchedDialog, self).accept()
        self.config.set_config('minesched', 'minesched_location',
                               self.minescheds[self.minesched_id])
        # 发送surpac启动消息
        self.start_minesched_signal.emit(self.minescheds[self.minesched_id])

    def start_minesched_change(self):
        self.minesched_id = self.start_minesched_button_group.checkedId()
class ChoiceSurpacDialog(QDialog):
    # 定义选择信号
    choices_surpac_signal = Signal(str)

    # 初始化
    def __init__(self, config: ConfigFactory, logger: LoggerFactory,
                 title: str, surpacs: list):
        super(ChoiceSurpacDialog, self).__init__()
        self.config = config
        self.logger = logger

        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.surpacs = surpacs
        self.choice_surpac_button_group = QButtonGroup()
        self.choice_surpac_button_group.setExclusive(True)
        layout = QVBoxLayout()
        for surpac_id, choice in enumerate(surpacs):
            surpac_item = QRadioButton(choice)
            self.choice_surpac_button_group.addButton(surpac_item)
            self.choice_surpac_button_group.setId(surpac_item, surpac_id)
            if surpac_id == 0:
                surpac_item.setChecked(True)
                self.surpac_id = 0
            layout.addWidget(surpac_item)
        self.choice_surpac_button_group.buttonClicked.connect(
            self.choice_surpac_change)
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        layout.addWidget(self.buttons)
        self.setLayout(layout)

    def accept(self):
        # 先关闭对话框,然后发送消息
        super(ChoiceSurpacDialog, self).accept()
        if self.config.get('master',
                           'surpac_location') == self.surpacs[self.surpac_id]:
            pass
        else:
            self.choices_surpac_signal.emit(self.surpacs[self.surpac_id])
            self.config.set_config('master', 'surpac_location',
                                   self.surpacs[self.surpac_id])

    def choice_surpac_change(self):
        self.surpac_id = self.choice_surpac_button_group.checkedId()
예제 #9
0
    def __init__(self, parent: QWidget = None):
        """
		Constructs a NewProjectDialog object.
		
		:param parent: the widget to nest this dialog inside of. If None, this dialog will be a window.
		:type parent: PySide2.QtWidgets.QWidget
		:return: The constructed new project dialog object.
		:rtype: NewProjectDialog
		"""

        super(NewProjectDialog, self).__init__(parent)
        self.ui = Ui_NewProjectDialog()
        self.ui.setupUi(self)
        self.setWindowTitle("Create New Project")

        # allow user to select folder to save project in
        self.ui.browseFilesButton_folder.clicked.connect(
            self._browseProjectFolders)
        self.ui.browseFilesButton_executable.clicked.connect(
            self._browseApplicationFile)

        # group all radio buttons together to make them mutually exclusive
        group = QButtonGroup()
        group.setExclusive(True)
        group.addButton(self.ui.option_Other)
        group.addButton(self.ui.option_idk)
        group.addButton(self.ui.option_Legacy)
        group.addButton(self.ui.option_MFC)
        group.addButton(self.ui.option_VB6)
        group.addButton(self.ui.option_VCL)
        group.addButton(self.ui.option_Browser)
        group.addButton(self.ui.option_Store_App)
        group.addButton(self.ui.option_WPF)
        group.addButton(self.ui.option_WinForms)
        group.addButton(self.ui.option_Qt5)
        group.buttonClicked.connect(self._onBackendChecked)
        self._radioBtnGroup = group

        # set default backend to unknown
        self.ui.option_idk.setChecked(True)
        self.ui.other_edit.setEnabled(False)

        # Remove error message originally
        self.ui.error_label.setText("")

        # disable file path editors
        self.ui.executable_file_edit.setEnabled(False)
        self.ui.project_folder_edit.setEnabled(False)
예제 #10
0
class CheckHLayout(QHBoxLayout):
    """Check boxes hlayout with QButtonGroup"""
    def __init__(self, boxes, checks, parent=None):
        QHBoxLayout.__init__(self)
        self.setSpacing(0)
        self.group = QButtonGroup()
        self.group.setExclusive(False)
        for i, (box, check) in enumerate(zip(boxes, checks)):
            cbx = QCheckBox(box)
            cbx.setChecked(eval(check))
            self.addWidget(cbx)
            self.group.addButton(cbx, i)

    def values(self):
        return [cbx.isChecked() for cbx in self.group.buttons()]

    def setStyleSheet(self, style):
        for cbx in self.group.buttons():
            cbx.setStyleSheet(style)
class ChoiceLanguageDialog(QDialog):
    # 定义选择信号
    choices_language_dialog_signal = Signal(str)

    # 初始化
    def __init__(self, config: ConfigFactory, logger: LoggerFactory, title: str, languages: list):
        super(ChoiceLanguageDialog, self).__init__()
        self.config = config
        self.logger = logger
        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.languages = languages
        self.choice_language_button_group = QButtonGroup()
        self.choice_language_button_group.setExclusive(True)
        layout = QVBoxLayout()
        for language_id, language in enumerate(languages):
            # 显示语言提示
            language_item = QRadioButton(language.split(':')[0])
            self.choice_language_button_group.addButton(language_item)
            self.choice_language_button_group.setId(language_item, language_id)
            if language_id == 0:
                language_item.setChecked(True)
                self.language_id = 0
            layout.addWidget(language_item)
        self.choice_language_button_group.buttonClicked.connect(self.language_change)
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)
        layout.addWidget(self.buttons)
        self.setLayout(layout)

    def accept(self):
        # 先关闭对话框,然后发送消息
        super(ChoiceLanguageDialog, self).accept()
        # 发送语言文件
        language = self.languages[self.language_id].split(':')[1]
        self.choices_language_dialog_signal.emit(language)
        self.config.set_config('master', 'surpac_language_cfg', language)

    def language_change(self):
        self.language_id = self.choice_language_button_group.checkedId()
예제 #12
0
 def _insert_merged(self, al, bl):
     if al:
         row = self.rowCount()
         self.insertRow(row)
         self.setItem(row, 1,
                      self._table_item('\n'.join(map(lambda x: x[0], al))))
         self.setItem(row, 2, self._table_item())
         self.setItem(row, 3, self._table_item())
         editor = NPTextEdit(bg_color='#ffeef0')
         editor.sig_size.connect(self.item(row, 3).setSizeHint)
         self._highlight(editor, ''.join(map(lambda x: x[1], al)),
                         self.fmt_sub, self.fmt_sub)
         self.setCellWidget(row, 3, editor)
         if not bl:
             self.setItem(row, 0, self._table_item())
             self.setCellWidget(row, 0, QCheckBox(checked=True))
             self.cellWidget(row, 3).setReadOnly(True)
     if bl:
         row = self.rowCount()
         self.insertRow(row)
         self.setItem(row, 1, self._table_item())
         self.setItem(row, 2,
                      self._table_item('\n'.join(map(lambda x: x[0], bl))))
         self.setItem(row, 3, self._table_item())
         editor = NPTextEdit(bg_color='#e6ffed')
         editor.sig_size.connect(self.item(row, 3).setSizeHint)
         self._highlight(editor, ''.join(map(lambda x: x[1], bl)),
                         self.fmt_add, self.fmt_add)
         self.setCellWidget(row, 3, editor)
         if not al:
             self.setCellWidget(row, 0, QCheckBox(checked=True))
     if al and bl:  # 변경 시 radio button 필요
         group = QButtonGroup(self)
         group.setExclusive(True)
         ar = QRadioButton()
         br = QRadioButton(checked=True)
         group.addButton(ar)
         group.addButton(br)
         self.setCellWidget(self.rowCount() - 2, 0, ar)
         self.setCellWidget(self.rowCount() - 1, 0, br)
예제 #13
0
class _Widget(QWidget):
    _SPACER: int = 20

    def __init__(self, parent=None):
        super().__init__(parent)
        self.mainLayout = QVBoxLayout(self)
        self.byTime = QCheckBox('By time', self)
        self.byDate = QCheckBox('By date', self)
        self.group = QButtonGroup(self)
        butLayout = QHBoxLayout()
        butLayout.addWidget(self.byDate)
        butLayout.addWidget(self.byTime)
        self.group.addButton(self.byDate)
        self.group.addButton(self.byTime)
        self.addRowBut = QPushButton('Add interval', self)
        self.addRowBut.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.gLayout = QGridLayout()
        self.mainLayout.addLayout(butLayout)
        self.mainLayout.addWidget(self.addRowBut, 0, Qt.AlignLeft)
        self.mainLayout.addLayout(self.gLayout)
        self.gLayout.setHorizontalSpacing(self._SPACER)
        self.group.setExclusive(False)
        self.byDate.setChecked(True)
        self.byTime.setChecked(True)
예제 #14
0
class MultiCheckWidget(QGroupBox):
    """Qt Widget to show multiple checkboxes for a sequence of numbers.

    Args:
        count: The number of checkboxes to show.
        title: Display title for group of checkboxes.
        selected: List of checkbox numbers to initially check.
        default: Whether to default boxes as checked.
    """
    def __init__(self,
                 *args,
                 count: int,
                 title: Optional[str] = "",
                 selected: Optional[List] = None,
                 default: Optional[bool] = False,
                 **kwargs):
        super(MultiCheckWidget, self).__init__(*args, **kwargs)

        # QButtonGroup is the logical container
        # it allows us to get list of checked boxes more easily
        self.check_group = QButtonGroup()
        self.check_group.setExclusive(False)  # more than one can be checked

        if title != "":
            self.setTitle(title)
            self.setFlat(False)
        else:
            self.setFlat(True)

        if selected is None:
            selected = list(range(count)) if default else []

        check_layout = QGridLayout()
        self.setLayout(check_layout)
        for i in range(count):
            check = QCheckBox("%d" % (i))
            # call signal/slot on self when one of the checkboxes is changed
            check.stateChanged.connect(lambda e: self.selectionChanged.emit())
            self.check_group.addButton(check, i)
            check_layout.addWidget(check, i // 8, i % 8)
        self.setSelected(selected)

    """
    selectionChanged signal sent when a checkbox gets a stateChanged signal
    """
    selectionChanged = Signal()

    def getSelected(self) -> list:
        """Method to get list of the checked checkboxes.

        Returns:
            list of checked checkboxes
        """
        selected = []
        for check_button in self.check_group.buttons():
            if check_button.isChecked():
                selected.append(self.check_group.id(check_button))
        return selected

    def setSelected(self, selected: list):
        """Method to set some checkboxes as checked.

        Args:
            selected: List of checkboxes to check.

        Returns:
            None
        """
        for check_button in self.check_group.buttons():
            if self.check_group.id(check_button) in selected:
                check_button.setChecked(True)
            else:
                check_button.setChecked(False)

    def boundingRect(self) -> QRectF:
        """Method required by Qt.
        """
        return QRectF()

    def paint(self, painter, option, widget=None):
        """Method required by Qt.
        """
        pass
예제 #15
0
class ParameterTagToolBar(QToolBar):
    """A toolbar to add items using drag and drop actions."""

    tag_button_toggled = Signal("QVariant", "bool")
    manage_tags_action_triggered = Signal("bool")
    tag_actions_added = Signal("QVariant", "QVariant")

    def __init__(self, parent, db_mngr, *db_maps):
        """

        Args:
            parent (DataStoreForm): tree or graph view form
            db_mngr (SpineDBManager): the DB manager for interacting with the db
            db_maps (iter): DiffDatabaseMapping instances
        """
        super().__init__("Parameter Tag Toolbar", parent=parent)
        self.db_mngr = db_mngr
        self.db_maps = db_maps
        label = QLabel("Parameter tag")
        self.addWidget(label)
        self.tag_button_group = QButtonGroup(self)
        self.tag_button_group.setExclusive(False)
        self.actions = []
        self.db_map_ids = []
        empty = QWidget()
        empty.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.empty_action = self.addWidget(empty)
        button = QPushButton("Manage tags...")
        self.addWidget(button)
        # noinspection PyUnresolvedReferences
        # pylint: disable=unnecessary-lambda
        button.clicked.connect(lambda checked: self.manage_tags_action_triggered.emit(checked))
        self.setStyleSheet(PARAMETER_TAG_TOOLBAR_SS)
        self.setObjectName("ParameterTagToolbar")
        self.tag_actions_added.connect(self._add_db_map_tag_actions)

    def init_toolbar(self):
        for button in self.tag_button_group.buttons():
            self.tag_button_group.removeButton(button)
        for action in self.actions:
            self.removeAction(action)
        action = QAction("untagged")
        self.insertAction(self.empty_action, action)
        action.setCheckable(True)
        button = self.widgetForAction(action)
        self.tag_button_group.addButton(button, id=0)
        self.actions = [action]
        self.db_map_ids = [[(db_map, 0) for db_map in self.db_maps]]
        tag_data = {}
        for db_map in self.db_maps:
            for parameter_tag in self.db_mngr.get_items(db_map, "parameter tag"):
                tag_data.setdefault(parameter_tag["tag"], {})[db_map] = parameter_tag["id"]
        for tag, db_map_data in tag_data.items():
            action = QAction(tag)
            self.insertAction(self.empty_action, action)
            action.setCheckable(True)
            button = self.widgetForAction(action)
            self.tag_button_group.addButton(button, id=len(self.db_map_ids))
            self.actions.append(action)
            self.db_map_ids.append(list(db_map_data.items()))
        self.tag_button_group.buttonToggled["int", "bool"].connect(
            lambda i, checked: self.tag_button_toggled.emit(self.db_map_ids[i], checked)
        )

    def receive_parameter_tags_added(self, db_map_data):
        for db_map, parameter_tags in db_map_data.items():
            self.tag_actions_added.emit(db_map, parameter_tags)

    @Slot("QVariant", "QVariant")
    def _add_db_map_tag_actions(self, db_map, parameter_tags):
        action_texts = [a.text() for a in self.actions]
        for parameter_tag in parameter_tags:
            if parameter_tag["tag"] in action_texts:
                # Already a tag named after that, add db_map id information
                i = action_texts.index(parameter_tag["tag"])
                self.db_map_ids[i].append((db_map, parameter_tag["id"]))
            else:
                action = QAction(parameter_tag["tag"])
                self.insertAction(self.empty_action, action)
                action.setCheckable(True)
                button = self.widgetForAction(action)
                self.tag_button_group.addButton(button, id=len(self.db_map_ids))
                self.actions.append(action)
                self.db_map_ids.append([(db_map, parameter_tag["id"])])
                action_texts.append(action.text())

    def receive_parameter_tags_removed(self, db_map_data):
        for db_map, parameter_tags in db_map_data.items():
            parameter_tag_ids = {x["id"] for x in parameter_tags}
            self._remove_db_map_tag_actions(db_map, parameter_tag_ids)

    def _remove_db_map_tag_actions(self, db_map, parameter_tag_ids):
        for tag_id in parameter_tag_ids:
            i = next(k for k, x in enumerate(self.db_map_ids) if (db_map, tag_id) in x)
            self.db_map_ids[i].remove((db_map, tag_id))
            if not self.db_map_ids[i]:
                self.db_map_ids.pop(i)
                self.removeAction(self.actions.pop(i))

    def receive_parameter_tags_updated(self, db_map_data):
        for db_map, parameter_tags in db_map_data.items():
            self._update_db_map_tag_actions(db_map, parameter_tags)

    def _update_db_map_tag_actions(self, db_map, parameter_tags):
        for parameter_tag in parameter_tags:
            i = next(k for k, x in enumerate(self.db_map_ids) if (db_map, parameter_tag["id"]) in x)
            action = self.actions[i]
            action.setText(parameter_tag["tag"])
예제 #16
0
    def __init__(self, name: str, parent: QWidget = None):
        QFrame.__init__(self, parent)

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

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

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

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

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

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

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

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

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

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

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

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

        self.setupMatrix()
예제 #17
0
class _RemoveNanEditor(AbsOperationEditor):
    _baseText = {
        0: 'Remove with more than: <b>{}</b> nan',
        1: 'Remove with more than: <b>{}%</b> nan'
    }

    def __init__(self, mode: str, parent: QWidget = None):
        """ Builds the editor

        :param mode: one of 'col' or 'row'
        :param parent: a parent widget

        """
        self.__mode: str = mode
        super().__init__(parent)

    def editorBody(self) -> QWidget:
        self.__group = QButtonGroup()
        self.__group.setExclusive(True)
        lab = QLabel('Choose how to remove:')
        self.__group.addButton(QRadioButton('By number'), id=0)
        self.__group.addButton(QRadioButton('By percentage'), id=1)
        self.__currId = None

        self.__summaryLabel = QLabel()
        self.__slider = QSlider(Qt.Horizontal, self)
        self.__slider.setMinimum(0)
        self.__slider.setTracking(True)
        self.__slider.setSingleStep(1)

        self.__numBox = QSpinBox()
        self.__numBox.setMinimum(0)
        self.__numBox.setMaximum(10000000)

        radioLayout = QHBoxLayout()
        radioLayout.addWidget(self.__group.button(0))
        radioLayout.addWidget(self.__group.button(1))
        self.__bodyLayout = QVBoxLayout()
        self.__bodyLayout.addWidget(lab)
        self.__bodyLayout.addLayout(radioLayout)
        self.__bodyLayout.addSpacing(20)
        self.__bodyLayout.addWidget(QLabel('Move the slider to set removal parameter:'))
        self.__bodyLayout.addSpacing(10)
        self.__bodyLayout.addWidget(self.__slider if self.__mode == 'row' else self.__numBox)
        self.__bodyLayout.addWidget(self.__summaryLabel)

        self.__group.buttonClicked[int].connect(self._toggleMode)
        # Both are connected, only one is shown
        self.__slider.valueChanged.connect(self._onValueChanged)
        self.__numBox.valueChanged[int].connect(self._onValueChanged)
        # Set a default button and label text
        self.__group.button(0).click()
        self.__summaryLabel.setText(self._baseText[0].format(self.__slider.minimum()))

        body = QWidget()
        body.setLayout(self.__bodyLayout)
        return body

    @Slot(int)
    def _toggleMode(self, bid: int) -> None:
        # NOTE: could be refactored
        if bid == self.__currId:
            return
        self.__currId = bid
        if bid == 0:
            if not (self.inputShapes and self.inputShapes[0]) and self.__mode == 'row':
                self.__slider.setDisabled(True)
                self._onValueChanged(self.__slider.value())
            elif not self.__slider.isEnabled():
                self.__slider.setEnabled(True)
            else:
                if self.__mode == 'row':
                    self.__slider.setMaximum(self.inputShapes[0].nColumns)
                    self._onValueChanged(self.__slider.value())
                else:
                    self.__bodyLayout.replaceWidget(self.__slider, self.__numBox)
                    self.__slider.hide()
                    self.__numBox.show()
                    self._onValueChanged(self.__numBox.value())
        else:
            if self.__mode == 'row':
                if not self.__slider.isEnabled():
                    self.__slider.setEnabled(True)
            else:
                self.__bodyLayout.replaceWidget(self.__numBox, self.__slider)
                self.__numBox.hide()
                self.__slider.show()
            self._onValueChanged(self.__slider.value())
            self.__slider.setMaximum(100)

    @Slot(int)
    def _onValueChanged(self, value: int):
        self.__summaryLabel.setText(self._baseText[self.__currId].format(value))

    def getOptions(self) -> Iterable:
        if self.__group.checkedId() == 0:
            # By number
            return None, self.__slider.value() if self.__mode == 'row' else self.__numBox.value()
        else:
            # By perc
            return self.__slider.value() / 100, None

    def setOptions(self, percentage: float, number: int) -> None:
        if percentage is not None:
            self.__group.button(1).click()
            self.__slider.setValue(percentage * 100)
        elif number is not None:
            self.__group.button(0).click()
            self.__slider.setValue(number) if self.__mode == 'row' else self.__numBox.setValue(number)
        else:
            # Both None
            self.__slider.setValue(0)
            self.__numBox.setValue(0)

    def refresh(self) -> None:
        if self.__mode == 'row' and self.__group.checkedId() == 0:
            self.__slider.setMaximum(self.inputShapes[0].nColumns)
            self.__slider.setEnabled(True)
예제 #18
0
class ElchDeviceMenu(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.labels = {
            key: QLabel(text=key, objectName='Header')
            for key in ['Controller', 'Sensor']
        }
        self.device_menus = {key: QComboBox() for key in self.labels}
        self.port_menus = {key: QComboBox() for key in self.labels}
        self.connect_buttons = {
            key: QPushButton(text='Connect', objectName=key)
            for key in self.labels
        }

        self.buttongroup = QButtonGroup()
        self.buttongroup.setExclusive(False)
        self.buttongroup.buttonToggled.connect(self.connect_device)

        self.unitbuttons = {
            key: QRadioButton(text=key)
            for key in ['Temperature', 'Voltage']
        }
        self.refresh_button = QPushButton(text='Refresh Serial',
                                          objectName='Refresh')

        vbox = QVBoxLayout()
        vbox.setSpacing(10)
        vbox.setContentsMargins(10, 10, 10, 10)

        vbox.addWidget(QLabel(text='Process Variable', objectName='Header'))
        for key, button in self.unitbuttons.items():
            vbox.addWidget(button)
            button.toggled.connect(
                functools.partial(self.set_measurement_unit, unit=key))
        vbox.addSpacing(20)

        for key in self.labels:
            self.buttongroup.addButton(self.connect_buttons[key])
            self.connect_buttons[key].setCheckable(True)
            vbox.addWidget(self.labels[key])
            vbox.addWidget(self.device_menus[key])
            vbox.addWidget(self.port_menus[key])
            vbox.addWidget(self.connect_buttons[key])
            vbox.addSpacing(20)

        vbox.addWidget(self.refresh_button)
        self.refresh_button.clicked.connect(
            lambda: pubsub.pub.sendMessage('gui.request.ports'))
        vbox.addStretch()
        self.setLayout(vbox)

        pubsub.pub.subscribe(listener=self.update_ports,
                             topicName='engine.answer.ports')
        pubsub.pub.subscribe(listener=self.update_devices,
                             topicName='engine.answer.devices')

        pubsub.pub.sendMessage('gui.request.ports')

    def update_ports(self, ports):
        """Populate the controller and sensor menus with lists of device names and ports"""
        for key, menu in self.port_menus.items():
            menu.clear()
            menu.addItems(ports)
            for port, description in ports.items():
                index = menu.findText(port)
                menu.setItemData(index, description, Qt.ToolTipRole)

    def update_devices(self, devices):
        for key in self.device_menus:
            self.device_menus[key].clear()
            self.device_menus[key].addItems(devices[key])

    def connect_device(self, source, state):
        key = source.objectName()
        port = self.port_menus[key].currentText()
        device = self.device_menus[key].currentText()

        if state:
            if key == 'Controller':
                pubsub.pub.sendMessage('gui.con.connect_controller',
                                       controller_type=device,
                                       controller_port=port)
            elif key == 'Sensor':
                pubsub.pub.sendMessage('gui.con.connect_sensor',
                                       sensor_type=device,
                                       sensor_port=port)
        else:
            if key == 'Controller':
                pubsub.pub.sendMessage('gui.con.disconnect_controller')
            elif key == 'Sensor':
                pubsub.pub.sendMessage('gui.con.disconnect_sensor')

    @staticmethod
    def set_measurement_unit(checked, unit):
        if checked:
            pubsub.pub.sendMessage('gui.set.units', unit=unit)
예제 #19
0
        class MyWidget(QWidget):
            def __init__(self, parent):
                super().__init__(parent)
                self.buttons_id_value = {
                    1: ('comma', ','),
                    2: ('space', '\b'),
                    3: ('tab', '\t'),
                    4: ('semicolon', ';')
                }
                self.separator = QButtonGroup()
                lab = QLabel()
                lab.setText('Choose a separator:')
                for bid, value in self.buttons_id_value.items():
                    self.separator.addButton(QRadioButton(value[0]), id=bid)
                self.separator.setExclusive(True)
                self.default_button = self.separator.button(1)
                button_layout = QHBoxLayout()
                for button in self.separator.buttons():
                    button_layout.addWidget(button)
                self.default_button.click()

                openFileChooser = QPushButton('Choose')
                fileChooser = QFileDialog(self, 'Open csv', str(os.getcwd()),
                                          'Csv (*.csv *.tsv *.dat)')
                fileChooser.setFileMode(QFileDialog.ExistingFile)
                self.filePath = QLineEdit()
                openFileChooser.released.connect(fileChooser.show)
                fileChooser.fileSelected.connect(self.filePath.setText)
                self.filePath.textChanged.connect(self.checkFileExists)
                nameLabel = QLabel('Select a name:', self)
                self.nameField = QLineEdit(self)
                self.nameErrorLabel = QLabel(self)

                self.file_layout = QVBoxLayout()
                fileChooserLayout = QHBoxLayout()
                nameRowLayout = QHBoxLayout()
                fileChooserLayout.addWidget(openFileChooser)
                fileChooserLayout.addWidget(self.filePath)
                nameRowLayout.addWidget(nameLabel)
                nameRowLayout.addWidget(self.nameField)
                self.fileErrorLabel = QLabel(self)
                self.file_layout.addLayout(fileChooserLayout)
                self.file_layout.addWidget(self.fileErrorLabel)
                self.file_layout.addLayout(nameRowLayout)
                self.file_layout.addWidget(self.nameErrorLabel)
                self.fileErrorLabel.hide()
                self.nameErrorLabel.hide()
                self.tablePreview = SearchableAttributeTableWidget(self, True)
                self.tableSpinner = QtWaitingSpinner(
                    self.tablePreview,
                    centerOnParent=True,
                    disableParentWhenSpinning=True)
                self.nameField.textEdited.connect(self.nameErrorLabel.hide)

                # Split file by row
                splitRowLayout = QHBoxLayout()
                self.checkSplit = QCheckBox('Split file by rows', self)
                self.numberRowsChunk = QLineEdit(self)
                self.numberRowsChunk.setPlaceholderText(
                    'Number of rows per chunk')
                self.numberRowsChunk.setValidator(QIntValidator(self))
                splitRowLayout.addWidget(self.checkSplit)
                splitRowLayout.addWidget(self.numberRowsChunk)
                self.checkSplit.stateChanged.connect(self.toggleSplitRows)

                layout = QVBoxLayout()
                layout.addLayout(self.file_layout)
                layout.addWidget(lab)
                layout.addLayout(button_layout)
                layout.addLayout(splitRowLayout)
                layout.addWidget(QLabel('Preview'))
                layout.addWidget(self.tablePreview)
                self.setLayout(layout)

                self.filePath.textChanged.connect(self.loadPreview)
                self.separator.buttonClicked.connect(self.loadPreview)

            @Slot(object)
            def loadPreview(self) -> None:
                if not os.path.isfile(self.filePath.text()):
                    return

                class WorkerThread(QThread):
                    resultReady = Signal(Frame)

                    def __init__(self, path: str, separ: str, parent=None):
                        super().__init__(parent)
                        self.__path = path
                        self.__sep = separ

                    def run(self):
                        header = pd.read_csv(self.__path,
                                             sep=self.__sep,
                                             index_col=False,
                                             nrows=0)
                        self.resultReady.emit(Frame(header))

                sep: int = self.separator.checkedId()
                sep_s: str = self.buttons_id_value[sep][
                    1] if sep != -1 else None
                assert sep_s is not None

                # Async call to load header
                worker = WorkerThread(path=self.filePath.text(),
                                      separ=sep_s,
                                      parent=self)
                worker.resultReady.connect(self.onPreviewComputed)
                worker.finished.connect(worker.deleteLater)
                self.tableSpinner.start()
                worker.start()

            @Slot(Frame)
            def onPreviewComputed(self, header: Frame):
                self.tablePreview.setSourceFrameModel(FrameModel(self, header))
                self.tablePreview.model().setAllChecked(True)
                self.tableSpinner.stop()

            @Slot(str)
            def checkFileExists(self, path: str) -> None:
                file_exists = os.path.isfile(path)
                if not file_exists:
                    self.fileErrorLabel.setText('File does not exists!')
                    self.fileErrorLabel.setStyleSheet('color: red')
                    self.filePath.setToolTip('File does not exists!')
                    self.filePath.setStyleSheet('border: 1px solid red')
                    # self.file_layout.addWidget(self.fileErrorLabel)
                    self.parentWidget().disableOkButton()
                    self.fileErrorLabel.show()
                else:
                    # self.file_layout.removeWidget(self.fileErrorLabel)
                    self.fileErrorLabel.hide()
                    self.filePath.setStyleSheet('')
                    self.parentWidget().enableOkButton()
                    if not self.nameField.text():
                        name: str = os.path.splitext(os.path.basename(path))[0]
                        self.nameField.setText(name)

            @Slot(Qt.CheckState)
            def toggleSplitRows(self, state: Qt.CheckState) -> None:
                if state == Qt.Checked:
                    self.numberRowsChunk.setEnabled(True)
                else:
                    self.numberRowsChunk.setDisabled(True)

            def showNameError(self, msg: str) -> None:
                self.nameErrorLabel.setText(msg)
                self.nameErrorLabel.setStyleSheet('color: red')
                self.nameErrorLabel.show()
예제 #20
0
class PaletteSelectorLayout(QGroupBox):
    """
    Qt Layout class for a palette
    """
    def __init__(self, fgIndex, bgIndex, palette, informFunction, parent=None):
        super(PaletteSelectorLayout, self).__init__("", parent)

        if ZXAttribute.paletteCount() != 2:
            raise Exception(
                "The palette selector is current designed for 2 palettes only")

        self._bright = palette
        self._fgIndex = fgIndex
        self._bgIndex = bgIndex
        self._informFunction = informFunction

        vert_layout = QVBoxLayout()
        self.setLayout(vert_layout)

        vert_layout.addWidget(QLabel("Palette Selector:"))
        vert_layout.addSpacing(20)

        # Add check box to select brightness
        bright_select = QCheckBox("Bright Enabled")
        vert_layout.addWidget(bright_select)
        if palette == 1:
            bright_select.setChecked(True)
        bright_select.clicked.connect(self._brightSelect)

        vert_layout.addSpacing(10)

        # Foreground color checkboxes
        self._fg_group = QButtonGroup()
        self._fg_group.setExclusive(True)
        self._createLayout(vert_layout, "Foreground color:", self._fg_group,
                           self._fgIndexSelect, fgIndex)

        vert_layout.addSpacing(10)

        # Background color checkboxes
        self._bg_group = QButtonGroup()
        self._bg_group.setExclusive(True)
        self._createLayout(vert_layout, "Background color:", self._bg_group,
                           self._bgIndexSelect, bgIndex)

    def _createLayout(self, vert_layout, labelText, buttonGroup, clickSlot,
                      setIndex):
        horiz_layout = QHBoxLayout()
        vert_layout.addLayout(horiz_layout)

        horiz_layout.addWidget(QLabel(labelText))

        for index in range(0, ZXAttribute.paletteSize()):
            button = QCheckBox()
            color = QColor(*ZXAttribute.getPaletteColor(index, 0))
            button.setStyleSheet("background-color: {}".format(color.name()))
            button.setText(ZXAttribute.getPaletteName(index, 0))

            if index == setIndex:
                button.setChecked(True)

            buttonGroup.addButton(button, index)
            horiz_layout.addWidget(button)

            button.clicked.connect(clickSlot)

    @Slot()
    def _brightSelect(self, checked):
        if not checked:
            self._bright = 0
        else:
            self._bright = 1
        self._informFunction(self.fgIndex, self.bgIndex, self.palette)

    @Slot()
    def _fgIndexSelect(self, checked):
        self._fgIndex = self._fg_group.id(self.sender())
        self._informFunction(self.fgIndex, self.bgIndex, self.palette)

    @Slot()
    def _bgIndexSelect(self, checked):
        self._bgIndex = self._bg_group.id(self.sender())
        self._informFunction(self.fgIndex, self.bgIndex, self.palette)

    @property
    def palette(self):
        return self._bright

    @property
    def fgIndex(self):
        return self._fgIndex

    @property
    def bgIndex(self):
        return self._bgIndex