Skip to content

Added rotate left/right button on toolbar when selecting images #7832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/Files/Helpers/BitmapHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
using Files.Filesystem;
using Files.Filesystem.StorageItems;
using Windows.UI.Xaml.Media.Imaging;

namespace Files.Helpers
Expand All @@ -19,5 +24,44 @@ public static async Task<BitmapImage> ToBitmapAsync(this byte[] data)
await image.SetSourceAsync(ms.AsRandomAccessStream());
return image;
}


/// <summary>
/// Rotates the image at the specified file path.
/// </summary>
/// <param name="filePath">The file path to the image.</param>
/// <param name="rotation">The rotation direction.</param>
/// <remarks>
/// https://docs.microsoft.com/en-us/uwp/api/windows.graphics.imaging.bitmapdecoder?view=winrt-22000
/// https://docs.microsoft.com/en-us/uwp/api/windows.graphics.imaging.bitmapencoder?view=winrt-22000
/// </remarks>
public static async Task Rotate(string filePath, BitmapRotation rotation)
{
if (string.IsNullOrEmpty(filePath))
{
return;
}

var file = await StorageHelpers.ToStorageItem<IStorageFile>(filePath);
if (file == null)
{
return;
}

using IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);

using var memStream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(memStream, decoder);

encoder.BitmapTransform.Rotation = rotation;

await encoder.FlushAsync();

memStream.Seek(0);
fileStream.Seek(0);
fileStream.Size = 0;
await RandomAccessStream.CopyAsync(memStream, fileStream);
}
}
}
15 changes: 15 additions & 0 deletions src/Files/Interacts/BaseLayoutCommandImplementationModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Windows.ApplicationModel.DataTransfer.DragDrop;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.System;
using Windows.UI.Core;
Expand Down Expand Up @@ -786,6 +787,20 @@ public async void DecompressArchiveToChildFolder()
}
}

public async void RotateImageLeft()
{
await BitmapHelper.Rotate(PathNormalization.NormalizePath(SlimContentPage?.SelectedItems.First().ItemPath), BitmapRotation.Clockwise270Degrees);
SlimContentPage?.ItemManipulationModel.RefreshItemsThumbnail();
SlimContentPage?.PreviewPaneViewModel.UpdateSelectedItemPreview();
}

public async void RotateImageRight()
{
await BitmapHelper.Rotate(PathNormalization.NormalizePath(SlimContentPage?.SelectedItems.First().ItemPath), BitmapRotation.Clockwise90Degrees);
SlimContentPage?.ItemManipulationModel.RefreshItemsThumbnail();
SlimContentPage?.PreviewPaneViewModel.UpdateSelectedItemPreview();
}

public async void InstallFont()
{
foreach (ListedItem selectedItem in SlimContentPage.SelectedItems)
Expand Down
6 changes: 6 additions & 0 deletions src/Files/Interacts/BaseLayoutCommandsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ private void InitializeCommands()
DecompressArchiveCommand = new RelayCommand(CommandsModel.DecompressArchive);
DecompressArchiveHereCommand = new RelayCommand(CommandsModel.DecompressArchiveHere);
DecompressArchiveToChildFolderCommand = new RelayCommand(CommandsModel.DecompressArchiveToChildFolder);
RotateImageLeftCommand = new RelayCommand(CommandsModel.RotateImageLeft);
RotateImageRightCommand = new RelayCommand(CommandsModel.RotateImageRight);
InstallFontCommand = new RelayCommand(CommandsModel.InstallFont);
}

Expand Down Expand Up @@ -169,6 +171,10 @@ private void InitializeCommands()

public ICommand DecompressArchiveToChildFolderCommand { get; private set; }

public ICommand RotateImageLeftCommand { get; private set; }

public ICommand RotateImageRightCommand { get; private set; }

public ICommand InstallFontCommand { get; private set; }

#endregion Commands
Expand Down
4 changes: 4 additions & 0 deletions src/Files/Interacts/IBaseLayoutCommandImplementationModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ public interface IBaseLayoutCommandImplementationModel : IDisposable

void DecompressArchiveToChildFolder();

void RotateImageLeft();

void RotateImageRight();

void InstallFont();
}
}
7 changes: 7 additions & 0 deletions src/Files/Interacts/ItemManipulationModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class ItemManipulationModel

public event EventHandler RefreshItemsOpacityInvoked;

public event EventHandler RefreshItemsThumbnailInvoked;

