diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 5bd3d8ddac..bf2cbdbf19 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -130,10 +130,6 @@
[NSApp setMenu:nativeAppMenu->GetNative()];
}
- else
- {
- [NSApp setMenu:nullptr];
- }
}
-(void) applyMenu:(AvnMenu *)menu
diff --git a/samples/ControlCatalog/Pages/ComboBoxPage.xaml b/samples/ControlCatalog/Pages/ComboBoxPage.xaml
index 64e80a8e11..9f2fbb88f3 100644
--- a/samples/ControlCatalog/Pages/ComboBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/ComboBoxPage.xaml
@@ -86,6 +86,16 @@
+
+
+
+
+
+ Inline Items
+ Inline Item 2
+ Inline Item 3
+ Inline Item 4
+
WrapSelection
diff --git a/src/Avalonia.Controls/Primitives/IPopupHost.cs b/src/Avalonia.Controls/Primitives/IPopupHost.cs
index 36d2ae9230..8652924f90 100644
--- a/src/Avalonia.Controls/Primitives/IPopupHost.cs
+++ b/src/Avalonia.Controls/Primitives/IPopupHost.cs
@@ -2,6 +2,7 @@ using System;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input;
+using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives
@@ -17,16 +18,50 @@ namespace Avalonia.Controls.Primitives
public interface IPopupHost : IDisposable, IFocusScope
{
///
- /// Sets the control to display in the popup.
+ /// Gets or sets the fixed width of the popup.
///
- ///
- void SetChild(IControl? control);
+ double Width { get; set; }
+
+ ///
+ /// Gets or sets the minimum width of the popup.
+ ///
+ double MinWidth { get; set; }
+
+ ///
+ /// Gets or sets the maximum width of the popup.
+ ///
+ double MaxWidth { get; set; }
+
+ ///
+ /// Gets or sets the fixed height of the popup.
+ ///
+ double Height { get; set; }
+
+ ///
+ /// Gets or sets the minimum height of the popup.
+ ///
+ double MinHeight { get; set; }
+
+ ///
+ /// Gets or sets the maximum height of the popup.
+ ///
+ double MaxHeight { get; set; }
///
/// Gets the presenter from the control's template.
///
IContentPresenter? Presenter { get; }
+ ///
+ /// Gets or sets whether the popup appears on top of all other windows.
+ ///
+ bool Topmost { get; set; }
+
+ ///
+ /// Gets or sets a transform that will be applied to the popup.
+ ///
+ Transform? Transform { get; set; }
+
///
/// Gets the root of the visual tree in the case where the popup is presented using a
/// separate visual tree.
@@ -57,6 +92,12 @@ namespace Avalonia.Controls.Primitives
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
Rect? rect = null);
+ ///
+ /// Sets the control to display in the popup.
+ ///
+ ///
+ void SetChild(IControl? control);
+
///
/// Shows the popup.
///
@@ -66,14 +107,5 @@ namespace Avalonia.Controls.Primitives
/// Hides the popup.
///
void Hide();
-
- ///
- /// Binds the constraints of the popup host to a set of properties, usally those present on
- /// .
- ///
- IDisposable BindConstraints(AvaloniaObject popup, StyledProperty widthProperty,
- StyledProperty minWidthProperty, StyledProperty maxWidthProperty,
- StyledProperty heightProperty, StyledProperty minHeightProperty,
- StyledProperty maxHeightProperty, StyledProperty topmostProperty);
}
}
diff --git a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
index 6ac544e0fe..4765718c3b 100644
--- a/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
+++ b/src/Avalonia.Controls/Primitives/OverlayPopupHost.cs
@@ -11,6 +11,12 @@ namespace Avalonia.Controls.Primitives
{
public class OverlayPopupHost : ContentControl, IPopupHost, IInteractive, IManagedPopupPositionerPopup
{
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty TransformProperty =
+ PopupRoot.TransformProperty.AddOwner();
+
private readonly OverlayLayer _overlayLayer;
private PopupPositionerParameters _positionerParameters = new PopupPositionerParameters();
private ManagedPopupPositioner _positioner;
@@ -29,10 +35,22 @@ namespace Avalonia.Controls.Primitives
}
public IVisual? HostedVisualTreeRoot => null;
-
+
+ public Transform? Transform
+ {
+ get => GetValue(TransformProperty);
+ set => SetValue(TransformProperty, value);
+ }
+
///
IInteractive? IInteractive.InteractiveParent => Parent;
+ bool IPopupHost.Topmost
+ {
+ get => false;
+ set { /* Not currently supported in overlay popups */ }
+ }
+
public void Dispose() => Hide();
@@ -48,28 +66,6 @@ namespace Avalonia.Controls.Primitives
_shown = false;
}
- public IDisposable BindConstraints(AvaloniaObject popup, StyledProperty widthProperty, StyledProperty minWidthProperty,
- StyledProperty maxWidthProperty, StyledProperty heightProperty, StyledProperty minHeightProperty,
- StyledProperty maxHeightProperty, StyledProperty topmostProperty)
- {
- // Topmost property is not supported
- var bindings = new List();
-
- void Bind(AvaloniaProperty what, AvaloniaProperty to) => bindings.Add(this.Bind(what, popup[~to]));
- Bind(WidthProperty, widthProperty);
- Bind(MinWidthProperty, minWidthProperty);
- Bind(MaxWidthProperty, maxWidthProperty);
- Bind(HeightProperty, heightProperty);
- Bind(MinHeightProperty, minHeightProperty);
- Bind(MaxHeightProperty, maxHeightProperty);
-
- return Disposable.Create(() =>
- {
- foreach (var x in bindings)
- x.Dispose();
- });
- }
-
public void ConfigurePosition(IVisual target, PlacementMode placement, Point offset,
PopupAnchor anchor = PopupAnchor.None, PopupGravity gravity = PopupGravity.None,
PopupPositionerConstraintAdjustment constraintAdjustment = PopupPositionerConstraintAdjustment.All,
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index bb546107e0..7a7e41b029 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -14,6 +14,8 @@ using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.VisualTree;
+using Avalonia.Media;
+using Avalonia.Utilities;
namespace Avalonia.Controls.Primitives
{
@@ -33,6 +35,12 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty ChildProperty =
AvaloniaProperty.Register(nameof(Child));
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty InheritsTransformProperty =
+ AvaloniaProperty.Register(nameof(InheritsTransform));
+
///
/// Defines the property.
///
@@ -196,6 +204,16 @@ namespace Avalonia.Controls.Primitives
set;
}
+ ///
+ /// Gets or sets a value that determines whether the popup inherits the render transform
+ /// from its . Defaults to false.
+ ///
+ public bool InheritsTransform
+ {
+ get => GetValue(InheritsTransformProperty);
+ set => SetValue(InheritsTransformProperty, value);
+ }
+
///
/// Gets or sets a value that determines how the can be dismissed.
///
@@ -395,24 +413,29 @@ namespace Avalonia.Controls.Primitives
}
_isOpenRequested = false;
- var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver);
+ var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver);
var handlerCleanup = new CompositeDisposable(7);
- popupHost.BindConstraints(this, WidthProperty, MinWidthProperty, MaxWidthProperty,
- HeightProperty, MinHeightProperty, MaxHeightProperty, TopmostProperty).DisposeWith(handlerCleanup);
-
+ UpdateHostSizing(popupHost, topLevel, placementTarget);
+ popupHost.Topmost = Topmost;
popupHost.SetChild(Child);
((ISetLogicalParent)popupHost).SetParent(this);
- popupHost.ConfigurePosition(
- placementTarget,
- PlacementMode,
- new Point(HorizontalOffset, VerticalOffset),
- PlacementAnchor,
- PlacementGravity,
- PlacementConstraintAdjustment,
- PlacementRect);
+ if (InheritsTransform && placementTarget is Control c)
+ {
+ SubscribeToEventHandler>(
+ c,
+ PlacementTargetPropertyChanged,
+ (x, handler) => x.PropertyChanged += handler,
+ (x, handler) => x.PropertyChanged -= handler).DisposeWith(handlerCleanup);
+ }
+ else
+ {
+ popupHost.Transform = null;
+ }
+
+ UpdateHostPosition(popupHost, placementTarget);
SubscribeToEventHandler>(popupHost, RootTemplateApplied,
(x, handler) => x.TemplateApplied += handler,
@@ -494,7 +517,7 @@ namespace Avalonia.Controls.Primitives
}
}
- _openState = new PopupOpenState(topLevel, popupHost, cleanupPopup);
+ _openState = new PopupOpenState(placementTarget, topLevel, popupHost, cleanupPopup);
WindowManagerAddShadowHintChanged(popupHost, WindowManagerAddShadowHint);
@@ -542,7 +565,93 @@ namespace Avalonia.Controls.Primitives
base.OnDetachedFromLogicalTree(e);
Close();
}
-
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ if (_openState is not null)
+ {
+ if (change.Property == WidthProperty ||
+ change.Property == MinWidthProperty ||
+ change.Property == MaxWidthProperty ||
+ change.Property == HeightProperty ||
+ change.Property == MinHeightProperty ||
+ change.Property == MaxHeightProperty)
+ {
+ UpdateHostSizing(_openState.PopupHost, _openState.TopLevel, _openState.PlacementTarget);
+ }
+ else if (change.Property == PlacementTargetProperty ||
+ change.Property == PlacementModeProperty ||
+ change.Property == HorizontalOffsetProperty ||
+ change.Property == VerticalOffsetProperty ||
+ change.Property == PlacementAnchorProperty ||
+ change.Property == PlacementConstraintAdjustmentProperty ||
+ change.Property == PlacementRectProperty)
+ {
+ if (change.Property == PlacementTargetProperty)
+ {
+ var newTarget = change.GetNewValue() ?? this.FindLogicalAncestorOfType();
+
+ if (newTarget is null || newTarget.GetVisualRoot() != _openState.TopLevel)
+ {
+ Close();
+ return;
+ }
+
+ _openState.PlacementTarget = newTarget;
+ }
+
+ UpdateHostPosition(_openState.PopupHost, _openState.PlacementTarget);
+ }
+ else if (change.Property == TopmostProperty)
+ {
+ _openState.PopupHost.Topmost = change.GetNewValue();
+ }
+ }
+ }
+
+ private void UpdateHostPosition(IPopupHost popupHost, IControl placementTarget)
+ {
+ popupHost.ConfigurePosition(
+ placementTarget,
+ PlacementMode,
+ new Point(HorizontalOffset, VerticalOffset),
+ PlacementAnchor,
+ PlacementGravity,
+ PlacementConstraintAdjustment,
+ PlacementRect ?? new Rect(default, placementTarget.Bounds.Size));
+ }
+
+ private void UpdateHostSizing(IPopupHost popupHost, TopLevel topLevel, IControl placementTarget)
+ {
+ var scaleX = 1.0;
+ var scaleY = 1.0;
+
+ if (InheritsTransform && placementTarget.TransformToVisual(topLevel) is Matrix m)
+ {
+ scaleX = Math.Sqrt(m.M11 * m.M11 + m.M12 * m.M12);
+ scaleY = Math.Sqrt(m.M11 * m.M11 + m.M12 * m.M12);
+
+ // Ideally we'd only assign a ScaleTransform here when the scale != 1, but there's
+ // an issue with LayoutTransformControl in that it sets its LayoutTransform property
+ // with LocalValue priority in ArrangeOverride in certain cases when LayoutTransform
+ // is null, which breaks TemplateBindings to this property. Offending commit/line:
+ //
+ // https://github.com/AvaloniaUI/Avalonia/commit/6fbe1c2180ef45a940e193f1b4637e64eaab80ed#diff-5344e793df13f462126a8153ef46c44194f244b6890f25501709bae51df97f82R54
+ popupHost.Transform = new ScaleTransform(scaleX, scaleY);
+ }
+ else
+ {
+ popupHost.Transform = null;
+ }
+
+ popupHost.Width = Width * scaleX;
+ popupHost.MinWidth = MinWidth * scaleX;
+ popupHost.MaxWidth = MaxWidth * scaleX;
+ popupHost.Height = Height * scaleY;
+ popupHost.MinHeight = MinHeight * scaleY;
+ popupHost.MaxHeight = MaxHeight * scaleY;
+ }
+
private void HandlePositionChange()
{
if (_openState != null)
@@ -824,6 +933,14 @@ namespace Avalonia.Controls.Primitives
}
}
+ private void PlacementTargetPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
+ {
+ if (_openState is not null && e.Property == Visual.TransformedBoundsProperty)
+ {
+ UpdateHostSizing(_openState.PopupHost, _openState.TopLevel, _openState.PlacementTarget);
+ }
+ }
+
private void WindowLostFocus()
{
if (IsLightDismissEnabled)
@@ -862,15 +979,16 @@ namespace Avalonia.Controls.Primitives
private readonly IDisposable _cleanup;
private IDisposable? _presenterCleanup;
- public PopupOpenState(TopLevel topLevel, IPopupHost popupHost, IDisposable cleanup)
+ public PopupOpenState(IControl placementTarget, TopLevel topLevel, IPopupHost popupHost, IDisposable cleanup)
{
+ PlacementTarget = placementTarget;
TopLevel = topLevel;
PopupHost = popupHost;
_cleanup = cleanup;
}
public TopLevel TopLevel { get; }
-
+ public IControl PlacementTarget { get; set; }
public IPopupHost PopupHost { get; }
public void SetPresenterSubscription(IDisposable? presenterCleanup)
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index abf56e5420..f7bf7c1a27 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Reactive.Disposables;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Interactivity;
@@ -8,7 +6,6 @@ using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.VisualTree;
-using JetBrains.Annotations;
namespace Avalonia.Controls.Primitives
{
@@ -17,6 +14,12 @@ namespace Avalonia.Controls.Primitives
///
public sealed class PopupRoot : WindowBase, IInteractive, IHostedVisualTreeRoot, IDisposable, IStyleHost, IPopupHost
{
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty TransformProperty =
+ AvaloniaProperty.Register(nameof(Transform));
+
private PopupPositionerParameters _positionerParameters;
///
@@ -54,6 +57,15 @@ namespace Avalonia.Controls.Primitives
///
public new IPopupImpl? PlatformImpl => (IPopupImpl?)base.PlatformImpl;
+ ///
+ /// Gets or sets a transform that will be applied to the popup.
+ ///
+ public Transform? Transform
+ {
+ get => GetValue(TransformProperty);
+ set => SetValue(TransformProperty, value);
+ }
+
///
/// Gets the parent control in the event route.
///
@@ -103,27 +115,6 @@ namespace Avalonia.Controls.Primitives
IVisual IPopupHost.HostedVisualTreeRoot => this;
- public IDisposable BindConstraints(AvaloniaObject popup, StyledProperty widthProperty, StyledProperty minWidthProperty,
- StyledProperty maxWidthProperty, StyledProperty heightProperty, StyledProperty minHeightProperty,
- StyledProperty maxHeightProperty, StyledProperty topmostProperty)
- {
- var bindings = new List();
-
- void Bind(AvaloniaProperty what, AvaloniaProperty to) => bindings.Add(this.Bind(what, popup[~to]));
- Bind(WidthProperty, widthProperty);
- Bind(MinWidthProperty, minWidthProperty);
- Bind(MaxWidthProperty, maxWidthProperty);
- Bind(HeightProperty, heightProperty);
- Bind(MinHeightProperty, minHeightProperty);
- Bind(MaxHeightProperty, maxHeightProperty);
- Bind(TopmostProperty, topmostProperty);
- return Disposable.Create(() =>
- {
- foreach (var x in bindings)
- x.Dispose();
- });
- }
-
protected override Size MeasureOverride(Size availableSize)
{
var maxAutoSize = PlatformImpl?.MaxAutoSizeHint ?? Size.Infinity;
diff --git a/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml b/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml
index 301e19d208..07d905ea1d 100644
--- a/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml
+++ b/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml
@@ -1,4 +1,4 @@
-
diff --git a/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml b/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml
index 9468cc5535..5e8f3337ee 100644
--- a/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml
+++ b/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml
@@ -10,16 +10,18 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml b/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
index e35093d2f1..93ecc438eb 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
@@ -119,7 +119,8 @@
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
PlacementTarget="Background"
- IsLightDismissEnabled="True">
+ IsLightDismissEnabled="True"
+ InheritsTransform="True">
-
-
-
+
+
+
+
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml b/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
index 1e573913b9..f608cf55f5 100644
--- a/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/PopupRoot.xaml
@@ -10,16 +10,18 @@
-
-
-
-
+
+
+
+
-
-
+
+
+
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index 2548b9f5aa..b45968ec27 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -126,6 +126,7 @@ namespace Avalonia.Skia
SKCanvas ISkiaDrawingContextImpl.SkCanvas => Canvas;
SKSurface ISkiaDrawingContextImpl.SkSurface => Surface;
GRContext ISkiaDrawingContextImpl.GrContext => _grContext;
+ double ISkiaDrawingContextImpl.CurrentOpacity => _currentOpacity;
///
public void Clear(Color color)
diff --git a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs
index 38fa5a5253..87c89beb7e 100644
--- a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs
@@ -8,5 +8,6 @@ namespace Avalonia.Skia
SKCanvas SkCanvas { get; }
GRContext GrContext { get; }
SKSurface SkSurface { get; }
+ double CurrentOpacity { get; }
}
}
diff --git a/src/iOS/Avalonia.iOS/TouchHandler.cs b/src/iOS/Avalonia.iOS/TouchHandler.cs
index 43b19c85af..959a660d8a 100644
--- a/src/iOS/Avalonia.iOS/TouchHandler.cs
+++ b/src/iOS/Avalonia.iOS/TouchHandler.cs
@@ -41,7 +41,7 @@ namespace Avalonia.iOS
_ => RawPointerEventType.TouchUpdate
}, pt, RawInputModifiers.None, id);
- _device.ProcessRawEvent(ev);
+ _tl.Input?.Invoke(ev);
if (t.Phase == UITouchPhase.Cancelled || t.Phase == UITouchPhase.Ended)
_knownTouches.Remove(t);
@@ -49,4 +49,4 @@ namespace Avalonia.iOS
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
index f27ff3928c..6d3351d2b2 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
@@ -78,9 +78,13 @@ namespace Avalonia.Controls.UnitTests.Primitives
var templatedChild = ((Visual)target.Host).GetVisualChildren().Single();
- Assert.IsType(templatedChild);
+ Assert.IsType(templatedChild);
- var visualLayerManager = templatedChild.GetVisualChildren().Skip(1).Single();
+ var panel = templatedChild.GetVisualChildren().Single();
+
+ Assert.IsType(panel);
+
+ var visualLayerManager = panel.GetVisualChildren().Skip(1).Single();
Assert.IsType(visualLayerManager);
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
index cac8ca885d..d9cb40d1cc 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
@@ -325,6 +325,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.Equal(
new[]
{
+ "LayoutTransformControl",
"VisualLayerManager",
"ContentPresenter",
"ContentPresenter",
@@ -337,6 +338,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.Equal(
new[]
{
+ "LayoutTransformControl",
"Panel",
"Border",
"VisualLayerManager",
@@ -356,6 +358,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.Equal(
new object[]
{
+ popupRoot,
popupRoot,
popupRoot,
target,
@@ -372,6 +375,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
popupRoot,
popupRoot,
popupRoot,
+ popupRoot,
target,
null,
},