MetaCore-startup/MetaCore/ui/sidebar.py
2025-10-17 16:56:28 +08:00

294 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
侧边栏组件
"""
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from data.project_manager import ProjectManager
from ui.icon_manager import IconManager
class Sidebar(QWidget):
"""侧边栏组件"""
# 信号定义
filter_changed = pyqtSignal(str)
navigation_changed = pyqtSignal(str, str, str) # 新增信号:(section, item_name, filter_type)
create_project_requested = pyqtSignal()
import_project_requested = pyqtSignal()
def __init__(self, project_manager: ProjectManager):
super().__init__()
self.project_manager = project_manager
self.current_filter = "overview"
self.setObjectName("sidebar")
self.setAttribute(Qt.WA_StyledBackground, True)
# 导航项映射filter_type -> (section, item_name)
self.nav_mapping = {
"overview": ("我的项目", "项目概述"),
"management": ("我的项目", "项目管理"),
"resource_category": ("资源管理", "资源分类"),
"resource_management": ("资源管理", "资源管理"),
"project_settings": ("设置中心", "项目设置"),
"system_settings": ("设置中心", "系统设置"),
}
self.init_ui()
self.connect_signals()
# 设置固定宽度 - 匹配 Figma 设计规范
self.setFixedWidth(313)
def init_ui(self):
"""初始化UI"""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# Logo区域
self.create_logo_section(layout)
# 快速操作区域
self.create_quick_actions(layout)
# 导航菜单
self.create_navigation_menu(layout)
# 底部用户信息
# layout.addStretch()
# self.create_user_info(layout)
def create_logo_section(self, layout):
"""创建Logo区域"""
logo_widget = QWidget()
logo_widget.setObjectName("logoWidget")
logo_layout = QHBoxLayout(logo_widget)
logo_layout.setContentsMargins(37, 32, 46, 24)
logo_layout.setSpacing(28)
logo_layout.setAlignment(Qt.AlignCenter)
logo_icon = QLabel()
logo_icon.setObjectName("logoIcon")
logo_icon.setAlignment(Qt.AlignCenter)
logo_icon.setFixedSize(80, 80)
logo_icon.setScaledContents(True)
if IconManager.icon_exists('logo'):
logo_icon.setPixmap(IconManager.get_pixmap('logo', QSize(80, 80)))
else:
logo_icon.setText("")
logo_layout.addWidget(logo_icon, alignment=Qt.AlignCenter)
logo_text = QLabel("MetaCore")
logo_text.setObjectName("logoText")
logo_text.setAlignment(Qt.AlignCenter)
logo_layout.addWidget(logo_text, 0, Qt.AlignBottom)
layout.addWidget(logo_widget)
def create_quick_actions(self, layout):
"""创建快速操作区域"""
actions_widget = QWidget()
actions_widget.setObjectName("quickActions")
actions_layout = QVBoxLayout(actions_widget)
actions_layout.setContentsMargins(37, 24, 46, 24)
actions_layout.setSpacing(12)
self.create_btn = QPushButton("新建项目")
# if IconManager.icon_exists('create'):
# self.create_btn.setIcon(IconManager.get_icon('create'))
# self.create_btn.setIconSize(QSize(18, 18))
self.create_btn.setObjectName("createBtn")
self.create_btn.setCursor(Qt.PointingHandCursor)
self.create_btn.setMinimumHeight(36)
self.create_btn.setMaximumHeight(36)
self.create_btn.clicked.connect(self.create_project_requested.emit)
actions_layout.addWidget(self.create_btn)
self.import_btn = QPushButton("导入项目")
# if IconManager.icon_exists('import'):
# self.import_btn.setIcon(IconManager.get_icon('import'))
# self.import_btn.setIconSize(QSize(18, 18))
self.import_btn.setObjectName("sidebarImportBtn")
self.import_btn.setCursor(Qt.PointingHandCursor)
self.import_btn.setMinimumHeight(36)
self.import_btn.setMaximumHeight(36)
self.import_btn.clicked.connect(self.import_project_requested.emit)
actions_layout.addWidget(self.import_btn)
layout.addWidget(actions_widget)
def create_navigation_menu(self, layout):
"""创建导航菜单"""
# 滚动区域
scroll_area = QScrollArea()
scroll_area.setObjectName("navScrollArea") # 设置对象名称
scroll_area.setWidgetResizable(True) # 自适应内容大小
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 水平滚动条
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # 垂直滚动条
# 导航内容
nav_widget = QWidget()
nav_widget.setObjectName("navWidget")
nav_layout = QVBoxLayout(nav_widget)
nav_layout.setContentsMargins(0, 10, 0, 0) # 边距上10px
nav_layout.setSpacing(10) # 分组间距10px
# 我的项目分组
self.create_nav_section(nav_layout, "我的项目", [
("📊", "项目概述", "overview"),
# ("📋", "项目管理", "management"),
])
# 资源管理分组
# self.create_nav_section(nav_layout, "资源管理", [
# ("🏷", "资源分类", "resource_category"),
# ("📦", "资源管理", "resource_management"),
# ])
# 设置中心分组
self.create_nav_section(nav_layout, "设置中心", [
("📁", "项目设置", "project_settings"),
# ("⚙", "系统设置", "system_settings"),
])
nav_layout.addStretch()
scroll_area.setWidget(nav_widget)
layout.addWidget(scroll_area)
def create_nav_section(self, layout, title, items):
"""创建导航分组"""
# 分组标题
section_widget = QWidget()
section_widget.setObjectName("navSection")
section_layout = QVBoxLayout(section_widget)
section_layout.setContentsMargins(0, 0, 0, 0)
section_layout.setSpacing(0)
# 标题按钮(可展开/收起)
title_btn = QPushButton(f" {title}") # 默认有空格
if IconManager.icon_exists('down'):
title_btn.setIcon(IconManager.get_icon('down'))
else:
title_btn.setText(f"{title}")
title_btn.setObjectName("navSectionTitle")
title_btn.setCheckable(True)
title_btn.setChecked(True)
section_layout.addWidget(title_btn)
# 子项容器
items_widget = QWidget()
items_widget.setObjectName("navItems")
items_layout = QVBoxLayout(items_widget)
items_layout.setContentsMargins(50, 10, 0, 0)
items_layout.setSpacing(10)
# 创建导航项
for icon, text, filter_type in items:
nav_item = self.create_nav_item(icon, text, filter_type)
items_layout.addWidget(nav_item, alignment=Qt.AlignLeft)
section_layout.addWidget(items_widget)
# 展开/收起功能
def toggle_section():
is_expanded = title_btn.isChecked()
items_widget.setVisible(is_expanded)
if is_expanded:
if IconManager.icon_exists('down'):
title_btn.setIcon(IconManager.get_icon('down'))
# 文本已经在初始化时设置了空格,不需要重新设置
else:
title_btn.setText(f"{title}")
else:
if IconManager.icon_exists('right'):
title_btn.setIcon(IconManager.get_icon('right'))
# 文本已经在初始化时设置了空格,不需要重新设置
else:
title_btn.setText(f"{title}")
title_btn.clicked.connect(toggle_section)
layout.addWidget(section_widget)
def create_nav_item(self, icon, text, filter_type):
"""创建导航项"""
item_btn = QPushButton(text) # 直接使用文本,不显示图标
# 隐藏图标,不设置任何图标
# 注释掉图标相关代码
# if IconManager.icon_exists(filter_type):
# item_btn.setIcon(IconManager.get_icon(filter_type, QSize(16, 16)))
# item_btn.setIconSize(QSize(16, 16))
# else:
# # 如果图标不存在,使用原来的文字图标
# item_btn.setText(f"{icon} {text}")
item_btn.setObjectName("navItem")
item_btn.setCheckable(True)
item_btn.setFixedSize(QSize(186, 30))
item_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
# 设置默认选中
if filter_type == "overview":
item_btn.setChecked(True)
# 发送初始导航信号
if filter_type in self.nav_mapping:
section, item_name = self.nav_mapping[filter_type]
# 使用 QTimer.singleShot 确保在UI完全初始化后发送信号
QTimer.singleShot(0, lambda: self.navigation_changed.emit(section, item_name, filter_type))
# 点击事件
def on_clicked():
# 取消其他按钮的选中状态
for btn in self.findChildren(QPushButton):
if btn.objectName() == "navItem" and btn != item_btn:
btn.setChecked(False)
item_btn.setChecked(True)
self.current_filter = filter_type
self.filter_changed.emit(filter_type)
# 发送导航变化信号
if filter_type in self.nav_mapping:
section, item_name = self.nav_mapping[filter_type]
self.navigation_changed.emit(section, item_name, filter_type)
item_btn.clicked.connect(on_clicked)
return item_btn
def create_user_info(self, layout):
"""创建用户信息区域"""
user_widget = QWidget()
user_widget.setObjectName("userInfo")
user_layout = QHBoxLayout(user_widget)
user_layout.setContentsMargins(20, 15, 20, 20)
# 用户头像 - 创建圆形头像
avatar_label = QLabel("U")
avatar_label.setObjectName("userAvatar")
avatar_label.setAlignment(Qt.AlignCenter)
avatar_label.setFixedSize(32, 32)
user_layout.addWidget(avatar_label)
# 用户名
username_label = QLabel("Admin")
username_label.setObjectName("userName")
user_layout.addWidget(username_label)
user_layout.addStretch()
# 下拉箭头
dropdown_label = QLabel("")
dropdown_label.setObjectName("userDropdown")
user_layout.addWidget(dropdown_label)
layout.addWidget(user_widget)
def connect_signals(self):
"""连接信号"""
pass