first commit
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.CustomWindowTitleControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:misc="clr-namespace:ClassicAssist.UI.Misc"
|
||||
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="50" d:DesignWidth="800"
|
||||
DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}"
|
||||
Background="{DynamicResource ThemeWindowBackgroundBrush}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="../../Resources/Icons.xaml" />
|
||||
<ResourceDictionary Source="../../Resources/ResourceDictionary.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowMouseDownBehaviour />
|
||||
</i:Interaction.Behaviors>
|
||||
<Grid Margin="5">
|
||||
<ContentPresenter Content="{Binding AdditionalContent}" DockPanel.Dock="Left" />
|
||||
<Label DockPanel.Dock="Left" Content="{Binding CustomTitle}" FontSize="16" Margin="5,0,5,0"
|
||||
Foreground="{DynamicResource ThemeForegroundBrush}" />
|
||||
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button Background="{DynamicResource ThemeWindowBackgroundBrush}" BorderBrush="Transparent" Height="24"
|
||||
Width="24" DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding CanMinimize}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowCommandBehaviour Command="Minimize" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image Source="{StaticResource minusIcon}" />
|
||||
</Button>
|
||||
<Button Background="{DynamicResource ThemeWindowBackgroundBrush}" BorderBrush="Transparent" Height="24"
|
||||
Width="24" DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding CanMaximize}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowCommandBehaviour Command="Maximize" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image Source="{StaticResource squareIcon}" />
|
||||
</Button>
|
||||
<Button Background="{DynamicResource ThemeWindowBackgroundBrush}" BorderBrush="Transparent" Height="24"
|
||||
Width="24" DockPanel.Dock="Right"
|
||||
IsEnabled="{Binding CanClose}">
|
||||
<i:Interaction.Behaviors>
|
||||
<misc:WindowCommandBehaviour Command="Close" />
|
||||
</i:Interaction.Behaviors>
|
||||
<Image Source="{StaticResource closeIcon}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CustomWindowTitleControl.xaml
|
||||
/// </summary>
|
||||
public partial class CustomWindowTitleControl
|
||||
{
|
||||
public static readonly DependencyProperty AdditionalContentProperty =
|
||||
DependencyProperty.Register( "AdditionalContent", typeof( object ), typeof( CustomWindowTitleControl ),
|
||||
new PropertyMetadata( null ) );
|
||||
|
||||
public static readonly DependencyProperty CustomTitleProperty = DependencyProperty.Register( "CustomTitle",
|
||||
typeof( string ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( default( string ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty CanCloseProperty = DependencyProperty.Register( "CanClose",
|
||||
typeof( bool ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty CanMinimizeProperty = DependencyProperty.Register( "CanMinimize",
|
||||
typeof( bool ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty CanMaxmizeProperty = DependencyProperty.Register( "CanMaximize",
|
||||
typeof( bool ), typeof( CustomWindowTitleControl ),
|
||||
new FrameworkPropertyMetadata( true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public CustomWindowTitleControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public object AdditionalContent
|
||||
{
|
||||
get => GetValue( AdditionalContentProperty );
|
||||
set => SetValue( AdditionalContentProperty, value );
|
||||
}
|
||||
|
||||
public bool CanClose
|
||||
{
|
||||
get => (bool) GetValue( CanCloseProperty );
|
||||
set => SetValue( CanCloseProperty, value );
|
||||
}
|
||||
|
||||
public bool CanMaximize
|
||||
{
|
||||
get => (bool) GetValue( CanMaxmizeProperty );
|
||||
set => SetValue( CanMaxmizeProperty, value );
|
||||
}
|
||||
|
||||
public bool CanMinimize
|
||||
{
|
||||
get => (bool) GetValue( CanMinimizeProperty );
|
||||
set => SetValue( CanMinimizeProperty, value );
|
||||
}
|
||||
|
||||
public string CustomTitle
|
||||
{
|
||||
get => (string) GetValue( CustomTitleProperty );
|
||||
set => SetValue( CustomTitleProperty, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<UserControl x:Name="root" x:Class="ClassicAssist.UI.Controls.EditTextBlock"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:valueConverters="clr-namespace:ClassicAssist.UI.Misc.ValueConverters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<DrawingImage x:Key="PencilIcon">
|
||||
<DrawingImage.Drawing>
|
||||
<DrawingGroup ClipGeometry="M0,0 V512 H512 V0 H0 Z">
|
||||
<DrawingGroup Opacity="1">
|
||||
<DrawingGroup Opacity="1">
|
||||
<GeometryDrawing
|
||||
Geometry="F1 M512,512z M0,0z M434.214,0L0,434.213 0,512 77.787,512 512,77.786 434.214,0z M65.359,481.998L30.002,481.998 30.002,446.641 50.125,426.518 85.482,461.875 65.359,481.998z M399.206,77.437L434.214,42.429 469.571,77.786 434.563,112.794 399.206,77.437z"
|
||||
Brush="{Binding Foreground, ElementName=root}" />
|
||||
</DrawingGroup>
|
||||
</DrawingGroup>
|
||||
</DrawingGroup>
|
||||
</DrawingImage.Drawing>
|
||||
</DrawingImage>
|
||||
<valueConverters:PriorityMultiValueConverter x:Key="PriorityMultiValueConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<TextBlock x:Name="textBlock" VerticalAlignment="Center"
|
||||
MouseDown="TextBlock_OnMouseDown" Background="Transparent"
|
||||
Foreground="{Binding Foreground, ElementName=root}">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource PriorityMultiValueConverter}">
|
||||
<Binding Path="Label" ElementName="root" />
|
||||
<Binding Path="Text" ElementName="root" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
<TextBox x:Name="textBox"
|
||||
Text="{Binding ElementName=root, Path=Text, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
|
||||
VerticalAlignment="Center" Visibility="Collapsed" KeyDown="TextBox_OnKeyDown"
|
||||
LostFocus="TextBox_LostFocus" />
|
||||
<Button Width="12" Height="12" BorderThickness="0" Background="Transparent" Margin="0" Padding="0"
|
||||
HorizontalAlignment="Right"
|
||||
Visibility="{Binding ShowIcon, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=root}"
|
||||
Click="Button_OnClick" x:Name="pencilButton">
|
||||
<Image Source="{StaticResource PencilIcon}" Width="16" HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EditTextBlock.xaml
|
||||
/// </summary>
|
||||
public partial class EditTextBlock
|
||||
{
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof( string ),
|
||||
typeof( EditTextBlock ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register( "Label",
|
||||
typeof( string ), typeof( EditTextBlock ),
|
||||
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None ) );
|
||||
|
||||
public static readonly DependencyProperty ShowIconProperty = DependencyProperty.Register( "ShowIcon",
|
||||
typeof( bool ), typeof( EditTextBlock ), new UIPropertyMetadata() );
|
||||
|
||||
public EditTextBlock()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string Label
|
||||
{
|
||||
get => (string) GetValue( LabelProperty );
|
||||
set => SetValue( LabelProperty, value );
|
||||
}
|
||||
|
||||
public bool ShowIcon
|
||||
{
|
||||
get => (bool) GetValue( ShowIconProperty );
|
||||
set => SetValue( ShowIconProperty, value );
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string) GetValue( TextProperty );
|
||||
set => SetValue( TextProperty, value );
|
||||
}
|
||||
|
||||
private void TextBlock_OnMouseDown( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
if ( e.ClickCount <= 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShowTextBox();
|
||||
}
|
||||
|
||||
private void ShowTextBox()
|
||||
{
|
||||
textBlock.Visibility = Visibility.Collapsed;
|
||||
pencilButton.Visibility = Visibility.Collapsed;
|
||||
textBox.Visibility = Visibility.Visible;
|
||||
textBox.CaretIndex = textBox.Text.Length;
|
||||
textBox.SelectAll();
|
||||
|
||||
Dispatcher?.BeginInvoke( (Action) ( () => Keyboard.Focus( textBox ) ), DispatcherPriority.Render );
|
||||
}
|
||||
|
||||
private void TextBox_OnKeyDown( object sender, KeyEventArgs e )
|
||||
{
|
||||
if ( e.Key == Key.Return )
|
||||
{
|
||||
TextBox_LostFocus( sender, null );
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_LostFocus( object sender, RoutedEventArgs e )
|
||||
{
|
||||
textBlock.Visibility = Visibility.Visible;
|
||||
pencilButton.Visibility = ShowIcon ? Visibility.Visible : Visibility.Hidden;
|
||||
( (TextBox) sender ).Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void Button_OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
ShowTextBox();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.HexDumpControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ClassicAssist.UI.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="600">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Consolas" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<StackPanel
|
||||
DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:HexDumpControl}}}">
|
||||
<Label Content="{Binding Packet.Title}" />
|
||||
<Grid>
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Copy byte[] declaration" Click="Copy_OnClick" />
|
||||
<MenuItem Header="Replay" Click="Replay_OnClick" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding BinaryData}" Style="{StaticResource TextBlockStyle}" Grid.Column="0"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled" Margin="10,10,0,0" Width="310" />
|
||||
<TextBlock Text="{Binding TextData}" Style="{StaticResource TextBlockStyle}" Grid.Column="1"
|
||||
Margin="10,10,0,0" ScrollViewer.VerticalScrollBarVisibility="Disabled" />
|
||||
</Grid>
|
||||
<Label Content="{Binding Status}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using ClassicAssist.Shared;
|
||||
using ClassicAssist.UI.Misc;
|
||||
using ClassicAssist.UO.Network.PacketFilter;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for HexDumpControl.xaml
|
||||
/// </summary>
|
||||
public partial class HexDumpControl
|
||||
{
|
||||
public static readonly DependencyProperty PacketProperty = DependencyProperty.Register( "Packet",
|
||||
typeof( PacketEntry ), typeof( HexDumpControl ), new UIPropertyMetadata() );
|
||||
|
||||
public HexDumpControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string BinaryData
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( Packet?.Data == null )
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder binaryBuilder = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < Packet.Length; i++ )
|
||||
{
|
||||
byte b1 = (byte) ( Packet.Data[i] >> 4 );
|
||||
byte b2 = (byte) ( Packet.Data[i] & 0xF );
|
||||
binaryBuilder.Append( (char) ( b1 > 9 ? b1 + 0x37 : b1 + 0x30 ) );
|
||||
binaryBuilder.Append( (char) ( b2 > 9 ? b2 + 0x37 : b2 + 0x30 ) );
|
||||
binaryBuilder.Append( ' ' );
|
||||
|
||||
if ( ( i + 1 ) % 16 != 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
binaryBuilder.Remove( binaryBuilder.Length - 1, 1 );
|
||||
binaryBuilder.AppendLine();
|
||||
}
|
||||
|
||||
return binaryBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public PacketEntry Packet
|
||||
{
|
||||
get => (PacketEntry) GetValue( PacketProperty );
|
||||
set => SetValue( PacketProperty, value );
|
||||
}
|
||||
|
||||
public string Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( Packet?.Data == null )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return "Length: " + Packet.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public string TextData
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( Packet?.Data == null )
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < Packet.Length; i++ )
|
||||
{
|
||||
byte b1 = Packet.Data[i];
|
||||
|
||||
if ( b1 < 0x20 || b1 == 0xB7 || b1 == 0xFF )
|
||||
{
|
||||
b1 = (byte) '.';
|
||||
}
|
||||
|
||||
textBuilder.Append( (char) b1 );
|
||||
|
||||
if ( ( i + 1 ) % 16 == 0 )
|
||||
{
|
||||
textBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
return textBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void Copy_OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
try
|
||||
{
|
||||
string prepend = "byte[] packet = new byte[] { ";
|
||||
|
||||
for ( int i = 0; i < Packet.Data.Length; i++ )
|
||||
{
|
||||
prepend += $"0x{Packet.Data[i]:X2}";
|
||||
|
||||
if ( i + 1 < Packet.Data.Length )
|
||||
{
|
||||
prepend += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
prepend += " };";
|
||||
|
||||
Clipboard.SetData( DataFormats.Text, prepend );
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void Replay_OnClick( object sender, RoutedEventArgs e )
|
||||
{
|
||||
if ( Packet == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( Packet.Direction )
|
||||
{
|
||||
case PacketDirection.Incoming:
|
||||
Engine.SendPacketToClient( Packet.Data, Packet.Data.Length );
|
||||
break;
|
||||
case PacketDirection.Outgoing:
|
||||
Engine.SendPacketToServer( Packet.Data, Packet.Data.Length );
|
||||
break;
|
||||
case PacketDirection.Any:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.HueEntryControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ClassicAssist.UI.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="20" d:DesignWidth="640">
|
||||
<d:DesignerProperties.DesignStyle>
|
||||
<Style TargetType="UserControl">
|
||||
<Setter Property="Background" Value="White" />
|
||||
</Style>
|
||||
</d:DesignerProperties.DesignStyle>
|
||||
<StackPanel Orientation="Horizontal" x:Name="StackPanel">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="Rectangle">
|
||||
<Setter Property="Fill" Value="Black" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using ClassicAssist.UO.Data;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for HueEntryControl.xaml
|
||||
/// </summary>
|
||||
public partial class HueEntryControl : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty HueEntryProperty = DependencyProperty.Register( "HueEntry",
|
||||
typeof( HueEntry ), typeof( HueEntryControl ),
|
||||
new FrameworkPropertyMetadata( default( HueEntry ), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
PropertyChangedCallback ) );
|
||||
|
||||
public HueEntryControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public HueEntry HueEntry
|
||||
{
|
||||
get => (HueEntry) GetValue( HueEntryProperty );
|
||||
set => SetValue( HueEntryProperty, value );
|
||||
}
|
||||
|
||||
private static void PropertyChangedCallback( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
if ( d is HueEntryControl control )
|
||||
{
|
||||
control.SetHues( (HueEntry) e.NewValue );
|
||||
}
|
||||
}
|
||||
|
||||
private void SetHues( HueEntry entry )
|
||||
{
|
||||
for ( int i = 0; i < 32; i++ )
|
||||
{
|
||||
SolidColorBrush brush = new SolidColorBrush( Convert555ToARGB( entry.Colors[i] ) );
|
||||
|
||||
StackPanel.Children.Add( new Rectangle { Fill = brush, Width = 10 } );
|
||||
}
|
||||
}
|
||||
|
||||
protected static Color Convert555ToARGB( short Col )
|
||||
{
|
||||
int r = ( (short) ( Col >> 10 ) & 31 ) * 8;
|
||||
int g = ( (short) ( Col >> 5 ) & 31 ) * 8;
|
||||
int b = ( Col & 31 ) * 8;
|
||||
return Color.FromArgb( 255, (byte) r, (byte) g, (byte) b );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/*
|
||||
* https://stackoverflow.com/questions/8004981/how-to-make-wpf-wrappanel-child-items-to-stretch
|
||||
*/
|
||||
public class StretchyWrapPanel : Panel
|
||||
{
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register( nameof( ItemWidth ),
|
||||
typeof( double ), typeof( StretchyWrapPanel ),
|
||||
new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure ) );
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty =
|
||||
DependencyProperty.Register( nameof( ItemHeight ), typeof( double ), typeof( StretchyWrapPanel ),
|
||||
new FrameworkPropertyMetadata( double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure ) );
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty =
|
||||
StackPanel.OrientationProperty.AddOwner( typeof( StretchyWrapPanel ),
|
||||
new FrameworkPropertyMetadata( Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure,
|
||||
OnOrientationChanged ) );
|
||||
|
||||
public static readonly DependencyProperty StretchProportionallyProperty =
|
||||
DependencyProperty.Register( nameof( StretchProportionally ), typeof( bool ), typeof( StretchyWrapPanel ),
|
||||
new PropertyMetadata( true, OnStretchProportionallyChanged ) );
|
||||
|
||||
private Orientation _orientation = Orientation.Horizontal;
|
||||
|
||||
private bool _stretchProportionally = true;
|
||||
|
||||
[TypeConverter( typeof( LengthConverter ) )]
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue( ItemHeightProperty );
|
||||
set => SetValue( ItemHeightProperty, value );
|
||||
}
|
||||
|
||||
[TypeConverter( typeof( LengthConverter ) )]
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue( ItemWidthProperty );
|
||||
set => SetValue( ItemWidthProperty, value );
|
||||
}
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => _orientation;
|
||||
set => SetValue( OrientationProperty, value );
|
||||
}
|
||||
|
||||
public bool StretchProportionally
|
||||
{
|
||||
get => _stretchProportionally;
|
||||
set => SetValue( StretchProportionallyProperty, value );
|
||||
}
|
||||
|
||||
private static void OnOrientationChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
( (StretchyWrapPanel) d )._orientation = (Orientation) e.NewValue;
|
||||
}
|
||||
|
||||
private static void OnStretchProportionallyChanged( DependencyObject o, DependencyPropertyChangedEventArgs e )
|
||||
{
|
||||
( (StretchyWrapPanel) o )._stretchProportionally = (bool) e.NewValue;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride( Size constraint )
|
||||
{
|
||||
UVSize curLineSize = new UVSize( Orientation );
|
||||
UVSize panelSize = new UVSize( Orientation );
|
||||
UVSize uvConstraint = new UVSize( Orientation, constraint.Width, constraint.Height );
|
||||
double itemWidth = ItemWidth;
|
||||
double itemHeight = ItemHeight;
|
||||
bool itemWidthSet = !double.IsNaN( itemWidth );
|
||||
bool itemHeightSet = !double.IsNaN( itemHeight );
|
||||
|
||||
Size childConstraint = new Size( itemWidthSet ? itemWidth : constraint.Width,
|
||||
itemHeightSet ? itemHeight : constraint.Height );
|
||||
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
for ( int i = 0, count = children.Count; i < count; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flow passes its own constrint to children
|
||||
child.Measure( childConstraint );
|
||||
|
||||
// This is the size of the child in UV space
|
||||
UVSize sz = new UVSize( Orientation, itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height );
|
||||
|
||||
if ( curLineSize.U + sz.U > uvConstraint.U )
|
||||
{
|
||||
// Need to switch to another line
|
||||
panelSize.U = Math.Max( curLineSize.U, panelSize.U );
|
||||
panelSize.V += curLineSize.V;
|
||||
curLineSize = sz;
|
||||
|
||||
if ( sz.U > uvConstraint.U )
|
||||
{
|
||||
// The element is wider then the constrint - give it a separate line
|
||||
panelSize.U = Math.Max( sz.U, panelSize.U );
|
||||
panelSize.V += sz.V;
|
||||
curLineSize = new UVSize( Orientation );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continue to accumulate a line
|
||||
curLineSize.U += sz.U;
|
||||
curLineSize.V = Math.Max( sz.V, curLineSize.V );
|
||||
}
|
||||
}
|
||||
|
||||
// The last line size, if any should be added
|
||||
panelSize.U = Math.Max( curLineSize.U, panelSize.U );
|
||||
panelSize.V += curLineSize.V;
|
||||
|
||||
// Go from UV space to W/H space
|
||||
return new Size( panelSize.Width, panelSize.Height );
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride( Size finalSize )
|
||||
{
|
||||
int firstInLine = 0;
|
||||
double itemWidth = ItemWidth;
|
||||
double itemHeight = ItemHeight;
|
||||
double accumulatedV = 0;
|
||||
double itemU = Orientation == Orientation.Horizontal ? itemWidth : itemHeight;
|
||||
UVSize curLineSize = new UVSize( Orientation );
|
||||
UVSize uvFinalSize = new UVSize( Orientation, finalSize.Width, finalSize.Height );
|
||||
bool itemWidthSet = !double.IsNaN( itemWidth );
|
||||
bool itemHeightSet = !double.IsNaN( itemHeight );
|
||||
bool useItemU = Orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet;
|
||||
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
for ( int i = 0, count = children.Count; i < count; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UVSize sz = new UVSize( Orientation, itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height );
|
||||
|
||||
if ( curLineSize.U + sz.U > uvFinalSize.U )
|
||||
{
|
||||
// Need to switch to another line
|
||||
if ( !useItemU && StretchProportionally )
|
||||
{
|
||||
ArrangeLineProportionally( accumulatedV, curLineSize.V, firstInLine, i, uvFinalSize.Width );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine( accumulatedV, curLineSize.V, firstInLine, i, true,
|
||||
useItemU ? itemU : uvFinalSize.Width / Math.Max( 1, i - firstInLine - 1 ) );
|
||||
}
|
||||
|
||||
accumulatedV += curLineSize.V;
|
||||
curLineSize = sz;
|
||||
|
||||
if ( sz.U > uvFinalSize.U )
|
||||
{
|
||||
// The element is wider then the constraint - give it a separate line
|
||||
// Switch to next line which only contain one element
|
||||
if ( !useItemU && StretchProportionally )
|
||||
{
|
||||
ArrangeLineProportionally( accumulatedV, sz.V, i, ++i, uvFinalSize.Width );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine( accumulatedV, sz.V, i, ++i, true, useItemU ? itemU : uvFinalSize.Width );
|
||||
}
|
||||
|
||||
accumulatedV += sz.V;
|
||||
curLineSize = new UVSize( Orientation );
|
||||
}
|
||||
|
||||
firstInLine = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Continue to accumulate a line
|
||||
curLineSize.U += sz.U;
|
||||
curLineSize.V = Math.Max( sz.V, curLineSize.V );
|
||||
}
|
||||
}
|
||||
|
||||
// Arrange the last line, if any
|
||||
if ( firstInLine < children.Count )
|
||||
{
|
||||
if ( !useItemU && StretchProportionally )
|
||||
{
|
||||
ArrangeLineProportionally( accumulatedV, curLineSize.V, firstInLine, children.Count,
|
||||
uvFinalSize.Width );
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine( accumulatedV, curLineSize.V, firstInLine, children.Count, true,
|
||||
useItemU ? itemU : uvFinalSize.Width / Math.Max( 1, children.Count - firstInLine - 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private void ArrangeLineProportionally( double v, double lineV, int start, int end, double limitU )
|
||||
{
|
||||
double u = 0d;
|
||||
bool horizontal = Orientation == Orientation.Horizontal;
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
double total = 0d;
|
||||
|
||||
for ( int i = start; i < end; i++ )
|
||||
{
|
||||
total += horizontal ? children[i].DesiredSize.Width : children[i].DesiredSize.Height;
|
||||
}
|
||||
|
||||
double uMultipler = limitU / total;
|
||||
|
||||
for ( int i = start; i < end; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child != null )
|
||||
{
|
||||
UVSize childSize = new UVSize( Orientation, child.DesiredSize.Width, child.DesiredSize.Height );
|
||||
double layoutSlotU = childSize.U * uMultipler;
|
||||
child.Arrange( new Rect( horizontal ? u : v, horizontal ? v : u, horizontal ? layoutSlotU : lineV,
|
||||
horizontal ? lineV : layoutSlotU ) );
|
||||
u += layoutSlotU;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ArrangeLine( double v, double lineV, int start, int end, bool useItemU, double itemU )
|
||||
{
|
||||
double u = 0d;
|
||||
bool horizontal = Orientation == Orientation.Horizontal;
|
||||
UIElementCollection children = InternalChildren;
|
||||
|
||||
for ( int i = start; i < end; i++ )
|
||||
{
|
||||
UIElement child = children[i];
|
||||
|
||||
if ( child != null )
|
||||
{
|
||||
UVSize childSize = new UVSize( Orientation, child.DesiredSize.Width, child.DesiredSize.Height );
|
||||
double layoutSlotU = useItemU ? itemU : childSize.U;
|
||||
child.Arrange( new Rect( horizontal ? u : v, horizontal ? v : u, horizontal ? layoutSlotU : lineV,
|
||||
horizontal ? lineV : layoutSlotU ) );
|
||||
u += layoutSlotU;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct UVSize
|
||||
{
|
||||
internal UVSize( Orientation orientation, double width, double height )
|
||||
{
|
||||
U = V = 0d;
|
||||
_orientation = orientation;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
internal UVSize( Orientation orientation )
|
||||
{
|
||||
U = V = 0d;
|
||||
_orientation = orientation;
|
||||
}
|
||||
|
||||
internal double U;
|
||||
internal double V;
|
||||
private readonly Orientation _orientation;
|
||||
|
||||
internal double Width
|
||||
{
|
||||
get => _orientation == Orientation.Horizontal ? U : V;
|
||||
private set
|
||||
{
|
||||
if ( _orientation == Orientation.Horizontal )
|
||||
{
|
||||
U = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
V = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal double Height
|
||||
{
|
||||
get => _orientation == Orientation.Horizontal ? V : U;
|
||||
private set
|
||||
{
|
||||
if ( _orientation == Orientation.Horizontal )
|
||||
{
|
||||
V = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
U = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<UserControl x:Class="ClassicAssist.UI.Controls.TextBoxKey"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300" x:Name="UserControl">
|
||||
<Grid>
|
||||
<TextBox Text="{Binding Shortcut, ElementName=UserControl, Mode=OneWay}"
|
||||
PreviewKeyDown="TextBox_PreviewKeyDown" IsReadOnly="True" IsReadOnlyCaretVisible="False"
|
||||
IsUndoEnabled="False" PreviewMouseDown="UIElement_OnPreviewMouseDown"
|
||||
MouseWheel="UIElement_OnMouseWheel" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using ClassicAssist.Data.Hotkeys;
|
||||
using Key = ClassicAssist.Misc.Key;
|
||||
|
||||
namespace ClassicAssist.UI.Controls
|
||||
{
|
||||
/// <inheritdoc cref="TextBox" />
|
||||
/// <summary>
|
||||
/// Interaction logic for TestBoxKey.xaml
|
||||
/// </summary>
|
||||
public partial class TextBoxKey
|
||||
{
|
||||
public static readonly DependencyProperty ShortcutProperty = DependencyProperty.Register( nameof( Shortcut ),
|
||||
typeof( ShortcutKeys ), typeof( TextBoxKey ),
|
||||
new FrameworkPropertyMetadata( default( ShortcutKeys ),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault ) );
|
||||
|
||||
private readonly Key[] _modifiers =
|
||||
{
|
||||
Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt
|
||||
};
|
||||
|
||||
public TextBoxKey()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public Key Key { get; private set; }
|
||||
public Key Modifier { get; set; }
|
||||
|
||||
public object Shortcut
|
||||
{
|
||||
get => GetValue( ShortcutProperty );
|
||||
set => SetValue( ShortcutProperty, value );
|
||||
}
|
||||
|
||||
private Key CheckModifiers()
|
||||
{
|
||||
return _modifiers.FirstOrDefault( e => Keyboard.IsKeyDown( (System.Windows.Input.Key) e ) );
|
||||
}
|
||||
|
||||
private bool IsModifier( Key key )
|
||||
{
|
||||
return _modifiers.Any( k => key == k );
|
||||
}
|
||||
|
||||
private void TextBox_PreviewKeyDown( object sender, KeyEventArgs e )
|
||||
{
|
||||
e.Handled = true;
|
||||
Key key = (Key) e.Key;
|
||||
|
||||
if ( key == Key.System )
|
||||
{
|
||||
key = (Key) e.SystemKey;
|
||||
}
|
||||
|
||||
if ( IsModifier( key ) )
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Modifier = CheckModifiers();
|
||||
|
||||
Key = key;
|
||||
|
||||
Shortcut = new ShortcutKeys { Modifier = Modifier, Key = Key };
|
||||
}
|
||||
|
||||
private void UIElement_OnPreviewMouseDown( object sender, MouseButtonEventArgs e )
|
||||
{
|
||||
if ( ( e.ChangedButton == MouseButton.Left ) | ( e.ChangedButton == MouseButton.Right ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
Modifier = CheckModifiers();
|
||||
|
||||
Shortcut = new ShortcutKeys { Mouse = (MouseOptions) e.ChangedButton };
|
||||
}
|
||||
|
||||
private void UIElement_OnMouseWheel( object sender, MouseWheelEventArgs e )
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
Modifier = CheckModifiers();
|
||||
|
||||
Shortcut = e.Delta < 0
|
||||
? new ShortcutKeys { Mouse = MouseOptions.MouseWheelDown, Modifier = Modifier }
|
||||
: new ShortcutKeys { Mouse = MouseOptions.MouseWheelUp, Modifier = Modifier };
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user