Browse Source

Minor refactor

Equbuxu 3 years ago
parent
commit
f7fa1e293e

+ 0 - 112
PixiEditor/ViewModels/CommandSearchViewModel.cs

@@ -1,112 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.Commands;
-using PixiEditor.Models.Commands.Search;
-using SkiaSharp;
-using System.Collections.ObjectModel;
-using System.Text.RegularExpressions;
-
-namespace PixiEditor.ViewModels
-{
-    public class CommandSearchViewModel : NotifyableObject
-    {
-        private string searchTerm;
-        private SearchResult selectedCommand;
-
-        public string SearchTerm
-        {
-            get => searchTerm;
-            set
-            {
-                if (SetProperty(ref searchTerm, value))
-                {
-                    UpdateSearchResults();
-                }
-            }
-        }
-
-        public SearchResult SelectedResult
-        {
-            get => selectedCommand;
-            set
-            {
-                if (SetProperty(ref selectedCommand, value, out var oldValue))
-                {
-                    if (oldValue != null)
-                    {
-                        oldValue.IsSelected = false;
-                    }
-                    if (value != null)
-                    {
-                        value.IsSelected = true;
-                    }
-                }
-            }
-        }
-
-        public ObservableCollection<SearchResult> Results { get; } = new();
-
-        public CommandSearchViewModel()
-        {
-            UpdateSearchResults();
-        }
-
-        private void UpdateSearchResults()
-        {
-            CommandController controller = CommandController.Current;
-            Results.Clear();
-
-            if (string.IsNullOrWhiteSpace(SearchTerm))
-            {
-                foreach (var file in ViewModelMain.Current.FileSubViewModel.RecentlyOpened)
-                {
-                    Results.Add(
-                        new FileSearchResult(file.FilePath)
-                        {
-                            SearchTerm = searchTerm
-                        });
-                }
-
-                SelectedResult = Results.FirstOrDefault(x => x.CanExecute);
-                return;
-            }
-
-            if (SearchTerm.StartsWith('#'))
-            {
-                if (SKColor.TryParse(SearchTerm, out SKColor color))
-                {
-                    Results.Add(new ColorSearchResult(color)
-                    {
-                        SearchTerm = searchTerm
-                    });
-                }
-            }
-
-            foreach (var command in controller.Commands
-                .Where(x => x.Description.Contains(SearchTerm, StringComparison.OrdinalIgnoreCase))
-                .OrderByDescending(x => x.Description.Contains($" {SearchTerm} ", StringComparison.OrdinalIgnoreCase))
-                .Take(12))
-            {
-                Results.Add(
-                    new CommandSearchResult(command)
-                    {
-                        SearchTerm = searchTerm,
-                        Match = Match(command.Description)
-                    });
-            }
-
-            foreach (var file in ViewModelMain.Current.FileSubViewModel.RecentlyOpened.Where(x => x.FilePath.Contains(searchTerm)))
-            {
-                Results.Add(
-                    new FileSearchResult(file.FilePath)
-                    {
-                        SearchTerm = searchTerm,
-                        Match = Match(file.FilePath)
-                    });
-            }
-
-            Match Match(string text) => Regex.Match(text, $"(.*)({Regex.Escape(SearchTerm)})(.*)", RegexOptions.IgnoreCase);
-
-            SelectedResult = Results.FirstOrDefault(x => x.CanExecute);
-        }
-    }
-}

+ 616 - 263
PixiEditor/Views/MainWindow.xaml

@@ -1,134 +1,255 @@
-<Window x:Class="PixiEditor.MainWindow" MinHeight="500" MinWidth="700"
-        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-        xmlns:local="clr-namespace:PixiEditor"
-        xmlns:tools="clr-namespace:PixiEditor.Models.Tools.Tools"
-        xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-        xmlns:dataHolders="clr-namespace:PixiEditor.Models.DataHolders"
-        xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
-        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
-        xmlns:ui="clr-namespace:PixiEditor.Helpers.UI"
-        xmlns:cmd="http://www.galasoft.ch/mvvmlight" 
-        xmlns:avalondock="https://github.com/Dirkster99/AvalonDock"
-        xmlns:colorpicker="clr-namespace:ColorPicker;assembly=ColorPicker" 
-        xmlns:usercontrols="clr-namespace:PixiEditor.Views.UserControls" 
-        xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours" 
-        xmlns:avalonDockTheme="clr-namespace:PixiEditor.Styles.AvalonDock" 
-        xmlns:layerUserControls="clr-namespace:PixiEditor.Views.UserControls.Layers" 
-        xmlns:cmds="clr-namespace:PixiEditor.Models.Commands.XAML"
-        d:DataContext="{d:DesignInstance Type=vm:ViewModelMain}"
-        mc:Ignorable="d" WindowStyle="None" Initialized="MainWindow_Initialized"
-        Title="PixiEditor" Name="mainWindow" Height="1000" Width="1600" Background="{StaticResource MainColor}"
-        WindowStartupLocation="CenterScreen" WindowState="Maximized">
+<Window
+    x:Class="PixiEditor.MainWindow"
+    MinHeight="500"
+    MinWidth="700"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:local="clr-namespace:PixiEditor"
+    xmlns:tools="clr-namespace:PixiEditor.Models.Tools.Tools"
+    xmlns:vm="clr-namespace:PixiEditor.ViewModels"
+    xmlns:dataHolders="clr-namespace:PixiEditor.Models.DataHolders"
+    xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
+    xmlns:ui="clr-namespace:PixiEditor.Helpers.UI"
+    xmlns:cmd="http://www.galasoft.ch/mvvmlight"
+    xmlns:avalondock="https://github.com/Dirkster99/AvalonDock"
+    xmlns:colorpicker="clr-namespace:ColorPicker;assembly=ColorPicker"
+    xmlns:usercontrols="clr-namespace:PixiEditor.Views.UserControls"
+    xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
+    xmlns:avalonDockTheme="clr-namespace:PixiEditor.Styles.AvalonDock"
+    xmlns:layerUserControls="clr-namespace:PixiEditor.Views.UserControls.Layers"
+    xmlns:cmds="clr-namespace:PixiEditor.Models.Commands.XAML"
+    xmlns:commandSearch="clr-namespace:PixiEditor.Views.UserControls.CommandSearch"
+    d:DataContext="{d:DesignInstance Type=vm:ViewModelMain}"
+    mc:Ignorable="d"
+    WindowStyle="None"
+    Initialized="MainWindow_Initialized"
+    Title="PixiEditor"
+    Name="mainWindow"
+    Height="1000"
+    Width="1600"
+    Background="{StaticResource MainColor}"
+    WindowStartupLocation="CenterScreen"
+    WindowState="Maximized">
     <WindowChrome.WindowChrome>
-        <WindowChrome CaptionHeight="35" GlassFrameThickness="0.1" x:Name="windowsChrome"/>
+        <WindowChrome
+            CaptionHeight="35"
+            GlassFrameThickness="0.1"
+            x:Name="windowsChrome" />
     </WindowChrome.WindowChrome>
 
     <Window.Resources>
         <ResourceDictionary>
-            <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
-            <converters:BoolToIntConverter x:Key="BoolToIntConverter" />
-            <converters:NotNullToBoolConverter x:Key="NotNullToBoolConverter" />
-            <converters:LayersToStructuredLayersConverter x:Key="LayersToStructuredLayersConverter"/>
-            <converters:DoubleToIntConverter x:Key="DoubleToIntConverter"/>
-            <converters:IsSpecifiedTypeConverter SpecifiedType="{x:Type tools:ZoomTool}" x:Key="IsZoomToolConverter"/>
-            <converters:IsSpecifiedTypeConverter SpecifiedType="{x:Type tools:MoveViewportTool}" x:Key="IsMoveViewportToolConverter"/>
-            <converters:SKColorToMediaColorConverter x:Key="SKColorToMediaColorConverter"/>
+            <BooleanToVisibilityConverter
+                x:Key="BoolToVisibilityConverter" />
+            <converters:BoolToIntConverter
+                x:Key="BoolToIntConverter" />
+            <converters:NotNullToBoolConverter
+                x:Key="NotNullToBoolConverter" />
+            <converters:LayersToStructuredLayersConverter
+                x:Key="LayersToStructuredLayersConverter" />
+            <converters:DoubleToIntConverter
+                x:Key="DoubleToIntConverter" />
+            <converters:IsSpecifiedTypeConverter
+                SpecifiedType="{x:Type tools:ZoomTool}"
+                x:Key="IsZoomToolConverter" />
+            <converters:IsSpecifiedTypeConverter
+                SpecifiedType="{x:Type tools:MoveViewportTool}"
+                x:Key="IsMoveViewportToolConverter" />
+            <converters:SKColorToMediaColorConverter
+                x:Key="SKColorToMediaColorConverter" />
             <ResourceDictionary.MergedDictionaries>
-                <ResourceDictionary Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
+                <ResourceDictionary
+                    Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
     </Window.Resources>
 
     <Window.CommandBindings>
-        <CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute"
-                        Executed="CommandBinding_Executed_Close" />
-        <CommandBinding Command="{x:Static SystemCommands.MaximizeWindowCommand}"
-                        CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Maximize" />
-        <CommandBinding Command="{x:Static SystemCommands.MinimizeWindowCommand}"
-                        CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed_Minimize" />
-        <CommandBinding Command="{x:Static SystemCommands.RestoreWindowCommand}" CanExecute="CommandBinding_CanExecute"
-                        Executed="CommandBinding_Executed_Restore" />
+        <CommandBinding
+            Command="{x:Static SystemCommands.CloseWindowCommand}"
+            CanExecute="CommandBinding_CanExecute"
+            Executed="CommandBinding_Executed_Close" />
+        <CommandBinding
+            Command="{x:Static SystemCommands.MaximizeWindowCommand}"
+            CanExecute="CommandBinding_CanExecute"
+            Executed="CommandBinding_Executed_Maximize" />
+        <CommandBinding
+            Command="{x:Static SystemCommands.MinimizeWindowCommand}"
+            CanExecute="CommandBinding_CanExecute"
+            Executed="CommandBinding_Executed_Minimize" />
+        <CommandBinding
+            Command="{x:Static SystemCommands.RestoreWindowCommand}"
+            CanExecute="CommandBinding_CanExecute"
+            Executed="CommandBinding_Executed_Restore" />
     </Window.CommandBindings>
 
     <i:Interaction.Triggers>
-        <i:EventTrigger EventName="ContentRendered">
-            <i:InvokeCommandAction Command="{Binding OnStartupCommand}" />
+        <i:EventTrigger
+            EventName="ContentRendered">
+            <i:InvokeCommandAction
+                Command="{Binding OnStartupCommand}" />
         </i:EventTrigger>
-        <i:EventTrigger EventName="Closing">
-            <cmd:EventToCommand Command="{Binding CloseWindowCommand}" PassEventArgsToCommand="True" />
+        <i:EventTrigger
+            EventName="Closing">
+            <cmd:EventToCommand
+                Command="{Binding CloseWindowCommand}"
+                PassEventArgsToCommand="True" />
         </i:EventTrigger>
     </i:Interaction.Triggers>
     <Grid>
-        <Grid Name="mainGrid" Margin="5" Focusable="True" >
+        <Grid
+            Name="mainGrid"
+            Margin="5"
+            Focusable="True">
             <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="45" />
-                <ColumnDefinition Width="1*" />
+                <ColumnDefinition
+                    Width="45" />
+                <ColumnDefinition
+                    Width="1*" />
             </Grid.ColumnDefinitions>
             <Grid.RowDefinitions>
-                <RowDefinition Height="30" />
-                <RowDefinition Height="40" />
-                <RowDefinition Height="1*" />
-                <RowDefinition Height="30" />
+                <RowDefinition
+                    Height="30" />
+                <RowDefinition
+                    Height="40" />
+                <RowDefinition
+                    Height="1*" />
+                <RowDefinition
+                    Height="30" />
             </Grid.RowDefinitions>
             <i:Interaction.Behaviors>
-                <behaviours:ClearFocusOnClickBehavior/>
+                <behaviours:ClearFocusOnClickBehavior />
             </i:Interaction.Behaviors>
-            <DockPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Background="{StaticResource MainColor}">
-                <Image DockPanel.Dock="Left" HorizontalAlignment="Left" VerticalAlignment="Top"
-                   Source="/Images/PixiEditorLogo.png" Width="20" Height="20" Margin="5,5,0,0" />
-                <cmds:Menu WindowChrome.IsHitTestVisibleInChrome="True" Margin="10, 4, 0, 0" DockPanel.Dock="Left"
-                  HorizontalAlignment="Left" VerticalAlignment="Top" Background="Transparent" IsMainMenu="True">
+            <DockPanel
+                Grid.Row="0"
+                Grid.Column="0"
+                Grid.ColumnSpan="3"
+                Background="{StaticResource MainColor}">
+                <Image
+                    DockPanel.Dock="Left"
+                    HorizontalAlignment="Left"
+                    VerticalAlignment="Top"
+                    Source="/Images/PixiEditorLogo.png"
+                    Width="20"
+                    Height="20"
+                    Margin="5,5,0,0" />
+                <cmds:Menu
+                    WindowChrome.IsHitTestVisibleInChrome="True"
+                    Margin="10, 4, 0, 0"
+                    DockPanel.Dock="Left"
+                    HorizontalAlignment="Left"
+                    VerticalAlignment="Top"
+                    Background="Transparent"
+                    IsMainMenu="True">
                     <Menu.Resources>
-                        <Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource menuItemStyle}" />
+                        <Style
+                            TargetType="{x:Type MenuItem}"
+                            BasedOn="{StaticResource menuItemStyle}" />
                     </Menu.Resources>
-                    <MenuItem Header="_File">
-                        <MenuItem Header="_New" cmds:Menu.Command="PixiEditor.File.New" />
-                        <MenuItem Header="_Open" cmds:Menu.Command="PixiEditor.File.Open" />
-                        <MenuItem Header="_Recent" ItemsSource="{Binding FileSubViewModel.RecentlyOpened}" x:Name="recentItemMenu" IsEnabled="{Binding FileSubViewModel.HasRecent}">
+                    <MenuItem
+                        Header="_File">
+                        <MenuItem
+                            Header="_New"
+                            cmds:Menu.Command="PixiEditor.File.New" />
+                        <MenuItem
+                            Header="_Open"
+                            cmds:Menu.Command="PixiEditor.File.Open" />
+                        <MenuItem
+                            Header="_Recent"
+                            ItemsSource="{Binding FileSubViewModel.RecentlyOpened}"
+                            x:Name="recentItemMenu"
+                            IsEnabled="{Binding FileSubViewModel.HasRecent}">
                             <MenuItem.ItemContainerStyle>
-                                <Style TargetType="MenuItem" BasedOn="{StaticResource PixiEditorDockThemeMenuItemStyle}">
-                                    <Setter Property="Command" Value="{cmds:Command PixiEditor.File.Open, UseProvided=True}"/>
-                                    <Setter Property="CommandParameter" Value="{Binding FilePath}"/>
+                                <Style
+                                    TargetType="MenuItem"
+                                    BasedOn="{StaticResource PixiEditorDockThemeMenuItemStyle}">
+                                    <Setter
+                                        Property="Command"
+                                        Value="{cmds:Command PixiEditor.File.Open, UseProvided=True}" />
+                                    <Setter
+                                        Property="CommandParameter"
+                                        Value="{Binding FilePath}" />
                                 </Style>
                             </MenuItem.ItemContainerStyle>
                             <MenuItem.ItemTemplate>
-                                <DataTemplate DataType="{x:Type dataHolders:RecentlyOpenedDocument}">
-                                    <TextBlock Text="{Binding FilePath}"/>
+                                <DataTemplate
+                                    DataType="{x:Type dataHolders:RecentlyOpenedDocument}">
+                                    <TextBlock
+                                        Text="{Binding FilePath}" />
                                 </DataTemplate>
                             </MenuItem.ItemTemplate>
                         </MenuItem>
-                        <MenuItem Header="_Save" cmds:Menu.Command="PixiEditor.File.Save" />
-                        <MenuItem Header="_Save As..." cmds:Menu.Command="PixiEditor.File.SaveAsNew" />
-                        <MenuItem Header="_Export" cmds:Menu.Command="PixiEditor.File.Export" />
+                        <MenuItem
+                            Header="_Save"
+                            cmds:Menu.Command="PixiEditor.File.Save" />
+                        <MenuItem
+                            Header="_Save As..."
+                            cmds:Menu.Command="PixiEditor.File.SaveAsNew" />
+                        <MenuItem
+                            Header="_Export"
+                            cmds:Menu.Command="PixiEditor.File.Export" />
                         <Separator />
-                        <MenuItem Header="_Exit" Command="{x:Static SystemCommands.CloseWindowCommand}" />
+                        <MenuItem
+                            Header="_Exit"
+                            Command="{x:Static SystemCommands.CloseWindowCommand}" />
                     </MenuItem>
-                    <MenuItem Header="_Edit">
-                        <MenuItem Header="_Undo" cmds:Menu.Command="PixiEditor.Undo.Undo" />
-                        <MenuItem Header="_Redo" cmds:Menu.Command="PixiEditor.Undo.Redo" />
+                    <MenuItem
+                        Header="_Edit">
+                        <MenuItem
+                            Header="_Undo"
+                            cmds:Menu.Command="PixiEditor.Undo.Undo" />
+                        <MenuItem
+                            Header="_Redo"
+                            cmds:Menu.Command="PixiEditor.Undo.Redo" />
                         <Separator />
-                        <MenuItem Header="_Cut" cmds:Menu.Command="PixiEditor.Clipboard.Cut" />
-                        <MenuItem Header="_Copy" cmds:Menu.Command="PixiEditor.Clipboard.Copy" />
-                        <MenuItem Header="_Paste" cmds:Menu.Command="PixiEditor.Clipboard.Paste" />
-                        <MenuItem Header="_Duplicate" cmds:Menu.Command="PixiEditor.Clipboard.Duplicate" />
+                        <MenuItem
+                            Header="_Cut"
+                            cmds:Menu.Command="PixiEditor.Clipboard.Cut" />
+                        <MenuItem
+                            Header="_Copy"
+                            cmds:Menu.Command="PixiEditor.Clipboard.Copy" />
+                        <MenuItem
+                            Header="_Paste"
+                            cmds:Menu.Command="PixiEditor.Clipboard.Paste" />
+                        <MenuItem
+                            Header="_Duplicate"
+                            cmds:Menu.Command="PixiEditor.Clipboard.Duplicate" />
                         <Separator />
-                        <MenuItem Header="_Delete Selected" cmds:Menu.Command="PixiEditor.Document.DeletePixels" />
+                        <MenuItem
+                            Header="_Delete Selected"
+                            cmds:Menu.Command="PixiEditor.Document.DeletePixels" />
                         <Separator />
-                        <MenuItem Header="_Settings" cmds:Menu.Command="PixiEditor.Window.OpenSettingsWindow" />
+                        <MenuItem
+                            Header="_Settings"
+                            cmds:Menu.Command="PixiEditor.Window.OpenSettingsWindow" />
                     </MenuItem>
-                    <MenuItem Header="_Select">
-                        <MenuItem Header="_Select All" cmds:Menu.Command="PixiEditor.Selection.SelectAll" />
-                        <MenuItem Header="_Deselect" cmds:Menu.Command="PixiEditor.Selection.Clear" />
+                    <MenuItem
+                        Header="_Select">
+                        <MenuItem
+                            Header="_Select All"
+                            cmds:Menu.Command="PixiEditor.Selection.SelectAll" />
+                        <MenuItem
+                            Header="_Deselect"
+                            cmds:Menu.Command="PixiEditor.Selection.Clear" />
                     </MenuItem>
