diff --git a/LanMontainDesktop/App.axaml b/LanMontainDesktop/App.axaml
index fccc171..d416fcd 100644
--- a/LanMontainDesktop/App.axaml
+++ b/LanMontainDesktop/App.axaml
@@ -1,5 +1,6 @@
@@ -10,6 +11,6 @@
-
+
-
\ No newline at end of file
+
diff --git a/LanMontainDesktop/LanMontainDesktop.csproj b/LanMontainDesktop/LanMontainDesktop.csproj
index 8106412..979e699 100644
--- a/LanMontainDesktop/LanMontainDesktop.csproj
+++ b/LanMontainDesktop/LanMontainDesktop.csproj
@@ -24,5 +24,6 @@
All
+
diff --git a/LanMontainDesktop/ViewModels/MainWindowViewModel.cs b/LanMontainDesktop/ViewModels/MainWindowViewModel.cs
index 631ef00..0a6f98d 100644
--- a/LanMontainDesktop/ViewModels/MainWindowViewModel.cs
+++ b/LanMontainDesktop/ViewModels/MainWindowViewModel.cs
@@ -2,5 +2,5 @@
public partial class MainWindowViewModel : ViewModelBase
{
- public string Greeting { get; } = "Welcome to Avalonia!";
+ public string Greeting { get; } = "A modern desktop shell powered by FluentAvalonia.";
}
diff --git a/LanMontainDesktop/Views/Components/ClockWidget.axaml b/LanMontainDesktop/Views/Components/ClockWidget.axaml
new file mode 100644
index 0000000..3da6dac
--- /dev/null
+++ b/LanMontainDesktop/Views/Components/ClockWidget.axaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/LanMontainDesktop/Views/Components/ClockWidget.axaml.cs b/LanMontainDesktop/Views/Components/ClockWidget.axaml.cs
new file mode 100644
index 0000000..1f8c555
--- /dev/null
+++ b/LanMontainDesktop/Views/Components/ClockWidget.axaml.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Globalization;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Threading;
+
+namespace LanMontainDesktop.Views.Components;
+
+public partial class ClockWidget : UserControl
+{
+ private readonly DispatcherTimer _timer = new()
+ {
+ Interval = TimeSpan.FromSeconds(1)
+ };
+
+ public ClockWidget()
+ {
+ InitializeComponent();
+
+ _timer.Tick += OnTimerTick;
+ AttachedToVisualTree += OnAttachedToVisualTree;
+ DetachedFromVisualTree += OnDetachedFromVisualTree;
+ UpdateClock();
+ }
+
+ private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
+ {
+ UpdateClock();
+ _timer.Start();
+ }
+
+ private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
+ {
+ _timer.Stop();
+ }
+
+ private void OnTimerTick(object? sender, EventArgs e)
+ {
+ UpdateClock();
+ }
+
+ private void UpdateClock()
+ {
+ var now = DateTime.Now;
+ TimeTextBlock.Text = now.ToString("HH:mm:ss", CultureInfo.CurrentCulture);
+ }
+}
diff --git a/LanMontainDesktop/Views/MainWindow.axaml b/LanMontainDesktop/Views/MainWindow.axaml
index 84e5fa7..9fa1e71 100644
--- a/LanMontainDesktop/Views/MainWindow.axaml
+++ b/LanMontainDesktop/Views/MainWindow.axaml
@@ -1,20 +1,91 @@
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LanMontainDesktop/Views/MainWindow.axaml.cs b/LanMontainDesktop/Views/MainWindow.axaml.cs
index 2152a01..678f33b 100644
--- a/LanMontainDesktop/Views/MainWindow.axaml.cs
+++ b/LanMontainDesktop/Views/MainWindow.axaml.cs
@@ -1,11 +1,125 @@
+using System;
+using Avalonia;
using Avalonia.Controls;
+using Avalonia.Interactivity;
namespace LanMontainDesktop.Views;
public partial class MainWindow : Window
{
+ private const int MinShortSideCells = 6;
+ private const int MaxShortSideCells = 96;
+ private int _targetShortSideCells;
+
public MainWindow()
{
InitializeComponent();
}
-}
\ No newline at end of file
+
+ protected override void OnOpened(EventArgs e)
+ {
+ base.OnOpened(e);
+
+ _targetShortSideCells = CalculateDefaultShortSideCellCountFromDpi();
+ GridSizeNumberBox.Value = _targetShortSideCells;
+ DesktopHost.SizeChanged += OnDesktopHostSizeChanged;
+ RebuildDesktopGrid();
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ DesktopHost.SizeChanged -= OnDesktopHostSizeChanged;
+ 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();
+ }
+
+ 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()
+ {
+ var hostWidth = DesktopHost.Bounds.Width;
+ var hostHeight = DesktopHost.Bounds.Height;
+ if (hostWidth <= 1 || hostHeight <= 1)
+ {
+ return;
+ }
+
+ var shortSideCells = Math.Max(1, _targetShortSideCells);
+ double cellSize;
+ int columnCount;
+ int rowCount;
+
+ if (hostWidth >= hostHeight)
+ {
+ rowCount = shortSideCells;
+ cellSize = hostHeight / rowCount;
+ columnCount = Math.Max(1, (int)Math.Ceiling(hostWidth / cellSize));
+ }
+ else
+ {
+ columnCount = shortSideCells;
+ cellSize = hostWidth / columnCount;
+ rowCount = Math.Max(1, (int)Math.Ceiling(hostHeight / cellSize));
+ }
+
+ DesktopGrid.RowDefinitions.Clear();
+ DesktopGrid.ColumnDefinitions.Clear();
+ DesktopGrid.Width = columnCount * cellSize;
+ DesktopGrid.Height = rowCount * cellSize;
+
+ for (var row = 0; row < rowCount; row++)
+ {
+ DesktopGrid.RowDefinitions.Add(new RowDefinition(new GridLength(cellSize, GridUnitType.Pixel)));
+ }
+
+ for (var col = 0; col < columnCount; col++)
+ {
+ DesktopGrid.ColumnDefinitions.Add(new ColumnDefinition(new GridLength(cellSize, GridUnitType.Pixel)));
+ }
+
+ Grid.SetRow(ClockWidget, 0);
+ Grid.SetColumn(ClockWidget, 0);
+ Grid.SetRowSpan(ClockWidget, 1);
+ Grid.SetColumnSpan(ClockWidget, Math.Min(3, columnCount));
+
+ Grid.SetRow(BackToWindowsButton, rowCount - 1);
+ Grid.SetColumn(BackToWindowsButton, 0);
+ Grid.SetRowSpan(BackToWindowsButton, 1);
+ Grid.SetColumnSpan(BackToWindowsButton, Math.Min(4, columnCount));
+
+ GridInfoTextBlock.Text =
+ $"Grid: {columnCount} cols x {rowCount} rows | cell {cellSize:F1}px (1:1)";
+ }
+
+ private void OnMinimizeClick(object? sender, RoutedEventArgs e)
+ {
+ WindowState = WindowState.Minimized;
+ }
+}