/// <summary> /// Arrange a sequence of elements in a single line. /// </summary> /// <param name="lineStart"> /// Index of the first element in the sequence to arrange. /// </param> /// <param name="lineEnd"> /// Index of the last element in the sequence to arrange. /// </param> /// <param name="directDelta"> /// Optional fixed growth in the primary direction. /// </param> /// <param name="indirectOffset"> /// Offset of the line in the indirect direction. /// </param> /// <param name="indirectGrowth"> /// Shared indirect growth of the elements on this line. /// </param> private void ArrangeLine(View[] children, int lineStart, int lineEnd, double?directDelta, double indirectOffset, double indirectGrowth) { double directOffset = 0.0f; Orientation o = Orientation; bool isHorizontal = o == Orientation.Horizontal; for (int index = lineStart; index < lineEnd; index++) { // Get the size of the element View element = children[index]; var desiredSize = GetElementDesiredSize(element); OrientedSize elementSize = new OrientedSize(o, desiredSize.Width, desiredSize.Height); // Determine if we should use the element's desired size or the // fixed item width or height double directGrowth = directDelta != null ? directDelta.Value : elementSize.Direct; // Arrange the element Foundation.Rect bounds = isHorizontal ? new Foundation.Rect(directOffset, indirectOffset, directGrowth, indirectGrowth) : new Foundation.Rect(indirectOffset, directOffset, indirectGrowth, directGrowth); ArrangeElement(element, bounds); directOffset += directGrowth; } }
internal void SetCoreBounds(UIKit.UIWindow keyWindow, Foundation.Rect windowBounds) { var statusBarHeight = UIApplication.SharedApplication.StatusBarFrame.Size.Height; UIEdgeInsets inset = new UIEdgeInsets(statusBarHeight, 0, 0, 0); // Not respecting its own documentation. https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc // iOS returns all zeros for SafeAreaInsets on non-iPhoneX phones. (ignoring nav bars or status bars) // For that reason, we will set the window's visible bounds to the SafeAreaInsets only for iPhones with notches, // other phones will have insets that consider the status bar if (UseSafeAreaInsets) { if (keyWindow.SafeAreaInsets != UIEdgeInsets.Zero) // if we have a notch { inset = keyWindow.SafeAreaInsets; } } VisibleBounds = new Foundation.Rect( x: windowBounds.Left + inset.Left, y: windowBounds.Top + inset.Top, width: windowBounds.Width - inset.Right - inset.Left, height: windowBounds.Height - inset.Top - inset.Bottom ); if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { this.Log().Debug($"Updated visible bounds {VisibleBounds}, SafeAreaInsets: {inset}"); } VisibleBoundsChanged?.Invoke(this, null); }
/// <summary> /// Arranges the children knowing the grid is 1x1 /// </summary> private void ArrangeSuperpositionPanel(Size finalSize, Column column, Row row) { if (column.Width.IsPixelSize) { finalSize.Width = column.Width.PixelSize.Value; } if (row.Height.IsPixelSize) { finalSize.Height = row.Height.PixelSize.Value; } var isMeasureRequired = column.Width.IsAuto || row.Height.IsAuto; if (isMeasureRequired) { finalSize = MeasureChildren(finalSize, column.Width.IsAuto, row.Height.IsAuto); } var offset = GetChildrenOffset(); foreach (var child in Children) { var childFrame = new Foundation.Rect( offset.X, offset.Y, finalSize.Width, finalSize.Height ); ArrangeElement(child, childFrame); } }
internal void SetVisibleBounds(UIKit.UIWindow keyWindow, Foundation.Rect windowBounds) { var inset = UseSafeAreaInsets ? keyWindow.SafeAreaInsets : UIEdgeInsets.Zero; // Not respecting its own documentation. https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc // iOS returns all zeros for SafeAreaInsets on non-iPhones and iOS11. (ignoring nav bars or status bars) // So we need to update the top inset depending of the status bar visibilty on other devices var statusBarHeight = UIApplication.SharedApplication.StatusBarHidden ? 0 : UIApplication.SharedApplication.StatusBarFrame.Size.Height; inset.Top = (nfloat)Math.Max(inset.Top, statusBarHeight); var newVisibleBounds = new Foundation.Rect( x: windowBounds.Left + inset.Left, y: windowBounds.Top + inset.Top, width: windowBounds.Width - inset.Right - inset.Left, height: windowBounds.Height - inset.Top - inset.Bottom ); if (VisibleBounds != newVisibleBounds) { VisibleBounds = newVisibleBounds; if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { this.Log().Debug($"Updated visible bounds {VisibleBounds}, SafeAreaInsets: {inset}"); } VisibleBoundsChanged?.Invoke(this, null); } }
protected override Size ArrangeOverride(Size arrangeSize) { arrangeSize.Width -= GetHorizontalOffset(); arrangeSize.Height -= GetVerticalOffset(); var childRectangle = new Foundation.Rect(BorderThickness.Left + Padding.Left, BorderThickness.Top + Padding.Top, arrangeSize.Width, arrangeSize.Height); var isHorizontal = Orientation == Windows.UI.Xaml.Controls.Orientation.Horizontal; var previousChildSize = 0.0; this.Log().Debug($"StackPanel/{Name}: Arranging {Children.Count} children."); // Shadow variables for evaluation performance var spacing = Spacing; var count = Children.Count; for (int i = 0; i < count; i++) { var view = Children[i]; var desiredChildSize = GetElementDesiredSize(view); var addSpacing = i != 0; if (isHorizontal) { childRectangle.X += previousChildSize; if (addSpacing) { childRectangle.X += spacing; } previousChildSize = desiredChildSize.Width; childRectangle.Width = desiredChildSize.Width; childRectangle.Height = Math.Max(arrangeSize.Height, desiredChildSize.Height); } else { childRectangle.Y += previousChildSize; if (addSpacing) { childRectangle.Y += spacing; } previousChildSize = desiredChildSize.Height; childRectangle.Height = desiredChildSize.Height; childRectangle.Width = Math.Max(arrangeSize.Width, desiredChildSize.Width); } var adjustedRectangle = childRectangle; ArrangeElement(view, adjustedRectangle); } arrangeSize.Width += GetHorizontalOffset(); arrangeSize.Height += GetVerticalOffset(); return(arrangeSize); }
internal void SetCoreBounds(NSWindow keyWindow, Foundation.Rect windowBounds) { VisibleBounds = windowBounds; if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { this.Log().Debug($"Updated visible bounds {VisibleBounds}"); } VisibleBoundsChanged?.Invoke(this, null); }
/// <summary> /// Create matrix to transform image based on relative dimensions of bitmap and drawRect, Stretch mode, and RelativeTransform /// </summary> /// <param name="drawRect"></param> /// <param name="bitmap"></param> /// <returns></returns> private Android.Graphics.Matrix GenerateMatrix(Foundation.Rect drawRect, Bitmap bitmap) { var matrix = new Android.Graphics.Matrix(); // Note that bitmap.Width and bitmap.Height (in physical pixels) are automatically scaled up when loaded from local resources, but aren't when acquired externally. // This means that bitmaps acquired externally might not render the same way on devices with different densities when using Stretch.None. var sourceRect = new Foundation.Rect(0, 0, bitmap.Width, bitmap.Height); var destinationRect = GetArrangedImageRect(sourceRect.Size, drawRect); matrix.SetRectToRect(sourceRect.ToRectF(), destinationRect.ToRectF(), Android.Graphics.Matrix.ScaleToFit.Fill); RelativeTransform?.ToNativeTransform(matrix, new Size(drawRect.Width, drawRect.Height), isBrush: true); return(matrix); }
protected override Size ArrangeOverride(Size finalSize) { var child = this.FindFirstChild(); if (child != null) { var padding = Padding; var borderThickness = BorderThickness; var finalRect = new Foundation.Rect( padding.Left + borderThickness.Left, padding.Top + borderThickness.Top, finalSize.Width - padding.Left - padding.Right - borderThickness.Left - borderThickness.Right, finalSize.Height - padding.Top - padding.Bottom - borderThickness.Top - borderThickness.Bottom ); base.ArrangeElement(child, finalRect); } return(finalSize); }
internal void SetVisibleBounds(UIKit.UIWindow keyWindow, Foundation.Rect windowBounds) { var inset = UseSafeAreaInsets ? keyWindow.SafeAreaInsets : UIEdgeInsets.Zero; // Not respecting its own documentation. https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc // iOS returns all zeros for SafeAreaInsets on non-iPhones and iOS11. (ignoring nav bars or status bars) // So we need to update the top inset depending of the status bar visibility on other devices var statusBarHeight = UIApplication.SharedApplication.StatusBarHidden ? 0 : UIApplication.SharedApplication.StatusBarFrame.Size.Height; inset.Top = (nfloat)Math.Max(inset.Top, statusBarHeight); var newVisibleBounds = new Foundation.Rect( x: windowBounds.Left + inset.Left, y: windowBounds.Top + inset.Top, width: windowBounds.Width - inset.Right - inset.Left, height: windowBounds.Height - inset.Top - inset.Bottom ); SetVisibleBounds(newVisibleBounds); }
private IDisposable BuildDrawableLayer() { if (_controlHeight == 0 || _controlWidth == 0) { return(Disposable.Empty); } var drawables = new List <Drawable>(); var path = GetPath(); if (path == null) { return(Disposable.Empty); } // Scale the path using its Stretch Android.Graphics.Matrix matrix = new Android.Graphics.Matrix(); switch (this.Stretch) { case Media.Stretch.Fill: case Media.Stretch.None: matrix.SetScale((float)_scaleX, (float)_scaleY); break; case Media.Stretch.Uniform: var scale = Math.Min(_scaleX, _scaleY); matrix.SetScale((float)scale, (float)scale); break; case Media.Stretch.UniformToFill: scale = Math.Max(_scaleX, _scaleY); matrix.SetScale((float)scale, (float)scale); break; } path.Transform(matrix); // Move the path using its alignements var translation = new Android.Graphics.Matrix(); var pathBounds = new RectF(); // Compute the bounds. This is needed for stretched shapes and stroke thickness translation calculations. path.ComputeBounds(pathBounds, true); if (Stretch == Stretch.None) { // Since we are not stretching, ensure we are using (0, 0) as origin. pathBounds.Left = 0; pathBounds.Top = 0; } if (!ShouldPreserveOrigin) { //We need to translate the shape to take in account the stroke thickness translation.SetTranslate((float)(-pathBounds.Left + PhysicalStrokeThickness * 0.5f), (float)(-pathBounds.Top + PhysicalStrokeThickness * 0.5f)); } path.Transform(translation); // Draw the fill var drawArea = new Foundation.Rect(0, 0, _controlWidth, _controlHeight); var imageBrushFill = Fill as ImageBrush; if (imageBrushFill != null) { var bitmapDrawable = new BitmapDrawable(Context.Resources, imageBrushFill.TryGetBitmap(drawArea, () => RefreshShape(forceRefresh: true), path)); drawables.Add(bitmapDrawable); } else { var fill = Fill ?? SolidColorBrushHelper.Transparent; var fillPaint = fill.GetFillPaint(drawArea); var lineDrawable = new PaintDrawable(); lineDrawable.Shape = new PathShape(path, (float)_controlWidth, (float)_controlHeight); lineDrawable.Paint.Color = fillPaint.Color; lineDrawable.Paint.SetShader(fillPaint.Shader); lineDrawable.Paint.SetStyle(Paint.Style.Fill); lineDrawable.Paint.Alpha = fillPaint.Alpha; this.SetStrokeDashEffect(lineDrawable.Paint); drawables.Add(lineDrawable); } // Draw the contour if (Stroke != null) { using (var strokeBrush = new Paint(Stroke.GetStrokePaint(drawArea))) { var lineDrawable = new PaintDrawable(); lineDrawable.Shape = new PathShape(path, (float)_controlWidth, (float)_controlHeight); lineDrawable.Paint.Color = strokeBrush.Color; lineDrawable.Paint.SetShader(strokeBrush.Shader); lineDrawable.Paint.StrokeWidth = (float)PhysicalStrokeThickness; lineDrawable.Paint.SetStyle(Paint.Style.Stroke); lineDrawable.Paint.Alpha = strokeBrush.Alpha; this.SetStrokeDashEffect(lineDrawable.Paint); drawables.Add(lineDrawable); } } var layerDrawable = new LayerDrawable(drawables.ToArray()); // Set bounds must always be called, otherwise the android layout engine can't determine // the rendering size. See Drawable documentation for details. layerDrawable.SetBounds(0, 0, (int)_controlWidth, (int)_controlHeight); return(SetOverlay(this, layerDrawable)); }
/// <summary> /// Synchronously tries to return a bitmap for this ImageBrush. If the backing image is not available, /// a fetch will be scheduled and the onImageLoaded callback will be called once the backing image is ready. /// </summary> /// <param name="drawRect">The destination bounds</param> /// <param name="onImageLoaded">A callback that will be called when the backing image changes (eg, to redraw your view)</param> /// <param name="maskingPath">An optional path to clip the bitmap by (eg an ellipse)</param> /// <returns>A bitmap transformed based on target bounds and shape, Stretch mode, and RelativeTransform</returns> internal Bitmap TryGetBitmap(Foundation.Rect drawRect, Action onImageLoaded, Path maskingPath = null) { ScheduleRefreshIfNeeded(drawRect, onImageLoaded); return(GetTransformedBitmap(drawRect, maskingPath)); }
internal InputPaneVisibilityEventArgs(Foundation.Rect occludedRect) { OccludedRect = occludedRect; }
protected override Size ArrangeOverride(Size arrangeSize) { var borderAndPaddingSize = BorderAndPaddingSize; arrangeSize = arrangeSize.Subtract(borderAndPaddingSize); var childRectangle = new Foundation.Rect(BorderThickness.Left + Padding.Left, BorderThickness.Top + Padding.Top, arrangeSize.Width, arrangeSize.Height); var isHorizontal = Orientation == Windows.UI.Xaml.Controls.Orientation.Horizontal; var previousChildSize = 0.0; if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { this.Log().Debug($"StackPanel/{Name}: Arranging {Children.Count} children."); } // Shadow variables for evaluation performance var spacing = Spacing; var count = Children.Count; for (var i = 0; i < count; i++) { var view = Children[i]; var desiredChildSize = GetElementDesiredSize(view); var addSpacing = i != 0; if (isHorizontal) { childRectangle.X += previousChildSize; if (addSpacing) { childRectangle.X += spacing; } previousChildSize = desiredChildSize.Width; childRectangle.Width = desiredChildSize.Width; childRectangle.Height = Math.Max(arrangeSize.Height, desiredChildSize.Height); } else { childRectangle.Y += previousChildSize; if (addSpacing) { childRectangle.Y += spacing; } previousChildSize = desiredChildSize.Height; childRectangle.Height = desiredChildSize.Height; childRectangle.Width = Math.Max(arrangeSize.Width, desiredChildSize.Width); } var adjustedRectangle = childRectangle; ArrangeElement(view, adjustedRectangle); } var finalSizeWithBorderAndPadding = arrangeSize.Add(borderAndPaddingSize); return(finalSizeWithBorderAndPadding); }