251 lines
No EOL
9.7 KiB
Python
251 lines
No EOL
9.7 KiB
Python
"""
|
||
Главное окно приложения - содержит меню, панели и canvas
|
||
"""
|
||
|
||
from PySide6.QtWidgets import (
|
||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||
QSplitter, QMenuBar, QMenu, QStatusBar, QMessageBox,
|
||
QFileDialog, QToolBar, QFrame, QScrollArea, QLabel
|
||
)
|
||
from PySide6.QtCore import Qt, QSize
|
||
from PySide6.QtGui import QAction, QKeySequence
|
||
|
||
from views.layer_widget import LayerWidget
|
||
from views.canvas_widget import SolarCanvas
|
||
from views.control_panel import ControlPanel
|
||
from views.timelapse_dialog import TimelapseDialog
|
||
from views.metadata_viewer import MetadataViewer
|
||
|
||
|
||
class MainWindow(QMainWindow):
|
||
"""Главное окно приложения"""
|
||
|
||
def __init__(self, controller):
|
||
super().__init__()
|
||
self.controller = controller
|
||
self.init_ui()
|
||
|
||
def init_ui(self):
|
||
"""Инициализация пользовательского интерфейса"""
|
||
self.setWindowTitle("Helioviewer Solar Viewer - Профессиональный просмотрщик снимков Солнца")
|
||
self.setMinimumSize(1200, 800)
|
||
|
||
# Центральный виджет
|
||
central_widget = QWidget()
|
||
self.setCentralWidget(central_widget)
|
||
|
||
# Основной layout
|
||
main_layout = QHBoxLayout(central_widget)
|
||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||
|
||
# Создаем сплиттер для левой панели и canvas
|
||
splitter = QSplitter(Qt.Orientation.Horizontal)
|
||
main_layout.addWidget(splitter)
|
||
|
||
# Левая панель (с прокруткой)
|
||
left_panel = self.create_left_panel_with_scroll()
|
||
splitter.addWidget(left_panel)
|
||
|
||
# Устанавливаем начальную ширину сплиттера
|
||
splitter.setSizes([400, self.width() - 400])
|
||
|
||
# Правая область (canvas)
|
||
right_area = self.create_right_area()
|
||
splitter.addWidget(right_area)
|
||
|
||
# Создаем меню
|
||
self.create_menu_bar()
|
||
|
||
# Создаем статус бар
|
||
self.status_bar = QStatusBar()
|
||
self.setStatusBar(self.status_bar)
|
||
self.status_bar.showMessage("Готов к работе")
|
||
|
||
# Добавляем тулбар для быстрого доступа
|
||
self.create_toolbar()
|
||
|
||
def create_left_panel_with_scroll(self) -> QWidget:
|
||
"""
|
||
Создает левую панель с прокруткой, где все виджеты равномерно распределяют пространство
|
||
"""
|
||
# Внешний контейнер для скролла
|
||
scroll_container = QWidget()
|
||
scroll_layout = QVBoxLayout(scroll_container)
|
||
scroll_layout.setContentsMargins(0, 0, 0, 0)
|
||
|
||
# Создаем QScrollArea
|
||
scroll_area = QScrollArea()
|
||
scroll_area.setWidgetResizable(True) # Позволяет виджету изменять размер
|
||
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||
scroll_area.setStyleSheet("""
|
||
QScrollArea {
|
||
border: none;
|
||
background-color: #2b2b2b;
|
||
}
|
||
QScrollBar:vertical {
|
||
background-color: #2b2b2b;
|
||
width: 12px;
|
||
border-radius: 6px;
|
||
}
|
||
QScrollBar::handle:vertical {
|
||
background-color: #555;
|
||
border-radius: 6px;
|
||
min-height: 20px;
|
||
}
|
||
QScrollBar::handle:vertical:hover {
|
||
background-color: #777;
|
||
}
|
||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
|
||
height: 0px;
|
||
}
|
||
""")
|
||
|
||
# Внутренний контейнер для всех виджетов
|
||
content_widget = QWidget()
|
||
content_widget.setStyleSheet("background-color: #2b2b2b;")
|
||
layout = QVBoxLayout(content_widget)
|
||
layout.setSpacing(10)
|
||
layout.setContentsMargins(10, 10, 10, 10)
|
||
|
||
# Панель управления (выбор даты, спектра)
|
||
self.control_panel = ControlPanel(self.controller)
|
||
layout.addWidget(self.control_panel, 1) # stretch factor = 1
|
||
|
||
# Разделитель
|
||
layout.addWidget(self.create_separator())
|
||
|
||
# Заголовок слоев
|
||
title_layers = self.create_section_title("📁 Слои изображений")
|
||
layout.addWidget(title_layers)
|
||
|
||
# Виджет слоев - будет занимать столько места, сколько нужно
|
||
self.layer_widget = LayerWidget(self.controller)
|
||
layout.addWidget(self.layer_widget, 2) # stretch factor = 2 (больше места)
|
||
|
||
# Разделитель
|
||
layout.addWidget(self.create_separator())
|
||
|
||
# Заголовок метаданных
|
||
title_metadata = self.create_section_title("📊 Метаданные FITS")
|
||
layout.addWidget(title_metadata)
|
||
|
||
# Просмотрщик метаданных
|
||
self.metadata_viewer = MetadataViewer()
|
||
layout.addWidget(self.metadata_viewer, 1) # stretch factor = 1
|
||
|
||
# Растягивающийся спейсер внизу (опционально)
|
||
layout.addStretch()
|
||
|
||
# Устанавливаем content_widget в scroll_area
|
||
scroll_area.setWidget(content_widget)
|
||
|
||
# Добавляем scroll_area в контейнер
|
||
scroll_layout.addWidget(scroll_area)
|
||
|
||
return scroll_container
|
||
|
||
def create_separator(self) -> QFrame:
|
||
"""Создает линию-разделитель"""
|
||
separator = QFrame()
|
||
separator.setFrameShape(QFrame.Shape.HLine)
|
||
separator.setFrameShadow(QFrame.Shadow.Sunken)
|
||
separator.setStyleSheet("background-color: #555; max-height: 1px;")
|
||
return separator
|
||
|
||
def create_section_title(self, title: str) -> QLabel:
|
||
"""Создает заголовок секции"""
|
||
label = QLabel(title)
|
||
label.setStyleSheet("""
|
||
font-weight: bold;
|
||
font-size: 14px;
|
||
padding: 8px 5px;
|
||
background-color: #3c3c3c;
|
||
border-radius: 4px;
|
||
margin-top: 5px;
|
||
margin-bottom: 5px;
|
||
""")
|
||
label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
||
return label
|
||
|
||
def create_right_area(self) -> QWidget:
|
||
"""Создает правую область с canvas"""
|
||
area = QWidget()
|
||
layout = QVBoxLayout(area)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
|
||
# Canvas для отображения изображений
|
||
self.canvas = SolarCanvas(self.controller)
|
||
layout.addWidget(self.canvas)
|
||
|
||
return area
|
||
|
||
def create_menu_bar(self):
|
||
"""Создает меню приложения"""
|
||
menubar = self.menuBar()
|
||
|
||
# Меню Файл
|
||
file_menu = menubar.addMenu("📁 Файл")
|
||
|
||
# Действия для меню Файл
|
||
self.setup_action = QAction("⚙️ Настройки", self)
|
||
self.exit_action = QAction("🚪 Выход", self)
|
||
self.exit_action.setShortcut(QKeySequence.StandardKey.Quit)
|
||
self.exit_action.triggered.connect(self.close)
|
||
|
||
file_menu.addAction(self.setup_action)
|
||
file_menu.addSeparator()
|
||
file_menu.addAction(self.exit_action)
|
||
|
||
# Меню Инструменты
|
||
tools_menu = menubar.addMenu("🛠️ Инструменты")
|
||
|
||
self.timelapse_action = QAction("🎬 Таймлапс...", self)
|
||
self.timelapse_action.triggered.connect(self.open_timelapse_dialog)
|
||
tools_menu.addAction(self.timelapse_action)
|
||
|
||
# Меню Справка
|
||
help_menu = menubar.addMenu("❓ Справка")
|
||
|
||
about_action = QAction("ℹ️ О программе", self)
|
||
about_action.triggered.connect(self.show_about)
|
||
help_menu.addAction(about_action)
|
||
|
||
def create_toolbar(self):
|
||
"""Создает панель инструментов"""
|
||
toolbar = QToolBar("Быстрый доступ")
|
||
self.addToolBar(toolbar)
|
||
toolbar.setIconSize(QSize(24, 24))
|
||
|
||
def open_timelapse_dialog(self):
|
||
"""Открывает диалог создания таймлапса"""
|
||
dialog = TimelapseDialog(self.controller, self)
|
||
dialog.exec()
|
||
|
||
def show_about(self):
|
||
"""Показывает информацию о программе"""
|
||
QMessageBox.about(
|
||
self,
|
||
"О программе",
|
||
"Helioviewer Solar Viewer v1.0\n\n"
|
||
"Профессиональный просмотрщик снимков Солнца\n"
|
||
"Использует данные Helioviewer API\n\n"
|
||
"Возможности:\n"
|
||
"• Загрузка снимков в различных спектрах\n"
|
||
"• Многослойный режим с наложением\n"
|
||
"• Создание таймлапс-анимаций\n"
|
||
"• Просмотр FITS-метаданных\n\n"
|
||
"© 2024 SolarViewer Team"
|
||
)
|
||
|
||
def update_status(self, message: str, timeout: int = 3000):
|
||
"""Обновляет статус в статус-баре"""
|
||
self.status_bar.showMessage(message, timeout)
|
||
|
||
def update_layer_list(self, layers):
|
||
"""Обновляет список слоев"""
|
||
self.layer_widget.update_layers(layers)
|
||
|
||
def get_control_panel(self):
|
||
"""Возвращает панель управления"""
|
||
return self.control_panel |