-                    <MenuItem Header="_Image">
-                        <MenuItem Header="Resize _Image..." cmds:Menu.Command="PixiEditor.Document.ResizeDocument" />
-                        <MenuItem Header="_Resize Canvas..." cmds:Menu.Command="PixiEditor.Document.ResizeCanvas" />
-                        <MenuItem Header="_Clip Canvas" cmds:Menu.Command="PixiEditor.Document.ClipCanvas" />
-                        <Separator/>
-                        <MenuItem Header="_Center Content" cmds:Menu.Command="PixiEditor.Document.CenterContent" />
+                    <MenuItem
+                        Header="_Image">
+                        <MenuItem
+                            Header="Resize _Image..."
+                            cmds:Menu.Command="PixiEditor.Document.ResizeDocument" />
+                        <MenuItem
+                            Header="_Resize Canvas..."
+                            cmds:Menu.Command="PixiEditor.Document.ResizeCanvas" />
+                        <MenuItem
+                            Header="_Clip Canvas"
+                            cmds:Menu.Command="PixiEditor.Document.ClipCanvas" />
+                        <Separator />
+                        <MenuItem
+                            Header="_Center Content"
+                            cmds:Menu.Command="PixiEditor.Document.CenterContent" />
                         <!--<Separator/>
                     <MenuItem Header="_Rotate to right 90&#186;" Command="{Binding DocumentSubViewModel.RotateToRightCommand}">
                         <MenuItem.CommandParameter>
@@ -145,114 +266,227 @@
                     <MenuItem Header="_Flip Vertical" Command="{Binding DocumentSubViewModel.FlipCommand}" CommandParameter="Vertical"/>
                 -->
                     </MenuItem>
-                    <MenuItem Header="_View">
-                        <MenuItem Header="_Show Grid Lines" IsChecked="{Binding ViewportSubViewModel.GridLinesEnabled, Mode=TwoWay}"
-                              IsCheckable="True" InputGestureText="{cmds:ShortcutBinding PixiEditor.View.ToggleGrid}"/>
-                        <MenuItem Header="Open _Startup Window" ToolTip="Hello there!" cmds:Menu.Command="PixiEditor.Window.OpenStartupWindow"/>
-                        <MenuItem Header="Open _Navigation Window" cmds:Menu.Command="PixiEditor.Window.OpenNavigationWindow"/>
-                        <MenuItem Header="Open _Shortcuts Window" cmds:Menu.Command="PixiEditor.Window.OpenShortcutWindow"/>
+                    <MenuItem
+                        Header="_View">
+                        <MenuItem
+                            Header="_Show Grid Lines"
+                            IsChecked="{Binding ViewportSubViewModel.GridLinesEnabled, Mode=TwoWay}"
+                            IsCheckable="True"
+                            InputGestureText="{cmds:ShortcutBinding PixiEditor.View.ToggleGrid}" />
+                        <MenuItem
+                            Header="Open _Startup Window"
+                            ToolTip="Hello there!"
+                            cmds:Menu.Command="PixiEditor.Window.OpenStartupWindow" />
+                        <MenuItem
+                            Header="Open _Navigation Window"
+                            cmds:Menu.Command="PixiEditor.Window.OpenNavigationWindow" />
+                        <MenuItem
+                            Header="Open _Shortcuts Window"
+                            cmds:Menu.Command="PixiEditor.Window.OpenShortcutWindow" />
                     </MenuItem>
-                    <MenuItem Header="_Help">
-                        <MenuItem Header="_Documentation" cmds:Menu.Command="PixiEditor.Links.OpenDocumentation" />
-                        <MenuItem Header="_Website" cmds:Menu.Command="PixiEditor.Links.OpenWebsite" />
-                        <MenuItem Header="_Repository" cmds:Menu.Command="PixiEditor.Links.OpenRepository" />
-                        <Separator/>
-                        <MenuItem Header="_License" cmds:Menu.Command="PixiEditor.Links.OpenLicense" />
-                        <MenuItem Header="_Third Party Licenses" cmds:Menu.Command="PixiEditor.Links.OpenOtherLicenses" />
+                    <MenuItem
+                        Header="_Help">
+                        <MenuItem
+                            Header="_Documentation"
+                            cmds:Menu.Command="PixiEditor.Links.OpenDocumentation" />
+                        <MenuItem
+                            Header="_Website"
+                            cmds:Menu.Command="PixiEditor.Links.OpenWebsite" />
+                        <MenuItem
+                            Header="_Repository"
+                            cmds:Menu.Command="PixiEditor.Links.OpenRepository" />
+                        <Separator />
+                        <MenuItem
+                            Header="_License"
+                            cmds:Menu.Command="PixiEditor.Links.OpenLicense" />
+                        <MenuItem
+                            Header="_Third Party Licenses"
+                            cmds:Menu.Command="PixiEditor.Links.OpenOtherLicenses" />
                     </MenuItem>
-                    <MenuItem Header="_Debug" Visibility="{Binding DebugSubViewModel.UseDebug, Converter={StaticResource BoolToVisibilityConverter}}">
-                        <MenuItem Header="Open _Local App Data" cmds:Menu.Command="PixiEditor.Debug.OpenLocalAppDataDirectory" />
-                        <MenuItem Header="Open _Roaming App Data" cmds:Menu.Command="PixiEditor.Debug.OpenRoamingAppDataDirectory" />
-                        <MenuItem Header="Open _Temp App Data" cmds:Menu.Command="PixiEditor.Debug.OpenTempDirectory" />
-                        <MenuItem Header="Open _Install Location" cmds:Menu.Command="PixiEditor.Debug.OpenInstallDirectory" />
-                        <Separator/>
-                        <MenuItem Header="_Crash" cmds:Menu.Command="PixiEditor.Debug.Crash" />
-                        <MenuItem Header="Delete">
-                            <MenuItem Header="User Preferences (Roaming)" cmds:Menu.Command="PixiEditor.Debug.DeleteUserPreferences" />
-                            <MenuItem Header="Shortcut File (Roaming)" cmds:Menu.Command="PixiEditor.Debug.DeleteShortcutFile" />
-                            <MenuItem Header="Editor Data (Local)" cmds:Menu.Command="PixiEditor.Debug.DeleteEditorData" />
+                    <MenuItem
+                        Header="_Debug"
+                        Visibility="{Binding DebugSubViewModel.UseDebug, Converter={StaticResource BoolToVisibilityConverter}}">
+                        <MenuItem
+                            Header="Open _Local App Data"
+                            cmds:Menu.Command="PixiEditor.Debug.OpenLocalAppDataDirectory" />
+                        <MenuItem
+                            Header="Open _Roaming App Data"
+                            cmds:Menu.Command="PixiEditor.Debug.OpenRoamingAppDataDirectory" />
+                        <MenuItem
+                            Header="Open _Temp App Data"
+                            cmds:Menu.Command="PixiEditor.Debug.OpenTempDirectory" />
+                        <MenuItem
+                            Header="Open _Install Location"
+                            cmds:Menu.Command="PixiEditor.Debug.OpenInstallDirectory" />
+                        <Separator />
+                        <MenuItem
+                            Header="_Crash"
+                            cmds:Menu.Command="PixiEditor.Debug.Crash" />
+                        <MenuItem
+                            Header="Delete">
+                            <MenuItem
+                                Header="User Preferences (Roaming)"
+                                cmds:Menu.Command="PixiEditor.Debug.DeleteUserPreferences" />
+                            <MenuItem
+                                Header="Shortcut File (Roaming)"
+                                cmds:Menu.Command="PixiEditor.Debug.DeleteShortcutFile" />
+                            <MenuItem
+                                Header="Editor Data (Local)"
+                                cmds:Menu.Command="PixiEditor.Debug.DeleteEditorData" />
                         </MenuItem>
                     </MenuItem>
                 </cmds:Menu>
-                <StackPanel DockPanel.Dock="Right" VerticalAlignment="Top" Orientation="Horizontal" Margin="0,-5,-5,0"
-                        HorizontalAlignment="Right" WindowChrome.IsHitTestVisibleInChrome="True">
-                    <Button Style="{StaticResource MinimizeButtonStyle}" WindowChrome.IsHitTestVisibleInChrome="True"
+                <StackPanel
+                    DockPanel.Dock="Right"
+                    VerticalAlignment="Top"
+                    Orientation="Horizontal"
+                    Margin="0,-5,-5,0"
+                    HorizontalAlignment="Right"
+                    WindowChrome.IsHitTestVisibleInChrome="True">
+                    <Button
+                        Style="{StaticResource MinimizeButtonStyle}"
+                        WindowChrome.IsHitTestVisibleInChrome="True"
                         ToolTip="Minimize"
                         Command="{x:Static SystemCommands.MinimizeWindowCommand}" />
-                    <Button x:Name="RestoreButton" Visibility="Visible" Style="{StaticResource RestoreButtonStyle}"
+                    <Button
+                        x:Name="RestoreButton"
+                        Visibility="Visible"
+                        Style="{StaticResource RestoreButtonStyle}"
                         Command="{x:Static SystemCommands.RestoreWindowCommand}"
-                        WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Restore" />
-                    <Button x:Name="MaximizeButton" Visibility="Collapsed" Style="{StaticResource MaximizeButtonStyle}"
+                        WindowChrome.IsHitTestVisibleInChrome="True"
+                        ToolTip="Restore" />
+                    <Button
+                        x:Name="MaximizeButton"
+                        Visibility="Collapsed"
+                        Style="{StaticResource MaximizeButtonStyle}"
                         Command="{x:Static SystemCommands.MaximizeWindowCommand}"
-                        WindowChrome.IsHitTestVisibleInChrome="True" ToolTip="Maximize" />
-                    <Button Style="{StaticResource CloseButtonStyle}" WindowChrome.IsHitTestVisibleInChrome="True"
+                        WindowChrome.IsHitTestVisibleInChrome="True"
+                        ToolTip="Maximize" />
+                    <Button
+                        Style="{StaticResource CloseButtonStyle}"
+                        WindowChrome.IsHitTestVisibleInChrome="True"
                         ToolTip="Close"
                         Command="{x:Static SystemCommands.CloseWindowCommand}" />
                 </StackPanel>
             </DockPanel>
