Коммит
04a5abdd0c
|
@ -2,7 +2,7 @@
|
|||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AvaloniaVersion>11.0.0-preview2</AvaloniaVersion>
|
||||
<AvaloniaVersion>11.0.0-preview5</AvaloniaVersion>
|
||||
<TextMateSharpVersion>1.0.50</TextMateSharpVersion>
|
||||
<NewtonsoftJsonVersion>13.0.1</NewtonsoftJsonVersion>
|
||||
<VersionSuffix>beta</VersionSuffix>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cc="clr-namespace:AvaloniaEdit.CodeCompletion;assembly=AvaloniaEdit"
|
||||
x:Class="AvaloniaEdit.Demo.App">
|
||||
x:Class="AvaloniaEdit.Demo.App"
|
||||
RequestedThemeVariant="Dark">
|
||||
<Application.Styles>
|
||||
<FluentTheme Mode="Dark" />
|
||||
<FluentTheme />
|
||||
<StyleInclude Source="avares://AvaloniaEdit/AvaloniaEdit.xaml" />
|
||||
|
||||
<!--Code completion-->
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Platform;
|
||||
|
@ -112,17 +113,10 @@ namespace AvaloniaEdit
|
|||
public static RoutedCommand Redo { get; } = new RoutedCommand(nameof(Redo), new KeyGesture(Key.Y, PlatformCommandKey));
|
||||
public static RoutedCommand Find { get; } = new RoutedCommand(nameof(Find), new KeyGesture(Key.F, PlatformCommandKey));
|
||||
public static RoutedCommand Replace { get; } = new RoutedCommand(nameof(Replace), GetReplaceKeyGesture());
|
||||
|
||||
private static OperatingSystemType GetOperatingSystemType()
|
||||
{
|
||||
return AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem;
|
||||
}
|
||||
|
||||
private static KeyModifiers GetPlatformCommandKey()
|
||||
{
|
||||
var os = GetOperatingSystemType();
|
||||
|
||||
if (os == OperatingSystemType.OSX)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return KeyModifiers.Meta;
|
||||
}
|
||||
|
@ -132,9 +126,7 @@ namespace AvaloniaEdit
|
|||
|
||||
private static KeyGesture GetReplaceKeyGesture()
|
||||
{
|
||||
var os = GetOperatingSystemType();
|
||||
|
||||
if (os == OperatingSystemType.OSX)
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return new KeyGesture(Key.F, KeyModifiers.Meta | KeyModifiers.Alt);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ using Avalonia;
|
|||
using AvaloniaEdit.Document;
|
||||
using AvaloniaEdit.Rendering;
|
||||
using Avalonia.Controls;
|
||||
using AvaloniaEdit.Utils;
|
||||
|
||||
namespace AvaloniaEdit.Editing
|
||||
{
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace AvaloniaEdit.Editing
|
|||
/// <summary>
|
||||
/// Creates a vertical dotted line to separate the line numbers from the text view.
|
||||
/// </summary>
|
||||
public static IControl Create()
|
||||
public static Control Create()
|
||||
{
|
||||
var line = new Line
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ namespace AvaloniaEdit.Editing
|
|||
/// <summary>
|
||||
/// Gets whether the specified UIElement is the result of a DottedLineMargin.Create call.
|
||||
/// </summary>
|
||||
public static bool IsDottedLineMargin(IControl element)
|
||||
public static bool IsDottedLineMargin(Control element)
|
||||
{
|
||||
var l = element as Line;
|
||||
return l != null && l.Tag == Tag;
|
||||
|
|
|
@ -128,13 +128,13 @@ namespace AvaloniaEdit.Editing
|
|||
}
|
||||
}
|
||||
|
||||
internal void AddChild(IVisual visual)
|
||||
internal void AddChild(Visual visual)
|
||||
{
|
||||
VisualChildren.Add(visual);
|
||||
InvalidateArrange();
|
||||
}
|
||||
|
||||
internal void RemoveChild(IVisual visual)
|
||||
internal void RemoveChild(Visual visual)
|
||||
{
|
||||
VisualChildren.Remove(visual);
|
||||
}
|
||||
|
@ -686,14 +686,14 @@ namespace AvaloniaEdit.Editing
|
|||
});
|
||||
}
|
||||
|
||||
public static readonly DirectProperty<TextArea, ObservableCollection<IControl>> LeftMarginsProperty
|
||||
= AvaloniaProperty.RegisterDirect<TextArea, ObservableCollection<IControl>>(nameof(LeftMargins),
|
||||
public static readonly DirectProperty<TextArea, ObservableCollection<Control>> LeftMarginsProperty
|
||||
= AvaloniaProperty.RegisterDirect<TextArea, ObservableCollection<Control>>(nameof(LeftMargins),
|
||||
c => c.LeftMargins);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of margins displayed to the left of the text view.
|
||||
/// </summary>
|
||||
public ObservableCollection<IControl> LeftMargins { get; } = new ObservableCollection<IControl>();
|
||||
public ObservableCollection<Control> LeftMargins { get; } = new ObservableCollection<Control>();
|
||||
|
||||
private void LeftMargins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
|
@ -1122,10 +1122,10 @@ namespace AvaloniaEdit.Editing
|
|||
}
|
||||
}
|
||||
|
||||
public bool BringIntoView(IControl target, Rect targetRect) =>
|
||||
public bool BringIntoView(Control target, Rect targetRect) =>
|
||||
_logicalScrollable?.BringIntoView(target, targetRect) ?? default(bool);
|
||||
|
||||
IControl ILogicalScrollable.GetControlInDirection(NavigationDirection direction, IControl from)
|
||||
Control ILogicalScrollable.GetControlInDirection(NavigationDirection direction, Control from)
|
||||
=> _logicalScrollable?.GetControlInDirection(direction, from);
|
||||
|
||||
public void RaiseScrollInvalidated(EventArgs e)
|
||||
|
@ -1168,7 +1168,7 @@ namespace AvaloniaEdit.Editing
|
|||
}
|
||||
}
|
||||
|
||||
public IVisual TextViewVisual => _textArea;
|
||||
public Visual TextViewVisual => _textArea;
|
||||
|
||||
public bool SupportsPreedit => false;
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace AvaloniaEdit.Rendering
|
|||
/// </summary>
|
||||
public FormattedTextElement Element { get; }
|
||||
|
||||
public override ReadOnlySlice<char> Text { get; }
|
||||
public override ReadOnlyMemory<char> Text { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override TextRunProperties Properties { get; }
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace AvaloniaEdit.Rendering
|
|||
if (length <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, "Value must be positive");
|
||||
|
||||
TextSourceLength = length;
|
||||
Length = length;
|
||||
Properties = properties ?? throw new ArgumentNullException(nameof(properties));
|
||||
Element = element ?? throw new ArgumentNullException(nameof(element));
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace AvaloniaEdit.Rendering
|
|||
|
||||
public override TextRunProperties? Properties { get; }
|
||||
|
||||
public override int TextSourceLength { get; }
|
||||
public override int Length { get; }
|
||||
|
||||
public override double Baseline
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace AvaloniaEdit.Rendering
|
|||
private const double PointerHoverHeight = 2;
|
||||
private static readonly TimeSpan PointerHoverTime = TimeSpan.FromMilliseconds(400);
|
||||
|
||||
private readonly IControl _target;
|
||||
private readonly Control _target;
|
||||
|
||||
private DispatcherTimer _timer;
|
||||
private Point _hoverStartPoint;
|
||||
|
@ -43,7 +43,7 @@ namespace AvaloniaEdit.Rendering
|
|||
/// <summary>
|
||||
/// Creates a new instance and attaches itself to the <paramref name="target" /> UIElement.
|
||||
/// </summary>
|
||||
public PointerHoverLogic(IControl target)
|
||||
public PointerHoverLogic(Control target)
|
||||
{
|
||||
_target = target ?? throw new ArgumentNullException(nameof(target));
|
||||
_target.PointerExited += OnPointerLeave;
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace AvaloniaEdit.Rendering
|
|||
{
|
||||
if (textSourceCharacterIndex < _text.Length)
|
||||
return new TextCharacters(
|
||||
new ReadOnlySlice<char>(_text.AsMemory(), textSourceCharacterIndex,
|
||||
_text.AsMemory().Slice(textSourceCharacterIndex,
|
||||
_text.Length - textSourceCharacterIndex), _properties);
|
||||
|
||||
return new TextEndOfParagraph(1);
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace AvaloniaEdit.Rendering
|
|||
if (startVisualColumn == VisualColumn)
|
||||
return new TabGlyphRun(this, TextRunProperties);
|
||||
else if (startVisualColumn == VisualColumn + 1)
|
||||
return new TextCharacters(new ReadOnlySlice<char>("\t".AsMemory(), VisualColumn + 1, 1), TextRunProperties);
|
||||
return new TextCharacters("\t".AsMemory(), TextRunProperties);
|
||||
else
|
||||
throw new ArgumentOutOfRangeException(nameof(startVisualColumn));
|
||||
}
|
||||
|
|
|
@ -1206,7 +1206,7 @@ namespace AvaloniaEdit.Rendering
|
|||
Debug.WriteLine(distance);
|
||||
}
|
||||
|
||||
offset += span.TextSourceLength;
|
||||
offset += span.Length;
|
||||
}
|
||||
pos = new Point(pos.X, pos.Y + textLine.Height);
|
||||
}
|
||||
|
@ -1950,7 +1950,7 @@ namespace AvaloniaEdit.Rendering
|
|||
return pen;
|
||||
}
|
||||
|
||||
bool ILogicalScrollable.BringIntoView(IControl target, Rect rectangle)
|
||||
bool ILogicalScrollable.BringIntoView(Control target, Rect rectangle)
|
||||
{
|
||||
if (rectangle.IsEmpty || target == null || target == this || !this.IsVisualAncestorOf(target))
|
||||
{
|
||||
|
@ -1967,7 +1967,7 @@ namespace AvaloniaEdit.Rendering
|
|||
return true;
|
||||
}
|
||||
|
||||
IControl ILogicalScrollable.GetControlInDirection(NavigationDirection direction, IControl from)
|
||||
Control ILogicalScrollable.GetControlInDirection(NavigationDirection direction, Control from)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -106,9 +106,9 @@ namespace AvaloniaEdit.Rendering
|
|||
/// Retrieves the text span immediately before the visual column.
|
||||
/// </summary>
|
||||
/// <remarks>This method is used for word-wrapping in bidirectional text.</remarks>
|
||||
public virtual ReadOnlySlice<char> GetPrecedingText(int visualColumnLimit, ITextRunConstructionContext context)
|
||||
public virtual ReadOnlyMemory<char> GetPrecedingText(int visualColumnLimit, ITextRunConstructionContext context)
|
||||
{
|
||||
return ReadOnlySlice<char>.Empty;
|
||||
return ReadOnlyMemory<char>.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -110,7 +110,12 @@ namespace AvaloniaEdit.Rendering
|
|||
if (!e.Handled && LinkIsClickable(e.KeyModifiers))
|
||||
{
|
||||
var eventArgs = new OpenUriRoutedEventArgs(NavigateUri) { RoutedEvent = OpenUriEvent };
|
||||
e.Source.RaiseEvent(eventArgs);
|
||||
|
||||
if(e.Source is Interactive interactive)
|
||||
{
|
||||
interactive.RaiseEvent(eventArgs);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,14 +68,7 @@ namespace AvaloniaEdit.Rendering
|
|||
offset,
|
||||
DocumentLength - relativeOffset);
|
||||
|
||||
var bufferOffset = RelativeTextOffset;
|
||||
|
||||
if (bufferOffset + text.Count > text.Text.Length)
|
||||
{
|
||||
bufferOffset = 0;
|
||||
}
|
||||
|
||||
var textSlice = new ReadOnlySlice<char>(text.Text.AsMemory(), text.Offset, text.Count, bufferOffset);
|
||||
var textSlice = text.Text.AsMemory().Slice(text.Offset, text.Count);
|
||||
|
||||
return new TextCharacters(textSlice, TextRunProperties);
|
||||
}
|
||||
|
@ -88,7 +81,7 @@ namespace AvaloniaEdit.Rendering
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ReadOnlySlice<char> GetPrecedingText(int visualColumnLimit, ITextRunConstructionContext context)
|
||||
public override ReadOnlyMemory<char> GetPrecedingText(int visualColumnLimit, ITextRunConstructionContext context)
|
||||
{
|
||||
if (context == null)
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
|
@ -97,7 +90,7 @@ namespace AvaloniaEdit.Rendering
|
|||
|
||||
var text = context.GetText(context.VisualLine.FirstDocumentLine.Offset + RelativeTextOffset, relativeOffset);
|
||||
|
||||
return new ReadOnlySlice<char>(text.Text.AsMemory(), text.Offset, text.Count);
|
||||
return text.Text.AsMemory().Slice(text.Offset, text.Count);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
@ -51,9 +51,9 @@ namespace AvaloniaEdit.Rendering
|
|||
TextRun run = element.CreateTextRun(textSourceCharacterIndex, this);
|
||||
if (run == null)
|
||||
throw new ArgumentNullException(element.GetType().Name + ".CreateTextRun");
|
||||
if (run.TextSourceLength == 0)
|
||||
if (run.Length == 0)
|
||||
throw new ArgumentException("The returned TextRun must not have length 0.", element.GetType().Name + ".Length");
|
||||
if (relativeOffset + run.TextSourceLength > element.VisualLength)
|
||||
if (relativeOffset + run.Length > element.VisualLength)
|
||||
throw new ArgumentException("The returned TextRun is too long.", element.GetType().Name + ".CreateTextRun");
|
||||
if (run is InlineObjectRun inlineRun) {
|
||||
inlineRun.VisualLine = VisualLine;
|
||||
|
@ -102,7 +102,7 @@ namespace AvaloniaEdit.Rendering
|
|||
return new FormattedTextRun(textElement, GlobalTextRunProperties);
|
||||
}
|
||||
|
||||
public ReadOnlySlice<char> GetPrecedingText(int textSourceCharacterIndexLimit)
|
||||
public ReadOnlyMemory<char> GetPrecedingText(int textSourceCharacterIndexLimit)
|
||||
{
|
||||
try {
|
||||
foreach (VisualLineElement element in VisualLine.Elements) {
|
||||
|
@ -118,7 +118,7 @@ namespace AvaloniaEdit.Rendering
|
|||
}
|
||||
}
|
||||
|
||||
return ReadOnlySlice<char>.Empty;
|
||||
return ReadOnlyMemory<char>.Empty;
|
||||
} catch (Exception ex) {
|
||||
Debug.WriteLine(ex.ToString());
|
||||
throw;
|
||||
|
|
|
@ -21,22 +21,29 @@ namespace AvaloniaEdit
|
|||
|
||||
static RoutedCommand()
|
||||
{
|
||||
CanExecuteEvent.AddClassHandler<IRoutedCommandBindable>(CanExecuteEventHandler);
|
||||
ExecutedEvent.AddClassHandler<IRoutedCommandBindable>(ExecutedEventHandler);
|
||||
CanExecuteEvent.AddClassHandler<Interactive>(CanExecuteEventHandler);
|
||||
ExecutedEvent.AddClassHandler<Interactive>(ExecutedEventHandler);
|
||||
}
|
||||
|
||||
private static void CanExecuteEventHandler(IRoutedCommandBindable control, CanExecuteRoutedEventArgs args)
|
||||
private static void CanExecuteEventHandler(Interactive control, CanExecuteRoutedEventArgs args)
|
||||
{
|
||||
var binding = control.CommandBindings.Where(c => c != null)
|
||||
.FirstOrDefault(c => c.Command == args.Command && c.DoCanExecute(control, args));
|
||||
args.CanExecute = binding != null;
|
||||
if (control is IRoutedCommandBindable bindable)
|
||||
{
|
||||
var binding = bindable.CommandBindings.Where(c => c != null)
|
||||
.FirstOrDefault(c => c.Command == args.Command && c.DoCanExecute(control, args));
|
||||
args.CanExecute = binding != null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExecutedEventHandler(IRoutedCommandBindable control, ExecutedRoutedEventArgs args)
|
||||
private static void ExecutedEventHandler(Interactive control, ExecutedRoutedEventArgs args)
|
||||
{
|
||||
// ReSharper disable once UnusedVariable
|
||||
var binding = control.CommandBindings.Where(c => c != null)
|
||||
.FirstOrDefault(c => c.Command == args.Command && c.DoExecuted(control, args));
|
||||
if (control is IRoutedCommandBindable bindable)
|
||||
{
|
||||
// ReSharper disable once UnusedVariable
|
||||
var binding = bindable.CommandBindings.Where(c => c != null)
|
||||
.FirstOrDefault(c => c.Command == args.Command && c.DoExecuted(control, args));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static RoutedEvent<CanExecuteRoutedEventArgs> CanExecuteEvent { get; } = RoutedEvent.Register<CanExecuteRoutedEventArgs>(nameof(CanExecuteEvent), RoutingStrategies.Bubble, typeof(RoutedCommand));
|
||||
|
@ -79,7 +86,7 @@ namespace AvaloniaEdit
|
|||
}
|
||||
}
|
||||
|
||||
public interface IRoutedCommandBindable : IInteractive
|
||||
public interface IRoutedCommandBindable
|
||||
{
|
||||
IList<RoutedCommandBinding> CommandBindings { get; }
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ using Avalonia.Media;
|
|||
using AvaloniaEdit.Document;
|
||||
using AvaloniaEdit.Editing;
|
||||
using AvaloniaEdit.Rendering;
|
||||
using AvaloniaEdit.Utils;
|
||||
|
||||
namespace AvaloniaEdit.Search
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ using Avalonia.Controls;
|
|||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Reactive;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace AvaloniaEdit.Utils
|
||||
|
@ -214,7 +215,7 @@ namespace AvaloniaEdit.Utils
|
|||
#endregion
|
||||
|
||||
#region Snap to device pixels
|
||||
public static Point SnapToDevicePixels(this Point p, IVisual targetVisual)
|
||||
public static Point SnapToDevicePixels(this Point p, Visual targetVisual)
|
||||
{
|
||||
var root = targetVisual.GetVisualRoot();
|
||||
|
||||
|
@ -301,5 +302,10 @@ namespace AvaloniaEdit.Utils
|
|||
{
|
||||
return stack.IsEmpty ? default(T) : stack.Peek();
|
||||
}
|
||||
|
||||
public static IDisposable Subscribe<T>(this IObservable<T> observable, Action<T> action)
|
||||
{
|
||||
return observable.Subscribe(new AnonymousObserver<T>(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
@ -305,7 +304,7 @@ namespace AvaloniaEdit.Utils
|
|||
{
|
||||
Interlocked.Increment(ref _deliveries);
|
||||
|
||||
return Disposable.Create(() => Interlocked.Decrement(ref _deliveries));
|
||||
return new Disposable(() => Interlocked.Decrement(ref _deliveries));
|
||||
}
|
||||
|
||||
// ReSharper disable once MemberHidesStaticFromOuterClass
|
||||
|
@ -341,4 +340,18 @@ namespace AvaloniaEdit.Utils
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Disposable : IDisposable
|
||||
{
|
||||
private volatile Action _dispose;
|
||||
public Disposable(Action dispose)
|
||||
{
|
||||
_dispose = dispose;
|
||||
}
|
||||
public bool IsDisposed => _dispose == null;
|
||||
public void Dispose()
|
||||
{
|
||||
Interlocked.Exchange(ref _dispose, null)?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
return true;
|
||||
}
|
||||
|
||||
public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface)
|
||||
public IGlyphTypeface CreateGlyphTypeface(Typeface typeface)
|
||||
{
|
||||
return new MockGlyphTypeface();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using Avalonia.Platform;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AvaloniaEdit.AvaloniaMocks
|
||||
{
|
||||
internal class MockGlyphRun : IGlyphRunImpl
|
||||
{
|
||||
public MockGlyphRun(IReadOnlyList<GlyphInfo> glyphInfos)
|
||||
{
|
||||
var width = 0.0;
|
||||
|
||||
for (var i = 0; i < glyphInfos.Count; ++i)
|
||||
{
|
||||
width += glyphInfos[i].GlyphAdvance;
|
||||
}
|
||||
|
||||
Size = new Size(width, 10);
|
||||
}
|
||||
|
||||
public Size Size { get; }
|
||||
|
||||
public Point BaselineOrigin => new Point(0, 8);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IReadOnlyList<float> GetIntersections(float lowerBound, float upperBound)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +1,26 @@
|
|||
using Avalonia.Platform;
|
||||
using Avalonia.Media;
|
||||
|
||||
using System;
|
||||
|
||||
namespace AvaloniaEdit.AvaloniaMocks
|
||||
{
|
||||
public class MockGlyphTypeface : IGlyphTypefaceImpl
|
||||
public class MockGlyphTypeface : IGlyphTypeface
|
||||
{
|
||||
public const int GlyphAdvance = 8;
|
||||
public const short DefaultFontSize = 10;
|
||||
public const int GlyphAscent = 2;
|
||||
public const int GlyphDescent = 10;
|
||||
public FontMetrics Metrics => new FontMetrics
|
||||
{
|
||||
DesignEmHeight = 10,
|
||||
Ascent = 2,
|
||||
Descent = 10,
|
||||
IsFixedPitch = true
|
||||
};
|
||||
|
||||
public short DesignEmHeight => DefaultFontSize;
|
||||
public int Ascent => GlyphAscent;
|
||||
public int Descent => GlyphDescent;
|
||||
public int LineGap { get; }
|
||||
public int UnderlinePosition { get; }
|
||||
public int UnderlineThickness { get; }
|
||||
public int StrikethroughPosition { get; }
|
||||
public int StrikethroughThickness { get; }
|
||||
public bool IsFixedPitch { get; }
|
||||
public int GlyphCount => 1337;
|
||||
|
||||
public FontSimulations FontSimulations => throw new NotImplementedException();
|
||||
|
||||
public ushort GetGlyph(uint codepoint)
|
||||
{
|
||||
return 0;
|
||||
return (ushort)codepoint;
|
||||
}
|
||||
|
||||
public ushort[] GetGlyphs(ReadOnlySpan<uint> codepoints)
|
||||
|
@ -33,9 +30,18 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
|
||||
public int GetGlyphAdvance(ushort glyph)
|
||||
{
|
||||
return GlyphAdvance;
|
||||
return 8;
|
||||
}
|
||||
|
||||
public bool TryGetGlyph(uint codepoint, out ushort glyph)
|
||||
{
|
||||
glyph = 8;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int GlyphAdvance => 8;
|
||||
|
||||
public int[] GetGlyphAdvances(ReadOnlySpan<ushort> glyphs)
|
||||
{
|
||||
var advances = new int[glyphs.Length];
|
||||
|
@ -49,5 +55,22 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public bool TryGetTable(uint tag, out byte[] table)
|
||||
{
|
||||
table = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
|
||||
{
|
||||
metrics = new GlyphMetrics
|
||||
{
|
||||
Width = 10,
|
||||
Height = 10
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ using System.IO;
|
|||
using Avalonia;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using Avalonia.Platform;
|
||||
|
||||
using Moq;
|
||||
|
||||
namespace AvaloniaEdit.AvaloniaMocks
|
||||
|
@ -143,5 +143,20 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IGlyphRunImpl CreateGlyphRun(IGlyphTypeface glyphTypeface, double fontRenderingEmSize, IReadOnlyList<GlyphInfo> glyphInfos, Point baselineOrigin)
|
||||
{
|
||||
return new MockGlyphRun(glyphInfos);
|
||||
}
|
||||
|
||||
public IPlatformRenderInterfaceContext CreateBackendContext(IPlatformGraphicsContext graphicsApiContext)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsSupportedBitmapPixelFormat(PixelFormat format)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Globalization;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.TextFormatting;
|
||||
using Avalonia.Media.TextFormatting.Unicode;
|
||||
|
@ -11,7 +12,7 @@ namespace AvaloniaEdit.AvaloniaMocks;
|
|||
|
||||
public class MockTextShaperImpl : ITextShaperImpl
|
||||
{
|
||||
public ShapedBuffer ShapeText(ReadOnlySlice<char> text, TextShaperOptions options)
|
||||
public ShapedBuffer ShapeText(ReadOnlyMemory<char> text, TextShaperOptions options)
|
||||
{
|
||||
var typeface = options.Typeface;
|
||||
var fontRenderingEmSize = options.FontRenderingEmSize;
|
||||
|
@ -21,8 +22,8 @@ public class MockTextShaperImpl : ITextShaperImpl
|
|||
|
||||
for (var i = 0; i < shapedBuffer.Length;)
|
||||
{
|
||||
var glyphCluster = i + text.Start;
|
||||
var codepoint = Codepoint.ReadAt(text, i, out var count);
|
||||
var glyphCluster = i;
|
||||
var codepoint = Codepoint.ReadAt(text.Span, i, out var count);
|
||||
|
||||
var glyphIndex = typeface.GetGlyph(codepoint);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Reactive.Concurrency;
|
||||
using Avalonia;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Input.Platform;
|
||||
|
@ -21,7 +20,6 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
platform: new AppBuilder().RuntimePlatform,
|
||||
renderInterface: new MockPlatformRenderInterface(),
|
||||
standardCursorFactory: Mock.Of<ICursorFactory>(),
|
||||
styler: new Styler(),
|
||||
theme: () => CreateDefaultTheme(),
|
||||
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true),
|
||||
windowingPlatform: new MockWindowingPlatform(),
|
||||
|
@ -34,9 +32,6 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
public static readonly TestServices MockPlatformWrapper = new TestServices(
|
||||
platform: Mock.Of<IRuntimePlatform>());
|
||||
|
||||
public static readonly TestServices MockStyler = new TestServices(
|
||||
styler: Mock.Of<IStyler>());
|
||||
|
||||
public static readonly TestServices MockThreadingInterface = new TestServices(
|
||||
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true));
|
||||
|
||||
|
@ -49,9 +44,6 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
keyboardNavigation: new KeyboardNavigationHandler(),
|
||||
inputManager: new InputManager());
|
||||
|
||||
public static readonly TestServices RealStyler = new TestServices(
|
||||
styler: new Styler());
|
||||
|
||||
public TestServices(
|
||||
IAssetLoader assetLoader = null,
|
||||
IFocusManager focusManager = null,
|
||||
|
@ -63,9 +55,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
IRuntimePlatform platform = null,
|
||||
IPlatformRenderInterface renderInterface = null,
|
||||
IRenderLoop renderLoop = null,
|
||||
IScheduler scheduler = null,
|
||||
ICursorFactory standardCursorFactory = null,
|
||||
IStyler styler = null,
|
||||
Func<Styles> theme = null,
|
||||
IPlatformThreadingInterface threadingInterface = null,
|
||||
IWindowImpl windowImpl = null,
|
||||
|
@ -83,9 +73,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
MouseDevice = mouseDevice;
|
||||
Platform = platform;
|
||||
RenderInterface = renderInterface;
|
||||
Scheduler = scheduler;
|
||||
StandardCursorFactory = standardCursorFactory;
|
||||
Styler = styler;
|
||||
Theme = theme;
|
||||
ThreadingInterface = threadingInterface;
|
||||
WindowImpl = windowImpl;
|
||||
|
@ -104,9 +92,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
public Func<IMouseDevice> MouseDevice { get; }
|
||||
public IRuntimePlatform Platform { get; }
|
||||
public IPlatformRenderInterface RenderInterface { get; }
|
||||
public IScheduler Scheduler { get; }
|
||||
public ICursorFactory StandardCursorFactory { get; }
|
||||
public IStyler Styler { get; }
|
||||
public Func<Styles> Theme { get; }
|
||||
public IPlatformThreadingInterface ThreadingInterface { get; }
|
||||
public IWindowImpl WindowImpl { get; }
|
||||
|
@ -127,9 +113,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
IRuntimePlatform platform = null,
|
||||
IPlatformRenderInterface renderInterface = null,
|
||||
IRenderLoop renderLoop = null,
|
||||
IScheduler scheduler = null,
|
||||
ICursorFactory standardCursorFactory = null,
|
||||
IStyler styler = null,
|
||||
Func<Styles> theme = null,
|
||||
IPlatformThreadingInterface threadingInterface = null,
|
||||
IWindowImpl windowImpl = null,
|
||||
|
@ -148,9 +132,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
mouseDevice: mouseDevice ?? MouseDevice,
|
||||
platform: platform ?? Platform,
|
||||
renderInterface: renderInterface ?? RenderInterface,
|
||||
scheduler: scheduler ?? Scheduler,
|
||||
standardCursorFactory: standardCursorFactory ?? StandardCursorFactory,
|
||||
styler: styler ?? Styler,
|
||||
theme: theme ?? Theme,
|
||||
threadingInterface: threadingInterface ?? ThreadingInterface,
|
||||
windowingPlatform: windowingPlatform ?? WindowingPlatform,
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
using System;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reflection;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Input.Platform;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaEdit.Utils;
|
||||
|
||||
namespace AvaloniaEdit.AvaloniaMocks
|
||||
{
|
||||
|
@ -30,7 +28,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
AvaloniaLocator.CurrentMutable.BindToSelf<Application>(app);
|
||||
var updateServices = Dispatcher.UIThread.GetType().GetMethod("UpdateServices", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
updateServices?.Invoke(Dispatcher.UIThread, null);
|
||||
return Disposable.Create(() =>
|
||||
return new Disposable(() =>
|
||||
{
|
||||
updateServices?.Invoke(Dispatcher.UIThread, null);
|
||||
AvaloniaLocator.CurrentMutable = null;
|
||||
|
@ -52,9 +50,7 @@ namespace AvaloniaEdit.AvaloniaMocks
|
|||
.Bind<IRuntimePlatform>().ToConstant(Services.Platform)
|
||||
.Bind<IPlatformRenderInterface>().ToConstant(Services.RenderInterface)
|
||||
.Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface)
|
||||
.Bind<IScheduler>().ToConstant(Services.Scheduler)
|
||||
.Bind<ICursorFactory>().ToConstant(Services.StandardCursorFactory)
|
||||
.Bind<IStyler>().ToConstant(Services.Styler)
|
||||
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
|
||||
.Bind<PlatformHotkeyConfiguration>().ToConstant(Services.PlatformHotkeyConfiguration)
|
||||
.Bind<IFontManagerImpl>().ToConstant(Services.FontManagerImpl)
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace AvaloniaEdit.Tests.Rendering
|
|||
VisualLine visualLine = textView.GetOrConstructVisualLine(document.Lines[0]);
|
||||
|
||||
Assert.AreEqual(1, visualLine.TextLines.Count);
|
||||
Assert.AreEqual("hello world", new string(visualLine.TextLines[0].TextRuns[0].Text.Buffer.Span));
|
||||
Assert.AreEqual("hello world", new string(visualLine.TextLines[0].TextRuns[0].Text.Span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче