vibefpmgui.completion

Popups for the language server: the completion list and argument hints.

Both are tooltip-style windows that never take the keyboard focus, so typing continues in the editor; vibefpmgui.code_editor.CodeEditor passes them the keys they use (Up/Down/Enter/Tab/Escape for the completion list).

  1"""Popups for the language server: the completion list and argument hints.
  2
  3Both are tooltip-style windows that never take the keyboard focus, so typing
  4continues in the editor; `vibefpmgui.code_editor.CodeEditor` passes them
  5the keys they use (Up/Down/Enter/Tab/Escape for the completion list).
  6"""
  7
  8from __future__ import annotations
  9
 10from qtpy.QtCore import QRect, QSize, Qt, Signal
 11from qtpy.QtGui import QColor, QPalette
 12from qtpy.QtWidgets import (
 13    QApplication,
 14    QFrame,
 15    QLabel,
 16    QListWidget,
 17    QListWidgetItem,
 18    QStyle,
 19    QStyledItemDelegate,
 20    QVBoxLayout,
 21)
 22
 23from . import lsp as lsp_mod
 24
 25MAX_ROWS = 10
 26ITEM_ROLE = Qt.UserRole + 1
 27
 28
 29def popup_colors(editor) -> tuple[QColor, QColor, QColor]:
 30    """(background, text, border) matching the editor's colors."""
 31    pal = editor.palette()
 32    base, text = pal.color(QPalette.Base), pal.color(QPalette.Text)
 33    bg = base.lighter(115) if base.lightness() < 128 else base.darker(103)
 34    border = QColor(text.red(), text.green(), text.blue(), 90)
 35    return bg, text, border
 36
 37
 38def place(popup, anchor: QRect, below: bool = True):
 39    """Put a popup just below (or above) a global rectangle, on screen."""
 40    screen = (QApplication.screenAt(anchor.center()) or QApplication.primaryScreen()).availableGeometry()
 41    x = min(max(anchor.left(), screen.left()), screen.right() - popup.width())
 42    y = anchor.bottom() + 2 if below else anchor.top() - popup.height() - 2
 43    if below and y + popup.height() > screen.bottom():
 44        y = anchor.top() - popup.height() - 2
 45    elif not below and y < screen.top():
 46        y = anchor.bottom() + 2
 47    popup.move(x, max(screen.top(), y))
 48
 49
 50class _KindDelegate(QStyledItemDelegate):
 51    """Draws each completion's kind (function, variable…) greyed at the right."""
 52
 53    def paint(self, painter, option, index):
 54        super().paint(painter, option, index)
 55        item: lsp_mod.Completion | None = index.data(ITEM_ROLE)
 56        if item is None or not item.kind:
 57            return
 58        painter.save()
 59        painter.setFont(option.font)
 60        color = option.palette.color(QPalette.HighlightedText if option.state & QStyle.State_Selected
 61                                     else QPalette.Text)
 62        color.setAlpha(140)
 63        painter.setPen(color)
 64        painter.drawText(option.rect.adjusted(0, 0, -8, 0), Qt.AlignRight | Qt.AlignVCenter, item.kind)
 65        painter.restore()
 66
 67
 68class CompletionPopup(QFrame):
 69    """The list of completions for the name being typed."""
 70
 71    accepted = Signal(object)  # the Completion chosen (double-click)
 72
 73    def __init__(self, editor):
 74        super().__init__(editor, Qt.ToolTip | Qt.FramelessWindowHint)
 75        self.editor = editor
 76        self.setFrameShape(QFrame.Box)
 77        self.items: list[lsp_mod.Completion] = []
 78        self.start: tuple[int, int] | None = None  # (block number, column) the name starts at
 79        self.list = QListWidget()
 80        self.list.setFocusPolicy(Qt.NoFocus)
 81        self.list.setFrameShape(QFrame.NoFrame)
 82        self.list.setUniformItemSizes(True)
 83        self.list.setItemDelegate(_KindDelegate(self.list))
 84        self.list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
 85        self.list.currentRowChanged.connect(self._show_detail)
 86        self.list.itemDoubleClicked.connect(lambda item: self.accepted.emit(item.data(ITEM_ROLE)))
 87        self.detail = QLabel()
 88        self.detail.setWordWrap(True)
 89        self.detail.setTextFormat(Qt.PlainText)
 90        self.detail.setContentsMargins(6, 3, 6, 4)
 91        layout = QVBoxLayout(self)
 92        layout.setContentsMargins(1, 1, 1, 1)
 93        layout.setSpacing(0)
 94        layout.addWidget(self.list)
 95        layout.addWidget(self.detail)
 96
 97    def open(self, items: list[lsp_mod.Completion], start: tuple[int, int], prefix: str,
 98             anchor: QRect) -> bool:
 99        """Show ``items`` matching ``prefix``; False (and hidden) if none do."""
