vibefpmgui.widgets
Small widgets shared by the window's parts.
1"""Small widgets shared by the window's parts.""" 2 3from qtpy.QtCore import QSize, Qt, Signal 4from qtpy.QtWidgets import QDialog, QLabel, QLineEdit, QMenu, QPushButton, QSizePolicy 5 6 7class StatusLabel(QLabel): 8 """A label for a line of status whose text keeps changing (an editor's 9 status line, a panel's progress): it asks for its text's width when 10 there's room, but needs only a little. A plain label's minimum width is 11 its whole text, so a longer status ("154 AI review notes", "… · context 12 ~14k of 32k") made the window wider, past the screen's edge for a window 13 filling it. When narrow, the text is cut off at the right.""" 14 15 MINIMUM_WIDTH = 40 16 17 def minimumSizeHint(self) -> QSize: 18 hint = super().minimumSizeHint() 19 return QSize(min(hint.width(), self.MINIMUM_WIDTH), hint.height()) 20 21 22class HistoryLineEdit(QLineEdit): 23 """A field for commands, as a shell's: Enter sends its text 24 (``submitted``), remembers it, and clears the field; Up and Down go 25 through what was sent (Down past the last one: what was being typed). 26 The history is this field's own, for as long as it lives (not saved).""" 27 28 submitted = Signal(str) 29 30 def __init__(self, parent=None): 31 super().__init__(parent) 32 self.history: list[str] = [] 33 self._index = 0 # (in history; len(history): the text being typed, not sent yet) 34 self._draft = "" 35 self.returnPressed.connect(self._submit) 36 37 def _submit(self): 38 text = self.text().strip() 39 if not text: 40 return 41 if not self.history or self.history[-1] != text: # (the same twice in a row: kept once) 42 self.history.append(text) 43 self._index, self._draft = len(self.history), "" 44 self.clear() 45 self.submitted.emit(text) 46 47 def keyPressEvent(self, event): 48 key = event.key() 49 if key == Qt.Key_Up and self._index > 0: 50 if self._index == len(self.history): 51 self._draft = self.text() 52 self._index -= 1 53 self.setText(self.history[self._index]) 54 elif key == Qt.Key_Down and self._index < len(self.history): 55 self._index += 1 56 self.setText(self._draft if self._index == len(self.history) else self.history[self._index]) 57 elif key in (Qt.Key_Up, Qt.Key_Down): 58 pass # (no earlier, or later, entry) 59 else: 60 super().keyPressEvent(event) 61 62 63def run_dialog(dialog: QDialog) -> int: 64 """Show a dialog until it's closed, then let it go (a dialog that's a 65 child of the window would otherwise stay, hidden, until the app quits).""" 66 try: 67 return dialog.exec() 68 finally: 69 dialog.deleteLater() 70 71 72class StayOpenMenu(QMenu): 73 """A menu that stays open when a checkable item is clicked (to tick several).""" 74 75 def mouseReleaseEvent(self, event): 76 action = self.activeAction() 77 if action is not None and action.isCheckable() and action.isEnabled(): 78 action.trigger() 79 return 80 super().mouseReleaseEvent(event) 81 82 83class MenuButton(QPushButton): 84 """A button that opens a menu, its text cut short with "…" to fit (it 85 doesn't make the panel it's in wider); the whole text is its tooltip.""" 86 87 def __init__(self, parent=None): 88 super().__init__(parent) 89 self._full_text = "" 90 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 91 92 def set_full_text(self, text: str): 93 self._full_text = text 94 self._elide() 95 96 def full_text(self) -> str: 97 return self._full_text 98 99 def minimumSizeHint(self): 100 hint = super().minimumSizeHint() 101 return QSize(60, hint.height()) 102 103 def sizeHint(self): 104 hint = super().sizeHint() 105 return QSize(60, hint.height()) 106 107 def resizeEvent(self, event): 108 super().resizeEvent(event) 109 self._elide() 110 111 def _elide(self): 112 room = max(10, self.width() - 40) # (the menu arrow and the margins) 113 self.setText(self.fontMetrics().elidedText(self._full_text, Qt.ElideRight, room))
8class StatusLabel(QLabel): 9 """A label for a line of status whose text keeps changing (an editor's 10 status line, a panel's progress): it asks for its text's width when 11 there's room, but needs only a little. A plain label's minimum width is 12 its whole text, so a longer status ("154 AI review notes", "… · context 13 ~14k of 32k") made the window wider, past the screen's edge for a window 14 filling it. When narrow, the text is cut off at the right.""" 15 16 MINIMUM_WIDTH = 40 17 18 def minimumSizeHint(self) -> QSize: 19 hint = super().minimumSizeHint() 20 return QSize(min(hint.width(), self.MINIMUM_WIDTH), hint.height())
A label for a line of status whose text keeps changing (an editor's status line, a panel's progress): it asks for its text's width when there's room, but needs only a little. A plain label's minimum width is its whole text, so a longer status ("154 AI review notes", "… · context ~14k of 32k") made the window wider, past the screen's edge for a window filling it. When narrow, the text is cut off at the right.
23class HistoryLineEdit(QLineEdit): 24 """A field for commands, as a shell's: Enter sends its text 25 (``submitted``), remembers it, and clears the field; Up and Down go 26 through what was sent (Down past the last one: what was being typed). 27 The history is this field's own, for as long as it lives (not saved).""" 28 29 submitted = Signal(str) 30 31 def __init__(self, parent=None): 32 super().__init__(parent) 33 self.history: list[str] = [] 34 self._index = 0 # (in history; len(history): the text being typed, not sent yet) 35 self._draft = "" 36 self.returnPressed.connect(self._submit) 37 38 def _submit(self): 39 text = self.text().strip() 40 if not text: 41 return 42 if not self.history or self.history[-1] != text: # (the same twice in a row: kept once) 43 self.history.append(text) 44 self._index, self._draft = len(self.history), "" 45 self.clear() 46 self.submitted.emit(text) 47 48 def keyPressEvent(self, event): 49 key = event.key() 50 if key == Qt.Key_Up and self._index > 0: 51 if self._index == len(self.history): 52 self._draft = self.text() 53 self._index -= 1 54 self.setText(self.history[self._index]) 55 elif key == Qt.Key_Down and self._index < len(self.history): 56 self._index += 1 57 self.setText(self._draft if self._index == len(self.history) else self.history[self._index]) 58 elif key in (Qt.Key_Up, Qt.Key_Down): 59 pass # (no earlier, or later, entry) 60 else: 61 super().keyPressEvent(event)
A field for commands, as a shell's: Enter sends its text
(submitted), remembers it, and clears the field; Up and Down go
through what was sent (Down past the last one: what was being typed).
The history is this field's own, for as long as it lives (not saved).
31 def __init__(self, parent=None): 32 super().__init__(parent) 33 self.history: list[str] = [] 34 self._index = 0 # (in history; len(history): the text being typed, not sent yet) 35 self._draft = "" 36 self.returnPressed.connect(self._submit)
__init__(self, arg__1: str, /, parent: PySide6.QtWidgets.QWidget | None = None, *, inputMask: str | None = None, text: str | None = None, maxLength: int | None = None, frame: bool | None = None, echoMode: PySide6.QtWidgets.QLineEdit.EchoMode | None = None, displayText: str | None = None, cursorPosition: int | None = None, alignment: PySide6.QtCore.Qt.AlignmentFlag | None = None, modified: bool | None = None, hasSelectedText: bool | None = None, selectedText: str | None = None, dragEnabled: bool | None = None, readOnly: bool | None = None, undoAvailable: bool | None = None, redoAvailable: bool | None = None, acceptableInput: bool | None = None, placeholderText: str | None = None, cursorMoveStyle: PySide6.QtCore.Qt.CursorMoveStyle | None = None, clearButtonEnabled: bool | None = None) -> None __init__(self, /, parent: PySide6.QtWidgets.QWidget | None = None, *, inputMask: str | None = None, text: str | None = None, maxLength: int | None = None, frame: bool | None = None, echoMode: PySide6.QtWidgets.QLineEdit.EchoMode | None = None, displayText: str | None = None, cursorPosition: int | None = None, alignment: PySide6.QtCore.Qt.AlignmentFlag | None = None, modified: bool | None = None, hasSelectedText: bool | None = None, selectedText: str | None = None, dragEnabled: bool | None = None, readOnly: bool | None = None, undoAvailable: bool | None = None, redoAvailable: bool | None = None, acceptableInput: bool | None = None, placeholderText: str | None = None, cursorMoveStyle: PySide6.QtCore.Qt.CursorMoveStyle | None = None, clearButtonEnabled: bool | None = None) -> None
Initialize self. See help(type(self)) for accurate signature.
48 def keyPressEvent(self, event): 49 key = event.key() 50 if key == Qt.Key_Up and self._index > 0: 51 if self._index == len(self.history): 52 self._draft = self.text() 53 self._index -= 1 54 self.setText(self.history[self._index]) 55 elif key == Qt.Key_Down and self._index < len(self.history): 56 self._index += 1 57 self.setText(self._draft if self._index == len(self.history) else self.history[self._index]) 58 elif key in (Qt.Key_Up, Qt.Key_Down): 59 pass # (no earlier, or later, entry) 60 else: 61 super().keyPressEvent(event)
keyPressEvent(self, arg__1: PySide6.QtGui.QKeyEvent, /) -> None
64def run_dialog(dialog: QDialog) -> int: 65 """Show a dialog until it's closed, then let it go (a dialog that's a 66 child of the window would otherwise stay, hidden, until the app quits).""" 67 try: 68 return dialog.exec() 69 finally: 70 dialog.deleteLater()
Show a dialog until it's closed, then let it go (a dialog that's a child of the window would otherwise stay, hidden, until the app quits).
73class StayOpenMenu(QMenu): 74 """A menu that stays open when a checkable item is clicked (to tick several).""" 75 76 def mouseReleaseEvent(self, event): 77 action = self.activeAction() 78 if action is not None and action.isCheckable() and action.isEnabled(): 79 action.trigger() 80 return 81 super().mouseReleaseEvent(event)
A menu that stays open when a checkable item is clicked (to tick several).
76 def mouseReleaseEvent(self, event): 77 action = self.activeAction() 78 if action is not None and action.isCheckable() and action.isEnabled(): 79 action.trigger() 80 return 81 super().mouseReleaseEvent(event)
mouseReleaseEvent(self, arg__1: PySide6.QtGui.QMouseEvent, /) -> None
84class MenuButton(QPushButton): 85 """A button that opens a menu, its text cut short with "…" to fit (it 86 doesn't make the panel it's in wider); the whole text is its tooltip.""" 87 88 def __init__(self, parent=None): 89 super().__init__(parent) 90 self._full_text = "" 91 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 92 93 def set_full_text(self, text: str): 94 self._full_text = text 95 self._elide() 96 97 def full_text(self) -> str: 98 return self._full_text 99 100 def minimumSizeHint(self): 101 hint = super().minimumSizeHint() 102 return QSize(60, hint.height()) 103 104 def sizeHint(self): 105 hint = super().sizeHint() 106 return QSize(60, hint.height()) 107 108 def resizeEvent(self, event): 109 super().resizeEvent(event) 110 self._elide() 111 112 def _elide(self): 113 room = max(10, self.width() - 40) # (the menu arrow and the margins) 114 self.setText(self.fontMetrics().elidedText(self._full_text, Qt.ElideRight, room))
A button that opens a menu, its text cut short with "…" to fit (it doesn't make the panel it's in wider); the whole text is its tooltip.
88 def __init__(self, parent=None): 89 super().__init__(parent) 90 self._full_text = "" 91 self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
__init__(self, text: str, /, parent: PySide6.QtWidgets.QWidget | None = None, *, autoDefault: bool | None = None, default: bool | None = None, flat: bool | None = None) -> None __init__(self, icon: PySide6.QtGui.QIcon | PySide6.QtGui.QPixmap, text: str, /, parent: PySide6.QtWidgets.QWidget | None = None, *, autoDefault: bool | None = None, default: bool | None = None, flat: bool | None = None) -> None __init__(self, /, parent: PySide6.QtWidgets.QWidget | None = None, *, autoDefault: bool | None = None, default: bool | None = None, flat: bool | None = None) -> None
Initialize self. See help(type(self)) for accurate signature.
100 def minimumSizeHint(self): 101 hint = super().minimumSizeHint() 102 return QSize(60, hint.height())
minimumSizeHint(self, /) -> PySide6.QtCore.QSize