1067 lines
38 KiB
Python
1067 lines
38 KiB
Python
"""
|
|
Advanced Main Window - Smart Intersection Monitoring System
|
|
Complete integration of all modern UI components with proper backend connections
|
|
"""
|
|
|
|
from PySide6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
QTabWidget, QSplitter, QMenuBar, QToolBar, QStatusBar,
|
|
QPushButton, QLabel, QFrame, QSystemTrayIcon, QMenu,
|
|
QMessageBox, QProgressBar, QComboBox, QCheckBox,
|
|
QApplication, QSizePolicy, QSpacerItem)
|
|
from PySide6.QtCore import (Qt, QTimer, QThread, Signal, QSettings, QSize,
|
|
QPropertyAnimation, QEasingCurve, QRect, QDateTime)
|
|
from PySide6.QtGui import (QFont, QIcon, QPixmap, QAction, QPalette, QColor,
|
|
QKeySequence, QPainter, QBrush, QPen)
|
|
import sys
|
|
import os
|
|
import json
|
|
import traceback
|
|
from pathlib import Path
|
|
|
|
# Import our modern UI components
|
|
try:
|
|
from ui.theme_manager import ThemeManager
|
|
from ui.widgets.notification_center import NotificationCenter
|
|
from ui.widgets.status_indicator import StatusIndicator
|
|
from ui.widgets.alert_widget import AlertWidget
|
|
from ui.dialogs.settings_dialog import SettingsDialog
|
|
|
|
# Import all the modern tabs
|
|
from ui.tabs.live_monitoring_tab import LiveMonitoringTab
|
|
from ui.tabs.video_analysis_tab import VideoAnalysisTab
|
|
from ui.tabs.vlm_insights_tab import VLMInsightsTab
|
|
from ui.tabs.violations_tab import ViolationsTab
|
|
from ui.tabs.system_performance_tab import SystemPerformanceTab
|
|
from ui.tabs.smart_intersection_tab import SmartIntersectionTab
|
|
|
|
MODERN_UI_AVAILABLE = True
|
|
print("✅ All modern UI components imported successfully")
|
|
|
|
except ImportError as e:
|
|
print(f"⚠️ Modern UI components not available: {e}")
|
|
MODERN_UI_AVAILABLE = False
|
|
|
|
# Import existing controllers
|
|
try:
|
|
from controllers.video_controller_new import VideoController
|
|
from controllers.model_manager import ModelManager
|
|
from controllers.analytics_controller import AnalyticsController
|
|
from controllers.vlm_controller import VLMController
|
|
CONTROLLERS_AVAILABLE = True
|
|
print("✅ Backend controllers imported successfully")
|
|
except ImportError as e:
|
|
print(f"⚠️ Backend controllers not available: {e}")
|
|
CONTROLLERS_AVAILABLE = False
|
|
|
|
class AdvancedSystemStatusWidget(QFrame):
|
|
"""Advanced system status widget with real-time metrics"""
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.setFixedHeight(80)
|
|
self.setStyleSheet("""
|
|
QFrame {
|
|
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
|
stop:0 #2c3e50, stop:1 #34495e);
|
|
border-radius: 8px;
|
|
margin: 4px;
|
|
}
|
|
""")
|
|
|
|
self._setup_ui()
|
|
|
|
# Update timer
|
|
self.update_timer = QTimer()
|
|
self.update_timer.timeout.connect(self._update_metrics)
|
|
self.update_timer.start(2000) # Update every 2 seconds
|
|
|
|
def _setup_ui(self):
|
|
"""Setup system status UI"""
|
|
layout = QHBoxLayout(self)
|
|
layout.setContentsMargins(15, 10, 15, 10)
|
|
|
|
# System status
|
|
system_layout = QVBoxLayout()
|
|
|
|
status_label = QLabel("🖥️ System Status")
|
|
status_label.setFont(QFont("Segoe UI", 9, QFont.Bold))
|
|
status_label.setStyleSheet("color: white;")
|
|
system_layout.addWidget(status_label)
|
|
|
|
self.system_status = QLabel("All Systems Operational")
|
|
self.system_status.setFont(QFont("Segoe UI", 8))
|
|
self.system_status.setStyleSheet("color: #27ae60;")
|
|
system_layout.addWidget(self.system_status)
|
|
|
|
layout.addLayout(system_layout)
|
|
|
|
# Separator
|
|
sep1 = QFrame()
|
|
sep1.setFrameShape(QFrame.VLine)
|
|
sep1.setStyleSheet("color: #7f8c8d;")
|
|
layout.addWidget(sep1)
|
|
|
|
# Active cameras
|
|
cameras_layout = QVBoxLayout()
|
|
|
|
cameras_label = QLabel("📷 Active Cameras")
|
|
cameras_label.setFont(QFont("Segoe UI", 9, QFont.Bold))
|
|
cameras_label.setStyleSheet("color: white;")
|
|
cameras_layout.addWidget(cameras_label)
|
|
|
|
self.cameras_count = QLabel("4 / 4 Online")
|
|
self.cameras_count.setFont(QFont("Segoe UI", 8))
|
|
self.cameras_count.setStyleSheet("color: #27ae60;")
|
|
cameras_layout.addWidget(self.cameras_count)
|
|
|
|
layout.addLayout(cameras_layout)
|
|
|
|
# Separator
|
|
sep2 = QFrame()
|
|
sep2.setFrameShape(QFrame.VLine)
|
|
sep2.setStyleSheet("color: #7f8c8d;")
|
|
layout.addWidget(sep2)
|
|
|
|
# Detection stats
|
|
detection_layout = QVBoxLayout()
|
|
|
|
detection_label = QLabel("🎯 Detections")
|
|
detection_label.setFont(QFont("Segoe UI", 9, QFont.Bold))
|
|
detection_label.setStyleSheet("color: white;")
|
|
detection_layout.addWidget(detection_label)
|
|
|
|
self.detection_count = QLabel("127 objects detected")
|
|
self.detection_count.setFont(QFont("Segoe UI", 8))
|
|
self.detection_count.setStyleSheet("color: #3498db;")
|
|
detection_layout.addWidget(self.detection_count)
|
|
|
|
layout.addLayout(detection_layout)
|
|
|
|
# Separator
|
|
sep3 = QFrame()
|
|
sep3.setFrameShape(QFrame.VLine)
|
|
sep3.setStyleSheet("color: #7f8c8d;")
|
|
layout.addWidget(sep3)
|
|
|
|
# Performance
|
|
performance_layout = QVBoxLayout()
|
|
|
|
perf_label = QLabel("⚡ Performance")
|
|
perf_label.setFont(QFont("Segoe UI", 9, QFont.Bold))
|
|
perf_label.setStyleSheet("color: white;")
|
|
performance_layout.addWidget(perf_label)
|
|
|
|
self.fps_label = QLabel("25.3 FPS avg")
|
|
self.fps_label.setFont(QFont("Segoe UI", 8))
|
|
self.fps_label.setStyleSheet("color: #f39c12;")
|
|
performance_layout.addWidget(self.fps_label)
|
|
|
|
layout.addLayout(performance_layout)
|
|
|
|
layout.addStretch()
|
|
|
|
# Quick actions
|
|
actions_layout = QVBoxLayout()
|
|
|
|
emergency_btn = QPushButton("🚨")
|
|
emergency_btn.setFixedSize(40, 30)
|
|
emergency_btn.setToolTip("Emergency Stop All")
|
|
emergency_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #e74c3c;
|
|
color: white;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #c0392b;
|
|
}
|
|
""")
|
|
actions_layout.addWidget(emergency_btn)
|
|
|
|
settings_btn = QPushButton("⚙️")
|
|
settings_btn.setFixedSize(40, 30)
|
|
settings_btn.setToolTip("Quick Settings")
|
|
settings_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #34495e;
|
|
color: white;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #4a6478;
|
|
}
|
|
""")
|
|
actions_layout.addWidget(settings_btn)
|
|
|
|
layout.addLayout(actions_layout)
|
|
|
|
def _update_metrics(self):
|
|
"""Update real-time metrics"""
|
|
import random
|
|
|
|
# Simulate real-time updates
|
|
detection_count = random.randint(100, 200)
|
|
self.detection_count.setText(f"{detection_count} objects detected")
|
|
|
|
fps = round(random.uniform(20.0, 30.0), 1)
|
|
self.fps_label.setText(f"{fps} FPS avg")
|
|
|
|
# Randomly show different statuses
|
|
statuses = [
|
|
("All Systems Operational", "#27ae60"),
|
|
("Processing Optimization", "#f39c12"),
|
|
("High Traffic Detected", "#e67e22")
|
|
]
|
|
|
|
if random.random() < 0.1: # 10% chance to change status
|
|
status, color = random.choice(statuses)
|
|
self.system_status.setText(status)
|
|
self.system_status.setStyleSheet(f"color: {color};")
|
|
|
|
class AdvancedControlPanel(QFrame):
|
|
"""Advanced control panel with quick actions"""
|
|
|
|
# Signals
|
|
recording_toggled = Signal(bool)
|
|
detection_toggled = Signal(bool)
|
|
emergency_activated = Signal()
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.setFixedHeight(60)
|
|
self.setStyleSheet("""
|
|
QFrame {
|
|
background-color: #ecf0f1;
|
|
border: 1px solid #bdc3c7;
|
|
border-radius: 6px;
|
|
margin: 2px;
|
|
}
|
|
""")
|
|
|
|
self.is_recording = False
|
|
self.is_detecting = True
|
|
|
|
self._setup_ui()
|
|
|
|
def _setup_ui(self):
|
|
"""Setup control panel UI"""
|
|
layout = QHBoxLayout(self)
|
|
layout.setContentsMargins(10, 8, 10, 8)
|
|
|
|
# Recording control
|
|
self.record_btn = QPushButton("🔴 Start Recording")
|
|
self.record_btn.setCheckable(True)
|
|
self.record_btn.clicked.connect(self._toggle_recording)
|
|
self.record_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #e74c3c;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 15px;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #c0392b;
|
|
}
|
|
QPushButton:checked {
|
|
background-color: #27ae60;
|
|
}
|
|
""")
|
|
layout.addWidget(self.record_btn)
|
|
|
|
# Detection control
|
|
self.detect_btn = QPushButton("🎯 Detection ON")
|
|
self.detect_btn.setCheckable(True)
|
|
self.detect_btn.setChecked(True)
|
|
self.detect_btn.clicked.connect(self._toggle_detection)
|
|
self.detect_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #27ae60;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 15px;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #229954;
|
|
}
|
|
QPushButton:!checked {
|
|
background-color: #95a5a6;
|
|
}
|
|
""")
|
|
layout.addWidget(self.detect_btn)
|
|
|
|
# Device selection
|
|
device_layout = QVBoxLayout()
|
|
device_label = QLabel("Compute:")
|
|
device_label.setFont(QFont("Segoe UI", 7))
|
|
device_layout.addWidget(device_label)
|
|
|
|
self.device_combo = QComboBox()
|
|
self.device_combo.addItems(["AUTO", "CPU", "GPU"])
|
|
self.device_combo.setCurrentText("AUTO")
|
|
device_layout.addWidget(self.device_combo)
|
|
|
|
layout.addLayout(device_layout)
|
|
|
|
# FPS control
|
|
fps_layout = QVBoxLayout()
|
|
fps_label = QLabel("Target FPS:")
|
|
fps_label.setFont(QFont("Segoe UI", 7))
|
|
fps_layout.addWidget(fps_label)
|
|
|
|
self.fps_combo = QComboBox()
|
|
self.fps_combo.addItems(["15", "20", "25", "30"])
|
|
self.fps_combo.setCurrentText("25")
|
|
fps_layout.addWidget(self.fps_combo)
|
|
|
|
layout.addLayout(fps_layout)
|
|
|
|
layout.addStretch()
|
|
|
|
# Emergency stop
|
|
emergency_btn = QPushButton("🚨 EMERGENCY")
|
|
emergency_btn.clicked.connect(self._emergency_stop)
|
|
emergency_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #8e44ad;
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
font-size: 10pt;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #7d3c98;
|
|
}
|
|
""")
|
|
layout.addWidget(emergency_btn)
|
|
|
|
def _toggle_recording(self, checked):
|
|
"""Toggle recording state"""
|
|
self.is_recording = checked
|
|
if checked:
|
|
self.record_btn.setText("⏹️ Stop Recording")
|
|
else:
|
|
self.record_btn.setText("🔴 Start Recording")
|
|
|
|
self.recording_toggled.emit(checked)
|
|
print(f"🎥 Recording {'started' if checked else 'stopped'}")
|
|
|
|
def _toggle_detection(self, checked):
|
|
"""Toggle detection state"""
|
|
self.is_detecting = checked
|
|
if checked:
|
|
self.detect_btn.setText("🎯 Detection ON")
|
|
else:
|
|
self.detect_btn.setText("⏸️ Detection OFF")
|
|
|
|
self.detection_toggled.emit(checked)
|
|
print(f"🎯 Detection {'enabled' if checked else 'disabled'}")
|
|
|
|
def _emergency_stop(self):
|
|
"""Emergency stop all operations"""
|
|
# Stop recording if active
|
|
if self.is_recording:
|
|
self.record_btn.setChecked(False)
|
|
self._toggle_recording(False)
|
|
|
|
# Stop detection
|
|
self.detect_btn.setChecked(False)
|
|
self._toggle_detection(False)
|
|
|
|
self.emergency_activated.emit()
|
|
print("🚨 EMERGENCY STOP ACTIVATED")
|
|
|
|
class AdvancedMainWindow(QMainWindow):
|
|
"""
|
|
Advanced Main Window for Smart Intersection Monitoring System
|
|
|
|
Features:
|
|
- Modern tabbed interface with 6 specialized tabs
|
|
- Real-time system status monitoring
|
|
- Advanced control panel with quick actions
|
|
- Integrated theme management
|
|
- System tray integration
|
|
- Comprehensive settings dialog
|
|
- Alert management system
|
|
- Backend controller integration
|
|
"""
|
|
|
|
# Signals
|
|
window_closing = Signal()
|
|
theme_changed = Signal(str)
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.settings = QSettings("SmartIntersection", "AdvancedMonitoring")
|
|
self.controllers = {}
|
|
self.active_alerts = []
|
|
|
|
# Initialize components
|
|
if MODERN_UI_AVAILABLE:
|
|
self.theme_manager = ThemeManager()
|
|
|
|
# Initialize backend controllers
|
|
self._initialize_controllers()
|
|
|
|
# Setup UI
|
|
self._setup_window()
|
|
self._setup_ui()
|
|
self._setup_menu_bar()
|
|
self._setup_toolbar()
|
|
self._setup_status_bar()
|
|
self._setup_system_tray()
|
|
|
|
# Load settings and apply theme
|
|
self._load_settings()
|
|
self._apply_initial_theme()
|
|
|
|
# Setup update timers
|
|
self._setup_timers()
|
|
|
|
print("🌉 Advanced Smart Intersection Monitoring System initialized")
|
|
|
|
def _initialize_controllers(self):
|
|
"""Initialize backend controllers"""
|
|
if not CONTROLLERS_AVAILABLE:
|
|
print("⚠️ Backend controllers not available - running in demo mode")
|
|
return
|
|
|
|
try:
|
|
# Video controller
|
|
self.controllers['video'] = VideoController()
|
|
print("✅ Video controller initialized")
|
|
|
|
# Model manager
|
|
self.controllers['model'] = ModelManager()
|
|
print("✅ Model manager initialized")
|
|
|
|
# Analytics controller
|
|
self.controllers['analytics'] = AnalyticsController()
|
|
print("✅ Analytics controller initialized")
|
|
|
|
# VLM controller
|
|
self.controllers['vlm'] = VLMController()
|
|
print("✅ VLM controller initialized")
|
|
|
|
except Exception as e:
|
|
print(f"⚠️ Error initializing controllers: {e}")
|
|
|
|
def _setup_window(self):
|
|
"""Setup main window properties"""
|
|
self.setWindowTitle("Smart Intersection Monitoring System - Advanced UI")
|
|
|
|
# Set window icon
|
|
try:
|
|
if os.path.exists("assets/app_icon.png"):
|
|
self.setWindowIcon(QIcon("assets/app_icon.png"))
|
|
else:
|
|
# Create a simple default icon
|
|
default_pixmap = QPixmap(32, 32)
|
|
default_pixmap.fill(QColor(52, 152, 219)) # Blue color
|
|
self.setWindowIcon(QIcon(default_pixmap))
|
|
except Exception:
|
|
pass # No icon if there's any issue
|
|
|
|
# Set window size and position
|
|
self.resize(1400, 900)
|
|
self.setMinimumSize(1200, 800)
|
|
|
|
# Center window on screen
|
|
screen_geometry = QApplication.primaryScreen().geometry()
|
|
window_geometry = self.frameGeometry()
|
|
center_point = screen_geometry.center()
|
|
window_geometry.moveCenter(center_point)
|
|
self.move(window_geometry.topLeft())
|
|
|
|
def _setup_ui(self):
|
|
"""Setup main UI layout"""
|
|
central_widget = QWidget()
|
|
self.setCentralWidget(central_widget)
|
|
|
|
# Main layout
|
|
main_layout = QVBoxLayout(central_widget)
|
|
main_layout.setContentsMargins(8, 8, 8, 8)
|
|
main_layout.setSpacing(6)
|
|
|
|
# System status widget
|
|
self.status_widget = AdvancedSystemStatusWidget()
|
|
main_layout.addWidget(self.status_widget)
|
|
|
|
# Control panel
|
|
self.control_panel = AdvancedControlPanel()
|
|
self.control_panel.recording_toggled.connect(self._on_recording_toggled)
|
|
self.control_panel.detection_toggled.connect(self._on_detection_toggled)
|
|
self.control_panel.emergency_activated.connect(self._on_emergency_activated)
|
|
main_layout.addWidget(self.control_panel)
|
|
|
|
# Main content splitter
|
|
content_splitter = QSplitter(Qt.Horizontal)
|
|
main_layout.addWidget(content_splitter)
|
|
|
|
# Main tabs
|
|
self.main_tabs = self._create_main_tabs()
|
|
content_splitter.addWidget(self.main_tabs)
|
|
|
|
# Side panel for alerts and notifications
|
|
side_panel = self._create_side_panel()
|
|
content_splitter.addWidget(side_panel)
|
|
|
|
# Set splitter proportions (main content: side panel = 4:1)
|
|
content_splitter.setSizes([1120, 280])
|
|
|
|
def _create_main_tabs(self):
|
|
"""Create main tabbed interface"""
|
|
tabs = QTabWidget()
|
|
tabs.setTabPosition(QTabWidget.North)
|
|
tabs.setMovable(True)
|
|
tabs.setTabsClosable(False)
|
|
|
|
# Tab styling
|
|
tabs.setStyleSheet("""
|
|
QTabWidget::pane {
|
|
border: 1px solid #c0c0c0;
|
|
background-color: white;
|
|
}
|
|
QTabBar::tab {
|
|
background-color: #f0f0f0;
|
|
border: 1px solid #c0c0c0;
|
|
padding: 8px 16px;
|
|
margin-right: 2px;
|
|
border-bottom: none;
|
|
}
|
|
QTabBar::tab:selected {
|
|
background-color: white;
|
|
border-bottom: 2px solid #3498db;
|
|
}
|
|
QTabBar::tab:hover {
|
|
background-color: #e0e0e0;
|
|
}
|
|
""")
|
|
|
|
if MODERN_UI_AVAILABLE:
|
|
# Add all modern tabs
|
|
try:
|
|
# Live Monitoring
|
|
live_tab = LiveMonitoringTab()
|
|
tabs.addTab(live_tab, "🎥 Live Monitoring")
|
|
|
|
# Video Analysis
|
|
analysis_tab = VideoAnalysisTab()
|
|
tabs.addTab(analysis_tab, "📊 Video Analysis")
|
|
|
|
# VLM Insights
|
|
vlm_tab = VLMInsightsTab()
|
|
tabs.addTab(vlm_tab, "🤖 AI Insights")
|
|
|
|
# Violations
|
|
violations_tab = ViolationsTab()
|
|
tabs.addTab(violations_tab, "⚠️ Violations")
|
|
|
|
# System Performance
|
|
performance_tab = SystemPerformanceTab()
|
|
tabs.addTab(performance_tab, "📈 Performance")
|
|
|
|
# Smart Intersection
|
|
intersection_tab = SmartIntersectionTab()
|
|
tabs.addTab(intersection_tab, "🌉 Smart Intersection")
|
|
|
|
print("✅ All 6 modern tabs loaded successfully")
|
|
|
|
except Exception as e:
|
|
print(f"⚠️ Error loading modern tabs: {e}")
|
|
# Add fallback tab
|
|
fallback_widget = QWidget()
|
|
fallback_layout = QVBoxLayout(fallback_widget)
|
|
fallback_label = QLabel("Modern UI components not available.\nRunning in fallback mode.")
|
|
fallback_label.setAlignment(Qt.AlignCenter)
|
|
fallback_layout.addWidget(fallback_label)
|
|
tabs.addTab(fallback_widget, "System")
|
|
else:
|
|
# Fallback tab
|
|
fallback_widget = QWidget()
|
|
fallback_layout = QVBoxLayout(fallback_widget)
|
|
fallback_label = QLabel("🌉 Smart Intersection Monitoring System\n\nModern UI components are loading...")
|
|
fallback_label.setAlignment(Qt.AlignCenter)
|
|
fallback_label.setFont(QFont("Segoe UI", 12))
|
|
fallback_layout.addWidget(fallback_label)
|
|
tabs.addTab(fallback_widget, "System")
|
|
|
|
return tabs
|
|
|
|
def _create_side_panel(self):
|
|
"""Create side panel with alerts and notifications"""
|
|
side_panel = QFrame()
|
|
side_panel.setFixedWidth(280)
|
|
side_panel.setStyleSheet("""
|
|
QFrame {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 6px;
|
|
}
|
|
""")
|
|
|
|
layout = QVBoxLayout(side_panel)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
if MODERN_UI_AVAILABLE:
|
|
# Notification center
|
|
try:
|
|
self.notification_center = NotificationCenter()
|
|
layout.addWidget(self.notification_center)
|
|
|
|
# Alert widget
|
|
self.alert_widget = AlertWidget()
|
|
self.alert_widget.alert_action_required.connect(self._handle_alert_action)
|
|
layout.addWidget(self.alert_widget)
|
|
|
|
print("✅ Notification center and alerts loaded")
|
|
|
|
except Exception as e:
|
|
print(f"⚠️ Error loading side panel components: {e}")
|
|
# Fallback label
|
|
fallback_label = QLabel("Notifications\n& Alerts")
|
|
fallback_label.setAlignment(Qt.AlignCenter)
|
|
layout.addWidget(fallback_label)
|
|
else:
|
|
# Fallback
|
|
fallback_label = QLabel("Notifications\n& Alerts\n\nLoading...")
|
|
fallback_label.setAlignment(Qt.AlignCenter)
|
|
layout.addWidget(fallback_label)
|
|
|
|
return side_panel
|
|
|
|
def _setup_menu_bar(self):
|
|
"""Setup application menu bar"""
|
|
menubar = self.menuBar()
|
|
|
|
# File menu
|
|
file_menu = menubar.addMenu("&File")
|
|
|
|
# New session
|
|
new_action = QAction("&New Session", self)
|
|
new_action.setShortcut(QKeySequence.New)
|
|
new_action.triggered.connect(self._new_session)
|
|
file_menu.addAction(new_action)
|
|
|
|
# Open configuration
|
|
open_action = QAction("&Open Configuration...", self)
|
|
open_action.setShortcut(QKeySequence.Open)
|
|
open_action.triggered.connect(self._open_configuration)
|
|
file_menu.addAction(open_action)
|
|
|
|
# Save configuration
|
|
save_action = QAction("&Save Configuration", self)
|
|
save_action.setShortcut(QKeySequence.Save)
|
|
save_action.triggered.connect(self._save_configuration)
|
|
file_menu.addAction(save_action)
|
|
|
|
file_menu.addSeparator()
|
|
|
|
# Export data
|
|
export_action = QAction("&Export Data...", self)
|
|
export_action.triggered.connect(self._export_data)
|
|
file_menu.addAction(export_action)
|
|
|
|
file_menu.addSeparator()
|
|
|
|
# Exit
|
|
exit_action = QAction("E&xit", self)
|
|
exit_action.setShortcut(QKeySequence.Quit)
|
|
exit_action.triggered.connect(self.close)
|
|
file_menu.addAction(exit_action)
|
|
|
|
# View menu
|
|
view_menu = menubar.addMenu("&View")
|
|
|
|
# Theme submenu
|
|
theme_submenu = view_menu.addMenu("&Theme")
|
|
|
|
# Light theme
|
|
light_action = QAction("&Light Theme", self)
|
|
light_action.triggered.connect(lambda: self._change_theme("light"))
|
|
theme_submenu.addAction(light_action)
|
|
|
|
# Dark theme
|
|
dark_action = QAction("&Dark Theme", self)
|
|
dark_action.triggered.connect(lambda: self._change_theme("dark"))
|
|
theme_submenu.addAction(dark_action)
|
|
|
|
view_menu.addSeparator()
|
|
|
|
# Fullscreen
|
|
fullscreen_action = QAction("&Fullscreen", self)
|
|
fullscreen_action.setShortcut(QKeySequence.FullScreen)
|
|
fullscreen_action.triggered.connect(self._toggle_fullscreen)
|
|
view_menu.addAction(fullscreen_action)
|
|
|
|
# Tools menu
|
|
tools_menu = menubar.addMenu("&Tools")
|
|
|
|
# Settings
|
|
settings_action = QAction("&Settings...", self)
|
|
settings_action.setShortcut(QKeySequence.Preferences)
|
|
settings_action.triggered.connect(self._show_settings)
|
|
tools_menu.addAction(settings_action)
|
|
|
|
# System diagnostics
|
|
diagnostics_action = QAction("&System Diagnostics", self)
|
|
diagnostics_action.triggered.connect(self._show_diagnostics)
|
|
tools_menu.addAction(diagnostics_action)
|
|
|
|
# Help menu
|
|
help_menu = menubar.addMenu("&Help")
|
|
|
|
# About
|
|
about_action = QAction("&About", self)
|
|
about_action.triggered.connect(self._show_about)
|
|
help_menu.addAction(about_action)
|
|
|
|
# Documentation
|
|
docs_action = QAction("&Documentation", self)
|
|
docs_action.triggered.connect(self._show_documentation)
|
|
help_menu.addAction(docs_action)
|
|
|
|
def _setup_toolbar(self):
|
|
"""Setup main toolbar"""
|
|
toolbar = self.addToolBar("Main")
|
|
toolbar.setMovable(False)
|
|
toolbar.setFloatable(False)
|
|
|
|
# Quick action buttons
|
|
self.start_monitoring_action = QAction("▶️ Start", self)
|
|
self.start_monitoring_action.setToolTip("Start monitoring all cameras")
|
|
self.start_monitoring_action.triggered.connect(self._start_monitoring)
|
|
toolbar.addAction(self.start_monitoring_action)
|
|
|
|
self.stop_monitoring_action = QAction("⏹️ Stop", self)
|
|
self.stop_monitoring_action.setToolTip("Stop all monitoring")
|
|
self.stop_monitoring_action.triggered.connect(self._stop_monitoring)
|
|
toolbar.addAction(self.stop_monitoring_action)
|
|
|
|
toolbar.addSeparator()
|
|
|
|
# Theme toggle
|
|
self.theme_action = QAction("🌙 Dark", self)
|
|
self.theme_action.setToolTip("Switch to dark theme")
|
|
self.theme_action.triggered.connect(self._toggle_theme)
|
|
toolbar.addAction(self.theme_action)
|
|
|
|
toolbar.addSeparator()
|
|
|
|
# Settings
|
|
settings_action = QAction("⚙️ Settings", self)
|
|
settings_action.triggered.connect(self._show_settings)
|
|
toolbar.addAction(settings_action)
|
|
|
|
def _setup_status_bar(self):
|
|
"""Setup status bar"""
|
|
status_bar = self.statusBar()
|
|
|
|
# Connection status
|
|
self.connection_status = QLabel("🟢 Connected")
|
|
status_bar.addWidget(self.connection_status)
|
|
|
|
status_bar.addPermanentWidget(QLabel("|"))
|
|
|
|
# Processing status
|
|
self.processing_status = QLabel("🎯 Processing")
|
|
status_bar.addPermanentWidget(self.processing_status)
|
|
|
|
status_bar.addPermanentWidget(QLabel("|"))
|
|
|
|
# Current time
|
|
self.time_label = QLabel()
|
|
self._update_time()
|
|
status_bar.addPermanentWidget(self.time_label)
|
|
|
|
def _setup_system_tray(self):
|
|
"""Setup system tray icon"""
|
|
if not QSystemTrayIcon.isSystemTrayAvailable():
|
|
return
|
|
|
|
# Create tray icon
|
|
self.tray_icon = QSystemTrayIcon(self)
|
|
|
|
# Set tray icon - use a simple default icon
|
|
try:
|
|
if os.path.exists("assets/tray_icon.png"):
|
|
self.tray_icon.setIcon(QIcon("assets/tray_icon.png"))
|
|
else:
|
|
# Create a simple default icon using standard icons
|
|
self.tray_icon.setIcon(self.style().standardIcon(self.style().StandardPixmap.SP_DesktopIcon))
|
|
except AttributeError:
|
|
# Fallback for older Qt versions
|
|
from PySide6.QtGui import QPixmap
|
|
default_pixmap = QPixmap(16, 16)
|
|
default_pixmap.fill(QColor(52, 152, 219)) # Blue color
|
|
self.tray_icon.setIcon(QIcon(default_pixmap))
|
|
|
|
# Tray menu
|
|
tray_menu = QMenu()
|
|
|
|
show_action = tray_menu.addAction("Show")
|
|
show_action.triggered.connect(self.show)
|
|
|
|
hide_action = tray_menu.addAction("Hide")
|
|
hide_action.triggered.connect(self.hide)
|
|
|
|
tray_menu.addSeparator()
|
|
|
|
quit_action = tray_menu.addAction("Quit")
|
|
quit_action.triggered.connect(self.close)
|
|
|
|
self.tray_icon.setContextMenu(tray_menu)
|
|
self.tray_icon.show()
|
|
|
|
# Tray icon activation
|
|
self.tray_icon.activated.connect(self._on_tray_activated)
|
|
|
|
def _setup_timers(self):
|
|
"""Setup update timers"""
|
|
# Status update timer
|
|
self.status_timer = QTimer()
|
|
self.status_timer.timeout.connect(self._update_status)
|
|
self.status_timer.start(5000) # Update every 5 seconds
|
|
|
|
# Time update timer
|
|
self.time_timer = QTimer()
|
|
self.time_timer.timeout.connect(self._update_time)
|
|
self.time_timer.start(1000) # Update every second
|
|
|
|
def _load_settings(self):
|
|
"""Load application settings"""
|
|
# Window geometry
|
|
geometry = self.settings.value("geometry")
|
|
if geometry:
|
|
self.restoreGeometry(geometry)
|
|
|
|
# Window state
|
|
state = self.settings.value("windowState")
|
|
if state:
|
|
self.restoreState(state)
|
|
|
|
# Theme
|
|
self.current_theme = self.settings.value("theme", "light")
|
|
|
|
def _apply_initial_theme(self):
|
|
"""Apply initial theme"""
|
|
if MODERN_UI_AVAILABLE and hasattr(self, 'theme_manager'):
|
|
self.theme_manager.set_theme(self.current_theme)
|
|
self.theme_manager.apply_theme(self)
|
|
print(f"✅ Applied {self.current_theme} theme")
|
|
|
|
# Event handlers
|
|
def _on_recording_toggled(self, recording):
|
|
"""Handle recording toggle"""
|
|
if hasattr(self, 'alert_widget'):
|
|
if recording:
|
|
self.alert_widget.add_alert("info", "Recording Started",
|
|
"Video recording has been started for all cameras")
|
|
else:
|
|
self.alert_widget.add_alert("info", "Recording Stopped",
|
|
"Video recording has been stopped")
|
|
|
|
def _on_detection_toggled(self, detecting):
|
|
"""Handle detection toggle"""
|
|
if hasattr(self, 'alert_widget'):
|
|
if detecting:
|
|
self.alert_widget.add_alert("success", "Detection Enabled",
|
|
"Object detection is now active")
|
|
else:
|
|
self.alert_widget.add_alert("warning", "Detection Disabled",
|
|
"Object detection has been disabled")
|
|
|
|
def _on_emergency_activated(self):
|
|
"""Handle emergency activation"""
|
|
if hasattr(self, 'alert_widget'):
|
|
self.alert_widget.add_alert("critical", "EMERGENCY STOP",
|
|
"All systems have been stopped due to emergency activation")
|
|
|
|
# Show emergency message
|
|
QMessageBox.critical(self, "Emergency Stop",
|
|
"Emergency stop has been activated.\nAll monitoring operations have been halted.")
|
|
|
|
def _handle_alert_action(self, alert_id, action):
|
|
"""Handle alert actions"""
|
|
print(f"🚨 Alert action: {action} for alert {alert_id}")
|
|
|
|
if action == "details":
|
|
QMessageBox.information(self, "Alert Details",
|
|
f"Detailed information for alert: {alert_id}")
|
|
|
|
# Menu actions
|
|
def _new_session(self):
|
|
"""Start new monitoring session"""
|
|
print("🆕 Starting new session")
|
|
if hasattr(self, 'alert_widget'):
|
|
self.alert_widget.add_alert("info", "New Session", "New monitoring session started")
|
|
|
|
def _open_configuration(self):
|
|
"""Open configuration file"""
|
|
print("📂 Opening configuration")
|
|
|
|
def _save_configuration(self):
|
|
"""Save current configuration"""
|
|
print("💾 Saving configuration")
|
|
|
|
def _export_data(self):
|
|
"""Export system data"""
|
|
print("📤 Exporting data")
|
|
|
|
def _change_theme(self, theme):
|
|
"""Change application theme"""
|
|
if MODERN_UI_AVAILABLE and hasattr(self, 'theme_manager'):
|
|
self.theme_manager.set_theme(theme)
|
|
self.theme_manager.apply_theme(self)
|
|
self.current_theme = theme
|
|
self.settings.setValue("theme", theme)
|
|
print(f"🎨 Theme changed to {theme}")
|
|
|
|
def _toggle_theme(self):
|
|
"""Toggle between light and dark theme"""
|
|
new_theme = "dark" if self.current_theme == "light" else "light"
|
|
self._change_theme(new_theme)
|
|
|
|
# Update toolbar button
|
|
if new_theme == "dark":
|
|
self.theme_action.setText("☀️ Light")
|
|
self.theme_action.setToolTip("Switch to light theme")
|
|
else:
|
|
self.theme_action.setText("🌙 Dark")
|
|
self.theme_action.setToolTip("Switch to dark theme")
|
|
|
|
def _toggle_fullscreen(self):
|
|
"""Toggle fullscreen mode"""
|
|
if self.isFullScreen():
|
|
self.showNormal()
|
|
else:
|
|
self.showFullScreen()
|
|
|
|
def _show_settings(self):
|
|
"""Show settings dialog"""
|
|
if MODERN_UI_AVAILABLE:
|
|
try:
|
|
settings_dialog = SettingsDialog(self)
|
|
settings_dialog.theme_changed.connect(self._change_theme)
|
|
settings_dialog.exec()
|
|
except Exception as e:
|
|
print(f"⚠️ Error showing settings: {e}")
|
|
QMessageBox.information(self, "Settings", "Settings dialog is not available")
|
|
else:
|
|
QMessageBox.information(self, "Settings", "Settings dialog is not available")
|
|
|
|
def _show_diagnostics(self):
|
|
"""Show system diagnostics"""
|
|
diagnostics_text = f"""
|
|
System Diagnostics:
|
|
|
|
Controllers Available: {CONTROLLERS_AVAILABLE}
|
|
Modern UI Available: {MODERN_UI_AVAILABLE}
|
|
Current Theme: {self.current_theme}
|
|
Active Tabs: {self.main_tabs.count()}
|
|
"""
|
|
|
|
QMessageBox.information(self, "System Diagnostics", diagnostics_text)
|
|
|
|
def _show_about(self):
|
|
"""Show about dialog"""
|
|
about_text = """
|
|
<h3>Smart Intersection Monitoring System</h3>
|
|
<p><b>Advanced UI Version 2.0</b></p>
|
|
<p>AI-powered traffic monitoring and management system</p>
|
|
<p>Built with PySide6 and OpenVINO</p>
|
|
<hr>
|
|
<p>© 2025 Smart Intersection Solutions</p>
|
|
"""
|
|
QMessageBox.about(self, "About", about_text)
|
|
|
|
def _show_documentation(self):
|
|
"""Show documentation"""
|
|
QMessageBox.information(self, "Documentation",
|
|
"Documentation will open in your default browser")
|
|
|
|
# Toolbar actions
|
|
def _start_monitoring(self):
|
|
"""Start monitoring"""
|
|
print("▶️ Starting monitoring")
|
|
if hasattr(self, 'alert_widget'):
|
|
self.alert_widget.add_alert("success", "Monitoring Started",
|
|
"All camera monitoring has been started")
|
|
|
|
def _stop_monitoring(self):
|
|
"""Stop monitoring"""
|
|
print("⏹️ Stopping monitoring")
|
|
if hasattr(self, 'alert_widget'):
|
|
self.alert_widget.add_alert("warning", "Monitoring Stopped",
|
|
"All camera monitoring has been stopped")
|
|
|
|
# System tray
|
|
def _on_tray_activated(self, reason):
|
|
"""Handle tray icon activation"""
|
|
if reason == QSystemTrayIcon.DoubleClick:
|
|
if self.isVisible():
|
|
self.hide()
|
|
else:
|
|
self.show()
|
|
self.raise_()
|
|
self.activateWindow()
|
|
|
|
# Status updates
|
|
def _update_status(self):
|
|
"""Update system status"""
|
|
# Update connection status
|
|
if hasattr(self, 'controllers') and self.controllers:
|
|
self.connection_status.setText("🟢 Connected")
|
|
else:
|
|
self.connection_status.setText("🟡 Demo Mode")
|
|
|
|
def _update_time(self):
|
|
"""Update current time"""
|
|
current_time = QDateTime.currentDateTime().toString("hh:mm:ss")
|
|
self.time_label.setText(f"🕐 {current_time}")
|
|
|
|
# Window events
|
|
def closeEvent(self, event):
|
|
"""Handle window close event"""
|
|
# Save settings
|
|
self.settings.setValue("geometry", self.saveGeometry())
|
|
self.settings.setValue("windowState", self.saveState())
|
|
|
|
# Emit closing signal
|
|
self.window_closing.emit()
|
|
|
|
# Accept close event
|
|
event.accept()
|
|
print("👋 Advanced monitoring system shutting down")
|
|
|
|
def main():
|
|
"""Main application entry point"""
|
|
app = QApplication.instance() or QApplication(sys.argv)
|
|
app.setApplicationName("Smart Intersection Monitoring - Advanced")
|
|
app.setOrganizationName("SmartIntersection")
|
|
|
|
try:
|
|
# Create and show main window
|
|
window = AdvancedMainWindow()
|
|
window.show()
|
|
|
|
print("🚀 Advanced Smart Intersection Monitoring System ready!")
|
|
return app.exec()
|
|
|
|
except Exception as e:
|
|
print(f"❌ Failed to start advanced monitoring system: {e}")
|
|
traceback.print_exc()
|
|
return 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|