This commit is contained in:
2025-11-23 20:41:50 +08:00
commit f7d5b7be07
65 changed files with 14986 additions and 0 deletions

384
main.py Normal file
View File

@@ -0,0 +1,384 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
NexusLauncher - 主程序(简化版)
一个现代化的应用启动器
"""
import customtkinter as ctk
from config import ConfigManager
from config.constants import (
BG_COLOR_DARK,
BG_COLOR_BUTTON,
BG_COLOR_BUTTON_HOVER,
BORDER_COLOR,
SEGMENTED_BUTTON_SELECTED_COLOR,
SEGMENTED_BUTTON_SELECTED_HOVER_COLOR,
SEGMENTED_BUTTON_UNSELECTED_COLOR,
SEGMENTED_BUTTON_UNSELECTED_HOVER_COLOR,
DROPDOWN_FG_COLOR,
DROPDOWN_HOVER_COLOR,
TEXT_COLOR_PRIMARY,
COLOR_TRANSPARENT
)
from ui import SettingsWindow, get_icons_dir, IconManager
from ui.task import TaskPanel
from ui.project import ProjectPanel
from ui.utilities import WindowManager, UIHelpers
class NexusLauncher(ctk.CTk):
"""主应用程序类(简化版)"""
def __init__(self):
super().__init__()
# 调试模式控制
self.debug_mode = False
# 创建启动画面
self.splash = None
try:
from ui import SplashScreen
self.splash = SplashScreen(self)
except Exception as e:
self._log(f"Failed to create splash screen: {e}", "WARNING")
# 初始化管理器
self.config_manager = ConfigManager()
self.window_manager = WindowManager(self, self.config_manager)
# 设置Windows AppUserModelID
self.window_manager.setup_window_appid()
# 图标管理
self.icons_dir = get_icons_dir()
self.icon_size = self.config_manager.get_icon_size()
self.icon_manager = IconManager(self.icons_dir, self.icon_size)
# 窗口配置
self._setup_window()
# 创建界面
self._create_widgets()
# 绑定事件
self._bind_events()
# 初始化UI
self._initialize_ui()
# 设置托盘和窗口关闭事件
self.protocol("WM_DELETE_WINDOW", self.window_manager.hide_window)
self.window_manager.setup_tray_icon()
def _log(self, message: str, level: str = "INFO"):
"""统一的日志方法
Args:
message: 日志消息
level: 日志级别 (DEBUG, INFO, WARNING, ERROR)
"""
# DEBUG级别的日志只在调试模式下输出
if level == "DEBUG" and not self.debug_mode:
return
prefix = f"[{level}]"
full_message = f"{prefix} {message}"
print(full_message)
def _setup_window(self):
"""设置窗口属性"""
self.title("NexusLauncher")
width, height = self.config_manager.get_window_size()
self.minsize(200, 200)
# 定位窗口到右下角
self.window_manager.position_window_bottom_right(width, height)
# 设置图标和主题
self.window_manager.set_window_icon()
ctk.set_appearance_mode("dark")
self.configure(fg_color=BG_COLOR_DARK)
def _create_widgets(self):
"""创建界面组件"""
# 配置网格布局
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=1)
# 创建各个部分
self._create_header()
self._create_project_area()
def _create_header(self):
"""创建顶部菜单栏"""
self.menu_frame = ctk.CTkFrame(self, height=40, corner_radius=0)
self.menu_frame.grid(row=0, column=0, sticky="ew", padx=0, pady=0)
self.menu_frame.grid_columnconfigure(0, weight=1)
# 标题
ctk.CTkLabel(
self.menu_frame,
text="NexusLauncher",
font=ctk.CTkFont(size=16, weight="bold")
).grid(row=0, column=0, padx=20, pady=8, sticky="w")
# 设置按钮
ctk.CTkButton(
self.menu_frame,
text="⚙ 设置",
command=self._open_settings,
width=90,
height=30,
font=ctk.CTkFont(size=12)
).grid(row=0, column=1, padx=20, pady=8, sticky="e")
def _create_project_area(self):
"""创建项目区域"""
self.project_frame = ctk.CTkFrame(self, corner_radius=0, fg_color=COLOR_TRANSPARENT)
self.project_frame.grid(row=1, column=0, sticky="nsew", padx=0, pady=0)
self.project_frame.grid_columnconfigure(0, weight=1)
self.project_frame.grid_rowconfigure(1, weight=1)
self._create_project_selector()
self._create_tabview()
def _create_project_selector(self):
"""创建项目选择下拉框"""
project_select_frame = ctk.CTkFrame(self.project_frame, fg_color=COLOR_TRANSPARENT)
project_select_frame.grid(row=0, column=0, sticky="ew", padx=20, pady=(3, 3))
project_select_frame.grid_columnconfigure(1, weight=1)
ctk.CTkLabel(
project_select_frame,
text="当前项目:",
font=ctk.CTkFont(size=13, weight="bold")
).grid(row=0, column=0, padx=(0, 10), sticky="w")
self.project_combo = ctk.CTkComboBox(
project_select_frame,
command=self._on_project_changed,
height=32,
font=ctk.CTkFont(size=12),
dropdown_font=ctk.CTkFont(size=12),
button_color=BG_COLOR_BUTTON,
button_hover_color=BG_COLOR_BUTTON_HOVER,
border_color=BORDER_COLOR,
border_width=1,
state="readonly",
corner_radius=8,
dropdown_fg_color=DROPDOWN_FG_COLOR,
dropdown_hover_color=DROPDOWN_HOVER_COLOR,
dropdown_text_color=TEXT_COLOR_PRIMARY,
justify="left"
)
self.project_combo.grid(row=0, column=1, sticky="ew")
def _create_tabview(self):
"""创建标签页"""
self.tabview = ctk.CTkTabview(
self.project_frame,
height=40,
corner_radius=10,
segmented_button_fg_color=SEGMENTED_BUTTON_UNSELECTED_COLOR,
segmented_button_selected_color=SEGMENTED_BUTTON_SELECTED_COLOR,
segmented_button_selected_hover_color=SEGMENTED_BUTTON_SELECTED_HOVER_COLOR,
segmented_button_unselected_color=SEGMENTED_BUTTON_UNSELECTED_COLOR,
segmented_button_unselected_hover_color=SEGMENTED_BUTTON_UNSELECTED_HOVER_COLOR,
anchor="w"
)
self.tabview.grid(row=1, column=0, sticky="nsew", padx=5, pady=(0, 5))
self._create_project_tab()
self._create_task_tab()
self.tabview.configure(command=self._on_tab_changed)
self.tabview.set("Project")
def _create_project_tab(self):
"""创建Project标签页"""
self.project_tab = self.tabview.add("Project")
self.project_tab.grid_columnconfigure(0, weight=1)
self.project_tab.grid_rowconfigure(0, weight=1)
# 使用ProjectPanel
self.project_panel = ProjectPanel(
self.project_tab,
self.config_manager,
self.icon_manager,
log_callback=self.window_manager.log_with_timestamp,
fg_color=COLOR_TRANSPARENT
)
self.project_panel.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
# 设置图标大小
self.project_panel.set_icon_size(self.icon_size)
# 初始化项目背景颜色
self._update_project_background()
def _create_task_tab(self):
"""创建Task标签页"""
self.task_tab = self.tabview.add("Task")
self.task_tab.grid_columnconfigure(0, weight=1)
self.task_tab.grid_rowconfigure(0, weight=1)
# 使用TaskPanel
self.task_panel = TaskPanel(self.task_tab, self.config_manager, fg_color=COLOR_TRANSPARENT)
self.task_panel.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
# 初始化项目颜色
self._update_task_colors()
def _bind_events(self):
"""绑定事件"""
self.project_combo.bind("<Button-1>", self._on_combo_click, add="+")
self.bind_all("<Control-MouseWheel>", self._on_zoom, add="+")
self.bind("<Configure>", self._on_window_resize)
def _initialize_ui(self):
"""初始化UI"""
self.after(100, lambda: UIHelpers.adjust_tab_button_width(self.tabview))
self.after(150, self._configure_tab_style)
self.after(200, lambda: UIHelpers.fix_dropdown_width(self.project_combo))
self.after(250, self._update_tab_appearance) # 延迟更新标签页外观确保UI完全初始化
self._update_project_list()
# 初始化Project标签页内容
self.after(300, self.project_panel.refresh)
# 关闭启动画面
if self.splash:
self.after(350, self._close_splash)
def _close_splash(self):
"""关闭启动画面"""
if self.splash:
try:
self.splash.close()
self.splash = None
except:
pass
def _configure_tab_style(self):
"""配置标签页样式"""
UIHelpers.configure_tab_transparency(self.project_tab, self.task_tab)
def _on_combo_click(self, event):
"""下拉框点击事件"""
self.after(1, lambda: UIHelpers.fix_dropdown_width(self.project_combo))
def _on_tab_changed(self):
"""标签页切换事件"""
current_tab = self.tabview.get()
self._log(f"Switched to tab: {current_tab}", "DEBUG")
if current_tab == "Task":
self.task_panel.refresh()
elif current_tab == "Project":
self.project_panel.refresh()
def _on_zoom(self, event):
"""处理缩放事件"""
# 检查事件是否来自主窗口
widget = event.widget
if hasattr(widget, 'winfo_toplevel'):
if widget.winfo_toplevel() != self:
return
# 委托给project_panel处理
return self.project_panel.handle_zoom(event)
def _on_window_resize(self, event):
"""窗口大小改变事件"""
if event.widget == self:
if hasattr(self, '_resize_timer'):
self.after_cancel(self._resize_timer)
self._resize_timer = self.after(150, self._on_resize_complete)
def _on_resize_complete(self):
"""窗口调整完成后的处理"""
try:
self.project_panel.on_window_resize()
UIHelpers.adjust_tab_button_width(self.tabview)
except Exception as e:
self._log(f"Window adjustment handling failed: {e}", "WARNING")
def _update_project_list(self):
"""更新项目列表"""
projects = self.config_manager.get_projects()
if projects:
self.project_combo.configure(values=projects)
current_project = self.config_manager.get_current_project()
if current_project in projects:
self.project_combo.set(current_project)
else:
self.project_combo.set(projects[0])
self.config_manager.set_current_project(projects[0])
else:
self.project_combo.configure(values=["无项目"])
self.project_combo.set("无项目")
def _on_project_changed(self, choice):
"""项目切换事件"""
self.config_manager.set_current_project(choice)
self._update_tab_appearance()
self.project_panel.refresh()
self.task_panel.refresh()
def _update_tab_appearance(self):
"""更新标签页外观"""
current_project = self.config_manager.get_current_project()
if not current_project:
return
# 更新背景颜色
self._update_project_background()
self._update_task_colors()
# 更新标签页图标(包含高度设置)
self.project_panel.update_tab_icon(self.tabview, current_project)
def _update_project_background(self):
"""更新project panel背景颜色"""
current_project = self.config_manager.get_current_project()
if current_project:
project_color = self.config_manager.get_project_color(current_project)
if project_color:
self.project_panel.configure(fg_color=project_color)
if hasattr(self.project_panel, 'update_background_color'):
self.project_panel.update_background_color(project_color)
def _update_task_colors(self):
"""更新task panel颜色"""
current_project = self.config_manager.get_current_project()
if current_project:
project_color = self.config_manager.get_project_color(current_project)
if project_color and hasattr(self.task_panel, 'update_colors'):
self.task_panel.update_colors(project_color)
def _open_settings(self):
"""打开设置窗口"""
self.window_manager.log_with_timestamp("🔧 打开设置窗口")
settings_window = SettingsWindow(self, self.config_manager, self._on_settings_updated)
def _on_settings_updated(self):
"""设置更新后的回调"""
self.window_manager.log_with_timestamp("🔄 设置已更新,重新加载应用")
self._update_project_list()
self._update_tab_appearance()
self.project_panel.refresh()
def log(self, message: str):
"""日志记录委托给window_manager"""
self.window_manager.log(message)
def main():
"""主函数"""
app = NexusLauncher()
app.mainloop()
if __name__ == "__main__":
main()