Coloring log message and Splitter control

This commit is contained in:
2025-09-26 03:09:18 +09:00
parent 5ea69f7e19
commit cc7d6ad475
7 changed files with 238 additions and 39 deletions

View File

@@ -29,15 +29,25 @@
Foreground="White"
VerticalAlignment="Center"/>
<Button Grid.Column="1"
x:Name="ClearLogButton"
Content="Clear"
Background="Transparent"
Foreground="White"
BorderBrush="White"
BorderThickness="1"
Padding="8,2"
Click="ClearLogButton_Click"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="5">
<Button x:Name="CopyLogButton"
Content="Copy"
Background="LightGreen"
Foreground="DarkGreen"
BorderThickness="0"
Padding="8,2"
CornerRadius="3"
Click="CopyLogButton_Click"/>
<Button x:Name="ClearLogButton"
Content="Clear"
Background="Yellow"
Foreground="DarkBlue"
BorderThickness="0"
Padding="8,2"
CornerRadius="3"
Click="ClearLogButton_Click"/>
</StackPanel>
</Grid>
</Border>
@@ -53,15 +63,16 @@
<DataTemplate>
<Border Margin="2"
Padding="8,4"
Background="White"
BorderBrush="LightGray"
BorderThickness="1"
CornerRadius="3">
CornerRadius="3"
Loaded="LogBorder_Loaded">
<TextBlock Text="{Binding}"
FontFamily="Consolas"
FontSize="12"
TextWrapping="Wrap"
Foreground="Black"/>
Foreground="Black"
x:Name="LogTextBlock"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>

View File

@@ -8,6 +8,7 @@ using namespace winrt;
using namespace winrt::Microsoft::UI::Xaml;
using namespace winrt::Microsoft::UI::Xaml::Controls;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Foundation::Collections;
using namespace std::chrono;
@@ -40,6 +41,69 @@ namespace winrt::Vav2Player::implementation
}
}
void LogMessagePage::CopyLogButton_Click(IInspectable const&, RoutedEventArgs const&)
{
try
{
std::wstring allLogText;
// Collect all log messages from the UI collection
{
std::lock_guard<std::mutex> lock(m_uiUpdateMutex);
for (uint32_t i = 0; i < m_logCollection.Size(); ++i)
{
if (auto logString = m_logCollection.GetAt(i).try_as<winrt::hstring>())
{
allLogText += logString->c_str();
allLogText += L"\r\n"; // Windows line ending for clipboard
}
}
}
if (!allLogText.empty())
{
// Remove the last line ending
if (allLogText.length() >= 2)
{
allLogText = allLogText.substr(0, allLogText.length() - 2);
}
// Copy to clipboard using Windows API
if (OpenClipboard(NULL))
{
EmptyClipboard();
size_t len = (allLogText.length() + 1) * sizeof(wchar_t);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
if (hMem != NULL)
{
wchar_t* pMem = static_cast<wchar_t*>(GlobalLock(hMem));
if (pMem != NULL)
{
wcscpy_s(pMem, allLogText.length() + 1, allLogText.c_str());
GlobalUnlock(hMem);
SetClipboardData(CF_UNICODETEXT, hMem);
}
}
CloseClipboard();
}
// Logs copied to clipboard - no need to log this action
}
else
{
// No log messages to copy - no need to log this
}
}
catch (...)
{
// Failed to copy logs - no need to log this error
}
}
void LogMessagePage::ClearLogButton_Click(IInspectable const&, RoutedEventArgs const&)
{
// Clear logs in LogManager (single source of truth)
@@ -52,8 +116,7 @@ namespace winrt::Vav2Player::implementation
LogCountText().Text(L"0 messages");
} // Release mutex before logging to avoid deadlock
// Log the clear action (called after releasing mutex to prevent deadlock)
::Vav2Player::LogManager::GetInstance().LogInfo(L"Log cleared by user", L"LogMessagePage");
// Log cleared - no need to log this action
}
void LogMessagePage::AutoScrollCheckBox_CheckedChanged(IInspectable const& sender, RoutedEventArgs const&)
@@ -251,4 +314,52 @@ namespace winrt::Vav2Player::implementation
default: return L"UNKNOWN";
}
}
void LogMessagePage::SetLogItemBackground(uint32_t index, LogLevel level)
{
// This approach doesn't work well with ItemsControl template system.
// Instead, we'll modify the approach to use a custom DataTemplate with binding.
// For now, we'll skip the background coloring and implement a simpler solution.
// TODO: Implement background coloring using a different approach
}
void LogMessagePage::LogBorder_Loaded(IInspectable const& sender, RoutedEventArgs const&)
{
try
{
if (auto border = sender.try_as<Microsoft::UI::Xaml::Controls::Border>())
{
// Find the TextBlock child to get the log text
if (auto textBlock = border.Child().try_as<Microsoft::UI::Xaml::Controls::TextBlock>())
{
auto logText = std::wstring(textBlock.Text().c_str());
// Check log level in the text and set background color accordingly
if (logText.find(L"ERROR:") != std::wstring::npos)
{
// Light red background for ERROR logs (#FFE4E1)
border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush(
Microsoft::UI::ColorHelper::FromArgb(255, 255, 228, 225)));
}
else if (logText.find(L"WARN:") != std::wstring::npos)
{
// Light yellow background for WARNING logs (#FFFACD)
border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush(
Microsoft::UI::ColorHelper::FromArgb(255, 255, 250, 205)));
}
else
{
// White background for other log levels
border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush(
Microsoft::UI::Colors::White()));
}
}
}
}
catch (...)
{
// Ignore errors in background color setting
}
}
}

