#include "pch.h" #include "MainWindow.xaml.h" #include "MainVideoPage.xaml.h" #include "MultiVideoPage.xaml.h" #include "LayeredVideoPage.xaml.h" #include "SettingsPage.xaml.h" #include "src/Logger/LogManager.h" #include #include #pragma comment(lib, "dwmapi.lib") #if __has_include("MainWindow.g.cpp") #include "MainWindow.g.cpp" #endif using namespace winrt; using namespace winrt::Microsoft::UI::Xaml; using namespace winrt::Microsoft::UI::Xaml::Controls; using namespace winrt::Windows::UI::Xaml::Interop; namespace winrt::Vav2Player::implementation { MainWindow::MainWindow() { InitializeComponent(); // Apply dark mode to title bar using DWM API try { auto windowNative = this->try_as<::IWindowNative>(); if (windowNative) { HWND hWnd = nullptr; windowNative->get_WindowHandle(&hWnd); if (hWnd) { BOOL isDarkMode = TRUE; ::DwmSetWindowAttribute( hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &isDarkMode, sizeof(isDarkMode) ); } } } catch (...) { // Ignore title bar dark mode errors - non-critical } // Initialize LogManager with default outputs (Console + Debug) FIRST ::Vav2Player::LogManager::GetInstance().InitializeDefaultOutputs(); ::Vav2Player::LogManager::GetInstance().SetLogLevel(::Vav2Player::LogLevel::Info); // Initialize log panel after LogManager is ready m_logPanel = LogPanel(); // Set LogMessagePage as global instance for backward compatibility // This enables Observer pattern - LogMessagePage will automatically receive updates from LogManager auto logPageImpl = winrt::get_self(m_logPanel); winrt::Vav2Player::implementation::LogMessagePage::SetInstance(std::shared_ptr(logPageImpl, [](auto*) {})); // Initially show log panel ShowLogToggle().IsChecked(true); // Load Multi Video as default page (start screen) TypeName pageTypeName; pageTypeName.Name = winrt::name_of(); pageTypeName.Kind = TypeKind::Metadata; ContentFrame().Navigate(pageTypeName); // Add welcome message to log - this will now be received by LogMessagePage via Observer pattern ::Vav2Player::LogManager::GetInstance().LogInfo(L"Vav2Player started successfully", L"MainWindow"); } // Navigation event handlers void MainWindow::SwitchToMainView_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { TypeName pageTypeName; pageTypeName.Name = winrt::name_of(); pageTypeName.Kind = TypeKind::Metadata; ContentFrame().Navigate(pageTypeName); } void MainWindow::SwitchToMultiVideoView_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { TypeName pageTypeName; pageTypeName.Name = winrt::name_of(); pageTypeName.Kind = TypeKind::Metadata; ContentFrame().Navigate(pageTypeName); } void MainWindow::SwitchToLayeredVideoView_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { TypeName pageTypeName; pageTypeName.Name = winrt::name_of(); pageTypeName.Kind = TypeKind::Metadata; ContentFrame().Navigate(pageTypeName); } void MainWindow::Exit_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { this->Close(); } void MainWindow::Settings_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { TypeName pageTypeName; pageTypeName.Name = winrt::name_of(); pageTypeName.Kind = TypeKind::Metadata; ContentFrame().Navigate(pageTypeName); } void MainWindow::About_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { // Could implement About dialog // For now, just log the request ::Vav2Player::LogManager::GetInstance().LogInfo(L"About dialog requested", L"MainWindow"); } void MainWindow::ShowLogToggle_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&) { if (auto toggleButton = sender.try_as()) { bool isChecked = toggleButton.IsChecked().GetBoolean(); if (isChecked) { // Show log panel with default width LogPanelColumn().Width(GridLength(400)); LogPanelBorder().Visibility(Visibility::Visible); } else { // Hide log panel LogPanelColumn().Width(GridLength(0)); LogPanelBorder().Visibility(Visibility::Collapsed); } // Log panel visibility toggled - no need to log this } } // Drag-based splitter implementation void MainWindow::Splitter_PointerPressed(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e) { // Capture pointer first to ensure we receive subsequent events if (auto border = SplitterBorder()) { border.CapturePointer(e.Pointer()); border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush(Microsoft::UI::Colors::CornflowerBlue())); } // Set drag state after capturing pointer m_isDraggingSplitter = true; // Store initial panel width m_initialPanelWidth = LogPanelColumn().Width().Value; // Store initial screen mouse position using Windows API POINT screenPoint; GetCursorPos(&screenPoint); m_lastMouseX = static_cast(screenPoint.x); // Mark event as handled to prevent bubbling e.Handled(true); // Splitter drag started - no need to log drag events } void MainWindow::Splitter_PointerMoved(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e) { if (!m_isDraggingSplitter) return; // Get current screen mouse position using Windows API POINT currentScreenPoint; GetCursorPos(¤tScreenPoint); double currentMouseX = static_cast(currentScreenPoint.x); // Calculate relative mouse movement delta double deltaX = currentMouseX - m_lastMouseX; m_lastMouseX = currentMouseX; // Get current panel width and apply delta auto currentWidth = LogPanelColumn().Width().Value; double newWidth = currentWidth + deltaX; // Set only minimum limit (no maximum limit) const double MIN_WIDTH = 200.0; newWidth = std::max(MIN_WIDTH, newWidth); // Update panel width immediately for natural dragging LogPanelColumn().Width(GridLength(newWidth)); // Mark event as handled e.Handled(true); } void MainWindow::Splitter_PointerReleased(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e) { if (m_isDraggingSplitter) { m_isDraggingSplitter = false; // Release pointer capture if (auto border = SplitterBorder()) { border.ReleasePointerCapture(e.Pointer()); border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush( Microsoft::UI::ColorHelper::FromArgb(255, 102, 102, 102))); // Dark gray for splitter } // Splitter drag completed - no need to log resize events // Mark event as handled e.Handled(true); } } void MainWindow::Splitter_PointerEntered(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const&) { // Highlight on hover if (auto border = SplitterBorder()) { border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush(Microsoft::UI::Colors::LightGray())); } } void MainWindow::Splitter_PointerExited(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const&) { // Reset to default color if (auto border = SplitterBorder()) { border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush( Microsoft::UI::ColorHelper::FromArgb(255, 80, 80, 80))); // Darker gray for default splitter } } // Helper methods moved to MainVideoPage void MainWindow::ConvertYUVToBGRA(const VavCoreVideoFrame& yuv_frame, uint8_t* bgra_buffer, uint32_t width, uint32_t height) { // Implementation moved to MainVideoPage } void MainWindow::RenderFrameToScreen(const VavCoreVideoFrame& frame, winrt::Microsoft::UI::Xaml::Media::Imaging::WriteableBitmap& bitmap, std::vector& bgra_buffer) { // Implementation moved to MainVideoPage } }