Skip to content

Commit

Permalink
[UX] Pasting into X textbox will split coords into textboxes
Browse files Browse the repository at this point in the history
  • Loading branch information
BAndysc committed Oct 1, 2021
1 parent e31942a commit a97889e
Show file tree
Hide file tree
Showing 13 changed files with 258 additions and 2 deletions.
22 changes: 22 additions & 0 deletions WDE.Common.Avalonia/Controls/FixedTextBox.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using System;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Styling;
using Avalonia.Threading;

namespace WDE.Common.Avalonia.Controls
{
Expand All @@ -19,6 +23,24 @@ protected override void OnTextInput(TextInputEventArgs e)
}
}

protected override void OnKeyDown(KeyEventArgs e)
{
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>();
if (keymap.Paste.Any(g => g.Matches(e)))
{
CustomPaste();
e.Handled = true;
}
else
base.OnKeyDown(e);

if (Text == "" && DataValidationErrors.GetHasErrors(this))
{
Text = "0";
SelectAll();
}
}

public virtual void CustomPaste()
{
Paste();
Expand Down
74 changes: 74 additions & 0 deletions WDE.Common.Avalonia/Controls/ParameterTextBox.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,81 @@
using System;
using System.Globalization;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Styling;
using Avalonia.VisualTree;
using WDE.Common.Utils;

namespace WDE.Common.Avalonia.Controls
{
public class ParameterTextBox : FixedTextBox, IStyleable
{
private DateTime lastFocusTime;
private bool specialCopying;
public static readonly DirectProperty<ParameterTextBox, bool> SpecialCopyingProperty = AvaloniaProperty.RegisterDirect<ParameterTextBox, bool>("SpecialCopying", o => o.SpecialCopying, (o, v) => o.SpecialCopying = v);

public override void CustomPaste()
{
if (specialCopying)
PasteAsync();
else
base.CustomPaste();
}

private async void PasteAsync()
{
var text = await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))).GetTextAsync();

if (text is null)
return;

var coords = CoordsParser.ExtractCoords(text);
if (coords.HasValue)
{
var nextTextBox = FindNext<ParameterTextBox>(this);
var nextNextTextBox = FindNext<ParameterTextBox>(nextTextBox);
var nextNextNextTextBox = FindNext<ParameterTextBox>(nextNextTextBox);

this.Text = coords.Value.x.ToString(CultureInfo.InvariantCulture);
if (nextTextBox != null)
nextTextBox.Text = coords.Value.y.ToString(CultureInfo.InvariantCulture);
if (nextNextTextBox != null)
nextNextTextBox.Text = coords.Value.z.ToString(CultureInfo.InvariantCulture);
if (nextNextNextTextBox != null && coords.Value.o.HasValue)
nextNextNextTextBox.Text = coords.Value.o.Value.ToString(CultureInfo.InvariantCulture);
}
else
Paste();
}

private static T? FindNext<T>(IVisual? start) where T : class, IVisual
{
if (start == null)
return null;

var parent = start.GetVisualParent();
if (parent == null)
return null;

int startChildrenIndex = 0;
while (startChildrenIndex < parent.VisualChildren.Count &&
parent.VisualChildren[startChildrenIndex] != start)
startChildrenIndex++;

startChildrenIndex++;

for (int i = startChildrenIndex; i < parent.VisualChildren.Count; ++i)
{
var find = parent.VisualChildren[i].FindDescendantOfType<T>(true);
if (find != null)
return find;
}

return FindNext<T>(parent);
}

protected override void OnGotFocus(GotFocusEventArgs e)
{
Expand All @@ -25,5 +93,11 @@ protected override void OnPointerPressed(PointerPressedEventArgs e)
}

Type IStyleable.StyleKey => typeof(TextBox);

public bool SpecialCopying
{
get { return specialCopying; }
set { SetAndRaise(SpecialCopyingProperty, ref specialCopying, value); }
}
}
}
11 changes: 10 additions & 1 deletion WDE.Common.Avalonia/Controls/ParameterValueHolderView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public class ParameterValueHolderView : TemplatedControl

private Func<Task<object?>>? specialCommand;
public static readonly DirectProperty<ParameterValueHolderView, Func<Task<object?>>?> SpecialCommandProperty = AvaloniaProperty.RegisterDirect<ParameterValueHolderView, Func<Task<object?>>?>("SpecialCommand", o => o.SpecialCommand, (o, v) => o.SpecialCommand = v);

private bool specialCopying;
public static readonly DirectProperty<ParameterValueHolderView, bool> SpecialCopyingProperty = AvaloniaProperty.RegisterDirect<ParameterValueHolderView, bool>("SpecialCopying", o => o.SpecialCopying, (o, v) => o.SpecialCopying = v);

