diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 34f931ff41..46e8665945 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,7 +18,7 @@ - [ ] Added unit tests (if possible)? - [ ] Added XML documentation to any related classes? -- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Avaloniaui.net with user documentation +- [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Documentation with user documentation ## Breaking changes diff --git a/native/Avalonia.Native/src/OSX/window.h b/native/Avalonia.Native/src/OSX/window.h index b1f64bca88..6a4ca2b8d8 100644 --- a/native/Avalonia.Native/src/OSX/window.h +++ b/native/Avalonia.Native/src/OSX/window.h @@ -34,6 +34,7 @@ class WindowBaseImpl; -(double) getScaling; -(double) getExtendedTitleBarHeight; -(void) setIsExtended:(bool)value; +-(void) updateShadow; @end struct INSWindowHolder diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index d7afbdaa3a..e7c144b2d3 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -124,7 +124,11 @@ public: [Window setTitle:_lastTitle]; _shown = true; - + + dispatch_async(dispatch_get_main_queue(), ^{ + [Window updateShadow]; + }); + return S_OK; } } @@ -1838,6 +1842,19 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent double _lastScaling; } +- (void)updateShadow +{ + // Common problem in Cocoa where [invalidateShadow] does work, + // This hack forces Cocoa to invalidate the shadow. + + NSRect frame = [self frame]; + NSRect updatedFrame = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width + 1.0, frame.size.height + 1.0); + [self setFrame:updatedFrame display:YES]; + [self setFrame:frame display:YES]; + + [self invalidateShadow]; +} + -(void) setIsExtended:(bool)value; { _isExtended = value; diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index e4ff5e9e5b..d0cf772c01 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -8,7 +8,7 @@ using System.Globalization; namespace Avalonia.Controls { /// - /// A control to allow the user to select a time + /// A control to allow the user to select a time. /// [PseudoClasses(":hasnotime")] public class TimePicker : TemplatedControl diff --git a/src/Avalonia.Controls/Expander.cs b/src/Avalonia.Controls/Expander.cs index 9ff2e41fa9..052b42a233 100644 --- a/src/Avalonia.Controls/Expander.cs +++ b/src/Avalonia.Controls/Expander.cs @@ -4,14 +4,35 @@ using Avalonia.Controls.Primitives; namespace Avalonia.Controls { + /// + /// Direction in which an control opens. + /// public enum ExpandDirection { + /// + /// Opens down. + /// Down, + + /// + /// Opens up. + /// Up, + + /// + /// Opens left. + /// Left, + + /// + /// Opens right. + /// Right } + /// + /// A control with a header that has a collapsible content section. + /// [PseudoClasses(":expanded", ":up", ":down", ":left", ":right")] public class Expander : HeaderedContentControl { diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index 105a2744e5..c7d598006d 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -17,7 +17,7 @@ using Avalonia.VisualTree; namespace Avalonia.Controls { /// - /// Grid + /// Defines a flexible grid area that consists of columns and rows. /// public class Grid : Panel { diff --git a/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs b/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs index 90727a3505..e62e087140 100644 --- a/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs +++ b/src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs @@ -1,10 +1,28 @@ namespace Avalonia.Controls.Primitives { + /// + /// Specifies the visibility of a for scrollable content. + /// public enum ScrollBarVisibility { + /// + /// No scrollbars and no scrolling in this dimension. + /// Disabled, + + /// + /// The scrollbar should be visible only if there is more content than fits in the viewport. + /// Auto, + + /// + /// The scrollbar should never be visible. No space should ever be reserved for the scrollbar. + /// Hidden, + + /// + /// The scrollbar should always be visible. Space should always be reserved for the scrollbar. + /// Visible, } } diff --git a/src/Avalonia.Controls/RadioButton.cs b/src/Avalonia.Controls/RadioButton.cs index 4bda241497..681278d247 100644 --- a/src/Avalonia.Controls/RadioButton.cs +++ b/src/Avalonia.Controls/RadioButton.cs @@ -8,6 +8,9 @@ using Avalonia.VisualTree; namespace Avalonia.Controls { + /// + /// Represents a button that allows a user to select a single option from a group of options. + /// public class RadioButton : ToggleButton { private class RadioButtonGroupManager diff --git a/src/Avalonia.Controls/RelativePanel.cs b/src/Avalonia.Controls/RelativePanel.cs index 2305d8fb9e..c5de004f09 100644 --- a/src/Avalonia.Controls/RelativePanel.cs +++ b/src/Avalonia.Controls/RelativePanel.cs @@ -8,6 +8,9 @@ using Avalonia.Layout; namespace Avalonia.Controls { + /// + /// Defines an area within which you can position and align child objects in relation to each other or the parent panel. + /// public partial class RelativePanel : Panel { private readonly Graph _childGraph; diff --git a/src/Avalonia.Controls/RepeatButton.cs b/src/Avalonia.Controls/RepeatButton.cs index fcd6607feb..ba770634d9 100644 --- a/src/Avalonia.Controls/RepeatButton.cs +++ b/src/Avalonia.Controls/RepeatButton.cs @@ -4,6 +4,9 @@ using Avalonia.Threading; namespace Avalonia.Controls { + /// + /// Represents a control that raises its event repeatedly when it is pressed and held. + /// public class RepeatButton : Button { /// diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 15a954b462..3c221cbf27 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -17,6 +17,9 @@ using Avalonia.Controls.Metadata; namespace Avalonia.Controls { + /// + /// Represents a control that can be used to display or edit unformatted text. + /// [PseudoClasses(":empty")] public class TextBox : TemplatedControl, UndoRedoHelper.IUndoRedoHost { diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 71359f733d..f716464d14 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -414,9 +414,7 @@ namespace Avalonia.Native public Action Input { get; set; } - Action ScalingChanged { get; set; } - - Action ITopLevelImpl.ScalingChanged { get; set; } + public Action ScalingChanged { get; set; } public Action TransparencyLevelChanged { get; set; } diff --git a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs index 723d5e81ab..b304b19910 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs @@ -109,7 +109,8 @@ namespace Avalonia.Media.TextFormatting GlyphRun.GlyphAdvances.Take(glyphCount), GlyphRun.GlyphOffsets.Take(glyphCount), GlyphRun.Characters.Take(length), - GlyphRun.GlyphClusters.Take(glyphCount)); + GlyphRun.GlyphClusters.Take(glyphCount), + GlyphRun.BiDiLevel); var firstTextRun = new ShapedTextCharacters(firstGlyphRun, Properties); @@ -120,7 +121,8 @@ namespace Avalonia.Media.TextFormatting GlyphRun.GlyphAdvances.Skip(glyphCount), GlyphRun.GlyphOffsets.Skip(glyphCount), GlyphRun.Characters.Skip(length), - GlyphRun.GlyphClusters.Skip(glyphCount)); + GlyphRun.GlyphClusters.Skip(glyphCount), + GlyphRun.BiDiLevel); var secondTextRun = new ShapedTextCharacters(secondGlyphRun, Properties); diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs index c6f524451b..0779716ec8 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs @@ -135,20 +135,20 @@ namespace Avalonia.Media.TextFormatting count = 0; var script = Script.Common; - //var direction = BiDiClass.LeftToRight; + var direction = BiDiClass.LeftToRight; var font = typeface.GlyphTypeface; var defaultFont = defaultTypeface.GlyphTypeface; - + var enumerator = new GraphemeEnumerator(text); while (enumerator.MoveNext()) { - var grapheme = enumerator.Current; + var currentGrapheme = enumerator.Current; - var currentScript = grapheme.FirstCodepoint.Script; + var currentScript = currentGrapheme.FirstCodepoint.Script; - //var currentDirection = grapheme.FirstCodepoint.BiDiClass; + var currentDirection = currentGrapheme.FirstCodepoint.BiDiClass; //// ToDo: Implement BiDi algorithm //if (currentScript.HorizontalDirection != direction) @@ -161,36 +161,44 @@ namespace Avalonia.Media.TextFormatting if (currentScript != script) { - if (currentScript != Script.Inherited && currentScript != Script.Common) + if (script == Script.Inherited || script == Script.Common) { - if (script == Script.Inherited || script == Script.Common) - { - script = currentScript; - } - else + script = currentScript; + } + else + { + if (currentScript != Script.Inherited && currentScript != Script.Common) { break; } } } - if (isFallback) + if (currentScript != Script.Common && currentScript != Script.Inherited) { - if (defaultFont.TryGetGlyph(grapheme.FirstCodepoint, out _)) + if (isFallback && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } - } - if (!font.TryGetGlyph(grapheme.FirstCodepoint, out _)) - { - if (!grapheme.FirstCodepoint.IsWhiteSpace) + if (!font.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } } - count += grapheme.Text.Length; + if (!currentGrapheme.FirstCodepoint.IsWhiteSpace && !font.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) + { + break; + } + + if (direction == BiDiClass.RightToLeft && currentDirection == BiDiClass.CommonSeparator) + { + break; + } + + count += currentGrapheme.Text.Length; + direction = currentDirection; } return count > 0; diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 97af874238..9c2a1953f1 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs @@ -125,6 +125,27 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } } + [Fact] + public void Should_Produce_A_Single_Fallback_Run() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + + const string text = "👍 👍 👍 👍"; + + var textSource = new SingleBufferTextSource(text, defaultProperties); + + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + Assert.Equal(1, textLine.TextRuns.Count); + } + } + [Fact] public void Should_Split_Run_On_Script() {