-            <StackPanel Background="{StaticResource MainColor}" Orientation="Horizontal" Grid.ColumnSpan="3" Grid.Column="0"
-                     Grid.Row="1">
-                <Button Margin="1,0,0,0" Command="{cmds:Command PixiEditor.Undo.Undo}" ToolTip="Undo"
-                    Style="{StaticResource ToolSettingsGlyphButton}" Content="&#xE7A7;"/>
-                <Button Command="{cmds:Command PixiEditor.Undo.Redo}" ToolTip="Redo"
-                    Style="{StaticResource ToolSettingsGlyphButton}" Content="&#xE7A6;"/>
-                <ToggleButton Width="30" BorderThickness="0"
-                          ToolTip="Pen Mode" Focusable="False"
-                          IsChecked="{Binding StylusSubViewModel.IsPenModeEnabled}">
+            <StackPanel
+                Background="{StaticResource MainColor}"
+                Orientation="Horizontal"
+                Grid.ColumnSpan="3"
+                Grid.Column="0"
+                Grid.Row="1">
+                <Button
+                    Margin="1,0,0,0"
+                    Command="{cmds:Command PixiEditor.Undo.Undo}"
+                    ToolTip="Undo"
+                    Style="{StaticResource ToolSettingsGlyphButton}"
+                    Content="&#xE7A7;" />
+                <Button
+                    Command="{cmds:Command PixiEditor.Undo.Redo}"
+                    ToolTip="Redo"
+                    Style="{StaticResource ToolSettingsGlyphButton}"
+                    Content="&#xE7A6;" />
+                <ToggleButton
+                    Width="30"
+                    BorderThickness="0"
+                    ToolTip="Pen Mode"
+                    Focusable="False"
+                    IsChecked="{Binding StylusSubViewModel.IsPenModeEnabled}">
                     <ToggleButton.Style>
-                        <Style TargetType="ToggleButton">
-                            <Setter Property="Template">
+                        <Style
+                            TargetType="ToggleButton">
+                            <Setter
+                                Property="Template">
                                 <Setter.Value>
-                                    <ControlTemplate TargetType="ToggleButton">
-                                        <Border BorderBrush="{TemplateBinding BorderBrush}" 
-                                            Background="{TemplateBinding Background}" Focusable="False">
-                                            <ContentPresenter HorizontalAlignment="Center"
-                                              VerticalAlignment="Center" Focusable="False"/>
+                                    <ControlTemplate
+                                        TargetType="ToggleButton">
+                                        <Border
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            Background="{TemplateBinding Background}"
+                                            Focusable="False">
+                                            <ContentPresenter
+                                                HorizontalAlignment="Center"
+                                                VerticalAlignment="Center"
+                                                Focusable="False" />
                                         </Border>
                                     </ControlTemplate>
                                 </Setter.Value>
                             </Setter>
                             <Style.Triggers>
-                                <Trigger Property="IsChecked" Value="False">
-                                    <Setter Property="Background" Value="Transparent"/>
+                                <Trigger
+                                    Property="IsChecked"
+                                    Value="False">
+                                    <Setter
+                                        Property="Background"
+                                        Value="Transparent" />
                                 </Trigger>
-                                <Trigger Property="IsMouseOver" Value="True">
-                                    <Setter Property="Background" Value="#404040"/>
+                                <Trigger
+                                    Property="IsMouseOver"
+                                    Value="True">
+                                    <Setter
+                                        Property="Background"
+                                        Value="#404040" />
                                 </Trigger>
-                                <Trigger Property="IsChecked" Value="True">
-                                    <Setter Property="Background" Value="#707070"/>
+                                <Trigger
+                                    Property="IsChecked"
+                                    Value="True">
+                                    <Setter
+                                        Property="Background"
+                                        Value="#707070" />
                                 </Trigger>
                             </Style.Triggers>
                         </Style>
                     </ToggleButton.Style>
-                    <Image Height="20" Source="../Images/penMode.png"/>
+                    <Image
+                        Height="20"
+                        Source="../Images/penMode.png" />
                 </ToggleButton>
-                <Grid Margin="5,5,10,5" Background="{StaticResource BrighterAccentColor}" Width="5"/>
-                <Label Style="{StaticResource BaseLabel}" FontSize="12"
-                   VerticalAlignment="Center" Content="{Binding ToolsSubViewModel.ActiveTool.DisplayName}"
-                   ToolTip="{Binding ToolsSubViewModel.ActiveTool.ActionDisplay}"/>
-                <ItemsControl ItemsSource="{Binding ToolsSubViewModel.ActiveTool.Toolbar.Settings}">
+                <Grid
+                    Margin="5,5,10,5"
+                    Background="{StaticResource BrighterAccentColor}"
+                    Width="5" />
+                <Label
+                    Style="{StaticResource BaseLabel}"
+                    FontSize="12"
+                    VerticalAlignment="Center"
+                    Content="{Binding ToolsSubViewModel.ActiveTool.DisplayName}"
+                    ToolTip="{Binding ToolsSubViewModel.ActiveTool.ActionDisplay}" />
+                <ItemsControl
+                    ItemsSource="{Binding ToolsSubViewModel.ActiveTool.Toolbar.Settings}">
                     <ItemsControl.ItemsPanel>
                         <ItemsPanelTemplate>
-                            <StackPanel Orientation="Horizontal" Margin="10, 0, 0, 0" />
+                            <StackPanel
+                                Orientation="Horizontal"
+                                Margin="10, 0, 0, 0" />
                         </ItemsPanelTemplate>
                     </ItemsControl.ItemsPanel>
                     <ItemsControl.ItemTemplate>
                         <DataTemplate>
-                            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,10,0">
+                            <StackPanel
+                                Orientation="Horizontal"
+                                VerticalAlignment="Center"
+                                Margin="10,0,10,0">
                                 <Label
-                                Visibility="{Binding HasLabel, Converter={StaticResource BoolToVisibilityConverter}}"
-                                Foreground="White" Content="{Binding Label}" />
-                                <ContentControl Content="{Binding SettingControl}" />
+                                    Visibility="{Binding HasLabel, Converter={StaticResource BoolToVisibilityConverter}}"
+                                    Foreground="White"
+                                    Content="{Binding Label}" />
+                                <ContentControl
+                                    Content="{Binding SettingControl}" />
                             </StackPanel>
                         </DataTemplate>
                     </ItemsControl.ItemTemplate>
                 </ItemsControl>
             </StackPanel>
-            <Grid Grid.Column="1" Grid.Row="2" Background="#303030" >
-                <Grid AllowDrop="True" Drop="MainWindow_Drop">
-                    <DockingManager ActiveContent="{Binding BitmapManager.ActiveWindow, Mode=TwoWay}"
-                                           DocumentsSource="{Binding BitmapManager.Documents}">
+            <Grid
+                Grid.Column="1"
+                Grid.Row="2"
+                Background="#303030">
+                <Grid
+                    AllowDrop="True"
+                    Drop="MainWindow_Drop">
+                    <DockingManager
+                        ActiveContent="{Binding BitmapManager.ActiveWindow, Mode=TwoWay}"
+                        DocumentsSource="{Binding BitmapManager.Documents}">
                         <DockingManager.Theme>
                             <avalonDockTheme:PixiEditorDockTheme />
                         </DockingManager.Theme>
@@ -260,9 +494,14 @@
                         <avalondock:DockingManager.LayoutItemContainerStyleSelector>
                             <ui:PanelsStyleSelector>
                                 <ui:PanelsStyleSelector.DocumentTabStyle>
-                                    <Style TargetType="{x:Type avalondock:LayoutItem}">
-                                        <Setter Property="Title" Value="{Binding Model.Name}" />
-                                        <Setter Property="CloseCommand" Value="{Binding Model.RequestCloseDocumentCommand}" />
+                                    <Style
+                                        TargetType="{x:Type avalondock:LayoutItem}">
+                                        <Setter
+                                            Property="Title"
+                                            Value="{Binding Model.Name}" />
+                                        <Setter
+                                            Property="CloseCommand"
+                                            Value="{Binding Model.RequestCloseDocumentCommand}" />
                                     </Style>
                                 </ui:PanelsStyleSelector.DocumentTabStyle>
                             </ui:PanelsStyleSelector>
@@ -270,39 +509,53 @@
                         <DockingManager.LayoutItemTemplateSelector>
                             <ui:DocumentsTemplateSelector>
                                 <ui:DocumentsTemplateSelector.DocumentsViewTemplate>
-                                    <DataTemplate DataType="{x:Type dataHolders:Document}">
+                                    <DataTemplate
+                                        DataType="{x:Type dataHolders:Document}">
                                         <usercontrols:DrawingViewPort
-                                        CenterViewportTrigger="{Binding CenterViewportTrigger}"
-                                        ZoomViewportTrigger="{Binding ZoomViewportTrigger}"
-                                        GridLinesVisible="{Binding XamlAccesibleViewModel.ViewportSubViewModel.GridLinesEnabled}"
-                                        Cursor="{Binding XamlAccesibleViewModel.ToolsSubViewModel.ToolCursor}"
-                                        MiddleMouseClickedCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.PreviewMouseMiddleButtonCommand}"
-                                        MouseMoveCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.MouseMoveCommand}"
-                                        MouseDownCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.MouseDownCommand}"
-                                        MouseUpCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.MouseUpCommand}"
-                                        MouseXOnCanvas="{Binding MouseXOnCanvas, Mode=TwoWay}"
-                                        MouseYOnCanvas="{Binding MouseYOnCanvas, Mode=TwoWay}"
-                                        StylusButtonDownCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusDownCommand}"
-                                        StylusButtonUpCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusUpCommand}"
-                                        StylusGestureCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusGestureCommand}"
-                                        StylusOutOfRangeCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusOutOfRangeCommand}"
-                                        UseTouchGestures="{Binding XamlAccesibleViewModel.StylusSubViewModel.UseTouchGestures}"
-                                        IsUsingZoomTool="{Binding XamlAccesibleViewModel.ToolsSubViewModel.ActiveTool, Converter={converters:IsSpecifiedTypeConverter SpecifiedType={x:Type tools:ZoomTool}}}"
-                                        IsUsingMoveViewportTool="{Binding XamlAccesibleViewModel.ToolsSubViewModel.ActiveTool, Converter={converters:IsSpecifiedTypeConverter SpecifiedType={x:Type tools:MoveViewportTool}}}"
-                                        Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False">
+                                            CenterViewportTrigger="{Binding CenterViewportTrigger}"
+                                            ZoomViewportTrigger="{Binding ZoomViewportTrigger}"
+                                            GridLinesVisible="{Binding XamlAccesibleViewModel.ViewportSubViewModel.GridLinesEnabled}"
+                                            Cursor="{Binding XamlAccesibleViewModel.ToolsSubViewModel.ToolCursor}"
+                                            MiddleMouseClickedCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.PreviewMouseMiddleButtonCommand}"
+                                            MouseMoveCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.MouseMoveCommand}"
+                                            MouseDownCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.MouseDownCommand}"
+                                            MouseUpCommand="{Binding XamlAccesibleViewModel.IoSubViewModel.MouseUpCommand}"
+                                            MouseXOnCanvas="{Binding MouseXOnCanvas, Mode=TwoWay}"
+                                            MouseYOnCanvas="{Binding MouseYOnCanvas, Mode=TwoWay}"
+                                            StylusButtonDownCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusDownCommand}"
+                                            StylusButtonUpCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusUpCommand}"
+                                            StylusGestureCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusGestureCommand}"
+                                            StylusOutOfRangeCommand="{Binding XamlAccesibleViewModel.StylusSubViewModel.StylusOutOfRangeCommand}"
+                                            UseTouchGestures="{Binding XamlAccesibleViewModel.StylusSubViewModel.UseTouchGestures}"
+                                            IsUsingZoomTool="{Binding XamlAccesibleViewModel.ToolsSubViewModel.ActiveTool, Converter={converters:IsSpecifiedTypeConverter SpecifiedType={x:Type tools:ZoomTool}}}"
+                                            IsUsingMoveViewportTool="{Binding XamlAccesibleViewModel.ToolsSubViewModel.ActiveTool, Converter={converters:IsSpecifiedTypeConverter SpecifiedType={x:Type tools:MoveViewportTool}}}"
+                                            Stylus.IsTapFeedbackEnabled="False"
+                                            Stylus.IsTouchFeedbackEnabled="False">
                                             <i:Interaction.Triggers>