public ICommand? PickCommand
{
Expand All @@ -32,10 +35,16 @@ public Func<Task<object?>>? SpecialCommand

public ICommand? PickSpecial { get; }

public bool SpecialCopying
{
get => specialCopying;
set => SetAndRaise(SpecialCopyingProperty, ref specialCopying, value);
}

protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
if (e.Source == this)
if (ReferenceEquals(e.Source, this))
{
Dispatcher.UIThread.Post(() =>
{
Expand Down
1 change: 1 addition & 0 deletions WDE.Common.Avalonia/Themes/Generic.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<controls:ParameterTextBox VerticalContentAlignment="Center"
Focusable="True"
Name="TextBox"
SpecialCopying="{Binding SpecialCopying, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=controls:ParameterValueHolderView}}"
Text="{Binding Value, Mode=TwoWay}"
FontFamily="Consolas,Menlo,Courier,Courier New"
Classes="InnerContentWithPadding">
Expand Down
72 changes: 72 additions & 0 deletions WDE.Common.Test/Utils/CoordsParserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using NUnit.Framework;
using WDE.Common.Utils;

namespace WDE.Common.Test.Utils
{
public class CoordsParserTests
{
private static float? O => null;

[Test]
public void TestSpaceXyz()
{
Assert.AreEqual((1f, 2f, 3f, O), CoordsParser.ExtractCoords("1 2 3"));
Assert.AreEqual((1.5f, 2.5f, 3.5f, O), CoordsParser.ExtractCoords("1.5 2.5 3.5"));
Assert.AreEqual((-1.5f, -2.5f, -3.5f, O), CoordsParser.ExtractCoords("-1.5 -2.5 -3.5"));
}

[Test]
public void TestCommaXyz()
{
Assert.AreEqual((1f, 2f, 3f, O), CoordsParser.ExtractCoords("1, 2, 3"));
}

[Test]
public void TestSemicolonXyz()
{
Assert.AreEqual((1f, 2f, 3f, O), CoordsParser.ExtractCoords("1; 2; 3"));
}

[Test]
public void TestLettersXyz()
{
Assert.AreEqual((1f, 2f, 3f, O), CoordsParser.ExtractCoords("X 1 Y 2 Z 3"));
}

[Test]
public void TestLettersXyzo()
{
Assert.AreEqual((1f, 2f, 3f, 4f), CoordsParser.ExtractCoords("X 1 Y 2 Z 3 O 4"));
}

[Test]
public void TestLettersColonXyz()
{
Assert.AreEqual((1f, 2f, 3f, O), CoordsParser.ExtractCoords("X: 1 Y: 2 Z: 3"));
}

[Test]
public void TestLettersColonXyzo()
{
Assert.AreEqual((1f, 2f, 3f, 4f), CoordsParser.ExtractCoords("X: 1 Y: 2 Z: 3 O: 4"));
}

[Test]
public void TestMixedXyz()
{
Assert.AreEqual((1f, 2f, 3f, 4f), CoordsParser.ExtractCoords("1 2, 3; 4"));
}

[Test]
public void TestRandomPrefix()
{
Assert.AreEqual((1f, 2f, 3f, 4f), CoordsParser.ExtractCoords("[1] position: 1, 2, 3, 4"));
}

[Test]
public void TestRandomSuffix()
{
Assert.AreEqual((1f, 2f, 3f, 4f), CoordsParser.ExtractCoords("1, 2, 3, 4[random]"));
}
}
}
23 changes: 23 additions & 0 deletions WDE.Common.Test/WDE.Common.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NSubstitute" Version="4.2.2" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\WoWDatabaseEditor.Common\WDE.Common\WDE.Common.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public class ParameterEditorView : TemplatedControl
public static readonly AttachedProperty<bool> OnEnterPressedProperty =
AvaloniaProperty.RegisterAttached<CompletionComboBox, bool>("OnEnterPressed", typeof(ParameterEditorView));

private bool specialCopying;
public static readonly DirectProperty<ParameterEditorView, bool> SpecialCopyingProperty = AvaloniaProperty.RegisterDirect<ParameterEditorView, bool>("SpecialCopying", o => o.SpecialCopying, (o, v) => o.SpecialCopying = v);

static ParameterEditorView()
{
OnEnterPressedProperty.Changed.AddClassHandler<CompletionComboBox>((box, args) =>
Expand All @@ -26,6 +29,12 @@ static ParameterEditorView()
});
}

public bool SpecialCopying
{
get => specialCopying;
set => SetAndRaise(SpecialCopyingProperty, ref specialCopying, value);
}

public static bool GetOnEnterPressed(IAvaloniaObject obj)
{
return obj.GetValue(OnEnterPressedProperty);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<ItemsPresenter.ItemTemplate>
<DataTemplate>
<editing:ParameterEditorView utils:FocusUtils.FocusFirst="{Binding FocusFirst}"
SpecialCopying="{Binding SpecialCopying}"
Margin="0,0,0,5" />
</DataTemplate>
</ItemsPresenter.ItemTemplate>
Expand Down
1 change: 1 addition & 0 deletions WDE.SmartScriptEditor.Avalonia/Themes/Generic.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@
<DataTemplate>
<extendedTextBlock:ParameterValueHolderView
DataContext="{Binding Parameter}"
SpecialCopying="{Binding DataContext.SpecialCopying, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editing:ParameterEditorView}, FallbackValue=False}"
SpecialCommand="{Binding DataContext.SpecialCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editing:ParameterEditorView}, FallbackValue=False}"
PickCommand="{Binding DataContext.SelectItemAction, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editing:ParameterEditorView}}" />
</DataTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ public class EditableParameterViewModel<T> : EditableParameterViewModel, IEditab
private readonly IItemFromListProvider itemFromListProvider;
private readonly ICurrentCoreVersion currentCoreVersion;

public EditableParameterViewModel(ParameterValueHolder<T> parameter, string group, IItemFromListProvider itemFromListProvider, ICurrentCoreVersion currentCoreVersion)
public EditableParameterViewModel(ParameterValueHolder<T> parameter,
string group,
IItemFromListProvider itemFromListProvider,
ICurrentCoreVersion currentCoreVersion)
{
this.itemFromListProvider = itemFromListProvider;
this.currentCoreVersion = currentCoreVersion;
Group = group;
Parameter = parameter;
SelectItemAction = new AsyncAutoCommand(SelectItem);
SpecialCopying = typeof(T) == typeof(float);

Watch(parameter, p => p.IsUsed, nameof(IsHidden));
Watch(parameter, p => p.ForceHidden, nameof(IsHidden));
Expand All @@ -42,6 +46,8 @@ public EditableParameterViewModel(ParameterValueHolder<T> parameter, string grou

public string Group { get; }

public bool SpecialCopying { get; }

public ICommand SelectItemAction { get; set; }

public string Name => Parameter.Name;
Expand Down
27 changes: 27 additions & 0 deletions WoWDatabaseEditor.Common/WDE.Common/Utils/CoordsParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Text.RegularExpressions;

namespace WDE.Common.Utils
{
public class CoordsParser
{
private static Regex waypointRegex = new Regex(@"(-?\d+(?:\.\d+)?)[ ,;Yy:]{1,5}(-?\d+(?:\.\d+)?)[ ,;Zz:]{1,5}(-?\d+(?:\.\d+)?)(?:[ ,;Oo:]{1,5}(-?\d+(?:\.\d+)?))?");

public static (float x, float y, float z, float? o)? ExtractCoords(string line)
{
var match = waypointRegex.Match(line);
if (match.Success &&
float.TryParse(match.Groups[1].Value, out var x) &&
float.TryParse(match.Groups[2].Value, out var y) &&
float.TryParse(match.Groups[3].Value, out var z))
{
float? o = null;
if (match.Groups.Count == 5 &&
float.TryParse(match.Groups[4].Value, out var o_))
o = o_;
return (x, y, z, o);
}

return null;
}
}
}
7 changes: 7 additions & 0 deletions WoWDatabaseEditor.sln
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WDE.RemoteSOAP", "WDE.Remot
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WDE.RemoteSOAP.Test", "WDE.RemoteSOAP.Test\WDE.RemoteSOAP.Test.csproj", "{0CA0846F-F6F3-4B4B-B0BA-8FF9502F9CEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WDE.Common.Test", "WoWDatabaseEditor\WDE.Common.Test\WDE.Common.Test.csproj", "{87974B90-DAD7-4027-A1F6-4405DC41F733}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "Solution Items", "{E9668961-BD19-4360-8ABE-B9BD55EB52CA}"
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
Expand Down Expand Up @@ -508,6 +510,10 @@ Global
{DACACBB1-29B3-435E-B1E5-CCE54C76D3A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DACACBB1-29B3-435E-B1E5-CCE54C76D3A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DACACBB1-29B3-435E-B1E5-CCE54C76D3A5}.Release|Any CPU.Build.0 = Release|Any CPU
{87974B90-DAD7-4027-A1F6-4405DC41F733}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87974B90-DAD7-4027-A1F6-4405DC41F733}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87974B90-DAD7-4027-A1F6-4405DC41F733}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87974B90-DAD7-4027-A1F6-4405DC41F733}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -579,5 +585,6 @@ Global
{96B60B17-8A72-40B5-9D2E-09BF256D7B07} = {4C553308-1140-42F2-B99C-90402248A983}
{6E0C8CDD-031A-4318-B612-9F1A575163AC} = {8A37024A-7A68-4BCB-B800-766D92E041EF}
{DACACBB1-29B3-435E-B1E5-CCE54C76D3A5} = {8A37024A-7A68-4BCB-B800-766D92E041EF}
{87974B90-DAD7-4027-A1F6-4405DC41F733} = {6C7361F8-036F-4C9A-8002-A94B71005DDB}
EndGlobalSection
EndGlobal
4 changes: 4 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ test_script:
dotnet test WDE.SqlQueryGenerator.Test/WDE.SqlQueryGenerator.Test.csproj
dotnet test WDE.SqlInterpreter.Test/WDE.SqlInterpreter.Test.csproj
dotnet test WDE.Common.Test/WDE.Common.Test.csproj
dotnet test WoWDatabaseEditorCore.Test/WoWDatabaseEditorCore.Test.csproj
artifacts:
- path: WoWDatabaseEditorMacOs.zip
Expand Down

0 comments on commit a97889e

Please sign in to comment.