Skip to content

Commit

Permalink
Merge pull request #16716 from peppy/carousel-less-invalidations
Browse files Browse the repository at this point in the history
Refactor carousel drawables to reduce invalidations
  • Loading branch information
smoogipoo authored Jan 31, 2022
2 parents 95582a9 + 6bc6675 commit 8d13e05
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 54 deletions.
6 changes: 2 additions & 4 deletions osu.Game/Screens/Select/BeatmapCarousel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -894,10 +894,8 @@ private void updateItem(DrawableCarouselItem item, DrawableCarouselItem parent =
// child items (difficulties) are still visible.
item.Header.X = offsetX(dist, visibleHalfHeight) - (parent?.X ?? 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 alpha transformations on top.
item.SetMultiplicativeAlpha(Math.Clamp(1.75f - 1.5f * dist, 0, 1));
// We are applying alpha to the header here such that we can layer alpha transformations on top.
item.Header.Alpha = Math.Clamp(1.75f - 1.5f * dist, 0, 1);
}

private enum PendingScrollOperation
Expand Down
29 changes: 12 additions & 17 deletions osu.Game/Screens/Select/Carousel/CarouselHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ namespace osu.Game.Screens.Select.Carousel
{
public class CarouselHeader : Container
{
public Container BorderContainer;

public readonly Bindable<CarouselItemState> State = new Bindable<CarouselItemState>(CarouselItemState.NotSelected);

private readonly HoverLayer hoverLayer;
Expand All @@ -37,17 +35,14 @@ public CarouselHeader()
RelativeSizeAxes = Axes.X;
Height = DrawableCarouselItem.MAX_HEIGHT;

InternalChild = BorderContainer = new Container
Masking = true;
CornerRadius = corner_radius;
BorderColour = new Color4(221, 255, 255, 255);

InternalChildren = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = corner_radius,
BorderColour = new Color4(221, 255, 255, 255),
Children = new Drawable[]
{
Content,
hoverLayer = new HoverLayer()
}
Content,
hoverLayer = new HoverLayer()
};
}

Expand All @@ -66,21 +61,21 @@ private void updateState(ValueChangedEvent<CarouselItemState> state)
case CarouselItemState.NotSelected:
hoverLayer.InsetForBorder = false;

BorderContainer.BorderThickness = 0;
BorderContainer.EdgeEffect = new EdgeEffectParameters
BorderThickness = 0;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(1),
Radius = 10,
Colour = Color4.Black.Opacity(100),
Colour = Color4.Black.Opacity(0.5f),
};
break;

case CarouselItemState.Selected:
hoverLayer.InsetForBorder = true;

BorderContainer.BorderThickness = border_thickness;
BorderContainer.EdgeEffect = new EdgeEffectParameters
BorderThickness = border_thickness;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = new Color4(130, 204, 255, 150),
Expand Down
10 changes: 6 additions & 4 deletions osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu
/// <summary>
/// The height of a carousel beatmap, including vertical spacing.
/// </summary>
public const float HEIGHT = height + CAROUSEL_BEATMAP_SPACING;
public const float HEIGHT = header_height + CAROUSEL_BEATMAP_SPACING;

private const float height = MAX_HEIGHT * 0.6f;
private const float header_height = MAX_HEIGHT * 0.6f;

private readonly BeatmapInfo beatmapInfo;

Expand Down Expand Up @@ -67,16 +67,18 @@ public class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu
private CancellationTokenSource starDifficultyCancellationSource;

public DrawableCarouselBeatmap(CarouselBeatmap panel)
: base(header_height)
{
beatmapInfo = panel.BeatmapInfo;
Item = panel;

// Difficulty panels should start hidden for a better initial effect.
Hide();
}

[BackgroundDependencyLoader(true)]
private void load(BeatmapManager manager, SongSelect songSelect)
{
Header.Height = height;

if (songSelect != null)
{
startRequested = b => songSelect.FinaliseSelection(b);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,10 @@ protected override void UpdateItem()
},
};

background.DelayedLoadComplete += fadeContentIn;
mainFlow.DelayedLoadComplete += fadeContentIn;
background.DelayedLoadComplete += d => d.FadeInFromZero(750, Easing.OutQuint);
mainFlow.DelayedLoadComplete += d => d.FadeInFromZero(500, Easing.OutQuint);
}

private void fadeContentIn(Drawable d) => d.FadeInFromZero(750, Easing.OutQuint);

protected override void Deselected()
{
base.Deselected();
Expand Down
71 changes: 46 additions & 25 deletions osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,44 +60,38 @@ public CarouselItem Item
}
}

protected DrawableCarouselItem()
protected DrawableCarouselItem(float headerHeight = MAX_HEIGHT)
{
RelativeSizeAxes = Axes.X;

Alpha = 0;

InternalChildren = new Drawable[]
{
MovementContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
Header = new CarouselHeader(),
Header = new CarouselHeader
{
Height = headerHeight,
},
Content = new Container
{
RelativeSizeAxes = Axes.Both,
Y = headerHeight,
}
}
},
};
}

public void SetMultiplicativeAlpha(float alpha) => Header.BorderContainer.Alpha = alpha;

protected override void LoadComplete()
{
base.LoadComplete();

UpdateItem();
}

protected override void Update()
{
base.Update();
Content.Y = Header.Height;
}

protected virtual void UpdateItem()
{
if (item == null)
Expand All @@ -121,29 +115,56 @@ protected virtual void UpdateItem()

private void onStateChange(ValueChangedEvent<bool> _) => Scheduler.AddOnce(ApplyState);

private CarouselItemState? lastAppliedState;

protected virtual void ApplyState()
{
// Use the fact that we know the precise height of the item from the model to avoid the need for AutoSize overhead.
// Additionally, AutoSize doesn't work well due to content starting off-screen and being masked away.
Height = Item.TotalHeight;

Debug.Assert(Item != null);

switch (Item.State.Value)
if (lastAppliedState != Item.State.Value)
{
case CarouselItemState.NotSelected:
Deselected();
break;
lastAppliedState = Item.State.Value;

// Use the fact that we know the precise height of the item from the model to avoid the need for AutoSize overhead.
// Additionally, AutoSize doesn't work well due to content starting off-screen and being masked away.
Height = Item.TotalHeight;

case CarouselItemState.Selected:
Selected();
break;
switch (lastAppliedState)
{
case CarouselItemState.NotSelected:
Deselected();
break;

case CarouselItemState.Selected:
Selected();
break;
}
}

if (!Item.Visible)
this.FadeOut(300, Easing.OutQuint);
Hide();
else
this.FadeIn(250);
Show();
}

private bool isVisible = true;

public override void Show()
{
if (isVisible)
return;

isVisible = true;
this.FadeIn(250);
}

public override void Hide()
{
if (!isVisible)
return;

isVisible = false;
this.FadeOut(300, Easing.OutQuint);
}

protected virtual void Selected()
Expand Down

0 comments on commit 8d13e05

Please sign in to comment.