-                                                <i:EventTrigger EventName="PreviewMouseDown">
-                                                    <i:InvokeCommandAction Command="{Binding SetAsActiveOnClickCommand}"/>
+                                                <i:EventTrigger
+                                                    EventName="PreviewMouseDown">
+                                                    <i:InvokeCommandAction
+                                                        Command="{Binding SetAsActiveOnClickCommand}" />
                                                 </i:EventTrigger>
                                             </i:Interaction.Triggers>
                                             <usercontrols:DrawingViewPort.ContextMenu>
                                                 <cmds:ContextMenu>
-                                                    <MenuItem Header="_Select All" cmds:ContextMenu.Command="PixiEditor.Selection.SelectAll" />
-                                                    <MenuItem Header="_Deselect" cmds:ContextMenu.Command="PixiEditor.Selection.Clear" />
-                                                    <Separator/>
-                                                    <MenuItem Header="_Cut" cmds:ContextMenu.Command="PixiEditor.Clipboard.Cut" />
-                                                    <MenuItem Header="_Copy" cmds:ContextMenu.Command="PixiEditor.Clipboard.Copy" />
-                                                    <MenuItem Header="_Paste" cmds:ContextMenu.Command="PixiEditor.Clipboard.Paste" />
+                                                    <MenuItem
+                                                        Header="_Select All"
+                                                        cmds:ContextMenu.Command="PixiEditor.Selection.SelectAll" />
+                                                    <MenuItem
+                                                        Header="_Deselect"
+                                                        cmds:ContextMenu.Command="PixiEditor.Selection.Clear" />
+                                                    <Separator />
+                                                    <MenuItem
+                                                        Header="_Cut"
+                                                        cmds:ContextMenu.Command="PixiEditor.Clipboard.Cut" />
+                                                    <MenuItem
+                                                        Header="_Copy"
+                                                        cmds:ContextMenu.Command="PixiEditor.Clipboard.Copy" />
+                                                    <MenuItem
+                                                        Header="_Paste"
+                                                        cmds:ContextMenu.Command="PixiEditor.Clipboard.Paste" />
                                                 </cmds:ContextMenu>
                                             </usercontrols:DrawingViewPort.ContextMenu>
                                         </usercontrols:DrawingViewPort>
@@ -310,69 +563,111 @@
                                 </ui:DocumentsTemplateSelector.DocumentsViewTemplate>
                             </ui:DocumentsTemplateSelector>
                         </DockingManager.LayoutItemTemplateSelector>
-                        <avalondock:LayoutRoot x:Name="LayoutRoot">
-                            <LayoutPanel Orientation="Horizontal">
-                                <LayoutDocumentPane/>
-                                <LayoutAnchorablePaneGroup Orientation="Vertical" DockWidth="290">
+                        <avalondock:LayoutRoot
+                            x:Name="LayoutRoot">
+                            <LayoutPanel
+                                Orientation="Horizontal">
+                                <LayoutDocumentPane />
+                                <LayoutAnchorablePaneGroup
+                                    Orientation="Vertical"
+                                    DockWidth="290">
 
-                                    <LayoutAnchorablePane x:Name="colorPane">
-                                        <LayoutAnchorable ContentId="colorPicker" Title="Color Picker" CanHide="False"
-                                                             CanClose="False" CanAutoHide="False" x:Name="colorPickerPanel"
-                                                             CanDockAsTabbedDocument="False" CanFloat="True">
-                                            <usercontrols:SmallColorPicker SelectedColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}"
-                                                                         SecondaryColor="{Binding ColorsSubViewModel.SecondaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}" 
-                                                                         Style="{StaticResource DefaultColorPickerStyle}" x:Name="mainColorPicker">
+                                    <LayoutAnchorablePane
+                                        x:Name="colorPane">
+                                        <LayoutAnchorable
+                                            ContentId="colorPicker"
+                                            Title="Color Picker"
+                                            CanHide="False"
+                                            CanClose="False"
+                                            CanAutoHide="False"
+                                            x:Name="colorPickerPanel"
+                                            CanDockAsTabbedDocument="False"
+                                            CanFloat="True">
+                                            <usercontrols:SmallColorPicker
+                                                SelectedColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}"
+                                                SecondaryColor="{Binding ColorsSubViewModel.SecondaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}"
+                                                Style="{StaticResource DefaultColorPickerStyle}"
+                                                x:Name="mainColorPicker">
                                                 <i:Interaction.Behaviors>
-                                                    <behaviours:GlobalShortcutFocusBehavior/>
+                                                    <behaviours:GlobalShortcutFocusBehavior />
                                                 </i:Interaction.Behaviors>
                                             </usercontrols:SmallColorPicker>
                                         </LayoutAnchorable>
-                                        <LayoutAnchorable ContentId="colorSliders" Title="Color Sliders" CanHide="False"
-                                                      CanClose="False" CanAutoHide="False" x:Name="colorSlidersPanel"
-                                                      CanDockAsTabbedDocument="False" CanFloat="True">
-                                            <colorpicker:ColorSliders Style="{StaticResource DefaultColorPickerStyle}" 
-                                                                  ColorState="{Binding ElementName=mainColorPicker, Path=ColorState, Delay=10, Mode=TwoWay}">
+                                        <LayoutAnchorable
+                                            ContentId="colorSliders"
+                                            Title="Color Sliders"
+                                            CanHide="False"
+                                            CanClose="False"
+                                            CanAutoHide="False"
+                                            x:Name="colorSlidersPanel"
+                                            CanDockAsTabbedDocument="False"
+                                            CanFloat="True">
+                                            <colorpicker:ColorSliders
+                                                Style="{StaticResource DefaultColorPickerStyle}"
+                                                ColorState="{Binding ElementName=mainColorPicker, Path=ColorState, Delay=10, Mode=TwoWay}">
                                                 <i:Interaction.Behaviors>
-                                                    <behaviours:GlobalShortcutFocusBehavior/>
+                                                    <behaviours:GlobalShortcutFocusBehavior />
                                                 </i:Interaction.Behaviors>
                                             </colorpicker:ColorSliders>
                                         </LayoutAnchorable>
-                                        <avalondock:LayoutAnchorable ContentId="swatches" Title="Swatches" CanHide="False"
-                                                                 CanClose="False" CanAutoHide="False"
-                                                                 CanDockAsTabbedDocument="False" CanFloat="True">
+                                        <avalondock:LayoutAnchorable
+                                            ContentId="swatches"
+                                            Title="Swatches"
+                                            CanHide="False"
+                                            CanClose="False"
+                                            CanAutoHide="False"
+                                            CanDockAsTabbedDocument="False"
+                                            CanFloat="True">
                                             <usercontrols:SwatchesView
-                                            SelectSwatchCommand="{cmds:Command PixiEditor.Colors.SelectColor, UseProvided=True}" RemoveSwatchCommand="{cmds:Command PixiEditor.Colors.RemoveSwatch, UseProvided=True}"
-                                            Swatches="{Binding BitmapManager.ActiveDocument.Swatches}"/>
+                                                SelectSwatchCommand="{cmds:Command PixiEditor.Colors.SelectColor, UseProvided=True}"
+                                                RemoveSwatchCommand="{cmds:Command PixiEditor.Colors.RemoveSwatch, UseProvided=True}"
+                                                Swatches="{Binding BitmapManager.ActiveDocument.Swatches}" />
                                         </avalondock:LayoutAnchorable>
                                     </LayoutAnchorablePane>
                                     <LayoutAnchorablePane>
-                                        <LayoutAnchorable ContentId="layers" Title="Layers" CanHide="False"
-                                                         CanClose="False" CanAutoHide="False"
-                                                         CanDockAsTabbedDocument="True" CanFloat="True">
-                                            <layerUserControls:LayersManager                                            
-                                            LayerCommandsViewModel="{Binding LayersSubViewModel}"
-                                            OpacityInputEnabled="{Binding BitmapManager.ActiveDocument, 
+                                        <LayoutAnchorable
+                                            ContentId="layers"
+                                            Title="Layers"
+                                            CanHide="False"
+                                            CanClose="False"
+                                            CanAutoHide="False"
+                                            CanDockAsTabbedDocument="True"
+                                            CanFloat="True">
+                                            <layerUserControls:LayersManager
+                                                LayerCommandsViewModel="{Binding LayersSubViewModel}"
+                                                OpacityInputEnabled="{Binding BitmapManager.ActiveDocument, 
                     Converter={converters:NotNullToBoolConverter}}">
                                                 <layerUserControls:LayersManager.LayerTreeRoot>
-                                                    <MultiBinding Converter="{converters:LayersToStructuredLayersConverter}">
-                                                        <Binding Path="BitmapManager.ActiveDocument.Layers" />
-                                                        <Binding Path="BitmapManager.ActiveDocument.LayerStructure"/>
+                                                    <MultiBinding
+                                                        Converter="{converters:LayersToStructuredLayersConverter}">
+                                                        <Binding
+                                                            Path="BitmapManager.ActiveDocument.Layers" />
+                                                        <Binding
+                                                            Path="BitmapManager.ActiveDocument.LayerStructure" />
                                                     </MultiBinding>
                                                 </layerUserControls:LayersManager.LayerTreeRoot>
                                             </layerUserControls:LayersManager>
                                         </LayoutAnchorable>
