示例#1
0
        /// <summary>
        /// Increment selection in the carousel in a chosen direction.
        /// </summary>
        /// <param name="direction">The direction to increment. Negative is backwards.</param>
        /// <param name="skipDifficulties">Whether to skip individual difficulties and only increment over full groups.</param>
        public void SelectNext(int direction = 1, bool skipDifficulties = true)
        {
            var visibleItems = Items.Where(s => !s.Item.Filtered).ToList();

            if (!visibleItems.Any())
            {
                return;
            }

            DrawableCarouselItem drawable = null;

            if (selectedBeatmap != null && (drawable = selectedBeatmap.Drawables.FirstOrDefault()) == null)
            {
                // if the selected beatmap isn't present yet, we can't correctly change selection.
                // we can fix this by changing this method to not reference drawables / Items in the first place.
                return;
            }

            int originalIndex = visibleItems.IndexOf(drawable);
            int currentIndex  = originalIndex;

            // local function to increment the index in the required direction, wrapping over extremities.
            int incrementIndex() => currentIndex = (currentIndex + direction + visibleItems.Count) % visibleItems.Count;

            while (incrementIndex() != originalIndex)
            {
                var item = visibleItems[currentIndex].Item;

                if (item.Filtered || item.State == CarouselItemState.Selected)
                {
                    continue;
                }

                switch (item)
                {
                case CarouselBeatmap beatmap:
                    if (skipDifficulties)
                    {
                        continue;
                    }
                    select(beatmap);
                    return;

                case CarouselBeatmapSet set:
                    if (skipDifficulties)
                    {
                        select(set);
                    }
                    else
                    {
                        select(direction > 0 ? set.Beatmaps.First(b => !b.Filtered) : set.Beatmaps.Last(b => !b.Filtered));
                    }
                    return;
                }
            }
        }
示例#2
0
        /// <summary>
        /// Update a item's x position and multiplicative alpha based on its y position and
        /// the current scroll position.
        /// </summary>
        /// <param name="p">The item to be updated.</param>
        /// <param name="halfHeight">Half the draw height of the carousel container.</param>
        private void updateItem(DrawableCarouselItem p, float halfHeight)
        {
            var height = p.IsPresent ? p.DrawHeight : 0;

            float itemDrawY = p.Position.Y - Current + height / 2;
            float dist      = Math.Abs(1f - itemDrawY / halfHeight);

            // Setting the origin position serves as an additive position on top of potential
            // local transformation we may want to apply (e.g. when a item gets selected, we
            // may want to smoothly transform it leftwards.)
            p.OriginPosition = new Vector2(-offsetX(dist, halfHeight), 0);

            // We are applying a multiplicative alpha (which is internally done by nesting an
            // additional container and setting that container's alpha) such that we can
            // layer transformations on top, with a similar reasoning to the previous comment.
            p.SetMultiplicativeAlpha(MathHelper.Clamp(1.75f - 1.5f * dist, 0, 1));
        }
示例#3
0
        protected override void Update()
        {
            base.Update();

            if (!itemsCache.IsValid)
            {
                updateItems();
            }

            if (!scrollPositionCache.IsValid)
            {
                updateScrollPosition();
            }

            float drawHeight = DrawHeight;

            // Remove all items that should no longer be on-screen
            scrollableContent.RemoveAll(p => p.Y <Current - p.DrawHeight || p.Y> Current + drawHeight || !p.IsPresent);

            // Find index range of all items that should be on-screen
            Trace.Assert(Items.Count == yPositions.Count);

            int firstIndex = yPositions.BinarySearch(Current - DrawableCarouselItem.MAX_HEIGHT);

            if (firstIndex < 0)
            {
                firstIndex = ~firstIndex;
            }
            int lastIndex = yPositions.BinarySearch(Current + drawHeight);

            if (lastIndex < 0)
            {
                lastIndex = ~lastIndex;
            }

            int notVisibleCount = 0;

            // Add those items within the previously found index range that should be displayed.
            for (int i = firstIndex; i < lastIndex; ++i)
            {
                DrawableCarouselItem item = Items[i];

                if (!item.Item.Visible)
                {
                    if (!item.IsPresent)
                    {
                        notVisibleCount++;
                    }
                    continue;
                }

                float depth = i + (item is DrawableCarouselBeatmapSet ? -Items.Count : 0);

                // Only add if we're not already part of the content.
                if (!scrollableContent.Contains(item))
                {
                    // Makes sure headers are always _below_ items,
                    // and depth flows downward.
                    item.Depth = depth;

                    switch (item.LoadState)
                    {
                    case LoadState.NotLoaded:
                        LoadComponentAsync(item);
                        break;

                    case LoadState.Loading:
                        break;

                    default:
                        scrollableContent.Add(item);
                        break;
                    }
                }
                else
                {
                    scrollableContent.ChangeChildDepth(item, depth);
                }
            }

            // this is not actually useful right now, but once we have groups may well be.
            if (notVisibleCount > 50)
            {
                itemsCache.Invalidate();
            }

            // Update externally controlled state of currently visible items
            // (e.g. x-offset and opacity).
            float halfHeight = drawHeight / 2;

            foreach (DrawableCarouselItem p in scrollableContent.Children)
            {
                updateItem(p, halfHeight);
            }
        }