first commit

This commit is contained in:
Beyhan Oğur
2026-09-03 04:45:36 +03:00
commit d5f52cc3d3
1038 changed files with 169579 additions and 0 deletions
@@ -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();
}
}
}
+318
View File
@@ -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 );
}
}
}
+30
View File
@@ -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; }
}
}
+29
View File
@@ -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 );
}
}
}
+32
View File
@@ -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;
}
}
}
+33
View File
@@ -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; }
}
}
+33
View File
@@ -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; }
}
}
+42
View File
@@ -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; }
}
}
+107
View File
@@ -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;
}
}
}
+152
View File
@@ -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;
}
}
}
+50
View File
@@ -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
View File
@@ -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 &apos;#&apos; are ignored
///# Table for converting body values to item numbers
///# Format:
///# Body&lt;tab&gt;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]&quot;;.
/// </summary>
public static string Shrink {
get {
return ResourceManager.GetString("Shrink", resourceCulture);
}
}
}
}
+136
View File
@@ -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>
+105
View File
@@ -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>
+104
View File
@@ -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>
+190
View File
@@ -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>
+442
View File
@@ -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;
}
}
}
}
}
}
+14
View File
@@ -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
}
}
+26
View File
@@ -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();
}
}
}
+79
View File
@@ -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 );
}
}
}
}
+154
View File
@@ -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