View File

@@ -15,15 +15,27 @@ namespace winrt::Vav2Player::implementation
using LogLevel = ::Vav2Player::LogLevel;
using LogMessage = ::Vav2Player::LogMessage;
// UI wrapper for log messages with visual styling information
struct LogMessageUI
{
std::wstring text;
LogLevel level;
bool isError() const { return level == LogLevel::Error; }
bool isWarning() const { return level == LogLevel::Warning; }
bool isInfo() const { return level == LogLevel::Info || level == LogLevel::Debug; }
};
struct LogMessagePage : LogMessagePageT<LogMessagePage>
{
LogMessagePage();
~LogMessagePage();
// Event handlers
void CopyLogButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e);
void ClearLogButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e);
void AutoScrollCheckBox_CheckedChanged(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e);
void LogLevelFilterComboBox_SelectionChanged(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::Controls::SelectionChangedEventArgs const& e);
void LogBorder_Loaded(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e);
// Observer pattern - LogMessagePage subscribes to LogManager updates
void InitializeLogObserver();
@@ -39,6 +51,7 @@ namespace winrt::Vav2Player::implementation
bool ShouldShowMessage(LogLevel level) const;
std::wstring GetLogLevelString(LogLevel level) const;
std::wstring FormatLogMessageForUI(const ::Vav2Player::LogMessage& message) const;
void SetLogItemBackground(uint32_t index, LogLevel level);
// UI state
LogLevel m_currentFilter = LogLevel::Debug; // Show all by default

View File

@@ -36,16 +36,21 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="300" x:Name="LogPanelColumn"/>
<ColumnDefinition Width="400" x:Name="LogPanelColumn"/>
</Grid.ColumnDefinitions>
<!-- Content Area with Frame for navigation -->
<Frame Grid.Column="0" x:Name="ContentFrame" Background="Black"/>
<!-- Splitter -->
<Border Grid.Column="1" x:Name="SplitterBorder" Width="5" Background="Gray"
<!-- Drag-based Splitter -->
<Border Grid.Column="1" x:Name="SplitterBorder" Width="8" Background="DarkGray"
PointerPressed="Splitter_PointerPressed"
PointerMoved="Splitter_PointerMoved" PointerReleased="Splitter_PointerReleased"/>
PointerMoved="Splitter_PointerMoved"
PointerReleased="Splitter_PointerReleased"
PointerEntered="Splitter_PointerEntered"
PointerExited="Splitter_PointerExited">
<ToolTipService.ToolTip>Drag to resize log panel</ToolTipService.ToolTip>
</Border>
<!-- Log Message Panel -->
<Border Grid.Column="2" x:Name="LogPanelBorder" BorderBrush="Gray" BorderThickness="1,0,0,0">

