#!/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("", self._on_combo_click, add="+") self.bind_all("", self._on_zoom, add="+") self.bind("", 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()