diff --git a/app/index.css b/app/index.css index 2c37a5fa..4f2b7ef5 100644 --- a/app/index.css +++ b/app/index.css @@ -2553,6 +2553,10 @@ input[type="color"] { border-bottom: 0px solid var(--secondary-border); } +#playback-options .playback-options-label { + white-space: nowrap; +} + .playback-options-title { justify-content: center; text-align: center; diff --git a/app/src/App.ts b/app/src/App.ts index 338e51e9..de2b9844 100644 --- a/app/src/App.ts +++ b/app/src/App.ts @@ -94,7 +94,8 @@ export class App { return } let foundSM = "" - for (const file of args) { + for (let file of args) { + if (file.startsWith("file://")) file = file.substring(7) if (extname(file) == ".ssc") { foundSM = file break diff --git a/app/src/chart/ChartManager.ts b/app/src/chart/ChartManager.ts index 6c376ad6..947a5495 100644 --- a/app/src/chart/ChartManager.ts +++ b/app/src/chart/ChartManager.ts @@ -71,6 +71,7 @@ interface PartialHold { oldNote: PartialHoldNotedataEntry newNote: PartialNotedataEntry }[] + direction: "up" | "down" | null } interface Selection { @@ -1259,6 +1260,7 @@ export class ChartManager { type, removedNotes: conflictingNotes, truncatedHolds: truncatedHolds, + direction: null, } this.holdEditing[col] = holdEdit @@ -1313,7 +1315,23 @@ export class ChartManager { if (hold == undefined) return if (beat == hold.startBeat && beat == hold.endBeat) return - hold.endBeat = Math.max(hold.startBeat, Math.round(beat * 48) / 48) + if (hold.direction === null) { + if (beat < hold.startBeat) { + hold.direction = "up" + } else { + hold.direction = "down" + } + } + if (Options.chart.defaultHoldPlacement) { + if (hold.direction == "up") { + hold.startBeat = Math.min(hold.endBeat, Math.round(beat * 48) / 48) + } else { + hold.endBeat = Math.max(hold.startBeat, Math.round(beat * 48) / 48) + } + } else { + hold.startBeat = Math.min(hold.startBeat, Math.round(beat * 48) / 48) + hold.endBeat = Math.max(hold.endBeat, Math.round(beat * 48) / 48) + } hold.roll ||= roll if (!hold.originalNote) { const note: PartialNotedataEntry = { diff --git a/app/src/chart/component/edit/BarlineContainer.ts b/app/src/chart/component/edit/BarlineContainer.ts index 583b429a..c5ba8002 100644 --- a/app/src/chart/component/edit/BarlineContainer.ts +++ b/app/src/chart/component/edit/BarlineContainer.ts @@ -20,14 +20,14 @@ export class BarlineContainer private barlinePool = new DisplayObjectPool({ create: () => { const line = new Sprite(Texture.WHITE) - assignTint(line, "--text-color") + assignTint(line, "text-color") return line }, }) private barlineLabelPool = new DisplayObjectPool({ create: () => { const text = new BitmapText("", measureNumbers) - assignTint(text, "--text-color") + assignTint(text, "text-color") return text }, }) diff --git a/app/src/chart/component/edit/PreviewAreaContainer.ts b/app/src/chart/component/edit/PreviewAreaContainer.ts index 8bb97f91..4165648b 100644 --- a/app/src/chart/component/edit/PreviewAreaContainer.ts +++ b/app/src/chart/component/edit/PreviewAreaContainer.ts @@ -27,7 +27,7 @@ export class PreviewAreaContainer }) this.previewText.x = -this.previewArea.width / 2 + 5 this.previewArea.anchor.x = 0.5 - assignTint(this.previewText, "--text-color") + assignTint(this.previewText, "text-color") this.addChild(this.previewArea, this.previewText) } diff --git a/app/src/chart/component/play/ErrorBarContainer.ts b/app/src/chart/component/play/ErrorBarContainer.ts index 6865acea..d3142a64 100644 --- a/app/src/chart/component/play/ErrorBarContainer.ts +++ b/app/src/chart/component/play/ErrorBarContainer.ts @@ -50,19 +50,19 @@ export class ErrorBarContainer this.barline.anchor.set(0.5) this.barline.height = 1 this.barline.alpha = 0.5 - assignTint(this.barline, "--text-color") + assignTint(this.barline, "text-color") const target = new Sprite(Texture.WHITE) target.width = 2 target.height = BAR_HEIGHT target.anchor.set(0.5) - assignTint(target, "--text-color") + assignTint(target, "text-color") this.currentMedian = new Graphics() this.currentMedian.beginFill(0xffffff) this.currentMedian.moveTo(0, -10) this.currentMedian.lineTo(5, -15) this.currentMedian.lineTo(-5, -15) this.currentMedian.lineTo(0, -10) - assignTint(this.currentMedian, "--text-color") + assignTint(this.currentMedian, "text-color") this.errorText.y = -25 this.errorText.anchor.set(0.5) this.addChild( diff --git a/app/src/data/UserOptionsWindowData.ts b/app/src/data/UserOptionsWindowData.ts index 64909242..121ac538 100644 --- a/app/src/data/UserOptionsWindowData.ts +++ b/app/src/data/UserOptionsWindowData.ts @@ -243,6 +243,16 @@ export const USER_OPTIONS_WINDOW_DATA: UserOption[] = [ type: "checkbox", }, }, + { + type: "item", + label: "Directional hold placement behavior", + id: "chart.defaultHoldPlacement", + input: { + type: "checkbox", + }, + tooltip: + "Changes the hold placement behavior. By default, holds can only be extended in one direction when placed. Turn this off to mimic the behavior of AV/Stepmania.", + }, ], }, { diff --git a/app/src/gui/widget/BaseTimelineWidget.ts b/app/src/gui/widget/BaseTimelineWidget.ts index 29789eea..1b85e3de 100644 --- a/app/src/gui/widget/BaseTimelineWidget.ts +++ b/app/src/gui/widget/BaseTimelineWidget.ts @@ -40,7 +40,7 @@ export class BaseTimelineWidget extends Widget { this.addChild(this.container) this.visible = false - assignTint(this.backing, "--widget-bg") + assignTint(this.backing, "widget-bg") this.overlay.anchor.x = 0.5 this.overlay.anchor.y = 0 diff --git a/app/src/gui/widget/DebugWidget.ts b/app/src/gui/widget/DebugWidget.ts index d4a1fcf4..564dfd5f 100644 --- a/app/src/gui/widget/DebugWidget.ts +++ b/app/src/gui/widget/DebugWidget.ts @@ -87,8 +87,8 @@ export class DebugWidget extends Widget { this.fpsText.x = 5 this.fpsBg.y = -5 - assignTint(this.fpsBg, "--widget-bg") - assignTint(this.fpsText, "--text-color") + assignTint(this.fpsBg, "widget-bg") + assignTint(this.fpsText, "text-color") this.graphs.addChild( this.frameTimeGraph, @@ -220,7 +220,7 @@ class DebugGraph extends Container { bg.width = this.graphWidth bg.height = this.graphHeight - assignTint(bg, "--text-color") + assignTint(bg, "text-color") this.labelText = new BitmapText(label, { fontName: "Main", diff --git a/app/src/gui/widget/NPSGraphWidget.ts b/app/src/gui/widget/NPSGraphWidget.ts index 89ab32db..cd9c9e22 100644 --- a/app/src/gui/widget/NPSGraphWidget.ts +++ b/app/src/gui/widget/NPSGraphWidget.ts @@ -28,7 +28,7 @@ export class NPSGraphWidget extends BaseTimelineWidget { this.npsText.visible = false this.npsText.anchor.x = 1 this.npsText.anchor.y = 0.5 - assignTint(this.npsText, "--text-color") + assignTint(this.npsText, "text-color") this.addChild(this.npsText) EventHandler.on("userOptionUpdated", optionId => { diff --git a/app/src/gui/widget/PlayInfoWidget.ts b/app/src/gui/widget/PlayInfoWidget.ts index 978cfd6c..118cfc55 100644 --- a/app/src/gui/widget/PlayInfoWidget.ts +++ b/app/src/gui/widget/PlayInfoWidget.ts @@ -54,7 +54,7 @@ export class PlayInfoWidget extends Widget { this.visible = false this.background.addChild(this.backgroundRect) - assignTint(this.backgroundRect, "--widget-bg") + assignTint(this.backgroundRect, "widget-bg") this.addChild(this.background) this.addChild(this.backgroundLines) this.eventMode = "static" @@ -140,7 +140,7 @@ export class PlayInfoWidget extends Widget { early.y = -HISTOGRAM_HEIGHT - 40 early.alpha = 0.3 this.background.addChild(early) - assignTint(early, "--text-color") + assignTint(early, "text-color") const late = new BitmapText("Late", { fontName: "Main", @@ -151,7 +151,7 @@ export class PlayInfoWidget extends Widget { late.y = -HISTOGRAM_HEIGHT - 40 late.alpha = 0.3 this.background.addChild(late) - assignTint(late, "--text-color") + assignTint(late, "text-color") this.meanText = new BitmapText("-", { fontName: "Main", @@ -226,7 +226,7 @@ export class PlayInfoWidget extends Widget { this.statText.addChild(stddevLabel) this.statText.children.forEach(child => { - assignTint(child as BitmapText, "--text-color") + assignTint(child as BitmapText, "text-color") }) const alignSongContainer = new Container() @@ -261,7 +261,7 @@ export class PlayInfoWidget extends Widget { alignSongBg.alpha = 0.3 }) this.statText.addChild(alignSongContainer) - assignTint(alignSongText, "--text-color") + assignTint(alignSongText, "text-color") const alignGlobalContainer = new Container() @@ -290,7 +290,7 @@ export class PlayInfoWidget extends Widget { alignGlobalText.x = WIDGET_WIDTH / 4 alignGlobalText.y = -25 alignGlobalContainer.addChild(alignGlobalBg, alignGlobalText) - assignTint(alignGlobalText, "--text-color") + assignTint(alignGlobalText, "text-color") alignGlobalContainer.eventMode = "static" alignGlobalContainer.addEventListener("mouseenter", () => { @@ -463,8 +463,8 @@ export class PlayInfoWidget extends Widget { fontName: "Main", fontSize: 15, }) - assignTint(label, "--text-color") - assignTint(count, "--text-color") + assignTint(label, "text-color") + assignTint(count, "text-color") if (name != "Mine") count.text = "0 / " + @@ -489,12 +489,12 @@ export class PlayInfoWidget extends Widget { fontName: "Main", fontSize: 15, }) - assignTint(label, "--text-color") + assignTint(label, "text-color") const count = new BitmapText("0", { fontName: "Main", fontSize: 15, }) - assignTint(count, "--text-color") + assignTint(count, "text-color") label.alpha = 0.8 count.alpha = 0.8 count.name = "Combo" @@ -512,7 +512,7 @@ export class PlayInfoWidget extends Widget { fontName: "Main", fontSize: 20, }) - assignTint(score, "--text-color") + assignTint(score, "text-color") score.alpha = 0.8 score.x = -WIDGET_WIDTH / 2 + 225 score.y = -HISTOGRAM_HEIGHT - 112 @@ -524,7 +524,7 @@ export class PlayInfoWidget extends Widget { fontName: "Main", fontSize: 13, }) - assignTint(scoreLabel, "--text-color") + assignTint(scoreLabel, "text-color") scoreLabel.alpha = 0.5 scoreLabel.x = -WIDGET_WIDTH / 2 + 225 scoreLabel.y = -HISTOGRAM_HEIGHT - 135 @@ -537,7 +537,7 @@ export class PlayInfoWidget extends Widget { }) windowLabel.y = -HISTOGRAM_HEIGHT - 245 windowLabel.anchor.set(0.5) - assignTint(windowLabel, "--text-color") + assignTint(windowLabel, "text-color") this.texts.addChild(windowLabel) gameStats.onJudge((error, judge) => { diff --git a/app/src/gui/widget/StatusWidget.ts b/app/src/gui/widget/StatusWidget.ts index 7610ce53..2bbcf917 100644 --- a/app/src/gui/widget/StatusWidget.ts +++ b/app/src/gui/widget/StatusWidget.ts @@ -9,12 +9,13 @@ import { TapNoteType, } from "../../chart/sm/NoteTypes" import { BetterRoundedRect } from "../../util/BetterRoundedRect" -import { assignTint, blendPixiColors, getCSSColor } from "../../util/Color" +import { assignTint, blendPixiColors } from "../../util/Color" import { EventHandler } from "../../util/EventHandler" import { Flags } from "../../util/Flags" import { Keybinds } from "../../util/Keybinds" import { roundDigit } from "../../util/Math" import { Options } from "../../util/Options" +import { Themes } from "../../util/Theme" import { Icons } from "../Icons" import { Dropdown } from "../element/Dropdown" import { TimingTrackOrderPopup } from "../popup/TimingTrackOrderPopup" @@ -494,7 +495,7 @@ export class StatusWidget extends Widget { }) sprite.scale.set(0.5) const bg = new Sprite(Texture.WHITE) - assignTint(bg, "--widget-bg") + assignTint(bg, "widget-bg") bg.width = 48 bg.height = 48 bg.anchor.set(0.5) @@ -804,8 +805,8 @@ export class StatusWidget extends Widget { } const noteType = this.manager.chartManager.getEditingNoteType() - const hoverColor = getCSSColor("--editable-overlay-hover") - const activeColor = getCSSColor("--editable-overlay-active") + const hoverColor = Themes.getColor("editable-overlay-hover") + const activeColor = Themes.getColor("editable-overlay-active") const emptyColor = new Color(hoverColor).setAlpha(0) this.noteArrows.forEach(arrow => { let color = diff --git a/app/src/util/Color.ts b/app/src/util/Color.ts index 8d751744..c0fd6e78 100644 --- a/app/src/util/Color.ts +++ b/app/src/util/Color.ts @@ -1,6 +1,8 @@ import { Color, ColorSource } from "pixi.js" +import { ThemeProperty } from "../data/ThemeData" import { EventHandler } from "./EventHandler" import { clamp, lerp } from "./Math" +import { Themes } from "./Theme" export function rgbtoHex(r: number, g: number, b: number): number { return (r << 16) + (g << 8) + b @@ -57,11 +59,11 @@ export function getCSSColor(id: string) { type TintableObject = { tint: ColorSource; alpha: number; destroyed: boolean } -const themeObjectMap = new Map() +const themeObjectMap = new Map() EventHandler.on("themeChanged", () => { for (const [id, objects] of themeObjectMap.entries()) { - const color = getCSSColor(id) + const color = Themes.getColor(id) objects.forEach(o => { if (o.destroyed) return o.tint = color.toNumber() @@ -74,12 +76,12 @@ EventHandler.on("themeChanged", () => { } }) -export function assignTint(element: TintableObject, id: string) { +export function assignTint(element: TintableObject, id: ThemeProperty) { if (!themeObjectMap.has(id)) { themeObjectMap.set(id, []) } themeObjectMap.get(id)!.push(element) - const color = getCSSColor(id) + const color = Themes.getColor(id) element.tint = color.toNumber() element.alpha = color.alpha } diff --git a/app/src/util/Options.ts b/app/src/util/Options.ts index 4d3e482a..5b468213 100644 --- a/app/src/util/Options.ts +++ b/app/src/util/Options.ts @@ -24,6 +24,7 @@ export class DefaultOptions { CMod: false, reverse: false, mousePlacement: false, + defaultHoldPlacement: true, zoom: 1, speed: 250, snap: 1, diff --git a/app/src/util/Theme.ts b/app/src/util/Theme.ts index c7e7ee0b..ed958d17 100644 --- a/app/src/util/Theme.ts +++ b/app/src/util/Theme.ts @@ -3,6 +3,7 @@ import { DEFAULT_THEMES, Theme, THEME_VAR_WHITELIST, + ThemeProperty, ThemeString, } from "../data/ThemeData" import { WaterfallManager } from "../gui/element/WaterfallManager" @@ -186,4 +187,8 @@ export class Themes { } return this.validateTheme(theme) } + + static getColor(id: ThemeProperty) { + return this.currentTheme?.[id] ?? DEFAULT_THEMES["default"][id] + } }