-                                        <LayoutAnchorable x:Name="rawLayerAnchorable" ContentId="rawLayer" Title="Raw layers">
-                                            <layerUserControls:RawLayersViewer Layers="{Binding BitmapManager.ActiveDocument.Layers}"
-                                                                      Structure="{Binding BitmapManager.ActiveDocument.LayerStructure}"/>
+                                        <LayoutAnchorable
+                                            x:Name="rawLayerAnchorable"
+                                            ContentId="rawLayer"
+                                            Title="Raw layers">
+                                            <layerUserControls:RawLayersViewer
+                                                Layers="{Binding BitmapManager.ActiveDocument.Layers}"
+                                                Structure="{Binding BitmapManager.ActiveDocument.LayerStructure}" />
                                         </LayoutAnchorable>
                                     </LayoutAnchorablePane>
                                     <LayoutAnchorablePane>
-                                        <LayoutAnchorable ContentId="navigation" Title="Navigation" 
-                                                      CanHide="True" CanAutoHide="False"
-                                                      CanDockAsTabbedDocument="False" CanFloat="True">
-                                            <usercontrols:PreviewWindow 
-                                            Document="{Binding BitmapManager.ActiveDocument}"
-                                            PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}"/>
+                                        <LayoutAnchorable
+                                            ContentId="navigation"
+                                            Title="Navigation"
+                                            CanHide="True"
+                                            CanAutoHide="False"
+                                            CanDockAsTabbedDocument="False"
+                                            CanFloat="True">
+                                            <usercontrols:PreviewWindow
+                                                Document="{Binding BitmapManager.ActiveDocument}"
+                                                PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={StaticResource SKColorToMediaColorConverter}}" />
                                         </LayoutAnchorable>
                                     </LayoutAnchorablePane>
                                 </LayoutAnchorablePaneGroup>
@@ -382,24 +677,38 @@
                 </Grid>
             </Grid>
 
-            <Border Grid.Row="2" Grid.Column="0"
-                    Background="{StaticResource AccentColor}" Grid.RowSpan="2" CornerRadius="5,0,5,5">
-                <StackPanel Orientation="Vertical" Cursor="Arrow" >
+            <Border
+                Grid.Row="2"
+                Grid.Column="0"
+                Background="{StaticResource AccentColor}"
+                Grid.RowSpan="2"
+                CornerRadius="5,0,5,5">
+                <StackPanel
+                    Orientation="Vertical"
+                    Cursor="Arrow">
 
-                    <ItemsControl ItemsSource="{Binding ToolsSubViewModel.ToolSet}">
+                    <ItemsControl
+                        ItemsSource="{Binding ToolsSubViewModel.ToolSet}">
                         <ItemsControl.ItemTemplate>
                             <DataTemplate>
-                                <Button BorderBrush="White"
-                                        BorderThickness="{Binding IsActive, Converter={StaticResource BoolToIntConverter}}"
-                                        Style="{StaticResource ToolButtonStyle}"
-                                        Command="{cmds:Command PixiEditor.Tools.SelectTool, UseProvided=True}"
-                                        CommandParameter="{Binding}" ToolTip="{Binding Tooltip}">
+                                <Button
+                                    BorderBrush="White"
+                                    BorderThickness="{Binding IsActive, Converter={StaticResource BoolToIntConverter}}"
+                                    Style="{StaticResource ToolButtonStyle}"
+                                    Command="{cmds:Command PixiEditor.Tools.SelectTool, UseProvided=True}"
+                                    CommandParameter="{Binding}"
+                                    ToolTip="{Binding Tooltip}">
                                     <Button.Background>
-                                        <ImageBrush ImageSource="{Binding ImagePath}" Stretch="Uniform" />
+                                        <ImageBrush
+                                            ImageSource="{Binding ImagePath}"
+                                            Stretch="Uniform" />
                                     </Button.Background>
                                     <Button.Resources>
-                                        <Style TargetType="Border">
-                                            <Setter Property="CornerRadius" Value="2.5"/>
+                                        <Style
+                                            TargetType="Border">
+                                            <Setter
+                                                Property="CornerRadius"
+                                                Value="2.5" />
                                         </Style>
                                     </Button.Resources>
                                 </Button>
@@ -409,32 +718,76 @@
                 </StackPanel>
             </Border>
 
-            <Grid Grid.Row="3" Grid.Column="1">
+            <Grid
+                Grid.Row="3"
+                Grid.Column="1">
                 <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="*"/>
-                    <ColumnDefinition Width="290"/>
+                    <ColumnDefinition
+                        Width="*" />
+                    <ColumnDefinition
+                        Width="290" />
                 </Grid.ColumnDefinitions>
                 <DockPanel>
-                    <TextBlock Text="{Binding ActionDisplay}" Foreground="White" FontSize="15" Margin="10,0,0,0" VerticalAlignment="Center"/>
-                    <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
-                        <TextBlock Text="X:" Foreground="White" FontSize="16"/>
-                        <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={converters:DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
-                        <TextBlock Text="Y:" Foreground="White" FontSize="16"/>
-                        <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={converters:DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
+                    <TextBlock
+                        Text="{Binding ActionDisplay}"
+                        Foreground="White"
+                        FontSize="15"
+                        Margin="10,0,0,0"
+                        VerticalAlignment="Center" />
+                    <StackPanel
+                        DockPanel.Dock="Right"
+                        Orientation="Horizontal"
+                        HorizontalAlignment="Right"
+                        VerticalAlignment="Center">
+                        <TextBlock
+                            Text="X:"
+                            Foreground="White"
+                            FontSize="16" />
+                        <TextBlock
+                            Margin="4,0,10,0"
+                            Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={converters:DoubleToIntConverter}}"
+                            Foreground="White"
+                            FontSize="16" />
+                        <TextBlock
+                            Text="Y:"
+                            Foreground="White"
+                            FontSize="16" />
+                        <TextBlock
+                            Margin="4,0,10,0"
+                            Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={converters:DoubleToIntConverter}}"
+                            Foreground="White"
+                            FontSize="16" />
                     </StackPanel>
                 </DockPanel>
-                <StackPanel Margin="10,0,0,0" VerticalAlignment="Center" Grid.Row="3"
-                       Grid.Column="3" Orientation="Horizontal">
-                    <Button Style="{StaticResource BaseDarkButton}" 
-                    Visibility="{Binding UpdateSubViewModel.UpdateReadyToInstall, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=Hidden}" FontSize="14" Height="20" 
-                    Command="{cmds:Command PixiEditor.Restart}">Restart</Button>
-                    <TextBlock VerticalAlignment="Center" Padding="10" HorizontalAlignment="Right"
-                       Foreground="White" FontSize="14"  Text="{Binding UpdateSubViewModel.VersionText}" />
+                <StackPanel
+                    Margin="10,0,0,0"
+                    VerticalAlignment="Center"
+                    Grid.Row="3"
+                    Grid.Column="3"
+                    Orientation="Horizontal">
+                    <Button
+                        Style="{StaticResource BaseDarkButton}"
+                        Visibility="{Binding UpdateSubViewModel.UpdateReadyToInstall, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=Hidden}"
+                        FontSize="14"
+                        Height="20"
+                        Command="{cmds:Command PixiEditor.Restart}">
+                        Restart
+                    </Button>
+                    <TextBlock
+                        VerticalAlignment="Center"
+                        Padding="10"
+                        HorizontalAlignment="Right"
+                        Foreground="White"
+                        FontSize="14"
+                        Text="{Binding UpdateSubViewModel.VersionText}" />
                 </StackPanel>
             </Grid>
         </Grid>
-        <usercontrols:CommandSearchControl Visibility="{Binding SearchSubViewModel.SearchWindowOpen, Converter={BoolToVisibilityConverter}, Mode=TwoWay}"
-                                           SearchTerm="{Binding SearchSubViewModel.SearchTerm, Mode=TwoWay}"
-                                           HorizontalAlignment="Center" Height="700" MaxWidth="920"/>
+        <commandSearch:CommandSearchControl
+            Visibility="{Binding SearchSubViewModel.SearchWindowOpen, Converter={BoolToVisibilityConverter}, Mode=TwoWay}"
+            SearchTerm="{Binding SearchSubViewModel.SearchTerm, Mode=TwoWay}"
+            HorizontalAlignment="Center"
+            Height="700"
+            MaxWidth="920" />
     </Grid>
-</Window>
+</Window>

+ 179 - 0
PixiEditor/Views/UserControls/CommandSearch/CommandSearchControl.xaml