100        self.items, self.start = items, start
101        bg, text, border = popup_colors(self.editor)
102        # The popup is never the active window, so give the selection the
103        # active colors explicitly (the inactive ones are hard to see).
104        pal = QApplication.palette()
105        sel, sel_text = pal.color(QPalette.Active, QPalette.Highlight), pal.color(QPalette.Active,
106                                                                                 QPalette.HighlightedText)
107        self.setStyleSheet(f"CompletionPopup {{ background: {bg.name()}; border: 1px solid "
108                           f"{border.name(QColor.HexArgb)}; }} QListWidget, QLabel {{ background: "
109                           f"{bg.name()}; color: {text.name()}; }}"
110                           f"QListWidget::item:selected {{ background: {sel.name()}; color: {sel_text.name()}; }}")
111        for widget in (self, self.list, self.detail):
112            widget.setFont(self.editor.font())
113        if not self.filter(prefix):
114            return False
115        place(self, anchor)
116        self.show()
117        return True
118
119    def filter(self, prefix: str) -> bool:
120        """Show the items matching what has been typed (names starting with
121        it first, then names containing it); False if nothing matches."""
122        lower = prefix.lower()
123        matches = [c for c in self.items if c.label.lower().startswith(lower)]
124        matches += [c for c in self.items if lower and lower in c.label.lower()[1:]
125                    and not c.label.lower().startswith(lower)]
126        if not matches or (len(matches) == 1 and matches[0].label == prefix):
127            self.hide()  # nothing to offer (or it's already typed out)
128            return False
129        self.list.clear()
130        for c in matches:
131            item = QListWidgetItem(c.label)
132            item.setData(ITEM_ROLE, c)
133            self.list.addItem(item)
134        self.list.setCurrentRow(0)
135        metrics = self.list.fontMetrics()
136        row_h = self.list.sizeHintForRow(0)
137        width = max(metrics.horizontalAdvance(c.label + "    " + c.kind) for c in matches[:200]) + 40
138        width = min(max(width, 260), 560)
139        self.list.setFixedSize(QSize(width, row_h * min(MAX_ROWS, len(matches)) + 4))
140        self.detail.setFixedWidth(width)
141        self._show_detail(0)
142        return True
143
144    def _fit(self):
145        """Size the popup to the list plus the detail line. (adjustSize()
146        only ever grows a window, so a shorter list left a gap.)"""
147        detail_h = self.detail.heightForWidth(self.detail.width()) if self.detail.isVisibleTo(self) else 0
148        self.detail.setFixedHeight(max(detail_h, 0))
149        self.setFixedSize(self.list.width() + 2, self.list.height() + detail_h + 2)
150
151    def _show_detail(self, row: int):
152        item = self.list.item(row)
153        c: lsp_mod.Completion | None = item.data(ITEM_ROLE) if item else None
154        text = c.detail if c else ""
155        self.detail.setText(text)
156        self.detail.setVisible(bool(text))
157        self._fit()
158
159    def move_selection(self, step: int):
160        rows = self.list.count()
161        if rows:
162            row = self.list.currentRow() + step
163            self.list.setCurrentRow(max(0, min(rows - 1, row)))
164
165    def current(self) -> lsp_mod.Completion | None:
166        item = self.list.currentItem()
167        return item.data(ITEM_ROLE) if item else None
168
169    def page_rows(self) -> int:
170        return MAX_ROWS - 1
171
172
173class SignaturePopup(QLabel):
174    """Argument hints for the call being typed: the routine's arguments with
175    the current one in bold, and that argument's declaration."""
176
177    def __init__(self, editor):
178        super().__init__(editor, Qt.ToolTip | Qt.FramelessWindowHint)
179        self.editor = editor
180        self.setTextFormat(Qt.RichText)
181        self.setWordWrap(False)
182        self.setMargin(6)
183        self.line: int | None = None  # the block the hint is for
184
185    def open(self, text_html: str, line: int, anchor: QRect):
186        bg, text, border = popup_colors(self.editor)
187        self.setStyleSheet(f"SignaturePopup {{ background: {bg.name()}; color: {text.name()}; "
188                           f"border: 1px solid {border.name(QColor.HexArgb)}; }}")
189        self.setFont(self.editor.font())
190        self.setText(text_html)
191        self.line = line
192        self.adjustSize()
193        screen = (QApplication.screenAt(anchor.center()) or QApplication.primaryScreen()).availableGeometry()
194        if self.width() > screen.width() * 0.8:
195            self.setWordWrap(True)
196            self.setFixedWidth(int(screen.width() * 0.8))
197            self.adjustSize()
198        place(self, anchor, below=False)  # above the line, so the completion list fits below
199        self.show()
200
201    def hideEvent(self, event):
202        self.line = None
203        super().hideEvent(event)
204
205
206def global_rect(editor, cursor) -> QRect:
207    """The cursor's rectangle in screen coordinates."""
208    rect = editor.cursorRect(cursor)
209    return QRect(editor.viewport().mapToGlobal(rect.topLeft()), rect.size())
MAX_ROWS = 10
ITEM_ROLE = 257
def place(popup, anchor: PySide6.QtCore.QRect, below: bool = True):
39def place(popup, anchor: QRect, below: bool = True):
40    """Put a popup just below (or above) a global rectangle, on screen."""
41    screen = (QApplication.screenAt(anchor.center()) or QApplication.primaryScreen()).availableGeometry()
42    x = min(max(anchor.left(), screen.left()), screen.right() - popup.width())
43    y = anchor.bottom() + 2 if below else anchor.top() - popup.height() - 2
44    if below and y + popup.height() > screen.bottom():
45        y = anchor.top() - popup.height() - 2
46    elif not below and y < screen.top():
47        y = anchor.bottom() + 2
48    popup.move(x, max(screen.top(), y))

