From abe5db81287b2611a94d004465c6d74c10387472 Mon Sep 17 00:00:00 2001 From: Reetus Date: Sun, 9 Nov 2025 23:05:38 +0700 Subject: [PATCH 1/2] Serialize Skills Sort Field/Direction --- .../Behaviours/SkillsGridViewSortBehaviour.cs | 144 ++++++++++++++++++ .../UI/ViewModels/SkillsTabViewModel.cs | 44 +++++- ClassicAssist/UI/Views/SkillsTabControl.xaml | 7 +- .../UI/Views/SkillsTabControl.xaml.cs | 53 +------ 4 files changed, 194 insertions(+), 54 deletions(-) create mode 100644 ClassicAssist/UI/Misc/Behaviours/SkillsGridViewSortBehaviour.cs diff --git a/ClassicAssist/UI/Misc/Behaviours/SkillsGridViewSortBehaviour.cs b/ClassicAssist/UI/Misc/Behaviours/SkillsGridViewSortBehaviour.cs new file mode 100644 index 00000000..e30d44aa --- /dev/null +++ b/ClassicAssist/UI/Misc/Behaviours/SkillsGridViewSortBehaviour.cs @@ -0,0 +1,144 @@ +#region License + +// Copyright (C) 2025 Reetus +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY + +#endregion + +using System.ComponentModel; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using ClassicAssist.Data.Skills; +using ClassicAssist.Shared.UI; +using Microsoft.Xaml.Behaviors; + +namespace ClassicAssist.UI.Misc.Behaviours +{ + public class SkillsGridViewSortBehaviour : Behavior + { + public static readonly DependencyProperty SortChangedCommandProperty = + DependencyProperty.Register( nameof( SortChangedCommand ), typeof( ICommand ), typeof( SkillsGridViewSortBehaviour ) ); + + public static readonly DependencyProperty SetSortCommandProperty = DependencyProperty.Register( nameof( SetSortCommand ), typeof( ICommand ), + typeof( SkillsGridViewSortBehaviour ), new PropertyMetadata( null ) ); + + private ListSortDirection _lastDirection; + + private SkillsGridViewColumn.Enums _lastHeaderClicked; + private ICommand _setSortCommandImpl; + + public ICommand SetSortCommand + { + get => (ICommand) GetValue( SetSortCommandProperty ); + set => SetValue( SetSortCommandProperty, value ); + } + + public ICommand SetSortCommandImpl => _setSortCommandImpl ?? ( _setSortCommandImpl = new RelayCommand( SetSort ) ); + + public ICommand SortChangedCommand + { + get => (ICommand) GetValue( SortChangedCommandProperty ); + set => SetValue( SortChangedCommandProperty, value ); + } + + private void SetSort( object obj ) + { + if ( !( obj is SkillsSortInfo info ) ) + { + return; + } + + if ( !( AssociatedObject.View is GridView gridView ) ) + { + return; + } + + SkillsGridViewColumn column = gridView.Columns.FirstOrDefault( e => e is SkillsGridViewColumn sgvc && sgvc.SortField == info.SortBy ) as SkillsGridViewColumn; + + ApplySort( column, info.Direction ); + } + + protected override void OnAttached() + { + base.OnAttached(); + + AssociatedObject.AddHandler( ButtonBase.ClickEvent, new RoutedEventHandler( OnHeaderClick ) ); + + SetValue( SetSortCommandProperty, SetSortCommandImpl ); + } + + protected override void OnDetaching() + { + AssociatedObject.RemoveHandler( ButtonBase.ClickEvent, new RoutedEventHandler( OnHeaderClick ) ); + + base.OnDetaching(); + } + + private void OnHeaderClick( object sender, RoutedEventArgs e ) + { + if ( !( e.OriginalSource is GridViewColumnHeader headerClicked ) || headerClicked.Column == null ) + { + return; + } + + SkillsGridViewColumn.Enums sortBy = ((SkillsGridViewColumn)headerClicked.Column).SortField; + + ListSortDirection direction; + + if ( sortBy == _lastHeaderClicked ) + { + direction = _lastDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; + } + else + { + direction = ListSortDirection.Ascending; + } + + ApplySort( headerClicked.Column as SkillsGridViewColumn, direction ); + + SortChangedCommand?.Execute( new SkillsSortInfo( sortBy, direction ) ); + } + + private void ApplySort( SkillsGridViewColumn column, ListSortDirection direction ) + { + _lastDirection = direction; + + _lastHeaderClicked = column.SortField; + + ListCollectionView dataView = (ListCollectionView)CollectionViewSource.GetDefaultView( AssociatedObject.ItemsSource ); + + if ( dataView == null ) + { + return; + } + + dataView.SortDescriptions.Clear(); + dataView.SortDescriptions.Add( new SortDescription( column.Header.ToString(), direction ) ); + dataView.CustomSort = new SkillComparer( direction, column.SortField ); + dataView.Refresh(); + } + } + + public class SkillsSortInfo + { + public SkillsSortInfo( SkillsGridViewColumn.Enums sortBy, ListSortDirection direction ) + { + SortBy = sortBy; + Direction = direction; + } + + public ListSortDirection Direction { get; } + public SkillsGridViewColumn.Enums SortBy { get; } + } +} \ No newline at end of file diff --git a/ClassicAssist/UI/ViewModels/SkillsTabViewModel.cs b/ClassicAssist/UI/ViewModels/SkillsTabViewModel.cs index 4eb7a2d6..c545dac1 100644 --- a/ClassicAssist/UI/ViewModels/SkillsTabViewModel.cs +++ b/ClassicAssist/UI/ViewModels/SkillsTabViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Input; @@ -13,6 +14,7 @@ using ClassicAssist.Shared.Resources; using ClassicAssist.Shared.UI; using ClassicAssist.UI.Misc; +using ClassicAssist.UI.Misc.Behaviours; using ClassicAssist.UO; using ClassicAssist.UO.Data; using ClassicAssist.UO.Network; @@ -29,6 +31,9 @@ public class SkillsTabViewModel : BaseViewModel, IGlobalSettingProvider private SkillEntry _selectedItem; private ICommand _setAllSkillLocksCommand; private ICommand _setSkillLocksCommand; + private ICommand _sortChangedCommand; + + private SkillsSortInfo _sortInfo; private float _totalBase; private ICommand _useSkillCommand; @@ -79,6 +84,10 @@ public float TotalBase _useSkillCommand ?? ( _useSkillCommand = new RelayCommand( UseSkill, o => SelectedItem?.Skill.Invokable ?? false ) ); + public ICommand SetSortCommand { get; set; } + + public ICommand SortChangedCommand => _sortChangedCommand ?? ( _sortChangedCommand = new RelayCommand( OnSortChanged ) ); + public void Serialize( JObject json, bool global = false ) { JArray skills = new JArray(); @@ -105,6 +114,15 @@ public void Serialize( JObject json, bool global = false ) } json.Add( "Skills", skills ); + + if ( _sortInfo == null || global ) + { + return; + } + + JObject obj = new JObject { { "SortField", _sortInfo.SortBy.ToString() }, { "SortDirection", _sortInfo.Direction.ToString() } }; + + json.Add( "SkillsSort", obj ); } public void Deserialize( JObject json, Options options, bool global = false ) @@ -191,6 +209,20 @@ public void Deserialize( JObject json, Options options, bool global = false ) } hotkey.AddCategory( _hotkeyCategory ); + + if ( !( json["SkillsSort"] is JObject obj ) || obj["SortField"] == null || obj["SortDirection"] == null || global ) + { + return; + } + + if ( !Enum.TryParse( obj["SortField"].ToObject(), out SkillsGridViewColumn.Enums sortBy ) || + !Enum.TryParse( obj["SortDirection"].ToObject(), out ListSortDirection direction ) ) + { + return; + } + + _sortInfo = new SkillsSortInfo( sortBy, direction ); + SetSortCommand?.Execute( _sortInfo ); } public string GetGlobalFilename() @@ -198,6 +230,16 @@ public string GetGlobalFilename() return "Skills.json"; } + private void OnSortChanged( object obj ) + { + if (!( obj is SkillsSortInfo info ) ) + { + return; + } + + _sortInfo = info; + } + private void ResetDeltas( object obj ) { foreach ( SkillEntry skillEntry in Items ) diff --git a/ClassicAssist/UI/Views/SkillsTabControl.xaml b/ClassicAssist/UI/Views/SkillsTabControl.xaml index 48a7896a..2c4fb933 100644 --- a/ClassicAssist/UI/Views/SkillsTabControl.xaml +++ b/ClassicAssist/UI/Views/SkillsTabControl.xaml @@ -11,6 +11,8 @@ xmlns:valueConverters="clr-namespace:ClassicAssist.UI.Misc.ValueConverters" xmlns:sharedResources="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared" xmlns:skills="clr-namespace:ClassicAssist.Data.Skills" + xmlns:b="http://schemas.microsoft.com/xaml/behaviors" + xmlns:behaviours="clr-namespace:ClassicAssist.UI.Misc.Behaviours" mc:Ignorable="d">