class PianoPanel(InstrumentPanel): def __init__(self): super().__init__(PianoInstrument()) self.name = 'Piano' self.initUI() def initUI(self): self.vbox = QVBoxLayout() # 往上对齐 self.vbox.setAlignment(Qt.AlignTop) self.fl = QHBoxLayout() self.fl.setAlignment(Qt.AlignTop) self.board = PianoBoard(self.instrument, 4) self.fl.addWidget(self.board) # 垂直布局 # self.vbox.addLayout(self.hbox) self.vbox.addLayout(self.fl) self.vbox.addWidget(self.detail) self.setLayout(self.vbox) def initPanel(self, num, notes=None): self.fl.removeWidget(self.board) self.board.deleteLater() self.currentNum = num self.board = PianoBoard(self.instrument, self.currentNum) self.board.highlightNotes(notes) self.fl.addWidget(self.board)
class RightPanel(FFrame): def __init__(self, app, parent=None): super().__init__(parent) self._app = app self.widget = None self._layout = QHBoxLayout(self) self.setLayout(self._layout) self.setObjectName('right_panel') self.set_theme_style() self.setup_ui() def set_theme_style(self): style_str = ''' #{0} {{ background: transparent; }} '''.format(self.objectName()) self.setStyleSheet(style_str) def set_widget(self, widget): if self.widget and self.widget != widget: self._layout.removeWidget(self.widget) self.widget.hide() widget.show() self._layout.addWidget(widget) else: self._layout.addWidget(widget) self.widget = widget def setup_ui(self): self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0)
class PlayersLayout(QWidget): def __init__(self, scheme: SchemePreset): super().__init__() self.scheme = scheme self.player_editors = [] # List[PlayerEditor] self._player_layout = QHBoxLayout(self) self.setLayout(self._player_layout) @property def players_count(self): return len(self.player_editors) def add_player(self): new_player_id = self.get_next_player_id() new_player_scheme_index = self.get_next_player_scheme_index() player_editor = PlayerEditor(player_id=new_player_id, initial_index=new_player_scheme_index, schemes=self.scheme) self.player_editors.append(player_editor) self._player_layout.addWidget(player_editor) def remove_player(self): item = self.player_editors.pop() self._player_layout.removeWidget(item) item.close() def get_next_player_id(self): return len(self.player_editors) + 1 def get_next_player_scheme_index(self): return len(self.player_editors) def get_players(self): return [i.create_player() for i in self.player_editors]
class TopBarView(QWidget): def __init__(self, tools): super().__init__() self.top_bars = {} for key in tools: self.top_bars[key] = tools[key].top_bar self.layout = QHBoxLayout() self.setFixedHeight(40) self.layout.setContentsMargins(0, 0, 0, 0) self.currentBar = self.top_bars['paint'] if self.currentBar is not None: self.layout.addWidget(self.currentBar) self.setAutoFillBackground(True) p = self.palette() p.setColor(self.backgroundRole(), Qt.darkGray) self.setPalette(p) self.setStyleSheet('color: white;') #self.layout.addStretch() self.setLayout(self.layout) # changes the top bar to the corresponding bar (of the clicked tool) def changeTopBar(self, name): #print("cleaning the widget") self.layout.removeWidget(self.currentBar) self.currentBar.setVisible(False) self.currentBar = self.top_bars[name] self.layout.addWidget(self.currentBar) #self.layout.addStretch() self.currentBar.setVisible(True)
class Tool(QFrame): def __init__(self, cfg): super().__init__() self.cfg = cfg self.custom_groups = {} self.selected_line_text = [] self.setFixedHeight(cfg["tool_height"]) # self.setStyleSheet("background-color: lightgrey") self.box = QHBoxLayout(self) self.word_line = LineEdit() # self.word_line.selectionChanged.connect(self.set_select_text) # self.word_line.editingFinished.connect(self.set_edit_text) self.search_btn = ToolBtn("search") self.config_btn = ToolBtn("config") self.box.addWidget(self.word_line) self.box.addWidget(self.search_btn) self.box.addWidget(CustomSpace(min_w=10)) # self.add_btn("uk") self.box.addStretch(1) self.box.addWidget(self.config_btn) # def set_select_text(self): self.selected_line_text.append(self.word_line.selectedText()) def set_edit_text(self): print(self.word_line.selectedText(), 888) @property def line_edit_text(self): return self.word_line.toPlainText() def set_line_validator(self, reg=None): if reg is None: reg = "[\d\w!]+" validator = QRegExpValidator(QRegExp(reg)) self.word_line.setValidator(validator) def set_custom_dict(self): self.custom_groups["dict"] = CustomButton("ru") self.box.insertWidget(3, self.custom_groups["dict"]) def del_custom_dict(self): try: self.box.removeWidget(self.custom_groups["dict"]) except KeyError: pass def selected_text(self): self.word_line.setFocus() cursor = self.word_line.textCursor() textSelected = cursor.selectedText() return textSelected
class ColorGroup(QWidget): def __init__(self, colors=None): super().__init__() self.widgets = [] self.layout = None self.set_colors(colors) def set_colors(self, colors): if self.layout is None: self.layout = QHBoxLayout() self.setLayout(self.layout) else: while len(self.widgets): widget = self.widgets.pop(0) self.layout.removeWidget(widget) widget.deleteLater() if colors: for x in colors: if x == 'vertex': widget = QLabel(x) else: widget = ColorWidget(color=x[1], text=x[0]) self.layout.addWidget(widget) self.widgets.append(widget) self.setLayout(self.layout)
class ShopWidget(QWidget): """Shop selection widget. A compound widget which consists of a QLabel showing the net income of the shop, a clickable button with its name and a QLabel with the QPixmap icon of the shop. The button is a subclass of QPushButton which has the ability to wrap text. """ clicked = pyqtSignal() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._layout = QHBoxLayout(self) self._money_label = QLabel('0', self) self._money_label.setStyleSheet('QLabel {color: grey}') self._money_label.setMaximumWidth(self._money_label.sizeHint().width()) self._button = QLabeledPushButton(self) self._button.clicked.connect(self.clicked.emit) self._icon = None self.initUi() def initUi(self): self._button.setFixedHeight(HEIGHT) self._money_label.setFixedHeight(HEIGHT) self._layout.addWidget(self._money_label) self._layout.addWidget(self._button) self._button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) def setText(self, text: str): self._button.setText(text) def set_money(self, money: int): if not isinstance(money, int): raise TypeError(f'Expected type: int, got: {type(money).__name__}') self._money_label.setText(f'{money:+}') self._money_label.setMaximumWidth(self._money_label.sizeHint().width()) if money < 0: self._money_label.setStyleSheet('QLabel {color: red}') elif money > 0: self._money_label.setStyleSheet('QLabel {color: green}') else: self._money_label.setStyleSheet('QLabel {color: grey}') def set_icon(self, pixmap: QPixmap): icon = QLabel() resized_pixmap = pixmap.scaled(HEIGHT, HEIGHT, Qt.KeepAspectRatio) icon.setPixmap(resized_pixmap) if self._icon is not None: self._layout.removeWidget(self._icon) self._icon = icon self._layout.addWidget(self._icon)
class GameView(QObject): unit_changed = pyqtSignal(UnitType) def __init__(self): super().__init__() self.game_window_ = QMainWindow() self.main_widget_ = QWidget() self.view_widget_ = QGraphicsView() self.british_creating_panel_ = UnitCreatingPanel( Game().get_british_player()) self.french_creating_panel_ = UnitCreatingPanel( Game().get_french_player()) self.current_creating_panel = self.british_creating_panel_ self.init_window() self.init_main_widget() self.british_creating_panel_.connect_radios(self.unit_changed) self.french_creating_panel_.connect_radios(self.unit_changed) def init_window(self): self.game_window_.setCentralWidget(self.main_widget_) self.game_window_.setWindowTitle('rly stupid game') self.game_window_.show() def init_main_widget(self): self.main_widget_.setMinimumSize(1000, 700) self.main_widget_layout = QHBoxLayout() self.main_widget_layout.addWidget(self.british_creating_panel_) self.main_widget_layout.addWidget(self.view_widget_) self.main_widget_.setLayout(self.main_widget_layout) def set_scene(self, scene): self.view_widget_.setScene(scene) scene.add_map_tiles() def update_after_adding_unit(self): self.british_creating_panel_.update_after_adding_unit() self.french_creating_panel_.update_after_adding_unit() def update_after_turn_change(self): self.main_widget_layout.removeWidget(self.current_creating_panel) self.current_creating_panel.hide() if self.current_creating_panel is self.british_creating_panel_: self.current_creating_panel = self.french_creating_panel_ self.main_widget_layout.addWidget(self.current_creating_panel) else: self.current_creating_panel = self.british_creating_panel_ self.main_widget_layout.insertWidget(0, self.current_creating_panel) self.current_creating_panel.show()
class PlayerConfWidget(QWidget): """docstring for PlayerConfWidget""" def __init__(self, **args): super(PlayerConfWidget, self).__init__() # props # main layout self.mainLayout = QHBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.widgets = [] # basic conf pal = QPalette(self.palette()) pal.setColor(QPalette.Background, QColor('#DDD')) self.setAutoFillBackground(True) self.setPalette(pal) # init ui self.initUI(args) def initUI(self, args): conf = propConf['player'] args = args['args'] brief = conf['brief'] print(brief) for key in brief.keys(): value = brief[key] name = '%s : %s ' if 'player' in args: p = args['player'] name = name % (value, str(p[key])) else: name = 'New player' label = QLabel(name) self.mainLayout.addWidget(label) self.widgets.append(label) self.mainLayout.addStretch() # self.saveBtn = QPushButton('Save') # self.saveBtn.setStyleSheet('border-radius: 0;background-color: %s' % (SAVE_BTN_COLOR)) # self.mainLayout.addWidget(self.saveBtn) self.deleteBtn = QPushButton('Delete') self.deleteBtn.setStyleSheet(DELETE_BTN_QSS) self.mainLayout.addWidget(self.deleteBtn) def reset(self): for widget in self.widgets: self.mainLayout.removeWidget(widget) widget.deleteLater() self.widgets = []
class NetworkLabel(QLabel): def __init__(self, parent): super().__init__() if parent: self.setParent(parent) self.setGeometry(300, 300, 900, 30) self.num = 0 self.label_num = 20 self.config = {} self.currentlab = "" self.setObjectName("main") self.setStyleSheet(NetworkLbel_style) self.main_layout = QHBoxLayout() self.main_layout.setContentsMargins(0, 1, 0, 1) self.main_layout.setSpacing(0) self.setLayout(self.main_layout) self.show() def addlabel(self, label: QLabel): self.num += 1 label.setParent(self) self.currentlab = "label" + str(self.num) self.config[self.currentlab] = {} self.config[self.currentlab]["widget"] = label def set_first_btn(self, btn: QPushButton): self.config[self.currentlab]["firstbtn"] = btn def set_close_btn(self, btn: QPushButton): self.config[self.currentlab]["closebtn"] = btn btn.clicked.connect(self.close_btn_label_close) def close_btn_label_close(self): self.num -= 1 self.sender().parent().close() for s in self.config.keys(): if self.config[s]["closebtn"] == self.sender(): del self.config[s] break self.add_layout() def add_layout(self): print(self.config) for s in self.children(): if s.isWidgetType(): self.main_layout.removeWidget(s) for d in self.config.keys(): self.main_layout.addWidget(self.config[d]["widget"], 1) if self.num < self.label_num: self.main_layout.addWidget(QFrame(self), self.label_num - self.num)
class Example(QWidget): def __init__(self): super().__init__() self.msh = int(input('Уровень маштабирования(от 0 до 17):')) self.initUI() def initUI(self): self.setGeometry(100, 100, *SCREEN_SIZE) self.hbox = QHBoxLayout(self) self.coords = [37.530887, 55.703118] self.setLayout(self.hbox) self.lbl = QLabel(self) self.show_image() def closeEvent(self, event): os.remove(self.map_file) def show_image(self): self.map_file = "map.png" response = requests.get( f"http://static-maps.yandex.ru/1.x/?ll={self.coords[0]},{self.coords[1]}&z={self.msh}&l=map" ) with open(self.map_file, "wb") as file: file.write(response.content) if self.lbl is not None: self.hbox.removeWidget(self.lbl) pixmap = QPixmap(self.map_file) self.lbl.setPixmap(pixmap) self.hbox.addWidget(self.lbl) def keyReleaseEvent(self, event): if event.key() == Qt.Key_PageUp: if self.msh > 1: self.msh -= 1 if event.key() == Qt.Key_PageDown: if self.msh < 14: self.msh += 1 if event.key() == Qt.Key_Up: self.coords[1] += (15 - self.msh) / (5 * self.msh) if event.key() == Qt.Key_Down: self.coords[1] -= (15 - self.msh) / (5 * self.msh) if event.key() == Qt.Key_Left: self.coords[0] -= (15 - self.msh) / (5 * self.msh) if event.key() == Qt.Key_Right: self.coords[0] += (15 - self.msh) / (5 * self.msh) self.show_image()
class SearchBox: searchFields = [] program = None #Use this group for keyword combinations def __init__(self): self.groupBox = QGroupBox("or:") #One initial search field self.searchTerm1 = LineEditColor("Example") self.searchFields.append(self.searchTerm1) #Add it to a vbox self.row = QHBoxLayout() #Add the vbox to a container #self.row.addStretch(1) self.groupBox.setLayout(self.row) #Create button for creating more search fields self.addButton = QPushButton("+") self.addButton.clicked.connect(lambda: self.AddSearchField()) self.row.addWidget(self.addButton) self.row.setAlignment(self.searchTerm1, Qt.AlignLeft) self.groupBox.setAlignment(Qt.AlignLeft) def AddSearchField(self): newST = LineEditColor("") self.searchFields.append(newST) self.addLabel = QLabel("&") self.addLabel.setFixedWidth(10) self.row.addWidget(self.addLabel, Qt.AlignLeft) self.row.addWidget(newST.colorPicker) self.row.addWidget(newST, Qt.AlignLeft) self.row.removeWidget(self.addButton) self.row.addWidget(self.addButton) def Get(self, title): self.groupBox.setTitle(title) return self.groupBox
def organizeWidgets(self, init, availableWidth=None): if not init: for i in reversed(range(self.cbArea.count())): item = self.cbArea.itemAt(i) if isinstance(item, QLayoutItem): layout = item.layout() for j in reversed(range(layout.count())): widget = layout.itemAt(j).widget() if widget is not None: layout.removeWidget(widget) else: print("ERR") else: print("Err") self.cbArea.removeItem(item) item.deleteLater() self.width_needed = None i = 0 while i < len(self.cbList): line = QHBoxLayout() columnCount = 0 while True: if availableWidth is not None and line.minimumSize().width( ) >= availableWidth: if columnCount > 1: i -= 1 line.removeWidget(self.cbList[i]) overlap = line.minimumSize().width() - availableWidth if self.width_needed is None: self.width_needed = overlap else: self.width_needed = min(self.width_needed, overlap) break elif i >= len(self.cbList): break else: line.addWidget(self.cbList[i]) i += 1 columnCount += 1 self.cbArea.addLayout(line)
class ThumbnailRow(QWidget): def __init__(self): super().__init__() self.labels = [] self.layout = QHBoxLayout() self.layout.setSpacing(3) self.layout.setContentsMargins(3, 0, 0, 3) self.setLayout(self.layout) self.items = [] def add_items(self, items): self.items = items self.draw_items() def draw_items(self): self.clear() for item in self.items: thumbnail = Thumbnail(item) self.layout.addWidget(thumbnail, 0) self.layout.addWidget(QWidget(), 1) def clear(self): for i in reversed(range(self.layout.count())): widget = self.layout.itemAt(i).widget() # remove it from the layout list self.layout.removeWidget(widget) # remove it from the gui widget.setParent(None) def zoom(self, scale): for i in reversed(range(self.layout.count())): widget = self.layout.itemAt(i).widget() if isinstance(widget, Thumbnail): widget.zoom(scale) def mousePressEvent(self, a0: QtGui.QMouseEvent): print("Mouse Press") def mouseDoubleClickEvent(self, a0: QtGui.QMouseEvent): print("Mouse Double Click")
class PlayerWidget(QWidget): """docstring for PlayerWidget""" def __init__(self, **args): super(PlayerWidget, self).__init__() # props self.widgets = [] self.mainLayout = QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.confLayout = QHBoxLayout() self.confLayout.setContentsMargins(0, 0, 0, 0) # TODO # create an empty players def initData(self, **args): self.reset() if 'args' in args: args = args['args'] if 'player' in args: playerWidget = PlayerConfWidget(args = args) self.mainLayout.addWidget(playerWidget) self.widgets.append(playerWidget) self.mainLayout.addLayout(self.confLayout) if 'generals' in args: generalWidget = ConfWidget(catagory = 'generals', args = args) self.confLayout.addWidget(generalWidget) self.widgets.append(generalWidget) if 'buildings' in args: buildingWidget = ConfWidget(catagory = 'buildings', args = args) self.confLayout.addWidget(buildingWidget) self.widgets.append(buildingWidget) if 'slave_buildings' in args: slaveBuildingsWidget = ConfWidget(catagory = 'slave_buildings', args = args) self.confLayout.addWidget(slaveBuildingsWidget) self.widgets.append(slaveBuildingsWidget) def reset(self): for widget in self.widgets: self.mainLayout.removeWidget(widget) self.confLayout.removeWidget(widget) widget.reset() self.widgets = []
class ShopWidget(QWidget): """Shop selection widget. A compound widget which consists of a QLabel showing the net income of the shop, a clickable button with its name and a QLabel with the QPixmap icon of the shop. The button is a subclass of QPushButton which has the ability to wrap text. """ clicked = pyqtSignal() def __init__(self, shop_id: int, *args, **kwargs): super().__init__(*args, **kwargs) self._layout = QHBoxLayout(self) self._button = QLabeledPushButton(self) self._button.clicked.connect(self.clicked.emit) self._icon = None self._id = shop_id self.initUi() def initUi(self): self._button.setFixedHeight(HEIGHT) self._layout.addWidget(self._button) self._button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) def setText(self, text: str): self._button.setText(text) def set_icon(self, pixmap: QPixmap): icon = QLabel() resized_pixmap = pixmap.scaled(HEIGHT, HEIGHT, Qt.KeepAspectRatio) icon.setPixmap(resized_pixmap) if self._icon is not None: self._layout.removeWidget(self._icon) self._icon = icon self._layout.addWidget(self._icon) def get_shop_id(self): return self._id
class QCustomQWidget(QWidget): def __init__(self, parent=None): super(QCustomQWidget, self).__init__(parent) self.textQVBoxLayout = QVBoxLayout() self.textUpQLabel = QLabel() self.textDownQLabel = QLabel() self.textQVBoxLayout.addWidget(self.textUpQLabel) self.textQVBoxLayout.addWidget(self.textDownQLabel) self.allQHBoxLayout = QHBoxLayout() self.iconQLabel = QLabel() self.allQHBoxLayout.addWidget(self.iconQLabel, 0) self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1) self.setLayout(self.allQHBoxLayout) # setStyleSheet self.textUpQLabel.setStyleSheet(''' color: rgb(0, 0, 255); ''') self.textDownQLabel.setStyleSheet(''' color: rgb(255, 0, 0); ''') def setTextUp(self, text): self.textUpQLabel.setText(text) def setTextDown(self, text): self.textDownQLabel.setText(text) def setIcon(self, imagePath): self.iconQLabel.setPixmap(QPixmap(imagePath)) def cleared(self): item = self.allQHBoxLayout if item != None: widget = item.widget() if widget != None: self.allQHBoxLayout.removeWidget(widget) widget.deleteLater()
class StatusBar(QWidget): """The statusbar at the bottom of the mainwindow. Attributes: txt: The Text widget in the statusbar. keystring: The KeyString widget in the statusbar. percentage: The Percentage widget in the statusbar. url: The UrlText widget in the statusbar. prog: The Progress widget in the statusbar. cmd: The Command widget in the statusbar. _hbox: The main QHBoxLayout. _stack: The QStackedLayout with cmd/txt widgets. _win_id: The window ID the statusbar is associated with. Signals: resized: Emitted when the statusbar has resized, so the completion widget can adjust its size to it. arg: The new size. moved: Emitted when the statusbar has moved, so the completion widget can move to the right position. arg: The new position. """ resized = pyqtSignal('QRect') moved = pyqtSignal('QPoint') _severity = None _color_flags = [] STYLESHEET = _generate_stylesheet() def __init__(self, *, win_id, private, parent=None): super().__init__(parent) objreg.register('statusbar', self, scope='window', window=win_id) self.setObjectName(self.__class__.__name__) self.setAttribute(Qt.WA_StyledBackground) config.set_register_stylesheet(self) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self._win_id = win_id self._color_flags = ColorFlags() self._color_flags.private = private self._hbox = QHBoxLayout(self) self._set_hbox_padding() self._hbox.setSpacing(5) self._stack = QStackedLayout() self._hbox.addLayout(self._stack) self._stack.setContentsMargins(0, 0, 0, 0) self.cmd = command.Command(private=private, win_id=win_id) self._stack.addWidget(self.cmd) objreg.register('status-command', self.cmd, scope='window', window=win_id) self.txt = textwidget.Text() self._stack.addWidget(self.txt) self.cmd.show_cmd.connect(self._show_cmd_widget) self.cmd.hide_cmd.connect(self._hide_cmd_widget) self._hide_cmd_widget() self.url = url.UrlText() self.percentage = percentage.Percentage() self.backforward = backforward.Backforward() self.tabindex = tabindex.TabIndex() self.keystring = keystring.KeyString() self.prog = progress.Progress(self) self._draw_widgets() config.instance.changed.connect(self._on_config_changed) QTimer.singleShot(0, self.maybe_hide) def __repr__(self): return utils.get_repr(self) @pyqtSlot(str) def _on_config_changed(self, option): if option == 'statusbar.hide': self.maybe_hide() elif option == 'statusbar.padding': self._set_hbox_padding() elif option == 'statusbar.widgets': self._draw_widgets() def _draw_widgets(self): """Draw statusbar widgets.""" # Start with widgets hidden and show them when needed for widget in [self.url, self.percentage, self.backforward, self.tabindex, self.keystring, self.prog]: widget.hide() self._hbox.removeWidget(widget) tab = self._current_tab() # Read the list and set widgets accordingly for segment in config.val.statusbar.widgets: if segment == 'url': self._hbox.addWidget(self.url) self.url.show() elif segment == 'scroll': self._hbox.addWidget(self.percentage) self.percentage.show() elif segment == 'scroll_raw': self._hbox.addWidget(self.percentage) self.percentage.raw = True self.percentage.show() elif segment == 'history': self._hbox.addWidget(self.backforward) self.backforward.enabled = True if tab: self.backforward.on_tab_changed(tab) elif segment == 'tabs': self._hbox.addWidget(self.tabindex) self.tabindex.show() elif segment == 'keypress': self._hbox.addWidget(self.keystring) self.keystring.show() elif segment == 'progress': self._hbox.addWidget(self.prog) self.prog.enabled = True if tab: self.prog.on_tab_changed(tab) @pyqtSlot() def maybe_hide(self): """Hide the statusbar if it's configured to do so.""" tab = self._current_tab() hide = config.val.statusbar.hide if hide or (tab is not None and tab.data.fullscreen): self.hide() else: self.show() def _set_hbox_padding(self): padding = config.val.statusbar.padding self._hbox.setContentsMargins(padding.left, 0, padding.right, 0) @pyqtProperty('QStringList') def color_flags(self): """Getter for self.color_flags, so it can be used as Qt property.""" return self._color_flags.to_stringlist() def _current_tab(self): """Get the currently displayed tab.""" window = objreg.get('tabbed-browser', scope='window', window=self._win_id) return window.widget.currentWidget() def set_mode_active(self, mode, val): """Setter for self.{insert,command,caret}_active. Re-set the stylesheet after setting the value, so everything gets updated by Qt properly. """ if mode == usertypes.KeyMode.insert: log.statusbar.debug("Setting insert flag to {}".format(val)) self._color_flags.insert = val if mode == usertypes.KeyMode.passthrough: log.statusbar.debug("Setting passthrough flag to {}".format(val)) self._color_flags.passthrough = val if mode == usertypes.KeyMode.command: log.statusbar.debug("Setting command flag to {}".format(val)) self._color_flags.command = val elif mode in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]: log.statusbar.debug("Setting prompt flag to {}".format(val)) self._color_flags.prompt = val elif mode == usertypes.KeyMode.caret: if not val: # Turning on is handled in on_current_caret_selection_toggled log.statusbar.debug("Setting caret mode off") self._color_flags.caret = ColorFlags.CaretMode.off config.set_register_stylesheet(self, update=False) def _set_mode_text(self, mode): """Set the mode text.""" if mode == 'passthrough': key_instance = config.key_instance all_bindings = key_instance.get_reverse_bindings_for('passthrough') bindings = all_bindings.get('leave-mode') if bindings: suffix = ' ({} to leave)'.format(bindings[0]) else: suffix = '' else: suffix = '' text = "-- {} MODE --{}".format(mode.upper(), suffix) self.txt.set_text(self.txt.Text.normal, text) def _show_cmd_widget(self): """Show command widget instead of temporary text.""" self._stack.setCurrentWidget(self.cmd) self.show() def _hide_cmd_widget(self): """Show temporary text instead of command widget.""" log.statusbar.debug("Hiding cmd widget") self._stack.setCurrentWidget(self.txt) self.maybe_hide() @pyqtSlot(str) def set_text(self, val): """Set a normal (persistent) text in the status bar.""" self.txt.set_text(self.txt.Text.normal, val) @pyqtSlot(usertypes.KeyMode) def on_mode_entered(self, mode): """Mark certain modes in the commandline.""" keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) if keyparsers[mode].passthrough: self._set_mode_text(mode.name) if mode in [usertypes.KeyMode.insert, usertypes.KeyMode.command, usertypes.KeyMode.caret, usertypes.KeyMode.prompt, usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough]: self.set_mode_active(mode, True) @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode) def on_mode_left(self, old_mode, new_mode): """Clear marked mode.""" keyparsers = objreg.get('keyparsers', scope='window', window=self._win_id) if keyparsers[old_mode].passthrough: if keyparsers[new_mode].passthrough: self._set_mode_text(new_mode.name) else: self.txt.set_text(self.txt.Text.normal, '') if old_mode in [usertypes.KeyMode.insert, usertypes.KeyMode.command, usertypes.KeyMode.caret, usertypes.KeyMode.prompt, usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough]: self.set_mode_active(old_mode, False) @pyqtSlot(browsertab.AbstractTab) def on_tab_changed(self, tab): """Notify sub-widgets when the tab has been changed.""" self.url.on_tab_changed(tab) self.prog.on_tab_changed(tab) self.percentage.on_tab_changed(tab) self.backforward.on_tab_changed(tab) self.maybe_hide() assert tab.private == self._color_flags.private @pyqtSlot(bool) def on_caret_selection_toggled(self, selection): """Update the statusbar when entering/leaving caret selection mode.""" log.statusbar.debug("Setting caret selection {}".format(selection)) if selection: self._set_mode_text("caret selection") self._color_flags.caret = ColorFlags.CaretMode.selection else: self._set_mode_text("caret") self._color_flags.caret = ColorFlags.CaretMode.on config.set_register_stylesheet(self, update=False) def resizeEvent(self, e): """Extend resizeEvent of QWidget to emit a resized signal afterwards. Args: e: The QResizeEvent. """ super().resizeEvent(e) self.resized.emit(self.geometry()) def moveEvent(self, e): """Extend moveEvent of QWidget to emit a moved signal afterwards. Args: e: The QMoveEvent. """ super().moveEvent(e) self.moved.emit(e.pos()) def minimumSizeHint(self): """Set the minimum height to the text height plus some padding.""" padding = config.val.statusbar.padding width = super().minimumSizeHint().width() height = self.fontMetrics().height() + padding.top + padding.bottom return QSize(width, height)
class SourceWidget(QWidget): """ Used to display summary information about a source in the list view. """ def __init__(self, parent, source): """ Set up the child widgets. """ super().__init__(parent) self.source = source self.name = QLabel() self.updated = QLabel() layout = QVBoxLayout() self.setLayout(layout) self.summary = QWidget(self) self.summary_layout = QHBoxLayout() self.summary.setLayout(self.summary_layout) self.attached = load_svg('paperclip.svg') self.attached.setMaximumSize(16, 16) self.summary_layout.addWidget(self.name) self.summary_layout.addStretch() self.summary_layout.addWidget(self.attached) layout.addWidget(self.summary) layout.addWidget(self.updated) self.delete = load_svg('cross.svg') self.delete.setMaximumSize(16, 16) self.delete.mouseReleaseEvent = self.delete_source self.summary_layout.addWidget(self.delete) self.update() def setup(self, controller): """ Pass through the controller object to this widget. """ self.controller = controller def display_star_icon(self): """ Show the correct star icon """ if getattr(self, 'starred', None): # Delete icon if it exists. self.summary_layout.removeWidget(self.starred) if self.source.is_starred: self.starred = load_svg('star_on.svg') else: self.starred = load_svg('star_off.svg') self.summary_layout.addWidget(self.starred) self.starred.setMaximumSize(16, 16) self.starred.mousePressEvent = self.toggle_star def update(self): """ Updates the displayed values with the current values from self.source. """ self.updated.setText(arrow.get(self.source.last_updated).humanize()) self.display_star_icon() self.name.setText("<strong>{}</strong>".format( html.escape(self.source.journalist_designation))) if self.source.document_count == 0: self.attached.hide() def toggle_star(self, event): """ Called when the star is clicked. """ self.controller.update_star(self.source) def delete_source(self, event): if self.controller.api is None: self.controller.on_action_requiring_login() return else: messagebox = DeleteSourceMessageBox(self, self.source, self.controller) messagebox.launch()
class MessageBox(QWidget): def __init__(self, parent, error=None, helpword=None, index=choiceIndex): super().__init__() self.helpword = helpword self.layout = QHBoxLayout(self) self.parent = parent self.index = str(index) self.screen_geomtery = QDesktopWidget().screenGeometry(-1) self.width = self.screen_geomtery.width() self.height = self.screen_geomtery.height() self.path = None self.add_browser = None self.setWindowIcon(QIcon('resources/Python-logo-notext.svg_.png')) self.initUI() def initUI(self): self.label = QLabel() self.layout.addWidget(self.label) self.deleteButton = QPushButton("Yes") self.button = QPushButton("No") self.cancel = QPushButton("Cancel") self.getHelpButton = QPushButton("Yes") self.closeAnywayButton = QPushButton() self.getHelpButton.setAutoDefault(True) self.saveButton = QPushButton("Save") self.deleteButton.clicked.connect(self.delete) self.cancel.clicked.connect(self.dont) self.button.clicked.connect(self.dont) self.getHelpButton.clicked.connect(self.gettingHelp) self.saved = None self.center() self.font = QFont() self.font.setFamily("Iosevka") self.font.setPointSize(12) self.setFont(self.font) def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def run(self, str, fileName): self.fileName = fileName baseName = os.path.basename(self.fileName) self.label.setText(str + baseName + " ?") self.deleteButton.setAutoDefault(True) self.layout.addWidget(self.deleteButton) self.layout.addWidget(self.button) self.show() def delete(self): if os.path.isdir(self.fileName): # If it is a directory shutil.rmtree(self.fileName) else: os.remove(self.fileName) self.hide() def dont(self): self.hide() def confirmation(self, index): self.label.setText \ ("Theme " + str(index) + " selected\nNOTE: For some changes to work you need to restart PyPad") self.button.setText("Ok") self.button.setAutoDefault(True) self.button.setFocus() self.layout.addWidget(self.button) self.show() def success(self, directory): def _exit(): self.hide() self.successButton = QPushButton("Ok") self.successButton.resize(10, 30) self.successLabel = QLabel() self.successLabel.setText("Successfully created a new project to: " + str(directory)) self.successButton.clicked.connect(_exit) self.layout.addWidget(self.successLabel) self.layout.addWidget(self.successButton) self.show() def saveMaybe(self, file, tabCounter, tab, index): def _closeAnyway(): try: file.deleteLater() tabCounter.pop(index) tab.removeTab(index) self.hide() except (IndexError, RuntimeError) as E: print(E, " on line 125 in the file Messagebox.py") def _hide(): self.hide() self.label.setText("<b>Warning</b>, you have unsaved changes!") self.saveButton.setText("Ok") self.saveButton.setAutoDefault(True) self.closeAnywayButton.setText("Close anyway") self.saveButton.clicked.connect(_hide) self.closeAnywayButton.clicked.connect(_closeAnyway) self.layout.addWidget(self.saveButton) self.layout.addWidget(self.closeAnywayButton) self.show() def gettingHelp(self): self.url = "https://duckduckgo.com/?q=" + str(self.helpword) self.add_browser.showBrowser( self.url, self.helpword ) # self.add_browser should have the value <__main__.Main self.hide() # DONE def noMatch(self, word): self.label.setText("No matches found for word: " + str(word)) self.button.setText("Ok") self.button.setAutoDefault(True) self.layout.addWidget(self.button) self.show() # DONE def newProject(self): cwd = os.getcwd() self.vertical = QVBoxLayout() def createFolder(): try: folderName = self.textField.text() directory = self.ProjectDirectory.text() if not os.path.exists(folderName): self.path = str(directory) + str(folderName) os.makedirs(self.path) self.hide() self.success(self.path) else: print("File already exists") except Exception as E: print(E, " on line 176 in the file Messagebox.py") self.setWindowTitle("New project") self.projectLabel = QLabel() self.directoryLabel = QLabel() self.directoryLabel.setText("Where do you want to create it?") self.projectLabel.setText("Enter a new project name: ") self.ProjectDirectory = QLineEdit() self.ProjectDirectory.setText(cwd) self.textField = QLineEdit() self.textFieldButton = QPushButton("Create") self.textFieldButton.clicked.connect(createFolder) self.vertical.addWidget(self.projectLabel) self.vertical.addWidget(self.textField) self.vertical.addWidget(self.directoryLabel) self.vertical.addWidget(self.ProjectDirectory) self.vertical.addWidget(self.textFieldButton) self.vertical.addWidget(self.cancel) self.layout.removeWidget(self.label) self.layout.addLayout(self.vertical) self.setLayout(self.layout) self.show() # def getHelp(self, paren): self.add_browser = paren try: self.layout.removeWidget(self.deleteButton) self.layout.removeWidget(self.button) except AttributeError as E: print(E, " on line 208 in the file Messagebox.py") self.label.setText( "It seems like you made an error, would you like to get help?") self.layout.addWidget(self.getHelpButton) self.layout.addWidget(self.button) config = editor if config["errorMessages"] is True: self.show() else: self.hide()
class ESCPanel(QDialog): DEFAULT_INTERVAL = 0.1 CMD_BIT_LENGTH = uavcan.get_uavcan_data_type(uavcan.equipment.esc.RawCommand().cmd).value_type.bitlen CMD_MAX = 2 ** (CMD_BIT_LENGTH - 1) - 1 CMD_MIN = -(2 ** (CMD_BIT_LENGTH - 1)) def __init__(self, parent, node): super(ESCPanel, self).__init__(parent) self.setWindowTitle('ESC Management Panel') self.setAttribute(Qt.WA_DeleteOnClose) # This is required to stop background timers! self._node = node self._sliders = [PercentSlider(self) for _ in range(5)] self._num_sliders = QSpinBox(self) self._num_sliders.setMinimum(len(self._sliders)) self._num_sliders.setMaximum(20) self._num_sliders.setValue(len(self._sliders)) self._num_sliders.valueChanged.connect(self._update_number_of_sliders) self._bcast_interval = QDoubleSpinBox(self) self._bcast_interval.setMinimum(0.01) self._bcast_interval.setMaximum(1.0) self._bcast_interval.setSingleStep(0.1) self._bcast_interval.setValue(self.DEFAULT_INTERVAL) self._bcast_interval.valueChanged.connect( lambda: self._bcast_timer.setInterval(self._bcast_interval.value() * 1e3)) self._stop_all = make_icon_button('hand-stop-o', 'Zero all channels', self, text='Stop All', on_clicked=self._do_stop_all) self._pause = make_icon_button('pause', 'Pause publishing', self, checkable=True, text='Pause') self._msg_viewer = QPlainTextEdit(self) self._msg_viewer.setReadOnly(True) self._msg_viewer.setLineWrapMode(QPlainTextEdit.NoWrap) self._msg_viewer.setFont(get_monospace_font()) self._msg_viewer.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._msg_viewer.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._bcast_timer = QTimer(self) self._bcast_timer.start(self.DEFAULT_INTERVAL * 1e3) self._bcast_timer.timeout.connect(self._do_broadcast) layout = QVBoxLayout(self) self._slider_layout = QHBoxLayout(self) for sl in self._sliders: self._slider_layout.addWidget(sl) layout.addLayout(self._slider_layout) layout.addWidget(self._stop_all) controls_layout = QHBoxLayout(self) controls_layout.addWidget(QLabel('Channels:', self)) controls_layout.addWidget(self._num_sliders) controls_layout.addWidget(QLabel('Broadcast interval:', self)) controls_layout.addWidget(self._bcast_interval) controls_layout.addWidget(QLabel('sec', self)) controls_layout.addStretch() controls_layout.addWidget(self._pause) layout.addLayout(controls_layout) layout.addWidget(QLabel('Generated message:', self)) layout.addWidget(self._msg_viewer) self.setLayout(layout) self.resize(self.minimumWidth(), self.minimumHeight()) def _do_broadcast(self): try: if not self._pause.isChecked(): msg = uavcan.equipment.esc.RPMCommand() for sl in self._sliders: # raw_value = sl.get_value() / 100100 raw_value = sl.get_value() # value = (-self.CMD_MIN if raw_value < 0 else self.CMD_MAX) * raw_value value = (-30 if raw_value < 0 else 30) * raw_value msg.rpm.append(int(value)) self._node.broadcast(msg) self._msg_viewer.setPlainText(uavcan.to_yaml(msg)) else: self._msg_viewer.setPlainText('Paused') except Exception as ex: self._msg_viewer.setPlainText('Publishing failed:\n' + str(ex)) def _do_stop_all(self): for sl in self._sliders: sl.zero() def _update_number_of_sliders(self): num_sliders = self._num_sliders.value() while len(self._sliders) > num_sliders: removee = self._sliders[-1] self._sliders = self._sliders[:-1] self._slider_layout.removeWidget(removee) removee.close() removee.deleteLater() while len(self._sliders) < num_sliders: new = PercentSlider(self) self._slider_layout.addWidget(new) self._sliders.append(new) def deferred_resize(): self.resize(self.minimumWidth(), self.height()) deferred_resize() # noinspection PyCallByClass,PyTypeChecker QTimer.singleShot(200, deferred_resize) def __del__(self): global _singleton _singleton = None def closeEvent(self, event): global _singleton _singleton = None super(ESCPanel, self).closeEvent(event)
class MyPlotWidget(QWidget): COLORS=('r','g','b','c','m') def __init__(self): QWidget.__init__(self) vBox = QVBoxLayout(self) self._labels = QHBoxLayout() #self._labels.setSpacing(0) self._labels.addStretch(1) vBox.addLayout(self._labels) self.pw = pg.PlotWidget() vBox.addWidget(self.pw) self.pw.setBackground('w') self.pw.showGrid(x=True, y=True) self.setAcceptDrops(True) self.pw.setAcceptDrops(True) self.cidx = 0 def dragEnterEvent(self, e): if e.mimeData().hasFormat("application/x-DataItem"): e.accept() else: e.ignore() def dropEvent(self, e): data = e.mimeData() bstream = data.retrieveData("application/x-DataItem", QVariant.ByteArray) selected = pickle.loads(bstream) name = f"{e.source().filename} : {selected.var_name}" print(type(selected.data)) item = self.pw.getPlotItem().plot(x=selected.time.to_numpy(), y=selected.data.to_numpy(), pen=pg.mkPen(color=MyPlotWidget.COLORS[self.cidx], width=2), name=name) label = self.makeLabel(item) self._labels.insertWidget(self._labels.count()-1, label) e.source().onClose.connect(lambda : self.removeItem(item, label)) self.pw.autoRange() self.cidx = (self.cidx + 1) % len(MyPlotWidget.COLORS) e.accept() def makeLabel(self, plot_item): label = QLabel(plot_item.name()) label.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)) palette = QPalette() color = plot_item.opts['pen'].color() palette.setColor(QPalette.WindowText, color) label.setPalette(palette) return label def removeItem(self, item, label): self.pw.removeItem(item) self._labels.removeWidget(label) # self._labels.takeAt(self._labels.indexOf(label)) label.deleteLater()
class RadioBox(QWidget): def __init__(self, parent=None, items=None, spread=True, **kwargs): # If spread is False, insert a spacer in the layout so that the items don't use all the # space they're given but rather align left. if items is None: items = [] super().__init__(parent, **kwargs) self._buttons = [] self._labels = items self._selected_index = 0 self._spacer = horizontalSpacer() if not spread else None self._layout = QHBoxLayout(self) self._update_buttons() #--- Private def _update_buttons(self): if self._spacer is not None: self._layout.removeItem(self._spacer) to_remove = self._buttons[len(self._labels):] for button in to_remove: self._layout.removeWidget(button) button.setParent(None) del self._buttons[len(self._labels):] to_add = self._labels[len(self._buttons):] for _ in to_add: button = QRadioButton(self) self._buttons.append(button) self._layout.addWidget(button) button.toggled.connect(self.buttonToggled) if self._spacer is not None: self._layout.addItem(self._spacer) if not self._buttons: return for button, label in zip(self._buttons, self._labels): button.setText(label) self._update_selection() def _update_selection(self): self._selected_index = max(0, min(self._selected_index, len(self._buttons)-1)) selected = self._buttons[self._selected_index] selected.setChecked(True) #--- Event Handlers def buttonToggled(self): for i, button in enumerate(self._buttons): if button.isChecked(): self._selected_index = i self.itemSelected.emit(i) break #--- Signals itemSelected = pyqtSignal(int) #--- Properties @property def buttons(self): return self._buttons[:] @property def items(self): return self._labels[:] @items.setter def items(self, value): self._labels = value self._update_buttons() @property def selected_index(self): return self._selected_index @selected_index.setter def selected_index(self, value): self._selected_index = value self._update_selection()
class WidgetView(QWidget): """ Class to show a dynamically loaded widget (or dialog). """ def __init__(self, uiFileName, parent=None, name=None): """ Constructor @param uiFileName name of the UI file to load (string) @param parent parent widget (QWidget) @param name name of this widget (string) """ super(WidgetView, self).__init__(parent) if name: self.setObjectName(name) self.setWindowTitle(name) self.__widget = None self.__uiFileName = uiFileName self.__layout = QHBoxLayout(self) self.__valid = False self.__timer = QTimer(self) self.__timer.setSingleShot(True) self.__timer.timeout.connect(self.buildWidget) def isValid(self): """ Public method to return the validity of this widget view. @return flag indicating the validity (boolean) """ return self.__valid def uiFileName(self): """ Public method to retrieve the name of the UI file. @return filename of the loaded UI file (string) """ return self.__uiFileName def buildWidget(self): """ Public slot to load a UI file. """ if self.__widget: self.__widget.close() self.__layout.removeWidget(self.__widget) del self.__widget self.__widget = None try: self.__widget = uic.loadUi(self.__uiFileName) except Exception: pass if not self.__widget: E5MessageBox.warning( self, self.tr("Load UI File"), self.tr( """<p>The file <b>{0}</b> could not be loaded.</p>""") .format(self.__uiFileName)) self.__valid = False return self.__widget.setParent(self) self.__layout.addWidget(self.__widget) self.__widget.show() self.__valid = True self.adjustSize() self.__timer.stop() def __rebuildWidget(self): """ Private method to schedule a rebuild of the widget. """ self.__timer.start(0)
class ViewDataWindow(QDialog): formSubmitted = pyqtSignal() closeSignal = pyqtSignal() def __init__(self, LOGIN, parent=None): #super(ViewDataWindow, self).__init__(parent) super().__init__(parent) self.LOGIN = LOGIN self.db = db(self.LOGIN, "Brewing") self.displayNo = 0 self.displayedBrewsH = [] self.displayedBrewsVMash = [] self.displayedBrewsVBoil = [] self.displayedBrewsVFerment = [] self.create_layout_viewData() self.setWindowTitle('Past Brew Viewer') self.activeColours = [] self.colours = ["red", "green", "blue", "black",\ "cyan", "magenta", "yellow", "gray"] # Function to create layout of New Brew window def create_layout_viewData(self): # Create scroll boxes for filtering data filterGroupBox = QGroupBox("Filter by:") # Date edit box lab_date = QLabel("Date:") self.dateEdit = QDateEdit() # Set range of possible dates, current date is max date self.maxDate = QDate().currentDate() self.minDate = QDate(2019, 1, 1) self.dateEdit.setDate(self.maxDate) self.dateEdit.setDateRange(self.minDate, self.maxDate) self.dateEdit.setCalendarPopup(1) self.dateEdit.setDisplayFormat("dd/MM/yy") #self.dateEdit2 = QLineEdit() self.dateEdit.dateChanged.connect(self.filter_date) dateHLayout = QHBoxLayout() dateHLayout.addWidget(lab_date) dateHLayout.addWidget(self.dateEdit) ### Text edit filters ### # Batch ID search lab_batch = QLabel("Batch ID:") self.edit_batchID = QLineEdit() self.edit_batchID.setPlaceholderText("Enter Batch ID") self.but_IDsearch = QPushButton("Go") self.but_IDsearch.setAutoDefault(0) self.but_IDsearch.clicked.connect(self.filter_batchID) self.edit_batchID.returnPressed.connect(self.filter_batchID) batchHLayout = QHBoxLayout() batchHLayout.addWidget(lab_batch) batchHLayout.addWidget(self.edit_batchID) batchHLayout.addWidget(self.but_IDsearch) # Recipe search lab_recipe = QLabel("Recipe:") self.lineEdit_recipe = QLineEdit() self.lineEdit_recipe.setPlaceholderText("Enter Recipe") self.lineEdit_recipe.textChanged.connect(self.filter_recipe) self.lineEdit_recipe.returnPressed.connect(self.filter_recipe) recipeHLayout = QHBoxLayout() recipeHLayout.addWidget(lab_recipe) recipeHLayout.addWidget(self.lineEdit_recipe) # Clear filters button self.but_clearFilter = QPushButton("Clear Filters") self.but_clearFilter.setAutoDefault(0) clearHLayout = QHBoxLayout() clearHLayout.addStretch(1) clearHLayout.addWidget(self.but_clearFilter) clearHLayout.addStretch(0) self.but_clearFilter.clicked.connect(self.clearFilters) # Filter groupbox layout #recipeHLayout.addWidget(self.recipeEdit) #recipeVLayout = QVBoxLayout() #recipeVLayout.addLayout(recipeHLayout) #recipeVLayout.addWidget(self.lineEdit_recipe) filterHLayout = QHBoxLayout() filterHLayout.addStretch(1) filterHLayout.addWidget(lab_date) filterHLayout.addWidget(self.dateEdit) filterHLayout.addStretch(1) #filterHLayout.addLayout(recipeVLayout) filterHLayout.addStretch(1) filterHLayout.addWidget(self.edit_batchID) filterHLayout.addWidget(self.but_IDsearch) filterHLayout.addStretch(1) #filterGroupBox.setLayout(filterHLayout) # Alternate - Filter vertical layout filterVLayout = QVBoxLayout() filterVLayout.addLayout(batchHLayout) filterVLayout.addLayout(recipeHLayout) filterVLayout.addLayout(dateHLayout) filterVLayout.addLayout(clearHLayout) filterGroupBox.setLayout(filterVLayout) # scrollHLayout = QHBoxLayout() # scrollHLayout.addWidget(filterGroupBox) # scrollHLayout.addStretch(1) # Create QTableView of brew data header = ['Brew ID', 'Recipe', 'Date'] self.model = MyTableModel( self.db.readFromTable("Brews", "id, Recipe, Date"), header, self) self.proxyModel = QSortFilterProxyModel(self) self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setSourceModel(self.model) self.dataTable = QTableView() self.dataTable.setModel(self.proxyModel) self.dataTable.setSortingEnabled(True) self.dataTable.setSelectionBehavior(1) # Create bottom buttons self.but_quit = QPushButton("Close") self.but_quit.setAutoDefault(0) self.but_view = QPushButton("Display Brew") self.but_view.setAutoDefault(0) quitHLayout = QHBoxLayout() quitHLayout.addStretch(0) quitHLayout.addWidget(self.but_quit) quitHLayout.addStretch(3) quitHLayout.addWidget(self.but_view) quitHLayout.addStretch(0) # Main vertical layout for left area lWidget = QWidget() vLayoutL = QVBoxLayout(lWidget) vLayoutL.addWidget(filterGroupBox) vLayoutL.addWidget(self.dataTable) vLayoutL.addLayout(quitHLayout) # Widget for displayed brews - Widget allows fixed height to be set displayedWidget = QWidget() #displayedWidget.setFixedHeight(180) # h Layout to add groupboxes of displayed brews - added to in viewButtonClicked slot self.hLayoutDisplayed = QHBoxLayout() self.hLayoutDisplayed.addStretch(1) self.hLayoutDisplayed.setSizeConstraint(5) displayedWidget.setLayout(self.hLayoutDisplayed) # Scroll area for horizontal displayed brews hScrollArea = QScrollArea() hScrollArea.setWidget(displayedWidget) hScrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) hScrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) #hScrollArea.setFixedHeight(120) hScrollArea.setMinimumHeight(20) # Main v layout for displayed brews widget displayTitle = QLabel("Displayed Brews:") displayTitle.setMaximumHeight(20) hDisplayedWidget = QWidget() self.vLayoutDisplayed = QVBoxLayout(hDisplayedWidget) self.vLayoutDisplayed.addWidget(displayTitle) self.vLayoutDisplayed.addWidget(hScrollArea) # Main vertical layout for right area rWidget = QWidget() rSplitter = QSplitter() rSplitter.setOrientation(Qt.Orientation(2)) #vLayoutR = QVBoxLayout(rWidget) self.tabs = QTabWidget() self.tabMash = MashTab() self.tabBoil = BoilTab() self.tabFerment = FermentTab() self.tabs.resize(100, 1000) self.tabs.setMinimumSize(400, 100) self.tabs.addTab(self.tabMash, "Mash") self.tabs.addTab(self.tabBoil, "Boil") self.tabs.addTab(self.tabFerment, "Ferment") #vLayoutR.addLayout(self.vLayoutDisplayed) #vLayoutR.addWidget(self.tabs) rSplitter.addWidget(hDisplayedWidget) rSplitter.addWidget(self.tabs) # Main layout for whole window - splitter so widget sizes are adjustable mainLayout = QHBoxLayout() mainSplitter = QSplitter() mainSplitter.addWidget(lWidget) mainSplitter.addWidget(rSplitter) mainLayout.addWidget(mainSplitter) mainSplitter.setSizes([260, 740]) self.setLayout(mainLayout) #self.showFullScreen() self.setGeometry(0, 0, 1500, 1000) self.but_view.clicked.connect(self.viewButtonClicked) self.but_view.clicked.connect(self.viewButtonClickedTabs) self.but_quit.clicked.connect(self.quitButtonClicked) def quitButtonClicked(self): self.close() self.closeSignal.emit() # Slot for adding selected brew to widget def viewButtonClicked(self): self.brewInfo = [] # array to place brew info: ID, Recipe, Date self.displayNo = self.displayNo + 1 # Add brew info to array based on selected row index = (self.dataTable.selectionModel().currentIndex()) for i in range(3): self.brewInfo.append( QLabel(str(index.sibling(index.row(), i).data()))) # Choose colour to use for this displayed brew self.colourToUse = self.chooseColour() # Create group box with all brew info displayed and Remove button brewGroupBox = QGroupBox(str(self.displayNo)) brewGroupBox.setObjectName("ColouredGroupBox") brewGroupBox.setStyleSheet( "QGroupBox#ColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) brewForm = QFormLayout() brewForm.addRow(QLabel('Brew ID:'), self.brewInfo[0]) brewForm.addRow(QLabel('Recipe:'), self.brewInfo[1]) brewForm.addRow(QLabel('Date:'), self.brewInfo[2]) removeButHLayout = QHBoxLayout() removeButHLayout.addStretch(1) self.but_Remove = QPushButton("Remove") removeButHLayout.addWidget(self.but_Remove) brewForm.addRow(removeButHLayout) brewGroupBox.setLayout(brewForm) # Add group box to layout - use insert so that stretch stays on right side self.hLayoutDisplayed.insertWidget(self.displayNo - 1, brewGroupBox) self.displayedBrewsH.append( brewGroupBox) # Add groupbox to array of displayed brews # Signal to connect remove brew button. Lambda function used to pass argument of specific # brew to be removed self.but_Remove.clicked.connect( lambda: self.removeBrewClickedMash(brewGroupBox)) self.but_Remove.clicked.connect( lambda: self.removeBrewClickedBoil(brewGroupBox)) self.but_Remove.clicked.connect( lambda: self.removeBrewClickedFerment(brewGroupBox)) self.but_Remove.clicked.connect( lambda: self.removeBrewClicked(brewGroupBox)) # Slot for adding brew info to each of the process tabs def viewButtonClickedTabs(self): batchID = self.brewInfo[0].text() # Query database to get recipe data for the brew selected to view # brewInfo[0].text() gives brew ID for selected brew from table sql = f"SELECT * FROM Brews WHERE id = '{self.brewInfo[0].text()}'" query = self.db.custom(sql) self.recipedata = {} self.recipedata['batchID'] = query[0][0] self.recipedata['recipeName'] = query[0][1] self.recipedata['recipeDate'] = query[0][2] self.recipedata['mashTemp'] = query[0][3] self.recipedata['mashTime'] = query[0][4] self.recipedata['boilTemp'] = query[0][5] self.recipedata['boilTime'] = query[0][6] self.recipedata['hop1'] = (query[0][7], query[0][8]) self.recipedata['hop2'] = (query[0][9], query[0][10]) self.recipedata['hop3'] = (query[0][11], query[0][12]) self.recipedata['hop4'] = (query[0][13], query[0][14]) self.recipedata['fermenttemp'] = query[0][15] # Create groupboxes for each of the process tabs to fill with brew info mashGroupBox = QGroupBox(str(self.displayNo)) mashGroupBox.setObjectName("MashColouredGroupBox") mashGroupBox.setStyleSheet( "QGroupBox#MashColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) mashFormLayout = QFormLayout() mashFormLayout.addRow( QLabel(f"Temp ({DEGREES}C): {self.recipedata['mashTemp']}")) mashFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['mashTime']}")) mashGroupBox.setLayout(mashFormLayout) self.tabMash.mashVLayout.insertWidget(self.displayNo - 1, mashGroupBox) self.displayedBrewsVMash.append(mashGroupBox) boilGroupBox = QGroupBox(str(self.displayNo)) boilGroupBox.setObjectName("BoilColouredGroupBox") boilGroupBox.setStyleSheet( "QGroupBox#BoilColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) boilFormLayout = QFormLayout() boilFormLayout.addRow( QLabel(f"Temp ({DEGREES}C):{self.recipedata['boilTemp']}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['boilTime']}")) boilFormLayout.addRow(QLabel(f"Hop 1: {self.recipedata['hop1'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop1'][1]}")) boilFormLayout.addRow(QLabel(f"Hop 2: {self.recipedata['hop2'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop2'][1]}")) boilFormLayout.addRow(QLabel(f"Hop 3: {self.recipedata['hop3'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop3'][1]}")) boilFormLayout.addRow(QLabel(f"Hop 4: {self.recipedata['hop4'][0]}")) boilFormLayout.addRow( QLabel(f"Time (mins): {self.recipedata['hop4'][1]}")) boilGroupBox.setLayout(boilFormLayout) self.tabBoil.boilVLayout.insertWidget(self.displayNo - 1, boilGroupBox) self.displayedBrewsVBoil.append(boilGroupBox) fermentGroupBox = QGroupBox(str(self.displayNo)) fermentGroupBox.setObjectName("FermentColouredGroupBox") fermentGroupBox.setStyleSheet( "QGroupBox#FermentColouredGroupBox { border: 2px solid %s;}" % self.colourToUse) fermentFormLayout = QFormLayout() fermentFormLayout.addRow( QLabel(f"Temp ({DEGREES}C): {self.recipedata['fermenttemp']}")) #fermentFormLayout.addRow(QLabel('Time (mins):')) fermentGroupBox.setLayout(fermentFormLayout) self.tabFerment.fermentVLayout.insertWidget(self.displayNo - 1, fermentGroupBox) self.displayedBrewsVFerment.append(fermentGroupBox) ### PUTTING DATA ONTO GRAPHS ### # Query database to get data to plot on graphs sqlMash = f"SELECT TimeStamp, Temp FROM Mash WHERE BatchID = '{batchID}'" sqlBoil = f"SELECT TimeStamp, Temp FROM BoilMonitor WHERE BatchID = '{batchID}'" sqlFermentTemp = f"SELECT TimeStamp, Temp FROM Ferment WHERE BatchID = '{batchID}'" sqlFermentSG = f"SELECT TimeStamp, Sg FROM Ferment WHERE BatchID = '{batchID}'" mashDataX, mashDataY = self.createData(sqlMash) boilDataX, boilDataY = self.createData(sqlBoil) fermentTempDataX, fermentTempDataY = self.createData(sqlFermentTemp) fermentSGDataX, fermentSGDataY = self.createData(sqlFermentSG) # Create and add curves to each of the plots self.tabMash.graph.createCurve(mashDataX, mashDataY, self.colourToUse) self.tabBoil.graph.createCurve(boilDataX, boilDataY, self.colourToUse) self.tabFerment.tempGraph.createCurve(fermentTempDataX[1:], fermentTempDataY[1:], self.colourToUse) self.tabFerment.gravGraph.createCurve(fermentSGDataX[1:], fermentSGDataY[1:], self.colourToUse) # Function to choose first available colour def chooseColour(self): # Loop through dictionary, checking if self.colours[j] appear for colours in self.colours: # If it does appear, continue to next colour if colours not in self.activeColours: # If it doesn't appear, add colour to dictionary and return colour self.activeColours.append(colours) return colours # Get data from database using sql query def createData(self, sql): timestamps = [] tempdat = [] try: for data in self.db.custom(sql): timestamps.append(data[0]) tempdat.append(data[1]) startTime = timestamps[0] for i in range(len(timestamps)): timestamps[i] = (timestamps[i] - startTime).seconds except IndexError: return [0], [0] return timestamps, tempdat # Slot for removing group boxes from horizontal tab def removeBrewClicked(self, brewToRemove): brewArrayPos = self.displayedBrewsH.index(brewToRemove) self.hLayoutDisplayed.removeWidget( brewToRemove) # remove widget from layout brewToRemove.setParent(None) # remove parent so widget dissappears self.displayNo = self.displayNo - 1 self.displayedBrewsH.remove( brewToRemove) # remove brew from array of displayed brews i = 0 # Loop to renumber the remaining displayed groupboxes using the array for i in range(len(self.displayedBrewsH)): self.displayedBrewsH[i].setTitle(str(i + 1)) del self.activeColours[brewArrayPos] # Slot for removing group boxes of brew info in mash tab def removeBrewClickedMash(self, brewToRemove): # Obtain position in array of displayed brews of brew to remove brewArrayPos = self.displayedBrewsH.index(brewToRemove) # Use position to remove widget from layout self.tabMash.mashVLayout.takeAt(brewArrayPos) # Use position to remove parent self.displayedBrewsVMash[brewArrayPos].setParent(None) # Use position to delete from vertical array del self.displayedBrewsVMash[brewArrayPos] # Renumber groupboxes in vertical display for i in range(len(self.displayedBrewsVMash)): self.displayedBrewsVMash[i].setTitle(str(i + 1)) # Remove curve from graph self.tabMash.graph.removeCurve(brewArrayPos) # Slot for removing group boxes of brew info in boil tab def removeBrewClickedBoil(self, brewToRemove): # Obtain position in array of displayed brews of brew to remove brewArrayPos = self.displayedBrewsH.index(brewToRemove) # Use position to remove widget from layout self.tabBoil.boilVLayout.takeAt(brewArrayPos) # Use position to remove parent self.displayedBrewsVBoil[brewArrayPos].setParent(None) # Use position to delete from vertical array del self.displayedBrewsVBoil[brewArrayPos] # Renumber groupboxes in vertical display for i in range(len(self.displayedBrewsVBoil)): self.displayedBrewsVBoil[i].setTitle(str(i + 1)) self.tabBoil.graph.removeCurve(brewArrayPos) # Slot for removing group boxes of brew info in ferment tab def removeBrewClickedFerment(self, brewToRemove): # Obtain position in array of displayed brews of brew to remove brewArrayPos = self.displayedBrewsH.index(brewToRemove) # Use position to remove widget from layout self.tabFerment.fermentVLayout.takeAt(brewArrayPos) # Use position to remove parent self.displayedBrewsVFerment[brewArrayPos].setParent(None) # Use position to delete from vertical array del self.displayedBrewsVFerment[brewArrayPos] # Renumber groupboxes in vertical display for i in range(len(self.displayedBrewsVFerment)): self.displayedBrewsVFerment[i].setTitle(str(i + 1)) self.tabFerment.tempGraph.removeCurve(brewArrayPos) self.tabFerment.gravGraph.removeCurve(brewArrayPos) # Slot for filtering by Batch IDdisplayed def filter_batchID(self): self.lineEdit_recipe.clear() self.proxyModel.setFilterRegExp(self.edit_batchID.text()) self.proxyModel.setFilterKeyColumn(0) # Slot for filtering by Recipe def filter_recipe(self): self.edit_batchID.clear() self.proxyModel.setFilterRegExp(self.lineEdit_recipe.text()) self.proxyModel.setFilterKeyColumn(1) # Slot for filtering by date def filter_date(self): self.lineEdit_recipe.clear() self.edit_batchID.clear() self.proxyModel.setFilterRegExp( self.dateEdit.date().toString("dd/MM/yy")) self.proxyModel.setFilterKeyColumn(2) # Slot for clearing all filters def clearFilters(self): self.dateEdit.setDate(self.maxDate) self.proxyModel.setFilterRegExp('') self.proxyModel.setFilterKeyColumn(0) self.proxyModel.setFilterKeyColumn(1) self.proxyModel.setFilterKeyColumn(2) self.lineEdit_recipe.clear() self.edit_batchID.clear()
class Main(QWidget): def __init__(self): super().__init__() simulation = Simulation(0.5, 100) simulation.run_interactively() self.state = MainState(simulation) self.music_window: QWidget = None self.music_thread = MusicPlayerThread(None, '') self.sidebar = None self.main_container: QHBoxLayout = None self.setStyleSheet(style.main) self.initWidgets() self.initMainContainer() self.initUI() def restart(self): self.__init__() def initWidgets(self): population = self.state.simulation.population[0:self.state.simulation. selection_size] self.music_window = MusicWindow(MusicWindowViewModel(self, population)) self.sidebar = Sidebar(self) def initMainContainer(self): self.main_container = QHBoxLayout() self.main_container.setContentsMargins(0, 0, 0, 0) self.main_container.setSpacing(0) self.main_container.addWidget(self.sidebar, 1) self.main_container.addWidget(self.music_window, 4) def initUI(self): self.setLayout(self.main_container) self.setGeometry(300, 300, 800, 600) self.setWindowTitle('EvoMusic') self.setObjectName('main') self.show() # def closeEvent(self, event): # # reply = QMessageBox.question(self, 'Message', # "Are you sure you want to quit?", QMessageBox.Yes | # QMessageBox.No, QMessageBox.No) # # if reply == QMessageBox.Yes: # event.accept() # else: # event.ignore() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def initPopulation(self): corpus = modelTrainer.get_corpus() pitch_matrix = modelTrainer.train_pitch_matrix(corpus) duration_matrix = modelTrainer.train_duration_matrix(corpus) self.simulation.run_interactively(pitch_matrix, duration_matrix, None) def toNextGeneration(self): print(f"Generating next generation {self.state.currGeneration + 1}") self.state.simulation.update() self.state.currGeneration += 1 self.state.curr_piece_index = 0 self.state.curr_pieces = self.state.simulation.population[0:5] self.updateViews() def updateViews(self): self.main_container.removeWidget(self.music_window) self.music_window.deleteLater() musicViewModel = MusicWindowViewModel( self, self.state.curr_pieces, self.state.curr_pieces[self.state.curr_piece_index], None) self.music_window = MusicWindow(musicViewModel) self.main_container.addWidget(self.music_window) self.sidebar.setModel(self.state.currGeneration) self.update() def setPieceRating(self, piece_idx, rating): self.state.simulation.population[piece_idx].user_score = rating def setMeasureRating(self, piece_index, measure_index, rating): self.state.simulation.population[piece_index] \ .measures[measure_index].user_score = rating def playMusicXml(self): curr = self.music_window.model.curr_piece musicPlayer.play_music_xml([curr]) def toNextPiece(self): next_index = self.state.curr_piece_index + 1 if next_index < len(self.state.curr_pieces): self.state.curr_individual = self.state.curr_pieces[next_index] self.state.curr_piece_index += 1 self.updateViews() def toPreviousPiece(self): prev_index = self.state.curr_piece_index - 1 if prev_index >= 0: self.state.curr_individual = self.state.curr_pieces[prev_index] self.state.curr_piece_index -= 1 self.updateViews() def refreshWindows(self): self.main_container.removeWidget(self.main_container) self.music_window.deleteLater() self.main_container.addWidget() def play(self): self.music_thread.terminate() self.music_thread = MusicPlayerThread( [self.state.curr_pieces[self.state.curr_piece_index]], 'piece') self.music_thread.start()
class Module(QGroupBox): def __init__(self, mainWindow, name, devices): QGroupBox.__init__(self) self.mainWindow = mainWindow self.name = name self.devices = devices self.groupBox = [] self.alarmGB = [] self.divcoeff = 5 self.cLayout = QHBoxLayout() self.alarmLayout = QHBoxLayout() self.gbLayout = QGridLayout() self.cLayout.addLayout(self.alarmLayout) self.cLayout.addLayout(self.gbLayout) self.setLayout(self.cLayout) self.initialize() self.waitforData() @property def actors(self): return list(OrderedDict.fromkeys([device.tablename.split('__')[0] for device in self.devices])) @property def isOffline(self): return True if self.mode == 'offline' else False def initialize(self): self.createGroupBox() self.eyeButton = EyeButton(self) self.acquisition = Acquisition(self) self.alarmLayout.addWidget(self.acquisition) def setAlarms(self, alarms): hide = self.cleanAlarms() self.mode = alarms[0].mode if alarms else 'offline' self.setTitle('%s - %s ' % (self.name, self.mode)) for alarm in alarms: widget = AlarmGB(self, alarm) self.alarmGB.append(widget) self.alarmLayout.addWidget(widget) widget.hide() if hide else widget.show() def cleanAlarms(self): hide = False while self.alarmGB: alarm = self.alarmGB[0] hide = alarm.isHidden() self.alarmLayout.removeWidget(alarm) alarm.deleteLater() self.alarmGB.remove(alarm) return hide def moveEye(self): try: self.eyeButton.move(self.width() - 30, 0) except: pass def createGroupBox(self): for i, deviceConf in enumerate(self.devices): groupbox = DeviceGB(self, deviceConf) try: groupbox.testData() self.groupBox.append(groupbox) self.gbLayout.addWidget(groupbox, (i // self.divcoeff) + 1, i % self.divcoeff) except Exception as e: print (e, deviceConf.tablename) def showAll(self, bool): for groupbox in self.groupBox: groupbox.hide() if not bool else groupbox.show() for alarm in self.alarmGB: alarm.show() if not bool else alarm.hide() try: self.acquisition.hide() if bool else self.acquisition.show() except AttributeError: pass self.adjustSize() self.mainWindow.mainWidget.adjustSize() self.mainWindow.adjustSize() def waitforData(self): try: for groupbox in self.groupBox: groupbox.waitforData() for alarm in self.alarmGB: alarm.getValue() self.acquisition.network = True except psycopg2.OperationalError: self.acquisition.network = False self.mainWindow.db.close() def updateMode(self, mode): modes = readMode() for actor in self.actors: modes[actor] = mode writeMode(modes) def getGroupBox(self, tableName): for i, groupbox in enumerate(self.groupBox): if groupbox.tablename == tableName: return self.groupBox[i] def mouseReleaseEvent(self, QMouseEvent): if QMouseEvent.button() == Qt.RightButton: menu = QMenu(self) all_modes = [f[:-4] for f in next(os.walk(self.mainWindow.alarmPath))[-1] if '.cfg' in f] for mode in all_modes: action = QAction(mode, self) action.triggered.connect(partial(self.updateMode, mode)) menu.addAction(action) menu.popup(QCursor.pos()) def resizeEvent(self, QResizeEvent): self.moveEye() QGroupBox.resizeEvent(self, QResizeEvent)
class StatusBar(QWidget): """The statusbar at the bottom of the mainwindow. Attributes: txt: The Text widget in the statusbar. keystring: The KeyString widget in the statusbar. percentage: The Percentage widget in the statusbar. url: The UrlText widget in the statusbar. prog: The Progress widget in the statusbar. cmd: The Command widget in the statusbar. _hbox: The main QHBoxLayout. _stack: The QStackedLayout with cmd/txt widgets. _win_id: The window ID the statusbar is associated with. Signals: resized: Emitted when the statusbar has resized, so the completion widget can adjust its size to it. arg: The new size. moved: Emitted when the statusbar has moved, so the completion widget can move to the right position. arg: The new position. """ resized = pyqtSignal('QRect') moved = pyqtSignal('QPoint') STYLESHEET = _generate_stylesheet() def __init__(self, *, win_id, private, parent=None): super().__init__(parent) self.setObjectName(self.__class__.__name__) self.setAttribute(Qt.WA_StyledBackground) stylesheet.set_register(self) self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self._win_id = win_id self._color_flags = ColorFlags() self._color_flags.private = private self._hbox = QHBoxLayout(self) self._set_hbox_padding() self._hbox.setSpacing(5) self._stack = QStackedLayout() self._hbox.addLayout(self._stack) self._stack.setContentsMargins(0, 0, 0, 0) self.cmd = command.Command(private=private, win_id=win_id) self._stack.addWidget(self.cmd) objreg.register('status-command', self.cmd, scope='window', window=win_id) self.txt = textbase.TextBase() self._stack.addWidget(self.txt) self.cmd.show_cmd.connect(self._show_cmd_widget) self.cmd.hide_cmd.connect(self._hide_cmd_widget) self._hide_cmd_widget() self.url = url.UrlText() self.percentage = percentage.Percentage() self.backforward = backforward.Backforward() self.tabindex = tabindex.TabIndex() self.keystring = keystring.KeyString() self.prog = progress.Progress(self) self._text_widgets = [] self._draw_widgets() config.instance.changed.connect(self._on_config_changed) QTimer.singleShot(0, self.maybe_hide) def __repr__(self): return utils.get_repr(self) @pyqtSlot(str) def _on_config_changed(self, option): if option == 'statusbar.show': self.maybe_hide() elif option == 'statusbar.padding': self._set_hbox_padding() elif option == 'statusbar.widgets': self._draw_widgets() def _draw_widgets(self): """Draw statusbar widgets.""" self._clear_widgets() tab = self._current_tab() # Read the list and set widgets accordingly for segment in config.val.statusbar.widgets: if segment == 'url': self._hbox.addWidget(self.url) self.url.show() elif segment == 'scroll': self._hbox.addWidget(self.percentage) self.percentage.show() elif segment == 'scroll_raw': self._hbox.addWidget(self.percentage) self.percentage.set_raw() self.percentage.show() elif segment == 'history': self._hbox.addWidget(self.backforward) self.backforward.enabled = True if tab: self.backforward.on_tab_changed(tab) elif segment == 'tabs': self._hbox.addWidget(self.tabindex) self.tabindex.show() elif segment == 'keypress': self._hbox.addWidget(self.keystring) self.keystring.show() elif segment == 'progress': self._hbox.addWidget(self.prog) self.prog.enabled = True if tab: self.prog.on_tab_changed(tab) elif segment.startswith('text:'): cur_widget = textbase.TextBase() self._text_widgets.append(cur_widget) cur_widget.setText(segment.split(':', maxsplit=1)[1]) self._hbox.addWidget(cur_widget) cur_widget.show() else: raise utils.Unreachable(segment) def _clear_widgets(self): """Clear widgets before redrawing them.""" # Start with widgets hidden and show them when needed for widget in [ self.url, self.percentage, self.backforward, self.tabindex, self.keystring, self.prog, *self._text_widgets ]: assert isinstance(widget, QWidget) widget.hide() self._hbox.removeWidget(widget) self._text_widgets.clear() @pyqtSlot() def maybe_hide(self): """Hide the statusbar if it's configured to do so.""" strategy = config.val.statusbar.show tab = self._current_tab() if tab is not None and tab.data.fullscreen: self.hide() elif strategy == 'never': self.hide() elif strategy == 'in-mode': try: mode_manager = modeman.instance(self._win_id) except modeman.UnavailableError: self.hide() else: if mode_manager.mode == usertypes.KeyMode.normal: self.hide() else: self.show() elif strategy == 'always': self.show() else: raise utils.Unreachable def _set_hbox_padding(self): padding = config.val.statusbar.padding self._hbox.setContentsMargins(padding.left, 0, padding.right, 0) @pyqtProperty('QStringList') # type: ignore[type-var] def color_flags(self): """Getter for self.color_flags, so it can be used as Qt property.""" return self._color_flags.to_stringlist() def _current_tab(self): """Get the currently displayed tab.""" window = objreg.get('tabbed-browser', scope='window', window=self._win_id) return window.widget.currentWidget() def set_mode_active(self, mode, val): """Setter for self.{insert,command,caret}_active. Re-set the stylesheet after setting the value, so everything gets updated by Qt properly. """ if mode == usertypes.KeyMode.insert: log.statusbar.debug("Setting insert flag to {}".format(val)) self._color_flags.insert = val if mode == usertypes.KeyMode.passthrough: log.statusbar.debug("Setting passthrough flag to {}".format(val)) self._color_flags.passthrough = val if mode == usertypes.KeyMode.command: log.statusbar.debug("Setting command flag to {}".format(val)) self._color_flags.command = val elif mode in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]: log.statusbar.debug("Setting prompt flag to {}".format(val)) self._color_flags.prompt = val elif mode == usertypes.KeyMode.caret: if not val: # Turning on is handled in on_current_caret_selection_toggled log.statusbar.debug("Setting caret mode off") self._color_flags.caret = ColorFlags.CaretMode.off stylesheet.set_register(self, update=False) def _set_mode_text(self, mode): """Set the mode text.""" if mode == 'passthrough': key_instance = config.key_instance all_bindings = key_instance.get_reverse_bindings_for('passthrough') bindings = all_bindings.get('mode-leave') if bindings: suffix = ' ({} to leave)'.format(' or '.join(bindings)) else: suffix = '' else: suffix = '' text = "-- {} MODE --{}".format(mode.upper(), suffix) self.txt.setText(text) def _show_cmd_widget(self): """Show command widget instead of temporary text.""" self._stack.setCurrentWidget(self.cmd) self.show() def _hide_cmd_widget(self): """Show temporary text instead of command widget.""" log.statusbar.debug("Hiding cmd widget") self._stack.setCurrentWidget(self.txt) self.maybe_hide() @pyqtSlot(str) def set_text(self, text): """Set a normal (persistent) text in the status bar.""" log.message.debug(text) self.txt.setText(text) @pyqtSlot(usertypes.KeyMode) def on_mode_entered(self, mode): """Mark certain modes in the commandline.""" mode_manager = modeman.instance(self._win_id) if config.val.statusbar.show == 'in-mode': self.show() if mode_manager.parsers[mode].passthrough: self._set_mode_text(mode.name) if mode in [ usertypes.KeyMode.insert, usertypes.KeyMode.command, usertypes.KeyMode.caret, usertypes.KeyMode.prompt, usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough ]: self.set_mode_active(mode, True) @pyqtSlot(usertypes.KeyMode, usertypes.KeyMode) def on_mode_left(self, old_mode, new_mode): """Clear marked mode.""" mode_manager = modeman.instance(self._win_id) if config.val.statusbar.show == 'in-mode': self.hide() if mode_manager.parsers[old_mode].passthrough: if mode_manager.parsers[new_mode].passthrough: self._set_mode_text(new_mode.name) else: self.txt.setText('') if old_mode in [ usertypes.KeyMode.insert, usertypes.KeyMode.command, usertypes.KeyMode.caret, usertypes.KeyMode.prompt, usertypes.KeyMode.yesno, usertypes.KeyMode.passthrough ]: self.set_mode_active(old_mode, False) @pyqtSlot(browsertab.AbstractTab) def on_tab_changed(self, tab): """Notify sub-widgets when the tab has been changed.""" self.url.on_tab_changed(tab) self.prog.on_tab_changed(tab) self.percentage.on_tab_changed(tab) self.backforward.on_tab_changed(tab) self.maybe_hide() assert tab.is_private == self._color_flags.private @pyqtSlot(browsertab.SelectionState) def on_caret_selection_toggled(self, selection_state): """Update the statusbar when entering/leaving caret selection mode.""" log.statusbar.debug( "Setting caret selection {}".format(selection_state)) if selection_state is browsertab.SelectionState.normal: self._set_mode_text("caret selection") self._color_flags.caret = ColorFlags.CaretMode.selection elif selection_state is browsertab.SelectionState.line: self._set_mode_text("caret line selection") self._color_flags.caret = ColorFlags.CaretMode.selection else: self._set_mode_text("caret") self._color_flags.caret = ColorFlags.CaretMode.on stylesheet.set_register(self, update=False) def resizeEvent(self, e): """Extend resizeEvent of QWidget to emit a resized signal afterwards. Args: e: The QResizeEvent. """ super().resizeEvent(e) self.resized.emit(self.geometry()) def moveEvent(self, e): """Extend moveEvent of QWidget to emit a moved signal afterwards. Args: e: The QMoveEvent. """ super().moveEvent(e) self.moved.emit(e.pos()) def minimumSizeHint(self): """Set the minimum height to the text height plus some padding.""" padding = config.cache['statusbar.padding'] width = super().minimumSizeHint().width() height = self.fontMetrics().height() + padding.top + padding.bottom return QSize(width, height)
class RadioBox(QWidget): def __init__(self, parent=None, items=None, spread=True, **kwargs): # If spread is False, insert a spacer in the layout so that the items don't use all the # space they're given but rather align left. if items is None: items = [] super().__init__(parent, **kwargs) self._buttons = [] self._labels = items self._selected_index = 0 self._spacer = horizontalSpacer() if not spread else None self._layout = QHBoxLayout(self) self._update_buttons() # --- Private def _update_buttons(self): if self._spacer is not None: self._layout.removeItem(self._spacer) to_remove = self._buttons[len(self._labels):] for button in to_remove: self._layout.removeWidget(button) button.setParent(None) del self._buttons[len(self._labels):] to_add = self._labels[len(self._buttons):] for _ in to_add: button = QRadioButton(self) self._buttons.append(button) self._layout.addWidget(button) button.toggled.connect(self.buttonToggled) if self._spacer is not None: self._layout.addItem(self._spacer) if not self._buttons: return for button, label in zip(self._buttons, self._labels): button.setText(label) self._update_selection() def _update_selection(self): self._selected_index = max( 0, min(self._selected_index, len(self._buttons) - 1)) selected = self._buttons[self._selected_index] selected.setChecked(True) # --- Event Handlers def buttonToggled(self): for i, button in enumerate(self._buttons): if button.isChecked(): self._selected_index = i self.itemSelected.emit(i) break # --- Signals itemSelected = pyqtSignal(int) # --- Properties @property def buttons(self): return self._buttons[:] @property def items(self): return self._labels[:] @items.setter def items(self, value): self._labels = value self._update_buttons() @property def selected_index(self): return self._selected_index @selected_index.setter def selected_index(self, value): self._selected_index = value self._update_selection()
class SongsTableToolbar(QWidget): play_all_needed = pyqtSignal() filter_albums_needed = pyqtSignal([list]) filter_text_changed = pyqtSignal([str]) def __init__(self, parent=None): super().__init__(parent) self._tmp_buttons = [] self.play_all_btn = TextButton('播放全部', self) self.play_all_btn.clicked.connect(self.play_all_needed.emit) self.play_all_btn.setObjectName('play_all') # album filters self.filter_albums_combobox = QComboBox(self) self.filter_albums_combobox.addItems( ['所有专辑', '标准', '单曲与EP', '现场', '合辑']) self.filter_albums_combobox.currentIndexChanged.connect( self.on_albums_filter_changed) # 8 works on macOS, don't know if it works on various Linux DEs self.filter_albums_combobox.setMinimumContentsLength(8) self.filter_albums_combobox.hide() self._setup_ui() def albums_mode(self): self._before_change_mode() self.filter_albums_combobox.show() def songs_mode(self): self._before_change_mode() self.play_all_btn.show() def artists_mode(self): self._before_change_mode() def manual_mode(self): """fully customized mode .. versionadded:: 3.7.11 You'd better use this mode and add_tmp_button to customize toolbar. """ self._before_change_mode() def enter_state_playall_start(self): self.play_all_btn.setEnabled(False) # currently, this is called only when feeluown is fetching songs, # so when we enter state_playall_start, we set play all btn text # to this. self.play_all_btn.setText('获取所有歌曲...') def enter_state_playall_end(self): self.play_all_btn.setText('获取所有歌曲...done') self.play_all_btn.setEnabled(True) self.play_all_btn.setText('播放全部') def add_tmp_button(self, button): """Append text button""" if button not in self._tmp_buttons: # FIXME(cosven): the button inserted isn't aligned with other buttons index = len(self._tmp_buttons) if self.play_all_btn.isVisible(): index = index + 1 self._layout.insertWidget(index, button) self._tmp_buttons.append(button) def _setup_ui(self): self._layout = QHBoxLayout(self) # left margin of meta widget is 30, we align with it # bottom margin of meta widget is 15, we should be larger than that self._layout.setContentsMargins(30, 15, 30, 10) self._layout.addWidget(self.play_all_btn) self._layout.addStretch(0) self._layout.addWidget(self.filter_albums_combobox) def _before_change_mode(self): """filter all filter buttons""" for button in self._tmp_buttons: self._layout.removeWidget(button) button.close() self._tmp_buttons.clear() self.filter_albums_combobox.hide() self.play_all_btn.hide() def on_albums_filter_changed(self, index): # ['所有', '专辑', '单曲与EP', '现场', '合辑'] if index == 0: types = [] elif index == 1: types = [AlbumType.standard] elif index == 2: types = [AlbumType.single, AlbumType.ep] elif index == 3: types = [AlbumType.live] else: types = [AlbumType.compilation, AlbumType.retrospective] self.filter_albums_needed.emit(types)
class LineEdit(QLineEdit): inactiveText = QtDynamicProperty('inactiveText', unicode) widgetSpacing = QtDynamicProperty('widgetSpacing', int) def __init__(self, parent=None, contents=u""): super(LineEdit, self).__init__(contents, parent) box_direction = QBoxLayout.RightToLeft if self.isRightToLeft() else QBoxLayout.LeftToRight self.inactiveText = u"" self.left_widget = SideWidget(self) self.left_widget.resize(0, 0) self.left_layout = QHBoxLayout(self.left_widget) self.left_layout.setContentsMargins(0, 0, 0, 0) self.left_layout.setDirection(box_direction) self.left_layout.setSizeConstraint(QLayout.SetFixedSize) self.right_widget = SideWidget(self) self.right_widget.resize(0, 0) self.right_layout = QHBoxLayout(self.right_widget) self.right_layout.setContentsMargins(0, 0, 0, 0) self.right_layout.setDirection(box_direction) self.right_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.widgetSpacing = 2 self.left_widget.sizeHintChanged.connect(self._update_text_margins) self.right_widget.sizeHintChanged.connect(self._update_text_margins) @property def left_margin(self): return self.left_widget.sizeHint().width() + 2*self.left_layout.spacing() @property def right_margin(self): return self.right_widget.sizeHint().width() + 2*self.right_layout.spacing() def _update_text_margins(self): self.setTextMargins(self.left_margin, 0, self.right_margin, 0) self._update_side_widget_locations() def _update_side_widget_locations(self): option = QStyleOptionFrame() self.initStyleOption(option) spacing = self.right_layout.spacing() text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, option, self) text_rect.adjust(spacing, 0, -spacing, 0) mid_height = text_rect.center().y() + 1 - (text_rect.height() % 2) # need -1 correction for odd heights -Dan if self.left_layout.count() > 0: left_height = mid_height - self.left_widget.height()/2 left_width = self.left_widget.width() if left_width == 0: left_height = mid_height - self.left_widget.sizeHint().height()/2 self.left_widget.move(text_rect.x(), left_height) text_rect.setX(self.left_margin) text_rect.setY(mid_height - self.right_widget.sizeHint().height()/2.0) text_rect.setHeight(self.right_widget.sizeHint().height()) self.right_widget.setGeometry(text_rect) def event(self, event): event_type = event.type() if event_type == QEvent.LayoutDirectionChange: box_direction = QBoxLayout.RightToLeft if self.isRightToLeft() else QBoxLayout.LeftToRight self.left_layout.setDirection(box_direction) self.right_layout.setDirection(box_direction) elif event_type == QEvent.DynamicPropertyChange: property_name = event.propertyName() if property_name == 'widgetSpacing': self.left_layout.setSpacing(self.widgetSpacing) self.right_layout.setSpacing(self.widgetSpacing) self._update_text_margins() elif property_name == 'inactiveText': self.update() return QLineEdit.event(self, event) def resizeEvent(self, event): self._update_side_widget_locations() QLineEdit.resizeEvent(self, event) def paintEvent(self, event): QLineEdit.paintEvent(self, event) if not self.hasFocus() and not self.text() and self.inactiveText: options = QStyleOptionFrame() self.initStyleOption(options) text_rect = self.style().subElementRect(QStyle.SE_LineEditContents, options, self) text_rect.adjust(self.left_margin+2, 0, -self.right_margin, 0) painter = QPainter(self) painter.setPen(self.palette().brush(QPalette.Disabled, QPalette.Text).color()) painter.drawText(text_rect, Qt.AlignLeft | Qt.AlignVCenter, self.inactiveText) def addHeadWidget(self, widget): if self.isRightToLeft(): self.right_layout.insertWidget(1, widget) else: self.left_layout.addWidget(widget) def addTailWidget(self, widget): if self.isRightToLeft(): self.left_layout.addWidget(widget) else: self.right_layout.insertWidget(1, widget) def removeWidget(self, widget): self.left_layout.removeWidget(widget) self.right_layout.removeWidget(widget) widget.hide()
class CPinUI(QWidget): def __init__(self, pinID, parent=None): super(CPinUI, self).__init__(parent) self.m_PinID = pinID self.m_NodeID = interface.GetNodeIDByPinID(pinID) self.m_GraphicID = interface.GetGraphicIDByNodeID(self.m_NodeID) self.m_Btn = None self.m_Label = None self.m_HLayout = None self.m_DefaultWidget = None # 默认值控件 self._InitUI() self.SetIcon() self.SetText() self.ShowDefaultWidget() GetUIMgr().AddPinUI(pinID, self) def __del__(self): GetUIMgr().DelPinUI(self.m_PinID) def _InitUI(self): hBox = QHBoxLayout(self) hBox.setContentsMargins(0, 0, 0, 0) hBox.setSpacing(6) self.m_Btn = CTypeButton(self.m_PinID, self) self.m_Label = QLabel(self) self.m_HLayout = QHBoxLayout() self.m_HLayout.setContentsMargins(0, 0, 0, 0) self.m_HLayout.setSpacing(6) hBox.addWidget(self.m_Btn) hBox.addWidget(self.m_Label) hBox.addLayout(self.m_HLayout) def contextMenuEvent(self, event): super(CPinUI, self).contextMenuEvent(event) lstLineID = interface.GetAllLineByPin(self.m_PinID) menu = QMenu() for lineID in lstLineID: oPinID = interface.GetLineOtherPin(lineID, self.m_PinID) sPinDisplayName = interface.GetPinAttr(oPinID, bddefine.PinAttrName.DISPLAYNAME) nodeID = interface.GetNodeIDByPinID(oPinID) sNodeDisplayName = interface.GetNodeAttr(nodeID, bddefine.NodeAttrName.DISPLAYNAME) sMsg = "删除与\"%s\"-\"%s\"的连线" % (sNodeDisplayName, sPinDisplayName) func = functor.Functor(interface.DelLine, lineID) menu.addAction(sMsg, func) menu.exec_(QCursor.pos()) event.accept() def SetIcon(self, iDataType=None): if iDataType is None: iPinType = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.PIN_TYPE) if bddefine.PinIsFlow(iPinType): iDataType = -1 else: iDataType = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.DATA_TYPE) icon = QIcon() pix = ":/icon/btn_%s.png" % iDataType icon.addPixmap(QPixmap(pix), QIcon.Normal, QIcon.Off) self.m_Btn.setIcon(icon) def SetText(self, sText=None): if sText is None: sText = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.DISPLAYNAME) self.m_Label.setText(sText) def ShowDefaultWidget(self): iPinType = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.PIN_TYPE) if iPinType != bddefine.PIN_INPUT_DATA_TYPE: return lstLine = interface.GetAllLineByPin(self.m_PinID) if lstLine: return oWidget = None iDataTye = interface.GetPinAttr(self.m_PinID, bddefine.PinAttrName.DATA_TYPE) if iDataTye in (bddefine.Type.INT, bddefine.Type.FLOAT, bddefine.Type.STR): oWidget = subpinui.CValidatorLineEdit(self.m_PinID, iDataTye) elif iDataTye == bddefine.Type.BOOL: oWidget = subpinui.CCheckBox(self.m_PinID) elif iDataTye == bddefine.Type.ENUM: oWidget = subpinui.CEnum(self.m_PinID) elif iDataTye == bddefine.Type.VECTOR3: oWidget = subpinui.CVector3(self.m_PinID) elif iDataTye == bddefine.Type.CHECKBOX: oWidget = subpinui.CComCheckBox(self.m_PinID) if oWidget: self.m_HLayout.addWidget(oWidget) self.m_DefaultWidget = oWidget self.adjustSize() def HideDefaultWidget(self): if not self.m_DefaultWidget: return self.m_DefaultWidget.setParent(None) index = self.m_HLayout.indexOf(self.m_DefaultWidget) item = self.m_HLayout.itemAt(index) self.m_HLayout.removeWidget(self.m_DefaultWidget) self.m_HLayout.removeItem(item) self.m_DefaultWidget = None self.adjustSize() def enterEvent(self, event): super(CPinUI, self).enterEvent(event) GetSignal().UI_LINE_CONNECT.emit(self.m_GraphicID, self.m_PinID) event.accept()
class maedit_widget(QWidget, themed_window): def __init__(self, parent, theme = "default"): super().__init__() self.parent = parent self.file_types_names = [".bck", ".bca", ".btk", ".brk", ".btp", ".bpk", ".bla", ".blk", ".bva" ]; #stuff that we want to return / have access to self.selected = None self.filepath = None self.values = [] self.setup_ui() self.set_theme(theme) def setup_ui(self): self.horizontalLayout = QHBoxLayout() self.centralwidget = self.horizontalLayout #self.setCentralWidget(self.horizontalLayout) self.setLayout(self.centralwidget) #choose the animation type self.type_layout = QWidget(self) self.type_box = QVBoxLayout(self.type_layout) self.select_label = QLabel(self.type_layout) self.select_label.setText("Select Animation Type to Edit") self.file_types = QListWidget(self.type_layout) self.file_types.clear() for type in self.file_types_names: self.file_types.addItem(type) self.file_types.setCurrentRow(0) self.file_types.clicked.connect(self.edit_right_side) self.type_box.addWidget(self.select_label) self.type_box.addWidget(self.file_types) #other needed info self.other_info_layout = QWidget(self) self.other_info_layout.setGeometry(0, 0, 250, 250) self.other_info_box = self.get_right_side() #add stuff to horizontal layout self.horizontalLayout.addWidget(self.type_layout) self.horizontalLayout.addWidget(self.other_info_layout) def edit_right_side(self): self.horizontalLayout.removeWidget(self.other_info_layout) self.other_info_layout = QWidget(self) self.other_info_box = self.get_right_side() self.horizontalLayout.addWidget(self.other_info_layout) if self.filepath: for i in range( self.bmd_thing_select.count() ): self.bmd_thing_select.remove(i) if self.selected in [".bck", ".bca"]: self.bmd_thing_select.addItems( j3d.get_bones_from_bmd(self.filepath) ) elif self.selected in [".btk", ".btp", ".bpk", ".brk"]: self.bmd_thing_select.addItems( j3d.get_materials_from_bmd(self.filepath) ) elif self.selected in [".blk", ".bla", ".bva"]: self.bmd_thing_select.addItems( j3d.get_meshes_from_bmd(self.filepath) ) def create_combo_box(self, widget_parent): combo_box = QComboBox(widget_parent) combo_box.addItems( ["+", "-", "*", "/", "Average / Set To"] ) return combo_box def get_right_side(self): operations_box = QGridLayout(self.other_info_layout) widget_parent = self.other_info_layout self.selected = self.file_types.currentItem().text() label = QLabel(widget_parent) label.setText("Select File") operations_box.addWidget(label, 0, 0) button = QPushButton("Select .bmd / .bdl") button.clicked.connect(self.open_file_dialog) operations_box.addWidget(button , 0, 1) self.bmd_thing_select = QComboBox(widget_parent) operations_box.addWidget(self.bmd_thing_select, 0, 2) if self.selected in [".bck", ".bca"]: srt = ["Scale ", "Rotation ", "Translation "]; axis = ["X:", "Y:", "Z:"] for i in range(len( srt )): for j in range(len( axis)): label = QLabel(widget_parent) label.setText(srt[i] + axis[j]) operations_box.addWidget( label ,3 * i + j + 1, 0 ) operations_box.addWidget( self.create_combo_box(widget_parent), 3* i + j+ 1, 1) operations_box.addWidget( QLineEdit(widget_parent), 3 * i + j+ 1, 2) elif self.selected in [".brk", ".bpk"]: #color animation comp = ["Red:", "Green:", "Blue:", "Alpha:"]; for i in range(len( comp )): label = QLabel(widget_parent) label.setText(comp[i]) operations_box.addWidget( label ,i+ 1, 0 ) operations_box.addWidget( self.create_combo_box(widget_parent), i + 1, 1) operations_box.addWidget( QLineEdit(widget_parent), i+ 1, 2) elif self.selected == ".btk": #texture swapping animation srt = ["Scale ", "Rotation ", "Translation "]; axis = ["U:", "V:", "W:"] for i in range(len( srt )): for j in range(len( axis)): label = QLabel(widget_parent) label.setText(srt[i] + axis[j]) operations_box.addWidget( label ,3 * i + j+ 1, 0 ) operations_box.addWidget( self.create_combo_box(widget_parent), 3* i + j+ 1, 1) operations_box.addWidget( QLineEdit(widget_parent), 3 * i + j+ 1, 2) elif self.selected in [".blk", ".bla"]: #cluster animation label = QLabel(widget_parent) label.setText("Weight") operations_box.addWidget( label , 1, 0 ) operations_box.addWidget( self.create_combo_box(widget_parent), 1, 1) operations_box.addWidget( QLineEdit(widget_parent), 1, 2) #button.setDisabled(True) elif self.selected == ".btp": #texture swapping animation label = QLabel(widget_parent) label.setText("Texture Index") operations_box.addWidget( label , 1, 0 ) operations_box.addWidget( self.create_combo_box(widget_parent), 1, 1) operations_box.addWidget( QLineEdit(widget_parent), 1, 2) elif self.selected == ".bva": #visibility animation label = QLabel(widget_parent) label.setText("Visibility") operations_box.addWidget( label , 1, 0 ) combo_box = QComboBox(widget_parent) combo_box.addItems( ["Swap", "Set To"] ) operations_box.addWidget( combo_box, 1, 1) operations_box.addWidget( QLineEdit(widget_parent), 1, 2) #button.setDisabled(True) return operations_box def get_info(self): if self.selected is None: return None if self.filepath is None: return None values = [] for i in range(1, self.other_info_box.rowCount() ): comp = [] combo_box = self.other_info_box.itemAtPosition(i, 0).widget() comp.append( combo_box.text() ) combo_box = self.other_info_box.itemAtPosition(i, 1).widget() comp.append( combo_box.currentIndex() ) line_edit = self.other_info_box.itemAtPosition(i, 2).widget() comp.append( line_edit.text() ) values.append(comp) if self.filepath.endswith(".bva"): # we KNOW that values only has one entry combo_box = self.other_info_box.itemAtPosition(i, 1).widget() if self.combo_box.currentIndex() == 0: #if swap values[0][2] = "" #print(self.selected, self.bmd_thing_select.currentText(), values) return ( [[self.selected, self.bmd_thing_select.currentText(), values]] ) def open_file_dialog(self): filepath, choosentype = QFileDialog.getOpenFileName(self.other_info_layout, "Choose File Path", "", "j3d model files (*.bmd *.bdl)") if filepath: #self.filename_text.setText(filepath) self.filepath = filepath for i in range( self.bmd_thing_select.count() ): self.bmd_thing_select.remove(i) if self.selected in [".bck", ".bca"]: self.bmd_thing_select.addItems( j3d.get_bones_from_bmd(filepath) ) elif self.selected in [".btk", ".btp", ".bpk", ".brk"]: self.bmd_thing_select.addItems( j3d.get_materials_from_bmd(filepath) ) elif self.selected in [".blk", ".bla", ".bva"]: self.bmd_thing_select.addItems( j3d.get_meshes_from_bmd(filepath) )
class E5LineEdit(QLineEdit): """ Class implementing a line edit widget showing some inactive text. """ LeftSide = 0 RightSide = 1 def __init__(self, parent=None, inactiveText=""): """ Constructor @param parent reference to the parent widget (QWidget) @param inactiveText text to be shown on inactivity (string) """ super(E5LineEdit, self).__init__(parent) self.setMinimumHeight(22) if qVersion() < "4.7.0": self.__inactiveText = inactiveText else: self.setPlaceholderText(inactiveText) self.__mainLayout = QHBoxLayout(self) self.__mainLayout.setContentsMargins(0, 0, 0, 0) self.__mainLayout.setSpacing(0) self.__leftMargin = 0 self.__leftWidget = E5LineEditSideWidget(self) self.__leftWidget.resize(0, 0) self.__leftLayout = QHBoxLayout(self.__leftWidget) self.__leftLayout.setContentsMargins(0, 0, 2, 0) if QApplication.isRightToLeft(): self.__leftLayout.setDirection(QBoxLayout.RightToLeft) else: self.__leftLayout.setDirection(QBoxLayout.LeftToRight) self.__leftLayout.setSizeConstraint(QLayout.SetFixedSize) self.__rightWidget = E5LineEditSideWidget(self) self.__rightWidget.resize(0, 0) self.__rightLayout = QHBoxLayout(self.__rightWidget) self.__rightLayout.setContentsMargins(0, 0, 2, 0) if self.isRightToLeft(): self.__rightLayout.setDirection(QBoxLayout.RightToLeft) else: self.__rightLayout.setDirection(QBoxLayout.LeftToRight) horizontalSpacer = QSpacerItem( 0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum) self.__mainLayout.addWidget( self.__leftWidget, 0, Qt.AlignVCenter | Qt.AlignLeft) self.__mainLayout.addItem(horizontalSpacer) self.__mainLayout.addWidget( self.__rightWidget, 0, Qt.AlignVCenter | Qt.AlignRight) if self.isRightToLeft(): self.__mainLayout.setDirection(QBoxLayout.RightToLeft) else: self.__mainLayout.setDirection(QBoxLayout.LeftToRight) self.setWidgetSpacing(3) self.__leftWidget.sizeHintChanged.connect(self._updateTextMargins) self.__rightWidget.sizeHintChanged.connect(self._updateTextMargins) def setLeftMargin(self, margin): """ Public method to set the left margin. @param margin left margin in pixel (integer) """ self.__leftMargin = margin def leftMargin(self): """ Public method to get the size of the left margin. @return left margin in pixel (integer) """ return self.__leftMargin def event(self, evt): """ Public method to handle events. @param evt reference to the event (QEvent) @return flag indicating, whether the event was recognized (boolean) """ if evt.type() == QEvent.LayoutDirectionChange: if self.isRightToLeft(): self.__mainLayout.setDirection(QBoxLayout.RightToLeft) self.__leftLayout.setDirection(QBoxLayout.RightToLeft) self.__rightLayout.setDirection(QBoxLayout.RightToLeft) else: self.__mainLayout.setDirection(QBoxLayout.LeftToRight) self.__leftLayout.setDirection(QBoxLayout.LeftToRight) self.__rightLayout.setDirection(QBoxLayout.LeftToRight) return QLineEdit.event(self, evt) def paintEvent(self, evt): """ Protected method handling a paint event. @param evt reference to the paint event (QPaintEvent) """ super(E5LineEdit, self).paintEvent(evt) if qVersion() < "4.7.0": if not self.text() and \ self.__inactiveText and \ not self.hasFocus(): panel = QStyleOptionFrame() self.initStyleOption(panel) textRect = self.style().subElementRect( QStyle.SE_LineEditContents, panel, self) textRect.adjust(2, 0, 0, 0) left = self.textMargin(self.LeftSide) right = self.textMargin(self.RightSide) textRect.adjust(left, 0, -right, 0) painter = QPainter(self) painter.setPen(self.palette().brush( QPalette.Disabled, QPalette.Text).color()) painter.drawText( textRect, Qt.AlignLeft | Qt.AlignVCenter, self.__inactiveText) def _updateTextMargins(self): """ Protected slot to update the text margins. """ if self.__leftMargin == 0: left = self.__leftWidget.sizeHint().width() else: left = self.__leftMargin right = self.__rightWidget.sizeHint().width() top = 0 bottom = 0 self.setTextMargins(left, top, right, bottom) def addWidget(self, widget, position): """ Public method to add a widget to a side. @param widget reference to the widget to add (QWidget) @param position position to add to (E5LineEdit.LeftSide, E5LineEdit.RightSide) """ if widget is None: return if self.isRightToLeft(): if position == self.LeftSide: position = self.RightSide else: position = self.LeftSide if position == self.LeftSide: self.__leftLayout.addWidget(widget) else: self.__rightLayout.insertWidget(1, widget) def removeWidget(self, widget): """ Public method to remove a widget from a side. @param widget reference to the widget to remove (QWidget) """ if widget is None: return self.__leftLayout.removeWidget(widget) self.__rightLayout.removeWidget(widget) widget.hide() def widgetSpacing(self): """ Public method to get the side widget spacing. @return side widget spacing (integer) """ return self.__leftLayout.spacing() def setWidgetSpacing(self, spacing): """ Public method to set the side widget spacing. @param spacing side widget spacing (integer) """ self.__leftLayout.setSpacing(spacing) self.__rightLayout.setSpacing(spacing) self._updateTextMargins() def textMargin(self, position): """ Public method to get the text margin for a side. @param position side to get margin for (E5LineEdit.LeftSide, E5LineEdit.RightSide) @return text margin (integer) """ spacing = self.__rightLayout.spacing() w = 0 if position == self.LeftSide: w = self.__leftWidget.sizeHint().width() else: w = self.__rightWidget.sizeHint().width() if w == 0: return 0 return w + spacing * 2 def inactiveText(self): """ Public method to get the inactive text. @return inactive text (string) """ if qVersion() < "4.7.0": return self.__inactiveText else: return self.placeholderText() def setInactiveText(self, inactiveText): """ Public method to set the inactive text. @param inactiveText text to be shown on inactivity (string) """ if qVersion() < "4.7.0": self.__inactiveText = inactiveText self.update() else: self.setPlaceholderText(inactiveText)
class ConfigBox(QGroupBox): modified = pyqtSignal() def __init__(self): super(ConfigBox, self).__init__() self._state_engine_option: List[ConfigParam] = [] self._state_use_encryption = True self._state_engine_option_holder: List[Union[QButtonGroup, QDoubleSpinBox]] = [] self._setup_ui() def _setup_ui(self): self.setTitle('Options') self._main_layout = QFormLayout() # Label self._encrypt_option_label = QLabel() self._encrypt_option_label.setText('Encryption') self._encrypt_password_label = QLabel() self._encrypt_password_label.setText('Key') # Encryption radio self._encrypt_option_group = QButtonGroup() self._encrypt_option_layout = QHBoxLayout() self._encrypt_option = QRadioButton() self._encrypt_option.setText('Enabled') self._encrypt_option.setChecked(True) self._encrypt_option.clicked.connect(self._on_radio_selected) self._no_encrypt_option = QRadioButton() self._no_encrypt_option.setText('Disabled') self._no_encrypt_option.clicked.connect(self._on_radio_selected) self._encrypt_option_group.addButton(self._encrypt_option) self._encrypt_option_group.setId(self._encrypt_option, 1) self._encrypt_option_layout.addWidget(self._encrypt_option) self._encrypt_option_group.addButton(self._no_encrypt_option) self._encrypt_option_group.setId(self._no_encrypt_option, 0) self._encrypt_option_layout.addWidget(self._no_encrypt_option) self._encrypt_option_layout.addStretch() # Encryption password self._encrypt_password = QLineEdit() self._encrypt_password.setMaxLength(25) self._encrypt_password.setText(StringUtil.generate_random_string(6)) # Engine options self._engine_option_layout = QVBoxLayout() # Add to layout self._main_layout.addRow(self._encrypt_option_label, self._encrypt_option_layout) self._main_layout.addRow(self._encrypt_password_label, self._encrypt_password) self.setLayout(self._main_layout) def disable_encrypt_option(self): self._encrypt_option_layout.removeWidget(self._encrypt_option) self._encrypt_option_layout.removeWidget(self._no_encrypt_option) label = QLabel() label.setText('Will be determined by file metadata') self._encrypt_option_layout.addWidget(label) def set_engine_option(self, engine_option: List[ConfigParam]): row_count = self._main_layout.rowCount() for i in range(row_count - 1, 1, -1): self._main_layout.removeRow(i) if len(engine_option) == 0: return self._state_engine_option = engine_option self._state_engine_option_holder.clear() for param in engine_option: engine_option_label = QLabel() engine_option_label.setText(param.title) if param.config_type == ConfigType.RADIO: assert isinstance(param, RadioParam) option_group = QButtonGroup() button_layout = QHBoxLayout() for idx, (key, value) in enumerate(param.options.items()): radio_btn = QRadioButton() radio_btn.setText(value) if idx == 0: radio_btn.setChecked(True) radio_btn.clicked.connect(lambda: self.modified.emit()) option_group.addButton(radio_btn) option_group.setId(radio_btn, idx) button_layout.addWidget(radio_btn) self._main_layout.addRow(engine_option_label, button_layout) self._state_engine_option_holder.append(option_group) elif param.config_type == ConfigType.FLOAT: assert isinstance(param, FloatParam) spinbox = QDoubleSpinBox() spinbox.setValue(param.default) spinbox.setMinimum(0) spinbox.setSingleStep(param.step) spinbox.valueChanged.connect(lambda: self.modified.emit()) self._state_engine_option_holder.append(spinbox) self._main_layout.addRow(engine_option_label, spinbox) @property def config(self) -> Tuple[str, List[Union[str, float, bool]]]: encryption_key = self._encrypt_password.text() engine_param = [self._state_use_encryption] for idx, param in enumerate(self._state_engine_option): holder = self._state_engine_option_holder[idx] if param.config_type == ConfigType.FLOAT: assert isinstance(holder, QDoubleSpinBox) engine_param.append(holder.value()) else: assert isinstance(holder, QButtonGroup) assert isinstance(param, RadioParam) option = param.options engine_param.append(list(option.keys())[holder.checkedId()]) return encryption_key, engine_param def _on_radio_selected(self): # self._encrypt_password.setDisabled(self._encrypt_option_group.checkedId() == 0) self._state_use_encryption = self._encrypt_option_group.checkedId( ) == 1
class ESCPanel(QDialog): DEFAULT_INTERVAL = 0.1 CMD_BIT_LENGTH = uavcan.get_uavcan_data_type(uavcan.equipment.esc.RawCommand().cmd).value_type.bitlen CMD_MAX = 2 ** (CMD_BIT_LENGTH - 1) - 1 CMD_MIN = -(2 ** (CMD_BIT_LENGTH - 1)) def __init__(self, parent, node): super(ESCPanel, self).__init__(parent) self.setWindowTitle("ESC Management Panel") self.setAttribute(Qt.WA_DeleteOnClose) # This is required to stop background timers! self._node = node self._sliders = [PercentSlider(self) for _ in range(4)] self._num_sliders = QSpinBox(self) self._num_sliders.setMinimum(len(self._sliders)) self._num_sliders.setMaximum(20) self._num_sliders.setValue(len(self._sliders)) self._num_sliders.valueChanged.connect(self._update_number_of_sliders) self._bcast_interval = QDoubleSpinBox(self) self._bcast_interval.setMinimum(0.01) self._bcast_interval.setMaximum(1.0) self._bcast_interval.setSingleStep(0.1) self._bcast_interval.setValue(self.DEFAULT_INTERVAL) self._bcast_interval.valueChanged.connect( lambda: self._bcast_timer.setInterval(self._bcast_interval.value() * 1e3) ) self._stop_all = make_icon_button( "hand-stop-o", "Zero all channels", self, text="Stop All", on_clicked=self._do_stop_all ) self._pause = make_icon_button("pause", "Pause publishing", self, checkable=True, text="Pause") self._msg_viewer = QPlainTextEdit(self) self._msg_viewer.setReadOnly(True) self._msg_viewer.setLineWrapMode(QPlainTextEdit.NoWrap) self._msg_viewer.setFont(get_monospace_font()) self._msg_viewer.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._msg_viewer.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._bcast_timer = QTimer(self) self._bcast_timer.start(self.DEFAULT_INTERVAL * 1e3) self._bcast_timer.timeout.connect(self._do_broadcast) layout = QVBoxLayout(self) self._slider_layout = QHBoxLayout(self) for sl in self._sliders: self._slider_layout.addWidget(sl) layout.addLayout(self._slider_layout) layout.addWidget(self._stop_all) controls_layout = QHBoxLayout(self) controls_layout.addWidget(QLabel("Channels:", self)) controls_layout.addWidget(self._num_sliders) controls_layout.addWidget(QLabel("Broadcast interval:", self)) controls_layout.addWidget(self._bcast_interval) controls_layout.addWidget(QLabel("sec", self)) controls_layout.addStretch() controls_layout.addWidget(self._pause) layout.addLayout(controls_layout) layout.addWidget(QLabel("Generated message:", self)) layout.addWidget(self._msg_viewer) self.setLayout(layout) self.resize(self.minimumWidth(), self.minimumHeight()) def _do_broadcast(self): try: if not self._pause.isChecked(): msg = uavcan.equipment.esc.RawCommand() for sl in self._sliders: raw_value = sl.get_value() / 100 value = (-self.CMD_MIN if raw_value < 0 else self.CMD_MAX) * raw_value msg.cmd.append(int(value)) self._node.broadcast(msg) self._msg_viewer.setPlainText(uavcan.to_yaml(msg)) else: self._msg_viewer.setPlainText("Paused") except Exception as ex: self._msg_viewer.setPlainText("Publishing failed:\n" + str(ex)) def _do_stop_all(self): for sl in self._sliders: sl.zero() def _update_number_of_sliders(self): num_sliders = self._num_sliders.value() while len(self._sliders) > num_sliders: removee = self._sliders[-1] self._sliders = self._sliders[:-1] self._slider_layout.removeWidget(removee) removee.close() removee.deleteLater() while len(self._sliders) < num_sliders: new = PercentSlider(self) self._slider_layout.addWidget(new) self._sliders.append(new) def deferred_resize(): self.resize(self.minimumWidth(), self.height()) deferred_resize() # noinspection PyCallByClass,PyTypeChecker QTimer.singleShot(200, deferred_resize) def __del__(self): global _singleton _singleton = None def closeEvent(self, event): global _singleton _singleton = None super(ESCPanel, self).closeEvent(event)
class SecondTest(QWidget): def __init__(self): self.title = "test window" self.X = 100 self.Y = 100 self.Width = 300 self.Height = 300 super(SecondTest, self).__init__() self.init_window() def init_window(self): self.title = "It Is A Test Window" self.setWindowTitle(self.title) self.setGeometry(self.X, self.Y, self.Width, self.Height) self.create_gui() self.show() def create_gui(self): # creating spacer item self.VSpacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.HSpacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.MainLayout = QHBoxLayout() self.setLayout(self.MainLayout) # Menu Button's self.MenuLayout = QVBoxLayout() self.MainLayout.addLayout(self.MenuLayout) self.FirstSlide = QPushButton("First Slide") self.SecondSlide = QPushButton("Second Slide") self.ThirdSlide = QPushButton("Third Slide") self.FirstSlide.clicked.connect(lambda l: self.change_slide_count(1)) self.SecondSlide.clicked.connect(lambda l: self.change_slide_count(2)) self.ThirdSlide.clicked.connect(lambda l: self.change_slide_count(3)) self.SlideNumber = QLabel("1..........") self.MenuLayout.addWidget(self.FirstSlide) self.MenuLayout.addWidget(self.SecondSlide) self.MenuLayout.addWidget(self.ThirdSlide) self.MenuLayout.addWidget(self.SlideNumber) self.MenuLayout.addItem(self.VSpacerItem) #self.MainSlideFrame = QFrame() #self.MainLayout.addWidget(self.MainSlideFrame) #slide 1st self.SlideFrame1 = QFrame() self.SlideLayout1 = QHBoxLayout() self.SlideFrame1.setLayout(self.SlideLayout1) button = QPushButton("111111111111111111") self.SlideLayout1.addWidget(button) # slide 2st self.SlideFrame2 = QFrame() self.SlideLayout2 = QHBoxLayout() self.SlideFrame2.setLayout(self.SlideLayout2) button = QPushButton("222222222222") self.SlideLayout2.addWidget(button) # slide 3st self.SlideFrame3 = QFrame() self.SlideLayout3 = QHBoxLayout() self.SlideFrame3.setLayout(self.SlideLayout3) button = QPushButton("333333") self.SlideLayout3.addWidget(button) #self.MainSlideFrame.setLayout(self.SlideLayout1) #self.LastSlide = self.SlideLayout1 self.MainLayout.addWidget(self.SlideFrame1) self.MainLayout.addWidget(self.SlideFrame2) self.MainLayout.addWidget(self.SlideFrame3) def change_slide_count1(self, slide): if slide == 1: print(self.MainLayout) self.MainLayout.removeWidget(self.LastSlide) self.LastSlide = self.SlideFrame1 self.MainLayout.addWidget(self.SlideFrame1) self.SlideNumber.setText("1.....") elif slide == 2: self.MainLayout.removeWidget(self.LastSlide) self.LastSlide = self.SlideFrame2 self.MainLayout.addWidget(self.SlideFrame2) self.SlideNumber.setText("2.....") elif slide == 3: self.MainLayout.removeWidget(self.LastSlide) self.LastSlide = self.SlideFrame3 self.MainLayout.addWidget(self.SlideFrame3) self.SlideNumber.setText("3.....") def change_slide_count2(self, slide): if slide == 1: self.MainSlideFrame.setLayout(self.SlideLayout1) self.SlideNumber.setText("1.....") if slide == 2: self.MainSlideFrame.setLayout(self.SlideLayout2) self.SlideNumber.setText("2.....") if slide == 3: self.MainSlideFrame.setLayout(self.SlideLayout3) self.SlideNumber.setText("3.....") def change_slide_count(self, slide): if slide == 1: self.SlideFrame1.show() self.SlideFrame2.hide() self.SlideFrame3.hide() if slide == 2: self.SlideFrame2.show() self.SlideFrame3.hide() self.SlideFrame1.hide() if slide == 3: self.SlideFrame3.show() self.SlideFrame2.hide() self.SlideFrame1.hide()