Beispiel #1
0
 private Uno.UI.IndexPath?GetDecrementedItemIndex(Uno.UI.IndexPath currentItem)
 {
     if (!IsGrouping)
     {
         if (currentItem.Section > 0)
         {
             throw new InvalidOperationException("Received an index with non-zero group, but source is not grouped.");
         }
         if (currentItem.Row == 0)
         {
             return(null);
         }
         return(Uno.UI.IndexPath.FromRowSection(currentItem.Row - 1, 0));
     }
     if (currentItem.Row == 0)
     {
         var nextSection = GetNextNonEmptySection(currentItem.Section, -1);
         if (!nextSection.HasValue)
         {
             //No previous non-empty sections
             return(null);
         }
         return(Uno.UI.IndexPath.FromRowSection(GetDisplayGroupCount(nextSection.Value) - 1, nextSection.Value));
     }
     return(Uno.UI.IndexPath.FromRowSection(currentItem.Row - 1, currentItem.Section));
 }
        protected override Line CreateLine(GeneratorDirection direction,
                                           int extentOffset,
                                           int breadthOffset,
                                           int availableBreadth,
                                           RecyclerView.Recycler recycler,
                                           RecyclerView.State state,
                                           Uno.UI.IndexPath nextVisibleItem,
                                           bool isNewGroup
                                           )
        {
            var item = GetFlatItemIndex(nextVisibleItem);
            var view = recycler.GetViewForPosition(item, state);

            if (!(view is SelectorItem))
            {
                throw new InvalidOperationException($"Expected {nameof(SelectorItem)} but received {view?.GetType().ToString() ?? "<null>"}");
            }
            var size         = AddViewAtOffset(view, direction, extentOffset, breadthOffset, availableBreadth);
            var physicalSize = size.LogicalToPhysicalPixels();

            var breadth = (int)(ScrollOrientation == Orientation.Vertical ? physicalSize.Width : physicalSize.Height);

            return(new Line
            {
                NumberOfViews = 1,
                Extent = (int)(ScrollOrientation == Orientation.Vertical ? physicalSize.Height : physicalSize.Width),
                FirstItem = nextVisibleItem,
                LastItem = nextVisibleItem,
                Breadth = breadth
            });
        }
Beispiel #3
0
 public CollectionChangedOperation(Uno.UI.IndexPath startingIndex, int range, NotifyCollectionChangedAction action, Element elementType)
 {
     StartingIndex = startingIndex;
     Range         = range;
     Action        = action;
     ElementType   = elementType;
 }
Beispiel #4
0
		private Uno.UI.IndexPath? GetIncrementedItemIndex(Uno.UI.IndexPath currentItem)
		{
			if (!IsGrouping)
			{
				if (currentItem.Section > 0)
				{
					throw new InvalidOperationException("Received an index with non-zero group, but source is not grouped.");
				}

				if (currentItem.Row == NumberOfItems - 1)
				{
					return null;
				}
				return Uno.UI.IndexPath.FromRowSection(currentItem.Row + 1, 0);
			}

			if (currentItem.Row == GetDisplayGroupCount(currentItem.Section) - 1)
			{
				var nextSection = GetNextNonEmptySection(currentItem.Section, 1);
				if (!nextSection.HasValue)
				{
					//No more non-empty sections
					return null;
				}
				return Uno.UI.IndexPath.FromRowSection(0, nextSection.Value);
			}
			return Uno.UI.IndexPath.FromRowSection(currentItem.Row + 1, currentItem.Section);
		}
Beispiel #5
0
            public Line(FrameworkElement[] containerViews, Uno.UI.IndexPath firstItem, Uno.UI.IndexPath lastItem, int firstItemFlat)
            {
                if (containerViews.Length == 0)
                {
                    throw new InvalidOperationException("Line must contain at least one view");
                }

                ContainerViews = containerViews;
                FirstItem      = firstItem;
                LastItem       = lastItem;
                FirstItemFlat  = firstItemFlat;
            }
Beispiel #6
0
		/// <summary>
		/// Gets a flattened item index. Unlike <see cref="GetDisplayIndexFromIndexPath(IndexPath)"/>, this can not be overridden to adjust for 
		/// supplementary elements (eg headers) on derived controls. This represents the (flattened) index in the data source as opposed
		/// to the 'display' index.
		/// 
		/// Note that the <see cref="IndexPath"/> is still the 'display' value in that it doesn't 'know about' empty groups if HidesIfEmpty is set to true.
		/// </summary>
		internal int GetIndexFromIndexPath(Uno.UI.IndexPath indexPath)
		{
			if (indexPath.Section == 0)
			{
				return indexPath.Row;
			}

			var itemsInPrecedingSections = 0;
			for (int i = 0; i < indexPath.Section; i++)
			{
				itemsInPrecedingSections += GetDisplayGroupCount(i);
			}
			return itemsInPrecedingSections + indexPath.Row;
		}