public void FocusFileList()
{
FocusFileListInvoked?.Invoke(this, EventArgs.Empty);
Expand Down Expand Up @@ -110,5 +112,10 @@ public void RefreshItemsOpacity()
{
RefreshItemsOpacityInvoked?.Invoke(this, EventArgs.Empty);
}

public void RefreshItemsThumbnail()
{
RefreshItemsThumbnailInvoked?.Invoke(this, EventArgs.Empty);
}
}
}
6 changes: 6 additions & 0 deletions src/Files/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2729,6 +2729,12 @@ We use App Center to track which settings are being used, find bugs, and fix cra
<data name="ShowFolderSizesWarning" xml:space="preserve">
<value>Calculating folder sizes is resource intensive and may cause your CPU usage to increase.</value>
</data>
<data name="RotateLeft" xml:space="preserve">
<value>Rotate left</value>
</data>
<data name="RotateRight" xml:space="preserve">
<value>Rotate right</value>
</data>
<data name="Install" xml:space="preserve">
<value>Install</value>
</data>
Expand Down
36 changes: 31 additions & 5 deletions src/Files/UserControls/InnerNavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<Grid BorderBrush="{ThemeResource ControlStrokeColorDefault}" BorderThickness="0,0,0,1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CommandBar
x:Name="ContextCommandBar"
Expand Down Expand Up @@ -203,12 +203,12 @@
<AppBarSeparator x:Name="AdditionalActionSeparator" x:Load="{x:Bind ViewModel.HasAdditionalAction, Mode=OneWay}" />
<AppBarButton
x:Name="EmptyRecycleBinButton"
x:Load="{x:Bind ViewModel.InstanceViewModel.IsPageTypeRecycleBin, Mode=OneWay, FallbackValue=False}"
AccessKey="B"
Command="{x:Bind ViewModel.EmptyRecycleBinCommand, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.CanEmptyRecycleBin, Mode=OneWay}"
Label="{helpers:ResourceString Name=EmptyRecycleBin}"
ToolTipService.ToolTip="{helpers:ResourceString Name=EmptyRecycleBin}"
Visibility="{x:Bind ViewModel.InstanceViewModel.IsPageTypeRecycleBin, Mode=OneWay, FallbackValue=Collapsed}">
ToolTipService.ToolTip="{helpers:ResourceString Name=EmptyRecycleBin}">
<AppBarButton.Icon>
<FontIcon FontFamily="{StaticResource RecycleBinIcons}" Glyph="&#xEF88;" />
</AppBarButton.Icon>
Expand All @@ -217,11 +217,11 @@
x:Name="ExtractButton"
Width="Auto"
MinWidth="40"
x:Load="{x:Bind ViewModel.CanExtract, Mode=OneWay, FallbackValue=False}"
AccessKey="Z"
IsEnabled="{x:Bind ViewModel.CanExtract, Mode=OneWay, FallbackValue=False}"
Label="{helpers:ResourceString Name=Extract}"
LabelPosition="Default"
Visibility="{x:Bind ViewModel.CanExtract, Mode=OneWay, FallbackValue=Collapsed}">
LabelPosition="Default">
<AppBarButton.Content>
<FontIcon FontFamily="{StaticResource CustomGlyph}" Glyph="&#xF11A;" />
</AppBarButton.Content>
Expand Down Expand Up @@ -263,6 +263,8 @@
</AppBarButton>
<AppBarButton
x:Name="RunWithPowerShellButton"
Width="Auto"
MinWidth="40"
x:Load="{x:Bind ViewModel.IsPowerShellScript, Mode=OneWay, FallbackValue=False}"
AutomationProperties.Name="RunWithPowerShell"
Command="{x:Bind ViewModel.RunWithPowerShellCommand, Mode=OneWay}"
Expand All @@ -275,6 +277,8 @@
</AppBarButton>
<AppBarButton
x:Name="SetAsBackgroundButton"
Width="Auto"
MinWidth="40"
x:Load="{x:Bind ViewModel.IsImage, Mode=OneWay, FallbackValue=False}"
Command="{x:Bind ViewModel.SetAsBackgroundCommand, Mode=OneWay}"
Label="{helpers:ResourceString Name=SetAsBackground}"
Expand All @@ -284,6 +288,28 @@
<FontIcon Glyph="&#xE91B;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
x:Name="RotateImageLeftButton"
x:Load="{x:Bind ViewModel.IsImage, Mode=OneWay, FallbackValue=False}"
Command="{x:Bind ViewModel.RotateImageLeftCommand, Mode=OneWay}"
Label="{helpers:ResourceString Name=RotateLeft}"
LabelPosition="Default"
ToolTipService.ToolTip="{helpers:ResourceString Name=RotateLeft}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE7A7;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
x:Name="RotateImageRightButton"
x:Load="{x:Bind ViewModel.IsImage, Mode=OneWay, FallbackValue=False}"
Command="{x:Bind ViewModel.RotateImageRightCommand, Mode=OneWay}"
Label="{helpers:ResourceString Name=RotateRight}"
LabelPosition="Default"
ToolTipService.ToolTip="{helpers:ResourceString Name=RotateRight}">
<AppBarButton.Icon>
<FontIcon Glyph="&#xE7A6;" />
</AppBarButton.Icon>
</AppBarButton>
<AppBarButton
x:Name="InstallFontButton"
x:Load="{x:Bind ViewModel.IsFont, Mode=OneWay, FallbackValue=False}"
Expand Down
4 changes: 4 additions & 0 deletions src/Files/ViewModels/NavToolbarViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,10 @@ public void SearchRegion_LostFocus(object sender, RoutedEventArgs e)