@@ -0,0 +1,179 @@
+<UserControl
+    x:Class="PixiEditor.Views.UserControls.CommandSearch.CommandSearchControl"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:PixiEditor.Views.UserControls.CommandSearch"
+    xmlns:vm="clr-namespace:PixiEditor.ViewModels"
+    xmlns:behaves="clr-namespace:PixiEditor.Helpers.Behaviours"
+    xmlns:cmdssearch="clr-namespace:PixiEditor.Models.Commands.Search"
+    xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
+    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
+    xmlns:system="clr-namespace:System;assembly=System.Runtime"
+    mc:Ignorable="d"
+    Foreground="White"
+    d:DesignHeight="450"
+    d:DesignWidth="600"
+    x:Name="uc">
+    <Grid x:Name="mainGrid">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+
+        <TextBox
+            Text="{Binding SearchTerm, ElementName=uc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+            FontSize="18"
+            Padding="5"
+            x:Name="textBox">
+            <i:Interaction.Behaviors>
+                <behaves:TextBoxFocusBehavior
+                    SelectOnMouseClick="True" />
+                <behaves:GlobalShortcutFocusBehavior />
+            </i:Interaction.Behaviors>
+            <TextBox.Style>
+                <Style
+                    TargetType="TextBox"
+                    BasedOn="{StaticResource DarkTextBoxStyle}">
+                    <Style.Resources>
+                        <Style TargetType="Border">
+                            <Setter Property="CornerRadius" Value="5,5,0,0" />
+                        </Style>
+                    </Style.Resources>
+                </Style>
+            </TextBox.Style>
+        </TextBox>
+        <Border
+            Grid.Row="1"
+            BorderThickness="1,0,1,0"
+            BorderBrush="{StaticResource BrighterAccentColor}"
+            Background="{StaticResource AccentColor}">
+            <ScrollViewer
+                VerticalScrollBarVisibility="Auto"
+                HorizontalScrollBarVisibility="Disabled">
+                <ItemsControl
+                    ItemsSource="{Binding Results, ElementName=uc}"
+                    MinWidth="400">
+                    <ItemsControl.ItemTemplate>
+                        <DataTemplate DataType="cmdssearch:SearchResult">
+                            <Button
+                                Padding="5"
+                                Height="40"
+                                BorderThickness="0"
+                                Background="Transparent"
+                                Command="{Binding ExecuteCommand}"
+                                CommandParameter="{Binding}"
+                                MouseMove="Button_MouseMove">
+                                <Button.Style>
+                                    <Style TargetType="Button">
+                                        <Setter Property="Template">
+                                            <Setter.Value>
+                                                <ControlTemplate TargetType="Button">
+                                                    <Border>
+                                                        <Border.Style>
+                                                            <Style TargetType="Border">
+                                                                <Style.Triggers>
+                                                                    <DataTrigger
+                                                                        Binding="{Binding IsSelected, Mode=TwoWay}"
+                                                                        Value="False">
+                                                                        <Setter
+                                                                            Property="Background"
+                                                                            Value="Transparent" />
+                                                                    </DataTrigger>
+                                                                    <DataTrigger
+                                                                        Binding="{Binding IsSelected, Mode=TwoWay}"
+                                                                        Value="True">
+                                                                        <Setter
+                                                                            Property="Background"
+                                                                            Value="{StaticResource BrighterAccentColor}" />
+                                                                    </DataTrigger>
+                                                                    <DataTrigger
+                                                                        Binding="{Binding CanExecute}"
+                                                                        Value="False">
+                                                                        <Setter
+                                                                            Property="Background"
+                                                                            Value="Transparent" />
+                                                                    </DataTrigger>
+                                                                </Style.Triggers>
+                                                            </Style>
+                                                        </Border.Style>
+                                                        <ContentPresenter />
+                                                    </Border>
+                                                </ControlTemplate>
+                                            </Setter.Value>
+                                        </Setter>
+                                    </Style>
+                                </Button.Style>
+                                <Button.Resources>
+                                    <Style
+                                        TargetType="TextBlock">
+                                        <Setter
+                                            Property="FontSize"
+                                            Value="16" />
+                                        <Style.Triggers>
+                                            <DataTrigger
+                                                Binding="{Binding CanExecute}"
+                                                Value="True">
+                                                <Setter
+                                                    Property="Foreground"
+                                                    Value="White" />
+                                            </DataTrigger>
+                                            <DataTrigger
+                                                Binding="{Binding CanExecute}"
+                                                Value="False">
+                                                <Setter
+                                                    Property="Foreground"
+                                                    Value="Gray" />
+                                            </DataTrigger>
+                                        </Style.Triggers>
+                                    </Style>
+                                </Button.Resources>
+                                <Grid
+                                    VerticalAlignment="Center"
+                                    x:Name="dp"
+                                    Margin="5,0,10,0">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition />
+                                        <ColumnDefinition
+                                            Width="Auto" />
+                                    </Grid.ColumnDefinitions>
+                                    <StackPanel Orientation="Horizontal">
+                                        <Border
+                                            Width="25"
+                                            Margin="0,0,5,0"
+                                            Padding="1">
+                                            <Image
+                                                HorizontalAlignment="Center"
+                                                Source="{Binding Icon}" />
+                                        </Border>
+                                        <TextBlock
+                                            VerticalAlignment="Center"
+                                            behaves:TextBlockExtensions.BindableInlines="{Binding TextBlockContent}" />
+                                    </StackPanel>
+                                    <TextBlock
+                                        Grid.Column="1"
+                                        VerticalAlignment="Center"
+                                        HorizontalAlignment="Right"
+                                        Text="{Binding Shortcut}" />
+                                </Grid>
+                            </Button>
+                        </DataTemplate>
+                    </ItemsControl.ItemTemplate>
+                </ItemsControl>
+            </ScrollViewer>
+        </Border>
+        <Border
+            Grid.Row="2"
+            BorderThickness="1"
+            BorderBrush="{StaticResource BrighterAccentColor}"
+            CornerRadius="0,0,5,5"
+            Background="{StaticResource AccentColor}">
+            <TextBlock
+                Margin="5"
+                FontSize="16"
+                Text="{Binding SelectedResult.Description, ElementName=uc, FallbackValue=''}" />
+        </Border>
+    </Grid>
+</UserControl>

+ 129 - 0
PixiEditor/Views/UserControls/CommandSearch/CommandSearchControl.xaml.cs

@@ -0,0 +1,129 @@
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.Commands;
+using PixiEditor.Models.Commands.Search;
+using PixiEditor.Models.DataHolders;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Threading;
+
+namespace PixiEditor.Views.UserControls.CommandSearch;
+#nullable enable
+public partial class CommandSearchControl : UserControl, INotifyPropertyChanged
+{
+    public static readonly DependencyProperty SearchTermProperty =
+        DependencyProperty.Register(nameof(SearchTerm), typeof(string), typeof(CommandSearchControl), new PropertyMetadata(OnSearchTermChange));
+
+    public string SearchTerm
+    {
+        get => (string)GetValue(SearchTermProperty);
+        set => SetValue(SearchTermProperty, value);
+    }
+
+    public event PropertyChangedEventHandler? PropertyChanged;
+
+    private SearchResult? selectedResult;
+
+    public SearchResult? SelectedResult
+    {
+        get => selectedResult;
+        private set
+        {
+            if (selectedResult is not null)
+                selectedResult.IsSelected = false;
+            if (value is not null)
+                value.IsSelected = true;
+            selectedResult = value;
+        }
+    }
+
+    public ObservableCollection<SearchResult> Results { get; } = new();
+
+    public CommandSearchControl()
+    {
+        InitializeComponent();
+        IsVisibleChanged += (_, args) =>
+        {
+            if (IsVisible)
+                Dispatcher.BeginInvoke(DispatcherPriority.Render, () => textBox.Focus());
+        };
+
+        textBox.LostFocus += TextBox_LostFocus;
+        textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
+        Loaded += (_, _) => UpdateSearchResults();
+    }
+
+    private void UpdateSearchResults()
+    {
+        Results.Clear();
+        List<SearchResult> newResults = CommandSearchControlHelper.ConstructSearchResults(SearchTerm);
+        foreach (var result in newResults)
+            Results.Add(result);
+        SelectedResult = Results.FirstOrDefault(x => x.CanExecute);
+    }
+
+    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
+    {
+        Visibility = Visibility.Collapsed;
+        SelectedResult = null;
+    }
+
+    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
+    {
+        e.Handled = true;
+
+        if (e.Key == Key.Enter && SelectedResult is not null)
+        {
+            Visibility = Visibility.Collapsed;
+            SelectedResult.Execute();
+        }
+        else if (e.Key is Key.Down or Key.PageDown)
+        {
+            MoveSelection(1);
+        }
+        else if (e.Key is Key.Up or Key.PageUp)
+        {
+            MoveSelection(-1);
+        }
+        else if (e.Key == Key.Escape ||
+                 CommandController.Current.Commands["PixiEditor.Search.Toggle"].Shortcut
+                 == new KeyCombination(e.Key, Keyboard.Modifiers))
+        {
+            FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
+            Keyboard.ClearFocus();
+        }
+        else
+        {
+            e.Handled = false;
+        }
+    }
+
+    private void MoveSelection(int delta)
+    {
+        if (delta == 0)
+            return;
+        if (SelectedResult is null)
+        {
+            SelectedResult = Results.Where(x => x.CanExecute).First();
+            return;
+        }
+
+        int newIndex = Results.IndexOf(SelectedResult) + delta;
+        newIndex = (newIndex % Results.Count + Results.Count) % Results.Count;
+
+        SelectedResult = delta > 0 ? Results.IndexOrNext(x => x.CanExecute, newIndex) : Results.IndexOrPrevious(x => x.CanExecute, newIndex);
+    }
+
+    private void Button_MouseMove(object sender, MouseEventArgs e)
+    {
+        var searchResult = ((Button)sender).DataContext as SearchResult;
+        SelectedResult = searchResult;
+    }
+
+    private static void OnSearchTermChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        ((CommandSearchControl)d).UpdateSearchResults();
+    }
+}

+ 65 - 0
PixiEditor/Views/UserControls/CommandSearch/CommandSearchControlHelper.cs

@@ -0,0 +1,65 @@
+using System.Text.RegularExpressions;
+using PixiEditor.Models.Commands;
+using PixiEditor.Models.Commands.Search;
+using PixiEditor.ViewModels;
+using SkiaSharp;
+
+namespace PixiEditor.Views.UserControls.CommandSearch;
+
+#nullable enable
+internal static class CommandSearchControlHelper
+{
+    public static List<SearchResult> ConstructSearchResults(string query)
+    {
+        if (string.IsNullOrWhiteSpace(query))
+        {
+            // show all recently opened
+            return ViewModelMain.Current.FileSubViewModel.RecentlyOpened
+                .Select(file => (SearchResult)new FileSearchResult(file.FilePath)
+                {
+                    SearchTerm = query
+                }).ToList();
+        }
+
+        var controller = CommandController.Current;
+        List<SearchResult> newResults = new();
+
+        // add matching colors
+        if (query.StartsWith('#'))
+        {
+            if (SKColor.TryParse(query, out SKColor color))
+            {
+                newResults.Add(new ColorSearchResult(color)
+                {
+                    SearchTerm = query
+                });
+            }
+        }
+
+        // add matching commands
+        newResults.AddRange(
+            controller.Commands
+                .Where(x => x.Description.Contains(query, StringComparison.OrdinalIgnoreCase))
+                .OrderByDescending(x => x.Description.Contains($" {query} ", StringComparison.OrdinalIgnoreCase))
+                .Take(12)
+                .Select(command => new CommandSearchResult(command)
+                {
+                    SearchTerm = query,
+                    Match = Match(command.Description)
+                }));
+
+        // add matching recent files
+        newResults.AddRange(
+            ViewModelMain.Current.FileSubViewModel.RecentlyOpened
+                .Where(x => x.FilePath.Contains(query))
+                .Select(file => new FileSearchResult(file.FilePath)
+                {
+                    SearchTerm = query,
+                    Match = Match(file.FilePath)
+                }));
+
+        Match Match(string text) => Regex.Match(text, $"(.*)({Regex.Escape(query)})(.*)", RegexOptions.IgnoreCase);
+
+        return newResults;
+    }
+}

