"""Wählfeld-Widget - Nummerneingabe + DTMF-Tastatur mit Kontaktsuche.""" from PySide6.QtWidgets import ( QWidget, QVBoxLayout, QGridLayout, QLineEdit, QPushButton, QSizePolicy, QListWidget, QListWidgetItem, ) from PySide6.QtCore import Signal, Qt from PySide6.QtGui import QFont, QColor class Waehlfeld(QWidget): """Wähltastatur mit Nummernfeld, Kontaktsuche und 12 Tasten.""" # Signale nummer_gewaehlt = Signal(str) # Komplette Nummer zum Anrufen dtmf_gedrueckt = Signal(str) # Einzelne DTMF-Ziffer # Tasten-Layout (4 Zeilen x 3 Spalten) TASTEN = [ ("1", ""), ("2", "ABC"), ("3", "DEF"), ("4", "GHI"), ("5", "JKL"), ("6", "MNO"), ("7", "PQRS"), ("8", "TUV"), ("9", "WXYZ"), ("*", ""), ("0", "+"), ("#", ""), ] def __init__(self, parent=None): super().__init__(parent) self._im_gespraech = False self._kontakte_liste = [] # Wird von HauptFenster gesetzt self._ui_aufbauen() def _ui_aufbauen(self): layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(8) # Nummern-/Suchfeld self.nummer_eingabe = QLineEdit() self.nummer_eingabe.setPlaceholderText("Nummer oder Name...") self.nummer_eingabe.setAlignment(Qt.AlignmentFlag.AlignCenter) eingabe_font = QFont() eingabe_font.setPointSize(18) self.nummer_eingabe.setFont(eingabe_font) self.nummer_eingabe.setMinimumHeight(48) self.nummer_eingabe.setStyleSheet( "QLineEdit { " " border: 2px solid #555; border-radius: 8px; " " padding: 8px 12px; font-size: 18px; " " background: rgba(255,255,255,0.05); " "}" "QLineEdit:focus { border-color: #4CAF50; }" ) self.nummer_eingabe.returnPressed.connect(self._nummer_senden) self.nummer_eingabe.textChanged.connect(self._suche_aktualisieren) layout.addWidget(self.nummer_eingabe) # Vorschlagsliste (normalerweise versteckt) self.vorschlaege = QListWidget() self.vorschlaege.setMaximumHeight(180) self.vorschlaege.setAlternatingRowColors(True) self.vorschlaege.setStyleSheet( "QListWidget { border: 1px solid #555; border-radius: 4px; }" "QListWidget::item { padding: 4px 8px; }" "QListWidget::item:hover { background: rgba(76,175,80,0.2); }" ) self.vorschlaege.itemClicked.connect(self._vorschlag_gewaehlt) self.vorschlaege.itemDoubleClicked.connect( self._vorschlag_anrufen) self.vorschlaege.hide() layout.addWidget(self.vorschlaege) # Tastatur-Grid grid = QGridLayout() grid.setSpacing(6) # DTMF-Button Styling btn_style = ( "QPushButton { " " border: 1px solid #555; border-radius: 8px; " " background: rgba(255,255,255,0.06); " " color: #ddd; font-size: 18px; font-weight: bold; " " padding: 4px; " "}" "QPushButton:hover { " " background: rgba(76,175,80,0.15); " " border-color: #4CAF50; " "}" "QPushButton:pressed { " " background: rgba(76,175,80,0.3); " "}" ) for index, (ziffer, buchstaben) in enumerate(self.TASTEN): zeile = index // 3 spalte = index % 3 if buchstaben: text = f"{ziffer}\n{buchstaben}" else: text = ziffer btn = QPushButton(text) btn.setStyleSheet(btn_style) btn.setMinimumSize(60, 50) btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) btn.setCursor(Qt.CursorShape.PointingHandCursor) btn.clicked.connect( lambda checked, z=ziffer: self._taste_gedrueckt(z)) grid.addWidget(btn, zeile, spalte) layout.addLayout(grid) def kontakte_setzen(self, kontakte): """Kontaktliste für die Suche setzen (von HauptFenster aufgerufen).""" self._kontakte_liste = kontakte or [] def _taste_gedrueckt(self, ziffer): """Taste wurde gedrückt - Ziffer anhängen oder DTMF senden.""" if self._im_gespraech: self.dtmf_gedrueckt.emit(ziffer) else: self.nummer_eingabe.setText(self.nummer_eingabe.text() + ziffer) self.nummer_eingabe.setFocus() def _nummer_senden(self): """Eingegebene Nummer zum Anrufen senden.""" nummer = self.nummer_eingabe.text().strip() if nummer: self.nummer_gewaehlt.emit(nummer) def _suche_aktualisieren(self, text): """Eingabe geändert → Vorschläge aktualisieren.""" if self._im_gespraech or not text or len(text) < 2: self.vorschlaege.hide() return text_lower = text.lower().strip() # Prüfen ob es eine reine Nummer ist (dann keine Suche) if all(c in "0123456789+*# " for c in text): self.vorschlaege.hide() return self.vorschlaege.clear() treffer = 0 for kontakt in self._kontakte_liste: name = kontakt.get("name", "") nummern = kontakt.get("nummern", {}) firma = kontakt.get("firma", "") # Nach Name oder Firma suchen if (text_lower not in name.lower() and text_lower not in firma.lower()): continue # Alle Nummern des Kontakts als Vorschläge typ_anzeige = { "telefon": "Tel", "handy": "Handy", "geschaeftlich": "Gesch.", "sonstige": "Sonst.", } for typ, nummer in nummern.items(): anzeige_typ = typ_anzeige.get(typ, typ) text_anzeige = f"{name} ({anzeige_typ}: {nummer})" item = QListWidgetItem(text_anzeige) item.setData(Qt.ItemDataRole.UserRole, nummer) item.setData(Qt.ItemDataRole.UserRole + 1, name) # CardDAV-Kontakte blau if kontakt.get("quelle") == "carddav": item.setForeground(QColor("#5599DD")) self.vorschlaege.addItem(item) treffer += 1 if treffer >= 15: break if treffer >= 15: break if treffer > 0: self.vorschlaege.show() else: self.vorschlaege.hide() def _vorschlag_gewaehlt(self, item): """Einfacher Klick auf Vorschlag → Nummer ins Feld.""" nummer = item.data(Qt.ItemDataRole.UserRole) if nummer: self.nummer_eingabe.setText(nummer) self.vorschlaege.hide() def _vorschlag_anrufen(self, item): """Doppelklick auf Vorschlag → direkt anrufen.""" nummer = item.data(Qt.ItemDataRole.UserRole) if nummer: self.nummer_eingabe.setText(nummer) self.vorschlaege.hide() self.nummer_gewaehlt.emit(nummer) def set_im_gespraech(self, aktiv): """Modus wechseln: Nummern-Eingabe ↔ DTMF-Versand.""" self._im_gespraech = aktiv if aktiv: self.nummer_eingabe.setPlaceholderText("DTMF-Modus aktiv") self.vorschlaege.hide() else: self.nummer_eingabe.setPlaceholderText( "Name oder Nummer eingeben...") def nummer_loeschen(self): """Nummernfeld leeren.""" self.nummer_eingabe.clear() self.vorschlaege.hide() def nummer_setzen(self, nummer): """Nummer ins Eingabefeld setzen.""" self.nummer_eingabe.setText(nummer) self.nummer_eingabe.setFocus() def keyPressEvent(self, event): """Tastatureingaben abfangen (Numpad-Support).""" taste = event.text() if taste in "0123456789*#": self._taste_gedrueckt(taste) elif event.key() == Qt.Key.Key_Backspace: text = self.nummer_eingabe.text() self.nummer_eingabe.setText(text[:-1]) elif event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter): self._nummer_senden() elif event.key() == Qt.Key.Key_Escape: self.vorschlaege.hide() else: super().keyPressEvent(event)