From 22a326d385bfc4ca59895f895a7071e4d788947a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Mon, 6 Jan 2025 18:29:24 +0100 Subject: [PATCH] Redesign timeline to look more like stable --- packages/common/src/editor/EditorLayout.ts | 16 +++- .../editor/screens/EditorScreenContainer.ts | 4 + .../screens/compose/ComposeScreenTimeline.ts | 17 ++-- .../SliderVelocityAdjustmentPiece.ts | 9 ++- .../hitObjects/TimelineHitObjectBlueprint.ts | 43 ++++++----- .../TimelineHitObjectBlueprintContainer.ts | 18 +++++ .../hitObjects/TimelineHitObjectBody.ts | 5 +- .../hitObjects/TimelineHitObjectCircle.ts | 71 +++++++++++++++++ .../hitObjects/TimelineHitObjectHead.ts | 77 ++++--------------- .../hitObjects/TimelineHitObjectTail.ts | 75 ++---------------- .../hitObjects/TimelineRepeatPiece.ts | 66 ++++++---------- .../skinning/stable/DrawableComboNumber.ts | 3 +- .../skinning/stable/OsuSkinComponentLookup.ts | 1 + .../osu/skinning/stable/OsuSkinComponents.ts | 2 + .../stable/StableOsuSkinTransformer.ts | 4 + .../skinning/stable/StableTimelineCircle.ts | 26 +++++++ 16 files changed, 225 insertions(+), 212 deletions(-) create mode 100644 packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectCircle.ts create mode 100644 packages/common/src/rulesets/osu/skinning/stable/StableTimelineCircle.ts diff --git a/packages/common/src/editor/EditorLayout.ts b/packages/common/src/editor/EditorLayout.ts index 0f95e8e8..8403f706 100644 --- a/packages/common/src/editor/EditorLayout.ts +++ b/packages/common/src/editor/EditorLayout.ts @@ -1,4 +1,13 @@ -import { Axes, CompositeDrawable, dependencyLoader, EasingFunction, Invalidation, LayoutMember } from 'osucad-framework'; +import type { + ReadonlyDependencyContainer, +} from 'osucad-framework'; +import { + Axes, + CompositeDrawable, + EasingFunction, + Invalidation, + LayoutMember, +} from 'osucad-framework'; import { EditorBottomBar } from './bottomBar/EditorBottomBar'; import { EditorHeader } from './header/EditorHeader'; import { EditorScreenContainer } from './screens/EditorScreenContainer'; @@ -10,8 +19,9 @@ export class EditorLayout extends CompositeDrawable { this.addLayout(this.#drawSizeBacking); } - @dependencyLoader() - [Symbol('load')]() { + protected override load(dependencies: ReadonlyDependencyContainer) { + super.load(dependencies); + this.relativeSizeAxes = Axes.Both; this.internalChildren = [ diff --git a/packages/common/src/editor/screens/EditorScreenContainer.ts b/packages/common/src/editor/screens/EditorScreenContainer.ts index 9459b0d8..238ec732 100644 --- a/packages/common/src/editor/screens/EditorScreenContainer.ts +++ b/packages/common/src/editor/screens/EditorScreenContainer.ts @@ -27,6 +27,10 @@ export class EditorScreenContainer extends CompositeDrawable { super.load(dependencies); this.currentScreen.bindTo(this.screenManager.currentScreen); + } + + protected override loadComplete() { + super.loadComplete(); this.currentScreen.addOnChangeListener((screen) => { if (this.#currentScreenDrawable) { diff --git a/packages/common/src/editor/screens/compose/ComposeScreenTimeline.ts b/packages/common/src/editor/screens/compose/ComposeScreenTimeline.ts index 2afd7dd7..91a9bade 100644 --- a/packages/common/src/editor/screens/compose/ComposeScreenTimeline.ts +++ b/packages/common/src/editor/screens/compose/ComposeScreenTimeline.ts @@ -27,22 +27,23 @@ export class ComposeScreenTimeline extends Timeline { ); this.addAll( - new Container({ - relativeSizeAxes: Axes.X, - height: 10, - anchor: Anchor.BottomLeft, - origin: Anchor.BottomLeft, - child: new BottomAlignedTickDisplay(), - }), new Container({ relativeSizeAxes: Axes.Both, - height: 0.5, + height: 0.65, anchor: Anchor.CenterLeft, origin: Anchor.CenterLeft, children: [ this.blueprintContainer = new ComposeScreenTimelineHitObjectBlueprintContainer(), ], }), + new Container({ + relativeSizeAxes: Axes.X, + height: 10, + anchor: Anchor.BottomLeft, + origin: Anchor.BottomLeft, + child: new BottomAlignedTickDisplay(), + }), + ); this.addInternal(new CurrentTimeOverlay()); diff --git a/packages/common/src/editor/ui/timeline/hitObjects/SliderVelocityAdjustmentPiece.ts b/packages/common/src/editor/ui/timeline/hitObjects/SliderVelocityAdjustmentPiece.ts index 5a84a26a..3ef2e6b3 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/SliderVelocityAdjustmentPiece.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/SliderVelocityAdjustmentPiece.ts @@ -1,4 +1,5 @@ import type { DragEndEvent, DragEvent, DragStartEvent, MouseDownEvent, ReadonlyDependencyContainer, TouchDownEvent, TouchUpEvent } from 'osucad-framework'; +import type { Color } from 'pixi.js'; import type { HitObject } from '../../../../hitObjects/HitObject'; import type { IHasSliderVelocity } from '../../../../hitObjects/IHasSliderVelocity'; import type { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; @@ -43,10 +44,10 @@ export class SliderVelocityAdjustmentPiece extends TimelineHitObjectTail { ); } - protected override updateColors() { - super.updateColors(); + protected override updateColor(color: Color) { + super.updateColor(color); - this.#longPressOutline.color = ColorUtils.lighten(this.accentColor.value, 0.5); + this.#longPressOutline.color = ColorUtils.lighten(this.accentColor.value, 0.25); } override onDragStart(e: DragStartEvent): boolean { @@ -120,7 +121,7 @@ export class SliderVelocityAdjustmentPiece extends TimelineHitObjectTail { if (e.button === MouseButton.Right && this.#touchDown) { this.#dragFromLongPress = true; this.#longPressOutline.scaleTo(1.2, 300, EasingFunction.OutExpo); - this.#longPressOutline.fadeIn(100); + this.#longPressOutline.fadeTo(0.5, 100); return true; } diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprint.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprint.ts index 9e21c1c6..9d9dacb3 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprint.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprint.ts @@ -1,19 +1,31 @@ -import type { Drawable, ReadonlyDependencyContainer } from 'osucad-framework'; +import type { + ReadonlyDependencyContainer, +} from 'osucad-framework'; import type { HitObjectLifetimeEntry } from '../../../../hitObjects/drawables/HitObjectLifetimeEntry'; import type { HitObjectSelectionEvent } from '../../../screens/compose/HitObjectSelectionManager'; -import { Anchor, Axes, Bindable, BindableBoolean, BindableNumber, Container, FastRoundedBox, FillMode, provide, resolved } from 'osucad-framework'; +import { + Anchor, + Axes, + Bindable, + BindableBoolean, + BindableNumber, + Container, + FillMode, + provide, + resolved, +} from 'osucad-framework'; import { Color } from 'pixi.js'; import { HitObjectList } from '../../../../beatmap/HitObjectList'; import { UpdateHandler } from '../../../../crdt/UpdateHandler'; import { hasComboInformation } from '../../../../hitObjects/IHasComboInformation'; import { hasDuration } from '../../../../hitObjects/IHasDuration'; import { hasSliderVelocity } from '../../../../hitObjects/IHasSliderVelocity'; -import { OsucadColors } from '../../../../OsucadColors'; import { PoolableDrawableWithLifetime } from '../../../../pooling/PoolableDrawableWithLifetime'; import { SliderRepeat } from '../../../../rulesets/osu/hitObjects/SliderRepeat'; import { ISkinSource } from '../../../../skinning/ISkinSource'; import { HitObjectSelectionManager } from '../../../screens/compose/HitObjectSelectionManager'; import { Timeline } from '../Timeline'; +import { TimelinePart } from '../TimelinePart'; import { DurationAdjustmentPiece } from './DurationAdjustmentPiece'; import { SliderVelocityAdjustmentPiece } from './SliderVelocityAdjustmentPiece'; import { TimelineHitObjectBody } from './TimelineHitObjectBody'; @@ -57,7 +69,7 @@ export class TimelineHitObjectBlueprint extends PoolableDrawableWithLifetime this.x = time.value); - this.selected.addOnChangeListener((selected) => { - if (selected.value) - this.selectionOutline.show(); - else - this.selectionOutline.hide(); - }, { immediate: true }); + // this.selected.addOnChangeListener((selected) => { + // if (selected.value) + // this.selectionOutline.show(); + // else + // this.selectionOutline.hide(); + // }, { immediate: true }); this.comboIndexBindable.valueChanged.addListener(this.updateComboColor, this); this.currentSkin.sourceChanged.addListener(this.updateComboColor, this); diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprintContainer.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprintContainer.ts index 6c8372a7..1b7a2f47 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprintContainer.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBlueprintContainer.ts @@ -3,6 +3,7 @@ import type { HitObject } from '../../../../hitObjects/HitObject'; import { Axes, Bindable, dependencyLoader, DrawablePool, LoadState, resolved } from 'osucad-framework'; import { IBeatmap } from '../../../../beatmap/IBeatmap'; import { HitObjectLifetimeEntry } from '../../../../hitObjects/drawables/HitObjectLifetimeEntry'; +import { zipWithNext } from '../../../../utils/arrayUtils'; import { TimelineBlueprintContainer } from '../TimelineBlueprintContainer'; import { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; @@ -58,6 +59,8 @@ export class TimelineHitObjectBlueprintContainer extends TimelineBlueprintContai } addHitObject(hitObject: HitObject) { + if (hitObject.transient) + return; this.#addEntry(new TimelineHitObjectLifetimeEntry(hitObject)); } @@ -134,4 +137,19 @@ export class TimelineHitObjectBlueprintContainer extends TimelineBlueprintContai return super.buildNonPositionalInputQueue(queue, allowBlocking); } + + override updateAfterChildren() { + super.updateAfterChildren(); + + let stackHeight = 0; + + for (const [current, last] of zipWithNext(this.blueprintContainer.content.aliveInternalChildren as TimelineHitObjectBlueprint[])) { + if (current.hitObject!.startTime < last.hitObject!.endTime) + stackHeight++; + else + stackHeight = 0; + + current.y = -stackHeight * 8; + } + } } diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBody.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBody.ts index 1cc1e64a..d56d9b42 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBody.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectBody.ts @@ -2,7 +2,7 @@ import type { DragEndEvent, DragEvent, DragStartEvent, MouseDownEvent, ReadonlyD import type { Color } from 'pixi.js'; import type { HitObject } from '../../../../hitObjects/HitObject'; import type { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; -import { Axes, Bindable, ColorUtils, CompositeDrawable, FastRoundedBox, MouseButton, resolved } from 'osucad-framework'; +import { Axes, Bindable, CompositeDrawable, FastRoundedBox, MouseButton, resolved } from 'osucad-framework'; import { HitObjectList } from '../../../../beatmap/HitObjectList'; import { UpdateHandler } from '../../../../crdt/UpdateHandler'; import { EditorClock } from '../../../EditorClock'; @@ -30,6 +30,7 @@ export class TimelineHitObjectBody extends CompositeDrawable { this.#body = new FastRoundedBox({ relativeSizeAxes: Axes.Both, cornerRadius: 100, + alpha: 0.75, }), ); @@ -38,7 +39,7 @@ export class TimelineHitObjectBody extends CompositeDrawable { } protected updateColors() { - this.#body.color = ColorUtils.darken(this.accentColor.value, 0.25); + this.#body.color = this.accentColor.value; } @resolved(HitObjectList) diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectCircle.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectCircle.ts new file mode 100644 index 00000000..a6b6282d --- /dev/null +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectCircle.ts @@ -0,0 +1,71 @@ +import type { ReadonlyDependencyContainer } from 'osucad-framework'; +import type { Color } from 'pixi.js'; +import type { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; +import { Anchor, Axes, Bindable, BindableBoolean, CompositeDrawable, DrawableSprite, FillMode, resolved } from 'osucad-framework'; +import { ISkinSource } from '../../../../skinning/ISkinSource'; + +export class TimelineHitObjectCircle extends CompositeDrawable { + constructor(readonly blueprint: TimelineHitObjectBlueprint) { + super(); + + this.relativeSizeAxes = Axes.Both; + this.fillMode = FillMode.Fit; + } + + protected circle!: DrawableSprite; + + protected overlay!: DrawableSprite; + + protected selectionOverlay!: DrawableSprite; + + @resolved(ISkinSource) + protected skin!: ISkinSource; + + protected readonly accentColor = new Bindable(null!); + + protected readonly selected = new BindableBoolean(); + + protected override load(dependencies: ReadonlyDependencyContainer) { + super.load(dependencies); + + const scaleCorrection = 64 / 60; + + this.addAllInternal( + this.circle = new DrawableSprite({ + relativeSizeAxes: Axes.Both, + texture: this.skin.getTexture('hitcircle'), + anchor: Anchor.Center, + origin: Anchor.Center, + scale: scaleCorrection, + }), + this.overlay = new DrawableSprite({ + relativeSizeAxes: Axes.Both, + texture: this.skin.getTexture('hitcircleoverlay'), + anchor: Anchor.Center, + origin: Anchor.Center, + scale: scaleCorrection, + }), + this.selectionOverlay = new DrawableSprite({ + relativeSizeAxes: Axes.Both, + texture: this.skin.getTexture('hitcircleselect'), + anchor: Anchor.Center, + origin: Anchor.Center, + scale: scaleCorrection, + }), + ); + + this.accentColor.bindTo(this.blueprint.accentColor); + this.selected.bindTo(this.blueprint.selected); + } + + protected override loadComplete() { + super.loadComplete(); + + this.accentColor.addOnChangeListener(color => this.updateColor(color.value), { immediate: true }); + this.selected.addOnChangeListener(selected => this.selectionOverlay.alpha = selected.value ? 1 : 0, { immediate: true }); + } + + protected updateColor(color: Color) { + this.circle.color = color; + } +} diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectHead.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectHead.ts index 3662470b..fd853764 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectHead.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectHead.ts @@ -1,78 +1,31 @@ -import type { HoverEvent, HoverLostEvent } from 'osucad-framework'; -import type { Color } from 'pixi.js'; +import type { ReadonlyDependencyContainer } from 'osucad-framework'; import type { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; -import { Anchor, Axes, Bindable, ColorUtils, CompositeDrawable, dependencyLoader, FastRoundedBox, FillMode } from 'osucad-framework'; -import { OsucadSpriteText } from '../../../../drawables/OsucadSpriteText'; +import { DrawableComboNumber } from '../../../../rulesets/osu/skinning/stable/DrawableComboNumber'; +import { TimelineHitObjectCircle } from './TimelineHitObjectCircle'; -export class TimelineHitObjectHead extends CompositeDrawable { - constructor(readonly blueprint: TimelineHitObjectBlueprint) { - super(); - this.relativeSizeAxes = Axes.Both; - this.fillMode = FillMode.Fit; +export class TimelineHitObjectHead extends TimelineHitObjectCircle { + constructor(blueprint: TimelineHitObjectBlueprint) { + super(blueprint); } - #outline!: FastRoundedBox; + #comboNumber!: DrawableComboNumber; - #body!: FastRoundedBox; - - #hoverOverlay!: FastRoundedBox; - - protected accentColor = new Bindable(null!); - - #comboNumber!: OsucadSpriteText; - - @dependencyLoader() - [Symbol('load')]() { + protected override load(dependencies: ReadonlyDependencyContainer) { + super.load(dependencies); this.addAllInternal( - this.#outline = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - anchor: Anchor.Center, - origin: Anchor.Center, - }), - this.#body = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - anchor: Anchor.Center, - origin: Anchor.Center, - scale: 0.85, - }), - this.#hoverOverlay = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - alpha: 0, - anchor: Anchor.Center, - origin: Anchor.Center, - }), - this.#comboNumber = new OsucadSpriteText({ - text: '1', - fontSize: 17, - anchor: Anchor.Center, - origin: Anchor.Center, - }), + this.#comboNumber = new DrawableComboNumber(), ); - this.accentColor.bindTo(this.blueprint.accentColor); - this.accentColor.addOnChangeListener(() => this.updateColors(), { immediate: true }); - this.blueprint.indexInComboBindable.addOnChangeListener(() => this.#updateComboNumber(), { immediate: true }); } - protected updateColors() { - this.#outline.color = ColorUtils.darken(this.accentColor.value, 0.25); - this.#body.color = this.accentColor.value; + #updateComboNumber() { + this.#comboNumber.comboNumber = this.blueprint.indexInComboBindable.value + 1; } - override onHover(e: HoverEvent): boolean { - this.#hoverOverlay.alpha = 0.35; - return true; - } + override update() { + super.update(); - override onHoverLost(e: HoverLostEvent) { - this.#hoverOverlay.alpha = 0; - } - - #updateComboNumber() { - this.#comboNumber.text = (this.blueprint.indexInComboBindable.value + 1).toString(); + this.#comboNumber.scale = (this.drawHeight / 140); } } diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectTail.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectTail.ts index 37956e08..aa4fc867 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectTail.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineHitObjectTail.ts @@ -1,78 +1,15 @@ -import type { HoverEvent, HoverLostEvent, MouseDownEvent } from 'osucad-framework'; -import type { Color } from 'pixi.js'; +import type { MouseDownEvent } from 'osucad-framework'; import type { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; -import { Anchor, Axes, Bindable, ColorUtils, CompositeDrawable, dependencyLoader, FastRoundedBox, FillMode, MouseButton } from 'osucad-framework'; +import { Anchor, MouseButton } from 'osucad-framework'; +import { TimelineHitObjectCircle } from './TimelineHitObjectCircle'; -export class TimelineHitObjectTail extends CompositeDrawable { - constructor(readonly blueprint: TimelineHitObjectBlueprint) { - super(); - this.relativeSizeAxes = Axes.Both; - this.fillMode = FillMode.Fit; +export class TimelineHitObjectTail extends TimelineHitObjectCircle { + constructor(blueprint: TimelineHitObjectBlueprint) { + super(blueprint); this.anchor = Anchor.CenterRight; this.origin = Anchor.CenterRight; } - #body!: FastRoundedBox; - - #outline!: FastRoundedBox; - - #hoverOverlay!: FastRoundedBox; - - protected get outline() { - return this.#outline; - } - - protected get body() { - return this.#body; - } - - protected accentColor = new Bindable(null!); - - @dependencyLoader() - [Symbol('load')]() { - this.addAllInternal( - this.#outline = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - anchor: Anchor.Center, - origin: Anchor.Center, - }), - this.#body = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - scale: 0.85, - anchor: Anchor.Center, - origin: Anchor.Center, - }), - this.#hoverOverlay = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - alpha: 0, - }), - ); - } - - protected override loadComplete() { - super.loadComplete(); - - this.accentColor.bindTo(this.blueprint.accentColor); - this.accentColor.addOnChangeListener(() => this.updateColors(), { immediate: true }); - } - - protected updateColors() { - this.#outline.color = ColorUtils.darken(this.accentColor.value, 0.25); - this.#body.color = this.accentColor.value; - } - - override onHover(e: HoverEvent): boolean { - this.#hoverOverlay.alpha = 0.35; - return true; - } - - override onHoverLost(e: HoverLostEvent) { - this.#hoverOverlay.alpha = 0; - } - override onMouseDown(e: MouseDownEvent): boolean { return e.button === MouseButton.Left; } diff --git a/packages/common/src/editor/ui/timeline/hitObjects/TimelineRepeatPiece.ts b/packages/common/src/editor/ui/timeline/hitObjects/TimelineRepeatPiece.ts index 8bf21b5f..739fc45a 100644 --- a/packages/common/src/editor/ui/timeline/hitObjects/TimelineRepeatPiece.ts +++ b/packages/common/src/editor/ui/timeline/hitObjects/TimelineRepeatPiece.ts @@ -1,55 +1,35 @@ -import type { Color } from 'pixi.js'; -import type { HitObject } from '../../../../hitObjects/HitObject'; +import type { ReadonlyDependencyContainer } from 'osucad-framework'; +import type { SliderRepeat } from '../../../../rulesets/osu/hitObjects/SliderRepeat'; import type { TimelineHitObjectBlueprint } from './TimelineHitObjectBlueprint'; -import { Anchor, Axes, Bindable, ColorUtils, CompositeDrawable, dependencyLoader, FastRoundedBox, FillMode, resolved } from 'osucad-framework'; +import { Anchor, Axes, DrawableSprite, resolved } from 'osucad-framework'; import { Timeline } from '../Timeline'; +import { TimelineHitObjectCircle } from './TimelineHitObjectCircle'; -export class TimelineRepeatPiece extends CompositeDrawable { - constructor( - readonly blueprint: TimelineHitObjectBlueprint, - readonly hitObject: HitObject, - ) { - super(); +export class TimelineRepeatPiece extends TimelineHitObjectCircle { + constructor(blueprint: TimelineHitObjectBlueprint, readonly repeat: SliderRepeat) { + super(blueprint); } - #outline!: FastRoundedBox; - - #body!: FastRoundedBox; - - @dependencyLoader() - [Symbol('load')]() { - this.relativeSizeAxes = Axes.Both; - this.fillMode = FillMode.Fit; + @resolved(Timeline) + timeline!: Timeline; - this.addAllInternal( - this.#outline = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - anchor: Anchor.Center, - origin: Anchor.Center, - scale: 0.65, - }), + protected override load(dependencies: ReadonlyDependencyContainer) { + super.load(dependencies); - this.#body = new FastRoundedBox({ - relativeSizeAxes: Axes.Both, - cornerRadius: 100, - scale: 0.5, - anchor: Anchor.Center, - origin: Anchor.Center, - }), - ); + this.relativePositionAxes = Axes.X; - this.accentColor.bindTo(this.blueprint.accentColor); - this.accentColor.addOnChangeListener(() => this.updateColors(), { immediate: true }); - } + this.addInternal(new DrawableSprite({ + texture: this.skin.getTexture('reversearrow'), + size: 0.75, + relativeSizeAxes: Axes.Both, + scale: 60 / 64, + anchor: Anchor.Center, + origin: Anchor.Center, + })); - protected accentColor = new Bindable(null!); + const slider = this.blueprint.hitObject!; - protected updateColors() { - this.#outline.color = ColorUtils.darken(this.accentColor.value, 0.25); - this.#body.color = this.accentColor.value; + if (slider.duration !== 0) + this.x = this.repeat.startTime - slider.startTime; } - - @resolved(Timeline) - timeline!: Timeline; } diff --git a/packages/common/src/rulesets/osu/skinning/stable/DrawableComboNumber.ts b/packages/common/src/rulesets/osu/skinning/stable/DrawableComboNumber.ts index a40afae9..a8372f5d 100644 --- a/packages/common/src/rulesets/osu/skinning/stable/DrawableComboNumber.ts +++ b/packages/common/src/rulesets/osu/skinning/stable/DrawableComboNumber.ts @@ -25,7 +25,8 @@ export class DrawableComboNumber extends CompositeDrawable { protected override load(dependencies: ReadonlyDependencyContainer) { super.load(dependencies); - this.indexInComboBindable.bindTo(this.parentHitObject!.indexInComboBindable); + if (this.parentHitObject) + this.indexInComboBindable.bindTo(this.parentHitObject.indexInComboBindable); this.hitCircleOverlap = this.skin.getConfig(SkinConfig.HitCircleOverlap) ?? -2; diff --git a/packages/common/src/rulesets/osu/skinning/stable/OsuSkinComponentLookup.ts b/packages/common/src/rulesets/osu/skinning/stable/OsuSkinComponentLookup.ts index 168c387e..2fc447aa 100644 --- a/packages/common/src/rulesets/osu/skinning/stable/OsuSkinComponentLookup.ts +++ b/packages/common/src/rulesets/osu/skinning/stable/OsuSkinComponentLookup.ts @@ -15,6 +15,7 @@ export class OsuSkinComponentLookup extends GameplaySkinComponentLookup