+ 0 - 120
PixiEditor/Views/UserControls/CommandSearchControl.xaml

@@ -1,120 +0,0 @@
-<UserControl x:Class="PixiEditor.Views.UserControls.CommandSearchControl"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-             xmlns:local="clr-namespace:PixiEditor.Views.UserControls"
-             xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-             xmlns:behaves="clr-namespace:PixiEditor.Helpers.Behaviours"
-             xmlns:cmdssearch="clr-namespace:PixiEditor.Models.Commands.Search"
-             xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
-             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
-             mc:Ignorable="d"
-             Foreground="White"
-             d:DesignHeight="450" d:DesignWidth="600"
-             x:Name="uc">
-    <Grid DataContext="{DynamicResource viewModel}" x:Name="mainGrid">
-        <Grid.Resources>
-            <ResourceDictionary>
-                <vm:CommandSearchViewModel x:Key="viewModel"/>
-            </ResourceDictionary>
-        </Grid.Resources>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto"/>
-            <RowDefinition Height="*"/>
-            <RowDefinition Height="Auto"/>
-        </Grid.RowDefinitions>
-
-        <TextBox Text="{Binding SearchTerm, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="18" Padding="5"
-                 x:Name="textBox">
-            <i:Interaction.Behaviors>
-                <behaves:TextBoxFocusBehavior SelectOnMouseClick="True" />
-                <behaves:GlobalShortcutFocusBehavior/>
-            </i:Interaction.Behaviors>
-            <TextBox.Style>
-                <Style TargetType="TextBox" BasedOn="{StaticResource DarkTextBoxStyle}">
-                    <Style.Resources>
-                        <Style TargetType="Border">
-                            <Setter Property="CornerRadius" Value="5,5,0,0"/>
-                        </Style>
-                    </Style.Resources>
-                </Style>
-            </TextBox.Style>
-        </TextBox>
-        <Border Grid.Row="1" BorderThickness="1,0,1,0" BorderBrush="{StaticResource BrighterAccentColor}"
-                Background="{StaticResource AccentColor}">
-            <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
-                <ItemsControl ItemsSource="{Binding Results}" MinWidth="400">
-                    <ItemsControl.ItemTemplate>
-                        <DataTemplate DataType="cmdssearch:SearchTerm">
-                            <Button Padding="5" Height="40" BorderThickness="0" Background="Transparent"
-                                Command="{Binding ExecuteCommand}"
-                                CommandParameter="{Binding}"
-                                MouseMove="Button_MouseMove">
-                                <Button.Style>
-                                    <Style TargetType="Button">
-                                        <Setter Property="Template">
-                                            <Setter.Value>
-                                                <ControlTemplate TargetType="Button">
-                                                    <Border>
-                                                        <Border.Style>
-                                                            <Style TargetType="Border">
-                                                                <Style.Triggers>
-                                                                    <DataTrigger Binding="{Binding IsSelected, Mode=TwoWay}" Value="False">
-                                                                        <Setter Property="Background" Value="Transparent"/>
-                                                                    </DataTrigger>
-                                                                    <DataTrigger Binding="{Binding IsSelected, Mode=TwoWay}" Value="True">
-                                                                        <Setter Property="Background" Value="{StaticResource BrighterAccentColor}"/>
-                                                                    </DataTrigger>
-                                                                    <DataTrigger Binding="{Binding CanExecute}" Value="False">
-                                                                        <Setter Property="Background" Value="Transparent"/>
-                                                                    </DataTrigger>
-                                                                </Style.Triggers>
-                                                            </Style>
-                                                        </Border.Style>
-                                                        <ContentPresenter/>
-                                                    </Border>
-                                                </ControlTemplate>
-                                            </Setter.Value>
-                                        </Setter>
-                                    </Style>
-                                </Button.Style>
-                                <Button.Resources>
-                                    <Style TargetType="TextBlock">
-                                        <Setter Property="FontSize" Value="16"/>
-                                        <Style.Triggers>
-                                            <DataTrigger Binding="{Binding CanExecute}" Value="True">
-                                                <Setter Property="Foreground" Value="White"/>
-                                            </DataTrigger>
-                                            <DataTrigger Binding="{Binding CanExecute}" Value="False">
-                                                <Setter Property="Foreground" Value="Gray"/>
-                                            </DataTrigger>
-                                        </Style.Triggers>
-                                    </Style>
-                                </Button.Resources>
-                                <Grid VerticalAlignment="Center" x:Name="dp" Margin="5,0,10,0">
-                                    <Grid.ColumnDefinitions>
-                                        <ColumnDefinition/>
-                                        <ColumnDefinition Width="Auto"/>
-                                    </Grid.ColumnDefinitions>
-                                    <StackPanel Orientation="Horizontal">
-                                        <Border Width="25" Margin="0,0,5,0" Padding="1">
-                                            <Image HorizontalAlignment="Center" Source="{Binding Icon}"/>
-                                        </Border>
-                                        <TextBlock VerticalAlignment="Center"
-                                               behaves:TextBlockExtensions.BindableInlines="{Binding TextBlockContent}"/>
-                                    </StackPanel>
-                                    <TextBlock Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" Text="{Binding Shortcut}"/>
-                                </Grid>
-                            </Button>
-                        </DataTemplate>
-                    </ItemsControl.ItemTemplate>
-                </ItemsControl>
-            </ScrollViewer>
-        </Border>
-        <Border Grid.Row="2" BorderThickness="1" BorderBrush="{StaticResource BrighterAccentColor}"
-                CornerRadius="0,0,5,5" Background="{StaticResource AccentColor}">
-            <TextBlock Margin="5" FontSize="16" Text="{Binding SelectedResult.Description}"/>
-        </Border>
-    </Grid>
-</UserControl>

+ 0 - 125
PixiEditor/Views/UserControls/CommandSearchControl.xaml.cs

@@ -1,125 +0,0 @@
-using PixiEditor.Models.Commands;
-using PixiEditor.Models.Commands.Search;
-using PixiEditor.ViewModels;
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Controls;
-using PixiEditor.Models.DataHolders;
-using System.Windows.Input;
-using System.Windows.Threading;
-using PixiEditor.Helpers.Extensions;
-
-namespace PixiEditor.Views.UserControls
-{
-    /// <summary>
-    /// Interaction logic for CommandSearchControl.xaml
-    /// </summary>
-    public partial class CommandSearchControl : UserControl
-    {
-        private readonly CommandSearchViewModel _viewModel;
-
-        public static readonly DependencyProperty SearchTermProperty =
-            DependencyProperty.Register(nameof(SearchTerm), typeof(string), typeof(CommandSearchControl), new(SearchTermPropertyChanged));
-
-        public string SearchTerm
-        {
-            get => _viewModel.SearchTerm;
-            set => _viewModel.SearchTerm = value;
-        }
-
-        public CommandSearchControl()
-        {
-            InitializeComponent();
-            _viewModel = mainGrid.DataContext as CommandSearchViewModel;
-            _viewModel.PropertyChanged += (s, e) =>
-            {
-                SetValue(SearchTermProperty, _viewModel.SearchTerm);
-            };
-
-            var descriptor = DependencyPropertyDescriptor.FromProperty(VisibilityProperty, typeof(UserControl));
-            descriptor.AddValueChanged(this, (sender, e) =>
-            {
-                if (Visibility == Visibility.Visible)
-                {
-                    Action action = () =>
-                    {
-                        textBox.Focus();
-                    };
-                    Application.Current.MainWindow.Dispatcher.Invoke(DispatcherPriority.Background, action);
-                }
-            });
-
-            textBox.LostFocus += TextBox_LostFocus;
-            textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
-        }
-
-        private void TextBox_LostFocus(object sender, RoutedEventArgs e)
-        {
-            Visibility = Visibility.Collapsed;
-            _viewModel.SelectedResult = null;
-        }
-
-        private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
-        {
-            e.Handled = true;
-
-            if (e.Key == Key.Enter)
-            {
-                Visibility = Visibility.Collapsed;
-                _viewModel.SelectedResult.Execute();
-            }
-            else if (e.Key == Key.Down || e.Key == Key.PageDown)
-            {
-                var newIndex = _viewModel.Results.IndexOf(_viewModel.SelectedResult) + 1;
-                if (newIndex >= _viewModel.Results.Count)
-                {
-                    newIndex = 0;
-                }
-
-                _viewModel.SelectedResult = _viewModel.Results.IndexOrNext(x => x.CanExecute, newIndex);
-            }
-            else if (e.Key == Key.Up || e.Key == Key.PageUp)
-            {
-                var newIndex = _viewModel.Results.IndexOf(_viewModel.SelectedResult);
-                if (newIndex == -1)
-                {
-                    newIndex = 0;
-                }
-                if (newIndex == 0)
-                {
-                    newIndex = _viewModel.Results.Count - 1;
-                }
-                else
-                {
-                    newIndex--;
-                }
-
-                _viewModel.SelectedResult = _viewModel.Results.IndexOrPrevious(x => x.CanExecute, newIndex);
-            }
-            else if (CommandController.Current.Commands["PixiEditor.Search.Toggle"].Shortcut
-                == new KeyCombination(e.Key, Keyboard.Modifiers) || e.Key == Key.Escape)
-            {
-                FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
-                Keyboard.ClearFocus();
-            }
-            else
-            {
-                e.Handled = false;
-            }
-        }
-
-        private static void SearchTermPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
-        {
-            var control = dp as CommandSearchControl;
-
-            control._viewModel.SearchTerm = e.NewValue as string;
-        }
-
-        private void Button_MouseMove(object sender, MouseEventArgs e)
-        {
-            var searchResult = (sender as Button).DataContext as SearchResult;
-
-            _viewModel.SelectedResult = searchResult;
-        }
-    }
-}