Browse Source

Merge branch 'master' into patch-1

pull/9174/head
Steven Kirk 4 years ago
committed by GitHub
parent
commit
e8f962b3c4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build/SharedVersion.props
  2. 4
      native/Avalonia.Native/src/OSX/Screens.mm
  3. 5
      samples/ControlCatalog.Web/ControlCatalog.Web.csproj
  4. 1
      samples/ControlCatalog.Web/Roots.xml
  5. 4
      samples/ControlCatalog/Pages/ScreenPage.cs
  6. 4
      src/Avalonia.Base/Media/PathMarkupParser.cs
  7. 6
      src/Avalonia.Controls/Platform/IScreenImpl.cs
  8. 57
      src/Avalonia.Controls/Platform/Screen.cs
  9. 23
      src/Avalonia.Controls/Screens.cs
  10. 1
      src/Avalonia.Controls/Viewbox.cs
  11. 4
      src/Avalonia.Native/ScreenImpl.cs
  12. 2
      src/Avalonia.Native/WindowImplBase.cs
  13. 4
      src/Avalonia.Native/avn.idl
  14. 28
      src/Avalonia.X11/X11Screens.cs
  15. 8
      src/Avalonia.X11/X11Window.cs
  16. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
  17. 1
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  18. 12
      src/Web/Avalonia.Web/AvaloniaView.cs
  19. 35
      src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts
  20. 5
      src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts
  21. 6
      src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts
  22. 5
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  23. 8
      src/Windows/Avalonia.Win32/TrayIconImpl.cs
  24. 3
      src/Windows/Avalonia.Win32/WinScreen.cs
  25. 2
      src/Windows/Avalonia.Win32/WindowImpl.cs
  26. 21
      tests/Avalonia.Controls.UnitTests/ViewboxTests.cs

2
build/SharedVersion.props

@ -8,7 +8,7 @@
<RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl> <RepositoryUrl>https://github.com/AvaloniaUI/Avalonia/</RepositoryUrl>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>CS1591</NoWarn> <NoWarn>CS1591</NoWarn>
<LangVersion>latest</LangVersion> <LangVersion>preview</LangVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon> <PackageIcon>Icon.png</PackageIcon>
<PackageDescription>Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly.</PackageDescription> <PackageDescription>Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly.</PackageDescription>

4
native/Avalonia.Native/src/OSX/Screens.mm

@ -41,9 +41,9 @@ public:
ret->WorkingArea.X = [screen visibleFrame].origin.x; ret->WorkingArea.X = [screen visibleFrame].origin.x;
ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height; ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height;
ret->PixelDensity = [screen backingScaleFactor]; ret->Scaling = [screen backingScaleFactor];
ret->Primary = index == 0; ret->IsPrimary = index == 0;
return S_OK; return S_OK;
} }

5
samples/ControlCatalog.Web/ControlCatalog.Web.csproj

@ -16,9 +16,8 @@
<TrimMode>full</TrimMode> <TrimMode>full</TrimMode>
<WasmBuildNative>true</WasmBuildNative> <WasmBuildNative>true</WasmBuildNative>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>
<WasmEnableSIMD>true</WasmEnableSIMD> <EmccCompileOptimizationFlag>-O2</EmccCompileOptimizationFlag>
<EmccCompileOptimizationFlag>-O3</EmccCompileOptimizationFlag> <EmccLinkOptimizationFlag>-O2</EmccLinkOptimizationFlag>
<EmccLinkOptimizationFlag>-O3</EmccLinkOptimizationFlag>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

1
samples/ControlCatalog.Web/Roots.xml

@ -3,4 +3,5 @@
<assembly fullname="ControlCatalog.Web" preserve="All" /> <assembly fullname="ControlCatalog.Web" preserve="All" />
<assembly fullname="Avalonia.Themes.Fluent" preserve="All" /> <assembly fullname="Avalonia.Themes.Fluent" preserve="All" />
<assembly fullname="Avalonia.Themes.Simple" preserve="All" /> <assembly fullname="Avalonia.Themes.Simple" preserve="All" />
<assembly fullname="Avalonia.Controls.ColorPicker" preserve="All" />
</linker> </linker>

4
samples/ControlCatalog/Pages/ScreenPage.cs

@ -62,10 +62,10 @@ namespace ControlCatalog.Pages
CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20)); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20));
formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%"); formattedText = CreateFormattedText($"Scaling: {screen.Scaling * 100}%");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
formattedText = CreateFormattedText($"Primary: {screen.Primary}"); formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}");
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
formattedText = formattedText =

4
src/Avalonia.Base/Media/PathMarkupParser.cs

@ -188,7 +188,7 @@ namespace Avalonia.Media
_isOpen = true; _isOpen = true;
} }
private void SetFillRule(ref ReadOnlySpan<char> span) private void SetFillRule(scoped ref ReadOnlySpan<char> span)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@ -452,7 +452,7 @@ namespace Avalonia.Media
return !span.IsEmpty && (span[0] == ',' || span[0] == '-' || span[0] == '.' || char.IsDigit(span[0])); return !span.IsEmpty && (span[0] == ',' || span[0] == '-' || span[0] == '.' || char.IsDigit(span[0]));
} }
private static bool ReadArgument(ref ReadOnlySpan<char> remaining, out ReadOnlySpan<char> argument) private static bool ReadArgument(scoped ref ReadOnlySpan<char> remaining, out ReadOnlySpan<char> argument)
{ {
remaining = SkipWhitespace(remaining); remaining = SkipWhitespace(remaining);
if (remaining.IsEmpty) if (remaining.IsEmpty)

6
src/Avalonia.Controls/Platform/IScreenImpl.cs

@ -6,8 +6,14 @@ namespace Avalonia.Platform
[Unstable] [Unstable]
public interface IScreenImpl public interface IScreenImpl
{ {
/// <summary>
/// Gets the total number of screens available on the device.
/// </summary>
int ScreenCount { get; } int ScreenCount { get; }
/// <summary>
/// Gets the list of all screens available on the device.
/// </summary>
IReadOnlyList<Screen> AllScreens { get; } IReadOnlyList<Screen> AllScreens { get; }
Screen? ScreenFromWindow(IWindowBaseImpl window); Screen? ScreenFromWindow(IWindowBaseImpl window);

57
src/Avalonia.Controls/Platform/Screen.cs

@ -1,21 +1,64 @@
namespace Avalonia.Platform using System;
namespace Avalonia.Platform
{ {
/// <summary>
/// Represents a single display screen.
/// </summary>
public class Screen public class Screen
{ {
public double PixelDensity { get; } /// <summary>
/// Gets the scaling factor applied to the screen by the operating system.
/// </summary>
/// <remarks>
/// Multiply this value by 100 to get a percentage.
/// Both X and Y scaling factors are assumed uniform.
/// </remarks>
public double Scaling { get; }
/// <inheritdoc cref="Scaling"/>
[Obsolete("Use the Scaling property instead.")]
public double PixelDensity => Scaling;
/// <summary>
/// Gets the overall pixel-size of the screen.
/// </summary>
/// <remarks>
/// This generally is the raw pixel counts in both the X and Y direction.
/// </remarks>
public PixelRect Bounds { get; } public PixelRect Bounds { get; }
/// <summary>
/// Gets the actual working-area pixel-size of the screen.
/// </summary>
/// <remarks>
/// This area may be smaller than <see href="Bounds"/> to account for notches and
/// other block-out areas such as taskbars etc.
/// </remarks>
public PixelRect WorkingArea { get; } public PixelRect WorkingArea { get; }
public bool Primary { get; } /// <summary>
/// Gets a value indicating whether the screen is the primary one.
public Screen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool primary) /// </summary>
public bool IsPrimary { get; }
/// <inheritdoc cref="IsPrimary"/>
[Obsolete("Use the IsPrimary property instead.")]
public bool Primary => IsPrimary;
/// <summary>
/// Initializes a new instance of the <see cref="Screen"/> class.
/// </summary>
/// <param name="scaling">The scaling factor applied to the screen by the operating system.</param>
/// <param name="bounds">The overall pixel-size of the screen.</param>
/// <param name="workingArea">The actual working-area pixel-size of the screen.</param>
/// <param name="isPrimary">Whether the screen is the primary one.</param>
public Screen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary)
{ {
this.PixelDensity = pixelDensity; this.Scaling = scaling;
this.Bounds = bounds; this.Bounds = bounds;
this.WorkingArea = workingArea; this.WorkingArea = workingArea;
this.Primary = primary; this.IsPrimary = isPrimary;
} }
} }
} }

23
src/Avalonia.Controls/Screens.cs

@ -8,14 +8,31 @@ using Avalonia.VisualTree;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary>
/// Represents all screens available on a device.
/// </summary>
public class Screens public class Screens
{ {
private readonly IScreenImpl _iScreenImpl; private readonly IScreenImpl _iScreenImpl;
/// <summary>
/// Gets the total number of screens available on the device.
/// </summary>
public int ScreenCount => _iScreenImpl?.ScreenCount ?? 0; public int ScreenCount => _iScreenImpl?.ScreenCount ?? 0;
/// <summary>
/// Gets the list of all screens available on the device.
/// </summary>
public IReadOnlyList<Screen> All => _iScreenImpl?.AllScreens ?? Array.Empty<Screen>(); public IReadOnlyList<Screen> All => _iScreenImpl?.AllScreens ?? Array.Empty<Screen>();
public Screen? Primary => All.FirstOrDefault(x => x.Primary);
/// <summary>
/// Gets the primary screen on the device.
/// </summary>
public Screen? Primary => All.FirstOrDefault(x => x.IsPrimary);
/// <summary>
/// Initializes a new instance of the <see cref="Screens"/> class.
/// </summary>
public Screens(IScreenImpl iScreenImpl) public Screens(IScreenImpl iScreenImpl)
{ {
_iScreenImpl = iScreenImpl; _iScreenImpl = iScreenImpl;
@ -25,14 +42,14 @@ namespace Avalonia.Controls
{ {
return _iScreenImpl.ScreenFromRect(bounds); return _iScreenImpl.ScreenFromRect(bounds);
} }
public Screen? ScreenFromWindow(IWindowBaseImpl window) public Screen? ScreenFromWindow(IWindowBaseImpl window)
{ {
return _iScreenImpl.ScreenFromWindow(window); return _iScreenImpl.ScreenFromWindow(window);
} }
public Screen? ScreenFromPoint(PixelPoint point) public Screen? ScreenFromPoint(PixelPoint point)
{ {
return _iScreenImpl.ScreenFromPoint(point); return _iScreenImpl.ScreenFromPoint(point);
} }

1
src/Avalonia.Controls/Viewbox.cs

@ -42,6 +42,7 @@ namespace Avalonia.Controls
// can be applied independently of the Viewbox and Child transforms. // can be applied independently of the Viewbox and Child transforms.
_containerVisual = new ViewboxContainer(); _containerVisual = new ViewboxContainer();
_containerVisual.RenderTransformOrigin = RelativePoint.TopLeft; _containerVisual.RenderTransformOrigin = RelativePoint.TopLeft;
((ISetLogicalParent)_containerVisual).SetParent(this);
VisualChildren.Add(_containerVisual); VisualChildren.Add(_containerVisual);
} }

4
src/Avalonia.Native/ScreenImpl.cs

@ -30,10 +30,10 @@ namespace Avalonia.Native
var screen = _native.GetScreen(i); var screen = _native.GetScreen(i);
result[i] = new Screen( result[i] = new Screen(
screen.PixelDensity, screen.Scaling,
screen.Bounds.ToAvaloniaPixelRect(), screen.Bounds.ToAvaloniaPixelRect(),
screen.WorkingArea.ToAvaloniaPixelRect(), screen.WorkingArea.ToAvaloniaPixelRect(),
screen.Primary.FromComBool()); screen.IsPrimary.FromComBool());
} }
return result; return result;

2
src/Avalonia.Native/WindowImplBase.cs

@ -92,7 +92,7 @@ namespace Avalonia.Native
_savedScaling = RenderScaling; _savedScaling = RenderScaling;
_nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost());
var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) var monitor = Screen.AllScreens.OrderBy(x => x.Scaling)
.FirstOrDefault(m => m.Bounds.Contains(Position)); .FirstOrDefault(m => m.Bounds.Contains(Position));
Resize(new Size(monitor.WorkingArea.Width * 0.75d, monitor.WorkingArea.Height * 0.7d), PlatformResizeReason.Layout); Resize(new Size(monitor.WorkingArea.Width * 0.75d, monitor.WorkingArea.Height * 0.7d), PlatformResizeReason.Layout);

4
src/Avalonia.Native/avn.idl

@ -256,8 +256,8 @@ struct AvnScreen
{ {
AvnRect Bounds; AvnRect Bounds;
AvnRect WorkingArea; AvnRect WorkingArea;
float PixelDensity; float Scaling;
bool Primary; bool IsPrimary;
} }
enum AvnPixelFormat enum AvnPixelFormat

28
src/Avalonia.X11/X11Screens.cs

@ -9,7 +9,7 @@ using JetBrains.Annotations;
namespace Avalonia.X11 namespace Avalonia.X11
{ {
class X11Screens : IScreenImpl class X11Screens : IScreenImpl
{ {
private IX11Screens _impl; private IX11Screens _impl;
@ -218,7 +218,7 @@ namespace Avalonia.X11
public int ScreenCount => _impl.Screens.Length; public int ScreenCount => _impl.Screens.Length;
public IReadOnlyList<Screen> AllScreens => public IReadOnlyList<Screen> AllScreens =>
_impl.Screens.Select(s => new Screen(s.PixelDensity, s.Bounds, s.WorkingArea, s.Primary)).ToArray(); _impl.Screens.Select(s => new Screen(s.Scaling, s.Bounds, s.WorkingArea, s.IsPrimary)).ToArray();
} }
interface IX11Screens interface IX11Screens
@ -281,30 +281,34 @@ namespace Avalonia.X11
{ {
private const int FullHDWidth = 1920; private const int FullHDWidth = 1920;
private const int FullHDHeight = 1080; private const int FullHDHeight = 1080;
public bool Primary { get; } public bool IsPrimary { get; }
public string Name { get; set; } public string Name { get; set; }
public PixelRect Bounds { get; set; } public PixelRect Bounds { get; set; }
public Size? PhysicalSize { get; set; } public Size? PhysicalSize { get; set; }
public double PixelDensity { get; set; } public double Scaling { get; set; }
public PixelRect WorkingArea { get; set; } public PixelRect WorkingArea { get; set; }
public X11Screen(PixelRect bounds, bool primary, public X11Screen(
string name, Size? physicalSize, double? pixelDensity) PixelRect bounds,
bool isPrimary,
string name,
Size? physicalSize,
double? scaling)
{ {
Primary = primary; IsPrimary = isPrimary;
Name = name; Name = name;
Bounds = bounds; Bounds = bounds;
if (physicalSize == null && pixelDensity == null) if (physicalSize == null && scaling == null)
{ {
PixelDensity = 1; Scaling = 1;
} }
else if (pixelDensity == null) else if (scaling == null)
{ {
PixelDensity = GuessPixelDensity(bounds, physicalSize.Value); Scaling = GuessPixelDensity(bounds, physicalSize.Value);
} }
else else
{ {
PixelDensity = pixelDensity.Value; Scaling = scaling.Value;
PhysicalSize = physicalSize; PhysicalSize = physicalSize;
} }
} }

8
src/Avalonia.X11/X11Window.cs

@ -120,7 +120,7 @@ namespace Avalonia.X11
if (!_popup && Screen != null) if (!_popup && Screen != null)
{ {
var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) var monitor = Screen.AllScreens.OrderBy(x => x.Scaling)
.FirstOrDefault(m => m.Bounds.Contains(Position)); .FirstOrDefault(m => m.Bounds.Contains(Position));
if (monitor != null) if (monitor != null)
@ -570,9 +570,9 @@ namespace Avalonia.X11
newScaling = _scalingOverride.Value; newScaling = _scalingOverride.Value;
else else
{ {
var monitor = _platform.X11Screens.Screens.OrderBy(x => x.PixelDensity) var monitor = _platform.X11Screens.Screens.OrderBy(x => x.Scaling)
.FirstOrDefault(m => m.Bounds.Contains(Position)); .FirstOrDefault(m => m.Bounds.Contains(Position));
newScaling = monitor?.PixelDensity ?? RenderScaling; newScaling = monitor?.Scaling ?? RenderScaling;
} }
if (RenderScaling != newScaling) if (RenderScaling != newScaling)
@ -994,7 +994,7 @@ namespace Avalonia.X11
public IScreenImpl Screen => _platform.Screens; public IScreenImpl Screen => _platform.Screens;
public Size MaxAutoSizeHint => _platform.X11Screens.Screens.Select(s => s.Bounds.Size.ToSize(s.PixelDensity)) public Size MaxAutoSizeHint => _platform.X11Screens.Screens.Select(s => s.Bounds.Size.ToSize(s.Scaling))
.OrderByDescending(x => x.Width + x.Height).FirstOrDefault(); .OrderByDescending(x => x.Width + x.Height).FirstOrDefault();

1
src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj

@ -5,7 +5,6 @@
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<PackageId>Avalonia.Markup.Xaml.Loader</PackageId> <PackageId>Avalonia.Markup.Xaml.Loader</PackageId>
<DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants> <DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants>
<LangVersion>11</LangVersion>
</PropertyGroup> </PropertyGroup>
<!--Disable Net Perf. analyzer for submodule to avoid commit issue --> <!--Disable Net Perf. analyzer for submodule to avoid commit issue -->
<PropertyGroup> <PropertyGroup>

1
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@ -2,7 +2,6 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<RootNamespace>Avalonia</RootNamespace> <RootNamespace>Avalonia</RootNamespace>
<LangVersion>11</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="Markup\Parsers\Nodes\ExpressionGrammer" /> <None Remove="Markup\Parsers\Nodes\ExpressionGrammer" />

12
src/Web/Avalonia.Web/AvaloniaView.cs

@ -77,8 +77,7 @@ namespace Avalonia.Web
_topLevelImpl.SetCssCursor = (cursor) => _topLevelImpl.SetCssCursor = (cursor) =>
{ {
InputHelper.SetCursor(_containerElement, cursor); // macOS InputHelper.SetCursor(_containerElement, cursor);
InputHelper.SetCursor(_canvas, cursor); // windows
}; };
_topLevel.Prepare(); _topLevel.Prepare();
@ -254,7 +253,14 @@ namespace Avalonia.Web
private bool OnKeyDown (string code, string key, int modifier) private bool OnKeyDown (string code, string key, int modifier)
{ {
return _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, code, key, (RawInputModifiers)modifier); var handled = _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, code, key, (RawInputModifiers)modifier);
if (!handled && key.Length == 1)
{
handled = _topLevelImpl.RawTextEvent(key);
}
return handled;
} }
private bool OnKeyUp(string code, string key, int modifier) private bool OnKeyUp(string code, string key, int modifier)

35
src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts

@ -106,12 +106,6 @@ export class Canvas {
// add the draw to the next frame // add the draw to the next frame
this.renderLoopRequest = window.requestAnimationFrame(() => { this.renderLoopRequest = window.requestAnimationFrame(() => {
if (this.glInfo) {
const GL = (globalThis as any).AvaloniaGL;
// make current
GL.makeContextCurrent(this.glInfo.context);
}
if (this.htmlCanvas.width !== this.newWidth) { if (this.htmlCanvas.width !== this.newWidth) {
this.htmlCanvas.width = this.newWidth ?? 0; this.htmlCanvas.width = this.newWidth ?? 0;
} }
@ -131,6 +125,11 @@ export class Canvas {
} }
public setCanvasSize(width: number, height: number): void { public setCanvasSize(width: number, height: number): void {
if (this.renderLoopRequest !== 0) {
window.cancelAnimationFrame(this.renderLoopRequest);
this.renderLoopRequest = 0;
}
this.newWidth = width; this.newWidth = width;
this.newHeight = height; this.newHeight = height;
@ -142,11 +141,7 @@ export class Canvas {
this.htmlCanvas.height = this.newHeight; this.htmlCanvas.height = this.newHeight;
} }
if (this.glInfo) { this.requestAnimationFrame();
const GL = (globalThis as any).AvaloniaGL;
// make current
GL.makeContextCurrent(this.glInfo.context);
}
} }
public static setCanvasSize(element: HTMLCanvasElement, width: number, height: number): void { public static setCanvasSize(element: HTMLCanvasElement, width: number, height: number): void {
@ -210,23 +205,25 @@ interface SizeWatcherInstance {
export class SizeWatcher { export class SizeWatcher {
static observer: ResizeObserver; static observer: ResizeObserver;
static elements: Map<string, HTMLElement>; static elements: Map<string, HTMLElement>;
private static lastMove: number;
public static observe(element: HTMLElement, elementId: string | undefined, callback: (width: number, height: number) => void): void { public static observe(element: HTMLElement, elementId: string | undefined, callback: (width: number, height: number) => void): void {
if (!element || !callback) { if (!element || !callback) {
return; return;
} }
SizeWatcher.init(); SizeWatcher.lastMove = Date.now();
const watcherElement = element as SizeWatcherElement; callback(element.clientWidth, element.clientHeight);
watcherElement.SizeWatcher = {
callback
};
SizeWatcher.elements.set(elementId ?? element.id, element); const handleResize = (args: UIEvent) => {
SizeWatcher.observer.observe(element); if (Date.now() - SizeWatcher.lastMove > 33) {
callback(element.clientWidth, element.clientHeight);
SizeWatcher.lastMove = Date.now();
}
};
SizeWatcher.invoke(element); window.addEventListener("resize", handleResize);
} }
public static unobserve(elementId: string): void { public static unobserve(elementId: string): void {

5
src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts

@ -19,12 +19,11 @@ export class AvaloniaDOM {
canvas.classList.add("avalonia-canvas"); canvas.classList.add("avalonia-canvas");
canvas.style.backgroundColor = "#ccc"; canvas.style.backgroundColor = "#ccc";
canvas.style.width = "100%"; canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.position = "absolute"; canvas.style.position = "absolute";
// Native controls host // Native controls host
const nativeHost = document.createElement("div"); const nativeHost = document.createElement("div");
canvas.id = `nativeHost${randomIdPart}`; nativeHost.id = `nativeHost${randomIdPart}`;
nativeHost.classList.add("avalonia-native-host"); nativeHost.classList.add("avalonia-native-host");
nativeHost.style.left = "0px"; nativeHost.style.left = "0px";
nativeHost.style.top = "0px"; nativeHost.style.top = "0px";
@ -34,7 +33,7 @@ export class AvaloniaDOM {
// IME // IME
const inputElement = document.createElement("input"); const inputElement = document.createElement("input");
canvas.id = `input${randomIdPart}`; inputElement.id = `inputElement${randomIdPart}`;
inputElement.classList.add("avalonia-input-element"); inputElement.classList.add("avalonia-input-element");
inputElement.autocapitalize = "none"; inputElement.autocapitalize = "none";
inputElement.type = "text"; inputElement.type = "text";

6
src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts

@ -159,7 +159,11 @@ export class InputHelper {
} }
public static setCursor(inputElement: HTMLInputElement, kind: string) { public static setCursor(inputElement: HTMLInputElement, kind: string) {
inputElement.style.cursor = kind; if (kind === "pointer") {
inputElement.style.removeProperty("cursor");
} else {
inputElement.style.cursor = kind;
}
} }
public static setBounds(inputElement: HTMLInputElement, x: number, y: number, caretWidth: number, caretHeight: number, caret: number) { public static setBounds(inputElement: HTMLInputElement, x: number, y: number, caretWidth: number, caretHeight: number, caret: number) {

5
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1878,7 +1878,10 @@ namespace Avalonia.Win32.Interop
public static uint LGID(IntPtr HKL) public static uint LGID(IntPtr HKL)
{ {
return (uint)(HKL.ToInt32() & 0xffff); unchecked
{
return (uint)((ulong)HKL & 0xffff);
}
} }
public const int SORT_DEFAULT = 0; public const int SORT_DEFAULT = 0;

8
src/Windows/Avalonia.Win32/TrayIconImpl.cs

@ -216,7 +216,7 @@ namespace Avalonia.Win32
{ {
Anchor = PopupAnchor.TopLeft, Anchor = PopupAnchor.TopLeft,
Gravity = PopupGravity.BottomRight, Gravity = PopupGravity.BottomRight,
AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.PixelDensity, new Size(1, 1)), AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.Scaling, new Size(1, 1)),
Size = finalRect.Size, Size = finalRect.Size,
ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY, ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY,
}); });
@ -244,16 +244,16 @@ namespace Avalonia.Win32
{ {
var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft; var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft;
var size = _hiddenWindow.Screens.Primary.Bounds.Size; var size = _hiddenWindow.Screens.Primary.Bounds.Size;
return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.PixelDensity, size.Height * _hiddenWindow.Screens.Primary.PixelDensity); return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.Scaling, size.Height * _hiddenWindow.Screens.Primary.Scaling);
} }
} }
public void MoveAndResize(Point devicePoint, Size virtualSize) public void MoveAndResize(Point devicePoint, Size virtualSize)
{ {
_moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.PixelDensity); _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.Scaling);
} }
public double Scaling => _hiddenWindow.Screens.Primary.PixelDensity; public double Scaling => _hiddenWindow.Screens.Primary.Scaling;
} }
} }

3
src/Windows/Avalonia.Win32/WinScreen.cs

@ -7,7 +7,8 @@ namespace Avalonia.Win32
{ {
private readonly IntPtr _hMonitor; private readonly IntPtr _hMonitor;
public WinScreen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool primary, IntPtr hMonitor) : base(pixelDensity, bounds, workingArea, primary) public WinScreen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary, IntPtr hMonitor)
: base(scaling, bounds, workingArea, isPrimary)
{ {
_hMonitor = hMonitor; _hMonitor = hMonitor;
} }

2
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -224,7 +224,7 @@ namespace Avalonia.Win32
} }
} }
private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.Primary)?.PixelDensity ?? 1; private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.Scaling ?? 1;
public double RenderScaling => _scaling; public double RenderScaling => _scaling;

21
tests/Avalonia.Controls.UnitTests/ViewboxTests.cs

@ -1,4 +1,5 @@
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Data;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.UnitTests; using Avalonia.UnitTests;
@ -207,6 +208,26 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Size(200, 200), target.DesiredSize); Assert.Equal(new Size(200, 200), target.DesiredSize);
} }
[Fact]
public void Child_DataContext_Binding_Works()
{
var data = new
{
Foo = "foo",
};
var target = new Viewbox()
{
DataContext = data,
Child = new Canvas
{
[!Canvas.DataContextProperty] = new Binding("Foo"),
},
};
Assert.Equal("foo", target.Child.DataContext);
}
private bool TryGetScale(Viewbox viewbox, out Vector scale) private bool TryGetScale(Viewbox viewbox, out Vector scale)
{ {
if (viewbox.InternalTransform is null) if (viewbox.InternalTransform is null)

Loading…
Cancel
Save