Put a popup just below (or above) a global rectangle, on screen.

class CompletionPopup(PySide6.QtWidgets.QFrame):
 69class CompletionPopup(QFrame):
 70    """The list of completions for the name being typed."""
 71
 72    accepted = Signal(object)  # the Completion chosen (double-click)
 73
 74    def __init__(self, editor):
 75        super().__init__(editor, Qt.ToolTip | Qt.FramelessWindowHint)
 76        self.editor = editor
 77        self.setFrameShape(QFrame.Box)
 78        self.items: list[lsp_mod.Completion] = []
 79        self.start: tuple[int, int] | None = None  # (block number, column) the name starts at
 80        self.list = QListWidget()
 81        self.list.setFocusPolicy(Qt.NoFocus)
 82        self.list.setFrameShape(QFrame.NoFrame)
 83        self.list.setUniformItemSizes(True)
 84        self.list.setItemDelegate(_KindDelegate(self.list))
 85        self.list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
 86        self.list.currentRowChanged.connect(self._show_detail)
 87        self.list.itemDoubleClicked.connect(lambda item: self.accepted.emit(item.data(ITEM_ROLE)))
 88        self.detail = QLabel()
 89        self.detail.setWordWrap(True)
 90        self.detail.setTextFormat(Qt.PlainText)
 91        self.detail.setContentsMargins(6, 3, 6, 4)
 92        layout = QVBoxLayout(self)
 93        layout.setContentsMargins(1, 1, 1, 1)
 94        layout.setSpacing(0)
 95        layout.addWidget(self.list)
 96        layout.addWidget(self.detail)
 97
 98    def open(self, items: list[lsp_mod.Completion], start: tuple[int, int], prefix: str,
 99             anchor: QRect) -> bool:
100        """Show ``items`` matching ``prefix``; False (and hidden) if none do."""
101        self.items, self.start = items, start
102        bg, text, border = popup_colors(self.editor)
103        # The popup is never the active window, so give the selection the
104        # active colors explicitly (the inactive ones are hard to see).
105        pal = QApplication.palette()
106        sel, sel_text = pal.color(QPalette.Active, QPalette.Highlight), pal.color(QPalette.Active,
107                                                                                 QPalette.HighlightedText)
108        self.setStyleSheet(f"CompletionPopup {{ background: {bg.name()}; border: 1px solid "
109                           f"{border.name(QColor.HexArgb)}; }} QListWidget, QLabel {{ background: "
110                           f"{bg.name()}; color: {text.name()}; }}"
111                           f"QListWidget::item:selected {{ background: {sel.name()}; color: {sel_text.name()}; }}")
112        for widget in (self, self.list, self.detail):
113            widget.setFont(self.editor.font())
114        if not self.filter(prefix):
115            return False
116        place(self, anchor)
117        self.show()
118        return True
119
120    def filter(self, prefix: str) -> bool:
121        """Show the items matching what has been typed (names starting with
122        it first, then names containing it); False if nothing matches."""
123        lower = prefix.lower()
124        matches = [c for c in self.items if c.label.lower().startswith(lower)]
125        matches += [c for c in self.items if lower and lower in c.label.lower()[1:]
126                    and not c.label.lower().startswith(lower)]
127        if not matches or (len(matches) == 1 and matches[0].label == prefix):
128            self.hide()  # nothing to offer (or it's already typed out)
129            return False
130        self.list.clear()
131        for c in matches:
132            item = QListWidgetItem(c.label)
133            item.setData(ITEM_ROLE, c)
134            self.list.addItem(item)
135        self.list.setCurrentRow(0)
136        metrics = self.list.fontMetrics()
137        row_h = self.list.sizeHintForRow(0)
138        width = max(metrics.horizontalAdvance(c.label + "    " + c.kind) for c in matches[:200]) + 40
139        width = min(max(width, 260), 560)
140        self.list.setFixedSize(QSize(width, row_h * min(MAX_ROWS, len(matches)) + 4))
141        self.detail.setFixedWidth(width)
142        self._show_detail(0)
143        return True
144
145    def _fit(self):
146        """Size the popup to the list plus the detail line. (adjustSize()
147        only ever grows a window, so a shorter list left a gap.)"""
148        detail_h = self.detail.heightForWidth(self.detail.width()) if self.detail.isVisibleTo(self) else 0
149        self.detail.setFixedHeight(max(detail_h, 0))
150        self.setFixedSize(self.list.width() + 2, self.list.height() + detail_h + 2)
151
152    def _show_detail(self, row: int):
153        item = self.list.item(row)
154        c: lsp_mod.Completion | None = item.data(ITEM_ROLE) if item else None
155        text = c.detail if c else ""
156        self.detail.setText(text)
157        self.detail.setVisible(bool(text))
158        self._fit()
159
160    def move_selection(self, step: int):
161        rows = self.list.count()
162        if rows:
163            row = self.list.currentRow() + step
164            self.list.setCurrentRow(max(0, min(rows - 1, row)))
165
166    def current(self) -> lsp_mod.Completion | None:
167        item = self.list.currentItem()
168        return item.data(ITEM_ROLE) if item else None
169
170    def page_rows(self) -> int:
171        return MAX_ROWS - 1

The list of completions for the name being typed.

CompletionPopup(editor)
74    def __init__(self, editor):
75        super().__init__(editor, Qt.ToolTip | Qt.FramelessWindowHint)
76        self.editor = editor
77        self.setFrameShape(QFrame.Box)
78        self.items: list[lsp_mod.Completion] = []
79        self.start: tuple[int, int] | None = None  # (block number, column) the name starts at
80        self.list = QListWidget()
81        self.list.setFocusPolicy(Qt.NoFocus)
82        self.list.setFrameShape(QFrame.NoFrame)
83        self.list.setUniformItemSizes(True)
84        self.list.setItemDelegate(_KindDelegate(self.list))
85        self.list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
86        self.list.currentRowChanged.connect(self._show_detail)
87        self.list.itemDoubleClicked.connect(lambda item: self.accepted.emit(item.data(ITEM_ROLE)))
88        self.detail = QLabel()
89        self.detail.setWordWrap(True)
90        self.detail.setTextFormat(Qt.PlainText)
91        self.detail.setContentsMargins(6, 3, 6, 4)
92        layout = QVBoxLayout(self)
93        layout.setContentsMargins(1, 1, 1, 1)
94        layout.setSpacing(0)
95        layout.addWidget(self.list)
96        layout.addWidget(self.detail)

__init__(self, /, parent: PySide6.QtWidgets.QWidget | None = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags), *, frameShape: PySide6.QtWidgets.QFrame.Shape | None = None, frameShadow: PySide6.QtWidgets.QFrame.Shadow | None = None, lineWidth: int | None = None, midLineWidth: int | None = None, frameWidth: int | None = None, frameRect: PySide6.QtCore.QRect | None = None) -> None