public ICommand SetAsBackgroundCommand { get; set; }

public ICommand RotateImageLeftCommand { get; set; }

public ICommand RotateImageRightCommand { get; set; }

public ICommand InstallFontCommand { get; set; }

public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem pathItem, IShellPage shellPage)
Expand Down
2 changes: 2 additions & 0 deletions src/Files/Views/ColumnShellPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ private void InitToolbarCommands()
NavToolbarViewModel.ExtractCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.DecompressArchiveCommand.Execute(null));
NavToolbarViewModel.ExtractHereCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.DecompressArchiveHereCommand.Execute(null));
NavToolbarViewModel.ExtractToCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.DecompressArchiveToChildFolderCommand.Execute(null));
NavToolbarViewModel.RotateImageLeftCommand = new RelayCommand(async () => SlimContentPage?.CommandsViewModel.RotateImageLeftCommand.Execute(null));
NavToolbarViewModel.RotateImageRightCommand = new RelayCommand(async () => SlimContentPage?.CommandsViewModel.RotateImageRightCommand.Execute(null));
NavToolbarViewModel.InstallFontCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.InstallFontCommand.Execute(null));
}

Expand Down
15 changes: 15 additions & 0 deletions src/Files/Views/LayoutModes/GridViewBrowser.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Toolkit.Uwp.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;
Expand Down Expand Up @@ -51,6 +52,13 @@ protected override void HookEvents()
ItemManipulationModel.FocusSelectedItemsInvoked += ItemManipulationModel_FocusSelectedItemsInvoked;
ItemManipulationModel.StartRenameItemInvoked += ItemManipulationModel_StartRenameItemInvoked;
ItemManipulationModel.ScrollIntoViewInvoked += ItemManipulationModel_ScrollIntoViewInvoked;
ItemManipulationModel.RefreshItemsThumbnailInvoked += ItemManipulationModel_RefreshItemThumbnail;

}

private void ItemManipulationModel_RefreshItemThumbnail(object sender, EventArgs args)
{
ReloadSelectedItemIcon();
}

private void ItemManipulationModel_ScrollIntoViewInvoked(object sender, ListedItem e)
Expand Down Expand Up @@ -496,6 +504,13 @@ private async void ReloadItemIcons()
}
}

private async void ReloadSelectedItemIcon()
{
ParentShellPageInstance.FilesystemViewModel.CancelExtendedPropertiesLoading();
ParentShellPageInstance.SlimContentPage.SelectedItem.ItemPropertiesInitialized = false;
await ParentShellPageInstance.FilesystemViewModel.LoadExtendedItemProperties(ParentShellPageInstance.SlimContentPage.SelectedItem, currentIconSize);
}

private void FileList_ItemTapped(object sender, TappedRoutedEventArgs e)
{
var ctrlPressed = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
Expand Down
2 changes: 2 additions & 0 deletions src/Files/Views/ModernShellPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ private void InitToolbarCommands()
NavToolbarViewModel.ExtractCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.DecompressArchiveCommand.Execute(null));
NavToolbarViewModel.ExtractHereCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.DecompressArchiveHereCommand.Execute(null));
NavToolbarViewModel.ExtractToCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.DecompressArchiveToChildFolderCommand.Execute(null));
NavToolbarViewModel.RotateImageLeftCommand = new RelayCommand(async () => SlimContentPage?.CommandsViewModel.RotateImageLeftCommand.Execute(null));
NavToolbarViewModel.RotateImageRightCommand = new RelayCommand(async () => SlimContentPage?.CommandsViewModel.RotateImageRightCommand.Execute(null));
NavToolbarViewModel.InstallFontCommand = new RelayCommand(() => SlimContentPage?.CommandsViewModel.InstallFontCommand.Execute(null));
}

Expand Down