262 lines
7.2 KiB
Python
262 lines
7.2 KiB
Python
"""标准对话框(QMessageBox / QInputDialog / QFileDialog)与当前主题一致。"""
|
||
from __future__ import annotations
|
||
|
||
from PyQt6.QtCore import Qt
|
||
from PyQt6.QtGui import QTextOption
|
||
from PyQt6.QtWidgets import (
|
||
QFileDialog,
|
||
QInputDialog,
|
||
QMessageBox,
|
||
QWidget,
|
||
QDialog,
|
||
QLabel,
|
||
QSizePolicy,
|
||
)
|
||
|
||
import ui.theme as theme
|
||
|
||
|
||
def stylesheet() -> str:
|
||
t = theme.current()
|
||
bg = t["menu_bg"]
|
||
fg = t["menu_color"]
|
||
border = t["menu_border"]
|
||
hover = t["menu_selected"]
|
||
inp = t["search_bg"]
|
||
inp_b = t["search_border"]
|
||
focus = t["search_focus"]
|
||
return f"""
|
||
QMessageBox {{
|
||
background-color: {bg};
|
||
color: {fg};
|
||
}}
|
||
QMessageBox QLabel {{
|
||
color: {fg};
|
||
background: transparent;
|
||
min-width: 0px;
|
||
}}
|
||
QMessageBox QLabel#qt_msgbox_label {{
|
||
min-width: 200px;
|
||
max-width: 560px;
|
||
}}
|
||
QMessageBox QLabel#qt_msgboxex_icon_label {{
|
||
min-width: 28px;
|
||
max-width: 28px;
|
||
}}
|
||
QMessageBox QPushButton {{
|
||
min-width: 64px;
|
||
padding: 6px 14px;
|
||
border: 1px solid {border};
|
||
border-radius: 5px;
|
||
background: {inp};
|
||
color: {fg};
|
||
}}
|
||
QMessageBox QPushButton:hover {{
|
||
background: {hover};
|
||
}}
|
||
QMessageBox QPushButton:default {{
|
||
border-color: {focus};
|
||
}}
|
||
QInputDialog {{
|
||
background-color: {bg};
|
||
color: {fg};
|
||
}}
|
||
QInputDialog QLabel {{
|
||
color: {fg};
|
||
background: transparent;
|
||
}}
|
||
QInputDialog QLineEdit {{
|
||
background: {inp};
|
||
border: 1px solid {inp_b};
|
||
border-radius: 5px;
|
||
padding: 6px 8px;
|
||
color: {fg};
|
||
min-width: 260px;
|
||
}}
|
||
QInputDialog QLineEdit:focus {{
|
||
border-color: {focus};
|
||
}}
|
||
QInputDialog QPushButton {{
|
||
min-width: 72px;
|
||
padding: 6px 14px;
|
||
border: 1px solid {border};
|
||
border-radius: 5px;
|
||
background: {inp};
|
||
color: {fg};
|
||
}}
|
||
QInputDialog QPushButton:hover {{
|
||
background: {hover};
|
||
}}
|
||
QFileDialog {{
|
||
background-color: {bg};
|
||
color: {fg};
|
||
}}
|
||
QFileDialog QLabel {{
|
||
color: {fg};
|
||
background: transparent;
|
||
}}
|
||
QFileDialog QLineEdit, QFileDialog QComboBox {{
|
||
background: {inp};
|
||
border: 1px solid {inp_b};
|
||
border-radius: 4px;
|
||
padding: 4px 6px;
|
||
color: {fg};
|
||
}}
|
||
QFileDialog QLineEdit:focus, QFileDialog QComboBox:focus {{
|
||
border-color: {focus};
|
||
}}
|
||
QFileDialog QTreeView, QFileDialog QListView, QFileDialog QTableView {{
|
||
background: {inp};
|
||
border: 1px solid {inp_b};
|
||
border-radius: 4px;
|
||
color: {fg};
|
||
outline: none;
|
||
}}
|
||
QFileDialog QTreeView::item:selected, QFileDialog QListView::item:selected {{
|
||
background: {hover};
|
||
}}
|
||
QFileDialog QPushButton {{
|
||
min-width: 72px;
|
||
padding: 6px 12px;
|
||
border: 1px solid {border};
|
||
border-radius: 5px;
|
||
background: {inp};
|
||
color: {fg};
|
||
}}
|
||
QFileDialog QPushButton:hover {{
|
||
background: {hover};
|
||
}}
|
||
QFileDialog QComboBox QAbstractItemView {{
|
||
background: {bg};
|
||
color: {fg};
|
||
border: 1px solid {border};
|
||
}}
|
||
"""
|
||
|
||
|
||
def _apply(w: QWidget | None) -> None:
|
||
if w is not None:
|
||
w.setStyleSheet(stylesheet())
|
||
|
||
|
||
def _prepare_qmessagebox(msg: QMessageBox) -> None:
|
||
"""让提示框按内容换行并自适应宽高(避免固定宽度截断文字)。"""
|
||
lbl = msg.findChild(QLabel, "qt_msgbox_label")
|
||
if lbl is not None:
|
||
lbl.setWordWrap(True)
|
||
lbl.setTextFormat(Qt.TextFormat.PlainText)
|
||
# 无空格长中文也能在边界处断行,而不是整段挤在一行被裁切
|
||
try:
|
||
lbl.setWordWrapMode(QTextOption.WrapMode.WrapAnywhere)
|
||
except AttributeError:
|
||
pass
|
||
lbl.setMinimumWidth(200)
|
||
lbl.setMaximumWidth(560)
|
||
lbl.setSizePolicy(
|
||
QSizePolicy.Policy.Preferred,
|
||
QSizePolicy.Policy.MinimumExpanding,
|
||
)
|
||
lay = msg.layout()
|
||
if lay is not None:
|
||
lay.activate()
|
||
msg.setSizePolicy(
|
||
QSizePolicy.Policy.Preferred,
|
||
QSizePolicy.Policy.Preferred,
|
||
)
|
||
msg.setMinimumSize(0, 0)
|
||
msg.adjustSize()
|
||
|
||
|
||
def question(
|
||
parent: QWidget | None,
|
||
title: str,
|
||
text: str,
|
||
*,
|
||
buttons: QMessageBox.StandardButton = (
|
||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||
),
|
||
default_button: QMessageBox.StandardButton | None = None,
|
||
icon: QMessageBox.Icon = QMessageBox.Icon.Question,
|
||
) -> QMessageBox.StandardButton:
|
||
msg = QMessageBox(parent)
|
||
msg.setWindowTitle(title)
|
||
msg.setText(text)
|
||
msg.setIcon(icon)
|
||
msg.setStandardButtons(buttons)
|
||
if default_button is not None:
|
||
msg.setDefaultButton(default_button)
|
||
_apply(msg)
|
||
_prepare_qmessagebox(msg)
|
||
return QMessageBox.StandardButton(msg.exec())
|
||
|
||
|
||
def warning(parent: QWidget | None, title: str, text: str) -> None:
|
||
msg = QMessageBox(parent)
|
||
msg.setWindowTitle(title)
|
||
msg.setText(text)
|
||
msg.setIcon(QMessageBox.Icon.Warning)
|
||
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||
_apply(msg)
|
||
_prepare_qmessagebox(msg)
|
||
msg.exec()
|
||
|
||
|
||
def information(parent: QWidget | None, title: str, text: str) -> None:
|
||
msg = QMessageBox(parent)
|
||
msg.setWindowTitle(title)
|
||
msg.setText(text)
|
||
msg.setIcon(QMessageBox.Icon.Information)
|
||
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||
_apply(msg)
|
||
_prepare_qmessagebox(msg)
|
||
msg.exec()
|
||
|
||
|
||
def get_text(
|
||
parent: QWidget | None,
|
||
title: str,
|
||
label: str,
|
||
text: str = "",
|
||
) -> tuple[str, bool]:
|
||
d = QInputDialog(parent)
|
||
d.setWindowTitle(title)
|
||
d.setLabelText(label)
|
||
d.setTextValue(text)
|
||
_apply(d)
|
||
ok = d.exec() == QDialog.DialogCode.Accepted
|
||
return d.textValue(), ok
|
||
|
||
|
||
def get_open_file_name(
|
||
parent: QWidget | None,
|
||
caption: str,
|
||
directory: str,
|
||
filter_str: str,
|
||
) -> tuple[str, str]:
|
||
fd = QFileDialog(parent, caption, directory, filter_str)
|
||
fd.setOption(QFileDialog.Option.DontUseNativeDialog, True)
|
||
fd.setFileMode(QFileDialog.FileMode.ExistingFile)
|
||
_apply(fd)
|
||
if fd.exec() == QDialog.DialogCode.Accepted:
|
||
files = fd.selectedFiles()
|
||
if files:
|
||
return files[0], fd.selectedNameFilter()
|
||
return "", ""
|
||
|
||
|
||
def get_existing_directory(
|
||
parent: QWidget | None,
|
||
caption: str,
|
||
directory: str = "",
|
||
) -> str:
|
||
fd = QFileDialog(parent, caption, directory)
|
||
fd.setOption(QFileDialog.Option.DontUseNativeDialog, True)
|
||
fd.setFileMode(QFileDialog.FileMode.Directory)
|
||
fd.setOption(QFileDialog.Option.ShowDirsOnly, True)
|
||
_apply(fd)
|
||
if fd.exec() == QDialog.DialogCode.Accepted:
|
||
files = fd.selectedFiles()
|
||
if files:
|
||
return files[0]
|
||
return ""
|