diff --git a/Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs b/Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs deleted file mode 100644 index acd9d9eb733..00000000000 --- a/Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.ComponentModel; - -namespace Flow.Launcher.Core.Resource -{ - public class LocalizedDescriptionAttribute : DescriptionAttribute - { - private readonly string _resourceKey; - - public LocalizedDescriptionAttribute(string resourceKey) - { - _resourceKey = resourceKey; - } - - public override string Description - { - get - { - string description = PublicApi.Instance.GetTranslation(_resourceKey); - return string.IsNullOrWhiteSpace(description) ? - string.Format("[[{0}]]", _resourceKey) : description; - } - } - } -} diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index d1f7da2a2fe..c3bb6190f01 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -449,9 +449,19 @@ public bool ChangeTheme(string theme = null) } return false; } - catch (XamlParseException) + catch (XamlParseException e) { - _api.LogError(ClassName, $"Theme <{theme}> fail to parse"); + _api.LogException(ClassName, $"Theme <{theme}> fail to parse xaml", e); + if (theme != Constant.DefaultTheme) + { + _api.ShowMsgBox(Localize.theme_load_failure_parse_error(theme)); + ChangeTheme(Constant.DefaultTheme); + } + return false; + } + catch (Exception e) + { + _api.LogException(ClassName, $"Theme <{theme}> fail to load", e); if (theme != Constant.DefaultTheme) { _api.ShowMsgBox(Localize.theme_load_failure_parse_error(theme)); diff --git a/Flow.Launcher/App.xaml b/Flow.Launcher/App.xaml index 565bbe3c74c..e922cd55842 100644 --- a/Flow.Launcher/App.xaml +++ b/Flow.Launcher/App.xaml @@ -2,7 +2,8 @@ x:Class="Flow.Launcher.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:ui="http://schemas.modernwpf.com/2019" + xmlns:sys="clr-namespace:System;assembly=mscorlib" + xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" ShutdownMode="OnMainWindowClose" Startup="OnStartup"> @@ -10,17 +11,17 @@ - + - + - + @@ -33,6 +34,15 @@ + + + 2 + 0 + 0 + 40 + 0 + 36 + \ No newline at end of file diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 58f8438d23b..1ca3ce2c637 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -22,6 +22,7 @@ using Flow.Launcher.Plugin; using Flow.Launcher.SettingPages.ViewModels; using Flow.Launcher.ViewModel; +using iNKORE.UI.WPF.Modern.Common; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.VisualStudio.Threading; @@ -56,6 +57,9 @@ public partial class App : IDisposable, ISingleInstanceApp public App() { + // Do not use bitmap cache since it can cause WPF second window freezing issue + ShadowAssist.UseBitmapCache = false; + // Initialize settings _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); diff --git a/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs b/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs index 41e87991317..82da6d936b3 100644 --- a/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs +++ b/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs @@ -5,7 +5,7 @@ namespace Flow.Launcher.Converters; -internal class BoolToIMEConversionModeConverter : IValueConverter +public class BoolToIMEConversionModeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { @@ -22,7 +22,7 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu } } -internal class BoolToIMEStateConverter : IValueConverter +public class BoolToIMEStateConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/Flow.Launcher/Converters/CornerRadiusFilterConverter.cs b/Flow.Launcher/Converters/CornerRadiusFilterConverter.cs new file mode 100644 index 00000000000..fd43cafacac --- /dev/null +++ b/Flow.Launcher/Converters/CornerRadiusFilterConverter.cs @@ -0,0 +1,91 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace Flow.Launcher.Converters; + +public class CornerRadiusFilterConverter : DependencyObject, IValueConverter +{ + public CornerRadiusFilterKind Filter { get; set; } + + public double Scale { get; set; } = 1.0; + + public static CornerRadius Convert(CornerRadius radius, CornerRadiusFilterKind filterKind) + { + CornerRadius result = radius; + + switch (filterKind) + { + case CornerRadiusFilterKind.Top: + result.BottomLeft = 0; + result.BottomRight = 0; + break; + case CornerRadiusFilterKind.Right: + result.TopLeft = 0; + result.BottomLeft = 0; + break; + case CornerRadiusFilterKind.Bottom: + result.TopLeft = 0; + result.TopRight = 0; + break; + case CornerRadiusFilterKind.Left: + result.TopRight = 0; + result.BottomRight = 0; + break; + } + + return result; + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var cornerRadius = (CornerRadius)value; + + var scale = Scale; + if (!double.IsNaN(scale)) + { + cornerRadius.TopLeft *= scale; + cornerRadius.TopRight *= scale; + cornerRadius.BottomRight *= scale; + cornerRadius.BottomLeft *= scale; + } + + var filterType = Filter; + if (filterType == CornerRadiusFilterKind.TopLeftValue || + filterType == CornerRadiusFilterKind.BottomRightValue) + { + return GetDoubleValue(cornerRadius, filterType); + } + + return Convert(cornerRadius, filterType); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + private static double GetDoubleValue(CornerRadius radius, CornerRadiusFilterKind filterKind) + { + switch (filterKind) + { + case CornerRadiusFilterKind.TopLeftValue: + return radius.TopLeft; + case CornerRadiusFilterKind.BottomRightValue: + return radius.BottomRight; + } + return 0; + } +} + +public enum CornerRadiusFilterKind +{ + None, + Top, + Right, + Bottom, + Left, + TopLeftValue, + BottomRightValue +} diff --git a/Flow.Launcher/Converters/PlacementRectangleConverter.cs b/Flow.Launcher/Converters/PlacementRectangleConverter.cs new file mode 100644 index 00000000000..130d04e160e --- /dev/null +++ b/Flow.Launcher/Converters/PlacementRectangleConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace Flow.Launcher.Converters; + +public class PlacementRectangleConverter : IMultiValueConverter +{ + public Thickness Margin { get; set; } + + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values.Length == 2 && + values[0] is double width && + values[1] is double height) + { + var margin = Margin; + var topLeft = new Point(margin.Left, margin.Top); + var bottomRight = new Point(width - margin.Right, height - margin.Bottom); + var rect = new Rect(topLeft, bottomRight); + return rect; + } + + return Rect.Empty; + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/Flow.Launcher/Converters/SharedSizeGroupConverter.cs b/Flow.Launcher/Converters/SharedSizeGroupConverter.cs new file mode 100644 index 00000000000..59478702749 --- /dev/null +++ b/Flow.Launcher/Converters/SharedSizeGroupConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace Flow.Launcher.Converters; + +public class SharedSizeGroupConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return (Visibility)value != Visibility.Collapsed ? (string)parameter : null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/Flow.Launcher/Converters/StringToKeyBindingConverter.cs b/Flow.Launcher/Converters/StringToKeyBindingConverter.cs index 21bf584e7a9..b7bca41c54e 100644 --- a/Flow.Launcher/Converters/StringToKeyBindingConverter.cs +++ b/Flow.Launcher/Converters/StringToKeyBindingConverter.cs @@ -5,7 +5,7 @@ namespace Flow.Launcher.Converters; -class StringToKeyBindingConverter : IValueConverter +public class StringToKeyBindingConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index aa8e95429ef..8c7670426bb 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -138,6 +138,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -146,9 +147,6 @@ - - - all diff --git a/Flow.Launcher/Helper/BorderHelper.cs b/Flow.Launcher/Helper/BorderHelper.cs new file mode 100644 index 00000000000..0f2a78e7dd6 --- /dev/null +++ b/Flow.Launcher/Helper/BorderHelper.cs @@ -0,0 +1,33 @@ +using System.Windows; +using System.Windows.Controls; + +namespace Flow.Launcher.Helper; + +public static class BorderHelper +{ + #region Child + + public static readonly DependencyProperty ChildProperty = + DependencyProperty.RegisterAttached( + "Child", + typeof(UIElement), + typeof(BorderHelper), + new PropertyMetadata(default(UIElement), OnChildChanged)); + + public static UIElement GetChild(Border border) + { + return (UIElement)border.GetValue(ChildProperty); + } + + public static void SetChild(Border border, UIElement value) + { + border.SetValue(ChildProperty, value); + } + + private static void OnChildChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((Border)d).Child = (UIElement)e.NewValue; + } + + #endregion +} diff --git a/Flow.Launcher/HotkeyControlDialog.xaml b/Flow.Launcher/HotkeyControlDialog.xaml index d416f1bdcda..9fdfda865e7 100644 --- a/Flow.Launcher/HotkeyControlDialog.xaml +++ b/Flow.Launcher/HotkeyControlDialog.xaml @@ -2,7 +2,7 @@ x:Class="Flow.Launcher.HotkeyControlDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:ui="http://schemas.modernwpf.com/2019" + xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" Background="{DynamicResource PopuBGColor}" BorderBrush="{DynamicResource PopupButtonAreaBorderColor}" BorderThickness="0 1 0 0" diff --git a/Flow.Launcher/HotkeyControlDialog.xaml.cs b/Flow.Launcher/HotkeyControlDialog.xaml.cs index 740425f8bff..e1fc86f9541 100644 --- a/Flow.Launcher/HotkeyControlDialog.xaml.cs +++ b/Flow.Launcher/HotkeyControlDialog.xaml.cs @@ -9,7 +9,7 @@ using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; -using ModernWpf.Controls; +using iNKORE.UI.WPF.Modern.Controls; namespace Flow.Launcher; diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 132ec838978..dd47f9d4ede 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -6,7 +6,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:flowlauncher="clr-namespace:Flow.Launcher" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="http://schemas.modernwpf.com/2019" + xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" xmlns:vm="clr-namespace:Flow.Launcher.ViewModel" Name="FlowMainWindow" Title="Flow Launcher" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 01a7dc9bd50..b2ba33269af 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -25,7 +25,8 @@ using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Plugin.SharedModels; using Flow.Launcher.ViewModel; -using ModernWpf.Controls; +using iNKORE.UI.WPF.Modern; +using iNKORE.UI.WPF.Modern.Controls; using DataObject = System.Windows.DataObject; using Key = System.Windows.Input.Key; using MouseButtons = System.Windows.Forms.MouseButtons; @@ -191,11 +192,11 @@ private void OnLoaded(object sender, RoutedEventArgs e) // Initialize color scheme if (_settings.ColorScheme == Constant.Light) { - ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Light; + ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light; } else if (_settings.ColorScheme == Constant.Dark) { - ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Dark; + ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark; } // Initialize position diff --git a/Flow.Launcher/PluginUpdateWindow.xaml b/Flow.Launcher/PluginUpdateWindow.xaml index 04cd1f7bc11..a4bb0643169 100644 --- a/Flow.Launcher/PluginUpdateWindow.xaml +++ b/Flow.Launcher/PluginUpdateWindow.xaml @@ -4,6 +4,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:flowlauncher="clr-namespace:Flow.Launcher" + xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" Title="{DynamicResource updateAllPluginsButtonContent}" Width="530" Background="{DynamicResource PopuBGColor}" @@ -66,13 +67,13 @@ Text="{DynamicResource updateAllPluginsButtonContent}" TextAlignment="Left" /> - - + - + @@ -161,18 +162,23 @@ Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" - Margin="18 0 18 0"> - + Margin="6 0 18 0"> + - + Height="500" + Margin="15 0 0 0" + Padding="0 0 15 0" + HorizontalAlignment="Stretch"> @@ -193,11 +199,11 @@ VerticalScrollBarVisibility="Disabled" Visibility="Collapsed" /> - + - + Properties.Settings.Default.GithubRepo + "/releases"; public ReleaseNotesWindow() { InitializeComponent(); - SeeMore.Uri = ReleaseNotes; - ModernWpf.ThemeManager.Current.ActualApplicationThemeChanged += ThemeManager_ActualApplicationThemeChanged; + ThemeManager.Current.ActualApplicationThemeChanged += ThemeManager_ActualApplicationThemeChanged; } #region Window Events - private void ThemeManager_ActualApplicationThemeChanged(ModernWpf.ThemeManager sender, object args) + private void ThemeManager_ActualApplicationThemeChanged(ThemeManager sender, object args) { Application.Current.Dispatcher.Invoke(() => { - if (ModernWpf.ThemeManager.Current.ActualApplicationTheme == ModernWpf.ApplicationTheme.Light) + if (ThemeManager.Current.ActualApplicationTheme == ApplicationTheme.Light) { MarkdownViewer.MarkdownStyle = (Style)Application.Current.Resources["DocumentStyleGithubLikeLight"]; MarkdownViewer.Foreground = Brushes.Black; @@ -58,7 +58,7 @@ private void OnCloseExecuted(object sender, ExecutedRoutedEventArgs e) private void Window_Closed(object sender, EventArgs e) { - ModernWpf.ThemeManager.Current.ActualApplicationThemeChanged -= ThemeManager_ActualApplicationThemeChanged; + ThemeManager.Current.ActualApplicationThemeChanged -= ThemeManager_ActualApplicationThemeChanged; } #endregion @@ -147,7 +147,6 @@ private async void RefreshMarkdownViewer() private void Grid_SizeChanged(object sender, SizeChangedEventArgs e) { MarkdownScrollViewer.Height = e.NewSize.Height; - MarkdownScrollViewer.Width = e.NewSize.Width; } private void MarkdownViewer_MouseWheel(object sender, MouseWheelEventArgs e) diff --git a/Flow.Launcher/Resources/Controls/Card.xaml b/Flow.Launcher/Resources/Controls/Card.xaml deleted file mode 100644 index e3c5f819490..00000000000 --- a/Flow.Launcher/Resources/Controls/Card.xaml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Flow.Launcher/Resources/Controls/Card.xaml.cs b/Flow.Launcher/Resources/Controls/Card.xaml.cs deleted file mode 100644 index 6a70dded2c9..00000000000 --- a/Flow.Launcher/Resources/Controls/Card.xaml.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Windows; -using UserControl = System.Windows.Controls.UserControl; - -namespace Flow.Launcher.Resources.Controls -{ - public partial class Card : UserControl - { - public enum CardType - { - Default, - Inside, - InsideFit, - First, - Middle, - Last - } - - public Card() - { - InitializeComponent(); - } - - public string Title - { - get { return (string)GetValue(TitleProperty); } - set { SetValue(TitleProperty, value); } - } - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register(nameof(Title), typeof(string), typeof(Card), new PropertyMetadata(string.Empty)); - - public string Sub - { - get { return (string)GetValue(SubProperty); } - set { SetValue(SubProperty, value); } - } - public static readonly DependencyProperty SubProperty = - DependencyProperty.Register(nameof(Sub), typeof(string), typeof(Card), new PropertyMetadata(string.Empty)); - - public string Icon - { - get { return (string)GetValue(IconProperty); } - set { SetValue(IconProperty, value); } - } - public static readonly DependencyProperty IconProperty = - DependencyProperty.Register(nameof(Icon), typeof(string), typeof(Card), new PropertyMetadata(string.Empty)); - - /// - /// Gets or sets additional content for the UserControl - /// - public object AdditionalContent - { - get { return (object)GetValue(AdditionalContentProperty); } - set { SetValue(AdditionalContentProperty, value); } - } - public static readonly DependencyProperty AdditionalContentProperty = - DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(Card), - new PropertyMetadata(null)); - public CardType Type - { - get { return (CardType)GetValue(TypeProperty); } - set { SetValue(TypeProperty, value); } - } - public static readonly DependencyProperty TypeProperty = - DependencyProperty.Register(nameof(Type), typeof(CardType), typeof(Card), - new PropertyMetadata(CardType.Default)); - } -} diff --git a/Flow.Launcher/Resources/Controls/CardGroup.xaml b/Flow.Launcher/Resources/Controls/CardGroup.xaml deleted file mode 100644 index f48bf4b6c9f..00000000000 --- a/Flow.Launcher/Resources/Controls/CardGroup.xaml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - diff --git a/Flow.Launcher/Resources/Controls/CardGroup.xaml.cs b/Flow.Launcher/Resources/Controls/CardGroup.xaml.cs deleted file mode 100644 index b9588275c7f..00000000000 --- a/Flow.Launcher/Resources/Controls/CardGroup.xaml.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using System.Windows; -using System.Windows.Controls; - -namespace Flow.Launcher.Resources.Controls; - -public partial class CardGroup : UserControl -{ - public enum CardGroupPosition - { - NotInGroup, - First, - Middle, - Last - } - - public new ObservableCollection Content - { - get { return (ObservableCollection)GetValue(ContentProperty); } - set { SetValue(ContentProperty, value); } - } - - public static new readonly DependencyProperty ContentProperty = - DependencyProperty.Register(nameof(Content), typeof(ObservableCollection), typeof(CardGroup)); - - public static readonly DependencyProperty PositionProperty = DependencyProperty.RegisterAttached( - "Position", typeof(CardGroupPosition), typeof(CardGroup), - new FrameworkPropertyMetadata(CardGroupPosition.NotInGroup, FrameworkPropertyMetadataOptions.AffectsRender) - ); - - public static void SetPosition(UIElement element, CardGroupPosition value) - { - element.SetValue(PositionProperty, value); - } - - public static CardGroupPosition GetPosition(UIElement element) - { - return (CardGroupPosition)element.GetValue(PositionProperty); - } - - public CardGroup() - { - InitializeComponent(); - Content = new ObservableCollection(); - } -} diff --git a/Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs b/Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs deleted file mode 100644 index 605934e80c1..00000000000 --- a/Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -namespace Flow.Launcher.Resources.Controls; - -public class CardGroupCardStyleSelector : StyleSelector -{ - public Style FirstStyle { get; set; } - public Style MiddleStyle { get; set; } - public Style LastStyle { get; set; } - - public override Style SelectStyle(object item, DependencyObject container) - { - var itemsControl = ItemsControl.ItemsControlFromItemContainer(container); - var index = itemsControl.ItemContainerGenerator.IndexFromContainer(container); - - if (index == 0) return FirstStyle; - if (index == itemsControl.Items.Count - 1) return LastStyle; - return MiddleStyle; - } -} diff --git a/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs b/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs new file mode 100644 index 00000000000..78985108ce2 --- /dev/null +++ b/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs @@ -0,0 +1,253 @@ +using iNKORE.UI.WPF.Modern.Controls; +using iNKORE.UI.WPF.Modern.Controls.Helpers; +using iNKORE.UI.WPF.Modern.Controls.Primitives; +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace Flow.Launcher.Resources.Controls +{ + // TODO: Use IsScrollAnimationEnabled property in future: https://github.com/iNKORE-NET/UI.WPF.Modern/pull/347 + public class CustomScrollViewerEx : ScrollViewer + { + private double LastVerticalLocation = 0; + private double LastHorizontalLocation = 0; + + public CustomScrollViewerEx() + { + Loaded += OnLoaded; + var valueSource = DependencyPropertyHelper.GetValueSource(this, AutoPanningMode.IsEnabledProperty).BaseValueSource; + if (valueSource == BaseValueSource.Default) + { + AutoPanningMode.SetIsEnabled(this, true); + } + } + + #region Orientation + + public static readonly DependencyProperty OrientationProperty = + DependencyProperty.Register( + nameof(Orientation), + typeof(Orientation), + typeof(CustomScrollViewerEx), + new PropertyMetadata(Orientation.Vertical)); + + public Orientation Orientation + { + get => (Orientation)GetValue(OrientationProperty); + set => SetValue(OrientationProperty, value); + } + + #endregion + + #region AutoHideScrollBars + + public static readonly DependencyProperty AutoHideScrollBarsProperty = + ScrollViewerHelper.AutoHideScrollBarsProperty + .AddOwner( + typeof(CustomScrollViewerEx), + new PropertyMetadata(true, OnAutoHideScrollBarsChanged)); + + public bool AutoHideScrollBars + { + get => (bool)GetValue(AutoHideScrollBarsProperty); + set => SetValue(AutoHideScrollBarsProperty, value); + } + + private static void OnAutoHideScrollBarsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CustomScrollViewerEx sv) + { + sv.UpdateVisualState(); + } + } + + #endregion + + private void OnLoaded(object sender, RoutedEventArgs e) + { + LastVerticalLocation = VerticalOffset; + LastHorizontalLocation = HorizontalOffset; + UpdateVisualState(false); + } + + /// + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + if (Style == null && ReadLocalValue(StyleProperty) == DependencyProperty.UnsetValue) + { + SetResourceReference(StyleProperty, typeof(ScrollViewer)); + } + } + + /// + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + var Direction = GetDirection(); + ScrollViewerBehavior.SetIsAnimating(this, true); + + if (Direction == Orientation.Vertical) + { + if (ScrollableHeight > 0) + { + e.Handled = true; + } + + var WheelChange = e.Delta * (ViewportHeight / 1.5) / ActualHeight; + var newOffset = LastVerticalLocation - WheelChange; + + if (newOffset < 0) + { + newOffset = 0; + } + + if (newOffset > ScrollableHeight) + { + newOffset = ScrollableHeight; + } + + if (newOffset == LastVerticalLocation) + { + return; + } + + ScrollToVerticalOffset(LastVerticalLocation); + + ScrollToValue(newOffset, Direction); + LastVerticalLocation = newOffset; + } + else + { + if (ScrollableWidth > 0) + { + e.Handled = true; + } + + var WheelChange = e.Delta * (ViewportWidth / 1.5) / ActualWidth; + var newOffset = LastHorizontalLocation - WheelChange; + + if (newOffset < 0) + { + newOffset = 0; + } + + if (newOffset > ScrollableWidth) + { + newOffset = ScrollableWidth; + } + + if (newOffset == LastHorizontalLocation) + { + return; + } + + ScrollToHorizontalOffset(LastHorizontalLocation); + + ScrollToValue(newOffset, Direction); + LastHorizontalLocation = newOffset; + } + } + + /// + protected override void OnScrollChanged(ScrollChangedEventArgs e) + { + base.OnScrollChanged(e); + if (!ScrollViewerBehavior.GetIsAnimating(this)) + { + LastVerticalLocation = VerticalOffset; + LastHorizontalLocation = HorizontalOffset; + } + } + + private Orientation GetDirection() + { + var isShiftDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift); + + if (Orientation == Orientation.Horizontal) + { + return isShiftDown ? Orientation.Vertical : Orientation.Horizontal; + } + else + { + return isShiftDown ? Orientation.Horizontal : Orientation.Vertical; + } + } + + /// + /// Causes the to load a new view into the viewport using the specified offsets and zoom factor. + /// + /// A value between 0 and that specifies the distance the content should be scrolled horizontally. + /// A value between 0 and that specifies the distance the content should be scrolled vertically. + /// A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor. + /// if the view is changed; otherwise, . + public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor) + { + return ChangeView(horizontalOffset, verticalOffset, zoomFactor, false); + } + + /// + /// Causes the to load a new view into the viewport using the specified offsets and zoom factor, and optionally disables scrolling animation. + /// + /// A value between 0 and that specifies the distance the content should be scrolled horizontally. + /// A value between 0 and that specifies the distance the content should be scrolled vertically. + /// A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor. + /// to disable zoom/pan animations while changing the view; otherwise, . The default is false. + /// if the view is changed; otherwise, . + public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor, bool disableAnimation) + { + if (disableAnimation) + { + if (horizontalOffset.HasValue) + { + ScrollToHorizontalOffset(horizontalOffset.Value); + } + + if (verticalOffset.HasValue) + { + ScrollToVerticalOffset(verticalOffset.Value); + } + } + else + { + if (horizontalOffset.HasValue) + { + ScrollToHorizontalOffset(LastHorizontalLocation); + ScrollToValue(Math.Min(ScrollableWidth, horizontalOffset.Value), Orientation.Horizontal); + LastHorizontalLocation = horizontalOffset.Value; + } + + if (verticalOffset.HasValue) + { + ScrollToVerticalOffset(LastVerticalLocation); + ScrollToValue(Math.Min(ScrollableHeight, verticalOffset.Value), Orientation.Vertical); + LastVerticalLocation = verticalOffset.Value; + } + } + + return true; + } + + private void ScrollToValue(double value, Orientation Direction) + { + if (Direction == Orientation.Vertical) + { + ScrollToVerticalOffset(value); + } + else + { + ScrollToHorizontalOffset(value); + } + + ScrollViewerBehavior.SetIsAnimating(this, false); + } + + private void UpdateVisualState(bool useTransitions = true) + { + var stateName = AutoHideScrollBars ? "NoIndicator" : "MouseIndicator"; + VisualStateManager.GoToState(this, stateName, useTransitions); + } + } +} diff --git a/Flow.Launcher/Resources/Controls/ExCard.xaml b/Flow.Launcher/Resources/Controls/ExCard.xaml deleted file mode 100644 index a70c0f4ea46..00000000000 --- a/Flow.Launcher/Resources/Controls/ExCard.xaml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Flow.Launcher/Resources/Controls/ExCard.xaml.cs b/Flow.Launcher/Resources/Controls/ExCard.xaml.cs deleted file mode 100644 index f149951f039..00000000000 --- a/Flow.Launcher/Resources/Controls/ExCard.xaml.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Windows; -using System.Windows.Controls; - -namespace Flow.Launcher.Resources.Controls -{ - public partial class ExCard : UserControl - { - public ExCard() - { - InitializeComponent(); - } - public string Title - { - get { return (string)GetValue(TitleProperty); } - set { SetValue(TitleProperty, value); } - } - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register(nameof(Title), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty)); - - public string Sub - { - get { return (string)GetValue(SubProperty); } - set { SetValue(SubProperty, value); } - } - public static readonly DependencyProperty SubProperty = - DependencyProperty.Register(nameof(Sub), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty)); - - public string Icon - { - get { return (string)GetValue(IconProperty); } - set { SetValue(IconProperty, value); } - } - public static readonly DependencyProperty IconProperty = - DependencyProperty.Register(nameof(Icon), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty)); - - /// - /// Gets or sets additional content for the UserControl - /// - public object AdditionalContent - { - get { return (object)GetValue(AdditionalContentProperty); } - set { SetValue(AdditionalContentProperty, value); } - } - public static readonly DependencyProperty AdditionalContentProperty = - DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(ExCard), - new PropertyMetadata(null)); - - public object SideContent - { - get { return (object)GetValue(SideContentProperty); } - set { SetValue(SideContentProperty, value); } - } - public static readonly DependencyProperty SideContentProperty = - DependencyProperty.Register(nameof(SideContent), typeof(object), typeof(ExCard), - new PropertyMetadata(null)); - } -} diff --git a/Flow.Launcher/Resources/Controls/HyperLink.xaml b/Flow.Launcher/Resources/Controls/HyperLink.xaml deleted file mode 100644 index 9ea550afd51..00000000000 --- a/Flow.Launcher/Resources/Controls/HyperLink.xaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - diff --git a/Flow.Launcher/Resources/Controls/HyperLink.xaml.cs b/Flow.Launcher/Resources/Controls/HyperLink.xaml.cs deleted file mode 100644 index 855cccdbd60..00000000000 --- a/Flow.Launcher/Resources/Controls/HyperLink.xaml.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Navigation; - -namespace Flow.Launcher.Resources.Controls; - -public partial class HyperLink : UserControl -{ - public static readonly DependencyProperty UriProperty = DependencyProperty.Register( - nameof(Uri), typeof(string), typeof(HyperLink), new PropertyMetadata(default(string)) - ); - - public string Uri - { - get => (string)GetValue(UriProperty); - set => SetValue(UriProperty, value); - } - - public static readonly DependencyProperty TextProperty = DependencyProperty.Register( - nameof(Text), typeof(string), typeof(HyperLink), new PropertyMetadata(default(string)) - ); - - public string Text - { - get => (string)GetValue(TextProperty); - set => SetValue(TextProperty, value); - } - - public HyperLink() - { - InitializeComponent(); - } - - private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e) - { - App.API.OpenUrl(e.Uri); - e.Handled = true; - } -} diff --git a/Flow.Launcher/Resources/Controls/InfoBar.xaml b/Flow.Launcher/Resources/Controls/InfoBar.xaml deleted file mode 100644 index 2ddcbdd0cc8..00000000000 --- a/Flow.Launcher/Resources/Controls/InfoBar.xaml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + + + + + + + + + + + - - - - - + + + + + +