View File

@@ -4,6 +4,7 @@
#include "MultiVideoPage.xaml.h"
#include "LayeredVideoPage.xaml.h"
#include "src/Logger/LogManager.h"
#include <microsoft.ui.xaml.window.h>
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif
@@ -96,33 +97,46 @@ namespace winrt::Vav2Player::implementation
if (isChecked)
{
// Show log panel
LogPanelColumn().Width(GridLength(300));
// Show log panel with default width
LogPanelColumn().Width(GridLength(400));
LogPanelBorder().Visibility(Visibility::Visible);
SplitterBorder().Visibility(Visibility::Visible);
}
else
{
// Hide log panel
LogPanelColumn().Width(GridLength(0));
LogPanelBorder().Visibility(Visibility::Collapsed);
SplitterBorder().Visibility(Visibility::Collapsed);
}
::Vav2Player::LogManager::GetInstance().LogInfo(isChecked ? L"Log panel shown" : L"Log panel hidden", L"MainWindow");
// 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)
{
m_isDraggingSplitter = true;
// Simplified for now - disable detailed pointer tracking
m_lastPointerX = 0.0;
// 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<double>(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)
@@ -130,8 +144,28 @@ namespace winrt::Vav2Player::implementation
if (!m_isDraggingSplitter)
return;
// Simplified for now - no detailed pointer tracking
// Just maintain current log panel width
// Get current screen mouse position using Windows API
POINT currentScreenPoint;
GetCursorPos(&currentScreenPoint);
double currentMouseX = static_cast<double>(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)
@@ -140,10 +174,35 @@ namespace winrt::Vav2Player::implementation
{
m_isDraggingSplitter = false;
// Release pointer capture
if (auto border = SplitterBorder())
{
border.ReleasePointerCapture(e.Pointer());
border.Background(Microsoft::UI::Xaml::Media::SolidColorBrush(Microsoft::UI::Colors::LightGray()));
}
// 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::Colors::DarkGray()));
}
}

View File

@@ -23,10 +23,12 @@ namespace winrt::Vav2Player::implementation
// Log panel handlers
void ShowLogToggle_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
// Splitter handlers
// Drag-based splitter handlers
void Splitter_PointerPressed(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void Splitter_PointerMoved(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void Splitter_PointerReleased(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void Splitter_PointerEntered(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void Splitter_PointerExited(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& e);
// 성능 최적화된 비디오 렌더링 함수들
static void ConvertYUVToBGRA(const VavCoreVideoFrame& yuv_frame, uint8_t* bgra_buffer, uint32_t width, uint32_t height);
@@ -37,7 +39,8 @@ namespace winrt::Vav2Player::implementation
private:
bool m_isDraggingSplitter = false;
double m_lastPointerX = 0.0;
double m_initialPanelWidth = 0.0;
double m_lastMouseX = 0.0;
winrt::Vav2Player::LogMessagePage m_logPanel{nullptr};
};
}

View File

@@ -4,14 +4,9 @@ amd decoder 를 탑재해야해.
-> nvidia
player UI 개선
* webm 파일을 읽어서 av1 코덱이 아니면, 지원하지 않는 코덱이라고 텍스트 로그를 출력.
UI 화면/버튼, 폰트 크기를 재조정. 메뉴바 크기를 재조정.
android player 를 만들어서 av1 디코딩 테스트 필요.
IAdaptiveVideoDecoder.h 인터페이스가 정말로 필요한 것일까? 재검토를 해봐줘.
@@ -20,5 +15,7 @@ CLAUDE.md 파일을 확인하여 현재 작업 상황을 점검하고 완료된
완료된 사항만 간단하게 적어주고, 불필요한 정보들은 최대한 줄여줘.
● Now I understand. The VavCoreVideoFrame doesn't have a color_space field, and we need to update the MainWindow files
to use VavCoreVideoFrame instead of the old VideoFrame. Let me fix these issues:
player UI 화면/버튼, 폰트 크기를 재조정. 메뉴바 크기를 재조정.
VavCoreVideoFrame 에는 color_space 변수가 없다. 차후에 이것을 사용할 기능이 들어가게 될까?