Initialize self. See help(type(self)) for accurate signature.

def accepted(unknown):

The type of the None singleton.

editor
start: tuple[int, int] | None
list
detail
def open( self, items: list[vibefpmgui.lsp.Completion], start: tuple[int, int], prefix: str, anchor: PySide6.QtCore.QRect) -> bool:
 98    def open(self, items: list[lsp_mod.Completion], start: tuple[int, int], prefix: str,
 99             anchor: QRect) -> bool:
100        """Show ``items`` matching ``prefix``; False (and hidden) if none do."""
101        self.items, self.start = items, start
102        bg, text, border = popup_colors(self.editor)
103        # The popup is never the active window, so give the selection the
104        # active colors explicitly (the inactive ones are hard to see).
105        pal = QApplication.palette()
106        sel, sel_text = pal.color(QPalette.Active, QPalette.Highlight), pal.color(QPalette.Active,
107                                                                                 QPalette.HighlightedText)
108        self.setStyleSheet(f"CompletionPopup {{ background: {bg.name()}; border: 1px solid "
109                           f"{border.name(QColor.HexArgb)}; }} QListWidget, QLabel {{ background: "
110                           f"{bg.name()}; color: {text.name()}; }}"
111                           f"QListWidget::item:selected {{ background: {sel.name()}; color: {sel_text.name()}; }}")
112        for widget in (self, self.list, self.detail):
113            widget.setFont(self.editor.font())
114        if not self.filter(prefix):
115            return False
116        place(self, anchor)
117        self.show()
118        return True

Show items matching prefix; False (and hidden) if none do.

def filter(self, prefix: str) -> bool:
120    def filter(self, prefix: str) -> bool:
121        """Show the items matching what has been typed (names starting with
122        it first, then names containing it); False if nothing matches."""
123        lower = prefix.lower()
124        matches = [c for c in self.items if c.label.lower().startswith(lower)]
125        matches += [c for c in self.items if lower and lower in c.label.lower()[1:]
126                    and not c.label.lower().startswith(lower)]
127        if not matches or (len(matches) == 1 and matches[0].label == prefix):
128            self.hide()  # nothing to offer (or it's already typed out)
129            return False
130        self.list.clear()
131        for c in matches:
132            item = QListWidgetItem(c.label)
133            item.setData(ITEM_ROLE, c)
134            self.list.addItem(item)
135        self.list.setCurrentRow(0)
136        metrics = self.list.fontMetrics()
137        row_h = self.list.sizeHintForRow(0)
138        width = max(metrics.horizontalAdvance(c.label + "    " + c.kind) for c in matches[:200]) + 40
139        width = min(max(width, 260), 560)
140        self.list.setFixedSize(QSize(width, row_h * min(MAX_ROWS, len(matches)) + 4))
141        self.detail.setFixedWidth(width)
142        self._show_detail(0)
143        return True

Show the items matching what has been typed (names starting with it first, then names containing it); False if nothing matches.

