Files
LanMountainDesktop/LanMontainDesktop/Views/MainWindow.axaml.cs

546 lines
21 KiB
C#
Raw Normal View History

2026-02-27 13:43:27 +08:00
using System;
2026-02-27 19:27:38 +08:00
using System.Collections.Generic;
2026-02-28 03:00:25 +08:00
using System.IO;
using System.Linq;
2026-02-27 19:27:38 +08:00
using System.Runtime.InteropServices;
2026-02-28 03:00:25 +08:00
using System.Threading.Tasks;
2026-02-27 13:43:27 +08:00
using Avalonia;
2026-02-26 23:08:19 +08:00
using Avalonia.Controls;
2026-02-27 13:43:27 +08:00
using Avalonia.Interactivity;
2026-03-01 00:34:07 +08:00
using Avalonia.Layout;
2026-02-27 19:27:38 +08:00
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Styling;
2026-02-27 15:15:09 +08:00
using Avalonia.Threading;
2026-02-28 03:00:25 +08:00
using FluentAvalonia.Styling;
2026-02-28 12:30:16 +08:00
using LanMontainDesktop.ComponentSystem;
using LanMontainDesktop.ComponentSystem.Extensions;
2026-02-27 19:27:38 +08:00
using LanMontainDesktop.Models;
using LanMontainDesktop.Services;
using LanMontainDesktop.Theme;
2026-02-28 03:00:25 +08:00
using LibVLCSharp.Shared;
2026-02-26 23:08:19 +08:00
namespace LanMontainDesktop.Views;
public partial class MainWindow : Window
{
2026-02-27 19:27:38 +08:00
private enum WallpaperPlacement
{
Fill,
Fit,
Stretch,
Center,
Tile
}
2026-02-28 03:00:25 +08:00
private enum WallpaperMediaType
{
None,
Image,
Video
}
2026-02-27 19:27:38 +08:00
private const int StatusBarRowIndex = 0;
2026-02-27 13:43:27 +08:00
private const int MinShortSideCells = 6;
private const int MaxShortSideCells = 96;
2026-02-27 19:27:38 +08:00
private const int SettingsTransitionDurationMs = 240;
2026-02-28 04:23:28 +08:00
private const double WallpaperPreviewMaxWidth = 520;
2026-02-27 19:27:38 +08:00
private const double LightBackgroundLuminanceThreshold = 0.57;
2026-02-28 03:00:25 +08:00
private const string TaskbarLayoutBottomFullRowMacStyle = "BottomFullRowMacStyle";
private static readonly HashSet<string> SupportedImageExtensions = new(StringComparer.OrdinalIgnoreCase)
{
".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp"
};
private static readonly HashSet<string> SupportedVideoExtensions = new(StringComparer.OrdinalIgnoreCase)
{
".mp4", ".mkv", ".webm", ".avi", ".mov", ".m4v"
};
private static readonly TaskbarActionId[] DefaultPinnedTaskbarActions =
[
TaskbarActionId.MinimizeToWindows,
TaskbarActionId.OpenSettings
];
2026-02-27 19:27:38 +08:00
private readonly record struct GridMetrics(int ColumnCount, int RowCount, double CellSize);
private readonly MonetColorService _monetColorService = new();
2026-02-28 03:00:25 +08:00
private readonly AppSettingsService _appSettingsService = new();
2026-02-28 04:23:28 +08:00
private readonly LocalizationService _localizationService = new();
2026-02-28 12:30:16 +08:00
private readonly ComponentRegistry _componentRegistry = ComponentRegistry
.CreateDefault()
.RegisterExtensions(
JsonComponentExtensionProvider.LoadProvidersFromDirectory(
Path.Combine(AppContext.BaseDirectory, "Extensions", "Components")));
2026-02-28 03:00:25 +08:00
private readonly FluentAvaloniaTheme? _fluentAvaloniaTheme;
private readonly HashSet<string> _topStatusComponentIds = new(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<TaskbarActionId> _pinnedTaskbarActions = [];
2026-02-27 13:43:27 +08:00
private int _targetShortSideCells;
2026-02-27 19:27:38 +08:00
private bool _isSettingsOpen;
private bool _isNightMode;
2026-02-28 03:00:25 +08:00
private bool _enableDynamicTaskbarActions;
2026-02-27 19:27:38 +08:00
private bool _suppressThemeToggleEvents;
2026-02-28 03:00:25 +08:00
private bool _suppressStatusBarToggleEvents;
2026-02-28 04:23:28 +08:00
private bool _suppressLanguageSelectionEvents;
2026-02-28 03:00:25 +08:00
private bool _suppressSettingsPersistence;
2026-02-28 04:23:28 +08:00
private bool _isUpdatingWallpaperPreviewLayout;
2026-02-28 04:51:00 +08:00
private bool _isComponentLibraryOpen;
private bool _reopenSettingsAfterComponentLibraryClose;
2026-02-27 19:27:38 +08:00
private TranslateTransform? _settingsContentPanelTransform;
private IBrush? _defaultDesktopBackground;
private Bitmap? _wallpaperBitmap;
2026-02-28 03:00:25 +08:00
private WallpaperMediaType _wallpaperMediaType;
private string? _wallpaperVideoPath;
private LibVLC? _libVlc;
private MediaPlayer? _videoWallpaperPlayer;
private Media? _videoWallpaperMedia;
private MediaPlayer? _previewVideoWallpaperPlayer;
private Media? _previewVideoWallpaperMedia;
2026-02-27 19:27:38 +08:00
private string? _wallpaperPath;
private string _wallpaperStatus = "Current background uses solid color.";
private IReadOnlyList<Color> _recommendedColors = Array.Empty<Color>();
private IReadOnlyList<Color> _monetColors = Array.Empty<Color>();
private Color _selectedThemeColor = Color.Parse("#FF3B82F6");
2026-02-28 04:23:28 +08:00
private double _currentDesktopCellSize;
2026-02-28 03:00:25 +08:00
private string _taskbarLayoutMode = TaskbarLayoutBottomFullRowMacStyle;
2026-02-28 04:23:28 +08:00
private string _languageCode = "zh-CN";
2026-02-27 13:43:27 +08:00
2026-02-26 23:08:19 +08:00
public MainWindow()
{
InitializeComponent();
2026-02-28 03:00:25 +08:00
_fluentAvaloniaTheme = Application.Current?.Styles.OfType<FluentAvaloniaTheme>().FirstOrDefault();
2026-02-27 15:15:09 +08:00
PropertyChanged += OnWindowPropertyChanged;
2026-02-26 23:08:19 +08:00
}
2026-02-27 13:43:27 +08:00
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
2026-02-28 03:00:25 +08:00
_suppressSettingsPersistence = true;
var snapshot = _appSettingsService.Load();
_targetShortSideCells = Math.Clamp(
snapshot.GridShortSideCells > 0 ? snapshot.GridShortSideCells : CalculateDefaultShortSideCellCountFromDpi(),
MinShortSideCells,
MaxShortSideCells);
2026-02-27 13:43:27 +08:00
GridSizeNumberBox.Value = _targetShortSideCells;
2026-02-28 03:00:25 +08:00
2026-02-28 04:23:28 +08:00
SettingsNavListBox.SelectedIndex = Math.Clamp(snapshot.SettingsTabIndex, 0, 4);
2026-02-27 19:27:38 +08:00
UpdateSettingsTabContent();
2026-02-28 03:00:25 +08:00
WallpaperPlacementComboBox.SelectedIndex = GetPlacementIndexFromSetting(snapshot.WallpaperPlacement);
_defaultDesktopBackground = DesktopWallpaperLayer.Background;
ApplyTaskbarSettings(snapshot);
2026-02-28 04:23:28 +08:00
InitializeLocalization(snapshot.LanguageCode);
2026-03-01 00:34:07 +08:00
InitializeDesktopSurfaceState(snapshot);
InitializeSettingsIcons();
2026-02-28 03:00:25 +08:00
TryRestoreWallpaper(snapshot.WallpaperPath);
ApplyWallpaperBrush();
2026-02-27 19:27:38 +08:00
UpdateWallpaperDisplay();
2026-02-28 03:00:25 +08:00
if (TryParseColor(snapshot.ThemeColor, out var savedThemeColor))
{
_selectedThemeColor = savedThemeColor;
}
_isNightMode = snapshot.IsNightMode ?? (CalculateCurrentBackgroundLuminance() < LightBackgroundLuminanceThreshold);
ApplyNightModeState(_isNightMode, refreshPalettes: true);
_suppressStatusBarToggleEvents = true;
2026-02-28 12:30:16 +08:00
StatusBarClockToggleSwitch.IsChecked = _topStatusComponentIds.Contains(BuiltInComponentIds.Clock);
2026-02-28 03:00:25 +08:00
_suppressStatusBarToggleEvents = false;
2026-02-28 04:23:28 +08:00
ApplyLocalization();
ThemeColorStatusTextBlock.Text = Lf("settings.color.theme_ready_format", "Theme color ready: {0}.", _selectedThemeColor);
2026-02-27 19:27:38 +08:00
_settingsContentPanelTransform = SettingsContentPanel.RenderTransform as TranslateTransform;
2026-02-27 13:43:27 +08:00
DesktopHost.SizeChanged += OnDesktopHostSizeChanged;
2026-02-27 19:27:38 +08:00
WallpaperPreviewHost.SizeChanged += OnWallpaperPreviewHostSizeChanged;
2026-02-27 13:43:27 +08:00
RebuildDesktopGrid();
2026-03-01 00:34:07 +08:00
PopulateComponentLibraryItems();
LoadLauncherEntriesAsync();
2026-02-28 03:00:25 +08:00
_suppressSettingsPersistence = false;
PersistSettings();
2026-02-27 13:43:27 +08:00
}
protected override void OnClosed(EventArgs e)
{
2026-02-28 03:00:25 +08:00
PersistSettings();
StopVideoWallpaper();
_previewVideoWallpaperMedia?.Dispose();
_previewVideoWallpaperMedia = null;
_previewVideoWallpaperPlayer?.Dispose();
_previewVideoWallpaperPlayer = null;
2026-03-01 00:34:07 +08:00
DisposeLauncherResources();
2026-02-28 03:00:25 +08:00
_videoWallpaperMedia?.Dispose();
_videoWallpaperMedia = null;
_videoWallpaperPlayer?.Dispose();
_videoWallpaperPlayer = null;
_libVlc?.Dispose();
_libVlc = null;
2026-02-27 19:27:38 +08:00
_wallpaperBitmap?.Dispose();
_wallpaperBitmap = null;
2026-02-27 15:15:09 +08:00
PropertyChanged -= OnWindowPropertyChanged;
2026-02-27 13:43:27 +08:00
DesktopHost.SizeChanged -= OnDesktopHostSizeChanged;
2026-02-27 19:27:38 +08:00
WallpaperPreviewHost.SizeChanged -= OnWallpaperPreviewHostSizeChanged;
2026-02-27 13:43:27 +08:00
base.OnClosed(e);
}
private int CalculateDefaultShortSideCellCountFromDpi()
{
var dpi = 96d * RenderScaling;
var count = (int)Math.Round(dpi / 8d);
return Math.Clamp(count, MinShortSideCells, MaxShortSideCells);
}
private void OnDesktopHostSizeChanged(object? sender, SizeChangedEventArgs e)
{
RebuildDesktopGrid();
2026-02-28 03:00:25 +08:00
PersistSettings();
2026-02-27 13:43:27 +08:00
}
2026-02-27 19:27:38 +08:00
private void OnWallpaperPreviewHostSizeChanged(object? sender, SizeChangedEventArgs e)
{
UpdateWallpaperPreviewLayout();
}
2026-02-27 13:43:27 +08:00
private void OnApplyGridSizeClick(object? sender, RoutedEventArgs e)
{
var requested = (int)Math.Round(GridSizeNumberBox.Value);
if (requested <= 0)
{
requested = _targetShortSideCells;
}
_targetShortSideCells = Math.Clamp(requested, MinShortSideCells, MaxShortSideCells);
if (Math.Abs(GridSizeNumberBox.Value - _targetShortSideCells) > double.Epsilon)
{
GridSizeNumberBox.Value = _targetShortSideCells;
}
RebuildDesktopGrid();
}
private void RebuildDesktopGrid()
{
2026-02-27 19:27:38 +08:00
var gridMetrics = CalculateGridMetrics(
DesktopHost.Bounds.Width,
DesktopHost.Bounds.Height,
_targetShortSideCells);
if (gridMetrics.CellSize <= 0)
2026-02-27 13:43:27 +08:00
{
return;
}
2026-02-28 04:23:28 +08:00
_currentDesktopCellSize = gridMetrics.CellSize;
2026-02-27 13:43:27 +08:00
2026-02-27 19:27:38 +08:00
DesktopGrid.RowDefinitions.Clear();
DesktopGrid.ColumnDefinitions.Clear();
DesktopGrid.Width = gridMetrics.ColumnCount * gridMetrics.CellSize;
DesktopGrid.Height = gridMetrics.RowCount * gridMetrics.CellSize;
2026-02-27 13:43:27 +08:00
2026-02-27 19:27:38 +08:00
for (var row = 0; row < gridMetrics.RowCount; row++)
{
DesktopGrid.RowDefinitions.Add(new RowDefinition(new GridLength(gridMetrics.CellSize, GridUnitType.Pixel)));
}
for (var col = 0; col < gridMetrics.ColumnCount; col++)
2026-02-27 13:43:27 +08:00
{
2026-02-27 19:27:38 +08:00
DesktopGrid.ColumnDefinitions.Add(new ColumnDefinition(new GridLength(gridMetrics.CellSize, GridUnitType.Pixel)));
}
2026-02-28 03:00:25 +08:00
PlaceStatusBarComponent(
TopStatusBarHost,
column: 0,
requestedColumnSpan: gridMetrics.ColumnCount,
totalColumns: gridMetrics.ColumnCount);
2026-02-27 13:43:27 +08:00
2026-02-28 03:00:25 +08:00
var taskbarRow = gridMetrics.RowCount - 1;
Grid.SetRow(BottomTaskbarContainer, taskbarRow);
Grid.SetColumn(BottomTaskbarContainer, 0);
Grid.SetRowSpan(BottomTaskbarContainer, 1);
Grid.SetColumnSpan(BottomTaskbarContainer, gridMetrics.ColumnCount);
2026-02-27 19:27:38 +08:00
2026-02-28 03:00:25 +08:00
ApplyTopStatusComponentVisibility();
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
2026-02-27 13:43:27 +08:00
2026-02-27 19:27:38 +08:00
ApplyWidgetSizing(gridMetrics.CellSize);
2026-03-01 00:34:07 +08:00
UpdateDesktopSurfaceLayout(gridMetrics);
2026-02-28 04:23:28 +08:00
UpdateSettingsViewportInsets(gridMetrics.CellSize);
2026-02-27 19:27:38 +08:00
2026-02-28 04:23:28 +08:00
GridInfoTextBlock.Text = Lf(
"settings.grid.info_format",
"Grid: {0} cols x {1} rows | cell {2:F1}px (1:1)",
gridMetrics.ColumnCount,
gridMetrics.RowCount,
gridMetrics.CellSize);
2026-02-27 19:27:38 +08:00
UpdateWallpaperPreviewLayout();
}
private static GridMetrics CalculateGridMetrics(double hostWidth, double hostHeight, int targetShortSideCells)
{
if (hostWidth <= 1 || hostHeight <= 1)
2026-02-27 13:43:27 +08:00
{
2026-02-27 19:27:38 +08:00
return default;
2026-02-27 13:43:27 +08:00
}
2026-02-27 19:27:38 +08:00
var shortSideCells = Math.Max(1, targetShortSideCells);
if (hostWidth >= hostHeight)
2026-02-27 13:43:27 +08:00
{
2026-02-27 19:27:38 +08:00
var rowCount = shortSideCells;
var cellSize = hostHeight / rowCount;
var columnCount = Math.Max(1, (int)Math.Floor(hostWidth / cellSize));
return new GridMetrics(columnCount, rowCount, cellSize);
2026-02-27 13:43:27 +08:00
}
2026-02-27 19:27:38 +08:00
var columns = shortSideCells;
var size = hostWidth / columns;
var rows = Math.Max(1, (int)Math.Floor(hostHeight / size));
return new GridMetrics(columns, rows, size);
}
2026-02-27 13:43:27 +08:00
2026-02-27 19:27:38 +08:00
private static int ClampComponentSpan(int requestedSpan, int axisCellCount)
{
return Math.Clamp(requestedSpan, 1, Math.Max(1, axisCellCount));
}
2026-02-27 13:43:27 +08:00
2026-02-27 19:27:38 +08:00
private static int ClampGridIndex(int requestedIndex, int axisCellCount)
{
return Math.Clamp(requestedIndex, 0, Math.Max(0, axisCellCount - 1));
}
2026-02-27 15:15:09 +08:00
2026-02-27 19:27:38 +08:00
private static void PlaceStatusBarComponent(
Control component,
int column,
int requestedColumnSpan,
int totalColumns)
{
var clampedColumn = ClampGridIndex(column, totalColumns);
var availableColumns = Math.Max(1, totalColumns - clampedColumn);
Grid.SetRow(component, StatusBarRowIndex);
Grid.SetColumn(component, clampedColumn);
Grid.SetRowSpan(component, 1);
Grid.SetColumnSpan(component, ClampComponentSpan(requestedColumnSpan, availableColumns));
2026-02-27 13:43:27 +08:00
}
2026-02-27 15:15:09 +08:00
private void ApplyWidgetSizing(double cellSize)
{
var margin = Math.Clamp(cellSize * 0.08, 1.5, 10);
var verticalPadding = Math.Clamp(cellSize * 0.08, 2, 12);
var horizontalPadding = Math.Clamp(cellSize * 0.20, 4, 22);
2026-02-28 03:00:25 +08:00
var taskbarCell = Math.Clamp(cellSize, 28, 128);
2026-02-27 15:15:09 +08:00
2026-02-28 03:00:25 +08:00
TopStatusBarHost.Padding = new Thickness(Math.Clamp(cellSize * 0.08, 1.5, 10));
2026-02-27 15:15:09 +08:00
ClockWidget.Margin = new Thickness(margin);
ClockWidget.ApplyCellSize(cellSize);
2026-02-28 03:00:25 +08:00
BottomTaskbarContainer.Margin = new Thickness(Math.Clamp(cellSize * 0.18, 6, 18));
BottomTaskbarContainer.CornerRadius = new CornerRadius(Math.Clamp(cellSize * 0.24, 10, 24));
BottomTaskbarContainer.Padding = new Thickness(Math.Clamp(cellSize * 0.08, 2, 10));
2026-02-28 04:23:28 +08:00
BackToWindowsButton.Margin = new Thickness(0);
2026-02-27 15:15:09 +08:00
BackToWindowsButton.Padding = new Thickness(horizontalPadding, verticalPadding);
2026-02-28 03:00:25 +08:00
BackToWindowsButton.FontSize = Math.Clamp(cellSize * 0.22, 8, 22);
BackToWindowsButton.MinHeight = taskbarCell;
BackToWindowsButton.MinWidth = Math.Clamp(cellSize * 2.3, 90, 320);
2026-02-28 04:51:00 +08:00
OpenComponentLibraryButton.Margin = new Thickness(0);
OpenComponentLibraryButton.Padding = new Thickness(horizontalPadding, verticalPadding);
OpenComponentLibraryButton.FontSize = Math.Clamp(cellSize * 0.22, 8, 22);
OpenComponentLibraryButton.MinHeight = taskbarCell;
OpenComponentLibraryButton.MinWidth = Math.Clamp(cellSize * 2.0, 88, 300);
2026-02-27 19:27:38 +08:00
2026-02-28 04:23:28 +08:00
OpenSettingsButton.Margin = new Thickness(0);
2026-02-28 03:00:25 +08:00
OpenSettingsButton.Height = taskbarCell;
2026-02-28 04:23:28 +08:00
OpenSettingsButton.MinHeight = taskbarCell;
if (_isSettingsOpen)
{
OpenSettingsButton.Width = double.NaN;
OpenSettingsButton.MinWidth = Math.Clamp(cellSize * 2.3, 120, 340);
OpenSettingsButton.Padding = new Thickness(horizontalPadding, verticalPadding);
}
else
{
OpenSettingsButton.Width = taskbarCell;
OpenSettingsButton.MinWidth = taskbarCell;
OpenSettingsButton.Padding = new Thickness(Math.Clamp(taskbarCell * 0.2, 4, 12));
}
2026-02-28 04:51:00 +08:00
UpdateComponentLibraryLayout(cellSize);
}
private void UpdateComponentLibraryLayout(double cellSize)
{
if (ComponentLibraryWindow is null)
{
return;
}
var horizontalMargin = Math.Clamp(cellSize * 0.7, 18, 44);
var bottomMargin = Math.Clamp(cellSize * 1.4, 56, 190);
ComponentLibraryWindow.Margin = new Thickness(horizontalMargin, 20, horizontalMargin, bottomMargin);
ComponentLibraryWindow.CornerRadius = new CornerRadius(Math.Clamp(cellSize * 0.24, 12, 24));
ComponentLibraryWindow.Height = Math.Clamp(cellSize * 4.8, 220, 360);
ComponentLibraryWindow.Width = Math.Clamp(cellSize * 9.2, 360, 760);
2026-02-28 04:23:28 +08:00
}
private void UpdateSettingsViewportInsets(double cellSize)
{
2026-03-01 00:34:07 +08:00
if (SettingsContentPanel is null)
2026-02-28 04:23:28 +08:00
{
return;
}
var clampedCell = Math.Max(1, cellSize);
var horizontalInset = Math.Clamp(clampedCell * 0.45, 12, 64);
var verticalGap = Math.Clamp(clampedCell * 0.16, 6, 18);
var topInset = clampedCell + verticalGap;
var bottomInset = clampedCell + verticalGap;
2026-03-01 00:34:07 +08:00
// 添加额外的安全边距以确保圆角不被裁剪
var cornerSafetyMargin = Math.Clamp(clampedCell * 0.12, 4, 12);
var inset = new Thickness(
horizontalInset + cornerSafetyMargin,
topInset + cornerSafetyMargin,
horizontalInset + cornerSafetyMargin,
bottomInset + cornerSafetyMargin);
// 使用 Margin 来定位,而不是直接设置 Width/Height
// 这样可以让面板自然填充可用空间,同时保持边距
SettingsContentPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
SettingsContentPanel.VerticalAlignment = VerticalAlignment.Stretch;
2026-02-28 04:23:28 +08:00
SettingsContentPanel.Margin = inset;
2026-03-01 00:34:07 +08:00
SettingsContentPanel.Width = double.NaN;
SettingsContentPanel.Height = double.NaN;
2026-02-27 19:27:38 +08:00
}
private void UpdateWallpaperPreviewLayout()
{
if (WallpaperPreviewFrame is null ||
WallpaperPreviewHost is null ||
2026-03-01 00:34:07 +08:00
WallpaperPreviewViewport is null ||
2026-02-27 19:27:38 +08:00
WallpaperPreviewGrid is null)
{
return;
}
2026-02-28 04:23:28 +08:00
if (_isUpdatingWallpaperPreviewLayout)
{
return;
}
_isUpdatingWallpaperPreviewLayout = true;
try
{
2026-03-01 00:34:07 +08:00
var desktopWidth = Math.Max(1, DesktopHost.Bounds.Width);
var desktopHeight = Math.Max(1, DesktopHost.Bounds.Height);
var aspectRatio = desktopWidth / desktopHeight;
// Use the host width (which is roughly 50% of the settings area)
// Subtract padding for the outer host container if needed, but let it stretch
var availableWidth = Math.Max(100, WallpaperPreviewHost.Bounds.Width);
// Calculate height based on aspect ratio
var previewWidth = availableWidth;
var previewHeight = previewWidth / aspectRatio;
// Apply sizes to the monitor frame
2026-02-28 04:23:28 +08:00
WallpaperPreviewFrame.Width = previewWidth;
WallpaperPreviewFrame.Height = previewHeight;
2026-02-27 19:27:38 +08:00
2026-03-01 00:34:07 +08:00
WallpaperPreviewClockTextBlock.Text = DateTime.Now.ToString("HH:mm");
var gridMetrics = CalculateGridMetrics(previewWidth, previewHeight, _targetShortSideCells);
if (gridMetrics.CellSize <= 0)
{
return;
}
WallpaperPreviewGrid.Width = gridMetrics.ColumnCount * gridMetrics.CellSize;
WallpaperPreviewGrid.Height = gridMetrics.RowCount * gridMetrics.CellSize;
// This can be triggered by layout changes; always rebuild the preview grid definitions
// to avoid definitions accumulating and shifting overlay components out of place.
WallpaperPreviewGrid.RowDefinitions.Clear();
WallpaperPreviewGrid.ColumnDefinitions.Clear();
for (var row = 0; row < gridMetrics.RowCount; row++)
{
WallpaperPreviewGrid.RowDefinitions.Add(
new RowDefinition(new GridLength(gridMetrics.CellSize, GridUnitType.Pixel)));
}
for (var col = 0; col < gridMetrics.ColumnCount; col++)
{
WallpaperPreviewGrid.ColumnDefinitions.Add(
new ColumnDefinition(new GridLength(gridMetrics.CellSize, GridUnitType.Pixel)));
}
PlaceStatusBarComponent(
WallpaperPreviewTopStatusBarHost,
column: 0,
requestedColumnSpan: gridMetrics.ColumnCount,
totalColumns: gridMetrics.ColumnCount);
var taskbarRow = gridMetrics.RowCount - 1;
Grid.SetRow(WallpaperPreviewBottomTaskbarContainer, taskbarRow);
Grid.SetColumn(WallpaperPreviewBottomTaskbarContainer, 0);
Grid.SetRowSpan(WallpaperPreviewBottomTaskbarContainer, 1);
Grid.SetColumnSpan(WallpaperPreviewBottomTaskbarContainer, gridMetrics.ColumnCount);
ApplyTopStatusComponentVisibility();
ApplyTaskbarActionVisibility(GetCurrentTaskbarContext());
ApplyPreviewWidgetSizing(gridMetrics.CellSize);
2026-02-28 04:23:28 +08:00
}
finally
{
_isUpdatingWallpaperPreviewLayout = false;
}
2026-02-27 19:27:38 +08:00
}
private void ApplyPreviewWidgetSizing(double cellSize)
{
var margin = Math.Clamp(cellSize * 0.08, 1, 6);
2026-02-28 03:00:25 +08:00
var previewTaskbarCell = Math.Clamp(cellSize, 10, 36);
WallpaperPreviewTopStatusBarHost.Padding = new Thickness(Math.Clamp(cellSize * 0.08, 1, 4));
WallpaperPreviewBottomTaskbarContainer.Margin = new Thickness(margin);
WallpaperPreviewBottomTaskbarContainer.CornerRadius = new CornerRadius(Math.Clamp(cellSize * 0.22, 4, 10));
WallpaperPreviewBottomTaskbarContainer.Padding = new Thickness(Math.Clamp(cellSize * 0.06, 1, 4));
2026-02-27 19:27:38 +08:00
WallpaperPreviewClockTextBlock.FontSize = Math.Clamp(cellSize * 0.30, 6, 18);
WallpaperPreviewBackButtonTextBlock.FontSize = Math.Clamp(cellSize * 0.19, 5, 13);
2026-02-28 04:51:00 +08:00
WallpaperPreviewComponentLibraryTextBlock.FontSize = Math.Clamp(cellSize * 0.18, 5, 12);
2026-02-28 04:23:28 +08:00
WallpaperPreviewBackButtonVisual.MinHeight = previewTaskbarCell;
WallpaperPreviewBackButtonVisual.MinWidth = Math.Clamp(cellSize * 2.1, 30, 120);
2026-02-28 04:51:00 +08:00
WallpaperPreviewComponentLibraryVisual.MinHeight = previewTaskbarCell;
WallpaperPreviewComponentLibraryVisual.MinWidth = Math.Clamp(cellSize * 2.0, 28, 110);
2026-02-28 03:00:25 +08:00
WallpaperPreviewSettingsButtonIcon.Width = Math.Clamp(previewTaskbarCell * 0.42, 6, 14);
WallpaperPreviewSettingsButtonIcon.Height = Math.Clamp(previewTaskbarCell * 0.42, 6, 14);
2026-02-27 15:15:09 +08:00
}
2026-02-27 13:43:27 +08:00
private void OnMinimizeClick(object? sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
2026-02-27 15:15:09 +08:00
private void OnWindowPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property != WindowStateProperty)
{
return;
}
if (WindowState is WindowState.Minimized or WindowState.FullScreen)
{
return;
}
Dispatcher.UIThread.Post(() =>
{
if (WindowState is not (WindowState.Minimized or WindowState.FullScreen))
{
WindowState = WindowState.FullScreen;
}
});
}
2026-02-27 13:43:27 +08:00
}