From a1e1d663c310dfff4a52217ae803c1a7c710886c Mon Sep 17 00:00:00 2001 From: Divyansh Srivastava Date: Tue, 12 May 2020 15:42:21 -0700 Subject: [PATCH] Migrate Search box to WPF control (#2917) * Replaced UWP searchbox with WPF * Updated foreground color scheme for textbox * Add focus on visibility changed * Updated initial hiding of window * Fixed list box border * vis issue on start, fixing border * Revert "Merge branch 'somil55/MigrateSearchBoxToWPF' into fewTweaks" This reverts commit 3525171621f3fb5f946d4adea643c8f85acfd3d3, reversing changes made to b5daffca556f23341d27b82b05db07a83bcdfbc2. * Remove change in startup visibility Co-authored-by: Clint Rutkas --- .../PowerLauncher.UI/LauncherControl.xaml | 2 - .../PowerLauncher.UI/LauncherControl.xaml.cs | 40 +-- .../launcher/PowerLauncher.UI/ResultList.xaml | 3 +- .../PowerLauncher.UI/ResultList.xaml.cs | 50 +++- .../PowerLauncher/LauncherControl.xaml | 273 ++++++++++++++++++ .../PowerLauncher/LauncherControl.xaml.cs | 26 ++ .../launcher/PowerLauncher/MainWindow.xaml | 9 +- .../launcher/PowerLauncher/MainWindow.xaml.cs | 224 +++++++------- .../launcher/PowerLauncher/ResultListBox.xaml | 118 -------- .../PowerLauncher/ResultListBox.xaml.cs | 58 ---- 10 files changed, 458 insertions(+), 345 deletions(-) create mode 100644 src/modules/launcher/PowerLauncher/LauncherControl.xaml create mode 100644 src/modules/launcher/PowerLauncher/LauncherControl.xaml.cs delete mode 100644 src/modules/launcher/PowerLauncher/ResultListBox.xaml delete mode 100644 src/modules/launcher/PowerLauncher/ResultListBox.xaml.cs diff --git a/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml b/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml index 7a72b39db4..7665796629 100644 --- a/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml +++ b/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml @@ -5,8 +5,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - ActualThemeChanged="UserControl_ActualThemeChanged" - Loaded="UserControl_Loaded" d:DesignHeight="300" d:DesignWidth="720"> diff --git a/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml.cs b/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml.cs index 1713974da9..3a0838f092 100644 --- a/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml.cs +++ b/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml.cs @@ -1,50 +1,12 @@ -using System.ComponentModel; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; namespace PowerLauncher.UI { - public sealed partial class LauncherControl : UserControl, INotifyPropertyChanged + public sealed partial class LauncherControl : UserControl { - private Brush _borderBrush; - public LauncherControl() { InitializeComponent(); } - - public Brush SolidBorderBrush - { - get { return _borderBrush; } - set { Set(ref _borderBrush, value); } - } - - private void Set(ref T storage, T value, [CallerMemberName]string propertyName = null) - { - if (Equals(storage, value)) - { - return; - } - - storage = value; - OnPropertyChanged(propertyName); - } - - private void UserControl_ActualThemeChanged(FrameworkElement sender, object args) - { - SolidBorderBrush = Application.Current.Resources["SystemChromeLow"] as SolidColorBrush; - } - - private void UserControl_Loaded(object sender, RoutedEventArgs e) - { - SolidBorderBrush = Application.Current.Resources["SystemChromeLow"] as SolidColorBrush; - } - - public event PropertyChangedEventHandler PropertyChanged; - - private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } \ No newline at end of file diff --git a/src/modules/launcher/PowerLauncher.UI/ResultList.xaml b/src/modules/launcher/PowerLauncher.UI/ResultList.xaml index cff616a3a6..0d26461f78 100644 --- a/src/modules/launcher/PowerLauncher.UI/ResultList.xaml +++ b/src/modules/launcher/PowerLauncher.UI/ResultList.xaml @@ -5,10 +5,11 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - xmlns:ToolkitBehaviors="using:Microsoft.Toolkit.Uwp.UI.Animations.Behaviors" xmlns:Core="using:Microsoft.Xaml.Interactions.Core" xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters" + Loaded="UserControl_Loaded" + ActualThemeChanged="UserControl_ActualThemeChanged" d:DesignHeight="300" d:DesignWidth="720"> diff --git a/src/modules/launcher/PowerLauncher.UI/ResultList.xaml.cs b/src/modules/launcher/PowerLauncher.UI/ResultList.xaml.cs index c5b95acbca..2e7ac174c0 100644 --- a/src/modules/launcher/PowerLauncher.UI/ResultList.xaml.cs +++ b/src/modules/launcher/PowerLauncher.UI/ResultList.xaml.cs @@ -1,17 +1,26 @@ using Microsoft.PowerLauncher.Telemetry; using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Foundation; +using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; - +using Windows.UI.Xaml.Media; + namespace PowerLauncher.UI { public sealed partial class ResultList : UserControl { + private Brush _borderBrush; + + private Brush _primaryTextColor; + private LauncherResultActionEvent.TriggerType triggerType = LauncherResultActionEvent.TriggerType.Click; + public ResultList() { InitializeComponent(); @@ -41,5 +50,44 @@ namespace PowerLauncher.UI //Restore the trigger type back to click triggerType = LauncherResultActionEvent.TriggerType.Click; } + + public Brush SolidBorderBrush + { + get { return _borderBrush; } + set { Set(ref _borderBrush, value); } + } + + public Brush PrimaryTextColor + { + get { return _primaryTextColor; } + set { Set(ref _primaryTextColor, value); } + } + + private void Set(ref T storage, T value, [CallerMemberName]string propertyName = null) + { + if (Equals(storage, value)) + { + return; + } + + storage = value; + OnPropertyChanged(propertyName); + } + + private void UserControl_ActualThemeChanged(FrameworkElement sender, object args) + { + SolidBorderBrush = Application.Current.Resources["SystemChromeLow"] as SolidColorBrush; + PrimaryTextColor = Application.Current.Resources["PrimaryTextColor"] as SolidColorBrush; + } + + private void UserControl_Loaded(object sender, RoutedEventArgs e) + { + SolidBorderBrush = Application.Current.Resources["SystemChromeLow"] as SolidColorBrush; + PrimaryTextColor = Application.Current.Resources["PrimaryTextColor"] as SolidColorBrush; + } + + public event PropertyChangedEventHandler PropertyChanged; + + private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } diff --git a/src/modules/launcher/PowerLauncher/LauncherControl.xaml b/src/modules/launcher/PowerLauncher/LauncherControl.xaml new file mode 100644 index 0000000000..bad7fa0550 --- /dev/null +++ b/src/modules/launcher/PowerLauncher/LauncherControl.xaml @@ -0,0 +1,273 @@ + + + #66000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --> + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/modules/launcher/PowerLauncher/LauncherControl.xaml.cs b/src/modules/launcher/PowerLauncher/LauncherControl.xaml.cs new file mode 100644 index 0000000000..bddbf07b9c --- /dev/null +++ b/src/modules/launcher/PowerLauncher/LauncherControl.xaml.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace PowerLauncher +{ + /// + /// Interaction logic for ResultList.xaml + /// + public partial class LauncherControl : UserControl + { + public LauncherControl() + { + InitializeComponent(); + } + } +} diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml b/src/modules/launcher/PowerLauncher/MainWindow.xaml index c11d25e326..440439c890 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml @@ -6,6 +6,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:xaml="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost" + xmlns:local="clr-namespace:PowerLauncher" Title="PowerLaunch" Topmost="True" SizeToContent="Height" @@ -30,7 +31,7 @@ MouseDown="OnMouseDown"> - + - + DelayedCheck(latestTimeOfTyping, text)); + s_lastTimeOfTyping = latestTimeOfTyping; + } } private void InitializePosition() @@ -102,6 +131,41 @@ namespace PowerLauncher _settings.WindowLeft = Left; } + private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(MainViewModel.MainWindowVisibility)) + { + if (Visibility == Visibility.Visible) + { + _deletePressed = false; + _firstDeleteTimer.Start(); + Activate(); + UpdatePosition(); + SearchBox.QueryTextBox.Focus(); + _settings.ActivateTimes++; + if (!_viewModel.LastQuerySelected) + { + _viewModel.LastQuerySelected = true; + } + + // to select the text so that the user can continue to type + if (!String.IsNullOrEmpty(SearchBox.QueryTextBox.Text)) + { + SearchBox.QueryTextBox.SelectAll(); + } + } + else + { + _firstDeleteTimer.Stop(); + } + } + else if (e.PropertyName == nameof(MainViewModel.SystemQueryText)) + { + this._isTextSetProgramatically = true; + SearchBox.QueryTextBox.Text = _viewModel.SystemQueryText; + } + } + private void OnMouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) DragMove(); @@ -206,72 +270,37 @@ namespace PowerLauncher return top; } - private PowerLauncher.UI.LauncherControl _launcher = null; - private void WindowsXamlHostTextBox_ChildChanged(object sender, EventArgs ev) - { - if (sender == null) return; - - var host = (WindowsXamlHost)sender; - _launcher = (PowerLauncher.UI.LauncherControl)host.Child; - _launcher.DataContext = _viewModel; - _launcher.KeyDown += _launcher_KeyDown; - _launcher.QueryTextBox.TextChanging += QueryTextBox_TextChanging; - _launcher.QueryTextBox.Loaded += TextBox_Loaded; - _launcher.PropertyChanged += UserControl_PropertyChanged; - _viewModel.PropertyChanged += (o, e) => - { - if (e.PropertyName == nameof(MainViewModel.MainWindowVisibility)) - { - if (Visibility == System.Windows.Visibility.Visible) - { - _deletePressed = false; - _firstDeleteTimer.Start(); - Activate(); - UpdatePosition(); - _settings.ActivateTimes++; - if (!_viewModel.LastQuerySelected) - { - _viewModel.LastQuerySelected = true; - } - - // to select the text so that the user can continue to type - if(!String.IsNullOrEmpty(_launcher.QueryTextBox.Text)) - { - _launcher.QueryTextBox.SelectAll(); - } - } - else - { - _firstDeleteTimer.Stop(); - } - } - else if(e.PropertyName == nameof(MainViewModel.SystemQueryText)) - { - this._isTextSetProgramatically = true; - _launcher.QueryTextBox.Text = _viewModel.SystemQueryText; - } - }; - } - private void UserControl_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "SolidBorderBrush") { - if (_launcher != null) + if (_resultList != null) { - Windows.UI.Xaml.Media.SolidColorBrush uwpBrush = _launcher.SolidBorderBrush as Windows.UI.Xaml.Media.SolidColorBrush; - System.Windows.Media.Color borderColor = System.Windows.Media.Color.FromArgb(uwpBrush.Color.A, uwpBrush.Color.R, uwpBrush.Color.G, uwpBrush.Color.B); - this.SearchBoxBorder.BorderBrush = new SolidColorBrush(borderColor); - this.ListBoxBorder.BorderBrush = new SolidColorBrush(borderColor); + Windows.UI.Xaml.Media.SolidColorBrush borderBrush = _resultList.SolidBorderBrush as Windows.UI.Xaml.Media.SolidColorBrush; + Color borderColor = Color.FromArgb(borderBrush.Color.A, borderBrush.Color.R, borderBrush.Color.G, borderBrush.Color.B); + SolidColorBrush solidBorderBrush = new SolidColorBrush(borderColor); + + this.SearchBoxBorder.BorderBrush = solidBorderBrush; + this.SearchBoxBorder.Background = solidBorderBrush; + this.ListBoxBorder.BorderBrush = solidBorderBrush; + this.ListBoxBorder.Background = solidBorderBrush; + } } - } + else if(e.PropertyName == "PrimaryTextColor") + { + if (_resultList != null) + { + Windows.UI.Xaml.Media.SolidColorBrush primaryTextBrush = _resultList.PrimaryTextColor as Windows.UI.Xaml.Media.SolidColorBrush; + Color primaryTextColor = Color.FromArgb(primaryTextBrush.Color.A, primaryTextBrush.Color.R, primaryTextBrush.Color.G, primaryTextBrush.Color.B); + SolidColorBrush solidPrimaryTextBrush = new SolidColorBrush(primaryTextColor); - private void TextBox_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) - { - TextBox tb = (TextBox)sender; - tb.Focus(FocusState.Programmatic); - _viewModel.MainWindowVisibility = System.Windows.Visibility.Collapsed; + this.SearchBox.QueryTextBox.Foreground = solidPrimaryTextBrush; + this.SearchBox.QueryTextBox.CaretBrush = solidPrimaryTextBrush; + this.SearchBox.AutoCompleteTextBlock.Foreground = solidPrimaryTextBrush; + this.SearchBox.SearchLogo.Foreground = solidPrimaryTextBrush; + } + } } private UI.ResultList _resultList = null; @@ -286,6 +315,7 @@ namespace PowerLauncher _resultList.SuggestionsList.Loaded += SuggestionsList_Loaded; _resultList.SuggestionsList.SelectionChanged += SuggestionsList_SelectionChanged; _resultList.SuggestionsList.ContainerContentChanging += SuggestionList_UpdateListSize; + _resultList.PropertyChanged += UserControl_PropertyChanged; } private void SuggestionsList_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) @@ -293,49 +323,43 @@ namespace PowerLauncher _viewModel.ColdStartFix(); } - private bool IsKeyDown(VirtualKey key) + private void _launcher_KeyDown(object sender, KeyEventArgs e) { - var keyState = CoreWindow.GetForCurrentThread().GetKeyState(key); - return (keyState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down; - } - - private void _launcher_KeyDown(object sender, KeyRoutedEventArgs e) - { - if (e.Key == VirtualKey.Tab && IsKeyDown(VirtualKey.Shift)) + if (e.Key == Key.Tab && Keyboard.IsKeyDown(Key.LeftShift)) { _viewModel.SelectPrevTabItemCommand.Execute(null); UpdateTextBoxToSelectedItem(); e.Handled = true; } - else if (e.Key == VirtualKey.Tab) + else if (e.Key == Key.Tab) { _viewModel.SelectNextTabItemCommand.Execute(null); UpdateTextBoxToSelectedItem(); e.Handled = true; } - else if (e.Key == VirtualKey.Down) + else if (e.Key == Key.Down) { _viewModel.SelectNextItemCommand.Execute(null); UpdateTextBoxToSelectedItem(); e.Handled = true; } - else if (e.Key == VirtualKey.Up) + else if (e.Key == Key.Up) { _viewModel.SelectPrevItemCommand.Execute(null); UpdateTextBoxToSelectedItem(); e.Handled = true; } - else if (e.Key == VirtualKey.PageDown) + else if (e.Key == Key.PageDown) { _viewModel.SelectNextPageCommand.Execute(null); e.Handled = true; } - else if (e.Key == VirtualKey.PageUp) + else if (e.Key == Key.PageUp) { _viewModel.SelectPrevPageCommand.Execute(null); e.Handled = true; } - else if( e.Key == VirtualKey.Back) + else if( e.Key == Key.Back) { _deletePressed = true; } @@ -350,7 +374,7 @@ namespace PowerLauncher } } - private void SuggestionsList_Tapped(object sender, TappedRoutedEventArgs e) + private void SuggestionsList_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { var result = ((Windows.UI.Xaml.FrameworkElement)e.OriginalSource).DataContext; if (result != null) @@ -370,7 +394,7 @@ namespace PowerLauncher * when the number of elements were lesser than the maximum capacity of the list (ie. 4). * Binding Height/MaxHeight Properties did not solve this issue. */ - private void SuggestionList_UpdateListSize(object sender, ContainerContentChangingEventArgs e) + private void SuggestionList_UpdateListSize(object sender, Windows.UI.Xaml.Controls.ContainerContentChangingEventArgs e) { int count = _viewModel?.Results?.Results.Count ?? 0; int displayCount = Math.Min(count, _settings.MaxResultsToShow); @@ -388,7 +412,7 @@ namespace PowerLauncher // To populate the AutoCompleteTextBox as soon as the selection is changed or set. // Setting it here instead of when the text is changed as there is a delay in executing the query and populating the result - _launcher.AutoCompleteTextBlock.Text = ListView_FirstItem(_viewModel.QueryText); + SearchBox.AutoCompleteTextBlock.Text = ListView_FirstItem(_viewModel.QueryText); } private const int millisecondsToWait = 200; @@ -412,49 +436,9 @@ namespace PowerLauncher return String.Empty; } - private void QueryTextBox_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args) - { - ClearAllQueryTextChangedHanlders(); - - if(this._isTextSetProgramatically) - { - this._launcher.QueryTextBox.TextChanged += QueryTextBox_TextChangedProgramatically; - } - else - { - this._launcher.QueryTextBox.TextChanged += QueryTextBox_TextChangedByUserInput; - } - } - - private void ClearAllQueryTextChangedHanlders() - { - this._launcher.QueryTextBox.TextChanged -= QueryTextBox_TextChangedProgramatically; - this._launcher.QueryTextBox.TextChanged -= QueryTextBox_TextChangedByUserInput; - } - private void QueryTextBox_TextChangedProgramatically(object sender, Windows.UI.Xaml.Controls.TextChangedEventArgs e) { - var textBox = ((Windows.UI.Xaml.Controls.TextBox)sender); - textBox.SelectionStart = textBox.Text.Length; - - this._isTextSetProgramatically = false; - } - - - private void QueryTextBox_TextChangedByUserInput(object sender, Windows.UI.Xaml.Controls.TextChangedEventArgs e) - { - var text = ((Windows.UI.Xaml.Controls.TextBox)sender).Text; - //To clear the auto-suggest immediately instead of waiting for selection changed - if (text == String.Empty) - { - _launcher.AutoCompleteTextBlock.Text = String.Empty; - } - - _viewModel.QueryText = text; - var latestTimeOfTyping = DateTime.Now; - - Task.Run(() => DelayedCheck(latestTimeOfTyping, text)); - s_lastTimeOfTyping = latestTimeOfTyping; + } private async Task DelayedCheck(DateTime latestTimeOfTyping, string text) diff --git a/src/modules/launcher/PowerLauncher/ResultListBox.xaml b/src/modules/launcher/PowerLauncher/ResultListBox.xaml deleted file mode 100644 index 31562e3dfc..0000000000 --- a/src/modules/launcher/PowerLauncher/ResultListBox.xaml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/modules/launcher/PowerLauncher/ResultListBox.xaml.cs b/src/modules/launcher/PowerLauncher/ResultListBox.xaml.cs deleted file mode 100644 index a63e95f3fb..0000000000 --- a/src/modules/launcher/PowerLauncher/ResultListBox.xaml.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; - -namespace PowerLauncher -{ - public partial class ResultListBox - { - protected object _lock = new object(); - private Point _lastpos; - private ListBoxItem curItem = null; - public ResultListBox() - { - InitializeComponent(); - } - - private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (e.AddedItems.Count > 0 && e.AddedItems[0] != null) - { - ScrollIntoView(e.AddedItems[0]); - } - } - - private void OnMouseEnter(object sender, MouseEventArgs e) - { - lock(_lock) - { - curItem = (ListBoxItem)sender; - var p = e.GetPosition((IInputElement)sender); - _lastpos = p; - } - } - - private void OnMouseMove(object sender, MouseEventArgs e) - { - lock(_lock) - { - var p = e.GetPosition((IInputElement)sender); - if (_lastpos != p) - { - ((ListBoxItem)sender).IsSelected = true; - } - } - } - - private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e) - { - lock(_lock) - { - if (curItem != null) - { - curItem.IsSelected = true; - } - } - } - } -}