diff --git a/samples/BindingDemo/App.xaml b/samples/BindingDemo/App.xaml
index 9260dd280f..3e312c8685 100644
--- a/samples/BindingDemo/App.xaml
+++ b/samples/BindingDemo/App.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BindingDemo.App">
-
+
-
\ No newline at end of file
+
diff --git a/samples/BindingDemo/BindingDemo.csproj b/samples/BindingDemo/BindingDemo.csproj
index bd6054327f..056d3bf552 100644
--- a/samples/BindingDemo/BindingDemo.csproj
+++ b/samples/BindingDemo/BindingDemo.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
index 54acdd9114..a43ea4539a 100644
--- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
+++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj
@@ -9,7 +9,6 @@
1.0
apk
true
- android-arm64;android-x64
diff --git a/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs b/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
index cb79bf219a..f37e0f8701 100644
--- a/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
@@ -90,7 +90,6 @@ namespace ControlCatalog.Pages
private int _vertexBufferObject;
private int _indexBufferObject;
private int _vertexArrayObject;
- private GlExtrasInterface _glExt;
private string GetShader(bool fragment, string shader)
{
@@ -258,7 +257,6 @@ namespace ControlCatalog.Pages
protected unsafe override void OnOpenGlInit(GlInterface GL, int fb)
{
CheckError(GL);
- _glExt = new GlExtrasInterface(GL);
Info = $"Renderer: {GL.GetString(GL_RENDERER)} Version: {GL.GetString(GL_VERSION)}";
@@ -298,8 +296,8 @@ namespace ControlCatalog.Pages
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata),
GL_STATIC_DRAW);
CheckError(GL);
- _vertexArrayObject = _glExt.GenVertexArray();
- _glExt.BindVertexArray(_vertexArrayObject);
+ _vertexArrayObject = GL.GenVertexArray();
+ GL.BindVertexArray(_vertexArrayObject);
CheckError(GL);
GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT,
0, vertexSize, IntPtr.Zero);
@@ -316,12 +314,13 @@ namespace ControlCatalog.Pages
// Unbind everything
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- _glExt.BindVertexArray(0);
+ GL.BindVertexArray(0);
GL.UseProgram(0);
// Delete all resources.
- GL.DeleteBuffers(2, new[] { _vertexBufferObject, _indexBufferObject });
- _glExt.DeleteVertexArrays(1, new[] { _vertexArrayObject });
+ GL.DeleteBuffer(_vertexBufferObject);
+ GL.DeleteBuffer(_indexBufferObject);
+ GL.DeleteVertexArray(_vertexArrayObject);
GL.DeleteProgram(_shaderProgram);
GL.DeleteShader(_fragmentShader);
GL.DeleteShader(_vertexShader);
@@ -338,7 +337,7 @@ namespace ControlCatalog.Pages
GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject);
- _glExt.BindVertexArray(_vertexArrayObject);
+ GL.BindVertexArray(_vertexArrayObject);
GL.UseProgram(_shaderProgram);
CheckError(GL);
var projection =
@@ -369,34 +368,5 @@ namespace ControlCatalog.Pages
if (_disco > 0.01)
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
}
-
- class GlExtrasInterface : GlInterfaceBase
- {
- public GlExtrasInterface(GlInterface gl) : base(gl.GetProcAddress, gl.ContextInfo)
- {
- }
-
- public delegate void GlDeleteVertexArrays(int count, int[] buffers);
- [GlMinVersionEntryPoint("glDeleteVertexArrays", 3,0)]
- [GlExtensionEntryPoint("glDeleteVertexArraysOES", "GL_OES_vertex_array_object")]
- public GlDeleteVertexArrays DeleteVertexArrays { get; }
-
- public delegate void GlBindVertexArray(int array);
- [GlMinVersionEntryPoint("glBindVertexArray", 3,0)]
- [GlExtensionEntryPoint("glBindVertexArrayOES", "GL_OES_vertex_array_object")]
- public GlBindVertexArray BindVertexArray { get; }
- public delegate void GlGenVertexArrays(int n, int[] rv);
-
- [GlMinVersionEntryPoint("glGenVertexArrays",3,0)]
- [GlExtensionEntryPoint("glGenVertexArraysOES", "GL_OES_vertex_array_object")]
- public GlGenVertexArrays GenVertexArrays { get; }
-
- public int GenVertexArray()
- {
- var rv = new int[1];
- GenVertexArrays(1, rv);
- return rv[0];
- }
- }
}
}
diff --git a/samples/ControlCatalog/Pages/TextBlockPage.xaml b/samples/ControlCatalog/Pages/TextBlockPage.xaml
index cb49ba96c6..32914428ed 100644
--- a/samples/ControlCatalog/Pages/TextBlockPage.xaml
+++ b/samples/ControlCatalog/Pages/TextBlockPage.xaml
@@ -118,7 +118,7 @@
-
+
This is a
TextBlock
with several
diff --git a/samples/RenderDemo/App.xaml b/samples/RenderDemo/App.xaml
index 66d97a6444..8ea792de19 100644
--- a/samples/RenderDemo/App.xaml
+++ b/samples/RenderDemo/App.xaml
@@ -3,6 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
-
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Base/Media/GlyphRun.cs b/src/Avalonia.Base/Media/GlyphRun.cs
index ac87d521a5..2a7f3360ad 100644
--- a/src/Avalonia.Base/Media/GlyphRun.cs
+++ b/src/Avalonia.Base/Media/GlyphRun.cs
@@ -445,7 +445,7 @@ namespace Avalonia.Media
///
public int FindGlyphIndex(int characterIndex)
{
- if (GlyphClusters == null)
+ if (GlyphClusters == null || GlyphClusters.Count == 0)
{
return characterIndex;
}
@@ -614,17 +614,29 @@ namespace Avalonia.Media
private GlyphRunMetrics CreateGlyphRunMetrics()
{
+ var firstCluster = 0;
+ var lastCluster = Characters.Length - 1;
+
+ if (!IsLeftToRight)
+ {
+ var cluster = firstCluster;
+ firstCluster = lastCluster;
+ lastCluster = cluster;
+ }
+
if (GlyphClusters != null && GlyphClusters.Count > 0)
{
- var firstCluster = GlyphClusters[0];
+ firstCluster = GlyphClusters[0];
+ lastCluster = GlyphClusters[GlyphClusters.Count - 1];
_offsetToFirstCharacter = Math.Max(0, Characters.Start - firstCluster);
}
+ var isReversed = firstCluster > lastCluster;
var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale;
var widthIncludingTrailingWhitespace = 0d;
- var trailingWhitespaceLength = GetTrailingWhitespaceLength(out var newLineLength, out var glyphCount);
+ var trailingWhitespaceLength = GetTrailingWhitespaceLength(isReversed, out var newLineLength, out var glyphCount);
for (var index = 0; index < GlyphIndices.Count; index++)
{
@@ -635,16 +647,16 @@ namespace Avalonia.Media
var width = widthIncludingTrailingWhitespace;
- if (IsLeftToRight)
+ if (isReversed)
{
- for (var index = GlyphIndices.Count - glyphCount; index < GlyphIndices.Count; index++)
+ for (var index = 0; index < glyphCount; index++)
{
width -= GetGlyphAdvance(index, out _);
}
}
else
{
- for (var index = 0; index < glyphCount; index++)
+ for (var index = GlyphIndices.Count - glyphCount; index < GlyphIndices.Count; index++)
{
width -= GetGlyphAdvance(index, out _);
}
@@ -654,16 +666,15 @@ namespace Avalonia.Media
height);
}
- private int GetTrailingWhitespaceLength(out int newLineLength, out int glyphCount)
- {
- glyphCount = 0;
- newLineLength = 0;
-
- if (Characters.IsEmpty)
+ private int GetTrailingWhitespaceLength(bool isReversed, out int newLineLength, out int glyphCount)
+ {
+ if (isReversed)
{
- return 0;
+ return GetTralingWhitespaceLengthRightToLeft(out newLineLength, out glyphCount);
}
+ glyphCount = 0;
+ newLineLength = 0;
var trailingWhitespaceLength = 0;
if (GlyphClusters == null)
@@ -732,6 +743,78 @@ namespace Avalonia.Media
return trailingWhitespaceLength;
}
+ private int GetTralingWhitespaceLengthRightToLeft(out int newLineLength, out int glyphCount)
+ {
+ glyphCount = 0;
+ newLineLength = 0;
+ var trailingWhitespaceLength = 0;
+
+ if (GlyphClusters == null)
+ {
+ for (var i = 0; i < Characters.Length;)
+ {
+ var codepoint = Codepoint.ReadAt(_characters, i, out var count);
+
+ if (!codepoint.IsWhiteSpace)
+ {
+ break;
+ }
+
+ if (codepoint.IsBreakChar)
+ {
+ newLineLength++;
+ }
+
+ trailingWhitespaceLength++;
+
+ i += count;
+ glyphCount++;
+ }
+ }
+ else
+ {
+ for (var i = 0; i < GlyphClusters.Count; i++)
+ {
+ var currentCluster = GlyphClusters[i];
+ var characterIndex = Math.Max(0, currentCluster - _characters.BufferOffset);
+ var codepoint = Codepoint.ReadAt(_characters, characterIndex, out _);
+
+ if (!codepoint.IsWhiteSpace)
+ {
+ break;
+ }
+
+ var clusterLength = 1;
+
+ while (i - 1 >= 0)
+ {
+ var nextCluster = GlyphClusters[i - 1];
+
+ if (currentCluster == nextCluster)
+ {
+ clusterLength++;
+ i--;
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (codepoint.IsBreakChar)
+ {
+ newLineLength += clusterLength;
+ }
+
+ trailingWhitespaceLength += clusterLength;
+
+ glyphCount++;
+ }
+ }
+
+ return trailingWhitespaceLength;
+ }
+
private void Set(ref T field, T value)
{
_glyphRunImpl?.Dispose();
diff --git a/src/Avalonia.Base/Media/TextDecoration.cs b/src/Avalonia.Base/Media/TextDecoration.cs
index 8eeb86c555..4c9764af96 100644
--- a/src/Avalonia.Base/Media/TextDecoration.cs
+++ b/src/Avalonia.Base/Media/TextDecoration.cs
@@ -209,7 +209,7 @@ namespace Avalonia.Media
var pen = new Pen(Stroke ?? defaultBrush, thickness,
new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap);
- drawingContext.DrawLine(pen, origin, origin + new Point(glyphRun.Size.Width, 0));
+ drawingContext.DrawLine(pen, origin, origin + new Point(glyphRun.Metrics.Width, 0));
}
}
}
diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs
index f3af240c58..f3e8b5969c 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs
@@ -63,7 +63,7 @@ namespace Avalonia.Media.TextFormatting
MaxHeight = maxHeight;
- MaxLines = maxLines;
+ MaxLines = maxLines;
TextLines = CreateTextLines();
}
@@ -80,7 +80,7 @@ namespace Avalonia.Media.TextFormatting
/// The maximum number of text lines.
public TextLayout(
ITextSource textSource,
- TextParagraphProperties paragraphProperties,
+ TextParagraphProperties paragraphProperties,
TextTrimming? textTrimming = null,
double maxWidth = double.PositiveInfinity,
double maxHeight = double.PositiveInfinity,
@@ -178,24 +178,18 @@ namespace Avalonia.Media.TextFormatting
return new Rect();
}
- if (textPosition < 0 || textPosition >= _textSourceLength)
+ if (textPosition < 0)
{
- var lastLine = TextLines[TextLines.Count - 1];
-
- var lineX = lastLine.Width;
-
- var lineY = Bounds.Bottom - lastLine.Height;
-
- return new Rect(lineX, lineY, 0, lastLine.Height);
+ textPosition = _textSourceLength;
}
var currentY = 0.0;
foreach (var textLine in TextLines)
{
- var end = textLine.FirstTextSourceIndex + textLine.Length - 1;
+ var end = textLine.FirstTextSourceIndex + textLine.Length;
- if (end < textPosition)
+ if (end <= textPosition && end < _textSourceLength)
{
currentY += textLine.Height;
@@ -224,7 +218,7 @@ namespace Avalonia.Media.TextFormatting
}
var result = new List(TextLines.Count);
-
+
var currentY = 0d;
foreach (var textLine in TextLines)
@@ -239,7 +233,7 @@ namespace Avalonia.Media.TextFormatting
var textBounds = textLine.GetTextBounds(start, length);
- if(textBounds.Count > 0)
+ if (textBounds.Count > 0)
{
foreach (var bounds in textBounds)
{
@@ -262,7 +256,7 @@ namespace Avalonia.Media.TextFormatting
}
}
- if(textLine.FirstTextSourceIndex + textLine.Length >= start + length)
+ if (textLine.FirstTextSourceIndex + textLine.Length >= start + length)
{
break;
}
@@ -305,7 +299,7 @@ namespace Avalonia.Media.TextFormatting
return GetHitTestResult(currentLine, characterHit, point);
}
-
+
public int GetLineIndexFromCharacterIndex(int charIndex, bool trailingEdge)
{
if (charIndex < 0)
@@ -327,7 +321,7 @@ namespace Avalonia.Media.TextFormatting
continue;
}
- if (charIndex >= textLine.FirstTextSourceIndex &&
+ if (charIndex >= textLine.FirstTextSourceIndex &&
charIndex <= textLine.FirstTextSourceIndex + textLine.Length - (trailingEdge ? 0 : 1))
{
return index;
@@ -398,7 +392,7 @@ namespace Avalonia.Media.TextFormatting
/// The current left.
/// The current width.
/// The current height.
- private static void UpdateBounds(TextLine textLine,ref double left, ref double width, ref double height)
+ private static void UpdateBounds(TextLine textLine, ref double left, ref double width, ref double height)
{
var lineWidth = textLine.WidthIncludingTrailingWhitespace;
@@ -421,7 +415,7 @@ namespace Avalonia.Media.TextFormatting
{
var textLine = TextFormatterImpl.CreateEmptyTextLine(0, double.PositiveInfinity, _paragraphProperties);
- Bounds = new Rect(0,0,0, textLine.Height);
+ Bounds = new Rect(0, 0, 0, textLine.Height);
return new List { textLine };
}
@@ -439,9 +433,9 @@ namespace Avalonia.Media.TextFormatting
var textLine = TextFormatter.Current.FormatLine(_textSource, _textSourceLength, MaxWidth,
_paragraphProperties, previousLine?.TextLineBreak);
- if(textLine == null || textLine.Length == 0 || textLine.TextRuns.Count == 0 && textLine.TextLineBreak?.TextEndOfLine is TextEndOfParagraph)
+ if (textLine == null || textLine.Length == 0 || textLine.TextRuns.Count == 0 && textLine.TextLineBreak?.TextEndOfLine is TextEndOfParagraph)
{
- if(previousLine != null && previousLine.NewLineLength > 0)
+ if (previousLine != null && previousLine.NewLineLength > 0)
{
var emptyTextLine = TextFormatterImpl.CreateEmptyTextLine(_textSourceLength, MaxWidth, _paragraphProperties);
@@ -454,7 +448,7 @@ namespace Avalonia.Media.TextFormatting
}
_textSourceLength += textLine.Length;
-
+
//Fulfill max height constraint
if (textLines.Count > 0 && !double.IsPositiveInfinity(MaxHeight) && height + textLine.Height > MaxHeight)
{
@@ -485,12 +479,17 @@ namespace Avalonia.Media.TextFormatting
//Fulfill max lines constraint
if (MaxLines > 0 && textLines.Count >= MaxLines)
{
+ if(textLine.TextLineBreak is TextLineBreak lineBreak && lineBreak.RemainingRuns != null)
+ {
+ textLines[textLines.Count - 1] = textLine.Collapse(GetCollapsingProperties(width));
+ }
+
break;
}
}
//Make sure the TextLayout always contains at least on empty line
- if(textLines.Count == 0)
+ if (textLines.Count == 0)
{
var textLine = TextFormatterImpl.CreateEmptyTextLine(0, MaxWidth, _paragraphProperties);
@@ -501,7 +500,7 @@ namespace Avalonia.Media.TextFormatting
Bounds = new Rect(left, 0, width, height);
- if(_paragraphProperties.TextAlignment == TextAlignment.Justify)
+ if (_paragraphProperties.TextAlignment == TextAlignment.Justify)
{
var whitespaceWidth = 0d;
@@ -509,7 +508,7 @@ namespace Avalonia.Media.TextFormatting
{
var lineWhitespaceWidth = line.Width - line.WidthIncludingTrailingWhitespace;
- if(lineWhitespaceWidth > whitespaceWidth)
+ if (lineWhitespaceWidth > whitespaceWidth)
{
whitespaceWidth = lineWhitespaceWidth;
}
@@ -517,7 +516,7 @@ namespace Avalonia.Media.TextFormatting
var justificationWidth = width - whitespaceWidth;
- if(justificationWidth > 0)
+ if (justificationWidth > 0)
{
var justificationProperties = new InterWordJustification(justificationWidth);
diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
index 7c686358e2..f3c62f4994 100644
--- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
+++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
@@ -166,58 +166,74 @@ namespace Avalonia.Media.TextFormatting
if (distance <= 0)
{
- // hit happens before the line, return the first position
var firstRun = _textRuns[0];
- if (firstRun is ShapedTextCharacters shapedTextCharacters)
- {
- return shapedTextCharacters.GlyphRun.GetCharacterHitFromDistance(distance, out _);
- }
+ return GetRunCharacterHit(firstRun, FirstTextSourceIndex, 0);
+ }
- return _resolvedFlowDirection == FlowDirection.LeftToRight ?
- new CharacterHit(FirstTextSourceIndex) :
- new CharacterHit(FirstTextSourceIndex + Length);
+ if (distance > WidthIncludingTrailingWhitespace)
+ {
+ var lastRun = _textRuns[_textRuns.Count - 1];
+
+ return GetRunCharacterHit(lastRun, FirstTextSourceIndex + Length - lastRun.TextSourceLength, lastRun.Size.Width);
}
// process hit that happens within the line
var characterHit = new CharacterHit();
var currentPosition = FirstTextSourceIndex;
+ var currentDistance = 0.0;
foreach (var currentRun in _textRuns)
{
- switch (currentRun)
+ if (currentDistance + currentRun.Size.Width < distance)
{
- case ShapedTextCharacters shapedRun:
- {
- characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _);
+ currentDistance += currentRun.Size.Width;
+ currentPosition += currentRun.TextSourceLength;
- var offset = Math.Max(0, currentPosition - shapedRun.Text.Start);
+ continue;
+ }
- characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength);
+ characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
- break;
- }
- default:
+ break;
+ }
+
+ return characterHit;
+ }
+
+ private static CharacterHit GetRunCharacterHit(DrawableTextRun run, int currentPosition, double distance)
+ {
+ CharacterHit characterHit;
+
+ switch (run)
+ {
+ case ShapedTextCharacters shapedRun:
+ {
+ characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _);
+
+ var offset = Math.Max(0, currentPosition - shapedRun.Text.Start);
+
+ if (!shapedRun.GlyphRun.IsLeftToRight)
{
- if (distance < currentRun.Size.Width / 2)
- {
- characterHit = new CharacterHit(currentPosition);
- }
- else
- {
- characterHit = new CharacterHit(currentPosition, currentRun.TextSourceLength);
- }
- break;
+ offset = Math.Max(0, offset - shapedRun.Text.End);
}
- }
- if (distance <= currentRun.Size.Width)
- {
- break;
- }
+ characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength);
- distance -= currentRun.Size.Width;
- currentPosition += currentRun.TextSourceLength;
+ break;
+ }
+ default:
+ {
+ if (distance < run.Size.Width / 2)
+ {
+ characterHit = new CharacterHit(currentPosition);
+ }
+ else
+ {
+ characterHit = new CharacterHit(currentPosition, run.TextSourceLength);
+ }
+ break;
+ }
}
return characterHit;
@@ -226,136 +242,122 @@ namespace Avalonia.Media.TextFormatting
///
public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
{
- var isTrailingHit = characterHit.TrailingLength > 0;
+ var flowDirection = _paragraphProperties.FlowDirection;
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
- var currentDistance = Start;
var currentPosition = FirstTextSourceIndex;
var remainingLength = characterIndex - FirstTextSourceIndex;
- GlyphRun? lastRun = null;
+ var currentDistance = Start;
- for (var index = 0; index < _textRuns.Count; index++)
+ if (flowDirection == FlowDirection.LeftToRight)
+ {
+ for (var index = 0; index < _textRuns.Count; index++)
+ {
+ var currentRun = _textRuns[index];
+
+ if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength,
+ flowDirection, out var distance, out _))
+ {
+ return currentDistance + distance;
+ }
+
+ //No hit hit found so we add the full width
+ currentDistance += currentRun.Size.Width;
+ currentPosition += currentRun.TextSourceLength;
+ remainingLength -= currentRun.TextSourceLength;
+ }
+ }
+ else
{
- var textRun = _textRuns[index];
+ currentDistance += WidthIncludingTrailingWhitespace;
- switch (textRun)
+ for (var index = _textRuns.Count - 1; index >= 0; index--)
{
- case ShapedTextCharacters shapedTextCharacters:
- {
- var currentRun = shapedTextCharacters.GlyphRun;
+ var currentRun = _textRuns[index];
- if (lastRun != null)
- {
- if (!lastRun.IsLeftToRight && currentRun.IsLeftToRight &&
- currentRun.Characters.Start == characterHit.FirstCharacterIndex &&
- characterHit.TrailingLength == 0)
- {
- return currentDistance;
- }
- }
+ if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength,
+ flowDirection, out var distance, out var currentGlyphRun))
+ {
+ if (currentGlyphRun != null)
+ {
+ distance = currentGlyphRun.Size.Width - distance;
+ }
- //Look for a hit in within the current run
- if (currentPosition + remainingLength <= currentPosition + textRun.Text.Length)
- {
- characterHit = new CharacterHit(textRun.Text.Start + remainingLength);
+ return currentDistance - distance;
+ }
- var distance = currentRun.GetDistanceFromCharacterHit(characterHit);
+ //No hit hit found so we add the full width
+ currentDistance -= currentRun.Size.Width;
+ currentPosition += currentRun.TextSourceLength;
+ remainingLength -= currentRun.TextSourceLength;
+ }
+ }
- return currentDistance + distance;
- }
+ return currentDistance;
+ }
- //Look at the left and right edge of the current run
- if (currentRun.IsLeftToRight)
- {
- if (_resolvedFlowDirection == FlowDirection.LeftToRight && (lastRun == null || lastRun.IsLeftToRight))
- {
- if (characterIndex <= currentPosition)
- {
- return currentDistance;
- }
- }
- else
- {
- if (characterIndex == currentPosition)
- {
- return currentDistance;
- }
- }
+ private static bool TryGetDistanceFromCharacterHit(
+ DrawableTextRun currentRun,
+ CharacterHit characterHit,
+ int currentPosition,
+ int remainingLength,
+ FlowDirection flowDirection,
+ out double distance,
+ out GlyphRun? currentGlyphRun)
+ {
+ var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
+ var isTrailingHit = characterHit.TrailingLength > 0;
- if (characterIndex == currentPosition + textRun.Text.Length && isTrailingHit)
- {
- return currentDistance + currentRun.Size.Width;
- }
- }
- else
- {
- if (characterIndex == currentPosition)
- {
- return currentDistance + currentRun.Size.Width;
- }
+ distance = 0;
+ currentGlyphRun = null;
- var nextRun = index + 1 < _textRuns.Count ?
- _textRuns[index + 1] as ShapedTextCharacters :
- null;
+ switch (currentRun)
+ {
+ case ShapedTextCharacters shapedTextCharacters:
+ {
+ currentGlyphRun = shapedTextCharacters.GlyphRun;
- if (nextRun != null)
- {
- if (nextRun.ShapedBuffer.IsLeftToRight)
- {
- if (characterIndex == currentPosition + textRun.Text.Length)
- {
- return currentDistance;
- }
- }
- else
- {
- if (currentPosition + nextRun.Text.Length == characterIndex)
- {
- return currentDistance;
- }
- }
- }
- else
- {
- if (characterIndex > currentPosition + textRun.Text.Length)
- {
- return currentDistance;
- }
- }
- }
+ if (currentPosition + remainingLength <= currentPosition + currentRun.Text.Length)
+ {
+ characterHit = new CharacterHit(currentRun.Text.Start + remainingLength);
- lastRun = currentRun;
+ distance = currentGlyphRun.GetDistanceFromCharacterHit(characterHit);
- break;
+ return true;
}
- default:
+
+ if (currentPosition + remainingLength == currentPosition + currentRun.Text.Length && isTrailingHit)
{
- if (characterIndex == currentPosition)
+ if (currentGlyphRun.IsLeftToRight || flowDirection == FlowDirection.RightToLeft)
{
- return currentDistance;
+ distance = currentGlyphRun.Size.Width;
}
- if (characterIndex == currentPosition + textRun.TextSourceLength)
- {
- return currentDistance + textRun.Size.Width;
- }
+ return true;
+ }
- break;
+ break;
+ }
+ default:
+ {
+ if (characterIndex == currentPosition)
+ {
+ return true;
}
- }
- //No hit hit found so we add the full width
- currentDistance += textRun.Size.Width;
- currentPosition += textRun.TextSourceLength;
- remainingLength -= textRun.TextSourceLength;
+ if (characterIndex == currentPosition + currentRun.TextSourceLength)
+ {
+ distance = currentRun.Size.Width;
- if (remainingLength <= 0)
- {
- break;
- }
+ return true;
+
+ }
+
+ break;
+ }
}
- return currentDistance;
+ return false;
}
///
@@ -460,20 +462,33 @@ namespace Avalonia.Media.TextFormatting
var startIndex = currentRun.Text.Start + offset;
- var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(
- currentShapedRun.ShapedBuffer.IsLeftToRight ?
- new CharacterHit(startIndex + remainingLength) :
- new CharacterHit(startIndex));
+ double startOffset;
+ double endOffset;
- endX += endOffset;
+ if (currentShapedRun.ShapedBuffer.IsLeftToRight)
+ {
+ startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
+
+ endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
+ }
+ else
+ {
+ endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
- var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(
- currentShapedRun.ShapedBuffer.IsLeftToRight ?
- new CharacterHit(startIndex) :
- new CharacterHit(startIndex + remainingLength));
+ if (currentPosition < startIndex)
+ {
+ startOffset = endOffset;
+ }
+ else
+ {
+ startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
+ }
+ }
startX += startOffset;
+ endX += endOffset;
+
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
@@ -504,47 +519,40 @@ namespace Avalonia.Media.TextFormatting
}
//Lines that only contain a linebreak need to be covered here
- if(characterLength == 0)
+ if (characterLength == 0)
{
characterLength = NewLineLength;
}
- var runwidth = endX - startX;
- var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runwidth, Height), currentPosition, characterLength, currentRun);
+ var runWidth = endX - startX;
+ var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
- if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX))
+ if (!MathUtilities.IsZero(runWidth) || NewLineLength > 0)
{
- currentRect = currentRect.WithWidth(currentWidth + runwidth);
+ if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX))
+ {
+ currentRect = currentRect.WithWidth(currentWidth + runWidth);
- var textBounds = result[result.Count - 1];
+ var textBounds = result[result.Count - 1];
- textBounds.Rectangle = currentRect;
+ textBounds.Rectangle = currentRect;
- textBounds.TextRunBounds.Add(currentRunBounds);
- }
- else
- {
- currentRect = currentRunBounds.Rectangle;
+ textBounds.TextRunBounds.Add(currentRunBounds);
+ }
+ else
+ {
+ currentRect = currentRunBounds.Rectangle;
- result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds }));
+ result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds }));
+ }
}
- currentWidth += runwidth;
+ currentWidth += runWidth;
currentPosition += characterLength;
- if (currentDirection == FlowDirection.LeftToRight)
- {
- if (currentPosition > characterIndex)
- {
- break;
- }
- }
- else
+ if (currentPosition > characterIndex)
{
- if (currentPosition <= firstTextSourceIndex)
- {
- break;
- }
+ break;
}
startX = endX;
@@ -571,7 +579,7 @@ namespace Avalonia.Media.TextFormatting
var currentPosition = FirstTextSourceIndex;
var remainingLength = textLength;
- var startX = Start + WidthIncludingTrailingWhitespace;
+ var startX = WidthIncludingTrailingWhitespace;
double currentWidth = 0;
var currentRect = Rect.Empty;
@@ -582,7 +590,7 @@ namespace Avalonia.Media.TextFormatting
continue;
}
- if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
+ if (currentPosition + currentRun.TextSourceLength < firstTextSourceIndex)
{
startX -= currentRun.Size.Width;
@@ -601,20 +609,31 @@ namespace Avalonia.Media.TextFormatting
currentPosition += offset;
var startIndex = currentRun.Text.Start + offset;
+ double startOffset;
+ double endOffset;
- var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(
- currentShapedRun.ShapedBuffer.IsLeftToRight ?
- new CharacterHit(startIndex + remainingLength) :
- new CharacterHit(startIndex));
+ if (currentShapedRun.ShapedBuffer.IsLeftToRight)
+ {
+ if (currentPosition < startIndex)
+ {
+ startOffset = endOffset = 0;
+ }
+ else
+ {
+ endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
- endX += endOffset - currentShapedRun.Size.Width;
+ startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
+ }
+ }
+ else
+ {
+ endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
- var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(
- currentShapedRun.ShapedBuffer.IsLeftToRight ?
- new CharacterHit(startIndex) :
- new CharacterHit(startIndex + remainingLength));
+ startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
+ }
- startX += startOffset - currentShapedRun.Size.Width;
+ startX -= currentRun.Size.Width - startOffset;
+ endX -= currentRun.Size.Width - endOffset;
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
@@ -652,41 +671,35 @@ namespace Avalonia.Media.TextFormatting
}
var runWidth = endX - startX;
- var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
- if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX))
+ var currentRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun);
+
+ if(!MathUtilities.IsZero(runWidth) || NewLineLength > 0)
{
- currentRect = currentRect.WithWidth(currentWidth + runWidth);
+ if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, Start + startX))
+ {
+ currentRect = currentRect.WithWidth(currentWidth + runWidth);
- var textBounds = result[result.Count - 1];
+ var textBounds = result[result.Count - 1];
- textBounds.Rectangle = currentRect;
+ textBounds.Rectangle = currentRect;
- textBounds.TextRunBounds.Add(currentRunBounds);
- }
- else
- {
- currentRect = currentRunBounds.Rectangle;
+ textBounds.TextRunBounds.Add(currentRunBounds);
+ }
+ else
+ {
+ currentRect = currentRunBounds.Rectangle;
- result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds }));
- }
+ result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds }));
+ }
+ }
currentWidth += runWidth;
currentPosition += characterLength;
- if (currentDirection == FlowDirection.LeftToRight)
- {
- if (currentPosition > characterIndex)
- {
- break;
- }
- }
- else
+ if (currentPosition > characterIndex)
{
- if (currentPosition <= firstTextSourceIndex)
- {
- break;
- }
+ break;
}
lastDirection = currentDirection;
@@ -698,6 +711,8 @@ namespace Avalonia.Media.TextFormatting
}
}
+ result.Reverse();
+
return result;
}
@@ -1302,8 +1317,14 @@ namespace Avalonia.Media.TextFormatting
switch (textAlignment)
{
case TextAlignment.Center:
- return Math.Max(0, (_paragraphWidth - width) / 2);
+ var start = (_paragraphWidth - width) / 2;
+
+ if(paragraphFlowDirection == FlowDirection.RightToLeft)
+ {
+ start -= (widthIncludingTrailingWhitespace - width);
+ }
+ return Math.Max(0, start);
case TextAlignment.Right:
return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace);
diff --git a/src/Avalonia.Base/Platform/IGeometryImpl.cs b/src/Avalonia.Base/Platform/IGeometryImpl.cs
index c80f8923ef..5826cfb2ff 100644
--- a/src/Avalonia.Base/Platform/IGeometryImpl.cs
+++ b/src/Avalonia.Base/Platform/IGeometryImpl.cs
@@ -38,8 +38,8 @@ namespace Avalonia.Platform
/// Intersects the geometry with another geometry.
///
/// The other geometry.
- /// A new representing the intersection.
- IGeometryImpl Intersect(IGeometryImpl geometry);
+ /// A new representing the intersection or null when the operation failed.
+ IGeometryImpl? Intersect(IGeometryImpl geometry);
///
/// Indicates whether the geometry's stroke contains the specified point.
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml
index ebecd65cc3..db1fa3ee4e 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Default/Default.xaml
@@ -37,4 +37,8 @@
+
+
+
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml
index a4d5ff673f..907b00dfff 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPicker.xaml
@@ -1,14 +1,13 @@
-
+
-
-
- 5,5,0,0
-
+
+ 5,5,0,0
-
+
-
+ -->
-
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml
index 74f33d1258..1c4a44d081 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorPreviewer.xaml
@@ -1,15 +1,14 @@
-
+
-
-
- 80
- 40
-
+
+ 80
+ 40
-
+
-
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml
index 162ac372de..eb67ada334 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSlider.xaml
@@ -1,188 +1,190 @@
-
+
-
+
-
+
-
+
-
-
+
+
+
+
+
+
-
-
-
-
+
+
-
-
+
-
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml
index dba4ad19f5..f95721c881 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorSpectrum.xaml
@@ -1,9 +1,10 @@
-
+
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
-
+
+
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml
index e25e822f3f..993745b1e5 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml
@@ -1,86 +1,85 @@
-
+
-
-
-
-
-
-
- 48
- 30
- 80
-
-
- M3 2C3.27614 2 3.5 2.22386 3.5 2.5V5.5C3.5 5.77614 3.72386 6 4 6H16C16.2761 6 16.5 5.77614
- 16.5 5.5V2.5C16.5 2.22386 16.7239 2 17 2C17.2761 2 17.5 2.22386 17.5 2.5V5.5C17.5 6.32843
- 16.8284 7 16 7H15.809L12.2236 14.1708C12.0615 14.4951 11.7914 14.7431 11.4695
- 14.8802C11.4905 15.0808 11.5 15.2891 11.5 15.5C11.5 16.0818 11.4278 16.6623 11.2268
- 17.1165C11.019 17.5862 10.6266 18 10 18C9.37343 18 8.98105 17.5862 8.77323 17.1165C8.57222
- 16.6623 8.5 16.0818 8.5 15.5C8.5 15.2891 8.50952 15.0808 8.53051 14.8802C8.20863 14.7431
- 7.93851 14.4951 7.77639 14.1708L4.19098 7H4C3.17157 7 2.5 6.32843 2.5 5.5V2.5C2.5 2.22386
- 2.72386 2 3 2ZM9.11803 14H10.882C11.0714 14 11.2445 13.893 11.3292 13.7236L14.691
- 7H5.30902L8.67082 13.7236C8.75552 13.893 8.92865 14 9.11803 14ZM9.52346 15C9.50787 15.1549
- 9.5 15.3225 9.5 15.5C9.5 16.0228 9.56841 16.4423 9.6877 16.7119C9.8002 16.9661 9.90782 17
- 10 17C10.0922 17 10.1998 16.9661 10.3123 16.7119C10.4316 16.4423 10.5 16.0228 10.5
- 15.5C10.5 15.3225 10.4921 15.1549 10.4765 15H9.52346Z
-
-
-
- M9.75003 6.5C10.1642 6.5 10.5 6.16421 10.5 5.75C10.5 5.33579 10.1642 5 9.75003 5C9.33582
- 5 9.00003 5.33579 9.00003 5.75C9.00003 6.16421 9.33582 6.5 9.75003 6.5ZM12.75 7.5C13.1642
- 7.5 13.5 7.16421 13.5 6.75C13.5 6.33579 13.1642 6 12.75 6C12.3358 6 12 6.33579 12 6.75C12
- 7.16421 12.3358 7.5 12.75 7.5ZM15.25 9C15.25 9.41421 14.9142 9.75 14.5 9.75C14.0858 9.75
- 13.75 9.41421 13.75 9C13.75 8.58579 14.0858 8.25 14.5 8.25C14.9142 8.25 15.25 8.58579
- 15.25 9ZM14.5 12.75C14.9142 12.75 15.25 12.4142 15.25 12C15.25 11.5858 14.9142 11.25 14.5
- 11.25C14.0858 11.25 13.75 11.5858 13.75 12C13.75 12.4142 14.0858 12.75 14.5 12.75ZM13.25
- 14C13.25 14.4142 12.9142 14.75 12.5 14.75C12.0858 14.75 11.75 14.4142 11.75 14C11.75
- 13.5858 12.0858 13.25 12.5 13.25C12.9142 13.25 13.25 13.5858 13.25 14ZM13.6972
- 2.99169C10.9426 1.57663 8.1432 1.7124 5.77007 3.16636C4.55909 3.9083 3.25331 5.46925
- 2.51605 7.05899C2.14542 7.85816 1.89915 8.70492 1.90238 9.49318C1.90566 10.2941 2.16983
- 11.0587 2.84039 11.6053C3.45058 12.1026 3.98165 12.353 4.49574 12.3784C5.01375 12.404
- 5.41804 12.1942 5.73429 12.0076C5.80382 11.9666 5.86891 11.927 5.93113 11.8892C6.17332
- 11.7421 6.37205 11.6214 6.62049 11.5426C6.90191 11.4534 7.2582 11.4205 7.77579
- 11.5787C7.96661 11.637 8.08161 11.7235 8.16212 11.8229C8.24792 11.9289 8.31662 12.0774
- 8.36788 12.2886C8.41955 12.5016 8.44767 12.7527 8.46868 13.0491C8.47651 13.1594 8.48379
- 13.2855 8.49142 13.4176C8.50252 13.6098 8.51437 13.8149 8.52974 14.0037C8.58435 14.6744
- 8.69971 15.4401 9.10362 16.1357C9.51764 16.8488 10.2047 17.439 11.307 17.8158C12.9093
- 18.3636 14.3731 17.9191 15.5126 17.0169C16.6391 16.125 17.4691 14.7761 17.8842
- 13.4272C19.1991 9.15377 17.6728 5.03394 13.6972 2.99169ZM6.29249 4.01905C8.35686 2.75426
- 10.7844 2.61959 13.2403 3.88119C16.7473 5.68275 18.1135 9.28161 16.9284 13.1332C16.5624
- 14.3227 15.8338 15.4871 14.8919 16.2329C13.963 16.9684 12.8486 17.286 11.6305
- 16.8696C10.7269 16.5607 10.2467 16.1129 9.96842 15.6336C9.68001 15.1369 9.57799 14.5556
- 9.52644 13.9225C9.51101 13.733 9.50132 13.5621 9.49147 13.3884C9.48399 13.2564 9.47642
- 13.1229 9.46618 12.9783C9.44424 12.669 9.41175 12.3499 9.33968 12.0529C9.26719 11.7541
- 9.14902 11.4527 8.93935 11.1937C8.72439 10.9282 8.43532 10.7346 8.06801 10.6223C7.36648
- 10.408 6.80266 10.4359 6.31839 10.5893C5.94331 10.7082 5.62016 10.9061 5.37179
- 11.0582C5.31992 11.0899 5.2713 11.1197 5.22616 11.1463C4.94094 11.3146 4.75357 11.39
- 4.54514 11.3796C4.33279 11.3691 4.00262 11.2625 3.47218 10.8301C3.0866 10.5158 2.90473
- 10.0668 2.90237 9.48908C2.89995 8.89865 3.08843 8.20165 3.42324 7.47971C4.09686 6.0272
- 5.28471 4.63649 6.29249 4.01905Z
-
-
-
- M14.95 5C14.7184 3.85888 13.7095 3 12.5 3C11.2905 3 10.2816 3.85888 10.05 5H2.5C2.22386
- 5 2 5.22386 2 5.5C2 5.77614 2.22386 6 2.5 6H10.05C10.2816 7.14112 11.2905 8 12.5 8C13.7297
- 8 14.752 7.11217 14.961 5.94254C14.9575 5.96177 14.9539 5.98093 14.95 6H17.5C17.7761 6 18
- 5.77614 18 5.5C18 5.22386 17.7761 5 17.5 5H14.95ZM12.5 7C11.6716 7 11 6.32843 11 5.5C11
- 4.67157 11.6716 4 12.5 4C13.3284 4 14 4.67157 14 5.5C14 6.32843 13.3284 7 12.5 7ZM9.94999
- 14C9.71836 12.8589 8.70948 12 7.5 12C6.29052 12 5.28164 12.8589 5.05001 14H2.5C2.22386
- 14 2 14.2239 2 14.5C2 14.7761 2.22386 15 2.5 15H5.05001C5.28164 16.1411 6.29052 17 7.5
- 17C8.70948 17 9.71836 16.1411 9.94999 15H17.5C17.7761 15 18 14.7761 18 14.5C18 14.2239
- 17.7761 14 17.5 14H9.94999ZM7.5 16C6.67157 16 6 15.3284 6 14.5C6 13.6716 6.67157 13 7.5
- 13C8.32843 13 9 13.6716 9 14.5C9 15.3284 8.32843 16 7.5 16Z
-
-
+
+
+
+
+
+ 48
+ 30
+ 80
+
+
+ M3 2C3.27614 2 3.5 2.22386 3.5 2.5V5.5C3.5 5.77614 3.72386 6 4 6H16C16.2761 6 16.5 5.77614
+ 16.5 5.5V2.5C16.5 2.22386 16.7239 2 17 2C17.2761 2 17.5 2.22386 17.5 2.5V5.5C17.5 6.32843
+ 16.8284 7 16 7H15.809L12.2236 14.1708C12.0615 14.4951 11.7914 14.7431 11.4695
+ 14.8802C11.4905 15.0808 11.5 15.2891 11.5 15.5C11.5 16.0818 11.4278 16.6623 11.2268
+ 17.1165C11.019 17.5862 10.6266 18 10 18C9.37343 18 8.98105 17.5862 8.77323 17.1165C8.57222
+ 16.6623 8.5 16.0818 8.5 15.5C8.5 15.2891 8.50952 15.0808 8.53051 14.8802C8.20863 14.7431
+ 7.93851 14.4951 7.77639 14.1708L4.19098 7H4C3.17157 7 2.5 6.32843 2.5 5.5V2.5C2.5 2.22386
+ 2.72386 2 3 2ZM9.11803 14H10.882C11.0714 14 11.2445 13.893 11.3292 13.7236L14.691
+ 7H5.30902L8.67082 13.7236C8.75552 13.893 8.92865 14 9.11803 14ZM9.52346 15C9.50787 15.1549
+ 9.5 15.3225 9.5 15.5C9.5 16.0228 9.56841 16.4423 9.6877 16.7119C9.8002 16.9661 9.90782 17
+ 10 17C10.0922 17 10.1998 16.9661 10.3123 16.7119C10.4316 16.4423 10.5 16.0228 10.5
+ 15.5C10.5 15.3225 10.4921 15.1549 10.4765 15H9.52346Z
+
+
+
+ M9.75003 6.5C10.1642 6.5 10.5 6.16421 10.5 5.75C10.5 5.33579 10.1642 5 9.75003 5C9.33582
+ 5 9.00003 5.33579 9.00003 5.75C9.00003 6.16421 9.33582 6.5 9.75003 6.5ZM12.75 7.5C13.1642
+ 7.5 13.5 7.16421 13.5 6.75C13.5 6.33579 13.1642 6 12.75 6C12.3358 6 12 6.33579 12 6.75C12
+ 7.16421 12.3358 7.5 12.75 7.5ZM15.25 9C15.25 9.41421 14.9142 9.75 14.5 9.75C14.0858 9.75
+ 13.75 9.41421 13.75 9C13.75 8.58579 14.0858 8.25 14.5 8.25C14.9142 8.25 15.25 8.58579
+ 15.25 9ZM14.5 12.75C14.9142 12.75 15.25 12.4142 15.25 12C15.25 11.5858 14.9142 11.25 14.5
+ 11.25C14.0858 11.25 13.75 11.5858 13.75 12C13.75 12.4142 14.0858 12.75 14.5 12.75ZM13.25
+ 14C13.25 14.4142 12.9142 14.75 12.5 14.75C12.0858 14.75 11.75 14.4142 11.75 14C11.75
+ 13.5858 12.0858 13.25 12.5 13.25C12.9142 13.25 13.25 13.5858 13.25 14ZM13.6972
+ 2.99169C10.9426 1.57663 8.1432 1.7124 5.77007 3.16636C4.55909 3.9083 3.25331 5.46925
+ 2.51605 7.05899C2.14542 7.85816 1.89915 8.70492 1.90238 9.49318C1.90566 10.2941 2.16983
+ 11.0587 2.84039 11.6053C3.45058 12.1026 3.98165 12.353 4.49574 12.3784C5.01375 12.404
+ 5.41804 12.1942 5.73429 12.0076C5.80382 11.9666 5.86891 11.927 5.93113 11.8892C6.17332
+ 11.7421 6.37205 11.6214 6.62049 11.5426C6.90191 11.4534 7.2582 11.4205 7.77579
+ 11.5787C7.96661 11.637 8.08161 11.7235 8.16212 11.8229C8.24792 11.9289 8.31662 12.0774
+ 8.36788 12.2886C8.41955 12.5016 8.44767 12.7527 8.46868 13.0491C8.47651 13.1594 8.48379
+ 13.2855 8.49142 13.4176C8.50252 13.6098 8.51437 13.8149 8.52974 14.0037C8.58435 14.6744
+ 8.69971 15.4401 9.10362 16.1357C9.51764 16.8488 10.2047 17.439 11.307 17.8158C12.9093
+ 18.3636 14.3731 17.9191 15.5126 17.0169C16.6391 16.125 17.4691 14.7761 17.8842
+ 13.4272C19.1991 9.15377 17.6728 5.03394 13.6972 2.99169ZM6.29249 4.01905C8.35686 2.75426
+ 10.7844 2.61959 13.2403 3.88119C16.7473 5.68275 18.1135 9.28161 16.9284 13.1332C16.5624
+ 14.3227 15.8338 15.4871 14.8919 16.2329C13.963 16.9684 12.8486 17.286 11.6305
+ 16.8696C10.7269 16.5607 10.2467 16.1129 9.96842 15.6336C9.68001 15.1369 9.57799 14.5556
+ 9.52644 13.9225C9.51101 13.733 9.50132 13.5621 9.49147 13.3884C9.48399 13.2564 9.47642
+ 13.1229 9.46618 12.9783C9.44424 12.669 9.41175 12.3499 9.33968 12.0529C9.26719 11.7541
+ 9.14902 11.4527 8.93935 11.1937C8.72439 10.9282 8.43532 10.7346 8.06801 10.6223C7.36648
+ 10.408 6.80266 10.4359 6.31839 10.5893C5.94331 10.7082 5.62016 10.9061 5.37179
+ 11.0582C5.31992 11.0899 5.2713 11.1197 5.22616 11.1463C4.94094 11.3146 4.75357 11.39
+ 4.54514 11.3796C4.33279 11.3691 4.00262 11.2625 3.47218 10.8301C3.0866 10.5158 2.90473
+ 10.0668 2.90237 9.48908C2.89995 8.89865 3.08843 8.20165 3.42324 7.47971C4.09686 6.0272
+ 5.28471 4.63649 6.29249 4.01905Z
+
+
+
+ M14.95 5C14.7184 3.85888 13.7095 3 12.5 3C11.2905 3 10.2816 3.85888 10.05 5H2.5C2.22386
+ 5 2 5.22386 2 5.5C2 5.77614 2.22386 6 2.5 6H10.05C10.2816 7.14112 11.2905 8 12.5 8C13.7297
+ 8 14.752 7.11217 14.961 5.94254C14.9575 5.96177 14.9539 5.98093 14.95 6H17.5C17.7761 6 18
+ 5.77614 18 5.5C18 5.22386 17.7761 5 17.5 5H14.95ZM12.5 7C11.6716 7 11 6.32843 11 5.5C11
+ 4.67157 11.6716 4 12.5 4C13.3284 4 14 4.67157 14 5.5C14 6.32843 13.3284 7 12.5 7ZM9.94999
+ 14C9.71836 12.8589 8.70948 12 7.5 12C6.29052 12 5.28164 12.8589 5.05001 14H2.5C2.22386
+ 14 2 14.2239 2 14.5C2 14.7761 2.22386 15 2.5 15H5.05001C5.28164 16.1411 6.29052 17 7.5
+ 17C8.70948 17 9.71836 16.1411 9.94999 15H17.5C17.7761 15 18 14.7761 18 14.5C18 14.2239
+ 17.7761 14 17.5 14H9.94999ZM7.5 16C6.67157 16 6 15.3284 6 14.5C6 13.6716 6.67157 13 7.5
+ 13C8.32843 13 9 13.6716 9 14.5C9 15.3284 8.32843 16 7.5 16Z
+
-
+
-
+
diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml
index 186b6de9bc..a5a94a2322 100644
--- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml
+++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml
@@ -3,42 +3,48 @@
xmlns:converters="using:Avalonia.Controls.Converters">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls/Documents/LineBreak.cs b/src/Avalonia.Controls/Documents/LineBreak.cs
index aeb81f7313..108a38d86b 100644
--- a/src/Avalonia.Controls/Documents/LineBreak.cs
+++ b/src/Avalonia.Controls/Documents/LineBreak.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
-using Avalonia.LogicalTree;
using Avalonia.Media.TextFormatting;
using Avalonia.Metadata;
@@ -22,7 +21,13 @@ namespace Avalonia.Controls.Documents
internal override void BuildTextRun(IList textRuns)
{
- textRuns.Add(new TextEndOfLine());
+ var text = Environment.NewLine.AsMemory();
+
+ var textRunProperties = CreateTextRunProperties();
+
+ var textCharacters = new TextCharacters(text, textRunProperties);
+
+ textRuns.Add(textCharacters);
}
internal override void AppendText(StringBuilder stringBuilder)
diff --git a/src/Avalonia.Controls/Platform/PlatformManager.cs b/src/Avalonia.Controls/Platform/PlatformManager.cs
index 92f6f1cb52..de7708e869 100644
--- a/src/Avalonia.Controls/Platform/PlatformManager.cs
+++ b/src/Avalonia.Controls/Platform/PlatformManager.cs
@@ -20,17 +20,8 @@ namespace Avalonia.Controls.Platform
{
}
- public static ITrayIconImpl? CreateTrayIcon()
- {
- var platform = AvaloniaLocator.Current.GetService();
-
- if (platform == null)
- {
- throw new Exception("Could not CreateTrayIcon(): IWindowingPlatform is not registered.");
- }
-
- return s_designerMode ? null : platform.CreateTrayIcon();
- }
+ public static ITrayIconImpl? CreateTrayIcon() =>
+ s_designerMode ? null : AvaloniaLocator.Current.GetService()?.CreateTrayIcon();
public static IWindowImpl CreateWindow()
diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs
index d0e8e8f1a0..56b9caf085 100644
--- a/src/Avalonia.Controls/ProgressBar.cs
+++ b/src/Avalonia.Controls/ProgressBar.cs
@@ -100,6 +100,7 @@ namespace Avalonia.Controls
private double _indeterminateStartingOffset;
private double _indeterminateEndingOffset;
private Border? _indicator;
+ private IDisposable? _trackSizeChangedListener;
public static readonly StyledProperty IsIndeterminateProperty =
AvaloniaProperty.Register(nameof(IsIndeterminate));
@@ -195,8 +196,9 @@ namespace Avalonia.Controls
///
protected override Size ArrangeOverride(Size finalSize)
{
+ var result = base.ArrangeOverride(finalSize);
UpdateIndicator();
- return base.ArrangeOverride(finalSize);
+ return result;
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
@@ -216,8 +218,15 @@ namespace Avalonia.Controls
///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
+ // dispose any previous track size listener
+ _trackSizeChangedListener?.Dispose();
+
_indicator = e.NameScope.Get("PART_Indicator");
+ // listen to size changes of the indicators track (parent) and update the indicator there.
+ _trackSizeChangedListener = _indicator.Parent?.GetPropertyChangedObservable(BoundsProperty)
+ .Subscribe(_ => UpdateIndicator());
+
UpdateIndicator();
}
diff --git a/src/Avalonia.Controls/RichTextBlock.cs b/src/Avalonia.Controls/RichTextBlock.cs
index 9b5afaef5d..0c8b1d125d 100644
--- a/src/Avalonia.Controls/RichTextBlock.cs
+++ b/src/Avalonia.Controls/RichTextBlock.cs
@@ -41,9 +41,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty SelectionBrushProperty =
AvaloniaProperty.Register(nameof(SelectionBrush), Brushes.Blue);
- public static readonly StyledProperty SelectionForegroundBrushProperty =
- AvaloniaProperty.Register(nameof(SelectionForegroundBrush));
-
///
/// Defines the property.
///
@@ -63,12 +60,13 @@ namespace Avalonia.Controls
private bool _canCopy;
private int _selectionStart;
private int _selectionEnd;
+ private int _wordSelectionStart = -1;
static RichTextBlock()
{
FocusableProperty.OverrideDefaultValue(typeof(RichTextBlock), true);
- AffectsRender(SelectionStartProperty, SelectionEndProperty, SelectionForegroundBrushProperty, SelectionBrushProperty);
+ AffectsRender(SelectionStartProperty, SelectionEndProperty, SelectionBrushProperty, IsTextSelectionEnabledProperty);
}
public RichTextBlock()
@@ -89,15 +87,6 @@ namespace Avalonia.Controls
set => SetValue(SelectionBrushProperty, value);
}
- ///
- /// Gets or sets a value that defines the brush used for selected text.
- ///
- public IBrush? SelectionForegroundBrush
- {
- get => GetValue(SelectionForegroundBrushProperty);
- set => SetValue(SelectionForegroundBrushProperty, value);
- }
-
///
/// Gets or sets a character index for the beginning of the current selection.
///
@@ -200,7 +189,7 @@ namespace Avalonia.Controls
}
}
- public override void Render(DrawingContext context)
+ protected override void RenderTextLayout(DrawingContext context, Point origin)
{
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
@@ -215,13 +204,16 @@ namespace Avalonia.Controls
var rects = TextLayout.HitTestTextRange(start, length);
- foreach (var rect in rects)
+ using (context.PushPostTransform(Matrix.CreateTranslation(origin)))
{
- context.FillRectangle(selectionBrush, PixelRect.FromRect(rect, 1).ToRect(1));
+ foreach (var rect in rects)
+ {
+ context.FillRectangle(selectionBrush, PixelRect.FromRect(rect, 1).ToRect(1));
+ }
}
}
- base.Render(context);
+ base.RenderTextLayout(context, origin);
}
///
@@ -297,8 +289,9 @@ namespace Avalonia.Controls
/// A object.
protected override TextLayout CreateTextLayout(string? text)
{
+ var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
var defaultProperties = new GenericTextRunProperties(
- new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
+ typeface,
FontSize,
TextDecorations,
Foreground);
@@ -345,6 +338,8 @@ namespace Avalonia.Controls
protected override void OnKeyDown(KeyEventArgs e)
{
+ base.OnKeyDown(e);
+
var handled = false;
var modifiers = e.KeyModifiers;
var keymap = AvaloniaLocator.Current.GetRequiredService();
@@ -363,6 +358,8 @@ namespace Avalonia.Controls
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
+ base.OnPointerPressed(e);
+
if (!IsTextSelectionEnabled)
{
return;
@@ -373,7 +370,9 @@ namespace Avalonia.Controls
if (text != null && clickInfo.Properties.IsLeftButtonPressed)
{
- var point = e.GetPosition(this);
+ var padding = Padding;
+
+ var point = e.GetPosition(this) - new Point(padding.Left, padding.Top);
var clickToSelect = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
@@ -382,8 +381,6 @@ namespace Avalonia.Controls
var hit = TextLayout.HitTestPoint(point);
var index = hit.TextPosition;
- SelectionStart = SelectionEnd = index;
-
#pragma warning disable CS0618 // Type or member is obsolete
switch (e.ClickCount)
#pragma warning restore CS0618 // Type or member is obsolete
@@ -391,12 +388,34 @@ namespace Avalonia.Controls
case 1:
if (clickToSelect)
{
- SelectionStart = Math.Min(oldIndex, index);
- SelectionEnd = Math.Max(oldIndex, index);
+ if (_wordSelectionStart >= 0)
+ {
+ var previousWord = StringUtils.PreviousWord(text, index);
+
+ if (index > _wordSelectionStart)
+ {
+ SelectionEnd = StringUtils.NextWord(text, index);
+ }
+
+ if (index < _wordSelectionStart || previousWord == _wordSelectionStart)
+ {
+ SelectionStart = previousWord;
+ }
+ }
+ else
+ {
+ SelectionStart = Math.Min(oldIndex, index);
+ SelectionEnd = Math.Max(oldIndex, index);
+ }
}
else
{
- SelectionStart = SelectionEnd = index;
+ if (_wordSelectionStart == -1 || index < SelectionStart || index > SelectionEnd)
+ {
+ SelectionStart = SelectionEnd = index;
+
+ _wordSelectionStart = -1;
+ }
}
break;
@@ -406,9 +425,13 @@ namespace Avalonia.Controls
SelectionStart = StringUtils.PreviousWord(text, index);
}
+ _wordSelectionStart = SelectionStart;
+
SelectionEnd = StringUtils.NextWord(text, index);
break;
case 3:
+ _wordSelectionStart = -1;
+
SelectAll();
break;
}
@@ -420,6 +443,8 @@ namespace Avalonia.Controls
protected override void OnPointerMoved(PointerEventArgs e)
{
+ base.OnPointerMoved(e);
+
if (!IsTextSelectionEnabled)
{
return;
@@ -428,20 +453,49 @@ namespace Avalonia.Controls
// selection should not change during pointer move if the user right clicks
if (e.Pointer.Captured == this && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
- var point = e.GetPosition(this);
+ var text = Text;
+ var padding = Padding;
+
+ var point = e.GetPosition(this) - new Point(padding.Left, padding.Top);
point = new Point(
- MathUtilities.Clamp(point.X, 0, Math.Max(Bounds.Width - 1, 0)),
- MathUtilities.Clamp(point.Y, 0, Math.Max(Bounds.Height - 1, 0)));
+ MathUtilities.Clamp(point.X, 0, Math.Max(TextLayout.Bounds.Width, 0)),
+ MathUtilities.Clamp(point.Y, 0, Math.Max(TextLayout.Bounds.Width, 0)));
var hit = TextLayout.HitTestPoint(point);
+ var textPosition = hit.TextPosition;
+
+ if (text != null && _wordSelectionStart >= 0)
+ {
+ var distance = textPosition - _wordSelectionStart;
+
+ if (distance <= 0)
+ {
+ SelectionStart = StringUtils.PreviousWord(text, textPosition);
+ }
+
+ if (distance >= 0)
+ {
+ if (SelectionStart != _wordSelectionStart)
+ {
+ SelectionStart = _wordSelectionStart;
+ }
+
+ SelectionEnd = StringUtils.NextWord(text, textPosition);
+ }
+ }
+ else
+ {
+ SelectionEnd = textPosition;
+ }
- SelectionEnd = hit.TextPosition;
}
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
+ base.OnPointerReleased(e);
+
if (!IsTextSelectionEnabled)
{
return;
@@ -454,7 +508,9 @@ namespace Avalonia.Controls
if (e.InitialPressMouseButton == MouseButton.Right)
{
- var point = e.GetPosition(this);
+ var padding = Padding;
+
+ var point = e.GetPosition(this) - new Point(padding.Left, padding.Top);
var hit = TextLayout.HitTestPoint(point);
@@ -487,11 +543,6 @@ namespace Avalonia.Controls
InvalidateTextLayout();
break;
}
- case nameof(TextProperty):
- {
- InvalidateTextLayout();
- break;
- }
}
}
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index 80edaf4f26..99c8068b3d 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -505,7 +505,12 @@ namespace Avalonia.Controls
}
}
- TextLayout.Draw(context, new Point(padding.Left, top));
+ RenderTextLayout(context, new Point(padding.Left, top));
+ }
+
+ protected virtual void RenderTextLayout(DrawingContext context, Point origin)
+ {
+ TextLayout.Draw(context, origin);
}
void IAddChild.AddChild(string text)
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 9531f719b9..1b268db2f7 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -53,7 +53,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty PasswordCharProperty =
AvaloniaProperty.Register(nameof(PasswordChar));
-
+
public static readonly StyledProperty SelectionBrushProperty =
AvaloniaProperty.Register(nameof(SelectionBrush));
@@ -80,7 +80,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty MaxLinesProperty =
AvaloniaProperty.Register(nameof(MaxLines), defaultValue: 0);
-
+
public static readonly DirectProperty TextProperty =
TextBlock.TextProperty.AddOwnerWithDataValidation(
o => o.Text,
@@ -105,7 +105,7 @@ namespace Avalonia.Controls
public static readonly StyledProperty TextWrappingProperty =
TextBlock.TextWrappingProperty.AddOwner();
-
+
///
/// Defines see property.
///
@@ -202,6 +202,7 @@ namespace Avalonia.Controls
private string _newLine = Environment.NewLine;
private static readonly string[] invalidCharacters = new String[1] { "\u007f" };
+ private int _wordSelectionStart = -1;
private int _selectedTextChangesMadeSinceLastUndoSnapshot;
private bool _hasDoneSnapshotOnce;
private const int _maxCharsBeforeUndoSnapshot = 7;
@@ -275,7 +276,7 @@ namespace Avalonia.Controls
get => GetValue(IsReadOnlyProperty);
set => SetValue(IsReadOnlyProperty, value);
}
-
+
public char PasswordChar
{
get => GetValue(PasswordCharProperty);
@@ -307,7 +308,7 @@ namespace Avalonia.Controls
{
value = CoerceCaretIndex(value);
var changed = SetAndRaise(SelectionStartProperty, ref _selectionStart, value);
-
+
if (changed)
{
UpdateCommandStates();
@@ -327,12 +328,12 @@ namespace Avalonia.Controls
{
value = CoerceCaretIndex(value);
var changed = SetAndRaise(SelectionEndProperty, ref _selectionEnd, value);
-
+
if (changed)
{
UpdateCommandStates();
}
-
+
if (SelectionStart == value && CaretIndex != value)
{
CaretIndex = value;
@@ -351,7 +352,7 @@ namespace Avalonia.Controls
get => GetValue(MaxLinesProperty);
set => SetValue(MaxLinesProperty, value);
}
-
+
///
/// Gets or sets the line height.
///
@@ -370,7 +371,7 @@ namespace Avalonia.Controls
var caretIndex = CaretIndex;
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
-
+
CaretIndex = CoerceCaretIndex(caretIndex, value);
SelectionStart = CoerceCaretIndex(selectionStart, value);
SelectionEnd = CoerceCaretIndex(selectionEnd, value);
@@ -567,7 +568,7 @@ namespace Avalonia.Controls
_presenter = e.NameScope.Get("PART_TextPresenter");
_imClient.SetPresenter(_presenter, this);
-
+
if (IsFocused)
{
_presenter?.ShowCaret();
@@ -577,7 +578,7 @@ namespace Avalonia.Controls
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
-
+
if (IsFocused)
{
_presenter?.ShowCaret();
@@ -587,7 +588,7 @@ namespace Avalonia.Controls
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
-
+
_imClient.SetPresenter(null, null);
}
@@ -637,7 +638,7 @@ namespace Avalonia.Controls
}
UpdateCommandStates();
-
+
_imClient.SetPresenter(_presenter, this);
_presenter?.ShowCaret();
@@ -657,7 +658,7 @@ namespace Avalonia.Controls
UpdateCommandStates();
_presenter?.HideCaret();
-
+
_imClient.SetPresenter(null, null);
}
@@ -700,14 +701,14 @@ namespace Avalonia.Controls
if (grapheme.FirstCodepoint.IsBreakChar)
{
- if(lineCount + 1 > MaxLines)
+ if (lineCount + 1 > MaxLines)
{
break;
}
else
{
lineCount++;
- }
+ }
}
length += grapheme.Text.Length;
@@ -736,7 +737,7 @@ namespace Avalonia.Controls
text = Text ?? string.Empty;
SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex));
ClearSelection();
-
+
if (IsUndoEnabled)
{
_undoRedoHelper.DiscardRedo();
@@ -746,7 +747,7 @@ namespace Avalonia.Controls
{
RaisePropertyChanged(TextProperty, oldText, _text);
}
-
+
CaretIndex = caretIndex + input.Length;
}
}
@@ -828,7 +829,7 @@ namespace Avalonia.Controls
{
return;
}
-
+
var text = Text ?? string.Empty;
var caretIndex = CaretIndex;
var movement = false;
@@ -985,87 +986,87 @@ namespace Avalonia.Controls
break;
case Key.Up:
- {
- selection = DetectSelection();
-
- _presenter.MoveCaretVertical(LogicalDirection.Backward);
-
- if (caretIndex != _presenter.CaretIndex)
{
- movement = true;
- }
+ selection = DetectSelection();
- if (selection)
- {
- SelectionEnd = _presenter.CaretIndex;
- }
- else
- {
- CaretIndex = _presenter.CaretIndex;
+ _presenter.MoveCaretVertical(LogicalDirection.Backward);
+
+ if (caretIndex != _presenter.CaretIndex)
+ {
+ movement = true;
+ }
+
+ if (selection)
+ {
+ SelectionEnd = _presenter.CaretIndex;
+ }
+ else
+ {
+ CaretIndex = _presenter.CaretIndex;
+ }
+
+ break;
}
-
- break;
- }
case Key.Down:
- {
- selection = DetectSelection();
-
- _presenter.MoveCaretVertical();
-
- if (caretIndex != _presenter.CaretIndex)
- {
- movement = true;
- }
-
- if (selection)
- {
- SelectionEnd = _presenter.CaretIndex;
- }
- else
{
- CaretIndex = _presenter.CaretIndex;
+ selection = DetectSelection();
+
+ _presenter.MoveCaretVertical();
+
+ if (caretIndex != _presenter.CaretIndex)
+ {
+ movement = true;
+ }
+
+ if (selection)
+ {
+ SelectionEnd = _presenter.CaretIndex;
+ }
+ else
+ {
+ CaretIndex = _presenter.CaretIndex;
+ }
+
+ break;
}
-
- break;
- }
case Key.Back:
- {
- SnapshotUndoRedo();
-
- if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
{
- SetSelectionForControlBackspace();
- }
-
- if (!DeleteSelection())
- {
- var characterHit = _presenter.GetNextCharacterHit(LogicalDirection.Backward);
+ SnapshotUndoRedo();
- var backspacePosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
+ if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
+ {
+ SetSelectionForControlBackspace();
+ }
- if (caretIndex != backspacePosition)
+ if (!DeleteSelection())
{
- var start = Math.Min(backspacePosition, caretIndex);
- var end = Math.Max(backspacePosition, caretIndex);
+ var characterHit = _presenter.GetNextCharacterHit(LogicalDirection.Backward);
- var length = end - start;
+ var backspacePosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
- var editedText = text.Substring(0, start) + text.Substring(Math.Min(end, text.Length));
+ if (caretIndex != backspacePosition)
+ {
+ var start = Math.Min(backspacePosition, caretIndex);
+ var end = Math.Max(backspacePosition, caretIndex);
- SetTextInternal(editedText);
+ var length = end - start;
- CaretIndex = start;
- }
- }
-
- SnapshotUndoRedo();
+ var editedText = text.Substring(0, start) + text.Substring(Math.Min(end, text.Length));
- handled = true;
- break;
- }
+ SetTextInternal(editedText);
+
+ CaretIndex = start;
+ }
+ }
+
+ SnapshotUndoRedo();
+
+ handled = true;
+ break;
+ }
case Key.Delete:
SnapshotUndoRedo();
-
+
if (hasWholeWordModifiers && SelectionStart == SelectionEnd)
{
SetSelectionForControlDelete();
@@ -1077,7 +1078,7 @@ namespace Avalonia.Controls
var nextPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
- if(nextPosition != caretIndex)
+ if (nextPosition != caretIndex)
{
var start = Math.Min(nextPosition, caretIndex);
var end = Math.Max(nextPosition, caretIndex);
@@ -1144,7 +1145,7 @@ namespace Avalonia.Controls
{
return;
}
-
+
var text = Text;
var clickInfo = e.GetCurrentPoint(this);
@@ -1170,24 +1171,50 @@ namespace Avalonia.Controls
case 1:
if (clickToSelect)
{
- SelectionStart = Math.Min(oldIndex, index);
- SelectionEnd = Math.Max(oldIndex, index);
+ if (_wordSelectionStart >= 0)
+ {
+ var previousWord = StringUtils.PreviousWord(text, index);
+
+ if (index > _wordSelectionStart)
+ {
+ SelectionEnd = StringUtils.NextWord(text, index);
+ }
+
+ if (index < _wordSelectionStart || previousWord == _wordSelectionStart)
+ {
+ SelectionStart = previousWord;
+ }
+ }
+ else
+ {
+ SelectionStart = Math.Min(oldIndex, index);
+ SelectionEnd = Math.Max(oldIndex, index);
+ }
}
else
{
- SelectionStart = SelectionEnd = index;
+ if(_wordSelectionStart == -1 || index < SelectionStart || index > SelectionEnd)
+ {
+ SelectionStart = SelectionEnd = index;
+ _wordSelectionStart = -1;
+ }
}
break;
- case 2:
+ case 2:
+
if (!StringUtils.IsStartOfWord(text, index))
{
SelectionStart = StringUtils.PreviousWord(text, index);
}
+ _wordSelectionStart = SelectionStart;
+
SelectionEnd = StringUtils.NextWord(text, index);
break;
case 3:
+ _wordSelectionStart = -1;
+
SelectAll();
break;
}
@@ -1203,7 +1230,7 @@ namespace Avalonia.Controls
{
return;
}
-
+
// selection should not change during pointer move if the user right clicks
if (e.Pointer.Captured == _presenter && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
@@ -1215,7 +1242,32 @@ namespace Avalonia.Controls
_presenter.MoveCaretToPoint(point);
- SelectionEnd = _presenter.CaretIndex;
+ var caretIndex = _presenter.CaretIndex;
+ var text = Text;
+
+ if (text != null && _wordSelectionStart >= 0)
+ {
+ var distance = caretIndex - _wordSelectionStart;
+
+ if (distance <= 0)
+ {
+ SelectionStart = StringUtils.PreviousWord(text, caretIndex);
+ }
+
+ if (distance >= 0)
+ {
+ if(SelectionStart != _wordSelectionStart)
+ {
+ SelectionStart = _wordSelectionStart;
+ }
+
+ SelectionEnd = StringUtils.NextWord(text, caretIndex);
+ }
+ }
+ else
+ {
+ SelectionEnd = _presenter.CaretIndex;
+ }
}
}
@@ -1234,9 +1286,9 @@ namespace Avalonia.Controls
if (e.InitialPressMouseButton == MouseButton.Right)
{
var point = e.GetPosition(_presenter);
-
+
_presenter.MoveCaretToPoint(point);
-
+
var caretIndex = _presenter.CaretIndex;
// see if mouse clicked inside current selection
@@ -1250,7 +1302,7 @@ namespace Avalonia.Controls
CaretIndex = SelectionEnd = SelectionStart = caretIndex;
}
}
-
+
e.Pointer.Capture(null);
}
@@ -1309,7 +1361,7 @@ namespace Avalonia.Controls
{
return;
}
-
+
var text = Text ?? string.Empty;
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
@@ -1319,11 +1371,11 @@ namespace Avalonia.Controls
if (isSelecting)
{
_presenter.MoveCaretToTextPosition(selectionEnd);
-
+
_presenter.MoveCaretHorizontal(direction > 0 ?
LogicalDirection.Forward :
LogicalDirection.Backward);
-
+
SelectionEnd = _presenter.CaretIndex;
}
else
@@ -1347,7 +1399,7 @@ namespace Avalonia.Controls
else
{
int offset;
-
+
if (direction > 0)
{
offset = StringUtils.NextWord(text, selectionEnd) - selectionEnd;
@@ -1356,7 +1408,7 @@ namespace Avalonia.Controls
{
offset = StringUtils.PreviousWord(text, selectionEnd) - selectionEnd;
}
-
+
SelectionEnd += offset;
_presenter.MoveCaretToTextPosition(SelectionEnd);
@@ -1378,7 +1430,7 @@ namespace Avalonia.Controls
{
return;
}
-
+
var caretIndex = CaretIndex;
if (document)
@@ -1401,7 +1453,7 @@ namespace Avalonia.Controls
{
return;
}
-
+
var text = Text ?? string.Empty;
var caretIndex = CaretIndex;
@@ -1432,8 +1484,9 @@ namespace Avalonia.Controls
private bool DeleteSelection(bool raiseTextChanged = true)
{
- if (IsReadOnly) return true;
-
+ if (IsReadOnly)
+ return true;
+
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
@@ -1444,40 +1497,40 @@ namespace Avalonia.Controls
var text = Text!;
SetTextInternal(text.Substring(0, start) + text.Substring(end), raiseTextChanged);
-
+
_presenter?.MoveCaretToTextPosition(start);
-
- CaretIndex= start;
-
+
+ CaretIndex = start;
+
ClearSelection();
-
+
return true;
}
-
+
CaretIndex = SelectionStart;
-
+
return false;
}
private string GetSelection()
{
var text = Text;
-
+
if (string.IsNullOrEmpty(text))
{
return "";
}
-
+
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
var start = Math.Min(selectionStart, selectionEnd);
var end = Math.Max(selectionStart, selectionEnd);
-
+
if (start == end || (Text?.Length ?? 0) < end)
{
return "";
}
-
+
return text.Substring(start, end - start);
}
@@ -1496,7 +1549,7 @@ namespace Avalonia.Controls
private void SetSelectionForControlBackspace()
{
var selectionStart = CaretIndex;
-
+
MoveHorizontal(-1, true, false);
SelectionStart = selectionStart;
@@ -1508,9 +1561,9 @@ namespace Avalonia.Controls
{
return;
}
-
+
SelectionStart = CaretIndex;
-
+
MoveHorizontal(1, true, true);
if (SelectionEnd < _text.Length && _text[SelectionEnd] == ' ')
diff --git a/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs b/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
index 94e7728d68..3a8fdb8491 100644
--- a/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
+++ b/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
@@ -21,7 +21,7 @@ namespace Avalonia.OpenGL.Angle
var display = IntPtr.Zero;
AngleOptions.PlatformApi angleApi = default;
{
- if (_egl.GetPlatformDisplayEXT == null)
+ if (!_egl.IsGetPlatformDisplayExtAvailable)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll");
var allowedApis = AvaloniaLocator.Current.GetService()?.AllowedPlatformApis
@@ -37,7 +37,7 @@ namespace Avalonia.OpenGL.Angle
else
continue;
- display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
+ display = _egl.GetPlatformDisplayExt(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero,
new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE });
if (display != IntPtr.Zero)
{
diff --git a/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj b/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
index 76924d060f..bacb10c792 100644
--- a/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
+++ b/src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
@@ -11,4 +11,5 @@
+
diff --git a/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs b/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
index b3469c212b..68442c1fd3 100644
--- a/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
+++ b/src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
@@ -66,11 +66,9 @@ namespace Avalonia.OpenGL.Controls
return;
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderBuffer);
- if (_depthBuffer != 0) gl.DeleteRenderbuffers(1, new[] { _depthBuffer });
+ if (_depthBuffer != 0) gl.DeleteRenderbuffer(_depthBuffer);
- var oneArr = new int[1];
- gl.GenRenderbuffers(1, oneArr);
- _depthBuffer = oneArr[0];
+ _depthBuffer = gl.GenRenderbuffer();
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER,
GlVersion.Type == GlProfileType.OpenGLES ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT,
@@ -88,9 +86,9 @@ namespace Avalonia.OpenGL.Controls
var gl = _context.GlInterface;
gl.BindTexture(GL_TEXTURE_2D, 0);
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
- gl.DeleteFramebuffers(1, new[] { _fb });
+ gl.DeleteFramebuffer(_fb);
_fb = 0;
- gl.DeleteRenderbuffers(1, new[] { _depthBuffer });
+ gl.DeleteRenderbuffer(_depthBuffer);
_depthBuffer = 0;
_attachment?.Dispose();
_attachment = null;
@@ -174,9 +172,7 @@ namespace Avalonia.OpenGL.Controls
{
_depthBufferSize = GetPixelSize();
var gl = _context.GlInterface;
- var oneArr = new int[1];
- gl.GenFramebuffers(1, oneArr);
- _fb = oneArr[0];
+ _fb = gl.GenFramebuffer();
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
EnsureDepthBufferAttachment(gl);
diff --git a/src/Avalonia.OpenGL/Egl/EglContext.cs b/src/Avalonia.OpenGL/Egl/EglContext.cs
index bc517c3e27..e7b5dc7c83 100644
--- a/src/Avalonia.OpenGL/Egl/EglContext.cs
+++ b/src/Avalonia.OpenGL/Egl/EglContext.cs
@@ -24,7 +24,7 @@ namespace Avalonia.OpenGL.Egl
SampleCount = sampleCount;
StencilSize = stencilSize;
using (MakeCurrent())
- GlInterface = GlInterface.FromNativeUtf8GetProcAddress(version, b => _egl.GetProcAddress(b));
+ GlInterface = GlInterface.FromNativeUtf8GetProcAddress(version, _egl.GetProcAddress);
}
public IntPtr Context { get; }
diff --git a/src/Avalonia.OpenGL/Egl/EglDisplay.cs b/src/Avalonia.OpenGL/Egl/EglDisplay.cs
index 623364866b..d3d85e8c83 100644
--- a/src/Avalonia.OpenGL/Egl/EglDisplay.cs
+++ b/src/Avalonia.OpenGL/Egl/EglDisplay.cs
@@ -34,9 +34,9 @@ namespace Avalonia.OpenGL.Egl
}
else
{
- if (egl.GetPlatformDisplayEXT == null)
+ if (!egl.IsGetPlatformDisplayExtAvailable)
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl");
- display = egl.GetPlatformDisplayEXT(platformType, platformDisplay, attrs);
+ display = egl.GetPlatformDisplayExt(platformType, platformDisplay, attrs);
}
if (display == IntPtr.Zero)
diff --git a/src/Avalonia.OpenGL/Egl/EglInterface.cs b/src/Avalonia.OpenGL/Egl/EglInterface.cs
index 6148e58440..4fec8e5356 100644
--- a/src/Avalonia.OpenGL/Egl/EglInterface.cs
+++ b/src/Avalonia.OpenGL/Egl/EglInterface.cs
@@ -2,31 +2,26 @@
using System.Runtime.InteropServices;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
+using Avalonia.SourceGenerator;
namespace Avalonia.OpenGL.Egl
{
- public class EglInterface : GlInterfaceBase
+ public unsafe partial class EglInterface
{
- public EglInterface() : base(Load())
+ public EglInterface(Func getProcAddress)
{
-
- }
-
- public EglInterface(Func getProcAddress) : base(getProcAddress)
- {
-
+ Initialize(getProcAddress);
}
- public EglInterface(Func getProcAddress) : base(getProcAddress)
+ public EglInterface(string library) : this(Load(library))
{
-
}
-
- public EglInterface(string library) : base(Load(library))
+
+ public EglInterface() : this(Load())
{
+
}
-
static Func Load()
{
var os = AvaloniaLocator.Current.GetService().GetRuntimeInfo().OperatingSystem;
@@ -46,119 +41,75 @@ namespace Avalonia.OpenGL.Egl
}
// ReSharper disable UnassignedGetOnlyAutoProperty
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate int EglGetError();
- [GlEntryPoint("eglGetError")]
- public EglGetError GetError { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
- [GlEntryPoint("eglGetDisplay")]
- public EglGetDisplay GetDisplay { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglGetPlatformDisplayEXT(int platform, IntPtr nativeDisplay, int[] attrs);
- [GlEntryPoint("eglGetPlatformDisplayEXT")]
- [GlOptionalEntryPoint]
- public EglGetPlatformDisplayEXT GetPlatformDisplayEXT { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglInitialize(IntPtr display, out int major, out int minor);
- [GlEntryPoint("eglInitialize")]
- public EglInitialize Initialize { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglGetProcAddress(Utf8Buffer proc);
- [GlEntryPoint("eglGetProcAddress")]
- public EglGetProcAddress GetProcAddress { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglBindApi(int api);
- [GlEntryPoint("eglBindAPI")]
- public EglBindApi BindApi { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglChooseConfig(IntPtr display, int[] attribs,
- out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
- [GlEntryPoint("eglChooseConfig")]
- public EglChooseConfig ChooseConfig { get; }
+
+ [GetProcAddress("eglGetError")]
+ public partial int GetError();
+
+ [GetProcAddress("eglGetDisplay")]
+ public partial IntPtr GetDisplay(IntPtr nativeDisplay);
+
+ [GetProcAddress("eglGetPlatformDisplayEXT", true)]
+ public partial IntPtr GetPlatformDisplayExt(int platform, IntPtr nativeDisplay, int[] attrs);
+
+ [GetProcAddress("eglInitialize")]
+ public partial bool Initialize(IntPtr display, out int major, out int minor);
+
+ [GetProcAddress("eglGetProcAddress")]
+ public partial IntPtr GetProcAddress(IntPtr proc);
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglCreateContext(IntPtr display, IntPtr config,
+ [GetProcAddress("eglBindAPI")]
+ public partial bool BindApi(int api);
+
+ [GetProcAddress("eglChooseConfig")]
+ public partial bool ChooseConfig(IntPtr display, int[] attribs,
+ out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
+
+ [GetProcAddress("eglCreateContext")]
+ public partial IntPtr CreateContext(IntPtr display, IntPtr config,
IntPtr share, int[] attrs);
- [GlEntryPoint("eglCreateContext")]
- public EglCreateContext CreateContext { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglDestroyContext(IntPtr display, IntPtr context);
- [GlEntryPoint("eglDestroyContext")]
- public EglDestroyContext DestroyContext { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglCreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
- [GlEntryPoint("eglCreatePbufferSurface")]
- public EglCreatePBufferSurface CreatePBufferSurface { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglMakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
- [GlEntryPoint("eglMakeCurrent")]
- public EglMakeCurrent MakeCurrent { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglGetCurrentContext();
- [GlEntryPoint("eglGetCurrentContext")]
- public EglGetCurrentContext GetCurrentContext { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglGetCurrentDisplay();
- [GlEntryPoint("eglGetCurrentDisplay")]
- public EglGetCurrentContext GetCurrentDisplay { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglGetCurrentSurface(int readDraw);
- [GlEntryPoint("eglGetCurrentSurface")]
- public EglGetCurrentSurface GetCurrentSurface { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate void EglDisplaySurfaceVoidDelegate(IntPtr display, IntPtr surface);
- [GlEntryPoint("eglDestroySurface")]
- public EglDisplaySurfaceVoidDelegate DestroySurface { get; }
-
- [GlEntryPoint("eglSwapBuffers")]
- public EglDisplaySurfaceVoidDelegate SwapBuffers { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr
- EglCreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs);
- [GlEntryPoint("eglCreateWindowSurface")]
- public EglCreateWindowSurface CreateWindowSurface { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglGetConfigAttrib(IntPtr display, IntPtr config, int attr, out int rv);
- [GlEntryPoint("eglGetConfigAttrib")]
- public EglGetConfigAttrib GetConfigAttrib { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglWaitGL();
- [GlEntryPoint("eglWaitGL")]
- public EglWaitGL WaitGL { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglWaitClient();
- [GlEntryPoint("eglWaitClient")]
- public EglWaitGL WaitClient { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglWaitNative(int engine);
- [GlEntryPoint("eglWaitNative")]
- public EglWaitNative WaitNative { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglQueryString(IntPtr display, int i);
-
- [GlEntryPoint("eglQueryString")]
- public EglQueryString QueryStringNative { get; }
+
+ [GetProcAddress("eglDestroyContext")]
+ public partial bool DestroyContext(IntPtr display, IntPtr context);
+
+ [GetProcAddress("eglCreatePbufferSurface")]
+ public partial IntPtr CreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
+ [GetProcAddress("eglMakeCurrent")]
+ public partial bool MakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
+
+ [GetProcAddress("eglGetCurrentContext")]
+ public partial IntPtr GetCurrentContext();
+
+ [GetProcAddress("eglGetCurrentDisplay")]
+ public partial IntPtr GetCurrentDisplay();
+
+ [GetProcAddress("eglGetCurrentSurface")]
+ public partial IntPtr GetCurrentSurface(int readDraw);
+
+ [GetProcAddress("eglDestroySurface")]
+ public partial void DestroySurface(IntPtr display, IntPtr surface);
+
+ [GetProcAddress("eglSwapBuffers")]
+ public partial void SwapBuffers(IntPtr display, IntPtr surface);
+
+ [GetProcAddress("eglCreateWindowSurface")]
+ public partial IntPtr CreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs);
+
+ [GetProcAddress("eglGetConfigAttrib")]
+ public partial bool GetConfigAttrib(IntPtr display, IntPtr config, int attr, out int rv);
+
+ [GetProcAddress("eglWaitGL")]
+ public partial bool WaitGL();
+
+ [GetProcAddress("eglWaitClient")]
+ public partial bool WaitClient();
+
+ [GetProcAddress("eglWaitNative")]
+ public partial bool WaitNative(int engine);
+
+ [GetProcAddress("eglQueryString")]
+ public partial IntPtr QueryStringNative(IntPtr display, int i);
+
public string QueryString(IntPtr display, int i)
{
var rv = QueryStringNative(display, i);
@@ -166,25 +117,15 @@ namespace Avalonia.OpenGL.Egl
return null;
return Marshal.PtrToStringAnsi(rv);
}
+
+ [GetProcAddress("eglCreatePbufferFromClientBuffer")]
+ public partial IntPtr CreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[] attrib_list);
+
+ [GetProcAddress("eglQueryDisplayAttribEXT", true)]
+ public partial bool QueryDisplayAttribExt(IntPtr display, int attr, out IntPtr res);
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr EglCreatePbufferFromClientBuffer(IntPtr display, int buftype, IntPtr buffer, IntPtr config, int[] attrib_list);
- [GlEntryPoint("eglCreatePbufferFromClientBuffer")]
-
- public EglCreatePbufferFromClientBuffer CreatePbufferFromClientBuffer { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglQueryDisplayAttribEXT(IntPtr display, int attr, out IntPtr res);
-
- [GlEntryPoint("eglQueryDisplayAttribEXT"), GlOptionalEntryPoint]
- public EglQueryDisplayAttribEXT QueryDisplayAttribExt { get; }
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate bool EglQueryDeviceAttribEXT(IntPtr display, int attr, out IntPtr res);
-
- [GlEntryPoint("eglQueryDeviceAttribEXT"), GlOptionalEntryPoint]
- public EglQueryDisplayAttribEXT QueryDeviceAttribExt { get; }
-
- // ReSharper restore UnassignedGetOnlyAutoProperty
+
+ [GetProcAddress("eglQueryDeviceAttribEXT", true)]
+ public partial bool QueryDeviceAttribExt(IntPtr display, int attr, out IntPtr res);
}
}
diff --git a/src/Avalonia.OpenGL/GlBasicInfoInterface.cs b/src/Avalonia.OpenGL/GlBasicInfoInterface.cs
index aaba2ec09c..7a7110f15b 100644
--- a/src/Avalonia.OpenGL/GlBasicInfoInterface.cs
+++ b/src/Avalonia.OpenGL/GlBasicInfoInterface.cs
@@ -3,46 +3,24 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
+using Avalonia.SourceGenerator;
namespace Avalonia.OpenGL
{
- public class GlBasicInfoInterface : GlBasicInfoInterface