csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.9 KiB
116 lines
3.9 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Avalonia.Automation.Peers;
|
|
using Avalonia.Controls.Chrome;
|
|
using Avalonia.Input;
|
|
using Avalonia.Layout;
|
|
using Avalonia.LogicalTree;
|
|
using Avalonia.Reactive;
|
|
|
|
namespace Avalonia.Controls;
|
|
|
|
/// <summary>
|
|
/// Hosts the TopLevel and, when enabled, drawn decoration layers (underlay, overlay, fullscreen popover).
|
|
/// Serves as the visual root for PresentationSource.
|
|
/// </summary>
|
|
internal partial class TopLevelHost : Control
|
|
{
|
|
private Thickness _decorationInset;
|
|
|
|
static TopLevelHost()
|
|
{
|
|
KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue<TopLevelHost>(KeyboardNavigationMode.Cycle);
|
|
}
|
|
|
|
public TopLevelHost(TopLevel tl)
|
|
{
|
|
_topLevel = tl;
|
|
VisualChildren.Add(tl);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the decoration inset applied to the TopLevel child in forced decoration mode.
|
|
/// When non-zero, the TopLevel is measured and arranged within the inset area while
|
|
/// decoration layers use the full available size.
|
|
/// </summary>
|
|
internal Thickness DecorationInset
|
|
{
|
|
get => _decorationInset;
|
|
set
|
|
{
|
|
if (_decorationInset == value)
|
|
return;
|
|
_decorationInset = value;
|
|
InvalidateMeasure();
|
|
}
|
|
}
|
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
|
{
|
|
var inset = _decorationInset;
|
|
var hasInset = inset != default;
|
|
var desiredSize = default(Size);
|
|
|
|
foreach (var child in VisualChildren)
|
|
{
|
|
if (child is Layoutable l)
|
|
{
|
|
if (hasInset && ReferenceEquals(child, _topLevel))
|
|
{
|
|
// In forced mode, measure the TopLevel with reduced size
|
|
var contentSize = new Size(
|
|
Math.Max(0, availableSize.Width - inset.Left - inset.Right),
|
|
Math.Max(0, availableSize.Height - inset.Top - inset.Bottom));
|
|
l.Measure(contentSize);
|
|
|
|
// Add inset back so TopLevelHost's desired size represents the full frame.
|
|
// This ensures ArrangeOverride receives the full frame size and can correctly
|
|
// position the TopLevel within the inset area.
|
|
desiredSize = new Size(
|
|
Math.Max(desiredSize.Width, l.DesiredSize.Width + inset.Left + inset.Right),
|
|
Math.Max(desiredSize.Height, l.DesiredSize.Height + inset.Top + inset.Bottom));
|
|
}
|
|
else
|
|
{
|
|
l.Measure(availableSize);
|
|
|
|
desiredSize = new Size(
|
|
Math.Max(desiredSize.Width, l.DesiredSize.Width),
|
|
Math.Max(desiredSize.Height, l.DesiredSize.Height));
|
|
}
|
|
}
|
|
}
|
|
|
|
return desiredSize;
|
|
}
|
|
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|
{
|
|
var inset = _decorationInset;
|
|
var hasInset = inset != default;
|
|
|
|
foreach (var child in VisualChildren)
|
|
{
|
|
if (child is Layoutable l)
|
|
{
|
|
if (hasInset && ReferenceEquals(child, _topLevel))
|
|
{
|
|
// In forced mode, arrange the TopLevel within the inset area
|
|
var contentSize = new Size(
|
|
Math.Max(0, finalSize.Width - inset.Left - inset.Right),
|
|
Math.Max(0, finalSize.Height - inset.Top - inset.Bottom));
|
|
|
|
l.Arrange(new Rect(inset.Left, inset.Top, contentSize.Width, contentSize.Height));
|
|
}
|
|
else
|
|
{
|
|
l.Arrange(new Rect(finalSize));
|
|
}
|
|
}
|
|
}
|
|
|
|
return finalSize;
|
|
}
|
|
|
|
protected override bool BypassFlowDirectionPolicies => true;
|
|
}
|
|
|