From 9fa8929c5b196431e30f529529144559eb4be692 Mon Sep 17 00:00:00 2001 From: Saravanan Ganapathi Date: Thu, 31 Jul 2025 19:07:25 +0530 Subject: [PATCH 1/4] ### **Resolved / Related Issues** Closes [Feature: Make columns resizable in Column Layout](https://github.com/files-community/Files/issues/6534) --- ### **Steps used to test these changes** 1. Opened Files and confirmed that: - Columns are resizable using the splitter between them - Cursor changes to a resize icon when hovering over the column divider - Double-clicking the divider resets to default width - Content inside each column adjusts correctly to new width - No visual glitches appear when resizing multiple columns rapidly 2. Verified that: - Column resizing works with mouse. - Resizing does not interfere with item selection, list scroll or navigation - Minimum and maximum column widths are respected --- src/Files.App.Controls/BladeView/BladeItem.cs | 85 +++++++++++++++++++ .../BladeView/BladeView.xaml | 45 ++++++++++ .../Files.App.Launcher.exe.sha256 | 2 +- 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/Files.App.Controls/BladeView/BladeItem.cs b/src/Files.App.Controls/BladeView/BladeItem.cs index 0ba8f525f6c0..10b2a54e3f83 100644 --- a/src/Files.App.Controls/BladeView/BladeItem.cs +++ b/src/Files.App.Controls/BladeView/BladeItem.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.UI.Input; using Microsoft.UI.Xaml.Automation.Peers; +using Microsoft.UI.Xaml.Input; namespace Files.App.Controls { @@ -11,7 +13,14 @@ namespace Files.App.Controls [TemplatePart(Name = "CloseButton", Type = typeof(Button))] public partial class BladeItem : ContentControl { + private const double MINIMUM_WIDTH = 150; + private const double DEFAULT_WIDTH = 300; // Default width for the blade item + private Button _closeButton; + private Border _bladeResizer; + private bool draggingSidebarResizer; + private double preManipulationSidebarWidth = 0; + /// /// Initializes a new instance of the class. /// @@ -36,7 +45,31 @@ protected override void OnApplyTemplate() _closeButton.Click -= CloseButton_Click; _closeButton.Click += CloseButton_Click; + + _bladeResizer = GetTemplateChild("BladeResizer") as Border; + + if (_bladeResizer != null) + { + _bladeResizer.ManipulationStarted -= BladeResizer_ManipulationStarted; + _bladeResizer.ManipulationStarted += BladeResizer_ManipulationStarted; + + _bladeResizer.ManipulationDelta -= BladeResizer_ManipulationDelta; + _bladeResizer.ManipulationDelta += BladeResizer_ManipulationDelta; + + _bladeResizer.ManipulationCompleted -= BladeResizer_ManipulationCompleted; + _bladeResizer.ManipulationCompleted += BladeResizer_ManipulationCompleted; + + _bladeResizer.PointerEntered -= BladeResizer_PointerEntered; + _bladeResizer.PointerEntered += BladeResizer_PointerEntered; + + _bladeResizer.PointerExited -= BladeResizer_PointerExited; + _bladeResizer.PointerExited += BladeResizer_PointerExited; + + _bladeResizer.DoubleTapped -= BladeResizer_DoubleTapped; + _bladeResizer.DoubleTapped += BladeResizer_DoubleTapped; + } } + /// /// Creates AutomationPeer () /// @@ -50,5 +83,57 @@ private void CloseButton_Click(object sender, RoutedEventArgs e) { IsOpen = false; } + private void BladeResizer_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) + { + draggingSidebarResizer = true; + preManipulationSidebarWidth = ActualWidth; + VisualStateManager.GoToState(this, "ResizerPressed", true); + e.Handled = true; + } + + private void BladeResizer_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) + { + var newWidth = preManipulationSidebarWidth + e.Cumulative.Translation.X; + + Debug.WriteLine($"BladeResizer - New item width: {newWidth}"); + + if (newWidth < MINIMUM_WIDTH) + newWidth = MINIMUM_WIDTH; + + Width = newWidth; + e.Handled = true; + } + + private void BladeResizer_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) + { + draggingSidebarResizer = false; + VisualStateManager.GoToState(this, "ResizerNormal", true); + e.Handled = true; + } + + private void BladeResizer_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e) + { + Width = DEFAULT_WIDTH; + e.Handled = true; + } + + private void BladeResizer_PointerEntered(object sender, PointerRoutedEventArgs e) + { + var sidebarResizer = (FrameworkElement)sender; + sidebarResizer.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.SizeWestEast)); + VisualStateManager.GoToState(this, "ResizerPointerOver", true); + e.Handled = true; + } + + private void BladeResizer_PointerExited(object sender, PointerRoutedEventArgs e) + { + if (draggingSidebarResizer) + return; + + var sidebarResizer = (FrameworkElement)sender; + sidebarResizer.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.Arrow)); + VisualStateManager.GoToState(this, "ResizerNormal", true); + e.Handled = true; + } } } diff --git a/src/Files.App.Controls/BladeView/BladeView.xaml b/src/Files.App.Controls/BladeView/BladeView.xaml index 82a593fed509..a638961df576 100644 --- a/src/Files.App.Controls/BladeView/BladeView.xaml +++ b/src/Files.App.Controls/BladeView/BladeView.xaml @@ -114,6 +114,24 @@ VerticalAlignment="Stretch" Background="{TemplateBinding Background}" /> + + +