Beispiel #7
0
        /// <summary>
        /// Apply the offset to a collection index resulting from this collection operation.
        /// </summary>
        /// <param name="indexPath">The index in the collection prior to the operation</param>
        /// <returns>The offset position, or null if this position is no longer valid (ie because it has been removed by the operation).</returns>
        public Uno.UI.IndexPath?Offset(Uno.UI.IndexPath indexPath)
        {
            var section = indexPath.Section;
            var row     = indexPath.Row;

            switch (this)
            {
            case var itemAdd when itemAdd.ElementType == CollectionChangedOperation.Element.Item &&
                itemAdd.Action == NotifyCollectionChangedAction.Add &&
                itemAdd.StartingIndex.Section == section &&
                itemAdd.EndIndex.Row <= row:
                row += itemAdd.Range;
                break;

            case var itemRemove when itemRemove.ElementType == CollectionChangedOperation.Element.Item &&
                itemRemove.Action == NotifyCollectionChangedAction.Remove &&
                itemRemove.StartingIndex.Section == section &&
                itemRemove.EndIndex.Row < row:
                row -= itemRemove.Range;
                break;

            case var thisItemRemoved when thisItemRemoved.ElementType == CollectionChangedOperation.Element.Item &&
                (thisItemRemoved.Action == NotifyCollectionChangedAction.Remove || thisItemRemoved.Action == NotifyCollectionChangedAction.Replace) &&
                thisItemRemoved.StartingIndex.Section == section &&
                thisItemRemoved.StartingIndex.Row <= row && thisItemRemoved.EndIndex.Row >= row:
                // This item has been removed or replaced, the index is no longer valid
                return(null);

            // Group operations are currently unsupported
            case var groupAdd when groupAdd.ElementType == CollectionChangedOperation.Element.Group &&
                groupAdd.Action == NotifyCollectionChangedAction.Add &&
                groupAdd.EndIndex.Section <= section:
            case var groupRemove when groupRemove.ElementType == CollectionChangedOperation.Element.Group &&
                groupRemove.Action == NotifyCollectionChangedAction.Remove &&
                groupRemove.EndIndex.Section < section:
            case var thisGroupRemoved when thisGroupRemoved.ElementType == CollectionChangedOperation.Element.Group &&
                (thisGroupRemoved.Action == NotifyCollectionChangedAction.Remove || thisGroupRemoved.Action == NotifyCollectionChangedAction.Replace) &&
                thisGroupRemoved.StartingIndex.Section <= section && thisGroupRemoved.EndIndex.Section >= section:
                if (this.Log().IsEnabled(LogLevel.Warning))
                {
                    this.Log().LogWarning("Collection change not supported");
                }
                break;
            }

            return(Uno.UI.IndexPath.FromRowSection(row, section));
        }
Beispiel #8
0
        /// <summary>
        /// Sequentially applies offsets to a collection index resulting from multiple collection operations.
        /// </summary>
        /// <param name="index">The index in the collection prior to the operation</param>
        /// <param name="collectionChanges">The changes to be applied, in order from oldest to newest.</param>
        /// <returns>The offset position, or null if this position is no longer valid (ie because it has been removed by one of the operations).</returns>
        public static Uno.UI.IndexPath?Offset(Uno.UI.IndexPath index, IEnumerable <CollectionChangedOperation> collectionChanges)
        {
            Uno.UI.IndexPath?newIndex = index;

            foreach (var change in collectionChanges)
            {
                if (newIndex is Uno.UI.IndexPath newIndexValue)
                {
                    newIndex = change.Offset(newIndexValue);
                }
                else
                {
                    break;
                }
            }

            return(newIndex);
        }
Beispiel #9
0
        internal override int GetDisplayIndexFromIndexPath(Uno.UI.IndexPath indexPath)
        {
            var displayIndex = base.GetDisplayIndexFromIndexPath(indexPath);

            return(ConvertIndexToDisplayPosition(displayIndex));
        }
        protected override Line CreateLine(GeneratorDirection fillDirection, double extentOffset, double availableBreadth, Uno.UI.IndexPath nextVisibleItem)
        {
            var item = GetFlatItemIndex(nextVisibleItem);
            var view = Generator.DequeueViewForItem(item);

            AddView(view, fillDirection, extentOffset, 0);

            return(new Line(new[] { view }, nextVisibleItem, nextVisibleItem, item));
        }
Beispiel #11
0
        protected override Line CreateLine(GeneratorDirection fillDirection, double extentOffset, double availableBreadth, Uno.UI.IndexPath nextVisibleItem)
        {
            if (ShouldInsertReorderingView(extentOffset) && GetAndUpdateReorderingIndex() is { } reorderingIndex)
            {
                nextVisibleItem = reorderingIndex;
            }

            var item = GetFlatItemIndex(nextVisibleItem);
            var view = Generator.DequeueViewForItem(item);

            AddView(view, fillDirection, extentOffset, 0);

            return(new Line(item, (view, nextVisibleItem)));
        }
