diff --git a/app/src/chart/ChartRenderer.ts b/app/src/chart/ChartRenderer.ts index 507485f7..5017e6e7 100644 --- a/app/src/chart/ChartRenderer.ts +++ b/app/src/chart/ChartRenderer.ts @@ -289,6 +289,10 @@ export class ChartRenderer extends Container { update() { if (this.destroyed) return + this.x = + this.chartManager.app.renderer.screen.width / 2 + + Options.chart.receptorXPos + this.speedMult = Options.chart.doSpeedChanges ? this.getCurrentSpeedMult() : 1 @@ -704,12 +708,10 @@ export class ChartRenderer extends Container { const scroll = this.findFirstOnScreenScroll() const pixelsToEffectiveBeats = - (1 / Math.abs(this.getEffectiveBeatsToPixelsRatio())) * - Options.chart.zoom + 1 / Math.abs(this.getEffectiveBeatsToPixelsRatio()) const scrollStartY = this.getYPosFromBeat(scroll.beat) - const pixelsToBeats = - (pixelsToEffectiveBeats / Math.abs(scroll.value)) * Options.chart.zoom + const pixelsToBeats = pixelsToEffectiveBeats / Math.abs(scroll.value) const direction = this.getScrollDirection(scroll.value) const bound = direction == 1 ? this.getUpperBound() : this.getLowerBound() @@ -738,17 +740,11 @@ export class ChartRenderer extends Container { ) { const scroll = this.findLastOnScreenScroll() - const speedMult = this.getCurrentSpeedMult() const pixelsToEffectiveBeats = - 100 / - Options.chart.speed / - Math.abs(speedMult) / - 64 / - Options.chart.zoom + 1 / Math.abs(this.getEffectiveBeatsToPixelsRatio()) const scrollStartY = this.getYPosFromBeat(scroll.beat) - const pixelsToBeats = - (pixelsToEffectiveBeats / Math.abs(scroll.value)) * Options.chart.zoom + const pixelsToBeats = pixelsToEffectiveBeats / Math.abs(scroll.value) const direction = this.getScrollDirection(scroll.value) const bound = direction == 1 ? this.getLowerBound() : this.getUpperBound() diff --git a/app/src/chart/component/edit/Waveform.ts b/app/src/chart/component/edit/Waveform.ts index 81e9d1a0..87501fbe 100644 --- a/app/src/chart/component/edit/Waveform.ts +++ b/app/src/chart/component/edit/Waveform.ts @@ -69,6 +69,7 @@ export class Waveform extends Sprite implements ChartRendererComponent { this.trackVariable(() => this.renderer.getVisualBeat()) this.trackVariable(() => this.renderer.getVisualTime()) + this.trackVariable(() => Options.chart.speed) this.trackVariable( () => this.getSpeed(), value => { diff --git a/app/src/chart/component/notefield/ReceptorContainer.ts b/app/src/chart/component/notefield/ReceptorContainer.ts index 300e18ab..68ac9cba 100644 --- a/app/src/chart/component/notefield/ReceptorContainer.ts +++ b/app/src/chart/component/notefield/ReceptorContainer.ts @@ -1,5 +1,7 @@ -import { Container } from "pixi.js" +import { Container, FederatedPointerEvent, Point } from "pixi.js" +import { EventHandler } from "../../../util/EventHandler" +import { Options } from "../../../util/Options" import { NoteskinSprite } from "../../gameTypes/noteskin/Noteskin" import { Notefield } from "./Notefield" @@ -7,6 +9,13 @@ export class ReceptorContainer extends Container { private readonly notefield readonly children: NoteskinSprite[] = [] + private dragStart: Point | null = null + private dragOptionsStart: [number, number] | null = null + private optionUpdate = (option: string) => { + if (option != "chart.allowReceptorDrag") return + this.eventMode = Options.chart.allowReceptorDrag ? "static" : "passive" + } + constructor(notefield: Notefield) { super() this.notefield = notefield @@ -20,6 +29,41 @@ export class ReceptorContainer extends Container { receptor.x = this.notefield.getColumnX(colNum) this.addChild(receptor) } + + const moveHandler = (e: FederatedPointerEvent) => { + if (!this.dragStart || !this.dragOptionsStart) return + Options.chart.receptorXPos = Math.round( + this.dragOptionsStart[0] + e.global.x - this.dragStart.x + ) + Options.chart.receptorYPos = Math.round( + this.dragOptionsStart[1] + e.global.y - this.dragStart.y + ) + } + + const releaseHandler = () => { + this.notefield.renderer.off("pointermove", moveHandler) + this.notefield.renderer.off("pointerup", releaseHandler) + } + + this.on("pointerdown", e => { + this.dragStart = new Point(e.globalX, e.globalY) + this.dragOptionsStart = [ + Options.chart.receptorXPos, + Options.chart.receptorYPos, + ] + e.preventDefault() + e.stopImmediatePropagation() + + this.notefield.renderer.on("pointermove", moveHandler) + this.notefield.renderer.on("pointerup", releaseHandler) + }) + + EventHandler.on("userOptionUpdated", this.optionUpdate) + this.optionUpdate("chart.allowReceptorDrag") + } + + destroy() { + EventHandler.off("userOptionUpdated", this.optionUpdate) } update(): void { diff --git a/app/src/data/UserOptionsWindowData.ts b/app/src/data/UserOptionsWindowData.ts index 121ac538..f9dd0e3c 100644 --- a/app/src/data/UserOptionsWindowData.ts +++ b/app/src/data/UserOptionsWindowData.ts @@ -287,6 +287,28 @@ export const USER_OPTIONS_WINDOW_DATA: UserOption[] = [ { type: "subgroup", children: [ + { + type: "item", + label: "Allow receptor dragging", + id: "chart.allowReceptorDrag", + input: { + type: "checkbox", + }, + tooltip: + "Allows the receptors to be dragged to move the playfield.", + }, + { + type: "item", + label: "X position", + id: "chart.receptorXPos", + input: { + type: "slider", + min: -400, + max: 400, + hardMin: -(2 ** 31 - 1), + hardMax: 2 ** 31 - 1, + }, + }, { type: "item", label: "Y position", @@ -299,6 +321,11 @@ export const USER_OPTIONS_WINDOW_DATA: UserOption[] = [ hardMax: 2 ** 31 - 1, }, }, + ], + }, + { + type: "subgroup", + children: [ { type: "item", label: "Draw length", diff --git a/app/src/gui/widget/BaseTimelineWidget.ts b/app/src/gui/widget/BaseTimelineWidget.ts index 1b85e3de..05c013ad 100644 --- a/app/src/gui/widget/BaseTimelineWidget.ts +++ b/app/src/gui/widget/BaseTimelineWidget.ts @@ -35,6 +35,7 @@ export class BaseTimelineWidget extends Widget { super(manager) this.backingWidth = backingWidth this.xOffset = xOffset + this.sortableChildren = true this.addChild(this.backing) this.addChild(this.container) @@ -45,6 +46,7 @@ export class BaseTimelineWidget extends Widget { this.overlay.anchor.x = 0.5 this.overlay.anchor.y = 0 this.overlay.alpha = 0.3 + this.overlay.zIndex = 10 this.lastCMod = Options.chart.CMod this.addChild(this.overlay) diff --git a/app/src/util/Options.ts b/app/src/util/Options.ts index 5b468213..3f4f2bef 100644 --- a/app/src/util/Options.ts +++ b/app/src/util/Options.ts @@ -33,7 +33,8 @@ export class DefaultOptions { doSpeedChanges: true, drawNoteFlash: true, drawIcons: true, - receptorYPos: -200, + allowReceptorDrag: true, + receptorYPos: -250, receptorXPos: 0, maxDrawBeats: 20, maxDrawBeatsBack: 10, diff --git a/app/src/util/file-handler/NodeFileHandler.ts b/app/src/util/file-handler/NodeFileHandler.ts index 6ad42ed0..75da015d 100644 --- a/app/src/util/file-handler/NodeFileHandler.ts +++ b/app/src/util/file-handler/NodeFileHandler.ts @@ -99,7 +99,7 @@ export class NodeFileHandler implements BaseFileHandler { if (!dir) { throw new DOMException(...GONE) } - return dir.getFileHandle(fileName) + return await dir.getFileHandle(fileName) } catch (err) { console.error("Failed to get relative file " + fileName + ": " + err) return undefined @@ -169,8 +169,10 @@ export class NodeFileHandler implements BaseFileHandler { } private async writeHandle(handle: FileSystemFileHandle, data: Blob | string) { + const length = data instanceof Blob ? data.size : data.length const writable = await handle.createWritable() await writable.write(data) + await writable.truncate(length) await writable.close() }