fix(config): render preset menus with opaque backgrounds

- Apply solid popup styling to API endpoint preset menus
- Enforce opaque painting across supported Qt platforms
- Add regression coverage for preset menu transparency
This commit is contained in:
DazedAnon 2026-07-25 08:38:04 -05:00
parent 33038978cc
commit fca1f8c1c6
2 changed files with 84 additions and 2 deletions

View file

@ -200,6 +200,61 @@ class ConfigComboBox(QComboBox):
]))
class ConfigMenu(QMenu):
"""Popup menu with the same fully opaque surface as config dropdowns."""
_BACKGROUND = QColor("#353539")
def __init__(self, parent=None):
super().__init__(parent)
self.setStyleSheet("""
QMenu {
background-color: #353539;
color: #f2f2f2;
border: 1px solid #56565b;
padding: 2px;
}
QMenu::item {
background-color: #353539;
color: #f2f2f2;
min-height: 26px;
padding: 3px 9px;
}
QMenu::item:selected {
background-color: #007acc;
color: #ffffff;
}
""")
self._apply_opaque_background()
def _apply_opaque_background(self):
self.setWindowOpacity(1.0)
self.setAttribute(Qt.WA_TranslucentBackground, False)
self.setAttribute(Qt.WA_StyledBackground, True)
self.setAttribute(Qt.WA_OpaquePaintEvent, True)
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, self._BACKGROUND)
palette.setColor(QPalette.Base, self._BACKGROUND)
palette.setColor(QPalette.Button, self._BACKGROUND)
palette.setColor(QPalette.Text, QColor("#f2f2f2"))
palette.setColor(QPalette.ButtonText, QColor("#f2f2f2"))
palette.setColor(QPalette.Highlight, QColor("#007acc"))
palette.setColor(QPalette.HighlightedText, QColor("#ffffff"))
self.setPalette(palette)
def showEvent(self, event):
self._apply_opaque_background()
super().showEvent(event)
self._apply_opaque_background()
def paintEvent(self, event):
painter = QPainter(self)
painter.fillRect(self.rect(), self._BACKGROUND)
painter.end()
super().paintEvent(event)
class ApiKeyEditDialog(QDialog):
"""Dialog to create or overwrite a named API key (secret entered once)."""
@ -256,7 +311,7 @@ class ApiKeyEditDialog(QDialog):
endpoint_preset_btn = QToolButton()
endpoint_preset_btn.setText("Presets ▾")
endpoint_preset_btn.setPopupMode(QToolButton.InstantPopup)
endpoint_menu = QMenu(endpoint_preset_btn)
endpoint_menu = ConfigMenu(endpoint_preset_btn)
for label, url in (
("OpenAI", "https://api.openai.com/v1"),
("Claude (Anthropic)", "https://api.anthropic.com/v1"),
@ -663,7 +718,7 @@ class ConfigTab(QWidget):
self.api_url_preset_btn.setPopupMode(QToolButton.InstantPopup)
self.api_url_preset_btn.setStyleSheet(btn_style)
api_url_menu = QMenu(self.api_url_preset_btn)
api_url_menu = ConfigMenu(self.api_url_preset_btn)
for name, url in (
("OpenAI", "https://api.openai.com/v1"),
("Claude (Anthropic)", "https://api.anthropic.com/v1"),

View file

@ -279,6 +279,33 @@ class ConfigTabRegressionTests(unittest.TestCase):
self.assertFalse(popup.testAttribute(Qt.WA_TranslucentBackground))
tab.model_combo.hidePopup()
def test_presets_menu_is_opaque(self) -> None:
tab = self.make_tab()
window = QMainWindow()
self._windows.append(window)
window.setCentralWidget(tab)
window.resize(1280, 760)
window.show()
for _ in range(3):
self._app.processEvents()
menu = tab.api_url_preset_btn.menu()
menu.popup(
tab.api_url_preset_btn.mapToGlobal(
tab.api_url_preset_btn.rect().bottomLeft()
)
)
for _ in range(3):
self._app.processEvents()
self.assertTrue(menu.autoFillBackground())
self.assertEqual(menu.palette().color(QPalette.Window).name(), "#353539")
self.assertEqual(menu.palette().color(QPalette.Base).name(), "#353539")
self.assertEqual(menu.windowOpacity(), 1.0)
self.assertFalse(menu.testAttribute(Qt.WA_TranslucentBackground))
self.assertTrue(menu.testAttribute(Qt.WA_OpaquePaintEvent))
menu.hide()
def test_save_and_reload_round_trip_for_every_option(self) -> None:
tab = self.make_tab()
tab.disconnect_auto_save()