diff --git a/Branding/SVGs/MiddleMouseButton.svg b/Branding/SVGs/MiddleMouseButton.svg
new file mode 100644
index 00000000..c48ff9e6
--- /dev/null
+++ b/Branding/SVGs/MiddleMouseButton.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Wabbajack/Resources/ResourceLinks.cs b/Wabbajack/Resources/ResourceLinks.cs
index e2a12a5d..f7b54b3d 100644
--- a/Wabbajack/Resources/ResourceLinks.cs
+++ b/Wabbajack/Resources/ResourceLinks.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Text;
using System.Windows;
using System.Windows.Media.Imaging;
@@ -18,5 +16,7 @@ namespace Wabbajack
UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/MO2Button.png")).Stream));
public static Lazy VortexButton { get; } = new Lazy(() =>
UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/VortexButton.png")).Stream));
+ public static Lazy MiddleMouseButton { get; } = new Lazy(() =>
+ UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/middle_mouse_button.png")).Stream));
}
}
diff --git a/Wabbajack/Resources/middle_mouse_button.png b/Wabbajack/Resources/middle_mouse_button.png
new file mode 100644
index 00000000..cb277a65
Binary files /dev/null and b/Wabbajack/Resources/middle_mouse_button.png differ
diff --git a/Wabbajack/View Models/ManifestVM.cs b/Wabbajack/View Models/ManifestVM.cs
index 80935f71..19293e04 100644
--- a/Wabbajack/View Models/ManifestVM.cs
+++ b/Wabbajack/View Models/ManifestVM.cs
@@ -1,4 +1,9 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reactive.Linq;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.Lib;
@@ -16,9 +21,34 @@ namespace Wabbajack
public IEnumerable Archives => Manifest.Archives;
+ [Reactive]
+ public string SearchTerm { get; set; }
+
+ private readonly ObservableAsPropertyHelper> _searchResults;
+ public IEnumerable SearchResults => _searchResults.Value;
+
public ManifestVM(Manifest manifest)
{
Manifest = manifest;
+
+ _searchResults =
+ this.WhenAnyValue(x => x.SearchTerm)
+ .Throttle(TimeSpan.FromMilliseconds(800))
+ .Select(term => term?.Trim())
+ .DistinctUntilChanged()
+ .Select(term =>
+ {
+ if (string.IsNullOrWhiteSpace(term))
+ return Archives;
+
+ return Archives.Where(x =>
+ {
+ if (term.StartsWith("hash:"))
+ return x.Hash.StartsWith(term.Replace("hash:", ""));
+ return x.Name.StartsWith(term);
+ });
+ })
+ .ToGuiProperty(this, nameof(SearchResults), Archives);
}
}
}
diff --git a/Wabbajack/Views/ManifestView.xaml b/Wabbajack/Views/ManifestView.xaml
index e2c9860d..900cf364 100644
--- a/Wabbajack/Views/ManifestView.xaml
+++ b/Wabbajack/Views/ManifestView.xaml
@@ -7,7 +7,8 @@
xmlns:reactiveUi="http://reactiveui.net"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
-
+
+
-
+
-
+
-
-
+
+
-
-
-
+
+
+
+
+
@@ -37,7 +42,7 @@
-
+
@@ -46,15 +51,17 @@
-
-
+
+
Link
-
+
+
+
diff --git a/Wabbajack/Views/ManifestView.xaml.cs b/Wabbajack/Views/ManifestView.xaml.cs
index 22ac66ac..c96b4de9 100644
--- a/Wabbajack/Views/ManifestView.xaml.cs
+++ b/Wabbajack/Views/ManifestView.xaml.cs
@@ -1,9 +1,15 @@
using System;
using System.Diagnostics;
using System.Reactive.Disposables;
+using System.Windows;
+using System.Windows.Controls;
using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
using System.Windows.Navigation;
+using System.Windows.Shapes;
using ReactiveUI;
+using Wabbajack.Common;
using Wabbajack.Lib;
namespace Wabbajack
@@ -30,12 +36,14 @@ namespace Wabbajack
.DisposeWith(disposable);
this.OneWayBind(ViewModel, x => x.Description, x => x.Description.Text)
.DisposeWith(disposable);
- this.OneWayBind(ViewModel, x => x.Archives, x => x.ModsList.ItemsSource)
+ this.OneWayBind(ViewModel, x => x.SearchResults, x => x.ModsList.ItemsSource)
.DisposeWith(disposable);
this.OneWayBind(ViewModel, x => x.InstallSize, x => x.InstallSize.Text)
.DisposeWith(disposable);
this.OneWayBind(ViewModel, x => x.DownloadSize, x => x.DownloadSize.Text)
.DisposeWith(disposable);
+ this.Bind(ViewModel, x => x.SearchTerm, x => x.SearchBar.Text)
+ .DisposeWith(disposable);
});
}
@@ -55,5 +63,78 @@ namespace Wabbajack
e.Handled = true;
}
+
+ //solution from https://stackoverflow.com/questions/5426232/how-can-i-make-wpf-scrollviewer-middle-click-scroll/5446307#5446307
+
+ private bool _isMoving; //False - ignore mouse movements and don't scroll
+ private bool _isDeferredMovingStarted; //True - Mouse down -> Mouse up without moving -> Move; False - Mouse down -> Move
+ private Point? _startPosition;
+ private const double Slowdown = 10; //smaller = faster
+
+ private void ScrollViewer_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (_isMoving)
+ CancelScrolling();
+ else if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Pressed)
+ {
+ if (_isMoving) return;
+
+ _isMoving = true;
+ _startPosition = e.GetPosition(sender as IInputElement);
+ _isDeferredMovingStarted = true;
+
+ AddScrollSign(e.GetPosition(TopLayer).X, e.GetPosition(TopLayer).Y);
+ }
+ }
+
+ private void ScrollViewer_MouseUp(object sender, MouseButtonEventArgs e)
+ {
+ if(e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Released && _isDeferredMovingStarted != true)
+ CancelScrolling();
+ }
+
+ private void ScrollViewer_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (!_isMoving || !(sender is ScrollViewer sv))
+ return;
+
+ _isDeferredMovingStarted = false;
+
+ var currentPosition = e.GetPosition(sv);
+ if (_startPosition == null)
+ return;
+
+ var offset = currentPosition - _startPosition.Value;
+ offset.Y /= Slowdown;
+ offset.X /= Slowdown;
+
+ sv.ScrollToVerticalOffset(sv.VerticalOffset + offset.Y);
+ sv.ScrollToHorizontalOffset(sv.HorizontalOffset + offset.X);
+ }
+
+ private void CancelScrolling()
+ {
+ _isMoving = false;
+ _startPosition = null;
+ _isDeferredMovingStarted = false;
+ RemoveScrollSign();
+ }
+
+ private void AddScrollSign(double x, double y)
+ {
+ const double size = 50.0;
+ var img = ResourceLinks.MiddleMouseButton.Value;
+ var icon = new Image {Source = img, Width = size, Height = size};
+ //var icon = new Ellipse { Stroke = Brushes.Red, StrokeThickness = 2.0, Width = 20, Height = 20 };
+
+ TopLayer.Children.Add(icon);
+ Canvas.SetLeft(icon, x - size / 2);
+ Canvas.SetTop(icon, y - size / 2);
+ }
+
+ private void RemoveScrollSign()
+ {
+ TopLayer.Children.Clear();
+ }
}
}
diff --git a/Wabbajack/Wabbajack.csproj b/Wabbajack/Wabbajack.csproj
index 8d5ec5a8..d12d402c 100644
--- a/Wabbajack/Wabbajack.csproj
+++ b/Wabbajack/Wabbajack.csproj
@@ -41,6 +41,7 @@
+
@@ -81,6 +82,7 @@
+