更新0.02版本
This commit is contained in:
+114
-24
@@ -38,10 +38,11 @@ from db import database
|
||||
from ui.group import GroupWidget
|
||||
import ui.theme as theme
|
||||
import ui.dialog_style as dialog_style
|
||||
from ui.updater import Updater
|
||||
|
||||
PANEL_W = 260
|
||||
PANEL_H = 40
|
||||
MIN_W, MIN_H = 180, 40
|
||||
MIN_W, MIN_H = 400, 5
|
||||
ANIM_MS = 180
|
||||
RESIZE_M = 8
|
||||
|
||||
@@ -354,6 +355,8 @@ class PanelWindow(QWidget):
|
||||
self._time_timer.setInterval(1000)
|
||||
self._time_timer.timeout.connect(self._refresh_time_label)
|
||||
|
||||
self._updater = Updater(self)
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
if not self._screen_hooked:
|
||||
@@ -499,18 +502,63 @@ class PanelWindow(QWidget):
|
||||
self._time_timer.start()
|
||||
|
||||
# ── UI ──────────────────────────────────────────────
|
||||
def _get_quick_actions(self):
|
||||
"""返回快捷动作列表,悬浮球右键菜单和左侧快捷栏共用同一份。
|
||||
每项: (tooltip, qtawesome_icon, callback)
|
||||
排除重启/退出。"""
|
||||
return [
|
||||
("管理员运行 CMD", "fa5s.terminal", self._open_admin_cmd),
|
||||
("管理员运行 PowerShell", "fa5b.windows", self._open_admin_powershell),
|
||||
("打开默认浏览器", "fa5s.globe", self._open_default_browser),
|
||||
]
|
||||
|
||||
def _build_ui(self):
|
||||
root = QVBoxLayout(self)
|
||||
root.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.container = QWidget()
|
||||
self.container.setObjectName("container")
|
||||
# container 也开启鼠标追踪,子 widget 的 MouseMove 会冒泡上来
|
||||
self.container.setMouseTracking(True)
|
||||
|
||||
inner = QVBoxLayout(self.container)
|
||||
# 横向:左侧快捷栏 + 右侧主内容
|
||||
h_layout = QHBoxLayout(self.container)
|
||||
h_layout.setContentsMargins(0, 0, 0, 0)
|
||||
h_layout.setSpacing(0)
|
||||
|
||||
# ── 左侧快捷栏
|
||||
self._quick_bar = QWidget()
|
||||
self._quick_bar.setObjectName("quick_bar")
|
||||
self._quick_bar.setFixedWidth(50)
|
||||
quick_layout = QVBoxLayout(self._quick_bar)
|
||||
quick_layout.setContentsMargins(0, 10, 0, 10)
|
||||
quick_layout.setSpacing(6)
|
||||
quick_layout.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
self._quick_btns = []
|
||||
for tooltip, icon_name, callback in self._get_quick_actions():
|
||||
btn = QPushButton()
|
||||
btn.setFixedSize(34, 34)
|
||||
btn.setToolTip(tooltip)
|
||||
btn.setStyleSheet("border:none; background:transparent; border-radius:4px;")
|
||||
try:
|
||||
btn.setIcon(qta.icon(icon_name, color="#888"))
|
||||
btn.setIconSize(QSize(16, 16))
|
||||
except Exception:
|
||||
btn.setText(tooltip[0])
|
||||
btn.clicked.connect(callback)
|
||||
quick_layout.addWidget(btn, alignment=Qt.AlignmentFlag.AlignHCenter)
|
||||
self._quick_btns.append((btn, icon_name))
|
||||
|
||||
quick_layout.addStretch()
|
||||
h_layout.addWidget(self._quick_bar)
|
||||
|
||||
# ── 右侧主内容
|
||||
right_widget = QWidget()
|
||||
right_widget.setMouseTracking(True)
|
||||
inner = QVBoxLayout(right_widget)
|
||||
inner.setContentsMargins(8, 10, 8, 8)
|
||||
inner.setSpacing(6)
|
||||
h_layout.addWidget(right_widget)
|
||||
|
||||
# ── 标题栏(仅此处可拖动窗口,避免分组内框选时带动面板)
|
||||
self._title_bar = QWidget()
|
||||
@@ -683,6 +731,12 @@ class PanelWindow(QWidget):
|
||||
|
||||
bottom_layout.addWidget(self.menu_btn)
|
||||
bottom_layout.addStretch()
|
||||
self.update_btn = QPushButton()
|
||||
self.update_btn.setFixedSize(28, 28)
|
||||
self.update_btn.setToolTip("检查更新")
|
||||
self.update_btn.setStyleSheet("border:none; background:transparent; border-radius:4px;")
|
||||
self.update_btn.clicked.connect(lambda: self._updater.check(silent_if_latest=False))
|
||||
bottom_layout.addWidget(self.update_btn)
|
||||
bottom_layout.addWidget(self.theme_btn)
|
||||
bottom_layout.addWidget(self.settings_btn)
|
||||
bottom_layout.addWidget(self.quit_btn)
|
||||
@@ -781,6 +835,26 @@ class PanelWindow(QWidget):
|
||||
if hasattr(self, "time_title_label"):
|
||||
self.time_title_label.setStyleSheet("font-size:11px; color: #888;")
|
||||
|
||||
# 左侧快捷栏
|
||||
bar_side_bg = "rgba(0,0,0,20)" if is_dark else "rgba(0,0,0,6)"
|
||||
self._quick_bar.setStyleSheet(
|
||||
f"""
|
||||
QWidget#quick_bar {{
|
||||
background: {bar_side_bg};
|
||||
border-right: 1px solid {t['panel_border']};
|
||||
border-radius: 10px 0 0 10px;
|
||||
}}
|
||||
QPushButton {{ border:none; background:transparent; border-radius:4px; }}
|
||||
QPushButton:hover {{ background:{t['header_hover']}; }}
|
||||
"""
|
||||
)
|
||||
for btn, icon_name in self._quick_btns:
|
||||
try:
|
||||
btn.setIcon(qta.icon(icon_name, color=ic))
|
||||
btn.setIconSize(QSize(14, 14))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 底部工具栏
|
||||
bar_bg2 = "rgba(0,0,0,30)" if is_dark else "rgba(0,0,0,8)"
|
||||
self.bottom_bar.setStyleSheet(
|
||||
@@ -798,6 +872,8 @@ class PanelWindow(QWidget):
|
||||
qta.icon("fa5s.sun" if is_dark else "fa5s.moon", color=ic)
|
||||
)
|
||||
self.theme_btn.setIconSize(QSize(14, 14))
|
||||
self.update_btn.setIcon(qta.icon("fa5s.sync-alt", color=ic))
|
||||
self.update_btn.setIconSize(QSize(14, 14))
|
||||
self.menu_btn.setIcon(qta.icon("fa5s.bars", color=ic))
|
||||
self.menu_btn.setIconSize(QSize(14, 14))
|
||||
self.settings_btn.setIcon(qta.icon("fa5s.cog", color=ic))
|
||||
@@ -820,6 +896,23 @@ class PanelWindow(QWidget):
|
||||
if ret == QMessageBox.StandardButton.Yes:
|
||||
QApplication.quit()
|
||||
|
||||
def _restart_application(self):
|
||||
import subprocess
|
||||
subprocess.Popen([sys.executable] + sys.argv)
|
||||
QApplication.quit()
|
||||
|
||||
def _open_admin_cmd(self):
|
||||
import ctypes
|
||||
ctypes.windll.shell32.ShellExecuteW(None, "runas", "cmd.exe", None, None, 1)
|
||||
|
||||
def _open_admin_powershell(self):
|
||||
import ctypes
|
||||
ctypes.windll.shell32.ShellExecuteW(None, "runas", "powershell.exe", None, None, 1)
|
||||
|
||||
def _open_default_browser(self):
|
||||
import webbrowser
|
||||
webbrowser.open("https://www.baidu.com")
|
||||
|
||||
def _toggle_theme(self):
|
||||
theme.set_theme("light" if theme.name() == "dark" else "dark")
|
||||
self._apply_theme()
|
||||
@@ -1050,13 +1143,9 @@ class PanelWindow(QWidget):
|
||||
"""收缩:隐藏内容区,窗口缩到只剩标题栏高度"""
|
||||
self._body.hide()
|
||||
self.weather_bar.hide()
|
||||
# 记录当前高度,展开时恢复
|
||||
self._quick_bar.hide()
|
||||
self._expanded_height = self.height()
|
||||
title_h = (
|
||||
self.container.layout().contentsMargins().top()
|
||||
+ self.container.layout().contentsMargins().bottom()
|
||||
+ self._title_bar.sizeHint().height()
|
||||
)
|
||||
title_h = self._title_bar.sizeHint().height() + 20
|
||||
self.setFixedHeight(title_h)
|
||||
ic = "#cccccc" if theme.name() == "dark" else "#555555"
|
||||
self._min_btn.setIcon(qta.icon("fa5s.chevron-down", color=ic))
|
||||
@@ -1066,6 +1155,7 @@ class PanelWindow(QWidget):
|
||||
"""展开:恢复内容区和窗口高度"""
|
||||
self.weather_bar.show()
|
||||
self._body.show()
|
||||
self._quick_bar.show()
|
||||
h = getattr(self, "_expanded_height", 520)
|
||||
self.setMinimumHeight(MIN_H)
|
||||
self.setMaximumHeight(16777215)
|
||||
@@ -1096,7 +1186,11 @@ class PanelWindow(QWidget):
|
||||
y = int(database.get_setting("panel_y", ""))
|
||||
w = int(database.get_setting("panel_w", str(PANEL_W)))
|
||||
h = int(database.get_setting("panel_h", str(PANEL_H)))
|
||||
screen = QApplication.primaryScreen().availableGeometry()
|
||||
# 用保存坐标所在屏幕来限制范围,支持多显示器
|
||||
screen_obj = QApplication.screenAt(QPoint(x, y))
|
||||
if screen_obj is None:
|
||||
screen_obj = QApplication.primaryScreen()
|
||||
screen = screen_obj.availableGeometry()
|
||||
x = max(screen.left(), min(x, screen.right() - w))
|
||||
y = max(screen.top(), min(y, screen.bottom() - h))
|
||||
self._persist_w = w
|
||||
@@ -1119,7 +1213,11 @@ class PanelWindow(QWidget):
|
||||
|
||||
# ── 显示/隐藏 ────────────────────────────────────────
|
||||
def show_near(self, ball_pos: QPoint, ball_size: int):
|
||||
screen = QApplication.primaryScreen().availableGeometry()
|
||||
# 根据球所在屏幕来定位 panel,避免跑到主屏幕
|
||||
screen_obj = QApplication.screenAt(ball_pos)
|
||||
if screen_obj is None:
|
||||
screen_obj = QApplication.primaryScreen()
|
||||
screen = screen_obj.availableGeometry()
|
||||
pw, ph = self.width(), self.height()
|
||||
bx, by = ball_pos.x(), ball_pos.y()
|
||||
|
||||
@@ -1165,6 +1263,7 @@ class PanelWindow(QWidget):
|
||||
def minimize_to_ball(self):
|
||||
self.hide_panel()
|
||||
if hasattr(self, "_ball_ref"):
|
||||
self._ball_ref.place_on_screen_of(self)
|
||||
self._ball_ref.show()
|
||||
self._ball_ref.setWindowOpacity(1.0)
|
||||
|
||||
@@ -1360,20 +1459,11 @@ class PanelWindow(QWidget):
|
||||
QMenu::separator { height:1px; background:#444; margin:4px 8px; }
|
||||
"""
|
||||
)
|
||||
menu.addAction("🖥 显示面板").triggered.connect(
|
||||
lambda: (
|
||||
self.show_near(self._ball_ref.pos(), self._ball_ref.width())
|
||||
if hasattr(self, "_ball_ref")
|
||||
else None
|
||||
)
|
||||
)
|
||||
menu.addAction("🔽 最小化到悬浮球").triggered.connect(self.minimize_to_ball)
|
||||
for tooltip, _icon, callback in self._get_quick_actions():
|
||||
menu.addAction(tooltip).triggered.connect(callback)
|
||||
menu.addSeparator()
|
||||
self._autostart_act = menu.addAction("🚀 开机自启: 开")
|
||||
self._autostart_act.triggered.connect(self._toggle_autostart)
|
||||
self._autostart_enabled = True
|
||||
menu.addSeparator()
|
||||
menu.addAction("❌ 退出").triggered.connect(QApplication.quit)
|
||||
menu.addAction("🔄 重启本程序").triggered.connect(self._restart_application)
|
||||
menu.addAction("❌ 退出本程序").triggered.connect(QApplication.quit)
|
||||
|
||||
self.tray.setContextMenu(menu)
|
||||
self.tray.activated.connect(self._on_tray_activated)
|
||||
|
||||
Reference in New Issue
Block a user