first commit
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace ClassicAssist.Browser.Controls
|
||||
{
|
||||
public class ClearableComboBox : ComboBox
|
||||
{
|
||||
public static readonly DependencyProperty ClearCommandProperty =
|
||||
DependencyProperty.Register( "ClearCommand", typeof( ICommand ), typeof( ClearableComboBox ) );
|
||||
|
||||
public static readonly DependencyProperty ClearCommandParameterProperty =
|
||||
DependencyProperty.Register( "ClearCommandParameter", typeof( object ), typeof( ClearableComboBox ),
|
||||
new UIPropertyMetadata( null ) );
|
||||
|
||||
public ICommand ClearCommand
|
||||
{
|
||||
get => (ICommand) GetValue( ClearCommandProperty );
|
||||
set => SetValue( ClearCommandProperty, value );
|
||||
}
|
||||
|
||||
public object ClearCommandParameter
|
||||
{
|
||||
get => GetValue( ClearCommandParameterProperty );
|
||||
set => SetValue( ClearCommandParameterProperty, value );
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
Button button = (Button) GetTemplateChild( "ClearButton" );
|
||||
|
||||
if ( button != null )
|
||||
{
|
||||
button.Click += ClearButtonOnClick;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearButtonOnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
SelectedItem = null;
|
||||
ClearCommand?.Execute( ClearCommandParameter );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:ClassicAssist.Browser.Controls">
|
||||
<SolidColorBrush x:Key="ThemeForegroundBrush" Color="#CCCCCC" />
|
||||
<DrawingImage x:Key="ClearIcon">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup ClipGeometry="M0,0 V512.001 H512.001 V0 H0 Z">
|
||||
<DrawingGroup.Transform>
|
||||
<TranslateTransform X="0.000250011682510376" Y="0" />
|
||||
</DrawingGroup.Transform>
|
||||
<DrawingGroup Opacity="1">
|
||||
<DrawingGroup Opacity="1">
|
||||
<GeometryDrawing Brush="{DynamicResource ThemeForegroundBrush}"
|
||||
Geometry="F1 M512.001,512.001z M0,0z M284.286,256.002L506.143,34.144C513.954,26.333 513.954,13.669 506.143,5.859 498.332,-1.951 485.668,-1.952 477.858,5.859L256,227.717 34.143,5.859C26.332,-1.952 13.668,-1.952 5.858,5.859 -1.952,13.67 -1.953,26.334 5.858,34.144L227.715,256.001 5.858,477.859C-1.953,485.67 -1.953,498.334 5.858,506.144 9.763,510.049 14.882,512.001 20.001,512.001 25.12,512.001 30.238,510.049 34.144,506.144L256,284.287 477.857,506.144C481.762,510.049 486.881,512.001 492,512.001 497.119,512.001 502.237,510.049 506.143,506.144 513.954,498.333 513.954,485.669 506.143,477.859L284.286,256.002z" />
|
||||
</DrawingGroup>
|
||||
</DrawingGroup>
|
||||
</DrawingGroup>
|
||||
</DrawingImage.Drawing>
|
||||
</DrawingImage>
|
||||
<Style TargetType="{x:Type controls:ClearableComboBox}">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="Background" Value="{DynamicResource TextBoxBackgroundBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextBoxForegroundBrush}" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
|
||||
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextBoxForegroundBrush}" />
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="Validation.ErrorTemplate" Value="{DynamicResource ValidationErrorOverlayTemplate}" />
|
||||
<Setter Property="Padding" Value="3,0" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:ClearableComboBox}">
|
||||
<Grid>
|
||||
<TextBox x:Name="PART_EditableTextBox"
|
||||
IsReadOnly="{TemplateBinding IsReadOnly}"
|
||||
Focusable="True"
|
||||
Style="{DynamicResource TextBoxStyle}"
|
||||
Visibility="Hidden" />
|
||||
<Border x:Name="NonEditableBorder"
|
||||
Background="{DynamicResource ComboBoxNonEditableBackgroundBrush}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource ComboBoxNonEditableBorderBrush}">
|
||||
<ContentPresenter IsHitTestVisible="False"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding ComboBox.SelectionBoxItem}"
|
||||
ContentTemplate="{TemplateBinding ComboBox.SelectionBoxItemTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
|
||||
Margin="{TemplateBinding Padding}" DockPanel.Dock="Left" />
|
||||
</Border>
|
||||
<Button x:Name="ClearButton" Padding="0" Background="Transparent"
|
||||
BorderBrush="Transparent" BorderThickness="0" Width="8" Height="8" Margin="0,0,20,0"
|
||||
HorizontalAlignment="Right">
|
||||
<Image Source="{DynamicResource ClearIcon}" Height="8" />
|
||||
</Button>
|
||||
<ToggleButton x:Name="ToggleButton"
|
||||
ClickMode="Press"
|
||||
HorizontalAlignment="Right"
|
||||
Background="{DynamicResource ComboBoxButtonBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource ComboBoxButtonBorderBrush}"
|
||||
BorderThickness="0"
|
||||
Foreground="{DynamicResource ComboBoxButtonForegroundBrush}"
|
||||
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsDropDownOpen, Mode=TwoWay}">
|
||||
<ToggleButton.Template>
|
||||
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.Column="1"
|
||||
x:Name="ButtonBorder"
|
||||
Margin="0"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
Background="{TemplateBinding Background}" />
|
||||
<Path x:Name="Arrow"
|
||||
Grid.Column="1"
|
||||
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z"
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ComboBoxButtonHoverBackgroundBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ComboBoxButtonPressBackgroundBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ComboBoxButtonCheckedBackgroundBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ComboBoxButtonDisabledBackgroundBrush}" />
|
||||
<Setter TargetName="ButtonBorder" Property="BorderBrush"
|
||||
Value="{DynamicResource ComboBoxButtonDisabledBorderBrush}" />
|
||||
<Setter TargetName="Arrow" Property="Fill"
|
||||
Value="{DynamicResource ComboBoxButtonDisabledForegroundBrush}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</ToggleButton.Template>
|
||||
</ToggleButton>
|
||||
<Popup Placement="Bottom"
|
||||
Focusable="False"
|
||||
AllowsTransparency="True"
|
||||
IsOpen="{TemplateBinding ComboBox.IsDropDownOpen}"
|
||||
PopupAnimation="Slide">
|
||||
<Grid MinWidth="{TemplateBinding ActualWidth}"
|
||||
MaxHeight="{TemplateBinding MaxDropDownHeight}">
|
||||
<Border BorderThickness="1"
|
||||
Background="{DynamicResource ComboBoxListBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource ComboBoxListBorderBrush}"
|
||||
Margin="0,1,0,0">
|
||||
<ScrollViewer SnapsToDevicePixels="True">
|
||||
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Popup>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="NonEditableBorder" Property="Background"
|
||||
Value="{DynamicResource ComboBoxNonEditableHoverBackgroundBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="NonEditableBorder" Property="Background"
|
||||
Value="{DynamicResource ComboBoxNonEditableDisabledBackgroundBrush}" />
|
||||
<Setter TargetName="NonEditableBorder" Property="BorderBrush"
|
||||
Value="{DynamicResource ComboBoxNonEditableDisabledBorderBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEditable" Value="True">
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" />
|
||||
<Setter TargetName="NonEditableBorder" Property="Visibility" Value="Hidden" />
|
||||
<Setter TargetName="ToggleButton" Property="BorderThickness" Value="1,0,0,0" />
|
||||
<Setter TargetName="ToggleButton" Property="Focusable" Value="False" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,58 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ClassicAssist.Browser.Data
|
||||
{
|
||||
public class CategoriesConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object ReadJson( JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer )
|
||||
{
|
||||
switch ( reader.TokenType )
|
||||
{
|
||||
case JsonToken.StartArray:
|
||||
{
|
||||
JToken token = JToken.Load( reader );
|
||||
return token.ToObject<string[]>();
|
||||
}
|
||||
case JsonToken.String:
|
||||
{
|
||||
JToken token = JToken.Load( reader );
|
||||
return new[] { token.ToObject<string>() };
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanConvert( Type objectType )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Browser.Models;
|
||||
using LiteDB;
|
||||
using Newtonsoft.Json;
|
||||
using Octokit;
|
||||
using Repository = ClassicAssist.Browser.Models.Repository;
|
||||
|
||||
namespace ClassicAssist.Browser.Data
|
||||
{
|
||||
public class Database
|
||||
{
|
||||
private const string DATABASE_FILE = "macros.db";
|
||||
|
||||
private const string MANIFEST_URL =
|
||||
"https://raw.githubusercontent.com/Reetus/ClassicAssist-Macros/master/Macros/metadata.json";
|
||||
|
||||
private const string MACRO_RAW_BASEURL =
|
||||
"https://raw.githubusercontent.com/Reetus/ClassicAssist-Macros/master/Macros/";
|
||||
|
||||
private const string MACRO_BASEURL = "https://github.com/Reetus/ClassicAssist-Macros/tree/master/Macros/";
|
||||
|
||||
private const string REPOSITORY_OWNER = "Reetus";
|
||||
private const string REPOSITORY_NAME = "ClassicAssist-Macros";
|
||||
|
||||
private static Database _instance;
|
||||
private static readonly object _instanceLock = new object();
|
||||
private readonly GitHubClient _github;
|
||||
private readonly HttpClient _httpClient;
|
||||
private ILiteCollection<Macro> _macros;
|
||||
private ILiteCollection<Manifest> _manifest;
|
||||
private ILiteCollection<Repository> _repository;
|
||||
|
||||
private Database()
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
string databasePath = Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, DATABASE_FILE );
|
||||
LiteDatabase database = new LiteDatabase( $"Filename={databasePath};Connection=Shared" );
|
||||
_github = new GitHubClient( new ProductHeaderValue( "ClassicAssist" ) );
|
||||
|
||||
InitCollections( database );
|
||||
}
|
||||
|
||||
private void InitCollections( ILiteDatabase database )
|
||||
{
|
||||
_repository = database.GetCollection<Repository>( "repository" );
|
||||
_repository.EnsureIndex( x => x.Id );
|
||||
_manifest = database.GetCollection<Manifest>( "manifest" );
|
||||
_manifest.EnsureIndex( x => x.Id );
|
||||
_macros = database.GetCollection<Macro>( "macros" );
|
||||
_macros.EnsureIndex( x => x.Id );
|
||||
}
|
||||
|
||||
public string GetCommitHash()
|
||||
{
|
||||
Repository latest = _repository.Find( r => true ).OrderByDescending( r => r.DateTime ).FirstOrDefault() ??
|
||||
new Repository();
|
||||
|
||||
return latest.CommitHash;
|
||||
}
|
||||
|
||||
public async Task<string> GetGithubHash()
|
||||
{
|
||||
Reference reference = await _github.Git.Reference.Get( REPOSITORY_OWNER, REPOSITORY_NAME, "heads/master" );
|
||||
|
||||
string hash = reference.Object.Sha;
|
||||
|
||||
Repository latest = _repository.Find( r => true ).OrderByDescending( r => r.DateTime ).FirstOrDefault() ??
|
||||
new Repository();
|
||||
|
||||
latest.CommitHash = hash;
|
||||
latest.DateTime = DateTime.Now;
|
||||
_repository.Upsert( latest );
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public async Task<Manifest> GetManifest()
|
||||
{
|
||||
Manifest latest = _manifest.Find( r => true ).OrderByDescending( r => r.DateTime ).FirstOrDefault();
|
||||
|
||||
if ( latest != null && !( DateTime.Now - latest.DateTime >= TimeSpan.FromMinutes( 15 ) ) )
|
||||
{
|
||||
return latest;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( latest != null && GetCommitHash() == await GetGithubHash() )
|
||||
{
|
||||
return latest;
|
||||
}
|
||||
}
|
||||
catch ( RateLimitExceededException )
|
||||
{
|
||||
// Github throttle error
|
||||
}
|
||||
|
||||
latest = await FetchManifest();
|
||||
_manifest.Upsert( latest );
|
||||
|
||||
return latest;
|
||||
}
|
||||
|
||||
public async Task<string[]> GetMacros( IEnumerable<Filter> filter = null )
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
if ( filter == null )
|
||||
{
|
||||
return manifest.Files.Select( f => f.Name ).OrderBy( f => f ).ToArray();
|
||||
}
|
||||
|
||||
string shardFilter = filter.FirstOrDefault( t => t.FilterType == FilterType.Shard )?.Value;
|
||||
string eraFilter = filter.FirstOrDefault( t => t.FilterType == FilterType.Era )?.Value;
|
||||
string authorFilter = filter.FirstOrDefault( t => t.FilterType == FilterType.Author )?.Value;
|
||||
|
||||
Predicate<string[]> categoryPredicate =
|
||||
CategoryToPredicate( filter.FirstOrDefault( t => t.FilterType == FilterType.Category ) );
|
||||
|
||||
IEnumerable<string> macros = manifest.Files.Where( m =>
|
||||
( string.IsNullOrEmpty( shardFilter ) || m.Shard != null && m.Shard.Equals( shardFilter ) ) &&
|
||||
( string.IsNullOrEmpty( eraFilter ) || m.Era == null || m.Era.Equals( eraFilter ) ) &&
|
||||
( string.IsNullOrEmpty( authorFilter ) || m.Author == null || m.Author.Equals( authorFilter ) ) &&
|
||||
categoryPredicate( m.Categories ) ).Select( m => m.Name );
|
||||
|
||||
return macros.ToArray();
|
||||
}
|
||||
|
||||
private Predicate<string[]> CategoryToPredicate( Filter filter )
|
||||
{
|
||||
if ( filter.Category == null )
|
||||
{
|
||||
return f => true;
|
||||
}
|
||||
|
||||
return m =>
|
||||
{
|
||||
if ( m.Length < filter.Category.Values.Length )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < filter.Category.Values.Length; i++ )
|
||||
{
|
||||
string macroCategory = m[i];
|
||||
string filterCategory = filter.Category.Values[i];
|
||||
|
||||
if ( !macroCategory.Equals( filterCategory ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<string[]> GetShards()
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
return manifest.Files.Where( f => f.Shard != null ).Select( f => f.Shard ).OrderBy( f => f ).Distinct()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private async Task<Manifest> FetchManifest()
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.GetAsync( MANIFEST_URL );
|
||||
|
||||
string json = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Metadata[] obj = JsonConvert.DeserializeObject<Metadata[]>( json );
|
||||
|
||||
if ( obj == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Manifest manifest = new Manifest { Files = obj };
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
public static Database GetInstance()
|
||||
{
|
||||
// ReSharper disable once InvertIf
|
||||
if ( _instance == null )
|
||||
{
|
||||
lock ( _instanceLock )
|
||||
{
|
||||
if ( _instance == null )
|
||||
{
|
||||
_instance = new Database();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
public async Task<string[]> GetEras()
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
return manifest.Files.Where( f => f.Era != null ).Select( f => f.Era ).OrderBy( f => f ).Distinct()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public async Task<string[]> GetAuthors()
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
return manifest.Files.Where( f => f.Author != null ).Select( f => f.Author ).OrderBy( f => f ).Distinct()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public async Task<Category[]> GetCategories()
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
List<Category> results = new List<Category>();
|
||||
|
||||
IEnumerable<string[]> categories = manifest.Files.Select( f => f.Categories ).OrderBy( f => f[0] )
|
||||
.ThenBy( f => f.Length ).Distinct();
|
||||
|
||||
foreach ( string[] category in categories )
|
||||
{
|
||||
if ( category.Length == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( results.All( e => e.Name != category[0] ) )
|
||||
{
|
||||
results.Add( new Category { Name = category[0], Values = new[] { category[0] } } );
|
||||
}
|
||||
|
||||
if ( category.Length == 1 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string res = $"--{category[1]}";
|
||||
|
||||
if ( category.Length > 2 )
|
||||
{
|
||||
for ( int i = 2; i < category.Length; i++ )
|
||||
{
|
||||
res += $" ˃ {category[i]}";
|
||||
}
|
||||
}
|
||||
|
||||
if ( results.All( e => e.Name != res ) )
|
||||
{
|
||||
results.Add( new Category { Name = res, Values = category } );
|
||||
}
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public async Task<string> GetMacroByName( string value )
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
Metadata macro = manifest.Files.FirstOrDefault( f => f.Name == value );
|
||||
|
||||
if ( macro == null )
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
Macro cached = _macros.Find( m => m.Name == macro.Name && m.SHA1 == macro.SHA1 ).FirstOrDefault();
|
||||
|
||||
if ( cached != null )
|
||||
{
|
||||
return cached.Text;
|
||||
}
|
||||
|
||||
string url = string.Concat( MACRO_RAW_BASEURL, macro.FileName.Replace( '\\', '/' ) );
|
||||
|
||||
string result = await _httpClient.GetStringAsync( url );
|
||||
|
||||
if ( string.IsNullOrEmpty( result ) )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Macro inserted = new Macro { Name = macro.Name, SHA1 = macro.SHA1, Text = result };
|
||||
_macros.Insert( inserted );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async void OpenGithubMacroURL( string value )
|
||||
{
|
||||
Manifest manifest = await GetManifest();
|
||||
|
||||
Metadata macro = manifest.Files.FirstOrDefault( f => f.Name == value );
|
||||
|
||||
if ( macro == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string url = string.Concat( MACRO_BASEURL, macro.FileName.Replace( '\\', '/' ) );
|
||||
|
||||
Process.Start( url );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using ClassicAssist.Browser.Models;
|
||||
|
||||
namespace ClassicAssist.Browser.Data
|
||||
{
|
||||
public class Filter
|
||||
{
|
||||
public Category Category { get; set; }
|
||||
public FilterType FilterType { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace ClassicAssist.Browser.Data
|
||||
{
|
||||
public enum FilterType
|
||||
{
|
||||
Shard,
|
||||
Era,
|
||||
Author,
|
||||
Category
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<UserControl x:Class="ClassicAssist.Browser.MacroBrowserControl"
|
||||
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:resources="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared"
|
||||
xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:misc="clr-namespace:ClassicAssist.UI.Misc"
|
||||
xmlns:controls="clr-namespace:ClassicAssist.Browser.Controls"
|
||||
xmlns:data="clr-namespace:ClassicAssist.Browser.Data"
|
||||
xmlns:browser="clr-namespace:ClassicAssist.Browser"
|
||||
xmlns:controls1="clr-namespace:ClassicAssist.UI.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="550" d:DesignWidth="900">
|
||||
<UserControl.DataContext>
|
||||
<browser:MacroBrowserViewModel />
|
||||
</UserControl.DataContext>
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../Resources/DarkTheme.xaml" />
|
||||
<ResourceDictionary Source="../Resources/Icons.xaml" />
|
||||
<ResourceDictionary
|
||||
Source="../UI/Views/Debug/DebugToolBarStyle.xaml" />
|
||||
<ResourceDictionary Source="Controls/ClearableComboBox.xaml" />
|
||||
<ResourceDictionary Source="../Resources/LeftRightIconToggleButton.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="5" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<controls1:StretchyWrapPanel Orientation="Horizontal" Grid.Row="0" Margin="10,0,10,10">
|
||||
<controls1:StretchyWrapPanel.Resources>
|
||||
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
|
||||
<Setter Property="Margin" Value="10,0,10,0" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
</Style>
|
||||
<Style TargetType="{x:Type controls:ClearableComboBox}"
|
||||
BasedOn="{StaticResource {x:Type controls:ClearableComboBox}}">
|
||||
<Setter Property="MinWidth" Value="80" />
|
||||
</Style>
|
||||
</controls1:StretchyWrapPanel.Resources>
|
||||
<TextBlock Text="{x:Static resources:Strings.Shard_}" Margin="0,0,10,0" />
|
||||
<controls:ClearableComboBox ItemsSource="{Binding Shards}" ClearCommand="{Binding ClearCommand}"
|
||||
ClearCommandParameter="{x:Static data:FilterType.Shard}"
|
||||
SelectedItem="{Binding ShardFilter}" />
|
||||
<TextBlock Text="{x:Static resources:Strings.Era}" />
|
||||
<controls:ClearableComboBox ItemsSource="{Binding Eras}" ClearCommand="{Binding ClearCommand}"
|
||||
ClearCommandParameter="{x:Static data:FilterType.Era}"
|
||||
SelectedItem="{Binding EraFilter}" />
|
||||
<TextBlock Text="{x:Static resources:Strings.Author}" />
|
||||
<controls:ClearableComboBox ItemsSource="{Binding Authors}" ClearCommand="{Binding ClearCommand}"
|
||||
ClearCommandParameter="{x:Static data:FilterType.Author}"
|
||||
SelectedItem="{Binding AuthorFilter}" />
|
||||
<TextBlock Text="{x:Static resources:Strings.Category}" />
|
||||
<controls:ClearableComboBox ItemsSource="{Binding Categories}" ClearCommand="{Binding ClearCommand}"
|
||||
ClearCommandParameter="{x:Static data:FilterType.Category}"
|
||||
SelectedItem="{Binding CategoryFilter}" />
|
||||
</controls1:StretchyWrapPanel>
|
||||
<Grid Row="1" Margin="10,0,10,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition>
|
||||
<ColumnDefinition.Style>
|
||||
<Style TargetType="{x:Type ColumnDefinition}">
|
||||
<Setter Property="Width" Value="200" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsChecked, ElementName=ToggleButton}" Value="True">
|
||||
<Setter Property="Width" Value="0" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ColumnDefinition.Style>
|
||||
</ColumnDefinition>
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox x:Name="listBox" ItemsSource="{Binding Macros}" Grid.Column="0" Grid.Row="0"
|
||||
SelectedItem="{Binding SelectedItem}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" ToolTip="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<TextBlock Grid.Row="1" TextWrapping="Wrap">
|
||||
<Hyperlink NavigateUri="https://github.com/Reetus/ClassicAssist-Macros/blob/master/README.md"
|
||||
RequestNavigate="Hyperlink_RequestNavigate">
|
||||
<Run Text="{x:Static resources:Strings.Learn_how_to_contribute_your_own_macros___}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
|
||||
<Grid Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<avalonedit:TextEditor ShowLineNumbers="True" x:Name="CodeTextEditor" Grid.Row="0"
|
||||
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
|
||||
FontFamily="Consolas" Margin="10,0,0,0" IsReadOnly="True">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:AvalonEditBehaviour
|
||||
TextBinding="{Binding SelectedMacro}" />
|
||||
</i:Interaction.Behaviors>
|
||||
</avalonedit:TextEditor>
|
||||
<WrapPanel Grid.Row="1" Orientation="Horizontal" Margin="10,10,0,0">
|
||||
<WrapPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Margin" Value="0,0,10,0" />
|
||||
<Setter Property="Padding" Value="10,5" />
|
||||
<Setter Property="FontSize" Value="11" />
|
||||
</Style>
|
||||
</WrapPanel.Resources>
|
||||
<ToggleButton x:Name="ToggleButton" Height="15" Margin="0"
|
||||
Style="{DynamicResource LeftRightIconToggleButton}" VerticalAlignment="Center" />
|
||||
<Button Content="{x:Static resources:Strings.Copy_to_clipboard}"
|
||||
Command="{Binding CopyToClipboardCommand}" CommandParameter="{Binding SelectedMacro}" />
|
||||
<Button Content="{x:Static resources:Strings.Create_Macro}"
|
||||
Command="{Binding CreateMacroCommand}" CommandParameter="{Binding SelectedItem}" />
|
||||
<Button Content="{x:Static resources:Strings.Open_in_Github}"
|
||||
Command="{Binding OpenGithubCommand}"
|
||||
CommandParameter="{Binding SelectedItem, ElementName=listBox}" />
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<ProgressBar Grid.Row="1" IsIndeterminate="True"
|
||||
Visibility="{Binding Loading, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Navigation;
|
||||
using System.Xml;
|
||||
using ICSharpCode.AvalonEdit.Highlighting;
|
||||
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
|
||||
|
||||
namespace ClassicAssist.Browser
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MacroBrowserControl : UserControl
|
||||
{
|
||||
public MacroBrowserControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
CodeTextEditor.SyntaxHighlighting = HighlightingLoader.Load(
|
||||
new XmlTextReader( Path.Combine( Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location ),
|
||||
"Python.Dark.xshd" ) ), HighlightingManager.Instance );
|
||||
}
|
||||
|
||||
private void Hyperlink_RequestNavigate( object sender, RequestNavigateEventArgs e )
|
||||
{
|
||||
Process.Start( e.Uri.ToString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using ClassicAssist.Browser.Data;
|
||||
using ClassicAssist.Browser.Models;
|
||||
using ClassicAssist.Data.Macros;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using ClassicAssist.UI.ViewModels;
|
||||
using Microsoft.Scripting.Utils;
|
||||
|
||||
namespace ClassicAssist.Browser
|
||||
{
|
||||
public class MacroBrowserViewModel : BaseViewModel
|
||||
{
|
||||
private readonly Dictionary<string, Func<Task<string[]>>>
|
||||
_data = new Dictionary<string, Func<Task<string[]>>>();
|
||||
|
||||
private readonly Database _database = Database.GetInstance();
|
||||
private string _authorFilter;
|
||||
private ObservableCollection<string> _authors = new ObservableCollection<string>();
|
||||
|
||||
private ObservableCollection<Category> _categories = new ObservableCollection<Category>();
|
||||
private Category _categoryFilter;
|
||||
|
||||
private ICommand _clearCommand;
|
||||
private ICommand _copyToClipboardCommand;
|
||||
private ICommand _createMacroCommand;
|
||||
private string _eraFilter;
|
||||
private ObservableCollection<string> _eras = new ObservableCollection<string>();
|
||||
|
||||
private bool _loading = true;
|
||||
private ObservableCollection<string> _macros = new ObservableCollection<string>();
|
||||
private ICommand _openGithubCommand;
|
||||
private string _selectedItem;
|
||||
private string _selectedMacro;
|
||||
private string _shardFilter;
|
||||
private ObservableCollection<string> _shards = new ObservableCollection<string>();
|
||||
private Dispatcher _test;
|
||||
|
||||
public MacroBrowserViewModel()
|
||||
{
|
||||
_data.Add( nameof( Macros ), async () => await _database.GetMacros() );
|
||||
_data.Add( nameof( Shards ), async () => await _database.GetShards() );
|
||||
_data.Add( nameof( Eras ), async () => await _database.GetEras() );
|
||||
_data.Add( nameof( Authors ), async () => await _database.GetAuthors() );
|
||||
|
||||
_test = Dispatcher.CurrentDispatcher;
|
||||
|
||||
Task.Run( async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await RefreshData();
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
MessageBox.Show( $"{Strings.Failed_to_download_manifest___}\n\n{e.Message}", Strings.Error,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error );
|
||||
}
|
||||
finally
|
||||
{
|
||||
Loading = false;
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public string AuthorFilter
|
||||
{
|
||||
get => _authorFilter;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _authorFilter, value );
|
||||
ApplyFilter();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<string> Authors
|
||||
{
|
||||
get => _authors;
|
||||
set => SetProperty( ref _authors, value );
|
||||
}
|
||||
|
||||
public ObservableCollection<Category> Categories
|
||||
{
|
||||
get => _categories;
|
||||
set => SetProperty( ref _categories, value );
|
||||
}
|
||||
|
||||
public Category CategoryFilter
|
||||
{
|
||||
get => _categoryFilter;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _categoryFilter, value );
|
||||
ApplyFilter();
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ClearCommand => _clearCommand ?? ( _clearCommand = new RelayCommand( ClearFilter, o => true ) );
|
||||
|
||||
public ICommand CopyToClipboardCommand =>
|
||||
_copyToClipboardCommand ??
|
||||
( _copyToClipboardCommand = new RelayCommand( CopyToClipboard, o => SelectedItem != null ) );
|
||||
|
||||
public ICommand CreateMacroCommand =>
|
||||
_createMacroCommand ??
|
||||
( _createMacroCommand = new RelayCommandAsync( CreateMacro, o => SelectedItem != null ) );
|
||||
|
||||
public string EraFilter
|
||||
{
|
||||
get => _eraFilter;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _eraFilter, value );
|
||||
ApplyFilter();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<string> Eras
|
||||
{
|
||||
get => _eras;
|
||||
set => SetProperty( ref _eras, value );
|
||||
}
|
||||
|
||||
public bool Loading
|
||||
{
|
||||
get => _loading;
|
||||
set => SetProperty( ref _loading, value );
|
||||
}
|
||||
|
||||
public ObservableCollection<string> Macros
|
||||
{
|
||||
get => _macros;
|
||||
set => SetProperty( ref _macros, value );
|
||||
}
|
||||
|
||||
public ICommand OpenGithubCommand =>
|
||||
_openGithubCommand ?? ( _openGithubCommand = new RelayCommand( OpenGithub, o => SelectedItem != null ) );
|
||||
|
||||
public string SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _selectedItem, value );
|
||||
GetMacro( value ).ConfigureAwait( false );
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectedMacro
|
||||
{
|
||||
get => _selectedMacro;
|
||||
set => SetProperty( ref _selectedMacro, value );
|
||||
}
|
||||
|
||||
public string ShardFilter
|
||||
{
|
||||
get => _shardFilter;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _shardFilter, value );
|
||||
ApplyFilter();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<string> Shards
|
||||
{
|
||||
get => _shards;
|
||||
set => SetProperty( ref _shards, value );
|
||||
}
|
||||
|
||||
private async Task CreateMacro( object obj )
|
||||
{
|
||||
if ( !( obj is string macro ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MessageBoxResult result = MessageBox.Show( Strings.Macro_Warning, Strings.Warning, MessageBoxButton.YesNo,
|
||||
MessageBoxImage.Warning );
|
||||
|
||||
if ( result != MessageBoxResult.Yes )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MacroManager.GetInstance().NewMacro?.Invoke( macro, await _database.GetMacroByName( macro ) );
|
||||
}
|
||||
|
||||
private static void CopyToClipboard( object obj )
|
||||
{
|
||||
if ( !( obj is string macro ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Clipboard.SetText( macro );
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearFilter( object obj )
|
||||
{
|
||||
if ( !( obj is FilterType filterType ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( filterType )
|
||||
{
|
||||
case FilterType.Shard:
|
||||
ShardFilter = null;
|
||||
break;
|
||||
case FilterType.Era:
|
||||
EraFilter = null;
|
||||
break;
|
||||
case FilterType.Author:
|
||||
AuthorFilter = null;
|
||||
break;
|
||||
case FilterType.Category:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
private void ApplyFilter()
|
||||
{
|
||||
List<Filter> filters = new List<Filter>
|
||||
{
|
||||
new Filter { FilterType = FilterType.Shard, Value = ShardFilter },
|
||||
new Filter { FilterType = FilterType.Era, Value = EraFilter },
|
||||
new Filter { FilterType = FilterType.Author, Value = AuthorFilter },
|
||||
new Filter { FilterType = FilterType.Category, Category = CategoryFilter }
|
||||
};
|
||||
|
||||
_database.GetMacros( filters ).ContinueWith( t =>
|
||||
{
|
||||
_dispatcher.Invoke( () =>
|
||||
{
|
||||
Macros.Clear();
|
||||
Macros.AddRange( t.Result );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
private async Task GetMacro( string value )
|
||||
{
|
||||
try
|
||||
{
|
||||
Loading = true;
|
||||
string macro = await _database.GetMacroByName( value );
|
||||
|
||||
SelectedMacro = macro;
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
MessageBox.Show( $"{Strings.Failed_to_download_macro___}\n\n{e.Message}", Strings.Error,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error );
|
||||
}
|
||||
finally
|
||||
{
|
||||
Loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RefreshData()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach ( KeyValuePair<string, Func<Task<string[]>>> kvp in _data )
|
||||
{
|
||||
PropertyInfo property =
|
||||
GetType().GetProperty( kvp.Key, BindingFlags.Instance | BindingFlags.Public );
|
||||
|
||||
if ( property == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] data = await kvp.Value.Invoke();
|
||||
|
||||
if ( data == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ObservableCollection<string> obj = (ObservableCollection<string>) property.GetValue( this );
|
||||
|
||||
if ( obj == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_test.Invoke( () =>
|
||||
{
|
||||
obj.Clear();
|
||||
obj.AddRange( data );
|
||||
} );
|
||||
}
|
||||
|
||||
await _dispatcher.InvokeAsync( async () => Categories.AddRange( await _database.GetCategories() ) );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
MessageBox.Show( e.Message, Strings.Error );
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenGithub( object obj )
|
||||
{
|
||||
if ( !( obj is string macro ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_database.OpenGithubMacroURL( macro );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
namespace ClassicAssist.Browser.Models
|
||||
{
|
||||
public class Category
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string[] Values { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using LiteDB;
|
||||
|
||||
namespace ClassicAssist.Browser.Models
|
||||
{
|
||||
public class Macro
|
||||
{
|
||||
[BsonId]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string SHA1 { get; set; }
|
||||
public string Text { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using LiteDB;
|
||||
|
||||
namespace ClassicAssist.Browser.Models
|
||||
{
|
||||
public class Manifest
|
||||
{
|
||||
public DateTime DateTime { get; set; } = DateTime.Now;
|
||||
public Metadata[] Files { get; set; }
|
||||
|
||||
[BsonId]
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using ClassicAssist.Browser.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ClassicAssist.Browser.Models
|
||||
{
|
||||
public class Metadata
|
||||
{
|
||||
public string Author { get; set; }
|
||||
|
||||
[JsonConverter( typeof( CategoriesConverter ) )]
|
||||
public string[] Categories { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
public string Era { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public DateTime ModifiedDate { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string SHA1 { get; set; }
|
||||
public string Shard { get; set; }
|
||||
public int Size { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using LiteDB;
|
||||
|
||||
namespace ClassicAssist.Browser.Models
|
||||
{
|
||||
public class Repository
|
||||
{
|
||||
public string CommitHash { get; set; }
|
||||
public DateTime DateTime { get; set; } = DateTime.Now;
|
||||
|
||||
[BsonId]
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<OutputPath>..\Output\</OutputPath>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Configurations>Debug;Release;Develop;Linux</Configurations>
|
||||
<GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="UO\**" />
|
||||
<EmbeddedResource Remove="UO\**" />
|
||||
<None Remove="UO\**" />
|
||||
<Page Remove="UO\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Python.Dark.xshd" />
|
||||
<None Remove="Python.xshd" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Python.Dark.xshd">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Python.xshd">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="**\*.xaml.cs">
|
||||
<DependentUpon>%(Filename)</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AnimatedGif" Version="1.0.5" />
|
||||
<PackageReference Include="AvalonEdit" Version="6.0.1" />
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="3.8.1" />
|
||||
<PackageReference Include="IronPython" Version="2.7.10-candidate1" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.8" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Octokit" Version="0.48.0" />
|
||||
<PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
|
||||
<PackageReference Include="ReactiveUI.WPF" Version="11.4.17" />
|
||||
<PackageReference Include="Sentry" Version="2.1.4" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
||||
<PackageReference Include="System.Resources.Extensions" Version="8.0.0" />
|
||||
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ClassicAssist.Shared\ClassicAssist.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="cuoapi">
|
||||
<HintPath>..\ClassicAssist.Shared\cuoapi.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe">
|
||||
<HintPath>..\Output\net48\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="UI\Controls\TextBoxKey.xaml.cs">
|
||||
<DependentUpon>TextBoxKey.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Views\Autoloot\ClilocSelectionWindow.xaml.cs">
|
||||
<DependentUpon>ClilocSelectionWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Views\HotkeysTabControl.xaml.cs">
|
||||
<DependentUpon>HotkeysTabControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Views\DebugWindow.xaml.cs">
|
||||
<DependentUpon>DebugWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Sounds\Bike Horn.wav">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="UI\ViewModels\Agents\" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<BuildDate>$([System.DateTime]::op_Subtraction($([System.DateTime]::get_Now().get_Date()),$([System.DateTime]::new(2020,7,3))).get_TotalDays())</BuildDate>
|
||||
<Version>0.3.$(BuildDate).0</Version>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Linux|AnyCPU'">
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Develop|AnyCPU'">
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<DefineConstants>DEVELOP</DefineConstants>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Threading;
|
||||
using System.Windows.Threading;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using ClassicAssist.UI.ViewModels;
|
||||
using ClassicAssist.UI.Views;
|
||||
using ClassicAssist.UO.Objects;
|
||||
using UOC = ClassicAssist.Shared.UO.Commands;
|
||||
|
||||
namespace ClassicAssist.Data.Hotkeys.Commands
|
||||
{
|
||||
[HotkeyCommand( Name = "Grid Container Viewer" )]
|
||||
public class EntityCollectionViewerHotkey : HotkeyCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
int serial = UOC.GetTargeSerialAsync( Strings.Target_container___ ).Result;
|
||||
|
||||
Entity entity = Engine.Items.GetItem( serial ) ?? (Entity) Engine.Mobiles.GetMobile( serial );
|
||||
|
||||
if ( entity == null )
|
||||
{
|
||||
UOC.SystemMessage( Strings.Cannot_find_item___ );
|
||||
return;
|
||||
}
|
||||
|
||||
ItemCollection collection = new ItemCollection( entity.Serial );
|
||||
|
||||
switch ( entity )
|
||||
{
|
||||
case Item item:
|
||||
if ( item.Container == null )
|
||||
{
|
||||
UOC.WaitForContainerContents( item.Serial, 1000 );
|
||||
}
|
||||
|
||||
collection = item.Container;
|
||||
break;
|
||||
case Mobile mobile:
|
||||
collection = new ItemCollection( entity.Serial ) { mobile.GetEquippedItems() };
|
||||
break;
|
||||
}
|
||||
|
||||
Thread t = new Thread( () =>
|
||||
{
|
||||
EntityCollectionViewer window = new EntityCollectionViewer
|
||||
{
|
||||
DataContext = new EntityCollectionViewerViewModel( collection )
|
||||
};
|
||||
|
||||
window.Show();
|
||||
Dispatcher.Run();
|
||||
} ) { IsBackground = true };
|
||||
|
||||
t.SetApartmentState( ApartmentState.STA );
|
||||
t.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using static ClassicAssist.Shared.UO.Commands;
|
||||
|
||||
namespace ClassicAssist.Data.Hotkeys.Commands
|
||||
{
|
||||
[HotkeyCommand( Name = "Object Inspector" )]
|
||||
public class ObjectInspector : HotkeyCommand
|
||||
{
|
||||
public override async void Execute()
|
||||
{
|
||||
await InspectObjectAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Threading;
|
||||
using System.Windows.Threading;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.UI.Views;
|
||||
|
||||
namespace ClassicAssist.Data.Hotkeys.Commands
|
||||
{
|
||||
[HotkeyCommand( Name = "Show Chat Window" )]
|
||||
public class ShowChatWindowCommand : HotkeyCommand
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
Engine.Dispatcher.Invoke( () =>
|
||||
{
|
||||
Thread t = new Thread( () =>
|
||||
{
|
||||
ChatWindow window = new ChatWindow();
|
||||
|
||||
window.Show();
|
||||
Dispatcher.Run();
|
||||
} )
|
||||
{ IsBackground = true };
|
||||
|
||||
t.SetApartmentState( ApartmentState.STA );
|
||||
t.Start();
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Threading;
|
||||
using ClassicAssist.UI.Views;
|
||||
|
||||
namespace ClassicAssist.Data.Hotkeys.Commands
|
||||
{
|
||||
[HotkeyCommand( Category = "Commands", Name = "Show GIF Capture" )]
|
||||
public class ShowGIFCaptureWindow : HotkeyCommand
|
||||
{
|
||||
private GIFRecorderWindow _window;
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
Thread t = new Thread( () =>
|
||||
{
|
||||
_window = new GIFRecorderWindow();
|
||||
_window.ShowDialog();
|
||||
} );
|
||||
|
||||
t.SetApartmentState( ApartmentState.STA );
|
||||
t.IsBackground = true;
|
||||
t.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
using ClassicAssist.Misc;
|
||||
using ICSharpCode.AvalonEdit.CodeCompletion;
|
||||
using ICSharpCode.AvalonEdit.Document;
|
||||
using ICSharpCode.AvalonEdit.Editing;
|
||||
|
||||
namespace ClassicAssist.Data.Macros
|
||||
{
|
||||
public class PythonCompletionData : ICompletionData
|
||||
{
|
||||
public PythonCompletionData( string text, string description, string insertText )
|
||||
{
|
||||
Description = description;
|
||||
Text = insertText;
|
||||
Content = text;
|
||||
}
|
||||
|
||||
public void Complete( TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs )
|
||||
{
|
||||
DocumentLine line = textArea.Document.Lines[textArea.Caret.Line - 1];
|
||||
|
||||
textArea.Document.Replace(
|
||||
new TextSegment { StartOffset = line.Offset, EndOffset = line.EndOffset, Length = line.Length }, Text );
|
||||
}
|
||||
|
||||
public ImageSource Image => Properties.Resources.python.ToImageSource();
|
||||
public string Text { get; }
|
||||
|
||||
public object Content { get; }
|
||||
public object Description { get; }
|
||||
public double Priority { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using ClassicAssist.UI.Misc;
|
||||
|
||||
namespace ClassicAssist.Data.Skills
|
||||
{
|
||||
public class SkillComparer : IComparer
|
||||
{
|
||||
private readonly ListSortDirection _direction;
|
||||
private readonly SkillsGridViewColumn.Enums _sortField;
|
||||
|
||||
public SkillComparer( ListSortDirection direction, SkillsGridViewColumn.Enums sortField )
|
||||
{
|
||||
_direction = direction;
|
||||
_sortField = sortField;
|
||||
}
|
||||
|
||||
public int Compare( object x, object y )
|
||||
{
|
||||
SkillEntry first = (SkillEntry) x;
|
||||
SkillEntry second = (SkillEntry) y;
|
||||
|
||||
if ( first == null || second == null )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result;
|
||||
|
||||
switch ( _sortField )
|
||||
{
|
||||
case SkillsGridViewColumn.Enums.Name:
|
||||
result = string.Compare( first.Skill.Name, second.Skill.Name, StringComparison.Ordinal );
|
||||
break;
|
||||
case SkillsGridViewColumn.Enums.Value:
|
||||
result = first.Value.CompareTo( second.Value );
|
||||
break;
|
||||
case SkillsGridViewColumn.Enums.Base:
|
||||
result = first.Base.CompareTo( second.Base );
|
||||
break;
|
||||
case SkillsGridViewColumn.Enums.Delta:
|
||||
result = first.Delta.CompareTo( second.Delta );
|
||||
|
||||
if ( result == 0 )
|
||||
{
|
||||
result = first.Base.CompareTo( second.Base );
|
||||
}
|
||||
|
||||
break;
|
||||
case SkillsGridViewColumn.Enums.Cap:
|
||||
result = first.Cap.CompareTo( second.Cap );
|
||||
break;
|
||||
case SkillsGridViewColumn.Enums.LockStatus:
|
||||
result = first.LockStatus.CompareTo( second.LockStatus );
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if ( _direction == ListSortDirection.Descending )
|
||||
{
|
||||
result = -result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows.Threading;
|
||||
using ClassicAssist;
|
||||
using ClassicAssist.Data;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.UI.Misc;
|
||||
using ClassicAssist.UI.ViewModels;
|
||||
using ClassicAssist.UI.Views;
|
||||
using ClassicAssist.UO.Data;
|
||||
using CUO_API;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SEngine = ClassicAssist.Shared.Engine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Assistant
|
||||
{
|
||||
public static unsafe class Engine
|
||||
{
|
||||
private static PluginHeader* _plugin;
|
||||
private static Thread _mainThread;
|
||||
private static MainWindow _window;
|
||||
|
||||
public static string StartupPath { get; set; }
|
||||
|
||||
public static void Install( PluginHeader* plugin )
|
||||
{
|
||||
_plugin = plugin;
|
||||
|
||||
StartupPath = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
|
||||
|
||||
if ( StartupPath == null )
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Assembly.LoadFile( Path.Combine( StartupPath, "ClassicAssist.Shared.dll" ) );
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
|
||||
|
||||
Initialize( plugin );
|
||||
|
||||
_mainThread = new Thread( () =>
|
||||
{
|
||||
SEngine.Dispatcher = new WPFDispatcher( Dispatcher.CurrentDispatcher );
|
||||
SEngine.UIInvoker = new WPFUIInvoker( Dispatcher.CurrentDispatcher );
|
||||
_window = new MainWindow();
|
||||
_window.Show();
|
||||
|
||||
Dispatcher.Run();
|
||||
} ) { IsBackground = true };
|
||||
|
||||
_mainThread.SetApartmentState( ApartmentState.STA );
|
||||
_mainThread.Start();
|
||||
}
|
||||
|
||||
private static void Initialize( PluginHeader* plugin )
|
||||
{
|
||||
SEngine.Install( plugin, new WPFMessageBoxProvider() );
|
||||
|
||||
Options.LoadEvent += OnOptionsLoad;
|
||||
Options.SaveEvent += OnOptionsSave;
|
||||
}
|
||||
|
||||
private static void OnOptionsSave( JObject obj )
|
||||
{
|
||||
BaseViewModel[] instances = BaseViewModel.Instances;
|
||||
|
||||
foreach ( BaseViewModel instance in instances )
|
||||
{
|
||||
if ( instance is ISettingProvider settingProvider )
|
||||
{
|
||||
settingProvider.Serialize( obj );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnOptionsLoad( JObject json, Options options )
|
||||
{
|
||||
BaseViewModel[] instances = BaseViewModel.Instances;
|
||||
|
||||
foreach ( BaseViewModel instance in instances )
|
||||
{
|
||||
if ( instance is ISettingProvider settingProvider )
|
||||
{
|
||||
settingProvider.Deserialize( json, options );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Assembly OnAssemblyResolve( object sender, ResolveEventArgs args )
|
||||
{
|
||||
string assemblyname = new AssemblyName( args.Name ).Name;
|
||||
|
||||
string[] searchPaths = { StartupPath, RuntimeEnvironment.GetRuntimeDirectory() };
|
||||
|
||||
if ( assemblyname.Contains( "Colletions" ) )
|
||||
{
|
||||
assemblyname = "System.Collections";
|
||||
}
|
||||
|
||||
foreach ( string searchPath in searchPaths )
|
||||
{
|
||||
string fullPath = Path.Combine( searchPath, assemblyname + ".dll" );
|
||||
|
||||
string culture = new AssemblyName( args.Name ).CultureName;
|
||||
|
||||
if ( !File.Exists( fullPath ) )
|
||||
{
|
||||
string culturePath = Path.Combine( searchPath, culture, assemblyname + ".dll" );
|
||||
|
||||
if ( File.Exists( culturePath ) )
|
||||
{
|
||||
fullPath = culturePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Assembly assembly = Assembly.LoadFrom( fullPath );
|
||||
|
||||
return assembly;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#region License
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace ClassicAssist
|
||||
{
|
||||
public static class ExtensionMethods
|
||||
{
|
||||
public static ImageSource ToImageSource( this Bitmap bmp )
|
||||
{
|
||||
IntPtr handle = bmp.GetHbitmap();
|
||||
|
||||
try
|
||||
{
|
||||
return Imaging.CreateBitmapSourceFromHBitmap( handle, IntPtr.Zero, Int32Rect.Empty,
|
||||
BitmapSizeOptions.FromEmptyOptions() );
|
||||
}
|
||||
finally
|
||||
{
|
||||
Misc.ExtensionMethods.DeleteObject( handle );
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmapSource ToBitmapSource( this Bitmap bmp )
|
||||
{
|
||||
return Imaging.CreateBitmapSourceFromHBitmap( bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
|
||||
BitmapSizeOptions.FromWidthAndHeight( bmp.Width, bmp.Height ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ClassicAssist.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClassicAssist.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap arrow_down {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("arrow_down", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap arrow_up {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("arrow_up", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap padlock {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("padlock", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap python {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("python", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to # All lines are trimmed. Empty lines and lines starting with '#' are ignored
|
||||
///# Table for converting body values to item numbers
|
||||
///# Format:
|
||||
///# Body<tab>Item
|
||||
///
|
||||
///1 0x20DF
|
||||
///2 0x20D8
|
||||
///3 0x25B8
|
||||
///4 0x20D9
|
||||
///5 0x211D
|
||||
///6 0x211A
|
||||
///7 0x25AF
|
||||
///8 0x2582
|
||||
///9 0x2584
|
||||
///10 0x2584
|
||||
///11 0x25C4
|
||||
///12 0x20D6
|
||||
///13 0x25D7
|
||||
///14 0x20D7
|
||||
///15 0x25D9
|
||||
///16 0x25DD
|
||||
///17 0x25AE
|
||||
///18 0x20D8
|
||||
///19 0x25C4
|
||||
///20 0x25C5
|
||||
///21 0x25BF
|
||||
///22 0x258F
|
||||
///23 0x25D0
|
||||
///24 0x25A4
|
||||
///25 0x25D1
|
||||
///26 0x25C7
|
||||
///27 0x25D1
|
||||
///28 0x25C6
|
||||
///29 0x2592
|
||||
///30 0x20DC
|
||||
///31 0x2595
|
||||
///33 0x20DE
|
||||
///34 0x25D2 [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
public static string Shrink {
|
||||
get {
|
||||
return ResourceManager.GetString("Shrink", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="arrow_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\arrow_down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="arrow_up" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\arrow_up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="padlock" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\lock.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="python" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\python.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Shrink" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\Shrink.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<SyntaxDefinition name="Python" extensions=".py;.pyw" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
<Color name="Comment" foreground="#FF6A8934" exampleText="# comment" />
|
||||
<Color name="String" foreground="#FFC56C79" exampleText="name = 'abc'" />
|
||||
<Color name="MethodCall" foreground="#FFDCD079" exampleText="def Hello()" />
|
||||
<Color name="NumberLiteral" foreground="#FFB5CEA8" exampleText="0xf00f" />
|
||||
<Color name="NumberLiteral2" foreground="#FFB5CEA8" exampleText="1000" />
|
||||
<Color name="Keywords" foreground="#FF9CDCFE" exampleText="if" />
|
||||
|
||||
<Property name="DocCommentMarker" value="///" />
|
||||
|
||||
<RuleSet name="CommentMarkerSet">
|
||||
<Keywords fontWeight="bold" foreground="Red">
|
||||
<Word>TODO</Word>
|
||||
<Word>FIXME</Word>
|
||||
</Keywords>
|
||||
<Keywords fontWeight="bold" foreground="#E0E000">
|
||||
<Word>HACK</Word>
|
||||
<Word>UNDONE</Word>
|
||||
</Keywords>
|
||||
</RuleSet>
|
||||
|
||||
<RuleSet>
|
||||
<Span color="Comment" ruleSet="CommentMarkerSet">
|
||||
<Begin>\#</Begin>
|
||||
</Span>
|
||||
|
||||
<Span color="String" multiline="true">
|
||||
<Begin>'''</Begin>
|
||||
<End>'''</End>
|
||||
</Span>
|
||||
<Span color="String" multiline="true">
|
||||
<Begin>"""</Begin>
|
||||
<End>"""</End>
|
||||
</Span>
|
||||
|
||||
<Span color="String">
|
||||
<Begin>"</Begin>
|
||||
<End>"</End>
|
||||
<RuleSet>
|
||||
<Span begin="\\" end="." />
|
||||
</RuleSet>
|
||||
</Span>
|
||||
<Span color="String">
|
||||
<Begin>'</Begin>
|
||||
<End>'</End>
|
||||
<RuleSet>
|
||||
<Span begin="\\" end="." />
|
||||
</RuleSet>
|
||||
</Span>
|
||||
|
||||
<Keywords color="Keywords">
|
||||
<Word>and</Word>
|
||||
<Word>as</Word>
|
||||
<Word>assert</Word>
|
||||
<Word>break</Word>
|
||||
<Word>class</Word>
|
||||
<Word>continue</Word>
|
||||
<Word>def</Word>
|
||||
<Word>del</Word>
|
||||
<Word>elif</Word>
|
||||
<Word>else</Word>
|
||||
<Word>except</Word>
|
||||
<Word>exec</Word>
|
||||
<Word>False</Word>
|
||||
<Word>finally</Word>
|
||||
<Word>for</Word>
|
||||
<Word>from</Word>
|
||||
<Word>global</Word>
|
||||
<Word>if</Word>
|
||||
<Word>import</Word>
|
||||
<Word>in</Word>
|
||||
<Word>is</Word>
|
||||
<Word>lambda</Word>
|
||||
<Word>None</Word>
|
||||
<Word>nonlocal</Word>
|
||||
<Word>not</Word>
|
||||
<Word>or</Word>
|
||||
<Word>pass</Word>
|
||||
<Word>print</Word>
|
||||
<Word>raise</Word>
|
||||
<Word>return</Word>
|
||||
<Word>True</Word>
|
||||
<Word>try</Word>
|
||||
<Word>while</Word>
|
||||
<Word>with</Word>
|
||||
<Word>yield</Word>
|
||||
<Word>async</Word>
|
||||
<Word>await</Word>
|
||||
</Keywords>
|
||||
|
||||
<Rule color="MethodCall">
|
||||
\b
|
||||
[\d\w_]+ # an identifier
|
||||
(?=\s*\() # followed by (
|
||||
</Rule>
|
||||
<Rule color="NumberLiteral">
|
||||
\b0[xX][0-9a-fA-F]+ # hex number
|
||||
</Rule>
|
||||
<Rule color="NumberLiteral2">
|
||||
\b[0-9]+ # number
|
||||
</Rule>
|
||||
</RuleSet>
|
||||
</SyntaxDefinition>
|
||||
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0"?>
|
||||
<SyntaxDefinition name="Python" extensions=".py;.pyw" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
<Color name="Comment" foreground="Green" exampleText="# comment" />
|
||||
<Color name="String" foreground="Gray" exampleText="name = 'abc'"/>
|
||||
<Color name="MethodCall" foreground="Purple" exampleText="def Hello()"/>
|
||||
<Color name="NumberLiteral" foreground="DarkBlue" exampleText="3.1415f"/>
|
||||
<Color name="Keywords" fontWeight="bold" foreground="Blue" exampleText="if"/>
|
||||
|
||||
<Property name="DocCommentMarker" value="///" />
|
||||
|
||||
<RuleSet name="CommentMarkerSet">
|
||||
<Keywords fontWeight="bold" foreground="Red">
|
||||
<Word>TODO</Word>
|
||||
<Word>FIXME</Word>
|
||||
</Keywords>
|
||||
<Keywords fontWeight="bold" foreground="#E0E000">
|
||||
<Word>HACK</Word>
|
||||
<Word>UNDONE</Word>
|
||||
</Keywords>
|
||||
</RuleSet>
|
||||
|
||||
<RuleSet>
|
||||
<Span color="Comment" ruleSet="CommentMarkerSet">
|
||||
<Begin>\#</Begin>
|
||||
</Span>
|
||||
|
||||
<Span color="String" multiline="true">
|
||||
<Begin>'''</Begin>
|
||||
<End>'''</End>
|
||||
</Span>
|
||||
<Span color="String" multiline="true">
|
||||
<Begin>"""</Begin>
|
||||
<End>"""</End>
|
||||
</Span>
|
||||
|
||||
<Span color="String">
|
||||
<Begin>"</Begin>
|
||||
<End>"</End>
|
||||
<RuleSet>
|
||||
<Span begin="\\" end="."/>
|
||||
</RuleSet>
|
||||
</Span>
|
||||
<Span color="String">
|
||||
<Begin>'</Begin>
|
||||
<End>'</End>
|
||||
<RuleSet>
|
||||
<Span begin="\\" end="."/>
|
||||
</RuleSet>
|
||||
</Span>
|
||||
|
||||
<Keywords color="Keywords">
|
||||
<Word>and</Word>
|
||||
<Word>as</Word>
|
||||
<Word>assert</Word>
|
||||
<Word>break</Word>
|
||||
<Word>class</Word>
|
||||
<Word>continue</Word>
|
||||
<Word>def</Word>
|
||||
<Word>del</Word>
|
||||
<Word>elif</Word>
|
||||
<Word>else</Word>
|
||||
<Word>except</Word>
|
||||
<Word>exec</Word>
|
||||
<Word>False</Word>
|
||||
<Word>finally</Word>
|
||||
<Word>for</Word>
|
||||
<Word>from</Word>
|
||||
<Word>global</Word>
|
||||
<Word>if</Word>
|
||||
<Word>import</Word>
|
||||
<Word>in</Word>
|
||||
<Word>is</Word>
|
||||
<Word>lambda</Word>
|
||||
<Word>None</Word>
|
||||
<Word>nonlocal</Word>
|
||||
<Word>not</Word>
|
||||
<Word>or</Word>
|
||||
<Word>pass</Word>
|
||||
<Word>print</Word>
|
||||
<Word>raise</Word>
|
||||
<Word>return</Word>
|
||||
<Word>True</Word>
|
||||
<Word>try</Word>
|
||||
<Word>while</Word>
|
||||
<Word>with</Word>
|
||||
<Word>yield</Word>
|
||||
<Word>async</Word>
|
||||
<Word>await</Word>
|
||||
</Keywords>
|
||||
|
||||
<Rule color="MethodCall">
|
||||
\b
|
||||
[\d\w_]+ # an identifier
|
||||
(?=\s*\() # followed by (
|
||||
</Rule>
|
||||
<Rule color="NumberLiteral">
|
||||
\b0[xX][0-9a-fA-F]+ # hex number
|
||||
( \b\d+(\.[0-9]+)? #number with optional floating point
|
||||
| \.[0-9]+ #or just starting with floating point
|
||||
)
|
||||
([eE][+-]?[0-9]+)? # optional exponent
|
||||
</Rule>
|
||||
</RuleSet>
|
||||
</SyntaxDefinition>
|
||||
@@ -0,0 +1,190 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:ClassicAssist.Resources">
|
||||
<Color x:Key="BackgroundColor1">#151515</Color>
|
||||
<Color x:Key="BackgroundColor2">#1A1A1A</Color>
|
||||
<Color x:Key="BackgroundColor3">#1E1E1E</Color>
|
||||
<Color x:Key="BackgroundColor4">#292929</Color>
|
||||
<Color x:Key="BackgroundColor5">#333333</Color>
|
||||
<Color x:Key="BackgroundColor6">#4B4B4B</Color>
|
||||
<Color x:Key="ForegroundColor5">#151515</Color>
|
||||
<Color x:Key="ForegroundColor4">#626262</Color>
|
||||
<Color x:Key="ForegroundColor3">#8A8A8A</Color>
|
||||
<Color x:Key="ForegroundColor2">#C4C4C4</Color>
|
||||
<Color x:Key="ForegroundColor1">#F0F0F0</Color>
|
||||
<Color x:Key="SelectionColor1">#17252D</Color>
|
||||
<Color x:Key="SelectionColor1Emphasized">#193644</Color>
|
||||
<Color x:Key="SelectionColor2">#207097</Color>
|
||||
<Color x:Key="SelectionColor2Emphasized">#26A0DA</Color>
|
||||
<Color x:Key="RedColor">#E31212</Color>
|
||||
<!-- Generic -->
|
||||
<SolidColorBrush x:Key="BackgroundColor1Brush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="BackgroundColor2Brush" Color="{DynamicResource BackgroundColor2}" />
|
||||
<SolidColorBrush x:Key="BackgroundColor3Brush" Color="{DynamicResource BackgroundColor3}" />
|
||||
<SolidColorBrush x:Key="BackgroundColor4Brush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="BackgroundColor5Brush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="BackgroundColor6Brush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ForegroundColor5Brush" Color="{DynamicResource ForegroundColor5}" />
|
||||
<SolidColorBrush x:Key="ForegroundColor4Brush" Color="{DynamicResource ForegroundColor4}" />
|
||||
<SolidColorBrush x:Key="ForegroundColor3Brush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="ForegroundColor2Brush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="ForegroundColor1Brush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="SelectionColor1Brush" Color="{DynamicResource SelectionColor1}" />
|
||||
<SolidColorBrush x:Key="SelectionColor1EmphasizedBrush" Color="{DynamicResource SelectionColor1Emphasized}" />
|
||||
<SolidColorBrush x:Key="SelectionColor2Brush" Color="{DynamicResource SelectionColor2}" />
|
||||
<SolidColorBrush x:Key="SelectionColor2EmphasizedBrush" Color="{DynamicResource SelectionColor2Emphasized}" />
|
||||
<SolidColorBrush x:Key="RedColorBrush" Color="{DynamicResource RedColor}" />
|
||||
|
||||
<!-- Window -->
|
||||
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="{DynamicResource BackgroundColor3}" />
|
||||
<SolidColorBrush x:Key="WindowShadowBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="WindowForegroundBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
|
||||
<!-- TabControl -->
|
||||
<SolidColorBrush x:Key="TabControlBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="TabControlContainedBackgroundBrush" Color="{DynamicResource BackgroundColor2}" />
|
||||
<SolidColorBrush x:Key="TabControlBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TabControlTabBackgroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="TabControlTabForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="TabControlTabHoverBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="TabControlTabSelectedBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TabControlTabDisabledBackgroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="TabControlTabDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
<!-- Button -->
|
||||
<SolidColorBrush x:Key="ButtonBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="ButtonBorderBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="ButtonForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="ButtonHoverBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="ButtonHoverBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ButtonPressBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ButtonPressBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ButtonDisabledBackgroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="ButtonDisabledBorderBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="ButtonDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
<!-- TextBox -->
|
||||
<SolidColorBrush x:Key="TextBoxBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="TextBoxBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TextBoxForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="TextBoxHoverBackgroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="TextBoxHoverBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TextBoxFocusBackgroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="TextBoxFocusBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TextBoxDisabledBackgroundBrush" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="TextBoxDisabledBorderBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="TextBoxDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
<!-- ComboBox -->
|
||||
<SolidColorBrush x:Key="ComboBoxNonEditableBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="ComboBoxNonEditableBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxNonEditableHoverBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxNonEditableDisabledBackgroundBrush" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ComboBoxNonEditableDisabledBorderBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonBackgroundBrush" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonHoverBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonPressBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonCheckedBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonDisabledBackgroundBrush" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonDisabledBorderBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="ComboBoxButtonDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="ComboBoxListBackgroundBrush" Color="{DynamicResource BackgroundColor2}" />
|
||||
<SolidColorBrush x:Key="ComboBoxListBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
|
||||
<SolidColorBrush x:Key="ComboBoxSelectionBackgroundBrush" Color="{DynamicResource SelectionColor1Emphasized}" />
|
||||
<SolidColorBrush x:Key="ComboBoxSelectionBorderBrush" Color="{DynamicResource SelectionColor2Emphasized}" />
|
||||
<SolidColorBrush x:Key="ComboBoxHoverBackgroundBrush" Color="{DynamicResource SelectionColor1}" />
|
||||
<SolidColorBrush x:Key="ComboBoxHoverBorderBrush" Color="{DynamicResource SelectionColor2}" />
|
||||
<SolidColorBrush x:Key="ComboBoxInactiveSelectionBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ComboBoxInactiveSelectionBorderBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
|
||||
|
||||
<!-- TreeView -->
|
||||
<SolidColorBrush x:Key="TreeViewButtonForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="TreeViewButtonDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="TreeViewBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="TreeViewBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TreeViewItemBorderBrush" Color="{DynamicResource SelectionColor2Emphasized}" />
|
||||
<SolidColorBrush x:Key="TreeViewItemInactiveBorderBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="TreeViewSelectecBackgroudBrush" Color="{DynamicResource SelectionColor1Emphasized}" />
|
||||
<SolidColorBrush x:Key="TreeViewInactiveSelectecBackgroudBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="TreeViewForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="TreeViewDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
|
||||
<!-- ValidationErrorOverlay -->
|
||||
<SolidColorBrush x:Key="ValidationErrorOverlayBorderBrush" Color="{DynamicResource RedColor}" />
|
||||
<SolidColorBrush x:Key="ValidationErrorOverlayForegroundBrush" Color="{DynamicResource ForegroundColor5}" />
|
||||
|
||||
<!-- CheckBox -->
|
||||
<SolidColorBrush x:Key="CheckBoxBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="CheckBoxForegroundBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="CheckBoxBorderBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="CheckBoxMarkBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="CheckBoxDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="CheckBoxDisabledBorderBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="CheckBoxDisabledMarkBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
<!-- RadioButton -->
|
||||
<SolidColorBrush x:Key="RadioButtonBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="RadioButtonForegroundBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="RadioButtonBorderBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="RadioButtonMarkBrush" Color="{DynamicResource ForegroundColor1}" />
|
||||
<SolidColorBrush x:Key="RadioButtonDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="RadioButtonDisabledBorderBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="RadioButtonDisabledMarkBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
<!-- GroupBox -->
|
||||
<SolidColorBrush x:Key="GroupBoxBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="GroupBoxContainedBackgroundBrush" Color="{DynamicResource BackgroundColor2}" />
|
||||
<SolidColorBrush x:Key="GroupBoxBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="GroupBoxHeaderForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
|
||||
<!-- ListBox -->
|
||||
<SolidColorBrush x:Key="ListBoxBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="ListBoxForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="ListBoxBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="ListBoxItemFirstBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="ListBoxItemSecondBackgroundBrush" Color="{DynamicResource BackgroundColor2}" />
|
||||
<SolidColorBrush x:Key="ListBoxDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="ListBoxSelectedInactiveBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
|
||||
<!-- DataGrid -->
|
||||
<SolidColorBrush x:Key="DataGridBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="DataGridForegroundBrush" Color="{DynamicResource ForegroundColor2}" />
|
||||
<SolidColorBrush x:Key="DataGridBorderBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="DataGridLinesBrush" Color="{DynamicResource BackgroundColor3}" />
|
||||
<SolidColorBrush x:Key="DataGridSelectAllButtonBackgroundBrush" Color="{DynamicResource BackgroundColor5}" />
|
||||
<SolidColorBrush x:Key="DataGridHeaderBackgroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
<SolidColorBrush x:Key="DataGridRowHeaderBackgroundBrush" Color="{DynamicResource BackgroundColor3}" />
|
||||
<SolidColorBrush x:Key="DataGridRowFirstBackgroundBrush" Color="{DynamicResource BackgroundColor1}" />
|
||||
<SolidColorBrush x:Key="DataGridRowSecondBackgroundBrush" Color="{DynamicResource BackgroundColor2}" />
|
||||
<SolidColorBrush x:Key="DataGridRowSelectedBackgroundBrush" Color="{DynamicResource SelectionColor1}" />
|
||||
<SolidColorBrush x:Key="DataGridCellSelectedBackgroundBrush" Color="{DynamicResource SelectionColor2}" />
|
||||
<SolidColorBrush x:Key="DataGridDisabledForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
|
||||
<!-- ScrollBar -->
|
||||
<SolidColorBrush x:Key="ScrollBarBackgroundBrush" Color="{DynamicResource BackgroundColor3}" />
|
||||
<SolidColorBrush x:Key="ScrollBarForegroundBrush" Color="{DynamicResource ForegroundColor4}" />
|
||||
<SolidColorBrush x:Key="ScrollBarHoverForegroundBrush" Color="{DynamicResource ForegroundColor3}" />
|
||||
<SolidColorBrush x:Key="ScrollBarDisabledForegroundBrush" Color="{DynamicResource ForegroundColor4}" />
|
||||
|
||||
<!-- ScrollViewer -->
|
||||
<SolidColorBrush x:Key="ScrollViewerBackgroundBrush" Color="{DynamicResource BackgroundColor3}" />
|
||||
|
||||
<!-- GridSplitter -->
|
||||
<SolidColorBrush x:Key="GridSplitterBackgroundBrush" Color="{DynamicResource BackgroundColor6}" />
|
||||
<SolidColorBrush x:Key="GridSplitterForegroundBrush" Color="{DynamicResource BackgroundColor4}" />
|
||||
|
||||
<!-- Custom -->
|
||||
<SolidColorBrush x:Key="ThemeBackgroundBrush" Color="#272727" />
|
||||
<SolidColorBrush x:Key="ThemeForegroundBrush" Color="#CCCCCC" />
|
||||
<SolidColorBrush x:Key="ThemeWindowBackgroundBrush" Color="Black" />
|
||||
<SolidColorBrush x:Key="ThemeBorderBrush" Color="#474747" />
|
||||
<SolidColorBrush x:Key="ThemeInnerControlBackgroundBrush" Color="#151515" />
|
||||
<SolidColorBrush x:Key="ThemeTabBackgroundBrush" Color="#121212" />
|
||||
<SolidColorBrush x:Key="IconForegroundBrush" Color="#CCCCCC" />
|
||||
|
||||
</ResourceDictionary>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,43 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:resources="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Icons.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Style x:Key="FocusVisual">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="LeftRightIconToggleButton" TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||
<Image>
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
|
||||
<Setter Property="Source" Value="{DynamicResource RightChevron}"/>
|
||||
<Setter Property="ToolTip" Value="{x:Static resources:Strings.Show}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}}" Value="False">
|
||||
<Setter Property="Source" Value="{DynamicResource LeftChevron}"/>
|
||||
<Setter Property="ToolTip" Value="{x:Static resources:Strings.Hide}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,7 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:ClassicAssist.UI.Controls">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="DarkTheme.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,442 @@
|
||||
# All lines are trimmed. Empty lines and lines starting with '#' are ignored
|
||||
# Table for converting body values to item numbers
|
||||
# Format:
|
||||
# Body<tab>Item
|
||||
|
||||
1 0x20DF
|
||||
2 0x20D8
|
||||
3 0x25B8
|
||||
4 0x20D9
|
||||
5 0x211D
|
||||
6 0x211A
|
||||
7 0x25AF
|
||||
8 0x2582
|
||||
9 0x2584
|
||||
10 0x2584
|
||||
11 0x25C4
|
||||
12 0x20D6
|
||||
13 0x25D7
|
||||
14 0x20D7
|
||||
15 0x25D9
|
||||
16 0x25DD
|
||||
17 0x25AE
|
||||
18 0x20D8
|
||||
19 0x25C4
|
||||
20 0x25C5
|
||||
21 0x25BF
|
||||
22 0x258F
|
||||
23 0x25D0
|
||||
24 0x25A4
|
||||
25 0x25D1
|
||||
26 0x25C7
|
||||
27 0x25D1
|
||||
28 0x25C6
|
||||
29 0x2592
|
||||
30 0x20DC
|
||||
31 0x2595
|
||||
33 0x20DE
|
||||
34 0x25D2
|
||||
35 0x20DE
|
||||
36 0x20DE
|
||||
37 0x25D2
|
||||
38 0x2585
|
||||
39 0x25A6
|
||||
40 0x2586
|
||||
41 0x25AE
|
||||
42 0x25B7
|
||||
43 0x2587
|
||||
44 0x25B7
|
||||
45 0x25B7
|
||||
46 0x20D6
|
||||
47 0x20FA
|
||||
48 0x25B9
|
||||
49 0x20D6
|
||||
50 0x25BC
|
||||
51 0x20E8
|
||||
52 0x25C2
|
||||
53 0x20E9
|
||||
54 0x20E9
|
||||
55 0x20E9
|
||||
56 0x25BC
|
||||
57 0x25BC
|
||||
58 0x2100
|
||||
59 0x20D6
|
||||
60 0x20D6
|
||||
61 0x20D6
|
||||
62 0x20D6
|
||||
63 0x2583
|
||||
64 0x25A3
|
||||
65 0x25A3
|
||||
66 0x25C8
|
||||
67 0x258E
|
||||
68 0x258F
|
||||
69 0x258F
|
||||
70 0x25CC
|
||||
71 0x25C9
|
||||
72 0x25CB
|
||||
73 0x2594
|
||||
74 0x259F
|
||||
75 0x212D
|
||||
76 0x25CD
|
||||
77 0x25A2
|
||||
78 0x25A5
|
||||
79 0x25A5
|
||||
80 0x258C
|
||||
81 0x2130
|
||||
82 0x25A5
|
||||
83 0x25A8
|
||||
84 0x25A8
|
||||
85 0x25AB
|
||||
86 0x25AD
|
||||
87 0x25AC
|
||||
88 0x2108
|
||||
89 0x25C0
|
||||
90 0x25C1
|
||||
91 0x25C2
|
||||
92 0x25C2
|
||||
93 0x25C2
|
||||
94 0x20E8
|
||||
96 0x20E8
|
||||
97 0x2596
|
||||
98 0x2596
|
||||
99 0x25D1
|
||||
100 0x25D2
|
||||
101 0x2581
|
||||
102 0x2584
|
||||
103 0x20D6
|
||||
104 0x20D6
|
||||
105 0x20D6
|
||||
106 0x20D6
|
||||
107 0x20D7
|
||||
108 0x20D7
|
||||
109 0x20D7
|
||||
110 0x20D7
|
||||
111 0x20D7
|
||||
112 0x20D7
|
||||
113 0x20D7
|
||||
114 0x259B
|
||||
115 0x259B
|
||||
116 0x259C
|
||||
117 0x259D
|
||||
118 0x259E
|
||||
119 0x259E
|
||||
120 0x259E
|
||||
121 0x259E
|
||||
122 0x25CE
|
||||
123 0x2589
|
||||
124 0x258A
|
||||
125 0x258B
|
||||
126 0x258B
|
||||
127 0x2597
|
||||
128 0x25B6
|
||||
129 0x25C8
|
||||
130 0x258D
|
||||
131 0x2590
|
||||
132 0x25A0
|
||||
133 0x2131
|
||||
134 0x25A1
|
||||
135 0x25A8
|
||||
136 0x25A9
|
||||
137 0x25AA
|
||||
138 0x25AF
|
||||
139 0x25AF
|
||||
140 0x25B1
|
||||
141 0x2106
|
||||
142 0x25B7
|
||||
143 0x25B7
|
||||
144 0x25BA
|
||||
145 0x20FB
|
||||
146 0x25BB
|
||||
147 0x25BD
|
||||
148 0x25BE
|
||||
150 0x20FB
|
||||
151 0x20F1
|
||||
152 0x25CA
|
||||
153 0x2591
|
||||
154 0x25A7
|
||||
155 0x20EC
|
||||
157 0x25C3
|
||||
158 0x25D6
|
||||
159 0x25D8
|
||||
160 0x25D8
|
||||
161 0x25DA
|
||||
162 0x25DB
|
||||
163 0x25DC
|
||||
164 0x20ED
|
||||
165 0x2100
|
||||
166 0x20D7
|
||||
167 0x2118
|
||||
168 0x259F
|
||||
170 0x20F6
|
||||
171 0x25B2
|
||||
172 0x20D6
|
||||
173 0x25C3
|
||||
175 0x2589
|
||||
176 0x25B6
|
||||
177 0x259C
|
||||
178 0x259C
|
||||
179 0x259C
|
||||
180 0x20D6
|
||||
181 0x25AE
|
||||
182 0x25AE
|
||||
183 0x2106
|
||||
184 0x2107
|
||||
185 0x2106
|
||||
186 0x2107
|
||||
187 0x2615
|
||||
188 0x2615
|
||||
189 0x25B0
|
||||
190 0x21F1
|
||||
191 0x25A0
|
||||
192 0x25CE
|
||||
193 0x2615
|
||||
194 0x2619
|
||||
195 0x260F
|
||||
197 0x20D6
|
||||
198 0x20D6
|
||||
200 0x2598
|
||||
201 0x211B
|
||||
202 0x2131
|
||||
203 0x2101
|
||||
204 0x259A
|
||||
205 0x2125
|
||||
206 0x2131
|
||||
207 0x20EB
|
||||
208 0x20D1
|
||||
209 0x2580
|
||||
210 0x25B2
|
||||
211 0x2118
|
||||
212 0x211E
|
||||
213 0x20E1
|
||||
214 0x25B5
|
||||
215 0x20D0
|
||||
216 0x2103
|
||||
217 0x2588
|
||||
218 0x25B3
|
||||
219 0x25B4
|
||||
220 0x20F6
|
||||
221 0x20FF
|
||||
223 0x20EB
|
||||
225 0x25D3
|
||||
226 0x2599
|
||||
228 0x259E
|
||||
231 0x20EF
|
||||
232 0x20EF
|
||||
233 0x20F0
|
||||
234 0x20D4
|
||||
237 0x20D4
|
||||
238 0x2123
|
||||
290 0x2101
|
||||
291 0x2126
|
||||
292 0x2127
|
||||
300 0x2620
|
||||
301 0x2621
|
||||
302 0x2622
|
||||
303 0x2623
|
||||
304 0x2624
|
||||
305 0x2625
|
||||
306 0x2626
|
||||
307 0x2627
|
||||
308 0x2628
|
||||
309 0x2629
|
||||
310 0x262A
|
||||
311 0x262B
|
||||
312 0x262C
|
||||
313 0x262D
|
||||
314 0x262E
|
||||
315 0x262F
|
||||
316 0x2630
|
||||
317 0x2631
|
||||
318 0x2632
|
||||
319 0x2633
|
||||
400 0x2106
|
||||
401 0x2107
|
||||
402 0x2106
|
||||
403 0x2107
|
||||
744 0x2106
|
||||
745 0x2107
|
||||
746 0x260E
|
||||
747 0x262A
|
||||
748 0x25C7
|
||||
749 0x25A4
|
||||
750 0x2106
|
||||
751 0x2107
|
||||
752 0x2610
|
||||
753 0x258D
|
||||
754 0x258D
|
||||
755 0x258D
|
||||
756 0x260C
|
||||
757 0x260B
|
||||
758 0x258D
|
||||
763 0x260B
|
||||
764 0x261F
|
||||
765 0x261E
|
||||
766 0x25FC
|
||||
767 0x25F9
|
||||
768 0x2612
|
||||
769 0x25F9
|
||||
770 0x261C
|
||||
771 0x261D
|
||||
772 0x25F8
|
||||
773 0x25FA
|
||||
774 0x25FB
|
||||
775 0x2613
|
||||
776 0x2611
|
||||
777 0x260D
|
||||
778 0x261A
|
||||
779 0x2607
|
||||
780 0x2608
|
||||
781 0x2604
|
||||
782 0x2603
|
||||
783 0x2602
|
||||
784 0x2605
|
||||
785 0x260E
|
||||
786 0x260A
|
||||
787 0x260F
|
||||
788 0x2618
|
||||
789 0x2614
|
||||
790 0x2616
|
||||
791 0x260F
|
||||
792 0x2609
|
||||
793 0x2617
|
||||
794 0x2619
|
||||
795 0x2611
|
||||
796 0x2611
|
||||
797 0x20D6
|
||||
798 0x20D6
|
||||
799 0x2619
|
||||
804 0x2602
|
||||
805 0x2604
|
||||
806 0x2603
|
||||
807 0x2602
|
||||
808 0x2602
|
||||
820 0x259A
|
||||
825 0x25B2
|
||||
826 0x25B3
|
||||
827 0x25B4
|
||||
828 0x20F6
|
||||
831 0x211A
|
||||
832 0x211A
|
||||
833 0x211A
|
||||
834 0x2597
|
||||
835 0x2125
|
||||
837 0x25C0
|
||||
838 0x25C1
|
||||
839 0x2615
|
||||
840 0x2615
|
||||
841 0x2615
|
||||
842 0x2615
|
||||
843 0x2123
|
||||
846 0x2599
|
||||
848 0x259E
|
||||
970 0x2106
|
||||
990 0x2106
|
||||
991 0x2106
|
||||
994 0x2106
|
||||
998 0x25A0
|
||||
|
||||
#SE Mobiles
|
||||
|
||||
246 0x2763
|
||||
254 0x2764
|
||||
242 0x2765
|
||||
199 0x2766
|
||||
247 0x2767
|
||||
248 0x2768
|
||||
196 0x2769
|
||||
243 0x276A
|
||||
240 0x276B
|
||||
252 0x276C
|
||||
241 0x276D
|
||||
251 0x276E
|
||||
244 0x276F
|
||||
250 0x2770
|
||||
249 0x2771
|
||||
255 0x2772
|
||||
253 0x2773
|
||||
245 0x281B
|
||||
169 0x281C
|
||||
|
||||
#ML Mobiles
|
||||
276 0x2D95
|
||||
277 0x2D96
|
||||
|
||||
#SA Mobiles
|
||||
666 16941
|
||||
667 16942
|
||||
714 0x4288
|
||||
715 0x4289
|
||||
716 0x428A
|
||||
717 0x428B
|
||||
718 0x428C
|
||||
719 0x428D
|
||||
720 0x428E
|
||||
721 0x428F
|
||||
722 0x4290
|
||||
723 0x4291
|
||||
724 0x4292
|
||||
334 0x4293
|
||||
725 0x4295
|
||||
726 0x4296
|
||||
727 0x4297
|
||||
728 0x4298
|
||||
729 0x4299
|
||||
830 0x429A
|
||||
730 0x429B
|
||||
829 0x429C
|
||||
732 0x429D
|
||||
740 0x429E
|
||||
733 0x429F
|
||||
741 0x42A0
|
||||
734 0x42A1
|
||||
735 0x42A2
|
||||
736 0x42A3
|
||||
737 0x42A4
|
||||
705 0x42A5
|
||||
826 0x42A6
|
||||
738 0x42A7
|
||||
742 0x42A8
|
||||
739 0x42A9
|
||||
|
||||
#TOL Mobiles
|
||||
|
||||
95 0x4988
|
||||
156 0x4988
|
||||
|
||||
1068 0x276E
|
||||
1069 0x9ED5
|
||||
1254 0x9844
|
||||
1255 0x9844
|
||||
|
||||
1285 0x9845
|
||||
1286 0x9846
|
||||
1287 0x9847
|
||||
1288 0x9848
|
||||
1289 0x9849
|
||||
1290 0x984A
|
||||
1291 0x984B
|
||||
1292 0x984C
|
||||
1293 0x984D
|
||||
1294 0x984E
|
||||
1308 0x20F5
|
||||
1309 0x9844
|
||||
1400 0x9DED
|
||||
1402 0x9D81
|
||||
1403 0x9D81
|
||||
1404 0x9D81
|
||||
1405 0x9DE4
|
||||
1406 0x9DB3
|
||||
1407 0x9E35
|
||||
1408 0x3ECD
|
||||
1410 0x9ED5
|
||||
1415 0x9DED
|
||||
1416 0x9844
|
||||
1417 0x20D6
|
||||
1418 0x20D6
|
||||
1419 0x20D6
|
||||
1420 0x20D6
|
||||
1422 0x20D6
|
||||
1423 0x211C
|
||||
1424 0x9DB6
|
||||
1425 0x2108
|
||||
1426 0x9F08
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 379 B |
Binary file not shown.
|
After Width: | Height: | Size: 372 B |
Binary file not shown.
|
After Width: | Height: | Size: 749 B |
Binary file not shown.
|
After Width: | Height: | Size: 528 B |
Binary file not shown.
@@ -0,0 +1,55 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.CustomWindowTitleControl"
|
||||
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:misc="clr-namespace:ClassicAssist.UI.Misc"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="50" d:DesignWidth="800"
|
||||
DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}"
|
||||
Background="{DynamicResource ThemeWindowBackgroundBrush}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Resources/Icons.xaml" />
|
||||
<ResourceDictionary Source="../../Resources/ResourceDictionary.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowMouseDownBehaviour />
|
||||
</i:Interaction.Behaviors>
|
||||
<Grid Margin="5">
|
||||
<ContentPresenter Content="{Binding AdditionalContent}" DockPanel.Dock="Left" />
|
||||
<Label DockPanel.Dock="Left" Content="{Binding CustomTitle}" FontSize="16" Margin="5,0,5,0"
|
||||
Foreground="{DynamicResource ThemeForegroundBrush}" />
|
||||
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button Background="{DynamicResource ThemeWindowBackgroundBrush}" BorderBrush="Transparent" Height="24"
|
||||
Width="24" DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding CanMinimize}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowCommandBehaviour Command="Minimize" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image Source="{StaticResource minusIcon}" />
|
||||
</Button>
|
||||
<Button Background="{DynamicResource ThemeWindowBackgroundBrush}" BorderBrush="Transparent" Height="24"
|
||||
Width="24" DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding CanMaximize}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowCommandBehaviour Command="Maximize" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image Source="{StaticResource squareIcon}" />
|
||||
</Button>
|
||||
<Button Background="{DynamicResource ThemeWindowBackgroundBrush}" BorderBrush="Transparent" Height="24"
|
||||
Width="24" DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding CanClose}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowCommandBehaviour Command="Close" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image Source="{StaticResource closeIcon}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CustomWindowTitleControl.xaml
|
||||
/// </summary>
|
||||
public partial class CustomWindowTitleControl
|
||||
{
|
||||
public static readonly DependencyProperty AdditionalContentProperty =
|
||||
DependencyProperty.Register( "AdditionalContent", typeof( object ), typeof( CustomWindowTitleControl ),
|
||||
new PropertyMetadata( null ) );
|
||||
|
||||
public static readonly DependencyProperty CustomTitleProperty = DependencyProperty.Register( "CustomTitle",
|
||||
typeof( string ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( default( string ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty CanCloseProperty = DependencyProperty.Register( "CanClose",
|
||||
typeof( bool ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty CanMinimizeProperty = DependencyProperty.Register( "CanMinimize",
|
||||
typeof( bool ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty CanMaxmizeProperty = DependencyProperty.Register( "CanMaximize",
|
||||
typeof( bool ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public CustomWindowTitleControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public object AdditionalContent
|
||||
{
|
||||
get => GetValue( AdditionalContentProperty );
|
||||
set => SetValue( AdditionalContentProperty, value );
|
||||
}
|
||||
|
||||
public bool CanClose
|
||||
{
|
||||
get => (bool) GetValue( CanCloseProperty );
|
||||
set => SetValue( CanCloseProperty, value );
|
||||
}
|
||||
|
||||
public bool CanMaximize
|
||||
{
|
||||
get => (bool) GetValue( CanMaxmizeProperty );
|
||||
set => SetValue( CanMaxmizeProperty, value );
|
||||
}
|
||||
|
||||
public bool CanMinimize
|
||||
{
|
||||
get => (bool) GetValue( CanMinimizeProperty );
|
||||
set => SetValue( CanMinimizeProperty, value );
|
||||
}
|
||||
|
||||
public string CustomTitle
|
||||
{
|
||||
get => (string) GetValue( CustomTitleProperty );
|
||||
set => SetValue( CustomTitleProperty, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<UserControl x:Name="root" x:Class="ClassicAssist.UI.Controls.EditTextBlock"
|
||||
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:valueConverters="clr-namespace:ClassicAssist.UI.Misc.ValueConverters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<DrawingImage x:Key="PencilIcon">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup ClipGeometry="M0,0 V512 H512 V0 H0 Z">
|
||||
<DrawingGroup Opacity="1">
|
||||
<DrawingGroup Opacity="1">
|
||||
<GeometryDrawing
|
||||
Geometry="F1 M512,512z M0,0z M434.214,0L0,434.213 0,512 77.787,512 512,77.786 434.214,0z M65.359,481.998L30.002,481.998 30.002,446.641 50.125,426.518 85.482,461.875 65.359,481.998z M399.206,77.437L434.214,42.429 469.571,77.786 434.563,112.794 399.206,77.437z"
|
||||
Brush="{Binding Foreground, ElementName=root}" />
|
||||
</DrawingGroup>
|
||||
</DrawingGroup>
|
||||
</DrawingGroup>
|
||||
</DrawingImage.Drawing>
|
||||
</DrawingImage>
|
||||
<valueConverters:PriorityMultiValueConverter x:Key="PriorityMultiValueConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<TextBlock x:Name="textBlock" VerticalAlignment="Center"
|
||||
MouseDown="TextBlock_OnMouseDown" Background="Transparent"
|
||||
Foreground="{Binding Foreground, ElementName=root}">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource PriorityMultiValueConverter}">
|
||||
<Binding Path="Label" ElementName="root" />
|
||||
<Binding Path="Text" ElementName="root" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
<TextBox x:Name="textBox"
|
||||
Text="{Binding ElementName=root, Path=Text, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
|
||||
VerticalAlignment="Center" Visibility="Collapsed" KeyDown="TextBox_OnKeyDown"
|
||||
LostFocus="TextBox_LostFocus" />
|
||||
<Button Width="12" Height="12" BorderThickness="0" Background="Transparent" Margin="0" Padding="0"
|
||||
HorizontalAlignment="Right"
|
||||
Visibility="{Binding ShowIcon, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=root}"
|
||||
Click="Button_OnClick" x:Name="pencilButton">
|
||||
<Image Source="{StaticResource PencilIcon}" Width="16" HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EditTextBlock.xaml
|
||||
/// </summary>
|
||||
public partial class EditTextBlock
|
||||
{
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof( string ),
|
||||
typeof( EditTextBlock ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register( "Label",
|
||||
typeof( string ), typeof( EditTextBlock ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None ) );
|
||||
|
||||
public static readonly DependencyProperty ShowIconProperty = DependencyProperty.Register( "ShowIcon",
|
||||
typeof( bool ), typeof( EditTextBlock ), new UIPropertyMetadata() );
|
||||
|
||||
public EditTextBlock()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string Label
|
||||
{
|
||||
get => (string) GetValue( LabelProperty );
|
||||
set => SetValue( LabelProperty, value );
|
||||
}
|
||||
|
||||
public bool ShowIcon
|
||||
{
|
||||
get => (bool) GetValue( ShowIconProperty );
|
||||
set => SetValue( ShowIconProperty, value );
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string) GetValue( TextProperty );
|
||||
set => SetValue( TextProperty, value );
|
||||
}
|
||||
|
||||
private void TextBlock_OnMouseDown( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
if ( e.ClickCount <= 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShowTextBox();
|
||||
}
|
||||
|
||||
private void ShowTextBox()
|
||||
{
|
||||
textBlock.Visibility = Visibility.Collapsed;
|
||||
pencilButton.Visibility = Visibility.Collapsed;
|
||||
textBox.Visibility = Visibility.Visible;
|
||||
textBox.CaretIndex = textBox.Text.Length;
|
||||
textBox.SelectAll();
|
||||
|
||||
Dispatcher?.BeginInvoke( (Action) ( () => Keyboard.Focus( textBox ) ), DispatcherPriority.Render );
|
||||
}
|
||||
|
||||
private void TextBox_OnKeyDown( object sender, KeyEventArgs e )
|
||||
{
|
||||
if ( e.Key == Key.Return )
|
||||
{
|
||||
TextBox_LostFocus( sender, null );
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_LostFocus( object sender, RoutedEventArgs e )
|
||||
{
|
||||
textBlock.Visibility = Visibility.Visible;
|
||||
pencilButton.Visibility = ShowIcon ? Visibility.Visible : Visibility.Hidden;
|
||||
( (TextBox) sender ).Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void Button_OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
ShowTextBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.HexDumpControl"
|
||||
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:ClassicAssist.UI.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="600">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Consolas" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<StackPanel
|
||||
DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:HexDumpControl}}}">
|
||||
<Label Content="{Binding Packet.Title}" />
|
||||
<Grid>
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Copy byte[] declaration" Click="Copy_OnClick" />
|
||||
<MenuItem Header="Replay" Click="Replay_OnClick" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding BinaryData}" Style="{StaticResource TextBlockStyle}" Grid.Column="0"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled" Margin="10,10,0,0" Width="310" />
|
||||
<TextBlock Text="{Binding TextData}" Style="{StaticResource TextBlockStyle}" Grid.Column="1"
|
||||
Margin="10,10,0,0" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
|
||||
</Grid>
|
||||
<Label Content="{Binding Status}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.UI.Misc;
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for HexDumpControl.xaml
|
||||
/// </summary>
|
||||
public partial class HexDumpControl
|
||||
{
|
||||
public static readonly DependencyProperty PacketProperty = DependencyProperty.Register( "Packet",
|
||||
typeof( PacketEntry ), typeof( HexDumpControl ), new UIPropertyMetadata() );
|
||||
|
||||
public HexDumpControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string BinaryData
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( Packet?.Data == null )
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder binaryBuilder = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < Packet.Length; i++ )
|
||||
{
|
||||
byte b1 = (byte) ( Packet.Data[i] >> 4 );
|
||||
byte b2 = (byte) ( Packet.Data[i] & 0xF );
|
||||
binaryBuilder.Append( (char) ( b1 > 9 ? b1 + 0x37 : b1 + 0x30 ) );
|
||||
binaryBuilder.Append( (char) ( b2 > 9 ? b2 + 0x37 : b2 + 0x30 ) );
|
||||
binaryBuilder.Append( ' ' );
|
||||
|
||||
if ( ( i + 1 ) % 16 != 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
binaryBuilder.Remove( binaryBuilder.Length - 1, 1 );
|
||||
binaryBuilder.AppendLine();
|
||||
}
|
||||
|
||||
return binaryBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public PacketEntry Packet
|
||||
{
|
||||
get => (PacketEntry) GetValue( PacketProperty );
|
||||
set => SetValue( PacketProperty, value );
|
||||
}
|
||||
|
||||
public string Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( Packet?.Data == null )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return "Length: " + Packet.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public string TextData
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( Packet?.Data == null )
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < Packet.Length; i++ )
|
||||
{
|
||||
byte b1 = Packet.Data[i];
|
||||
|
||||
if ( b1 < 0x20 || b1 == 0xB7 || b1 == 0xFF )
|
||||
{
|
||||
b1 = (byte) '.';
|
||||
}
|
||||
|
||||
textBuilder.Append( (char) b1 );
|
||||
|
||||
if ( ( i + 1 ) % 16 == 0 )
|
||||
{
|
||||
textBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
return textBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void Copy_OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
try
|
||||
{
|
||||
string prepend = "byte[] packet = new byte[] { ";
|
||||
|
||||
for ( int i = 0; i < Packet.Data.Length; i++ )
|
||||
{
|
||||
prepend += $"0x{Packet.Data[i]:X2}";
|
||||
|
||||
if ( i + 1 < Packet.Data.Length )
|
||||
{
|
||||
prepend += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
prepend += " };";
|
||||
|
||||
Clipboard.SetData( DataFormats.Text, prepend );
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void Replay_OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
if ( Packet == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( Packet.Direction )
|
||||
{
|
||||
case PacketDirection.Incoming:
|
||||
Engine.SendPacketToClient( Packet.Data, Packet.Data.Length );
|
||||
break;
|
||||
case PacketDirection.Outgoing:
|
||||
Engine.SendPacketToServer( Packet.Data, Packet.Data.Length );
|
||||
break;
|
||||
case PacketDirection.Any:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.HueEntryControl"
|
||||
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:ClassicAssist.UI.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="20" d:DesignWidth="640">
|
||||
<d:DesignerProperties.DesignStyle>
|
||||
<Style TargetType="UserControl">
|
||||
<Setter Property="Background" Value="White" />
|
||||
</Style>
|
||||
</d:DesignerProperties.DesignStyle>
|
||||
<StackPanel Orientation="Horizontal" x:Name="StackPanel">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="Rectangle">
|
||||
<Setter Property="Fill" Value="Black" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using ClassicAssist.UO.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for HueEntryControl.xaml
|
||||
/// </summary>
|
||||
public partial class HueEntryControl : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty HueEntryProperty = DependencyProperty.Register( "HueEntry",
|
||||
typeof( HueEntry ), typeof( HueEntryControl ),
|
||||
new FrameworkPropertyMetadata( default( HueEntry ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
public HueEntryControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public HueEntry HueEntry
|
||||
{
|
||||
get => (HueEntry) GetValue( HueEntryProperty );
|
||||
set => SetValue( HueEntryProperty, value );
|
||||
}
|
||||
|
||||
private static void PropertyChangedCallback( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
if ( d is HueEntryControl control )
|
||||
{
|
||||
control.SetHues( (HueEntry) e.NewValue );
|
||||
}
|
||||
}
|
||||
|
||||
private void SetHues( HueEntry entry )
|
||||
{
|
||||
for ( int i = 0; i < 32; i++ )
|
||||
{
|
||||
SolidColorBrush brush = new SolidColorBrush( Convert555ToARGB( entry.Colors[i] ) );
|
||||
|
||||
StackPanel.Children.Add( new Rectangle { Fill = brush, Width = 10 } );
|
||||
}
|
||||
}
|
||||
|
||||
protected static Color Convert555ToARGB( short Col )
|
||||
{
|
||||
int r = ( (short) ( Col >> 10 ) & 31 ) * 8;
|
||||
int g = ( (short) ( Col >> 5 ) & 31 ) * 8;
|
||||
int b = ( Col & 31 ) * 8;
|
||||
return Color.FromArgb( 255, (byte) r, (byte) g, (byte) b );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/*
|
||||
* https://stackoverflow.com/questions/8004981/how-to-make-wpf-wrappanel-child-items-to-stretch
|
||||
*/
|
||||
public class StretchyWrapPanel : Panel
|
||||
{
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register( nameof( ItemWidth ),
|
||||
typeof( double ), typeof( StretchyWrapPanel ),
|
||||
new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure ) );
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty =
|
||||
DependencyProperty.Register( nameof( ItemHeight ), typeof( double ), typeof( StretchyWrapPanel ),
|
||||
new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure ) );
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty =
|
||||
StackPanel.OrientationProperty.AddOwner( typeof( StretchyWrapPanel ),
|
||||
new FrameworkPropertyMetadata( Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure,
|
||||
OnOrientationChanged ) );
|
||||
|
||||
public static readonly DependencyProperty StretchProportionallyProperty =
|
||||
DependencyProperty.Register( nameof( StretchProportionally ), typeof( bool ), typeof( StretchyWrapPanel ),
|
||||
new PropertyMetadata( true, OnStretchProportionallyChanged ) );
|
||||
|
||||
private Orientation _orientation = Orientation.Horizontal;
|
||||
|
||||
private bool _stretchProportionally = true;
|
||||
|
||||
[TypeConverter( typeof( LengthConverter ) )]
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue( ItemHeightProperty );
|
||||
set => SetValue( ItemHeightProperty, value );
|
||||
}
|
||||
|
||||
[TypeConverter( typeof( LengthConverter ) )]
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue( ItemWidthProperty );
|
||||
set => SetValue( ItemWidthProperty, value );
|
||||
}
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => _orientation;
|
||||
set => SetValue( OrientationProperty, value );
|
||||
}
|
||||
|
||||
public bool StretchProportionally
|
||||
{
|
||||
get => _stretchProportionally;
|
||||
set => SetValue( StretchProportionallyProperty, value );
|
||||
}
|
||||
|
||||
private static void OnOrientationChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
( (StretchyWrapPanel) d )._orientation = (Orientation) e.NewValue;
|
||||
}
|
||||
|
||||
private static void OnStretchProportionallyChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
( (StretchyWrapPanel) o )._stretchProportionally = (bool) e.NewValue;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride( Size constraint )
|
||||
{
|
||||
UVSize curLineSize = new UVSize( Orientation );
|
||||
UVSize panelSize = new UVSize( Orientation );
|
||||
UVSize uvConstraint = new UVSize( Orientation, constraint.Width, constraint.Height );
|
||||
double itemWidth = ItemWidth;
|
||||
double itemHeight = ItemHeight;
|
||||
bool itemWidthSet = !double.IsNaN( itemWidth );
|
||||
bool itemHeightSet = !double.IsNaN( itemHeight );
|
||||
|
||||
Size childConstraint = new Size( itemWidthSet ? itemWidth : constraint.Width,
|
||||
itemHeightSet ? itemHeight : constraint.Height );
|
||||
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
for ( int i = 0, count = children.Count; i < count; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flow passes its own constrint to children
|
||||
child.Measure( childConstraint );
|
||||
|
||||
// This is the size of the child in UV space
|
||||
UVSize sz = new UVSize( Orientation, itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height );
|
||||
|
||||
if ( curLineSize.U + sz.U > uvConstraint.U )
|
||||
{
|
||||
// Need to switch to another line
|
||||
panelSize.U = Math.Max( curLineSize.U, panelSize.U );
|
||||
panelSize.V += curLineSize.V;
|
||||
curLineSize = sz;
|
||||
|
||||
if ( sz.U > uvConstraint.U )
|
||||
{
|
||||
// The element is wider then the constrint - give it a separate line
|
||||
panelSize.U = Math.Max( sz.U, panelSize.U );
|
||||
panelSize.V += sz.V;
|
||||
curLineSize = new UVSize( Orientation );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continue to accumulate a line
|
||||
curLineSize.U += sz.U;
|
||||
curLineSize.V = Math.Max( sz.V, curLineSize.V );
|
||||
}
|
||||
}
|
||||
|
||||
// The last line size, if any should be added
|
||||
panelSize.U = Math.Max( curLineSize.U, panelSize.U );
|
||||
panelSize.V += curLineSize.V;
|
||||
|
||||
// Go from UV space to W/H space
|
||||
return new Size( panelSize.Width, panelSize.Height );
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride( Size finalSize )
|
||||
{
|
||||
int firstInLine = 0;
|
||||
double itemWidth = ItemWidth;
|
||||
double itemHeight = ItemHeight;
|
||||
double accumulatedV = 0;
|
||||
double itemU = Orientation == Orientation.Horizontal ? itemWidth : itemHeight;
|
||||
UVSize curLineSize = new UVSize( Orientation );
|
||||
UVSize uvFinalSize = new UVSize( Orientation, finalSize.Width, finalSize.Height );
|
||||
bool itemWidthSet = !double.IsNaN( itemWidth );
|
||||
bool itemHeightSet = !double.IsNaN( itemHeight );
|
||||
bool useItemU = Orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet;
|
||||
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
for ( int i = 0, count = children.Count; i < count; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UVSize sz = new UVSize( Orientation, itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height );
|
||||
|
||||
if ( curLineSize.U + sz.U > uvFinalSize.U )
|
||||
{
|
||||
// Need to switch to another line
|
||||
if ( !useItemU && StretchProportionally )
|
||||
{
|
||||
ArrangeLineProportionally( accumulatedV, curLineSize.V, firstInLine, i, uvFinalSize.Width );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine( accumulatedV, curLineSize.V, firstInLine, i, true,
|
||||
useItemU ? itemU : uvFinalSize.Width / Math.Max( 1, i - firstInLine - 1 ) );
|
||||
}
|
||||
|
||||
accumulatedV += curLineSize.V;
|
||||
curLineSize = sz;
|
||||
|
||||
if ( sz.U > uvFinalSize.U )
|
||||
{
|
||||
// The element is wider then the constraint - give it a separate line
|
||||
// Switch to next line which only contain one element
|
||||
if ( !useItemU && StretchProportionally )
|
||||
{
|
||||
ArrangeLineProportionally( accumulatedV, sz.V, i, ++i, uvFinalSize.Width );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine( accumulatedV, sz.V, i, ++i, true, useItemU ? itemU : uvFinalSize.Width );
|
||||
}
|
||||
|
||||
accumulatedV += sz.V;
|
||||
curLineSize = new UVSize( Orientation );
|
||||
}
|
||||
|
||||
firstInLine = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continue to accumulate a line
|
||||
curLineSize.U += sz.U;
|
||||
curLineSize.V = Math.Max( sz.V, curLineSize.V );
|
||||
}
|
||||
}
|
||||
|
||||
// Arrange the last line, if any
|
||||
if ( firstInLine < children.Count )
|
||||
{
|
||||
if ( !useItemU && StretchProportionally )
|
||||
{
|
||||
ArrangeLineProportionally( accumulatedV, curLineSize.V, firstInLine, children.Count,
|
||||
uvFinalSize.Width );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine( accumulatedV, curLineSize.V, firstInLine, children.Count, true,
|
||||
useItemU ? itemU : uvFinalSize.Width / Math.Max( 1, children.Count - firstInLine - 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private void ArrangeLineProportionally( double v, double lineV, int start, int end, double limitU )
|
||||
{
|
||||
double u = 0d;
|
||||
bool horizontal = Orientation == Orientation.Horizontal;
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
double total = 0d;
|
||||
|
||||
for ( int i = start; i < end; i++ )
|
||||
{
|
||||
total += horizontal ? children[i].DesiredSize.Width : children[i].DesiredSize.Height;
|
||||
}
|
||||
|
||||
double uMultipler = limitU / total;
|
||||
|
||||
for ( int i = start; i < end; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child != null )
|
||||
{
|
||||
UVSize childSize = new UVSize( Orientation, child.DesiredSize.Width, child.DesiredSize.Height );
|
||||
double layoutSlotU = childSize.U * uMultipler;
|
||||
child.Arrange( new Rect( horizontal ? u : v, horizontal ? v : u, horizontal ? layoutSlotU : lineV,
|
||||
horizontal ? lineV : layoutSlotU ) );
|
||||
u += layoutSlotU;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ArrangeLine( double v, double lineV, int start, int end, bool useItemU, double itemU )
|
||||
{
|
||||
double u = 0d;
|
||||
bool horizontal = Orientation == Orientation.Horizontal;
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
for ( int i = start; i < end; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child != null )
|
||||
{
|
||||
UVSize childSize = new UVSize( Orientation, child.DesiredSize.Width, child.DesiredSize.Height );
|
||||
double layoutSlotU = useItemU ? itemU : childSize.U;
|
||||
child.Arrange( new Rect( horizontal ? u : v, horizontal ? v : u, horizontal ? layoutSlotU : lineV,
|
||||
horizontal ? lineV : layoutSlotU ) );
|
||||
u += layoutSlotU;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct UVSize
|
||||
{
|
||||
internal UVSize( Orientation orientation, double width, double height )
|
||||
{
|
||||
U = V = 0d;
|
||||
_orientation = orientation;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
internal UVSize( Orientation orientation )
|
||||
{
|
||||
U = V = 0d;
|
||||
_orientation = orientation;
|
||||
}
|
||||
|
||||
internal double U;
|
||||
internal double V;
|
||||
private readonly Orientation _orientation;
|
||||
|
||||
internal double Width
|
||||
{
|
||||
get => _orientation == Orientation.Horizontal ? U : V;
|
||||
private set
|
||||
{
|
||||
if ( _orientation == Orientation.Horizontal )
|
||||
{
|
||||
U = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
V = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal double Height
|
||||
{
|
||||
get => _orientation == Orientation.Horizontal ? V : U;
|
||||
private set
|
||||
{
|
||||
if ( _orientation == Orientation.Horizontal )
|
||||
{
|
||||
V = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
U = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.TextBoxKey"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300" x:Name="UserControl">
|
||||
<Grid>
|
||||
<TextBox Text="{Binding Shortcut, ElementName=UserControl, Mode=OneWay}"
|
||||
PreviewKeyDown="TextBox_PreviewKeyDown" IsReadOnly="True" IsReadOnlyCaretVisible="False"
|
||||
IsUndoEnabled="False" PreviewMouseDown="UIElement_OnPreviewMouseDown"
|
||||
MouseWheel="UIElement_OnMouseWheel" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Data.Hotkeys;
|
||||
using Key = ClassicAssist.Misc.Key;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <inheritdoc cref="TextBox" />
|
||||
/// <summary>
|
||||
/// Interaction logic for TestBoxKey.xaml
|
||||
/// </summary>
|
||||
public partial class TextBoxKey
|
||||
{
|
||||
public static readonly DependencyProperty ShortcutProperty = DependencyProperty.Register( nameof( Shortcut ),
|
||||
typeof( ShortcutKeys ), typeof( TextBoxKey ),
|
||||
new FrameworkPropertyMetadata( default( ShortcutKeys ),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
private readonly Key[] _modifiers =
|
||||
{
|
||||
Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt
|
||||
};
|
||||
|
||||
public TextBoxKey()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public Key Key { get; private set; }
|
||||
public Key Modifier { get; set; }
|
||||
|
||||
public object Shortcut
|
||||
{
|
||||
get => GetValue( ShortcutProperty );
|
||||
set => SetValue( ShortcutProperty, value );
|
||||
}
|
||||
|
||||
private Key CheckModifiers()
|
||||
{
|
||||
return _modifiers.FirstOrDefault( e => Keyboard.IsKeyDown( (System.Windows.Input.Key) e ) );
|
||||
}
|
||||
|
||||
private bool IsModifier( Key key )
|
||||
{
|
||||
return _modifiers.Any( k => key == k );
|
||||
}
|
||||
|
||||
private void TextBox_PreviewKeyDown( object sender, KeyEventArgs e )
|
||||
{
|
||||
e.Handled = true;
|
||||
Key key = (Key) e.Key;
|
||||
|
||||
if ( key == Key.System )
|
||||
{
|
||||
key = (Key) e.SystemKey;
|
||||
}
|
||||
|
||||
if ( IsModifier( key ) )
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Modifier = CheckModifiers();
|
||||
|
||||
Key = key;
|
||||
|
||||
Shortcut = new ShortcutKeys { Modifier = Modifier, Key = Key };
|
||||
}
|
||||
|
||||
private void UIElement_OnPreviewMouseDown( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
if ( ( e.ChangedButton == MouseButton.Left ) | ( e.ChangedButton == MouseButton.Right ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
Modifier = CheckModifiers();
|
||||
|
||||
Shortcut = new ShortcutKeys { Mouse = (MouseOptions) e.ChangedButton };
|
||||
}
|
||||
|
||||
private void UIElement_OnMouseWheel( object sender, MouseWheelEventArgs e )
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
Modifier = CheckModifiers();
|
||||
|
||||
Shortcut = e.Delta < 0
|
||||
? new ShortcutKeys { Mouse = MouseOptions.MouseWheelDown, Modifier = Modifier }
|
||||
: new ShortcutKeys { Mouse = MouseOptions.MouseWheelUp, Modifier = Modifier };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
internal class ListBoxBehavior
|
||||
{
|
||||
private static readonly Dictionary<ListBox, Capture> Associations = new Dictionary<ListBox, Capture>();
|
||||
|
||||
public static readonly DependencyProperty ScrollOnNewItemProperty =
|
||||
DependencyProperty.RegisterAttached( "ScrollOnNewItem", typeof( bool ), typeof( ListBoxBehavior ),
|
||||
new UIPropertyMetadata( false, OnScrollOnNewItemChanged ) );
|
||||
|
||||
public static bool GetScrollOnNewItem( DependencyObject obj )
|
||||
{
|
||||
return (bool) obj.GetValue( ScrollOnNewItemProperty );
|
||||
}
|
||||
|
||||
public static void SetScrollOnNewItem( DependencyObject obj, bool value )
|
||||
{
|
||||
obj.SetValue( ScrollOnNewItemProperty, value );
|
||||
}
|
||||
|
||||
public static void OnScrollOnNewItemChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
ListBox listBox = d as ListBox;
|
||||
|
||||
if ( listBox == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool oldValue = (bool) e.OldValue, newValue = (bool) e.NewValue;
|
||||
|
||||
if ( newValue == oldValue )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( newValue )
|
||||
{
|
||||
listBox.Loaded += ListBox_Loaded;
|
||||
listBox.Unloaded += ListBox_Unloaded;
|
||||
PropertyDescriptor itemsSourcePropertyDescriptor =
|
||||
TypeDescriptor.GetProperties( listBox )["ItemsSource"];
|
||||
itemsSourcePropertyDescriptor.AddValueChanged( listBox, ListBox_ItemsSourceChanged );
|
||||
}
|
||||
else
|
||||
{
|
||||
listBox.Loaded -= ListBox_Loaded;
|
||||
listBox.Unloaded -= ListBox_Unloaded;
|
||||
|
||||
if ( Associations.ContainsKey( listBox ) )
|
||||
{
|
||||
Associations[listBox].Dispose();
|
||||
}
|
||||
|
||||
PropertyDescriptor itemsSourcePropertyDescriptor =
|
||||
TypeDescriptor.GetProperties( listBox )["ItemsSource"];
|
||||
itemsSourcePropertyDescriptor.RemoveValueChanged( listBox, ListBox_ItemsSourceChanged );
|
||||
}
|
||||
}
|
||||
|
||||
private static void ListBox_ItemsSourceChanged( object sender, EventArgs e )
|
||||
{
|
||||
ListBox listBox = (ListBox) sender;
|
||||
|
||||
if ( Associations.ContainsKey( listBox ) )
|
||||
{
|
||||
Associations[listBox].Dispose();
|
||||
}
|
||||
|
||||
Associations[listBox] = new Capture( listBox );
|
||||
}
|
||||
|
||||
private static void ListBox_Unloaded( object sender, RoutedEventArgs e )
|
||||
{
|
||||
ListBox listBox = (ListBox) sender;
|
||||
|
||||
if ( Associations.ContainsKey( listBox ) )
|
||||
{
|
||||
Associations[listBox].Dispose();
|
||||
}
|
||||
|
||||
listBox.Unloaded -= ListBox_Unloaded;
|
||||
}
|
||||
|
||||
private static void ListBox_Loaded( object sender, RoutedEventArgs e )
|
||||
{
|
||||
ListBox listBox = (ListBox) sender;
|
||||
|
||||
listBox.Loaded -= ListBox_Loaded;
|
||||
Associations[listBox] = new Capture( listBox );
|
||||
}
|
||||
|
||||
private class Capture : IDisposable
|
||||
{
|
||||
private readonly INotifyCollectionChanged incc;
|
||||
private readonly ListBox listBox;
|
||||
|
||||
public Capture( ListBox listBox )
|
||||
{
|
||||
this.listBox = listBox;
|
||||
incc = listBox.ItemsSource as INotifyCollectionChanged;
|
||||
|
||||
if ( incc != null )
|
||||
{
|
||||
incc.CollectionChanged += incc_CollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if ( incc != null )
|
||||
{
|
||||
incc.CollectionChanged -= incc_CollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void incc_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
|
||||
{
|
||||
if ( e.Action == NotifyCollectionChangedAction.Add )
|
||||
{
|
||||
listBox.ScrollIntoView( e.NewItems[0] );
|
||||
listBox.SelectedItem = e.NewItems[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AutoScrollBehavior
|
||||
{
|
||||
public static readonly DependencyProperty AutoScrollProperty =
|
||||
DependencyProperty.RegisterAttached( "AutoScroll", typeof( bool ), typeof( AutoScrollBehavior ),
|
||||
new PropertyMetadata( false, AutoScrollPropertyChanged ) );
|
||||
|
||||
public static void AutoScrollPropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs args )
|
||||
{
|
||||
ScrollViewer scrollViewer = obj as ScrollViewer;
|
||||
|
||||
if ( scrollViewer != null && (bool) args.NewValue )
|
||||
{
|
||||
scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
|
||||
scrollViewer.ScrollToEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( scrollViewer != null )
|
||||
{
|
||||
scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScrollViewer_ScrollChanged( object sender, ScrollChangedEventArgs e )
|
||||
{
|
||||
// Only scroll to bottom when the extent changed. Otherwise you can't scroll up
|
||||
if ( e.ExtentHeightChange != 0 )
|
||||
{
|
||||
ScrollViewer scrollViewer = sender as ScrollViewer;
|
||||
scrollViewer?.ScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetAutoScroll( DependencyObject obj )
|
||||
{
|
||||
return (bool) obj.GetValue( AutoScrollProperty );
|
||||
}
|
||||
|
||||
public static void SetAutoScroll( DependencyObject obj, bool value )
|
||||
{
|
||||
obj.SetValue( AutoScrollProperty, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class AutoScrollTextBoxBehaviour : Behavior<TextBox>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.TextChanged += OnTextChanged;
|
||||
}
|
||||
|
||||
private void OnTextChanged( object sender, TextChangedEventArgs e )
|
||||
{
|
||||
AssociatedObject.ScrollToEnd();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
if ( AssociatedObject != null )
|
||||
{
|
||||
AssociatedObject.TextChanged -= OnTextChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interactivity;
|
||||
using ICSharpCode.AvalonEdit;
|
||||
using ICSharpCode.AvalonEdit.Document;
|
||||
using ICSharpCode.AvalonEdit.Editing;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class AvalonBindingBehaviour : Behavior<TextEditor>
|
||||
{
|
||||
public static readonly DependencyProperty DocumentBindingProperty = DependencyProperty.Register(
|
||||
"DocumentBinding", typeof( TextDocument ), typeof( AvalonBindingBehaviour ),
|
||||
new FrameworkPropertyMetadata( default( TextDocument ),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, PropertyChangedCallback ) );
|
||||
|
||||
public static readonly DependencyProperty CaretBindingProperty = DependencyProperty.Register( "CaretBinding",
|
||||
typeof( int ), typeof( AvalonBindingBehaviour ),
|
||||
new FrameworkPropertyMetadata( default( int ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
public int CaretBinding
|
||||
{
|
||||
get => (int) GetValue( CaretBindingProperty );
|
||||
set => SetValue( CaretBindingProperty, value );
|
||||
}
|
||||
|
||||
public TextDocument DocumentBinding
|
||||
{
|
||||
get => (TextDocument) GetValue( DocumentBindingProperty );
|
||||
set => SetValue( DocumentBindingProperty, value );
|
||||
}
|
||||
|
||||
private static void PropertyChangedCallback( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.Loaded += OnLoaded;
|
||||
AssociatedObject.TextArea.Caret.PositionChanged += CaretOnPositionChanged;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
AssociatedObject.Loaded -= OnLoaded;
|
||||
AssociatedObject.TextArea.Caret.PositionChanged -= CaretOnPositionChanged;
|
||||
}
|
||||
|
||||
private void CaretOnPositionChanged( object sender, EventArgs e )
|
||||
{
|
||||
if ( sender is Caret caret )
|
||||
{
|
||||
CaretBinding = caret.Offset;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoaded( object sender, RoutedEventArgs args )
|
||||
{
|
||||
if ( sender is TextEditor textEditor )
|
||||
{
|
||||
DocumentBinding = textEditor.Document;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interactivity;
|
||||
using ICSharpCode.AvalonEdit;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public sealed class AvalonEditBehaviour : Behavior<TextEditor>
|
||||
{
|
||||
public static readonly DependencyProperty TextBindingProperty = DependencyProperty.Register( "TextBinding",
|
||||
typeof( string ), typeof( AvalonEditBehaviour ),
|
||||
new FrameworkPropertyMetadata( default( string ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
public string TextBinding
|
||||
{
|
||||
get => (string) GetValue( TextBindingProperty );
|
||||
set => SetValue( TextBindingProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
if ( AssociatedObject != null )
|
||||
{
|
||||
AssociatedObject.TextChanged += AssociatedObjectOnTextChanged;
|
||||
AssociatedObject.LostFocus += AssociatedObjectOnLostFocus;
|
||||
}
|
||||
}
|
||||
|
||||
private void AssociatedObjectOnLostFocus( object sender, RoutedEventArgs routedEventArgs )
|
||||
{
|
||||
if ( !( sender is TextEditor textEditor ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( textEditor.Document != null )
|
||||
{
|
||||
TextBinding = textEditor.Document.Text;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
if ( AssociatedObject != null )
|
||||
{
|
||||
AssociatedObject.TextChanged -= AssociatedObjectOnTextChanged;
|
||||
AssociatedObject.LostFocus -= AssociatedObjectOnLostFocus;
|
||||
}
|
||||
}
|
||||
|
||||
private void AssociatedObjectOnTextChanged( object sender, EventArgs eventArgs )
|
||||
{
|
||||
if ( !( sender is TextEditor textEditor ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( textEditor.Document == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int carot = textEditor.CaretOffset;
|
||||
TextBinding = textEditor.Document.Text;
|
||||
textEditor.CaretOffset = carot;
|
||||
}
|
||||
|
||||
private static void PropertyChangedCallback( DependencyObject dependencyObject,
|
||||
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs )
|
||||
{
|
||||
AvalonEditBehaviour behavior = dependencyObject as AvalonEditBehaviour;
|
||||
|
||||
TextEditor editor = behavior?.AssociatedObject;
|
||||
|
||||
if ( editor?.Document == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( dependencyPropertyChangedEventArgs.NewValue == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
editor.Document.Text = dependencyPropertyChangedEventArgs.NewValue.ToString();
|
||||
editor.CaretOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class BindableSelectedItemBehavior : Behavior<TreeView>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
if ( AssociatedObject != null )
|
||||
{
|
||||
AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTreeViewSelectedItemChanged( object sender, RoutedPropertyChangedEventArgs<object> e )
|
||||
{
|
||||
SelectedItem = e.NewValue;
|
||||
}
|
||||
|
||||
#region SelectedItem Property
|
||||
|
||||
public object SelectedItem
|
||||
{
|
||||
get => GetValue( SelectedItemProperty );
|
||||
set => SetValue( SelectedItemProperty, value );
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( "SelectedItem",
|
||||
typeof( object ), typeof( BindableSelectedItemBehavior ),
|
||||
new UIPropertyMetadata( null, OnSelectedItemChanged ) );
|
||||
|
||||
private static void OnSelectedItemChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
if ( e.NewValue is TreeViewItem item )
|
||||
{
|
||||
item.SetValue( TreeViewItem.IsSelectedProperty, true );
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ClassicAssist.Misc
|
||||
{
|
||||
public class BindingProxy : Freezable
|
||||
{
|
||||
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty DataProperty = DependencyProperty.Register( "Data", typeof( object ),
|
||||
typeof( BindingProxy ), new UIPropertyMetadata( null ) );
|
||||
|
||||
public object Data
|
||||
{
|
||||
get => GetValue( DataProperty );
|
||||
set => SetValue( DataProperty, value );
|
||||
}
|
||||
|
||||
#region Overrides of Freezable
|
||||
|
||||
protected override Freezable CreateInstanceCore()
|
||||
{
|
||||
return new BindingProxy();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
|
||||
//https://stackoverflow.com/questions/4305565/wpf-context-menu-on-left-click
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class ClickOpensContextMenuBehaviour
|
||||
{
|
||||
private static readonly DependencyProperty ClickOpensContextMenuProperty =
|
||||
DependencyProperty.RegisterAttached( "Enabled", typeof( bool ), typeof( ClickOpensContextMenuBehaviour ),
|
||||
new PropertyMetadata( HandlePropertyChanged ) );
|
||||
|
||||
public static bool GetEnabled( DependencyObject obj )
|
||||
{
|
||||
return (bool) obj.GetValue( ClickOpensContextMenuProperty );
|
||||
}
|
||||
|
||||
public static void SetEnabled( DependencyObject obj, bool value )
|
||||
{
|
||||
obj.SetValue( ClickOpensContextMenuProperty, value );
|
||||
}
|
||||
|
||||
private static void HandlePropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs args )
|
||||
{
|
||||
switch ( obj )
|
||||
{
|
||||
case Image image:
|
||||
image.MouseLeftButtonDown -= ExecuteMouseDown;
|
||||
image.MouseLeftButtonDown += ExecuteMouseDown;
|
||||
break;
|
||||
case Hyperlink hyperlink:
|
||||
hyperlink.Click -= ExecuteClick;
|
||||
hyperlink.Click += ExecuteClick;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExecuteMouseDown( object sender, MouseButtonEventArgs args )
|
||||
{
|
||||
if ( !( sender is DependencyObject obj ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = (bool) obj.GetValue( ClickOpensContextMenuProperty );
|
||||
|
||||
if ( !enabled )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = sender as Image;
|
||||
|
||||
if ( image?.ContextMenu != null )
|
||||
{
|
||||
image.ContextMenu.IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExecuteClick( object sender, RoutedEventArgs args )
|
||||
{
|
||||
if ( !( sender is DependencyObject obj ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = (bool) obj.GetValue( ClickOpensContextMenuProperty );
|
||||
|
||||
if ( !enabled )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !( sender is Hyperlink hyperlink ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( hyperlink.ContextMenu != null )
|
||||
{
|
||||
hyperlink.ContextMenu.IsOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class ClipboardBehaviour : Behavior<UIElement>
|
||||
{
|
||||
public static readonly DependencyProperty CopyCommandProperty = DependencyProperty.Register( "CopyCommand",
|
||||
typeof( ICommand ), typeof( ClipboardBehaviour ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None ) );
|
||||
|
||||
public static readonly DependencyProperty PasteCommandProperty = DependencyProperty.Register( "PasteCommand",
|
||||
typeof( ICommand ), typeof( ClipboardBehaviour ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None ) );
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof( object ), typeof( ClipboardBehaviour ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None ) );
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue( CommandParameterProperty );
|
||||
set => SetValue( CommandParameterProperty, value );
|
||||
}
|
||||
|
||||
public ICommand CopyCommand
|
||||
{
|
||||
get => (ICommand) GetValue( CopyCommandProperty );
|
||||
set => SetValue( CopyCommandProperty, value );
|
||||
}
|
||||
|
||||
public ICommand PasteCommand
|
||||
{
|
||||
get => (ICommand) GetValue( PasteCommandProperty );
|
||||
set => SetValue( PasteCommandProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
CommandBinding CopyCommandBinding = new CommandBinding(
|
||||
ApplicationCommands.Copy, CopyCommandExecuted, CopyCommandCanExecute );
|
||||
AssociatedObject.CommandBindings.Add( CopyCommandBinding );
|
||||
|
||||
CommandBinding CutCommandBinding = new CommandBinding(
|
||||
ApplicationCommands.Cut, CutCommandExecuted, CutCommandCanExecute );
|
||||
AssociatedObject.CommandBindings.Add( CutCommandBinding );
|
||||
|
||||
CommandBinding PasteCommandBinding = new CommandBinding( ApplicationCommands.Paste, PasteCommandExecuted,
|
||||
PasteCommandCanExecute );
|
||||
AssociatedObject.CommandBindings.Add( PasteCommandBinding );
|
||||
}
|
||||
|
||||
private void CopyCommandExecuted( object target, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
CopyCommand?.Execute( CommandParameter );
|
||||
}
|
||||
|
||||
private void CopyCommandCanExecute( object target, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
e.CanExecute = true;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void CutCommandExecuted( object target, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
}
|
||||
|
||||
private void CutCommandCanExecute( object target, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
}
|
||||
|
||||
private void PasteCommandExecuted( object target, ExecutedRoutedEventArgs e )
|
||||
{
|
||||
PasteCommand?.Execute( CommandParameter );
|
||||
}
|
||||
|
||||
private void PasteCommandCanExecute( object target, CanExecuteRoutedEventArgs e )
|
||||
{
|
||||
e.CanExecute = true;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class CloseOnClickBehaviour : Behavior<Button>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.Click += OnClick;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Click -= OnClick;
|
||||
}
|
||||
|
||||
private void OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
if ( !( sender is Button button ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Window window = Window.GetWindow( button );
|
||||
|
||||
window?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class ComboBoxBehavior : Behavior<ComboBox>
|
||||
{
|
||||
public static readonly DependencyProperty CommandBindingProperty =
|
||||
DependencyProperty.Register( "CommandBinding", typeof( ICommand ), typeof( ComboBoxBehavior ),
|
||||
new FrameworkPropertyMetadata( default( ICommand ), FrameworkPropertyMetadataOptions.None,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty =
|
||||
DependencyProperty.Register( "CommandParameter", typeof( object ), typeof( ComboBoxBehavior ),
|
||||
new FrameworkPropertyMetadata( default, FrameworkPropertyMetadataOptions.None,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
public static readonly DependencyProperty OnlyUserTriggeredProperty =
|
||||
DependencyProperty.Register( "OnlyUserTriggered", typeof( bool ), typeof( ComboBoxBehavior ),
|
||||
new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.None,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
private bool _userTriggered;
|
||||
|
||||
public ICommand CommandBinding
|
||||
{
|
||||
get => (ICommand) GetValue( CommandBindingProperty );
|
||||
set => SetValue( CommandBindingProperty, value );
|
||||
}
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue( CommandParameterProperty );
|
||||
set => SetValue( CommandParameterProperty, value );
|
||||
}
|
||||
|
||||
public bool OnlyUserTriggered
|
||||
{
|
||||
get => (bool) GetValue( OnlyUserTriggeredProperty );
|
||||
set => SetValue( OnlyUserTriggeredProperty, value );
|
||||
}
|
||||
|
||||
private static void PropertyChangedCallback( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.SelectionChanged += OnSelectionChanged;
|
||||
AssociatedObject.PreviewMouseDown += OnPreviewMouseDown;
|
||||
}
|
||||
|
||||
private void OnPreviewMouseDown( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
_userTriggered = true;
|
||||
}
|
||||
|
||||
private void OnSelectionChanged( object sender, SelectionChangedEventArgs e )
|
||||
{
|
||||
if ( OnlyUserTriggered && !_userTriggered )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommandBinding?.Execute( AssociatedObject.SelectedItem );
|
||||
_userTriggered = false;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.SelectionChanged -= OnSelectionChanged;
|
||||
AssociatedObject.PreviewMouseDown -= OnPreviewMouseDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
/*
|
||||
* https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/
|
||||
*/
|
||||
public class EnumBindingSourceExtension : MarkupExtension
|
||||
{
|
||||
private Type _enumType;
|
||||
|
||||
public EnumBindingSourceExtension()
|
||||
{
|
||||
}
|
||||
|
||||
public EnumBindingSourceExtension( Type enumType )
|
||||
{
|
||||
EnumType = enumType;
|
||||
}
|
||||
|
||||
public Type EnumType
|
||||
{
|
||||
get => _enumType;
|
||||
set
|
||||
{
|
||||
if ( value != _enumType )
|
||||
{
|
||||
if ( null != value )
|
||||
{
|
||||
Type enumType = Nullable.GetUnderlyingType( value ) ?? value;
|
||||
|
||||
if ( !enumType.IsEnum )
|
||||
{
|
||||
throw new ArgumentException( "Type must be for an Enum." );
|
||||
}
|
||||
}
|
||||
|
||||
_enumType = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override object ProvideValue( IServiceProvider serviceProvider )
|
||||
{
|
||||
if ( null == _enumType )
|
||||
{
|
||||
throw new InvalidOperationException( "The EnumType must be specified." );
|
||||
}
|
||||
|
||||
Type actualEnumType = Nullable.GetUnderlyingType( _enumType ) ?? _enumType;
|
||||
Array enumValues = Enum.GetValues( actualEnumType );
|
||||
|
||||
if ( actualEnumType == _enumType )
|
||||
{
|
||||
return enumValues;
|
||||
}
|
||||
|
||||
Array tempArray = Array.CreateInstance( actualEnumType, enumValues.Length + 1 );
|
||||
enumValues.CopyTo( tempArray, 1 );
|
||||
return tempArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class ItemsControlAutoScrollBehaviour : Behavior<ItemsControl>
|
||||
{
|
||||
public static readonly DependencyProperty ScrollViewerProperty = DependencyProperty.Register( "ScrollViewer",
|
||||
typeof( ScrollViewer ), typeof( ItemsControlAutoScrollBehaviour ),
|
||||
new PropertyMetadata( default( ScrollViewer ) ) );
|
||||
|
||||
public ScrollViewer ScrollViewer
|
||||
{
|
||||
get => (ScrollViewer) GetValue( ScrollViewerProperty );
|
||||
set => SetValue( ScrollViewerProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
( (INotifyCollectionChanged) AssociatedObject.Items ).CollectionChanged += OnCollectionChanged;
|
||||
}
|
||||
|
||||
private void OnCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
|
||||
{
|
||||
ScrollViewer?.ScrollToEnd();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
( (INotifyCollectionChanged) AssociatedObject.Items ).CollectionChanged -= OnCollectionChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class ItemsControlSelectNewEntryBehaviour : Behavior<ItemsControl>
|
||||
{
|
||||
public static readonly DependencyProperty SelectedItemProperty =
|
||||
DependencyProperty.Register( nameof( SelectedItem ), typeof( object ),
|
||||
typeof( ItemsControlSelectNewEntryBehaviour ),
|
||||
new FrameworkPropertyMetadata( default, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register( nameof( Type ),
|
||||
typeof( Type ), typeof( ItemsControlSelectNewEntryBehaviour ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public object SelectedItem
|
||||
{
|
||||
get => GetValue( SelectedItemProperty );
|
||||
set => SetValue( SelectedItemProperty, value );
|
||||
}
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get => (Type) GetValue( TypeProperty );
|
||||
set => SetValue( TypeProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
( (INotifyCollectionChanged) AssociatedObject.Items ).CollectionChanged += OnCollectionChanged;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
( (INotifyCollectionChanged) AssociatedObject.Items ).CollectionChanged -= OnCollectionChanged;
|
||||
}
|
||||
|
||||
private void OnCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
|
||||
{
|
||||
if ( !( sender is ItemCollection ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( e.NewItems == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object firstItem = e.NewItems[0];
|
||||
|
||||
if ( Type != null )
|
||||
{
|
||||
if ( firstItem.GetType() != Type )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SelectedItem = firstItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interactivity;
|
||||
using ClassicAssist.UI.ViewModels;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class ListViewDoubleClickBehaviour : Behavior<ListView>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.MouseDoubleClick += OnMouseDoubleClick;
|
||||
}
|
||||
|
||||
private void OnMouseDoubleClick( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
ObjectInspectorViewModel i = (ObjectInspectorViewModel) ( (ListView) sender ).DataContext;
|
||||
|
||||
i.SelectedItem?.OnDoubleClick?.Invoke( i.SelectedItem );
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
AssociatedObject.MouseDoubleClick -= OnMouseDoubleClick;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
/*
|
||||
* https://stackoverflow.com/questions/8088595/synchronizing-multi-select-listbox-with-mvvm
|
||||
*/
|
||||
|
||||
public class ListViewMultiSelectionBehaviour : Behavior<ListView>
|
||||
{
|
||||
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register( "SelectedItems",
|
||||
typeof( IList ), typeof( ListViewMultiSelectionBehaviour ),
|
||||
new UIPropertyMetadata( null, SelectedItemsChanged ) );
|
||||
|
||||
private bool _isUpdatingSource;
|
||||
|
||||
private bool _isUpdatingTarget;
|
||||
|
||||
public IList SelectedItems
|
||||
{
|
||||
get => (IList) GetValue( SelectedItemsProperty );
|
||||
set => SetValue( SelectedItemsProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
if ( SelectedItems == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssociatedObject.SelectedItems.Clear();
|
||||
|
||||
foreach ( object item in SelectedItems )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Add( item );
|
||||
}
|
||||
|
||||
AssociatedObject.SelectionChanged += ListViewSelectionChanged;
|
||||
}
|
||||
|
||||
private static void SelectedItemsChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
if ( o == null || !( o is ListViewMultiSelectionBehaviour behavior ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
INotifyCollectionChanged oldValue = (INotifyCollectionChanged) e.OldValue;
|
||||
INotifyCollectionChanged newValue = (INotifyCollectionChanged) e.NewValue;
|
||||
|
||||
if ( oldValue != null )
|
||||
{
|
||||
oldValue.CollectionChanged -= behavior.SourceCollectionChanged;
|
||||
behavior.AssociatedObject.SelectionChanged -= behavior.ListViewSelectionChanged;
|
||||
}
|
||||
|
||||
if ( newValue == null || behavior.AssociatedObject == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
behavior.AssociatedObject.SelectedItems.Clear();
|
||||
|
||||
if ( newValue is IEnumerable items )
|
||||
{
|
||||
foreach ( object item in items )
|
||||
{
|
||||
behavior.AssociatedObject.SelectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
|
||||
behavior.AssociatedObject.SelectionChanged += behavior.ListViewSelectionChanged;
|
||||
newValue.CollectionChanged += behavior.SourceCollectionChanged;
|
||||
}
|
||||
|
||||
private void SourceCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
|
||||
{
|
||||
if ( _isUpdatingSource )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdatingTarget = true;
|
||||
|
||||
if ( e.OldItems != null )
|
||||
{
|
||||
foreach ( object item in e.OldItems )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Remove( item );
|
||||
}
|
||||
}
|
||||
|
||||
if ( e.NewItems != null )
|
||||
{
|
||||
foreach ( object item in e.NewItems )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
|
||||
if ( e.Action == NotifyCollectionChangedAction.Reset )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Clear();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdatingTarget = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ListViewSelectionChanged( object sender, SelectionChangedEventArgs e )
|
||||
{
|
||||
if ( e.OriginalSource.GetType() != typeof( ListView ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _isUpdatingTarget )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IList selectedItems = SelectedItems;
|
||||
|
||||
if ( selectedItems == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdatingSource = true;
|
||||
|
||||
foreach ( object item in e.RemovedItems )
|
||||
{
|
||||
selectedItems.Remove( item );
|
||||
}
|
||||
|
||||
foreach ( object item in e.AddedItems )
|
||||
{
|
||||
selectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdatingSource = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Interactivity;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Data;
|
||||
using Sentry;
|
||||
using Sentry.Protocol;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class LoadOptionsOnWindowLoaded : Behavior<Window>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
AssociatedObject.Loaded += OnLoaded;
|
||||
AssociatedObject.Closing += OnClosing;
|
||||
}
|
||||
|
||||
private static void OnClosing( object sender, CancelEventArgs e )
|
||||
{
|
||||
Options.Save( Options.CurrentOptions );
|
||||
AssistantOptions.Save();
|
||||
}
|
||||
|
||||
private static void OnLoaded( object sender, RoutedEventArgs e )
|
||||
{
|
||||
AssistantOptions.OnWindowLoaded();
|
||||
SentrySdk.Init( new SentryOptions
|
||||
{
|
||||
Dsn = new Dsn( "https://7a7c44cd07e64058a3b434e1c86e4c02@o369765.ingest.sentry.io/5325425" ),
|
||||
BeforeSend = SentryBeforeSend
|
||||
} );
|
||||
}
|
||||
|
||||
private static SentryEvent SentryBeforeSend( SentryEvent args )
|
||||
{
|
||||
args.User = new User { Id = AssistantOptions.UserId };
|
||||
args.SetTag( "SessionId", AssistantOptions.SessionId );
|
||||
args.SetExtra( "PlayerName", Engine.Player?.Name ?? "Unknown" );
|
||||
args.SetExtra( "PlayerSerial", Engine.Player?.Serial ?? 0 );
|
||||
args.SetExtra( "Shard", Engine.CurrentShard?.Name ?? "Unknown" );
|
||||
args.SetExtra( "Connected", Engine.Connected );
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.Loaded -= OnLoaded;
|
||||
AssociatedObject.Closing -= OnClosing;
|
||||
base.OnDetaching();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
/*
|
||||
* https://stackoverflow.com/questions/8088595/synchronizing-multi-select-listbox-with-mvvm
|
||||
*/
|
||||
|
||||
public class MultiSelectionBehaviour : Behavior<ListBox>
|
||||
{
|
||||
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register( "SelectedItems",
|
||||
typeof( IList ), typeof( MultiSelectionBehaviour ), new UIPropertyMetadata( null, SelectedItemsChanged ) );
|
||||
|
||||
private bool _isUpdatingSource;
|
||||
|
||||
private bool _isUpdatingTarget;
|
||||
|
||||
public IList SelectedItems
|
||||
{
|
||||
get => (IList) GetValue( SelectedItemsProperty );
|
||||
set => SetValue( SelectedItemsProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
if ( SelectedItems == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssociatedObject.SelectedItems.Clear();
|
||||
|
||||
foreach ( object item in SelectedItems )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
|
||||
private static void SelectedItemsChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
if ( o == null || !( o is MultiSelectionBehaviour behavior ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
INotifyCollectionChanged oldValue = (INotifyCollectionChanged) e.OldValue;
|
||||
INotifyCollectionChanged newValue = (INotifyCollectionChanged) e.NewValue;
|
||||
|
||||
if ( oldValue != null )
|
||||
{
|
||||
oldValue.CollectionChanged -= behavior.SourceCollectionChanged;
|
||||
behavior.AssociatedObject.SelectionChanged -= behavior.ListBoxSelectionChanged;
|
||||
}
|
||||
|
||||
if ( newValue == null || behavior.AssociatedObject == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
behavior.AssociatedObject.SelectedItems.Clear();
|
||||
|
||||
if ( newValue is IEnumerable items )
|
||||
{
|
||||
foreach ( object item in items )
|
||||
{
|
||||
behavior.AssociatedObject.SelectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
|
||||
behavior.AssociatedObject.SelectionChanged += behavior.ListBoxSelectionChanged;
|
||||
newValue.CollectionChanged += behavior.SourceCollectionChanged;
|
||||
}
|
||||
|
||||
private void SourceCollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
|
||||
{
|
||||
if ( _isUpdatingSource )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdatingTarget = true;
|
||||
|
||||
if ( e.OldItems != null )
|
||||
{
|
||||
foreach ( object item in e.OldItems )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Remove( item );
|
||||
}
|
||||
}
|
||||
|
||||
if ( e.NewItems != null )
|
||||
{
|
||||
foreach ( object item in e.NewItems )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
|
||||
if ( e.Action == NotifyCollectionChangedAction.Reset )
|
||||
{
|
||||
AssociatedObject.SelectedItems.Clear();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdatingTarget = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ListBoxSelectionChanged( object sender, SelectionChangedEventArgs e )
|
||||
{
|
||||
if ( _isUpdatingTarget )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IList selectedItems = SelectedItems;
|
||||
|
||||
if ( selectedItems == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdatingSource = true;
|
||||
|
||||
foreach ( object item in e.RemovedItems )
|
||||
{
|
||||
selectedItems.Remove( item );
|
||||
}
|
||||
|
||||
foreach ( object item in e.AddedItems )
|
||||
{
|
||||
selectedItems.Add( item );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdatingSource = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class SkillsGridViewColumn : GridViewColumn
|
||||
{
|
||||
public enum Enums
|
||||
{
|
||||
Name,
|
||||
Value,
|
||||
Base,
|
||||
Delta,
|
||||
Cap,
|
||||
LockStatus
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SortFieldProperty = DependencyProperty.Register( "SortField",
|
||||
typeof( Enums ), typeof( SkillsGridViewColumn ), new UIPropertyMetadata( null ) );
|
||||
|
||||
public Enums SortField
|
||||
{
|
||||
get => (Enums) GetValue( SortFieldProperty );
|
||||
set => SetValue( SortFieldProperty, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class CellWidthValueConverter : IValueConverter
|
||||
{
|
||||
private double substractValue = 15;
|
||||
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( parameter != null )
|
||||
{
|
||||
substractValue = double.Parse( parameter.ToString() );
|
||||
}
|
||||
|
||||
double? val = (double?) value - substractValue;
|
||||
return val;
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
return (double?) value + substractValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class DateTimeToTimeSpanValueConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
return !( value is DateTime dt ) ? null : ( DateTime.Now - dt ).ToString();
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class EnumMatchToBooleanConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( value == null || parameter == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string checkValue = value.ToString();
|
||||
string targetValue = parameter.ToString();
|
||||
return checkValue.Equals( targetValue, StringComparison.InvariantCultureIgnoreCase );
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( value == null || parameter == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
bool useValue = (bool) value;
|
||||
string targetValue = parameter.ToString();
|
||||
|
||||
if ( useValue )
|
||||
{
|
||||
return Enum.Parse( targetType, targetValue );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class HexToIntValueConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( value is string val && val.StartsWith( "0x" ) )
|
||||
{
|
||||
return System.Convert.ToInt32( val, 16 );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( value is string val && val.StartsWith( "0x" ) )
|
||||
{
|
||||
return System.Convert.ToInt32( val, 16 );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class IntToHexStringValueConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( value is int val )
|
||||
{
|
||||
return $"0x{val:x8}";
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class InverseBooleanConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
try
|
||||
{
|
||||
bool testValue = (bool) value;
|
||||
return !testValue; // or do whatever you need with this boolean
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
} // or false
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
return Convert( value, targetType, parameter, culture );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class JoinArrayValueConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( !( value is string[] array ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return string.Join( (string) parameter ?? ", ", array );
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.UO.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class LockStatusValueConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( !( value is LockStatus ) )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
LockStatus lockStatus = (LockStatus) value;
|
||||
|
||||
switch ( lockStatus )
|
||||
{
|
||||
case LockStatus.Up:
|
||||
|
||||
return Properties.Resources.arrow_up.ToImageSource();
|
||||
case LockStatus.Down:
|
||||
|
||||
return Properties.Resources.arrow_down.ToImageSource();
|
||||
case LockStatus.Locked:
|
||||
|
||||
return Properties.Resources.padlock.ToImageSource();
|
||||
default:
|
||||
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class PriorityMultiValueConverter : IMultiValueConverter
|
||||
{
|
||||
//https://stackoverflow.com/questions/1915562/wpf-binding-fallbackvalue-set-to-binding
|
||||
public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
return values.FirstOrDefault( o => o != null );
|
||||
}
|
||||
|
||||
public object[] ConvertBack( object value, Type[] targetTypes, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
using ClassicAssist.Data.Skills;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.UO.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class SetSkillLockData
|
||||
{
|
||||
public LockStatus LockStatus { get; set; }
|
||||
public IEnumerable<SkillEntry> SkillEntries { get; set; }
|
||||
}
|
||||
|
||||
public class SetSkillLockMultiValueConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
IList items = (IList) ( (BindingProxy) values[0] ).Data;
|
||||
IEnumerable<SkillEntry> skills = items.Cast<SkillEntry>();
|
||||
|
||||
LockStatus lockStatus = (LockStatus) values[1];
|
||||
|
||||
return new SetSkillLockData { SkillEntries = skills, LockStatus = lockStatus };
|
||||
}
|
||||
|
||||
public object[] ConvertBack( object value, Type[] targetTypes, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ClassicAssist.Shared;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
public class StringToResourceConverter : IValueConverter
|
||||
{
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
if ( value is string )
|
||||
{
|
||||
if ( targetType.Equals( typeof( ImageSource ) ) )
|
||||
{
|
||||
return BitmapFrame.Create( Engine.GetResourceStream( (string) value ), BitmapCreateOptions.None,
|
||||
BitmapCacheOption.OnLoad );
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc.ValueConverters
|
||||
{
|
||||
/*
|
||||
* https://stackoverflow.com/questions/2607490/is-there-a-way-to-chain-multiple-value-converters-in-xaml
|
||||
*/
|
||||
public class ValueConverterGroup : List<IValueConverter>, IValueConverter
|
||||
{
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
return this.Aggregate( value,
|
||||
( current, converter ) => converter.Convert( current, targetType, parameter, culture ) );
|
||||
}
|
||||
|
||||
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using MessageBoxButtons = ClassicAssist.Misc.MessageBoxButtons;
|
||||
using WMessageBox = System.Windows.Forms.MessageBox;
|
||||
using WMessageBoxButtons = System.Windows.Forms.MessageBoxButtons;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
internal class WPFMessageBoxProvider : IMessageBoxProvider
|
||||
{
|
||||
public Task<MessageBoxResult> Show( string text, string caption = null,
|
||||
MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxImage? icon = null )
|
||||
{
|
||||
if (string.IsNullOrEmpty( caption ))
|
||||
{
|
||||
caption = Strings.Error;
|
||||
}
|
||||
|
||||
DialogResult result = WMessageBox.Show( text, caption,
|
||||
buttons == MessageBoxButtons.YesNo ? WMessageBoxButtons.YesNo : WMessageBoxButtons.OK );
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case DialogResult.OK: return Task.FromResult( MessageBoxResult.OK );
|
||||
case DialogResult.Yes: return Task.FromResult( MessageBoxResult.Yes );
|
||||
default: return Task.FromResult( MessageBoxResult.No );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public enum WindowCommand
|
||||
{
|
||||
Minimize,
|
||||
Maximize,
|
||||
Close
|
||||
}
|
||||
|
||||
public class WindowCommandBehaviour : Behavior<Button>
|
||||
{
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command",
|
||||
typeof( WindowCommand ), typeof( WindowCommandBehaviour ),
|
||||
new FrameworkPropertyMetadata( WindowCommand.Close ) );
|
||||
|
||||
public WindowCommand Command
|
||||
{
|
||||
get => (WindowCommand) GetValue( CommandProperty );
|
||||
set => SetValue( CommandProperty, value );
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.Click += OnClick;
|
||||
}
|
||||
|
||||
private void OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
if ( !( sender is UIElement element ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Window window = Window.GetWindow( element );
|
||||
|
||||
if ( window == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( Command )
|
||||
{
|
||||
case WindowCommand.Minimize:
|
||||
{
|
||||
window.WindowState = WindowState.Minimized;
|
||||
break;
|
||||
}
|
||||
case WindowCommand.Maximize:
|
||||
{
|
||||
window.WindowState = window.WindowState == WindowState.Maximized
|
||||
? WindowState.Normal
|
||||
: WindowState.Maximized;
|
||||
|
||||
break;
|
||||
}
|
||||
case WindowCommand.Close:
|
||||
{
|
||||
window.Close();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
AssociatedObject.Click -= OnClick;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interactivity;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class WindowMouseDownBehaviour : Behavior<UIElement>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
AssociatedObject.MouseDown += OnMouseDown;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
AssociatedObject.MouseDown -= OnMouseDown;
|
||||
}
|
||||
|
||||
private static void OnMouseDown( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
if ( !( sender is UIElement element ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( e.ChangedButton == MouseButton.Left )
|
||||
{
|
||||
Window.GetWindow( element )?.DragMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interactivity;
|
||||
using ClassicAssist.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Misc
|
||||
{
|
||||
public class WindowResizeBehaviour : Behavior<Window>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
|
||||
#if !DEVELOP
|
||||
AssociatedObject.Width = AssistantOptions.WindowWidth;
|
||||
AssociatedObject.Height = AssistantOptions.WindowHeight;
|
||||
#endif
|
||||
|
||||
AssociatedObject.SizeChanged += OnSizeChanged;
|
||||
AssistantOptions.OptionsLoaded += OnOptionsLoaded;
|
||||
}
|
||||
|
||||
private void OnOptionsLoaded( object sender, EventArgs e )
|
||||
{
|
||||
AssociatedObject.Width = AssistantOptions.WindowWidth;
|
||||
AssociatedObject.Height = AssistantOptions.WindowHeight;
|
||||
}
|
||||
|
||||
private static void OnSizeChanged( object sender, SizeChangedEventArgs e )
|
||||
{
|
||||
#if !DEVELOP
|
||||
AssistantOptions.WindowHeight = e.HeightChanged ? e.NewSize.Height : AssistantOptions.WindowHeight;
|
||||
AssistantOptions.WindowWidth = e.WidthChanged ? e.NewSize.Width : AssistantOptions.WindowWidth;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
|
||||
AssociatedObject.SizeChanged += OnSizeChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Annotations;
|
||||
using ClassicAssist.Data.Autoloot;
|
||||
|
||||
namespace ClassicAssist.UI.Models
|
||||
{
|
||||
public class EntityCollectionFilter : INotifyPropertyChanged
|
||||
{
|
||||
private PropertyEntry _constraint;
|
||||
private AutolootOperator _operator = AutolootOperator.Equal;
|
||||
private int _value;
|
||||
|
||||
public PropertyEntry Constraint
|
||||
{
|
||||
get => _constraint;
|
||||
set => SetProperty( ref _constraint, value );
|
||||
}
|
||||
|
||||
public AutolootOperator Operator
|
||||
{
|
||||
get => _operator;
|
||||
set => SetProperty( ref _operator, value );
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => _value;
|
||||
set => SetProperty( ref _value, value );
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = null )
|
||||
{
|
||||
PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
|
||||
}
|
||||
|
||||
// ReSharper disable once RedundantAssignment
|
||||
public virtual void SetProperty<T>( ref T obj, T value, [CallerMemberName] string propertyName = "" )
|
||||
{
|
||||
obj = value;
|
||||
OnPropertyChanged( propertyName );
|
||||
CommandManager.InvalidateRequerySuggested();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace ClassicAssist.UI.Models
|
||||
{
|
||||
public enum EntityCollectionSortStyle
|
||||
{
|
||||
Name,
|
||||
Serial,
|
||||
Hue,
|
||||
ID,
|
||||
Quantity
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Data.Macros;
|
||||
using ClassicAssist.Data.Macros.Commands;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using ClassicAssist.UO;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels
|
||||
{
|
||||
public class TimerData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public OffsetStopwatch Value { get; set; }
|
||||
}
|
||||
|
||||
public class ActiveObjectsViewModel : BaseViewModel
|
||||
{
|
||||
private ICommand _clearAllAliasesCommand;
|
||||
private ICommand _clearAllListsCommand;
|
||||
private ICommand _clearIgnoreListCommand;
|
||||
private ObservableCollection<int> _ignoreEntries = new ObservableCollection<int>();
|
||||
private ICommand _refreshAliasesCommand;
|
||||
private ICommand _refreshIgnoreListCommand;
|
||||
private ICommand _refreshListsCommand;
|
||||
private ICommand _refreshTimersCommand;
|
||||
private ICommand _removeAliasCommand;
|
||||
private ICommand _removeIgnoreEntryCommand;
|
||||
private ICommand _removeInstanceAliasCommand;
|
||||
private ICommand _removeListCommand;
|
||||
private AliasEntry _selectedAlias;
|
||||
private int _selectedIgnoreEntry;
|
||||
private InstanceAliasEntry _selectedInstanceAlias;
|
||||
private ListEntry _selectedList;
|
||||
private TimerData _selectedTimer;
|
||||
private ICommand _setAliasCommand;
|
||||
private ObservableCollection<TimerData> _timers = new ObservableCollection<TimerData>();
|
||||
|
||||
public ActiveObjectsViewModel()
|
||||
{
|
||||
RefreshAliases();
|
||||
RefreshInstanceAliases();
|
||||
RefreshLists();
|
||||
RefreshTimers();
|
||||
RefreshIgnoreList();
|
||||
}
|
||||
|
||||
public ObservableCollection<AliasEntry> Aliases { get; set; } = new ObservableCollection<AliasEntry>();
|
||||
|
||||
public ICommand ClearAllAliasesCommand =>
|
||||
_clearAllAliasesCommand ?? ( _clearAllAliasesCommand = new RelayCommand( ClearAllAliases, o => true ) );
|
||||
|
||||
public ICommand ClearAllListsCommand =>
|
||||
_clearAllListsCommand ?? ( _clearAllListsCommand = new RelayCommand( ClearAllLists, o => true ) );
|
||||
|
||||
public ICommand ClearIgnoreListCommand =>
|
||||
_clearIgnoreListCommand ?? ( _clearIgnoreListCommand = new RelayCommand( ClearIgnoreList, o => true ) );
|
||||
|
||||
public ObservableCollection<int> IgnoreEntries
|
||||
{
|
||||
get => _ignoreEntries;
|
||||
set => SetProperty( ref _ignoreEntries, value );
|
||||
}
|
||||
|
||||
public ObservableCollection<InstanceAliasEntry> InstanceAliases { get; set; } =
|
||||
new ObservableCollection<InstanceAliasEntry>();
|
||||
|
||||
public ObservableCollection<ListEntry> Lists { get; set; } = new ObservableCollection<ListEntry>();
|
||||
|
||||
public ICommand RefreshAliasesCommand =>
|
||||
_refreshAliasesCommand ?? ( _refreshAliasesCommand = new RelayCommand( o => RefreshAliases(), o => true ) );
|
||||
|
||||
public ICommand RefreshIgnoreListCommand =>
|
||||
_refreshIgnoreListCommand ??
|
||||
( _refreshIgnoreListCommand = new RelayCommand( o => RefreshIgnoreList(), o => true ) );
|
||||
|
||||
public ICommand RefreshListsCommand =>
|
||||
_refreshListsCommand ?? ( _refreshListsCommand = new RelayCommand( o => RefreshLists(), o => true ) );
|
||||
|
||||
public ICommand RefreshTimersCommand =>
|
||||
_refreshTimersCommand ?? ( _refreshTimersCommand = new RelayCommand( o => RefreshTimers(), o => true ) );
|
||||
|
||||
public ICommand RemoveAliasCommand =>
|
||||
_removeAliasCommand ??
|
||||
( _removeAliasCommand = new RelayCommand( RemoveAlias, o => SelectedAlias != null ) );
|
||||
|
||||
public ICommand RemoveIgnoreEntryCommand =>
|
||||
_removeIgnoreEntryCommand ??
|
||||
( _removeIgnoreEntryCommand = new RelayCommand( RemoveIgnoreEntry, o => true ) );
|
||||
|
||||
public ICommand RemoveInstanceAliasCommand =>
|
||||
_removeInstanceAliasCommand ?? ( _removeInstanceAliasCommand =
|
||||
new RelayCommand( RemoveInstanceAlias, o => SelectedInstanceAlias != null ) );
|
||||
|
||||
public ICommand RemoveListCommand =>
|
||||
_removeListCommand ?? ( _removeListCommand = new RelayCommand( RemoveList, o => SelectedList != null ) );
|
||||
|
||||
public AliasEntry SelectedAlias
|
||||
{
|
||||
get => _selectedAlias;
|
||||
set => SetProperty( ref _selectedAlias, value );
|
||||
}
|
||||
|
||||
public int SelectedIgnoreEntry
|
||||
{
|
||||
get => _selectedIgnoreEntry;
|
||||
set => SetProperty( ref _selectedIgnoreEntry, value );
|
||||
}
|
||||
|
||||
public InstanceAliasEntry SelectedInstanceAlias
|
||||
{
|
||||
get => _selectedInstanceAlias;
|
||||
set => SetProperty( ref _selectedInstanceAlias, value );
|
||||
}
|
||||
|
||||
public ListEntry SelectedList
|
||||
{
|
||||
get => _selectedList;
|
||||
set => SetProperty( ref _selectedList, value );
|
||||
}
|
||||
|
||||
public TimerData SelectedTimer
|
||||
{
|
||||
get => _selectedTimer;
|
||||
set => SetProperty( ref _selectedTimer, value );
|
||||
}
|
||||
|
||||
public ICommand SetAliasCommand =>
|
||||
_setAliasCommand ?? ( _setAliasCommand = new RelayCommandAsync( SetAlias, o => o != null ) );
|
||||
|
||||
public ObservableCollection<TimerData> Timers
|
||||
{
|
||||
get => _timers;
|
||||
set => SetProperty( ref _timers, value );
|
||||
}
|
||||
|
||||
private void RefreshInstanceAliases()
|
||||
{
|
||||
InstanceAliases.Clear();
|
||||
|
||||
MacroManager manager = MacroManager.GetInstance();
|
||||
|
||||
foreach ( MacroEntry entry in manager.Items )
|
||||
{
|
||||
foreach ( KeyValuePair<string, int> alias in entry.Aliases )
|
||||
{
|
||||
InstanceAliases.Add( new InstanceAliasEntry
|
||||
{
|
||||
Macro = entry, Name = alias.Key, Serial = alias.Value
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveInstanceAlias( object obj )
|
||||
{
|
||||
if ( !( obj is InstanceAliasEntry entry ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entry.Macro.Aliases.Remove( entry.Name );
|
||||
|
||||
RefreshInstanceAliases();
|
||||
}
|
||||
|
||||
private void ClearIgnoreList( object obj )
|
||||
{
|
||||
ObjectCommands.ClearIgnoreList();
|
||||
|
||||
RefreshIgnoreList();
|
||||
}
|
||||
|
||||
private void RemoveIgnoreEntry( object obj )
|
||||
{
|
||||
if ( !( obj is int serial ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectCommands.IgnoreList.Remove( serial );
|
||||
|
||||
RefreshIgnoreList();
|
||||
}
|
||||
|
||||
private void RefreshIgnoreList()
|
||||
{
|
||||
IgnoreEntries.Clear();
|
||||
|
||||
foreach ( int serial in ObjectCommands.IgnoreList )
|
||||
{
|
||||
IgnoreEntries.Add( serial );
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshTimers()
|
||||
{
|
||||
Dictionary<string, OffsetStopwatch> timers = TimerCommands.GetAllTimers();
|
||||
|
||||
if ( timers == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Timers.Clear();
|
||||
|
||||
foreach ( KeyValuePair<string, OffsetStopwatch> timer in timers )
|
||||
{
|
||||
Timers.Add( new TimerData { Name = timer.Key, Value = timer.Value } );
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveList( object obj )
|
||||
{
|
||||
if ( !( obj is ListEntry entry ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ListCommands.RemoveList( entry.Name );
|
||||
Lists.Remove( entry );
|
||||
}
|
||||
|
||||
private void ClearAllLists( object obj )
|
||||
{
|
||||
string[] lists = ListCommands.GetAllLists().Select( l => l.Key ).ToArray();
|
||||
|
||||
for ( int i = 0; i < lists.Count(); i++ )
|
||||
{
|
||||
ListCommands.RemoveList( lists[i] );
|
||||
}
|
||||
|
||||
RefreshLists();
|
||||
}
|
||||
|
||||
private void RefreshLists()
|
||||
{
|
||||
Lists.Clear();
|
||||
|
||||
foreach ( KeyValuePair<string, List<int>> list in ListCommands.GetAllLists() )
|
||||
{
|
||||
Lists.Add( new ListEntry { Name = list.Key, Serials = list.Value.ToArray() } );
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveAlias( object obj )
|
||||
{
|
||||
if ( !( obj is AliasEntry entry ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AliasCommands.UnsetAlias( entry.Name );
|
||||
Aliases.Remove( entry );
|
||||
}
|
||||
|
||||
public void RefreshAliases()
|
||||
{
|
||||
Aliases.Clear();
|
||||
|
||||
foreach ( KeyValuePair<string, int> alias in AliasCommands.GetAllAliases() )
|
||||
{
|
||||
Aliases.AddSorted( new AliasEntry { Name = alias.Key, Serial = alias.Value } );
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearAllAliases( object obj )
|
||||
{
|
||||
string[] aliases = AliasCommands.GetAllAliases().Select( a => a.Key ).ToArray();
|
||||
|
||||
// ReSharper disable once ForCanBeConvertedToForeach
|
||||
for ( int i = 0; i < aliases.Length; i++ )
|
||||
{
|
||||
AliasCommands.UnsetAlias( aliases[i] );
|
||||
}
|
||||
|
||||
RefreshAliases();
|
||||
}
|
||||
|
||||
private static async Task SetAlias( object arg )
|
||||
{
|
||||
if ( !( arg is AliasEntry entry ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int serial =
|
||||
await Shared.UO.Commands.GetTargeSerialAsync( string.Format( Strings.Target_object___0_____, entry.Name ) );
|
||||
|
||||
if ( serial == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AliasCommands.SetAlias( entry.Name, serial );
|
||||
}
|
||||
|
||||
public class InstanceAliasEntry
|
||||
{
|
||||
public MacroEntry Macro { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Serial { get; set; }
|
||||
}
|
||||
|
||||
public class AliasEntry : IComparable<AliasEntry>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Serial { get; set; }
|
||||
|
||||
public int CompareTo( AliasEntry other )
|
||||
{
|
||||
if ( ReferenceEquals( this, other ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( ReferenceEquals( null, other ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return string.Compare( Name, other.Name, StringComparison.InvariantCultureIgnoreCase );
|
||||
}
|
||||
}
|
||||
|
||||
public class ListEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int[] Serials { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Data.Chat;
|
||||
using ClassicAssist.Data.Macros.Commands;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using ClassicAssist.Shared.UO;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels
|
||||
{
|
||||
public class ChatViewModel : BaseViewModel
|
||||
{
|
||||
private readonly SolidColorBrush _defaultBrush =
|
||||
new SolidColorBrush( Color.FromArgb( 0xff, 0xcc, 0xcc, 0xcc ) );
|
||||
|
||||
private readonly SolidColorBrush _enemyBrush = new SolidColorBrush( Colors.Orange );
|
||||
|
||||
private readonly SolidColorBrush _friendBrush = new SolidColorBrush( Colors.LimeGreen );
|
||||
|
||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||
private readonly ChatManager _manager;
|
||||
private ICommand _changeChannelCommand;
|
||||
private ObservableCollection<string> _channels = new ObservableCollection<string>();
|
||||
private string _currentChannel;
|
||||
private ObservableCollection<ChatMessage> _messages = new ObservableCollection<ChatMessage>();
|
||||
private string _selectedChannel;
|
||||
private string _title;
|
||||
private ICommand _toggleOptionCommand;
|
||||
private bool _topmost = true;
|
||||
private ObservableCollection<ChatUser> _users = new ObservableCollection<ChatUser>();
|
||||
|
||||
public ChatViewModel()
|
||||
{
|
||||
_manager = ChatManager.GetInstance();
|
||||
|
||||
_manager.UserJoinedEvent += OnUserJoined;
|
||||
_manager.UserLeftEvent += OnUserLeft;
|
||||
_manager.ClearUsersEvent += OnClearUsers;
|
||||
_manager.JoinedChatChannelEvent += OnJoinedChatChannel;
|
||||
_manager.LeftChatChannelEvent += OnLeftChatChannel;
|
||||
Engine.DisconnectedEvent += () => OnLeftChatChannel( string.Empty );
|
||||
_manager.ChannelCreatedEvent += OnChannelCreated;
|
||||
_manager.ChannelRemovedEvent += OnChannelRemoved;
|
||||
|
||||
if ( !string.IsNullOrEmpty( _manager.CurrentChannel ) )
|
||||
{
|
||||
OnJoinedChatChannel( _manager.CurrentChannel );
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateTitle( Strings.Chat );
|
||||
}
|
||||
|
||||
foreach ( string user in _manager.Users )
|
||||
{
|
||||
//TODO2
|
||||
Users.AddSorted( new ChatUser { Username = user/*, Colour = GetUserColour( user )*/ } );
|
||||
}
|
||||
|
||||
foreach ( string channel in _manager.Channels )
|
||||
{
|
||||
OnChannelCreated( channel );
|
||||
}
|
||||
|
||||
//foreach ( ChatMessage message in _manager.Messages )
|
||||
//{
|
||||
// Messages.Add( message );
|
||||
//}
|
||||
|
||||
_manager.ChatMessageEvent += OnChatMessage;
|
||||
}
|
||||
|
||||
public ICommand ChangeChannelCommand =>
|
||||
_changeChannelCommand ??
|
||||
( _changeChannelCommand = new RelayCommand( ChangeChannel, o => Channels.Count != 0 ) );
|
||||
|
||||
public ObservableCollection<string> Channels
|
||||
{
|
||||
get => _channels;
|
||||
set => SetProperty( ref _channels, value );
|
||||
}
|
||||
|
||||
public string CurrentChannel
|
||||
{
|
||||
get => _currentChannel;
|
||||
set => SetProperty( ref _currentChannel, value );
|
||||
}
|
||||
|
||||
public ObservableCollection<ChatMessage> Messages
|
||||
{
|
||||
get => _messages;
|
||||
set => SetProperty( ref _messages, value );
|
||||
}
|
||||
|
||||
public string SelectedChannel
|
||||
{
|
||||
get => _selectedChannel;
|
||||
set => SetProperty( ref _selectedChannel, value );
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => _title;
|
||||
set => SetProperty( ref _title, value );
|
||||
}
|
||||
|
||||
public ICommand ToggleOptionCommand =>
|
||||
_toggleOptionCommand ?? ( _toggleOptionCommand = new RelayCommand( ToggleOption, o => true ) );
|
||||
|
||||
public bool Topmost
|
||||
{
|
||||
get => _topmost;
|
||||
set => SetProperty( ref _topmost, value );
|
||||
}
|
||||
|
||||
public ObservableCollection<ChatUser> Users
|
||||
{
|
||||
get => _users;
|
||||
set => SetProperty( ref _users, value );
|
||||
}
|
||||
|
||||
private static void ToggleOption( object obj )
|
||||
{
|
||||
}
|
||||
|
||||
private void ChangeChannel( object obj )
|
||||
{
|
||||
if ( !( obj is string channel ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_dispatcher.Invoke( () => { Commands.JoinChatChannel( channel ); } );
|
||||
}
|
||||
|
||||
private void OnChannelRemoved( string channel )
|
||||
{
|
||||
_dispatcher.Invoke( () => { Channels.Remove( channel ); } );
|
||||
}
|
||||
|
||||
private void OnChannelCreated( string channel )
|
||||
{
|
||||
_dispatcher.Invoke( () => { Channels.Add( channel ); } );
|
||||
}
|
||||
|
||||
private void OnChatMessage( string username, string channel, string message )
|
||||
{
|
||||
_dispatcher.Invoke( () => Messages.Add( new ChatMessage
|
||||
{
|
||||
//TODO2
|
||||
Username = username,
|
||||
Channel = channel,
|
||||
Text = message/*, Colour = GetUserColour( username )*/
|
||||
} ) );
|
||||
}
|
||||
|
||||
private void OnLeftChatChannel( string channel )
|
||||
{
|
||||
_dispatcher.Invoke( () =>
|
||||
{
|
||||
Users.Clear();
|
||||
CurrentChannel = null;
|
||||
SelectedChannel = null;
|
||||
UpdateTitle( string.Empty );
|
||||
} );
|
||||
}
|
||||
|
||||
private void UpdateTitle( string channel )
|
||||
{
|
||||
if ( string.IsNullOrEmpty( channel ) )
|
||||
{
|
||||
Title = Strings.Chat;
|
||||
return;
|
||||
}
|
||||
|
||||
Title = $"{Strings.Chat} - {channel}";
|
||||
}
|
||||
|
||||
private void OnJoinedChatChannel( string channel )
|
||||
{
|
||||
_dispatcher.Invoke( () =>
|
||||
{
|
||||
CurrentChannel = channel;
|
||||
SelectedChannel = channel;
|
||||
UpdateTitle( channel );
|
||||
} );
|
||||
}
|
||||
|
||||
private void OnClearUsers()
|
||||
{
|
||||
_dispatcher.Invoke( () => Users.Clear() );
|
||||
}
|
||||
|
||||
private void OnUserLeft( string username, string channel )
|
||||
{
|
||||
_dispatcher.Invoke( () => { Users.Remove( Users.FirstOrDefault( u => u.Username == username ) ); } );
|
||||
}
|
||||
|
||||
private void OnUserJoined( string username, string channel )
|
||||
{
|
||||
_dispatcher.Invoke( () =>
|
||||
{
|
||||
//TODO2
|
||||
ChatUser user = new ChatUser { Username = username/*, Colour = GetUserColour( username )*/ };
|
||||
|
||||
Users.AddSorted( user );
|
||||
} );
|
||||
}
|
||||
|
||||
private SolidColorBrush GetUserColour( string username )
|
||||
{
|
||||
try
|
||||
{
|
||||
Match matches = Regex.Match( username, @"<(.*)>\s*(.*)" );
|
||||
|
||||
if ( !matches.Success )
|
||||
{
|
||||
return _defaultBrush;
|
||||
}
|
||||
|
||||
int serial = int.Parse( matches.Groups[1].Value );
|
||||
|
||||
if ( serial == Engine.Player?.Serial || MobileCommands.InFriendList( serial ) )
|
||||
{
|
||||
return _friendBrush;
|
||||
}
|
||||
|
||||
return serial == AliasCommands.GetAlias( "enemy" ) ? _enemyBrush : _defaultBrush;
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
return _defaultBrush;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
#region License
|
||||
|
||||
// Copyright (C) 2020 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; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Data;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels.Debug
|
||||
{
|
||||
public class DebugAssembliesViewModel : BaseViewModel
|
||||
{
|
||||
private ObservableCollection<Assembly> _items = new ObservableCollection<Assembly>();
|
||||
private ICommand _loadCommand;
|
||||
private ICommand _removeCommand;
|
||||
private ICommand _saveCommand;
|
||||
|
||||
public DebugAssembliesViewModel()
|
||||
{
|
||||
if ( AssistantOptions.Assemblies == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( string assemblyName in AssistantOptions.Assemblies )
|
||||
{
|
||||
Assembly assembly = LoadAssembly( assemblyName );
|
||||
|
||||
if ( assembly != null )
|
||||
{
|
||||
Items.Add( assembly );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<Assembly> Items
|
||||
{
|
||||
get => _items;
|
||||
set => SetProperty( ref _items, value );
|
||||
}
|
||||
|
||||
public ICommand LoadCommand => _loadCommand ?? ( _loadCommand = new RelayCommandAsync( Load, o => true ) );
|
||||
|
||||
public ICommand RemoveCommand =>
|
||||
_removeCommand ?? ( _removeCommand = new RelayCommandAsync( Remove, o => true ) );
|
||||
|
||||
public ICommand SaveCommand => _saveCommand ?? ( _saveCommand = new RelayCommandAsync( Save, o => true ) );
|
||||
|
||||
public Assembly SelectedItem { get; set; }
|
||||
|
||||
private async Task Load( object arg )
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog
|
||||
{
|
||||
InitialDirectory = Engine.StartupPath, Filter = "DLL Files|*.dll", CheckFileExists = true
|
||||
};
|
||||
|
||||
bool? result = ofd.ShowDialog();
|
||||
|
||||
if ( result.HasValue && result.Value )
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly assembly = LoadAssembly( ofd.FileName );
|
||||
|
||||
if ( assembly != null )
|
||||
{
|
||||
await _dispatcher.InvokeAsync( () => Items.Add( assembly ) );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
MessageBox.Show( string.Format( Strings.Error_loading_assembly___0_, e.Message ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Assembly LoadAssembly( string fileName )
|
||||
{
|
||||
if ( !File.Exists( fileName ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Assembly.LoadFile( fileName );
|
||||
}
|
||||
|
||||
private async Task Remove( object arg )
|
||||
{
|
||||
if ( !( arg is Assembly assembly ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _dispatcher.InvokeAsync( () => Items.Remove( assembly ) );
|
||||
}
|
||||
|
||||
private async Task Save( object arg )
|
||||
{
|
||||
AssistantOptions.Assemblies = Items.Select( a => a.Location ).ToArray();
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,620 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.Data.Autoloot;
|
||||
using ClassicAssist.Data.Macros.Commands;
|
||||
using ClassicAssist.Misc;
|
||||
using ClassicAssist.Shared.Resources;
|
||||
using ClassicAssist.UI.Models;
|
||||
using ClassicAssist.UI.Views;
|
||||
using ClassicAssist.UO;
|
||||
using ClassicAssist.UO.Data;
|
||||
using ClassicAssist.UO.Network;
|
||||
using ClassicAssist.UO.Network.Packets;
|
||||
using ClassicAssist.UO.Objects;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels
|
||||
{
|
||||
public class EntityCollectionViewerViewModel : BaseViewModel
|
||||
{
|
||||
private ICommand _applyFiltersCommand;
|
||||
private ICommand _cancelActionCommand;
|
||||
private CancellationTokenSource _cancellationToken;
|
||||
private ICommand _changeSortStyleCommand;
|
||||
private ItemCollection _collection;
|
||||
private ICommand _contextContextMenuRequestCommand;
|
||||
private ICommand _contextMoveToBackpackCommand;
|
||||
private ICommand _contextMoveToContainerCommand;
|
||||
private ICommand _contextUseItemCommand;
|
||||
private ObservableCollection<EntityCollectionData> _entities;
|
||||
private ICommand _equipItemCommand;
|
||||
private IEnumerable<EntityCollectionFilter> _filters;
|
||||
private bool _isPerformingAction;
|
||||
private ICommand _itemDoubleClickCommand;
|
||||
private ICommand _refreshCommand;
|
||||
|
||||
private ObservableCollection<EntityCollectionData> _selectedItems =
|
||||
new ObservableCollection<EntityCollectionData>();
|
||||
|
||||
private bool _showProperties;
|
||||
|
||||
private IComparer<Entity> _sorter = new IDThenSerialComparer();
|
||||
private string _statusLabel;
|
||||
private ICommand _togglePropertiesCommand;
|
||||
private bool _topmost;
|
||||
|
||||
public EntityCollectionViewerViewModel()
|
||||
{
|
||||
_collection = new ItemCollection( 0 );
|
||||
|
||||
for ( int i = 0; i < 5; i++ )
|
||||
{
|
||||
_collection.Add( new Item( i + 1 ) { ID = 100 + i } );
|
||||
}
|
||||
|
||||
_collection.Add( new Item( 6 ) { ID = 106, Hue = 2413 } );
|
||||
|
||||
Entities = new ObservableCollection<EntityCollectionData>( _collection.ToEntityCollectionData( _sorter ) );
|
||||
}
|
||||
|
||||
public EntityCollectionViewerViewModel( ItemCollection collection )
|
||||
{
|
||||
_collection = collection;
|
||||
|
||||
Entities = new ObservableCollection<EntityCollectionData>( collection.ToEntityCollectionData( _sorter ) );
|
||||
|
||||
SelectedItems.CollectionChanged += ( sender, args ) =>
|
||||
{
|
||||
if ( !( sender is ObservableCollection<EntityCollectionData> ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateStatusLabel();
|
||||
};
|
||||
|
||||
UpdateStatusLabel();
|
||||
}
|
||||
|
||||
public ICommand ApplyFiltersCommand =>
|
||||
_applyFiltersCommand ?? ( _applyFiltersCommand = new RelayCommand( ApplyFilters, o => true ) );
|
||||
|
||||
public ICommand CancelActionCommand =>
|
||||
_cancelActionCommand ?? ( _cancelActionCommand = new RelayCommandAsync( CancelAction,
|
||||
o => _cancellationToken != null ) );
|
||||
|
||||
public ICommand ChangeSortStyleCommand =>
|
||||
_changeSortStyleCommand ?? ( _changeSortStyleCommand = new RelayCommand( ChangeSortStyle, o => true ) );
|
||||
|
||||
public ICommand ContextContextMenuRequestCommand =>
|
||||
_contextContextMenuRequestCommand ?? ( _contextContextMenuRequestCommand =
|
||||
new RelayCommand( ContextMenuRequest, o => SelectedItems.Count > 0 ) );
|
||||
|
||||
public ICommand ContextMoveToBackpackCommand =>
|
||||
_contextMoveToBackpackCommand ?? ( _contextMoveToBackpackCommand =
|
||||
new RelayCommandAsync( ContextMoveToBackpack, o => SelectedItems != null && !IsPerformingAction ) );
|
||||
|
||||
public ICommand ContextMoveToContainerCommand =>
|
||||
_contextMoveToContainerCommand ?? ( _contextMoveToContainerCommand =
|
||||
new RelayCommandAsync( ContextMoveToContainer, o => SelectedItems != null && !IsPerformingAction ) );
|
||||
|
||||
public ICommand ContextUseItemCommand =>
|
||||
_contextUseItemCommand ?? ( _contextUseItemCommand =
|
||||
new RelayCommandAsync( ContextUseItem, o => SelectedItems != null && !IsPerformingAction ) );
|
||||
|
||||
public ObservableCollection<EntityCollectionData> Entities
|
||||
{
|
||||
get => _entities;
|
||||
set => SetProperty( ref _entities, value );
|
||||
}
|
||||
|
||||
public ICommand EquipItemCommand =>
|
||||
_equipItemCommand ?? ( _equipItemCommand = new RelayCommand( EquipItem, o => SelectedItems != null ) );
|
||||
|
||||
public bool IsPerformingAction
|
||||
{
|
||||
get => _isPerformingAction;
|
||||
set => SetProperty( ref _isPerformingAction, value );
|
||||
}
|
||||
|
||||
public ICommand ItemDoubleClickCommand =>
|
||||
_itemDoubleClickCommand ?? ( _itemDoubleClickCommand = new RelayCommand( ItemDoubleClick, o => true ) );
|
||||
|
||||
public static Lazy<Dictionary<int, int>> MountIDEntries { get; set; } =
|
||||
new Lazy<Dictionary<int, int>>( LoadMountIDEntries );
|
||||
|
||||
public ICommand RefreshCommand =>
|
||||
_refreshCommand ?? ( _refreshCommand = new RelayCommand( Refresh, o => _collection?.Serial != 0 ) );
|
||||
|
||||
public ObservableCollection<EntityCollectionData> SelectedItems
|
||||
{
|
||||
get => _selectedItems;
|
||||
set => SetProperty( ref _selectedItems, value );
|
||||
}
|
||||
|
||||
public bool ShowProperties
|
||||
{
|
||||
get => _showProperties;
|
||||
set => SetProperty( ref _showProperties, value );
|
||||
}
|
||||
|
||||
public static Lazy<int[]> ShrinkEntries { get; set; } = new Lazy<int[]>( LoadShrinkTable );
|
||||
|
||||
public string StatusLabel
|
||||
{
|
||||
get => _statusLabel;
|
||||
set => SetProperty( ref _statusLabel, value );
|
||||
}
|
||||
|
||||
public ICommand TogglePropertiesCommand =>
|
||||
_togglePropertiesCommand ?? ( _togglePropertiesCommand = new RelayCommand( ToggleProperties, o => true ) );
|
||||
|
||||
public bool Topmost
|
||||
{
|
||||
get => _topmost;
|
||||
set => SetProperty( ref _topmost, value );
|
||||
}
|
||||
|
||||
private static Dictionary<int, int> LoadMountIDEntries()
|
||||
{
|
||||
Dictionary<int, int> entries = new Dictionary<int, int>();
|
||||
|
||||
string fileName = Path.Combine( Engine.StartupPath, "Data", "MountID.json" );
|
||||
|
||||
if ( !File.Exists( fileName ) )
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
entries = JsonConvert.DeserializeObject<Dictionary<int, int>>( File.ReadAllText( fileName ) );
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static int[] LoadShrinkTable()
|
||||
{
|
||||
int[] table = new int[ushort.MaxValue];
|
||||
|
||||
using ( StringReader reader = new StringReader( Properties.Resources.Shrink ) )
|
||||
{
|
||||
string line;
|
||||
|
||||
while ( ( line = reader.ReadLine() ) != null )
|
||||
{
|
||||
if ( line.Length == 0 || line.StartsWith( "#" ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] split = line.Split( '\t' );
|
||||
|
||||
if ( split.Length < 2 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int body = Convert.ToInt32( split[0] );
|
||||
int item = Convert.ToInt32( split[1], 16 );
|
||||
|
||||
if ( body >= 0 && body < table.Length )
|
||||
{
|
||||
table[body] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private void EquipItem( object obj )
|
||||
{
|
||||
foreach ( EntityCollectionData item in SelectedItems )
|
||||
{
|
||||
StaticTile td = TileData.GetStaticTile( item.Entity.ID );
|
||||
|
||||
if ( !td.Flags.HasFlag( TileFlags.Wearable ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Layer layer = (Layer) td.Quality;
|
||||
|
||||
if ( layer == Layer.Invalid )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( item.Entity is Item equipItem )
|
||||
{
|
||||
Shared.UO.Commands.EquipItem( equipItem, layer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyFilters( object obj )
|
||||
{
|
||||
if ( !( obj is IEnumerable<EntityCollectionFilter> list ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_filters = list;
|
||||
|
||||
Entities.Clear();
|
||||
|
||||
Entities = new ObservableCollection<EntityCollectionData>( _collection.Filter( _filters )
|
||||
.ToEntityCollectionData( _sorter ) );
|
||||
|
||||
UpdateStatusLabel();
|
||||
}
|
||||
|
||||
private void ChangeSortStyle( object obj )
|
||||
{
|
||||
if ( !( obj is EntityCollectionSortStyle val ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( val )
|
||||
{
|
||||
case EntityCollectionSortStyle.Name:
|
||||
_sorter = new NameThenSerialComparer();
|
||||
|
||||
break;
|
||||
|
||||
case EntityCollectionSortStyle.Serial:
|
||||
_sorter = new SerialComparer();
|
||||
|
||||
break;
|
||||
|
||||
case EntityCollectionSortStyle.Hue:
|
||||
_sorter = new HueThenAmountComparer();
|
||||
|
||||
break;
|
||||
|
||||
case EntityCollectionSortStyle.ID:
|
||||
_sorter = new IDThenSerialComparer();
|
||||
|
||||
break;
|
||||
|
||||
case EntityCollectionSortStyle.Quantity:
|
||||
_sorter = new QuantityThenSerialComparer();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
Entities = new ObservableCollection<EntityCollectionData>( _collection.ToEntityCollectionData( _sorter ) );
|
||||
}
|
||||
|
||||
private void UpdateStatusLabel()
|
||||
{
|
||||
StatusLabel = string.Format( Strings._0__items___1__selected___2__total_amount, Entities.Count,
|
||||
SelectedItems?.Count ?? 0,
|
||||
SelectedItems?.Select( i => i.Entity ).Where( i => i is Item ).Cast<Item>().Sum( i => i.Count ) );
|
||||
}
|
||||
|
||||
private void Refresh( object obj )
|
||||
{
|
||||
ItemCollection collection = new ItemCollection( _collection.Serial );
|
||||
|
||||
Entity entity = Engine.Items.GetItem( _collection.Serial ) ??
|
||||
(Entity) Engine.Mobiles.GetMobile( _collection.Serial );
|
||||
|
||||
if ( entity == null )
|
||||
{
|
||||
Shared.UO.Commands.SystemMessage( Strings.Cannot_find_item___ );
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( entity )
|
||||
{
|
||||
case Item item:
|
||||
if ( item.Container == null )
|
||||
{
|
||||
Shared.UO.Commands.WaitForContainerContents( item.Serial, 1000 );
|
||||
}
|
||||
|
||||
collection = item.Container;
|
||||
break;
|
||||
case Mobile mobile:
|
||||
collection = new ItemCollection( entity.Serial ) { mobile.GetEquippedItems() };
|
||||
break;
|
||||
}
|
||||
|
||||
if ( collection == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_collection = collection;
|
||||
|
||||
Entities = new ObservableCollection<EntityCollectionData>( _collection.ToEntityCollectionData( _sorter ) );
|
||||
}
|
||||
|
||||
private async Task ContextUseItem( object arg )
|
||||
{
|
||||
_cancellationToken = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
IsPerformingAction = true;
|
||||
|
||||
await Task.Run( () =>
|
||||
{
|
||||
int[] items = SelectedItems.Select( i => i.Entity.Serial ).ToArray();
|
||||
|
||||
foreach ( int item in items )
|
||||
{
|
||||
ObjectCommands.UseObject( item );
|
||||
|
||||
if ( _cancellationToken.Token.IsCancellationRequested )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsPerformingAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ContextMoveToContainer( object arg )
|
||||
{
|
||||
_cancellationToken = new CancellationTokenSource();
|
||||
|
||||
int serial = 0;
|
||||
|
||||
if ( arg is int s )
|
||||
{
|
||||
serial = s;
|
||||
}
|
||||
|
||||
if ( serial == 0 )
|
||||
{
|
||||
serial = await Shared.UO.Commands.GetTargeSerialAsync( Strings.Target_container___ );
|
||||
}
|
||||
|
||||
if ( serial == 0 )
|
||||
{
|
||||
Shared.UO.Commands.SystemMessage( Strings.Invalid_container___ );
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsPerformingAction = true;
|
||||
|
||||
int[] items = SelectedItems.Select( i => i.Entity.Serial ).ToArray();
|
||||
|
||||
foreach ( int item in items )
|
||||
{
|
||||
await ActionPacketQueue.EnqueueDragDrop( item, -1, serial );
|
||||
|
||||
if ( _cancellationToken.Token.IsCancellationRequested )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsPerformingAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ContextMoveToBackpack( object arg )
|
||||
{
|
||||
await ContextMoveToContainer( Engine.Player.Backpack.Serial );
|
||||
}
|
||||
|
||||
private async Task CancelAction( object arg )
|
||||
{
|
||||
_cancellationToken?.Cancel();
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void ToggleProperties( object obj )
|
||||
{
|
||||
if ( !( obj is bool showProperties ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShowProperties = showProperties;
|
||||
}
|
||||
|
||||
private static void ItemDoubleClick( object obj )
|
||||
{
|
||||
if ( !( obj is EntityCollectionData ecd ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectInspectorWindow window =
|
||||
new ObjectInspectorWindow { DataContext = new ObjectInspectorViewModel( ecd.Entity ) };
|
||||
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private void ContextMenuRequest( object obj )
|
||||
{
|
||||
int[] items = SelectedItems.Select( i => i.Entity.Serial ).ToArray();
|
||||
|
||||
foreach ( int serial in items )
|
||||
{
|
||||
Engine.SendPacketToServer( new ContextMenuRequest( serial ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EntityCollectionData
|
||||
{
|
||||
public BitmapSource Bitmap
|
||||
{
|
||||
get
|
||||
{
|
||||
BitmapSource result = Art.GetStatic( Entity.ID, Entity.Hue ).ToBitmapSource();
|
||||
|
||||
if ( !( Entity is Item item ) || item.Layer != Layer.Mount )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if ( !( EntityCollectionViewerViewModel.MountIDEntries.Value?.ContainsKey( Entity.ID ) ?? false ) )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
int id = (int) EntityCollectionViewerViewModel.MountIDEntries.Value?[Entity.ID];
|
||||
|
||||
result = Art.GetStatic( id, Entity.Hue ).ToBitmapSource();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public Entity Entity { get; set; }
|
||||
public string FullName => GetProperties( Entity );
|
||||
public string Name => GetName( Entity );
|
||||
|
||||
private static string GetProperties( Entity entity )
|
||||
{
|
||||
return entity.Properties == null
|
||||
? GetName( entity )
|
||||
: entity.Properties.Aggregate( "",
|
||||
( current, entityProperty ) => current + entityProperty.Text + "\r\n" ).TrimTrailingNewLine();
|
||||
}
|
||||
|
||||
private static string GetName( Entity entity )
|
||||
{
|
||||
if ( !( entity is Item item ) || item.Layer != Layer.Mount )
|
||||
{
|
||||
return entity.Name;
|
||||
}
|
||||
|
||||
if ( !( EntityCollectionViewerViewModel.MountIDEntries.Value?.ContainsKey( entity.ID ) ?? false ) )
|
||||
{
|
||||
return entity.Name;
|
||||
}
|
||||
|
||||
int id = (int) EntityCollectionViewerViewModel.MountIDEntries.Value?[entity.ID];
|
||||
|
||||
if ( id == 0 )
|
||||
{
|
||||
return entity.Name;
|
||||
}
|
||||
|
||||
StaticTile tileData = TileData.GetStaticTile( id );
|
||||
|
||||
return !string.IsNullOrEmpty( tileData.Name ) ? tileData.Name : entity.Name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExtensionMethods
|
||||
{
|
||||
public static ItemCollection Filter( this ItemCollection collection,
|
||||
IEnumerable<EntityCollectionFilter> filterList )
|
||||
{
|
||||
ItemCollection newCollection = new ItemCollection( collection.Serial );
|
||||
|
||||
IEnumerable<Predicate<Item>> predicates = FiltersToPredicates( filterList ).ToList();
|
||||
|
||||
if ( !predicates.Any() )
|
||||
{
|
||||
return collection;
|
||||
}
|
||||
|
||||
foreach ( Item item in collection.GetItems() )
|
||||
{
|
||||
if ( predicates.All( p => p( item ) ) )
|
||||
{
|
||||
newCollection.Add( item );
|
||||
}
|
||||
}
|
||||
|
||||
return newCollection;
|
||||
}
|
||||
|
||||
private static IEnumerable<Predicate<Item>> FiltersToPredicates(
|
||||
IEnumerable<EntityCollectionFilter> filterList )
|
||||
{
|
||||
List<Predicate<Item>> predicates = new List<Predicate<Item>>();
|
||||
|
||||
foreach ( EntityCollectionFilter filter in filterList )
|
||||
{
|
||||
PropertyEntry constraint = filter.Constraint;
|
||||
|
||||
switch ( constraint.ConstraintType )
|
||||
{
|
||||
case PropertyType.Properties:
|
||||
{
|
||||
predicates.Add( i => i.Properties != null && constraint.Clilocs.Any( cliloc =>
|
||||
i.Properties.Any( p => AutolootHelpers.MatchProperty( p, cliloc,
|
||||
constraint, filter.Operator, filter.Value ) ) ) );
|
||||
|
||||
break;
|
||||
}
|
||||
case PropertyType.Object:
|
||||
{
|
||||
predicates.Add( i =>
|
||||
AutolootHelpers.ItemHasObjectProperty( i, constraint.Name ) && AutolootHelpers.Operation(
|
||||
filter.Operator, AutolootHelpers.GetItemObjectPropertyValue<int>( i, constraint.Name ),
|
||||
filter.Value ) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
public static string TrimTrailingNewLine( this string s )
|
||||
{
|
||||
return s.TrimEnd( '\r', '\n' );
|
||||
}
|
||||
|
||||
public static List<EntityCollectionData> ToEntityCollectionData( this ItemCollection itemCollection,
|
||||
IComparer<Entity> comparer )
|
||||
{
|
||||
if ( itemCollection == null )
|
||||
{
|
||||
return new List<EntityCollectionData>();
|
||||
}
|
||||
|
||||
Item[] items = itemCollection.GetItems();
|
||||
|
||||
IEnumerable<Item> noNames = items.Where( i => string.IsNullOrEmpty( i.Name ) );
|
||||
|
||||
foreach ( Item item in noNames )
|
||||
{
|
||||
item.Name = $"0x{item.Serial:x8}";
|
||||
}
|
||||
|
||||
return items.OrderBy( i => i, comparer ).Select( item => new EntityCollectionData { Entity = item } )
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Data.Filters;
|
||||
using ClassicAssist.UO.Data;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels.Filters
|
||||
{
|
||||
public class ClilocFilterConfigureViewModel : BaseViewModel
|
||||
{
|
||||
private ICommand _addItemCommand;
|
||||
private ObservableCollection<ClilocEntry> _allClilocs = new ObservableCollection<ClilocEntry>();
|
||||
private ObservableCollection<ClilocEntry> _filteredClilocs = new ObservableCollection<ClilocEntry>();
|
||||
private string _filterText;
|
||||
private ObservableCollection<FilterClilocEntry> _items = new ObservableCollection<FilterClilocEntry>();
|
||||
private ICommand _removeItemCommand;
|
||||
private ICommand _saveItemsCommand;
|
||||
private ClilocEntry _selectedClilocEntry;
|
||||
private FilterClilocEntry _selectedItem;
|
||||
|
||||
public ClilocFilterConfigureViewModel()
|
||||
{
|
||||
foreach ( KeyValuePair<int, string> kvp in Cliloc.GetItems() )
|
||||
{
|
||||
AllClilocs.Add( new ClilocEntry { Key = kvp.Key, Value = kvp.Value } );
|
||||
}
|
||||
|
||||
foreach ( KeyValuePair<int, string> filterFilter in ClilocFilter.Filters )
|
||||
{
|
||||
Items.Add( new FilterClilocEntry { Cliloc = filterFilter.Key, Replacement = filterFilter.Value } );
|
||||
}
|
||||
|
||||
UpdateEntries( _filterText );
|
||||
}
|
||||
|
||||
public ICommand AddItemCommand => _addItemCommand ?? ( _addItemCommand = new RelayCommand( AddItem ) );
|
||||
|
||||
public ObservableCollection<ClilocEntry> AllClilocs
|
||||
{
|
||||
get => _allClilocs;
|
||||
set => SetProperty( ref _allClilocs, value );
|
||||
}
|
||||
|
||||
public ObservableCollection<ClilocEntry> FilteredClilocs
|
||||
{
|
||||
get => _filteredClilocs;
|
||||
set => SetProperty( ref _filteredClilocs, value );
|
||||
}
|
||||
|
||||
public string FilterText
|
||||
{
|
||||
get => _filterText;
|
||||
set
|
||||
{
|
||||
SetProperty( ref _filterText, value );
|
||||
UpdateEntries( _filterText );
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<FilterClilocEntry> Items
|
||||
{
|
||||
get => _items;
|
||||
set => SetProperty( ref _items, value );
|
||||
}
|
||||
|
||||
public ICommand RemoveItemCommand =>
|
||||
_removeItemCommand ?? ( _removeItemCommand = new RelayCommand( RemoveItem, o => SelectedItem != null ) );
|
||||
|
||||
public ICommand SaveItemsCommand =>
|
||||
_saveItemsCommand ?? ( _saveItemsCommand = new RelayCommand( SaveItems, o => true ) );
|
||||
|
||||
public ClilocEntry SelectedClilocEntry
|
||||
{
|
||||
get => _selectedClilocEntry;
|
||||
set => SetProperty( ref _selectedClilocEntry, value );
|
||||
}
|
||||
|
||||
public FilterClilocEntry SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => SetProperty( ref _selectedItem, value );
|
||||
}
|
||||
|
||||
private void RemoveItem( object obj )
|
||||
{
|
||||
if ( !( obj is FilterClilocEntry entry ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Items.Remove( entry );
|
||||
}
|
||||
|
||||
private void SaveItems( object obj )
|
||||
{
|
||||
ClilocFilter.Filters.Clear();
|
||||
|
||||
foreach ( FilterClilocEntry entry in Items )
|
||||
{
|
||||
if ( !ClilocFilter.Filters.ContainsKey( entry.Cliloc ) )
|
||||
{
|
||||
ClilocFilter.Filters.Add( entry.Cliloc, entry.Replacement );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEntries( string filterText )
|
||||
{
|
||||
IEnumerable<ClilocEntry> matches = AllClilocs.Where( m =>
|
||||
string.IsNullOrEmpty( filterText ) || m.Value.ToLower().Contains( filterText.ToLower() ) );
|
||||
FilteredClilocs.Clear();
|
||||
|
||||
foreach ( ClilocEntry clilocEntry in matches )
|
||||
{
|
||||
FilteredClilocs.Add( clilocEntry );
|
||||
}
|
||||
}
|
||||
|
||||
private void AddItem( object obj )
|
||||
{
|
||||
if ( !( obj is ClilocEntry clilocEntry ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Items.Any( i => i.Cliloc == clilocEntry.Key ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Items.Add( new FilterClilocEntry { Cliloc = clilocEntry.Key, Replacement = clilocEntry.Value } );
|
||||
}
|
||||
|
||||
public class ClilocEntry
|
||||
{
|
||||
public int Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
public class FilterClilocEntry
|
||||
{
|
||||
public int Cliloc { get; set; }
|
||||
public string Original => UO.Data.Cliloc.GetProperty( Cliloc );
|
||||
public string Replacement { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Threading;
|
||||
using AnimatedGif;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.UI.Views;
|
||||
using Point = System.Drawing.Point;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels
|
||||
{
|
||||
public class GIFRecorderViewModel : BaseViewModel
|
||||
{
|
||||
private readonly GIFRecorderWindow _window;
|
||||
private bool _isRecording;
|
||||
private MemoryStream _lastStream;
|
||||
private ICommand _recordCommand;
|
||||
private ICommand _saveCommand;
|
||||
private CancellationTokenSource _token;
|
||||
|
||||
public GIFRecorderViewModel( GIFRecorderWindow window ) : this()
|
||||
{
|
||||
_window = window;
|
||||
}
|
||||
|
||||
public GIFRecorderViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsRecording
|
||||
{
|
||||
get => _isRecording;
|
||||
set => SetProperty( ref _isRecording, value );
|
||||
}
|
||||
|
||||
public MemoryStream LastStream
|
||||
{
|
||||
get => _lastStream;
|
||||
set => SetProperty( ref _lastStream, value );
|
||||
}
|
||||
|
||||
public ICommand RecordCommand => _recordCommand ?? ( _recordCommand = new RelayCommand( Record, o => true ) );
|
||||
|
||||
public ICommand SaveCommand => _saveCommand ?? ( _saveCommand = new RelayCommand( Save, o => !IsRecording ) );
|
||||
|
||||
private void Save( object obj )
|
||||
{
|
||||
if ( LastStream == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string directory = Path.Combine( Engine.StartupPath ?? Environment.CurrentDirectory, "Screenshots" );
|
||||
|
||||
if ( !Directory.Exists( directory ) )
|
||||
{
|
||||
Directory.CreateDirectory( directory );
|
||||
}
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
string fileName =
|
||||
$"ClassicAssist-{now.Year}-{now.Month}-{now.Day}-{now.Hour}-{now.Minute}-{now.Second}.gif";
|
||||
|
||||
string fullPath = Path.Combine( directory, fileName );
|
||||
|
||||
using ( FileStream fs = new FileStream( fullPath, FileMode.Create ) )
|
||||
{
|
||||
LastStream.WriteTo( fs );
|
||||
}
|
||||
|
||||
string args = $"/e, /select, \"{fullPath}\"";
|
||||
|
||||
ProcessStartInfo info = new ProcessStartInfo { FileName = "explorer", Arguments = args };
|
||||
Process.Start( info );
|
||||
}
|
||||
|
||||
private void Record( object obj )
|
||||
{
|
||||
if ( IsRecording )
|
||||
{
|
||||
_token.Cancel();
|
||||
}
|
||||
else
|
||||
{
|
||||
IsRecording = true;
|
||||
_token = new CancellationTokenSource();
|
||||
|
||||
Window w = Window.GetWindow( _window );
|
||||
WindowInteropHelper wih = new WindowInteropHelper( w ?? throw new InvalidOperationException() );
|
||||
|
||||
Task.Run( async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
TimeSpan frameInterval = TimeSpan.FromSeconds( 1.0 / 5 );
|
||||
MemoryStream ms = new MemoryStream();
|
||||
|
||||
using ( AnimatedGifCreator gif = new AnimatedGifCreator( ms, frameInterval.Milliseconds ) )
|
||||
{
|
||||
Rectangle rect = new Rectangle();
|
||||
_dispatcher.Invoke( () => GetWindowRect( wih.Handle, ref rect ) );
|
||||
|
||||
Bitmap bmp = new Bitmap( rect.Width - rect.Left - 10, rect.Height - rect.Top - 70 );
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
while ( true )
|
||||
{
|
||||
_dispatcher.Invoke( () => GetWindowRect( wih.Handle, ref rect ) );
|
||||
|
||||
using ( Graphics g = Graphics.FromImage( bmp ) )
|
||||
{
|
||||
g.CopyFromScreen( new Point( rect.Left + 5, rect.Top + 50 ), Point.Empty,
|
||||
new Size( bmp.Width, bmp.Height ) );
|
||||
}
|
||||
|
||||
await gif.AddFrameAsync( bmp, -1, GifQuality.Bit8 );
|
||||
|
||||
sw.Stop();
|
||||
|
||||
int wait = frameInterval.Milliseconds - (int) sw.ElapsedMilliseconds;
|
||||
|
||||
if ( wait > 0 )
|
||||
{
|
||||
await Task.Delay( wait );
|
||||
}
|
||||
|
||||
if ( _token.IsCancellationRequested )
|
||||
{
|
||||
return ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dispatcher.Invoke( () => IsRecording = false );
|
||||
}
|
||||
} ).ContinueWith( t =>
|
||||
{
|
||||
if ( !( t.Result is MemoryStream ms ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( LastStream != null )
|
||||
{
|
||||
LastStream.Dispose();
|
||||
LastStream = null;
|
||||
}
|
||||
|
||||
LastStream = ms;
|
||||
CommandManager.InvalidateRequerySuggested();
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport( "user32.dll" )]
|
||||
private static extern IntPtr GetWindowRect( IntPtr hWnd, ref Rectangle rect );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Data.Macros;
|
||||
|
||||
namespace ClassicAssist.UI.ViewModels.Macros
|
||||
{
|
||||
public class CommandsData
|
||||
{
|
||||
public CommandsDisplayAttribute Attribute { get; set; }
|
||||
public string Category { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Tooltip { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
public class MacrosCommandViewModel : BaseViewModel
|
||||
{
|
||||
private readonly MacrosTabViewModel _macrosViewModel;
|
||||
private ICommand _insertCommand;
|
||||
private ObservableCollection<CommandsData> _items = new ObservableCollection<CommandsData>();
|
||||
private CommandsData _selectedItem;
|
||||
|
||||
public MacrosCommandViewModel( MacrosTabViewModel macros ) : this()
|
||||
{
|
||||
_macrosViewModel = macros;
|
||||
}
|
||||
|
||||
public MacrosCommandViewModel()
|
||||
{
|
||||
IEnumerable<Type> types = Assembly.GetExecutingAssembly().GetTypes().Where( t =>
|
||||
t.Namespace != null && t.Namespace.StartsWith( "ClassicAssist.Data.Macros.Commands" ) );
|
||||
|
||||
foreach ( Type type in types )
|
||||
{
|
||||
MemberInfo[] members = type.GetMembers( BindingFlags.Public | BindingFlags.Static );
|
||||
|
||||
foreach ( MemberInfo memberInfo in members )
|
||||
{
|
||||
CommandsDisplayAttribute attr = memberInfo.GetCustomAttribute<CommandsDisplayAttribute>();
|
||||
|
||||
if ( attr == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CommandsData entry = new CommandsData
|
||||
{
|
||||
Category = attr.Category,
|
||||
IsExpanded = false,
|
||||
Name = memberInfo.ToString(),
|
||||
Tooltip = attr.Description,
|
||||
Attribute = attr
|
||||
};
|
||||
|
||||
Items.Add( entry );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand InsertCommand =>
|
||||
_insertCommand ?? ( _insertCommand = new RelayCommand( Insert, o => SelectedItem != null ) );
|
||||
|
||||
public ObservableCollection<CommandsData> Items
|
||||
{
|
||||
get => _items;
|
||||
set => SetProperty( ref _items, value );
|
||||
}
|
||||
|
||||
public CommandsData SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => SetProperty( ref _selectedItem, value );
|
||||
}
|
||||
|
||||
private void Insert( object obj )
|
||||
{
|
||||
if ( !( obj is CommandsData cd ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( cd.Attribute != null )
|
||||
{
|
||||
//TODO UI
|
||||
//_macrosViewModel?.Document.Insert( _macrosViewModel.CaretPosition, cd.Attribute.InsertText );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Views.AboutControl"
|
||||
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:ClassicAssist.UI.Views"
|
||||
xmlns:controls="clr-namespace:ClassicAssist.UI.Controls"
|
||||
xmlns:valueConverters1="clr-namespace:ClassicAssist.UI.Misc.ValueConverters"
|
||||
xmlns:r="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared"
|
||||
xmlns:viewModels="clr-namespace:ClassicAssist.UI.ViewModels;assembly=ClassicAssist.Shared"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="350" d:DesignWidth="600"
|
||||
d:DataContext="{d:DesignInstance {x:Type viewModels:AboutControlViewModel}, IsDesignTimeCreatable=True}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Resources/Icons.xaml" />
|
||||
<ResourceDictionary Source="../../Resources/ResourceDictionary.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<UserControl.DataContext>
|
||||
<viewModels:AboutControlViewModel />
|
||||
</UserControl.DataContext>
|
||||
<d:DesignerProperties.DesignStyle>
|
||||
<Style TargetType="UserControl">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
|
||||
</Style>
|
||||
</d:DesignerProperties.DesignStyle>
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
<valueConverters1:IntToHexStringValueConverter x:Key="IntToHexStringValueConverter" />
|
||||
<valueConverters1:DateTimeToTimeSpanValueConverter x:Key="DateTimeToTimeSpanValueConverter" />
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource {x:Type GroupBox}}">
|
||||
<Setter Property="Margin" Value="5" />
|
||||
<Setter Property="Padding" Value="5" />
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<GroupBox Header="{x:Static r:Strings.Software}" Grid.Row="0" Grid.Column="0">
|
||||
<StackPanel>
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<Label Content="{x:Static r:Strings.Product_}" />
|
||||
<Label Content="{x:Static r:Strings.Version_}" />
|
||||
<Label Content="{x:Static r:Strings.Build_Date_}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="Margin" Value="10,0,0,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Label Content="{Binding Product}" />
|
||||
<Label Content="{Binding Version}" />
|
||||
<Label Content="{Binding BuildDate}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
<Grid Margin="5">
|
||||
<TextBlock Text="{x:Static r:Strings.Made_For_Malo}" HorizontalAlignment="Center" FontWeight="Bold"
|
||||
MouseEnter="TextBlock_MouseEnter" MouseLeave="TextBlock_MouseLeave"
|
||||
TextDecorations="Underline" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Content="{x:Static r:Strings.Project_Homepage}" Command="{Binding LaunchHomepageCommand}"
|
||||
Grid.Column="0" Margin="0,0,5,0" />
|
||||
<Button Content="{x:Static r:Strings.Check_For_Updates}" Command="{Binding CheckForUpdatesCommand}"
|
||||
Grid.Column="1" Margin="5,0,0,0" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="{x:Static r:Strings.World_Status}" Grid.Row="0" Grid.Column="1">
|
||||
<StackPanel>
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Margin" Value="5" />
|
||||
<Setter Property="Width" Value="150" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<Label Content="{x:Static r:Strings.Connected_}" />
|
||||
<Label Content="{x:Static r:Strings.Items_}" />
|
||||
<Label Content="{x:Static r:Strings.Mobiles_}" />
|
||||
<Label Content="{x:Static r:Strings.Latency_}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="Margin" Value="10,0,0,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Label
|
||||
Content="{Binding ConnectedTime, Converter={StaticResource DateTimeToTimeSpanValueConverter}}"
|
||||
Visibility="{Binding Connected, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<Label Content="{Binding ItemCount}" />
|
||||
<Label Content="{Binding MobileCount}" />
|
||||
<Label Content="{Binding Latency}" ContentStringFormat="{}{0}ms" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
<Button Content="{x:Static r:Strings.Show_World_Items}" IsEnabled="{Binding Connected}"
|
||||
Command="{Binding ShowItemsCommand}" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="{x:Static r:Strings.Misc}" Grid.Row="1" Grid.Column="0">
|
||||
<StackPanel Margin="10">
|
||||
<Button Width="50" Background="Transparent" BorderThickness="0" Command="{Binding OpenPayPalCommand}">
|
||||
<Image Source="{StaticResource PayPalIcon}" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Text="{x:Static r:Strings.Donating_helps_support_continued_development__your_support_is_appreciated_}"
|
||||
TextWrapping="Wrap" TextAlignment="Center" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="{x:Static r:Strings.Player}" Grid.Row="1" Grid.Column="1">
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<Label Content="{x:Static r:Strings.Shard_}" />
|
||||
<Label Content="{x:Static r:Strings.Features_}" />
|
||||
<Label Content="{x:Static r:Strings.Name_}" />
|
||||
<Label Content="{x:Static r:Strings.Serial_}" />
|
||||
<Label Content="{x:Static r:Strings.Last_Target_}" />
|
||||
<Label Content="{x:Static r:Strings.Status_}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="Margin" Value="10,0,0,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Label Content="{Binding ShardName}" />
|
||||
<Label Content="{Binding ShardFeatures}" />
|
||||
<Label Content="{Binding PlayerName}" />
|
||||
<Label Content="{Binding PlayerSerial, Converter={StaticResource IntToHexStringValueConverter}}" />
|
||||
<Label
|
||||
Content="{Binding LastTargetSerial, Converter={StaticResource IntToHexStringValueConverter}}" />
|
||||
<Label Content="{Binding PlayerStatus}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Media;
|
||||
using System.Timers;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Shared;
|
||||
|
||||
namespace ClassicAssist.UI.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AboutControl.xaml
|
||||
/// </summary>
|
||||
public partial class AboutControl : UserControl
|
||||
{
|
||||
private Timer _timer;
|
||||
|
||||
public AboutControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void TextBlock_MouseEnter( object sender, MouseEventArgs e )
|
||||
{
|
||||
if ( !( sender is TextBlock textBlock ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_timer = new Timer( 1000 );
|
||||
_timer.Elapsed += ( o, args ) =>
|
||||
{
|
||||
_timer.Stop();
|
||||
|
||||
if ( !textBlock.IsMouseOver )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using ( SoundPlayer sound = new SoundPlayer( Engine.GetResourceStream( "kiss.wav" ) ) )
|
||||
{
|
||||
sound.Play();
|
||||
}
|
||||
};
|
||||
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
private void TextBlock_MouseLeave( object sender, MouseEventArgs e )
|
||||
{
|
||||
_timer?.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
<Window
|
||||
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:resources="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared"
|
||||
xmlns:viewModels="clr-namespace:ClassicAssist.UI.ViewModels"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:misc="clr-namespace:ClassicAssist.UI.Misc"
|
||||
xmlns:misc1="clr-namespace:ClassicAssist.Misc"
|
||||
xmlns:valueConverters="clr-namespace:ClassicAssist.UI.Misc.ValueConverters"
|
||||
x:Class="ClassicAssist.UI.Views.ActiveObjectsWindow"
|
||||
mc:Ignorable="d"
|
||||
Title="{x:Static resources:Strings.Active_Objects}" Height="350" Width="400">
|
||||
<Window.Resources>
|
||||
<valueConverters:IntToHexStringValueConverter x:Key="IntToHexStringValueConverter" />
|
||||
<misc1:BindingProxy x:Key="Proxy" Data="{Binding}" />
|
||||
</Window.Resources>
|
||||
<Window.DataContext>
|
||||
<viewModels:ActiveObjectsViewModel />
|
||||
</Window.DataContext>
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TabControl>
|
||||
<TabItem Header="{x:Static resources:Strings.Aliases}">
|
||||
<TabControl>
|
||||
<TabItem Header="{x:Static resources:Strings.Global}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListView ItemsSource="{Binding Aliases}" SelectedItem="{Binding SelectedAlias}">
|
||||
<ListView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{x:Static resources:Strings.Remove}"
|
||||
Command="{Binding Data.RemoveAliasCommand, Source={StaticResource Proxy}}"
|
||||
CommandParameter="{Binding SelectedAlias}" />
|
||||
<MenuItem Header="{x:Static resources:Strings.Set}" Command="{Binding Data.SetAliasCommand, Source={StaticResource Proxy}}"
|
||||
CommandParameter="{Binding SelectedAlias}" />
|
||||
</ContextMenu>
|
||||
</ListView.ContextMenu>
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Name}" Width="170"
|
||||
DisplayMemberBinding="{Binding Name}" />
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Serial}" Width="170"
|
||||
DisplayMemberBinding="{Binding Serial, Converter={StaticResource IntToHexStringValueConverter}}" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0, 10,0,0">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Height" Value="25" />
|
||||
<Setter Property="Padding" Value="10,0,10,0" />
|
||||
<Setter Property="Margin" Value="0,0,10,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Button Content="{x:Static resources:Strings.Close}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:CloseOnClickBehaviour />
|
||||
</i:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button Content="{x:Static resources:Strings.Refresh}"
|
||||
Command="{Binding RefreshAliasesCommand}" />
|
||||
<Button Content="{x:Static resources:Strings.Clear_All_Objects}"
|
||||
Command="{Binding ClearAllAliasesCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="{x:Static resources:Strings.Instance}">
|
||||
<TabItem.Resources>
|
||||
<CollectionViewSource x:Key='src' Source="{Binding InstanceAliases}">
|
||||
<CollectionViewSource.GroupDescriptions>
|
||||
<PropertyGroupDescription PropertyName="Macro" />
|
||||
</CollectionViewSource.GroupDescriptions>
|
||||
</CollectionViewSource>
|
||||
</TabItem.Resources>
|
||||
<ListView ItemsSource="{Binding Source={StaticResource src}}"
|
||||
SelectedItem="{Binding SelectedInstanceAlias}" Margin="5">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Name}" Width="170"
|
||||
DisplayMemberBinding="{Binding Name}" />
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Serial}" Width="150"
|
||||
DisplayMemberBinding="{Binding Serial, Converter={StaticResource IntToHexStringValueConverter}}" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
<ListView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{x:Static resources:Strings.Remove}"
|
||||
Command="{Binding Data.RemoveInstanceAliasCommand, Source={StaticResource Proxy}}"
|
||||
CommandParameter="{Binding SelectedInstanceAlias}" />
|
||||
</ContextMenu>
|
||||
</ListView.ContextMenu>
|
||||
<ListView.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.ContainerStyle>
|
||||
<Style TargetType="{x:Type GroupItem}">
|
||||
<Setter Property="Margin" Value="0,0,0,5" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type GroupItem}">
|
||||
<Expander IsExpanded="{Binding Items/IsExpanded}"
|
||||
BorderThickness="0,0,0,0">
|
||||
<Expander.Header>
|
||||
<DockPanel>
|
||||
<TextBlock FontSize="12" Text="{Binding Path=Name}"
|
||||
Margin="5,0,0,0" Width="100" />
|
||||
</DockPanel>
|
||||
</Expander.Header>
|
||||
<Expander.Content>
|
||||
<ItemsPresenter />
|
||||
</Expander.Content>
|
||||
</Expander>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</GroupStyle.ContainerStyle>
|
||||
</GroupStyle>
|
||||
</ListView.GroupStyle>
|
||||
</ListView>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</TabItem>
|
||||
<TabItem Header="{x:Static resources:Strings.Lists}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListView ItemsSource="{Binding Lists}" SelectedItem="{Binding SelectedList}">
|
||||
<ListView.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{x:Static resources:Strings.Remove}"
|
||||
Command="{Binding Data.RemoveListCommand, Source={StaticResource Proxy}}"
|
||||
CommandParameter="{Binding Data.SelectedList, Source={StaticResource Proxy}}" />
|
||||
</ContextMenu>
|
||||
</ListView.ContextMenu>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Expander IsExpanded="False" Header="{Binding Name}">
|
||||
<ItemsControl ItemsSource="{Binding Serials}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Mode=OneWay}" Margin="25,0,0,0" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Expander>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0, 10,0,0">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Height" Value="25" />
|
||||
<Setter Property="Padding" Value="10,0,10,0" />
|
||||
<Setter Property="Margin" Value="0,0,10,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Button Content="{x:Static resources:Strings.Close}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:CloseOnClickBehaviour />
|
||||
</i:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button Content="{x:Static resources:Strings.Refresh}" Command="{Binding RefreshListsCommand}" />
|
||||
<Button Content="{x:Static resources:Strings.Clear_All_Objects}"
|
||||
Command="{Binding ClearAllListsCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="{x:Static resources:Strings.Timers}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListView ItemsSource="{Binding Timers}" SelectedItem="{Binding SelectedTimer}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Name}" Width="170"
|
||||
DisplayMemberBinding="{Binding Name}" />
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Value}" Width="170"
|
||||
DisplayMemberBinding="{Binding Value, Converter={StaticResource IntToHexStringValueConverter}}" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0, 10,0,0">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Height" Value="25" />
|
||||
<Setter Property="Padding" Value="10,0,10,0" />
|
||||
<Setter Property="Margin" Value="0,0,10,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Button Content="{x:Static resources:Strings.Close}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:CloseOnClickBehaviour />
|
||||
</i:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button Content="{x:Static resources:Strings.Refresh}"
|
||||
Command="{Binding RefreshTimersCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="{x:Static resources:Strings.Ignore_List}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox x:Name="listBox" ItemsSource="{Binding IgnoreEntries}"
|
||||
SelectedItem="{Binding SelectedIgnoreEntry}">
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="{x:Static resources:Strings.Remove}"
|
||||
Command="{Binding Data.RemoveIgnoreEntryCommand, Source={StaticResource Proxy}}"
|
||||
CommandParameter="{Binding SelectedIgnoreEntry}" />
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding StringFormat={}0x{0:x}}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0, 10,0,0">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Height" Value="25" />
|
||||
<Setter Property="Padding" Value="10,0,10,0" />
|
||||
<Setter Property="Margin" Value="0,0,10,0" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<Button Content="{x:Static resources:Strings.Close}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:CloseOnClickBehaviour />
|
||||
</i:Interaction.Behaviors>
|
||||
</Button>
|
||||
<Button Content="{x:Static resources:Strings.Refresh}"
|
||||
Command="{Binding RefreshIgnoreListCommand}" />
|
||||
<Button Content="{x:Static resources:Strings.Clear_All}"
|
||||
Command="{Binding ClearIgnoreListCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ClassicAssist.UI.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ActiveObjectsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ActiveObjectsWindow : Window
|
||||
{
|
||||
public ActiveObjectsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<UserControl
|
||||
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:ClassicAssist.UI.Views.Agents"
|
||||
xmlns:resources="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared"
|
||||
xmlns:misc="clr-namespace:ClassicAssist.UI.Misc"
|
||||
xmlns:controls="clr-namespace:ClassicAssist.UI.Controls"
|
||||
xmlns:autoloot="clr-namespace:ClassicAssist.Data.Autoloot;assembly=ClassicAssist.Shared"
|
||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:ValueConverters="clr-namespace:ClassicAssist.UI.Misc.ValueConverters"
|
||||
xmlns:misc1="clr-namespace:ClassicAssist.Misc"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:agents="clr-namespace:ClassicAssist.Shared.UI.ViewModels.Agents;assembly=ClassicAssist.Shared"
|
||||
x:Class="ClassicAssist.UI.Views.Agents.AutolootTabControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="250" d:DesignWidth="600" x:Name="userControl">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../../Resources/ResourceDictionary.xaml" />
|
||||
<ResourceDictionary Source="../../../Resources/Icons.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<ValueConverters:CellWidthValueConverter x:Key="CellWidthValueConverter" />
|
||||
<misc1:BindingProxy x:Key="Proxy" Data="{Binding}" />
|
||||
<SolidColorBrush x:Key="ListBorder" Color="#828790" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<UserControl.DataContext>
|
||||
<agents:AutolootViewModel />
|
||||
</UserControl.DataContext>
|
||||
<Grid>
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:ClipboardBehaviour CopyCommand="{Binding ClipboardCopyCommand}"
|
||||
PasteCommand="{Binding ClipboardPasteCommand}"
|
||||
CommandParameter="{Binding SelectedProperties}" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Margin="10" Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<CheckBox Content="{x:Static resources:Strings.Enabled}" IsChecked="{Binding Enabled}" />
|
||||
<CheckBox Content="{x:Static resources:Strings.Disable_inside_guardzone}"
|
||||
IsChecked="{Binding DisableInGuardzone}" />
|
||||
</StackPanel>
|
||||
<ListBox x:Name="listView" Grid.Row="1" Margin="0,10,0,10" ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem}" HorizontalContentAlignment="Stretch">
|
||||
<ListBox.Resources>
|
||||
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Enabled}" Value="False">
|
||||
<Setter Property="TextDecorations" Value="Strikethrough"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ListBox.Resources>
|
||||
<ListBox.InputBindings>
|
||||
<KeyBinding Key="Delete"
|
||||
Command="{Binding RemoveCommand}" CommandParameter="{Binding SelectedItem}" />
|
||||
</ListBox.InputBindings>
|
||||
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:ItemsControlSelectNewEntryBehaviour SelectedItem="{Binding SelectedItem}"
|
||||
Type="{x:Type autoloot:AutolootEntry}" />
|
||||
</i:Interaction.Behaviors>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:EditTextBlock Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
|
||||
Label="{Binding}" MinWidth="160" ShowIcon="True" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<StackPanel Grid.Row="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Content="{x:Static resources:Strings.Remove}" Grid.Column="0" Margin="0,0,5,0"
|
||||
Command="{Binding RemoveCommand}"
|
||||
CommandParameter="{Binding SelectedItem, ElementName=listView}" />
|
||||
<Button Content="{x:Static resources:Strings.Insert}" Grid.Column="1" Margin="5,0,0,0"
|
||||
Command="{Binding InsertCommand}">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu IsOpen="False">
|
||||
<MenuItem Header="{x:Static resources:Strings.Match_Any_ID}"
|
||||
Command="{Binding Source={StaticResource Proxy}, Path=Data.InsertMatchAnyCommand}" />
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Content="{x:Static resources:Strings.Set_Container}" Margin="0,10,5,0"
|
||||
Command="{Binding SetContainerCommand}" Grid.Column="0" />
|
||||
<Image Source="{StaticResource configureIcon}" Height="16" Margin="5,10,0,0" Grid.Column="1"
|
||||
misc:ClickOpensContextMenuBehaviour.Enabled="True">
|
||||
<Image.ContextMenu>
|
||||
<ContextMenu IsOpen="False">
|
||||
<MenuItem Header="{x:Static resources:Strings.Reset_Container}"
|
||||
Command="{Binding Source={StaticResource Proxy}, Path=Data.ResetContainerCommand}" />
|
||||
<MenuItem Header="{x:Static resources:Strings.Define_Custom_Properties}"
|
||||
Command="{Binding Source={StaticResource Proxy}, Path=Data.DefineCustomPropertiesCommand}" />
|
||||
</ContextMenu>
|
||||
</Image.ContextMenu>
|
||||
</Image>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ComboBox x:Name="comboBox" Grid.Row="0" ItemsSource="{Binding Constraints}" DisplayMemberPath="Name"
|
||||
SelectedIndex="0" />
|
||||
<CheckBox Content="{x:Static resources:Strings.Enabled}" Grid.Row="1" Margin="0,10,0,0"
|
||||
IsChecked="{Binding SelectedItem.Enabled}" />
|
||||
<ListView x:Name="listView1" Grid.Row="2" Margin="0,10,0,10"
|
||||
ItemsSource="{Binding SelectedItem.Constraints}" SelectedItem="{Binding SelectedProperty}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:ListViewMultiSelectionBehaviour SelectedItems="{Binding SelectedProperties}" />
|
||||
</i:Interaction.Behaviors>
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Property}" Width="150"
|
||||
DisplayMemberBinding="{Binding Property.Name}" />
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Operator}" Width="75">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ComboBox Width="50" SelectedItem="{Binding Operator}"
|
||||
ItemsSource="{Binding Source={misc:EnumBindingSource {x:Type autoloot:AutolootOperator}}}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Value}" Width="75" x:Name="ValueColumn">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<controls:EditTextBlock
|
||||
Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
|
||||
MinWidth="40" ShowIcon="True"
|
||||
Width="{Binding Converter={StaticResource CellWidthValueConverter}, ConverterParameter=15, Path=Width, ElementName=ValueColumn, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<StackPanel Grid.Row="3">
|
||||
<Grid Margin="0,0,0,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Content="{x:Static resources:Strings.Remove}" Grid.Column="0" Margin="0,0,5,0"
|
||||
Command="{Binding RemoveConstraintCommand}"
|
||||
CommandParameter="{Binding SelectedProperties}" />
|
||||
<Button Content="{x:Static resources:Strings.Insert}" Grid.Column="1" Margin="5,0,0,0"
|
||||
Command="{Binding InsertConstraintCommand}"
|
||||
CommandParameter="{Binding SelectedValue, ElementName=comboBox}" />
|
||||
</Grid>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Content="{x:Static resources:Strings.Rehue_matching_items}"
|
||||
IsChecked="{Binding SelectedItem.Rehue}" />
|
||||
<Button Margin="10,0,0,0" Command="{Binding SelectHueCommand}"
|
||||
CommandParameter="{Binding SelectedItem, ElementName=listView}">
|
||||
<Image Source="{StaticResource ColorWheelIcon}" Height="12" Width="12" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<CheckBox Content="{x:Static resources:Strings.Autoloot_matching_items}"
|
||||
IsChecked="{Binding SelectedItem.Autoloot}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ClassicAssist.UI.Views.Agents
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AutolootTabControl.xaml
|
||||
/// </summary>
|
||||
public partial class AutolootTabControl : UserControl
|
||||
{
|
||||
public AutolootTabControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<UserControl
|
||||
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:ClassicAssist.UI.Views.Agents"
|
||||
xmlns:resources="clr-namespace:ClassicAssist.Shared.Resources;assembly=ClassicAssist.Shared"
|
||||
xmlns:controls="clr-namespace:ClassicAssist.UI.Controls"
|
||||
xmlns:ValueConverters="clr-namespace:ClassicAssist.UI.Misc.ValueConverters"
|
||||
xmlns:agents="clr-namespace:ClassicAssist.Shared.UI.ViewModels.Agents;assembly=ClassicAssist.Shared"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
x:Class="ClassicAssist.UI.Views.Agents.CountersTabControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="250" d:DesignWidth="500">
|
||||
<d:DesignerProperties.DesignStyle>
|
||||
<Style TargetType="UserControl">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
|
||||
</Style>
|
||||
</d:DesignerProperties.DesignStyle>
|
||||
<UserControl.DataContext>
|
||||
<agents:CountersTabViewModel />
|
||||
</UserControl.DataContext>
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../../Resources/ResourceDictionary.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.Resources>
|
||||
<ValueConverters:CellWidthValueConverter x:Key="CellWidthValueConverter" />
|
||||
</Grid.Resources>
|
||||
<ListView Grid.Row="0" Margin="10" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Name}" Width="150" x:Name="NameColumn">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<controls:EditTextBlock
|
||||
Width="{Binding ActualWidth, Converter={StaticResource CellWidthValueConverter}, ConverterParameter=15, ElementName=NameColumn, Mode=OneWay}"
|
||||
Text="{Binding Name}" ShowIcon="True" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Graphic}" Width="100"
|
||||
DisplayMemberBinding="{Binding Graphic, StringFormat={}0x{0:x}}" />
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Color}" Width="75" x:Name="ColorColumn">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<controls:EditTextBlock
|
||||
Width="{Binding ActualWidth, Converter={StaticResource CellWidthValueConverter}, ConverterParameter=15, ElementName=ColorColumn, Mode=OneWay}"
|
||||
Text="{Binding Color, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" ShowIcon="True" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="{x:Static resources:Strings.Count}" Width="75"
|
||||
DisplayMemberBinding="{Binding Count}" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<DockPanel Grid.Row="1" Margin="10,0,10,10">
|
||||
<CheckBox IsChecked="{Binding Warn}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resources:Strings.Warn_when_counter_amount_below_}" />
|
||||
<xctk:IntegerUpDown Minimum="0" Value="{Binding WarnAmount}" UpdateValueOnEnterKey="True" />
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</DockPanel>
|
||||
<DockPanel Grid.Row="2" Margin="10,0,10,10">
|
||||
<DockPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Width" Value="70" />
|
||||
<Setter Property="Height" Value="25" />
|
||||
</Style>
|
||||
</DockPanel.Resources>
|
||||
<Button Content="{x:Static resources:Strings.Remove}" HorizontalAlignment="Left" Margin="0,0,10,0"
|
||||
Command="{Binding RemoveEntryCommand}" CommandParameter="{Binding SelectedItem}" />
|
||||
<Button Content="{x:Static resources:Strings.Insert}" HorizontalAlignment="Left"
|
||||
Command="{Binding InsertEntryCommand}" />
|
||||
<Button Content="{x:Static resources:Strings.Recount}" HorizontalAlignment="Right"
|
||||
Command="{Binding RecountCommand}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ClassicAssist.UI.Views.Agents
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CountersTabControl.xaml
|
||||
/// </summary>
|
||||
public partial class CountersTabControl : UserControl
|
||||
{
|
||||
public CountersTabControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user