def __init__(self, specialized_device, display_mode, write_mode, parent=None): """Construct a device specific widget. * specialized_device should be a DeviceBase subclass tailored to the specific device. * display_mode and write_mode are the display and write modes to use with the device. """ super(DeviceWidgetBase, self).__init__(parent) self.log = util.make_logging_source_adapter(__name__, self) self.device = specialized_device self._display_mode = display_mode self._write_mode = write_mode self.make_settings = None self.device.hardware_set.connect(self._on_device_hardware_set) self._on_device_hardware_set(self.device, None, self.device.hw) self.notes_widget = gui_util.DeviceNotesWidget(specialized_device) self.hide_notes_button = QtWidgets.QPushButton( clicked=self._toggle_hide_notes) self.set_notes_visible(False) self.tab_widget = QtWidgets.QTabWidget() self.tab_widget.setCornerWidget(self.hide_notes_button, Qt.TopRightCorner) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.notes_widget) layout.addWidget(self.tab_widget) layout.setStretch(1, 1)
def __init__(self, orientation=Qt.Horizontal, parent=None): super(SimpleToolBar, self).__init__(parent) self.orientation = orientation if orientation == Qt.Horizontal: self.setLayout(QtWidgets.QHBoxLayout()) else: self.setLayout(QtWidgets.QVBoxLayout()) self.layout().setSpacing(2) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addStretch(1)
def get_toolbar(self): tb = QtWidgets.QToolBar() for a in self.actions(): tb.addAction(a) return tb
def make_title_label(title): title_font = QtGui.QFont() title_font.setBold(True) label = QtWidgets.QLabel(title) label.setFont(title_font) label.setAlignment(Qt.AlignCenter) return label
def make_spinbox(min_value=None, max_value=None, value=None, limits=None, prefix=None, suffix=None, single_step=None, parent=None): ret = QtWidgets.QSpinBox(parent) if min_value is not None: ret.setMinimum(min_value) if max_value is not None: ret.setMaximum(max_value) if limits is not None: ret.setMinimum(limits[0]) ret.setMaximum(limits[1]) if prefix is not None: ret.setPrefix(prefix) if suffix is not None: ret.setSuffix(suffix) if single_step is not None: ret.setSingleStep(single_step) if value is not None: ret.setValue(value) return ret
def __init__(self, gui_app, parent=None): super(TutorialWidget, self).__init__(parent) self.gui_app = gui_app #self.setStyleSheet('background: lightyellow;') self.text_doc = QtGui.QTextDocument(self) f = QtCore.QFile(":/quickstart.html") if f.open(QtCore.QIODevice.ReadOnly): s = QtCore.QTextStream(f) html = s.readAll() else: html = "quickstart.html not found!" self.text_doc.setHtml(html) self.text_browser = TutorialTextBrowser(openLinks=False) self.text_browser.setDocument(self.text_doc) self.text_browser.href_hover.connect(self._on_href_hover) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.text_browser) self.flasher = UIFlasher(widget=self)
def paint(self, painter, option, index): node = index.internalPointer() option = QtWidgets.QStyleOptionViewItem(option) self.initStyleOption(option, index) if (option.state & QtWidgets.QStyle.State_Selected and isinstance(node, (ctm.DeviceNode, htm.DeviceNode)) and self.director.linked_mode): device = node.ref color = None if device.idc_conflict or device.address_conflict: color = QtGui.QColor('darkRed') elif device.has_hw and device.has_cfg: if device.hw.is_connected(): if device.config_applied is True: color = QtGui.QColor('darkGreen') elif device.config_applied is False: color = QtGui.QColor('darkOrange') # else config_applied should be None meaning "unknown" if color is not None: option.palette.setColor(QtGui.QPalette.Highlight, color) super(MCTreeItemDelegate, self).paint(painter, option, index)
def __init__(self, serial_ports_usb, serial_ports_serial, urls_in_use=list(), url=None, do_connect_default=True, autoconnect_default=True, title="Add MRC", parent=None): super(AddMRCDialog, self).__init__(parent) self.urls_in_use = urls_in_use self.ui = util.loadUi(":/ui/connect_dialog.ui") layout = QtWidgets.QHBoxLayout(self) layout.addWidget(self.ui) self.setWindowTitle(title) self.ui.buttonBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(False) self.ui.accepted.connect(self.accept) self.ui.rejected.connect(self.reject) for combo in (self.ui.combo_serial_port_usb, self.ui.combo_serial_port_serial): combo.setValidator( QtGui.QRegExpValidator(QtCore.QRegExp('.+'), None)) self.ui.le_tcp_host.setValidator( QtGui.QRegExpValidator(QtCore.QRegExp('.+'), None)) self.ui.le_mesycontrol_host.setValidator( QtGui.QRegExpValidator(QtCore.QRegExp('.+'), None)) self.ui.le_tcp_host.setText('localhost') self.ui.le_mesycontrol_host.setText('localhost') self.ui.cb_connect.setChecked(do_connect_default) self.ui.cb_autoconnect.setChecked(autoconnect_default) for port in serial_ports_usb: self.ui.combo_serial_port_usb.addItem(port) for port in serial_ports_serial: self.ui.combo_serial_port_serial.addItem(port) for le in self.ui.findChildren(QtWidgets.QLineEdit): le.textChanged.connect(self._validate_inputs) for combo in self.ui.findChildren(QtWidgets.QComboBox): combo.currentIndexChanged.connect(self._validate_inputs) combo.editTextChanged.connect(self._validate_inputs) for spin in self.ui.findChildren(QtWidgets.QSpinBox): spin.valueChanged.connect(self._validate_inputs) self.ui.stacked_widget.currentChanged.connect(self._validate_inputs) self._validate_inputs() self._result = None if url is not None: self._set_url(url)
def _create_actions(self): a = QtWidgets.QAction(QtGui.QIcon.fromTheme("edit-copy"), "&Copy", self, triggered=self._copy_action) a.setShortcut(QtGui.QKeySequence.Copy) a.setEnabled(False) self._actions['copy'] = a a = QtWidgets.QAction(QtGui.QIcon.fromTheme("edit-paste"), "&Paste", self, triggered=self._paste_action) a.setShortcut(QtGui.QKeySequence.Paste) a.setEnabled(False) self._actions['paste'] = a
def contextMenuEvent(self, event): menu = QtWidgets.QMenu() for a in self._actions.values(): if a.isEnabled(): menu.addAction(a) if not menu.isEmpty(): menu.exec_(self.mapToGlobal(event.pos()))
def addAction(self, action): super(FixedWidthVerticalToolBar, self).addAction(action) b = QtWidgets.QToolButton() b.setDefaultAction(action) self.layout().takeAt(self.layout().count() - 1) self.layout().addWidget(b, 0, Qt.AlignHCenter) self.layout().addStretch(1) self.setFixedWidth(self.sizeHint().width())
def make_apply_common_button_layout(input_spinbox, tooltip, on_clicked): # Wrapper to invoke the clicked handler without the boolean arg that's # passed from QPushButton.clicked(). def _on_clicked(): on_clicked() button = QtWidgets.QPushButton(clicked=_on_clicked) button.setIcon(QtGui.QIcon(":/arrow-bottom.png")) button.setMaximumHeight(input_spinbox.sizeHint().height()) button.setMaximumWidth(16) button.setToolTip(tooltip) layout = QtWidgets.QHBoxLayout() layout.addWidget(input_spinbox) layout.addWidget(button) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(1) return (layout, button)
def __init__(self, context, parent=None): super(MainWindow, self).__init__(parent) self.log = util.make_logging_source_adapter(__name__, self) self.context = context self.mdiArea = MCMdiArea() self.toolbar = self.addToolBar("toolbar") self.toolbar.setObjectName("toolbar") self.setWindowTitle("mesycontrol") self.setWindowIcon(make_icon(":/window-icon.png")) self.mdiArea.setLayout(QtWidgets.QGridLayout()) self.setCentralWidget(self.mdiArea) self.status_bar = QtWidgets.QStatusBar() self.setStatusBar(self.status_bar) self.actionQuickstart = QtWidgets.QAction("Quickstart") self.actionQuickstart.setShortcut("F1") self.menu_file = QtWidgets.QMenu("&File") self.menu_window = QtWidgets.QMenu("&Window") self.menu_help = QtWidgets.QMenu("&Help") self.menu_help.addAction(self.actionQuickstart) self.menu_help.addSeparator() self.menu_help.addAction("&About", self.on_actionAbout_triggered) self.menu_help.addAction("About &Qt", self.on_actionAbout_Qt_triggered) self.menu_bar = self.menuBar() self.menu_bar.addMenu(self.menu_file) self.menu_bar.addMenu(self.menu_help) # Treeview self.treeview = MCTreeView(app_registry=context.app_registry, device_registry=context.device_registry) dw_tree = QtWidgets.QDockWidget("Device tree", self) dw_tree.setObjectName("dw_treeview") dw_tree.setWidget(self.treeview) dw_tree.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | QtWidgets.QDockWidget.DockWidgetFloatable) self.addDockWidget(Qt.BottomDockWidgetArea, dw_tree) # Log view self.logview = log_view.LogView(parent=self) dw_logview = QtWidgets.QDockWidget("Application Log", self) dw_logview.setObjectName("dw_logview") dw_logview.setWidget(self.logview) dw_logview.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | QtWidgets.QDockWidget.DockWidgetFloatable) self.addDockWidget(Qt.BottomDockWidgetArea, dw_logview)
def __init__(self, device, parent=None): super(DeviceNotesWidget, self).__init__(parent) self.device = device device.read_mode_changed.connect(self._on_device_read_mode_changed) device.write_mode_changed.connect(self._on_device_write_mode_changed) device.extension_changed.connect(self._on_device_extension_changed) self.text_edit = NotesTextEdit() self.text_edit.setReadOnly(True) self.text_edit.modificationChanged.connect( self._on_text_edit_modification_changed) fm = self.text_edit.fontMetrics() rh = fm.lineSpacing() + DeviceNotesWidget.ADD_PIXELS_PER_ROW self.text_edit.setFixedHeight(DeviceNotesWidget.DISPLAY_ROWS * rh) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.text_edit) self.edit_button = QtWidgets.QPushButton(util.make_icon(":/edit.png"), str(), clicked=self._on_edit_button_clicked) self.edit_button.setToolTip("Edit Device Notes") self.edit_button.setStatusTip(self.edit_button.toolTip()) button_layout = QtWidgets.QVBoxLayout() button_layout.setContentsMargins(0, 0, 0, 0) button_layout.addWidget(self.edit_button, 0, Qt.AlignHCenter) button_layout.addStretch(1) layout.addLayout(button_layout) self._populate()
def __init__(self, title=str(), parent=None): super(SubProgressDialog, self).__init__(parent) self.log = util.make_logging_source_adapter(__name__, self) self.ui = util.loadUi(":/ui/subprogress_widget.ui") self.setWindowTitle(title) self.setWindowIcon(util.make_icon(":/window-icon.png")) l = QtWidgets.QHBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) l.setSpacing(0) l.addWidget(self.ui) self.resize(300, 100) self.ui.cancel_button.clicked.connect(self.cancel) self._reset()
def wrapper(*args, **kwargs): f = func(*args, **kwargs) if f.done(): return fo = FutureObserver(the_future=f) pd = QtWidgets.QProgressDialog() if not cancelable: pd.setCancelButton(None) fo.progress_range_changed.connect(pd.setRange) fo.progress_changed.connect(pd.setValue) fo.progress_text_changed.connect(pd.setLabelText) fo.done.connect(pd.close) pd.exec_()
def createEditor(self, parent, options, idx): if not self._is_device_rc(idx): return super(MCTreeItemDelegate, self).createEditor(parent, options, idx) combo = QtWidgets.QComboBox(parent) combo = AutoPopupComboBox(parent) combo.addItem("RC on", True) combo.addItem("RC off", False) # Hack to make the combobox commit immediately after the user selects # an item. def on_combo_activated(index): self.commitData.emit(combo) self.closeEditor.emit(combo, QtWidgets.QAbstractItemDelegate.NoHint) combo.activated.connect(on_combo_activated) return combo
def __init__(self, parent=None): super(FixedWidthVerticalToolBar, self).__init__(parent) self.setLayout(QtWidgets.QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addStretch(1)
def vline(parent=None): ret = QtWidgets.QFrame(parent) ret.setFrameShape(QtWidgets.QFrame.VLine) ret.setFrameShadow(QtWidgets.QFrame.Sunken) return ret
def on_actionAbout_triggered(self): try: from . import mc_version version = mc_version.version except ImportError: version = "devel version" d = QtWidgets.QDialog(self) d.setWindowTitle("About mesycontrol") license = QtWidgets.QTextBrowser(parent=d) license.setWindowFlags(Qt.Window) license.setWindowTitle("mesycontrol license") license.setText("") try: f = QtCore.QFile(":/gpl-notice.txt") if not f.open(QtCore.QIODevice.ReadOnly | QtCore.QIODevice.Text): return license.setPlainText(str(f.readAll(), 'utf-8')) finally: f.close() l = QtWidgets.QVBoxLayout(d) logo = QtWidgets.QLabel() logo.setPixmap( QtGui.QPixmap(":/mesytec-logo.png").scaledToWidth( 300, Qt.SmoothTransformation)) l.addWidget(logo) t = "mesycontrol - %s" % version label = QtWidgets.QLabel(t) font = label.font() font.setPointSize(15) font.setBold(True) label.setFont(font) l.addWidget(label) l.addWidget(QtWidgets.QLabel("Remote control for mesytec devices.")) l.addWidget(QtWidgets.QLabel("© 2014-2022 mesytec GmbH & Co. KG")) t = '<a href="mailto:[email protected]">[email protected]</a> - <a href="http://www.mesytec.com">www.mesytec.com</a>' label = QtWidgets.QLabel(t) label.setOpenExternalLinks(True) l.addWidget(label) t = 'Running on Python %s using PySide2 %s with Qt %s.' % ( platform.python_version(), PySide2.__version__, PySide2.QtCore.__version__) l.addWidget(QtWidgets.QLabel(t)) l.addSpacing(20) bl = QtWidgets.QHBoxLayout() def license_button_clicked(): sz = license.size() sz = sz.expandedTo(QtCore.QSize(500, 300)) license.resize(sz) license.show() license.raise_() b = QtWidgets.QPushButton("&License", clicked=license_button_clicked) bl.addWidget(b) b = QtWidgets.QPushButton("&Close", clicked=d.close) b.setAutoDefault(True) b.setDefault(True) bl.addWidget(b) l.addLayout(bl) for item in (l.itemAt(i) for i in range(l.count())): item.setAlignment(Qt.AlignHCenter) w = item.widget() if isinstance(w, QtWidgets.QLabel): w.setTextInteractionFlags(Qt.TextBrowserInteraction) d.exec_()
#!/usr/bin/env python # -*- coding: utf-8 -*- import random import sys from mesycontrol.qt import Qt from mesycontrol.qt import QtCore from mesycontrol.qt import QtGui from mesycontrol.qt import QtWidgets from mesycontrol.qt import PySide2 if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) centerWidget = QtWidgets.QWidget() centerLayout = QtWidgets.QVBoxLayout(centerWidget) for i in range(10): letterCount = random.randint(0, 10) buttonText = f"Button {i}" + "z" * letterCount button = QtWidgets.QToolButton() button.setText(buttonText) button.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) centerLayout.addWidget(button) centerLayout.addStretch(1) centerWidget.setFixedWidth(centerWidget.sizeHint().width()) leftTree = QtWidgets.QTreeView()
def __init__(self, bus=None, available_addresses=bm.ALL_DEVICE_ADDRESSES, known_idcs=list(), allow_custom_idcs=True, title="Add Device", selected_bus=None, selected_address=None, selected_idc=None, assigned_name=None, parent=None): """ Dialog constructor. If `bus' is given the dialog will use it as the selected bus and won't allow the user to change the bus. `available_addresses` should be a list of (bus, address) pairs. These address pairs will be available for the user to choose from. `known_idcs` should be a list of (idc, name) pairs. If `allow_custom_idcs` is True the user may enter a custom IDC, otherwise only IDCs from `known_idcs` are selectable. If `known_idcs' is empty and `allow_custom_idcs' is False this method will raise an exception. If `selected_bus` and `selected_address` is not None the corresponding item will be preselected in the GUI. If `selected_idc` is not None the device type will be set using the given IDC and will not be modifyable. """ if len(known_idcs) == 0 and not allow_custom_idcs: raise RuntimeError("No devices to choose from") if len(available_addresses) == 0 or ( bus is not None and util.ilen_destructive( filter(lambda x: x[0] == bus, available_addresses)) == 0): raise RuntimeError("No addresses available") super(AddDeviceDialog, self).__init__(parent) self.log = util.make_logging_source_adapter(__name__, self) self.setWindowTitle(title) self._result = None self.allow_custom_idcs = allow_custom_idcs self.bus_combo = QtWidgets.QComboBox() self.bus_combo.addItems([str(i) for i in bm.BUS_RANGE]) self.address_combos = [QtWidgets.QComboBox() for i in bm.BUS_RANGE] for b, a in sorted(available_addresses): self.address_combos[b].addItem("%X" % a, a) self.address_combo_stack = QtWidgets.QStackedWidget() for combo in self.address_combos: self.address_combo_stack.addWidget(combo) self.bus_combo.activated.connect( self.address_combo_stack.setCurrentIndex) self.idc_combo = EatReturnCombo() for idc, name in sorted(known_idcs, key=lambda x: x[1]): self.idc_combo.addItem("%s (%d)" % (name, idc), idc) if self.idc_combo.findData(idc) < 0: self.idc_combo.addItem(str(idc), idc) if selected_idc is not None: self.log.debug("selected_idc=%d, idx=%d", selected_idc, self.idc_combo.findData(selected_idc)) self.idc_combo.setCurrentIndex( self.idc_combo.findData(selected_idc)) self.idc_combo.setEnabled(False) if bus is not None: self.bus_combo.setCurrentIndex(bus) self.address_combo_stack.setCurrentIndex(bus) self.name_input = QtWidgets.QLineEdit() if assigned_name is not None: self.name_input.setText(assigned_name) self.button_box = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) if allow_custom_idcs: self.idc_combo.setEditable(True) self.idc_combo.setValidator(QtGui.QIntValidator(1, 99)) ok_button = self.button_box.button(QtWidgets.QDialogButtonBox.Ok) ok_button.setEnabled(len(known_idcs)) def combo_index_changed(): ok_button.setEnabled(True) def combo_le_text_edited(): ok_button.setEnabled( self.idc_combo.lineEdit().hasAcceptableInput()) self.idc_combo.currentIndexChanged.connect(combo_index_changed) self.idc_combo.lineEdit().textEdited.connect(combo_le_text_edited) if selected_bus is not None: assert selected_bus in bm.BUS_RANGE self.bus_combo.setCurrentIndex(selected_bus) self.address_combo_stack.setCurrentIndex(selected_bus) if selected_address is not None: assert selected_address in bm.DEV_RANGE combo = self.address_combo_stack.currentWidget() combo.setCurrentIndex(combo.findText("%X" % selected_address)) def accept(): bus = self.bus_combo.currentIndex() address = int(self.address_combos[bus].itemData( self.address_combos[bus].currentIndex())) if self.allow_custom_idcs and self.idc_combo.lineEdit( ).hasAcceptableInput(): idc = int(self.idc_combo.lineEdit().text()) else: idx = self.idc_combo.currentIndex() idc = int(self.idc_combo.itemData(idx)) name = self.name_input.text() self._result = AddDeviceDialog.Result(bus, address, idc, name) super(AddDeviceDialog, self).accept() self.button_box.accepted.connect(accept) self.button_box.rejected.connect(self.reject) layout = QtWidgets.QFormLayout(self) layout.addRow("Bus", self.bus_combo) layout.addRow("Address", self.address_combo_stack) layout.addRow("IDC", self.idc_combo) layout.addRow("Name", self.name_input) layout.addRow(self.button_box)
layout = QtWidgets.QFormLayout(self) layout.addRow("Bus", self.bus_combo) layout.addRow("Address", self.address_combo_stack) layout.addRow("IDC", self.idc_combo) layout.addRow("Name", self.name_input) layout.addRow(self.button_box) def result(self): return self._result if __name__ == "__main__": from functools import partial import sys a = QtWidgets.QApplication(sys.argv) dialogs = list() d = AddDeviceDialog() dialogs.append(d) d = AddDeviceDialog(bus=1) dialogs.append(d) d = AddDeviceDialog(available_addresses=[(0, 1), (1, 1), (0, 15), (1, 13)]) dialogs.append(d) d = AddDeviceDialog(bus=1, available_addresses=[(0, 1), (1, 1), (0, 15), (1, 13)]) dialogs.append(d)
def get_toolbar(self): if self._toolbar is None: self._toolbar = tb = QtWidgets.QToolBar() for a in self._actions.values(): tb.addAction(a) return self._toolbar
def __init__(self, device, display_mode=util.COMBINED, write_mode=util.COMBINED, parent=None): super(DeviceTableWidget, self).__init__(parent) self.log = util.make_logging_source_adapter(__name__, self) settings = util.loadUi(":/ui/device_tableview_settings.ui") self.log.debug("display_mode=%d, write_mode=%d", display_mode, write_mode) model = DeviceTableModel(device, display_mode=display_mode, write_mode=write_mode) self.view = DeviceTableView(model=model) sort_model = self.view.sort_model self.view.display_mode_changed.connect(self.display_mode_changed) self.view.write_mode_changed.connect(self.write_mode_changed) menu = QtWidgets.QMenu('Filter options', self) action = menu.addAction("Hide unknown") action.setCheckable(True) action.setChecked(sort_model.filter_unknown) action.triggered.connect(sort_model.set_filter_unknown) action = menu.addAction("Hide read-only") action.setCheckable(True) action.setChecked(sort_model.filter_readonly) action.triggered.connect(sort_model.set_filter_readonly) action = menu.addAction("Hide volatile") action.setCheckable(True) action.setChecked(sort_model.filter_volatile) action.triggered.connect(sort_model.set_filter_volatile) action = menu.addAction("Hide static") action.setCheckable(True) action.setChecked(sort_model.filter_static) action.triggered.connect(sort_model.set_filter_static) menu.addSeparator() action = menu.addAction("Ignore param ranges on edit") action.setCheckable(True) action.triggered.connect(model.set_editing_ignore_parameter_ranges) action = menu.addAction("Hexadecimal values") action.setCheckable(True) action.triggered.connect(model.set_display_hex_values) menu.addSeparator() action = menu.addAction("Resize table cells") action.triggered.connect(self.view.resizeColumnsToContents) action.triggered.connect(self.view.resizeRowsToContents) settings.pb_settings.setMenu(menu) settings.le_filter.textChanged.connect(sort_model.setFilterWildcard) layout = QtWidgets.QVBoxLayout() layout.addWidget(settings) layout.addWidget(self.view) self.setLayout(layout)
factory.append_predicate_binding( RadioButtonGroupParameterBinding.predicate, RadioButtonGroupParameterBinding) factory.append_classinfo_binding( QtWidgets.QLCDNumber, LCDNumberParameterBinding) factory.append_classinfo_binding( QtWidgets.QSlider, SliderParameterBinding) factory.append_predicate_binding( lambda target: target is None, TargetlessParameterBinding) if __name__ == "__main__": import mock app = QtWidgets.QApplication([]) device = mock.MagicMock() profile = mock.MagicMock() display_mode = util.CONFIG write_mode = util.COMBINED target = QtWidgets.QSpinBox() d = dict(device=device) binding = factory.make_binding(device=device, profile=profile, display_mode=display_mode, write_mode=write_mode, target=target) target2 = util.DelayedDoubleSpinBox() binding2 = factory.make_binding(device=device, profile=profile, display_mode=display_mode, write_mode=write_mode, unit_name="the_unit_name", target=target2)
def __init__(self, app_registry, device_registry, linked_mode_on=False, parent=None): super(MCTreeView, self).__init__(parent) self.log = util.make_logging_source_adapter(__name__, self) self._director = MCTreeDirector(app_registry=app_registry, device_registry=device_registry, linked_mode_on=linked_mode_on) self.cfg_model = self._director.cfg_model self.hw_model = self._director.hw_model self.cfg_view = ConfigTreeView() self.cfg_view.setObjectName('config_tree_view') self.cfg_view.setModel(self.cfg_model) self.cfg_model.rowsInserted.connect(self.cfg_view.expandAll) def on_cfg_rows_removed(parentIndex, start, end): self.log.debug( f"on_cfg_rows_removed parentIndex={parentIndex} start={start} end={end}" ) self.cfg_view.rowsRemoved(parentIndex, start, end) self.cfg_view.resizeColumnToContents(0) self.cfg_model.rowsRemoved.connect(on_cfg_rows_removed) def resize_cfg_cols(): self.cfg_view.resizeColumnToContents(0) self.cfg_model.rowsInserted.connect(resize_cfg_cols) self.cfg_view.customContextMenuRequested.connect( self._cfg_context_menu) self.cfg_view.expanded.connect(self._cfg_expanded) self.cfg_view.collapsed.connect(self._cfg_collapsed) self.cfg_view.setItemDelegate(MCTreeItemDelegate(self._director)) self.cfg_view.selectionModel().selectionChanged.connect( self._cfg_selection_changed) self.cfg_view.doubleClicked.connect(self._cfg_view_double_clicked) self.cfg_view.clicked.connect(self._cfg_view_clicked) self.hw_view = HardwareTreeView() self.hw_view.setObjectName('hardware_tree_view') self.hw_view.setModel(self.hw_model) self.hw_model.rowsInserted.connect(self.hw_view.expandAll) def on_hw_rows_removed(parentIndex, start, end): self.log.debug( f"on_hw_rows_removed parentIndex={parentIndex} start={start} end={end}" ) self.hw_view.rowsRemoved(parentIndex, start, end) self.hw_view.resizeColumnToContents(0) self.hw_model.rowsRemoved.connect(on_hw_rows_removed) def resize_hw_cols(): self.hw_view.resizeColumnToContents(0) self.hw_model.rowsInserted.connect(resize_hw_cols) self.hw_view.customContextMenuRequested.connect(self._hw_context_menu) self.hw_view.expanded.connect(self._hw_expanded) self.hw_view.collapsed.connect(self._hw_collapsed) self.hw_view.setItemDelegate(MCTreeItemDelegate(self._director)) self.hw_view.setFirstColumnSpanned(0, QtCore.QModelIndex(), True) self.hw_view.selectionModel().selectionChanged.connect( self._hw_selection_changed) self.hw_view.doubleClicked.connect(self._hw_view_double_clicked) self.hw_view.clicked.connect(self._hw_view_clicked) self.cfg_view.expandAll() self.hw_view.expandAll() self.splitter_toolbar = util.SimpleToolBar(Qt.Vertical) self.cfg_toolbar = util.SimpleToolBar(Qt.Horizontal) self.cfg_toolbar.layout().setContentsMargins(0, 0, 0, 0) self.hw_toolbar = util.SimpleToolBar(Qt.Horizontal) self.hw_toolbar.layout().setContentsMargins(0, 0, 0, 0) cfg_widget = QtWidgets.QGroupBox("Config") cfg_layout = QtWidgets.QVBoxLayout(cfg_widget) cfg_layout.setContentsMargins(2, 2, 2, 2) cfg_layout.addWidget(self.cfg_toolbar) cfg_layout.addWidget(self.cfg_view) cfg_layout.setStretch(1, 1) hw_widget = QtWidgets.QGroupBox("Hardware") hw_layout = QtWidgets.QVBoxLayout(hw_widget) hw_layout.setContentsMargins(2, 2, 2, 2) hw_layout.addWidget(self.hw_toolbar) hw_layout.addWidget(self.hw_view) hw_layout.setStretch(1, 1) center_widget = QtWidgets.QGroupBox("Actions") center_layout = QtWidgets.QVBoxLayout(center_widget) center_layout.setContentsMargins(2, 2, 2, 2) center_layout.addWidget(self.splitter_toolbar) self.center_widget = center_widget self.splitter = splitter = DoubleClickSplitter() splitter.setChildrenCollapsible(False) splitter.addWidget(hw_widget) splitter.addWidget(center_widget) splitter.addWidget(cfg_widget) def on_handle_double_clicked(): # make hw and cfg views the same size which will result in the # splitter buttons being centered sizes = splitter.sizes() size = (sizes[0] + sizes[2]) / 2 sizes[0], sizes[2] = size, size splitter.setSizes(sizes) splitter.handle(1).doubleClicked.connect(on_handle_double_clicked) splitter.handle(2).doubleClicked.connect(on_handle_double_clicked) layout = QtWidgets.QGridLayout(self) layout.addWidget(splitter, 0, 0) self._ignore_next_selection = False
def addAction(self, action) -> QtWidgets.QToolButton: super(SimpleToolBar, self).addAction(action) b = QtWidgets.QToolButton() b.setDefaultAction(action) self.addWidget(b) return b
finally: self.setTextColor(self._original_text_color) def contextMenuEvent(self, event): pos = event.globalPos() menu = self.createStandardContextMenu(pos) menu.addAction("Clear").triggered.connect(self.clear) menu.exec_(pos) if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG, format='[%(asctime)-15s] [%(name)s.%(levelname)s] %(message)s') qapp = QtGui.QApplication(sys.argv) log_view = LogView() log_view.resize(400, 400) log_view.show() qt_logger = util.QtLogEmitter() qt_logger.log_record.connect(log_view.handle_log_record) logging.getLogger().addHandler(qt_logger.get_handler()) logger = logging.getLogger(__name__) def on_button_clicked(): logging.getLogger("testlogger").debug("Hello World!") button = QtWidgets.QPushButton("Log!", clicked=on_button_clicked) button.show() sys.exit(qapp.exec_())
def mesycontrol_gui_main(): faulthandler.enable() if not is_windows: parser = argparse.ArgumentParser( description='mesycontrol GUI command line arguments') parser.add_argument('--logging-config', metavar='FILE') parser.add_argument('--setup', metavar='FILE') opts = parser.parse_args() else: opts = None # Logging setup if opts is not None and opts.logging_config is not None: logging.config.fileConfig(opts.logging_config) else: logging.basicConfig( level=logging.DEBUG, format='[%(asctime)-15s] [%(name)s.%(levelname)-8s] %(message)s') if colorlog and (not is_windows or colorama): fmt = '%(bg_blue)s[%(asctime)-15s]%(reset)s ' fmt += '[%(green)s%(name)s%(reset)s.%(log_color)s%(levelname)-8s%(reset)s] %(message)s' fmt = colorlog.ColoredFormatter(fmt) hdlr = logging.getLogger().handlers[0] hdlr.setFormatter(fmt) # Lower the log level for certain loggers. for ln in ( "basic_tree_model", "future", "mc_treeview", #"tcp_client.MCTCPClient", "hardware_controller.Controller", "PyQt4.uic"): logging.getLogger(ln).setLevel(logging.INFO) fn = QtCore.QStandardPaths.writableLocation( QtCore.QStandardPaths.DocumentsLocation) fn = os.path.join(str(fn), "mesycontrol.log") try: fh = logging.FileHandler(fn, "w") fh.setFormatter( logging.Formatter( fmt= '[%(asctime)-15s] [%(name)s.%(levelname)-8s] %(message)s')) logging.getLogger().addHandler(fh) except IOError: pass logging.info("Starting up...") logging.info("Running on Python version %s", sys.version) # Signal handling signal.signum_to_name = dict((getattr(signal, n), n) for n in dir(signal) if n.startswith('SIG') and '_' not in n) class SignalHandler(object): def __init__(self): self._called = False self._app = None def set_app(self, app): self._app = weakref.ref(app) def get_app(self): return self._app() if self._app is not None else None def __call__(self, signum, frame): if not self._called and self.get_app() is not None: logging.info("Received signal %s. Quitting...", signal.signum_to_name.get(signum, "%d" % signum)) self._called = True self.get_app().quit() else: logging.info("Received signal %s. Forcing quit...", signal.signum_to_name.get(signum, "%d" % signum)) QtWidgets.QApplication.quit() sigint_handler = SignalHandler() signal.signal(signal.SIGINT, sigint_handler) # Create an exception hook registry and register the original handler with # it. sys.excepthook = util.ExceptionHookRegistry() sys.excepthook.register_handler(sys.__excepthook__) # Qt setup QtCore.QLocale.setDefault(QtCore.QLocale.c()) QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts, True) app = QtWidgets.QApplication(sys.argv) app.setStyle(QtWidgets.QStyleFactory.create("Windows")) app.setAttribute(Qt.AA_DontShowIconsInMenus, False) # Let the interpreter run every 500 ms to be able to react to signals # arriving from the OS. timer = QtCore.QTimer() timer.timeout.connect(lambda: None) timer.start(500) # Confine garbage collection to the main thread to avoid crashes. garbage_collector = util.GarbageCollector() # Path setup main_file = sys.executable if getattr(sys, 'frozen', False) else __file__ bin_dir = os.path.abspath(os.path.dirname(main_file)) # Update the environments path to easily find the mesycontrol_server binary. os.environ['PATH'] = bin_dir + os.pathsep + os.environ['PATH'] logging.debug("main_file=%s, bin_dir=%s", main_file, bin_dir) # Application setup context = app_context.Context(main_file, auto_load_device_modules=False) setup_file = None settings = context.make_qsettings() if opts is not None and opts.setup is not None: setup_file = opts.setup elif bool( settings.value('Options/open_last_setup_at_start', True, type=bool)): setup_file = settings.value('Files/last_setup_file', str()) with app_context.use(context): mainwindow = gui_mainwindow.MainWindow(context) gui_application = gui.GUIApplication(context, mainwindow) sigint_handler.set_app(gui_application) mainwindow.show() mainwindow.restore_settings() if setup_file: try: context.open_setup(setup_file) except Exception as e: settings.remove('Files/last_setup_file') QtWidgets.QMessageBox.critical( mainwindow, "Error", "Opening setup file %s failed:\n%s" % (setup_file, e)) def on_qapp_about_to_quit(): logging.debug( "received signal QApplication.aboutToQuit(), calling Context.shutdown()" ) # Call shutdown() here while the eventloop (app.exec_()) is still running. context.shutdown() app.aboutToQuit.connect(on_qapp_about_to_quit) ret = app.exec_() logging.debug("app.exec_() returned %d", ret) del mainwindow del garbage_collector sys.exit(ret)