def move_selection(self, step: int):
160    def move_selection(self, step: int):
161        rows = self.list.count()
162        if rows:
163            row = self.list.currentRow() + step
164            self.list.setCurrentRow(max(0, min(rows - 1, row)))
def current(self) -> vibefpmgui.lsp.Completion | None:
166    def current(self) -> lsp_mod.Completion | None:
167        item = self.list.currentItem()
168        return item.data(ITEM_ROLE) if item else None
def page_rows(self) -> int:
170    def page_rows(self) -> int:
171        return MAX_ROWS - 1
staticMetaObject = PySide6.QtCore.QMetaObject("CompletionPopup" inherits "QFrame": Methods: #33 type=Signal, signature=accepted(PyObject), parameters=PyObject )
class SignaturePopup(PySide6.QtWidgets.QLabel):
174class SignaturePopup(QLabel):
175    """Argument hints for the call being typed: the routine's arguments with
176    the current one in bold, and that argument's declaration."""
177
178    def __init__(self, editor):
179        super().__init__(editor, Qt.ToolTip | Qt.FramelessWindowHint)
180        self.editor = editor
181        self.setTextFormat(Qt.RichText)
182        self.setWordWrap(False)
183        self.setMargin(6)
184        self.line: int | None = None  # the block the hint is for
185
186    def open(self, text_html: str, line: int, anchor: QRect):
187        bg, text, border = popup_colors(self.editor)
188        self.setStyleSheet(f"SignaturePopup {{ background: {bg.name()}; color: {text.name()}; "
189                           f"border: 1px solid {border.name(QColor.HexArgb)}; }}")
190        self.setFont(self.editor.font())
191        self.setText(text_html)
192        self.line = line
193        self.adjustSize()
194        screen = (QApplication.screenAt(anchor.center()) or QApplication.primaryScreen()).availableGeometry()
195        if self.width() > screen.width() * 0.8:
196            self.setWordWrap(True)
197            self.setFixedWidth(int(screen.width() * 0.8))
198            self.adjustSize()
199        place(self, anchor, below=False)  # above the line, so the completion list fits below
200        self.show()
201
202    def hideEvent(self, event):
203        self.line = None
204        super().hideEvent(event)

Argument hints for the call being typed: the routine's arguments with the current one in bold, and that argument's declaration.

SignaturePopup(editor)
178    def __init__(self, editor):
179        super().__init__(editor, Qt.ToolTip | Qt.FramelessWindowHint)
180        self.editor = editor
181        self.setTextFormat(Qt.RichText)
182        self.setWordWrap(False)
183        self.setMargin(6)
184        self.line: int | None = None  # the block the hint is for

__init__(self, text: str, /, parent: PySide6.QtWidgets.QWidget | None = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags), *, textFormat: PySide6.QtCore.Qt.TextFormat | None = None, pixmap: PySide6.QtGui.QPixmap | None = None, scaledContents: bool | None = None, alignment: PySide6.QtCore.Qt.AlignmentFlag | None = None, wordWrap: bool | None = None, margin: int | None = None, indent: int | None = None, openExternalLinks: bool | None = None, textInteractionFlags: PySide6.QtCore.Qt.TextInteractionFlag | None = None, hasSelectedText: bool | None = None, selectedText: str | None = None) -> None __init__(self, /, parent: PySide6.QtWidgets.QWidget | None = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags), *, text: str | None = None, textFormat: PySide6.QtCore.Qt.TextFormat | None = None, pixmap: PySide6.QtGui.QPixmap | None = None, scaledContents: bool | None = None, alignment: PySide6.QtCore.Qt.AlignmentFlag | None = None, wordWrap: bool | None = None, margin: int | None = None, indent: int | None = None, openExternalLinks: bool | None = None, textInteractionFlags: PySide6.QtCore.Qt.TextInteractionFlag | None = None, hasSelectedText: bool | None = None, selectedText: str | None = None) -> None

Initialize self. See help(type(self)) for accurate signature.

editor
line: int | None
def open(self, text_html: str, line: int, anchor: PySide6.QtCore.QRect):
186    def open(self, text_html: str, line: int, anchor: QRect):
187        bg, text, border = popup_colors(self.editor)
188        self.setStyleSheet(f"SignaturePopup {{ background: {bg.name()}; color: {text.name()}; "
189                           f"border: 1px solid {border.name(QColor.HexArgb)}; }}")
190        self.setFont(self.editor.font())
191        self.setText(text_html)
192        self.line = line
193        self.adjustSize()
194        screen = (QApplication.screenAt(anchor.center()) or QApplication.primaryScreen()).availableGeometry()
195        if self.width() > screen.width() * 0.8:
196            self.setWordWrap(True)
197            self.setFixedWidth(int(screen.width() * 0.8))
198            self.adjustSize()
199        place(self, anchor, below=False)  # above the line, so the completion list fits below
200        self.show()
def hideEvent(self, event):
202    def hideEvent(self, event):
203        self.line = None
204        super().hideEvent(event)

hideEvent(self, event: PySide6.QtGui.QHideEvent, /) -> None

staticMetaObject = PySide6.QtCore.QMetaObject("SignaturePopup" inherits "QLabel": )
def global_rect(editor, cursor) -> PySide6.QtCore.QRect:
207def global_rect(editor, cursor) -> QRect:
208    """The cursor's rectangle in screen coordinates."""
209    rect = editor.cursorRect(cursor)
210    return QRect(editor.viewport().mapToGlobal(rect.topLeft()), rect.size())

The cursor's rectangle in screen coordinates.