Beispiel #12
0
        protected override Line CreateLine(GeneratorDirection direction,
                                           int extentOffset,
                                           int breadthOffset,
                                           int availableBreadth,
                                           RecyclerView.Recycler recycler,
                                           RecyclerView.State state,
                                           Uno.UI.IndexPath nextVisibleItem,
                                           bool isNewGroup
                                           )
        {
            var itemsInLine     = ResolveMaximumItemsInLine(availableBreadth);
            var firstItemInLine = nextVisibleItem;

            //Find first item in line, since the item we are passed is the last
            if (direction == GeneratorDirection.Backward)
            {
                // We are recreating the last line of the group - it may be truncated (if the total items are not an even multiple
                // of the items-per-line).
                if (isNewGroup)
                {
                    itemsInLine = XamlParent.GetItemsOnLastLine(firstItemInLine.Section, itemsInLine);
                }
                for (int i = 0; i < itemsInLine - 1; i++)
                {
                    firstItemInLine = GetNextUnmaterializedItem(GeneratorDirection.Backward, firstItemInLine).Value;
                    var isCorrectGroup = firstItemInLine.Section == nextVisibleItem.Section;
                    if (!isCorrectGroup)
                    {
                        //TODO: fix bug that makes this happen (#47229)
                    }
                    Debug.Assert(isCorrectGroup, GetAssertMessage("First item should not be from a different group"));
                }
            }
            Uno.UI.IndexPath lastItemInLine = firstItemInLine;

            Uno.UI.IndexPath?currentItem = firstItemInLine;
            var availableWidth           = ResolveAvailableWidth(availableBreadth);
            var availableHeight          = ResolveAvailableHeight(availableBreadth);

            int usedBreadth = 0;

            for (int i = 0; i < itemsInLine; i++)
            {
                var view = recycler.GetViewForPosition(GetFlatItemIndex(currentItem.Value), state);

                if (!(view is SelectorItem))
                {
                    throw new InvalidOperationException($"Expected {nameof(SelectorItem)} but received {view?.GetType().ToString() ?? "<null>"}");
                }

                //Add view before we measure it, this ensures that DP inheritances are correctly applied
                AddView(view, direction);

                var slotSize             = new Windows.Foundation.Size(availableWidth, availableHeight).PhysicalToLogicalPixels();
                var measuredSize         = _layouter.MeasureChild(view, slotSize);
                var physicalMeasuredSize = measuredSize.LogicalToPhysicalPixels();
                var measuredWidth        = (int)physicalMeasuredSize.Width;
                var measuredHeight       = (int)physicalMeasuredSize.Height;

                if (_implicitItemWidth == null)
                {
                    //Set these values to dimensions of first materialised item
                    _implicitItemWidth  = measuredWidth;
                    _implicitItemHeight = measuredHeight;

                    // When an item dimension is not fixed, we need to arrange based on the measured size,
                    // otherwise the arrange will be passed a dimension that is too large and the first
                    // few items will not be visible
                    if (double.IsNaN(ItemWidth))
                    {
                        slotSize.Width = ViewHelper.PhysicalToLogicalPixels(_implicitItemWidth.Value);
                    }
                    if (double.IsNaN(ItemHeight))
                    {
                        slotSize.Height = ViewHelper.PhysicalToLogicalPixels(_implicitItemHeight.Value);
                    }

                    availableWidth  = ResolveAvailableWidth(availableBreadth);
                    availableHeight = ResolveAvailableHeight(availableBreadth);

                    itemsInLine = ResolveMaximumItemsInLine(availableBreadth);
                }

                LayoutChild(view,
                            GeneratorDirection.Forward,
                            //We always lay out view 'top down' so that it is aligned correctly if its height is less than the line height
                            direction == GeneratorDirection.Forward ? extentOffset : extentOffset - ResolveItemExtent().Value,
                            breadthOffset + usedBreadth,
                            slotSize
                            );

                usedBreadth   += ResolveItemBreadth().Value;
                lastItemInLine = currentItem.Value;

                currentItem = GetNextUnmaterializedItem(GeneratorDirection.Forward, currentItem);
                if (currentItem == null || currentItem.Value.Section != firstItemInLine.Section)
                {
                    itemsInLine = i + 1;
                    break;
                }
            }

            return(new Line
            {
                NumberOfViews = itemsInLine,
                Extent = ResolveItemExtent().Value,
                Breadth = usedBreadth,
                FirstItem = firstItemInLine,
                LastItem = lastItemInLine
            });
        }
Beispiel #13
0
 /// <summary>
 /// Get flattened item index, if the source is grouped, to supply to <see cref="GetElementFromDisplayPosition(int)"/>.
 /// </summary>
 internal virtual int GetDisplayIndexFromIndexPath(Uno.UI.IndexPath indexPath)
 {
     return(GetIndexFromIndexPath(indexPath));
 }
 public bool Contains(Uno.UI.IndexPath index) => index >= FirstItem && index <= LastItem;