123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- import { IZoomView } from "../Common/Interfaces/IZoomView";
- import { MusicSheetDrawer, GraphicalMusicSheet, BoundingBox, DrawingParameters,
- MusicSystem, GraphicalVoiceEntry } from "../MusicalScore/Graphical";
- import { ScreenViewingRegion } from "./ScreenViewingRegion";
- import { PointF2D, Fraction, SizeF2D } from "../Common/DataObjects";
- import { AbstractZoomView } from "./AbstractZoomView";
- import { InteractionType } from "../Common/Enums/InteractionType";
- import { AbstractDisplayInteractionManager } from "./AbstractDisplayInteractionManager";
- import { IUserDisplayInteractionListener } from "../Common/Interfaces/IUserDisplayInteractionListener";
- import { PlaybackManager } from "../Playback";
- export class SheetRenderingManager extends AbstractZoomView implements IZoomView {
- protected musicSheetDrawer: MusicSheetDrawer;
- protected graphicalMusicSheet: GraphicalMusicSheet;
- protected mainViewingRegion: ScreenViewingRegion = ScreenViewingRegion.createWithDefaults();
- protected tryAgainToRenderCount: number = 0;
- private yOffsetMouseDown: number = Number.MIN_VALUE;
- private unlockCursorDistancePixel: number = 50.0;
- private relativeTopPosition: number = 0.06;
- /* The preview images are supersampled (because of our drawing mechanism with more than 1 rasterization stage,
- * this increases the output image quality significantly)
- **/
- protected internalPreviewImageScale: number = 3.0;
- protected listeners: IUserDisplayInteractionListener[] = [];
- public PlaybackManager: PlaybackManager;
- constructor(displayInteractionManager: AbstractDisplayInteractionManager, playbackManager?: PlaybackManager) {
- super(displayInteractionManager);
- this.addZoomView(this);
- this.lockRanges = true;
- this.TopBarHeightInPixel = 70;
- this.BottomBarHeightInPixel = 0;
- }
- public addListener(listener: IUserDisplayInteractionListener): void {
- this.listeners.push(listener);
- }
- public SingleTouchDisabled: boolean;
- public DoubleTouchDisabled: boolean;
- public LockDisplayToCursor: boolean = true;
- public ZoomActive: boolean = false;
- protected convertToUnitsReady(): boolean {
- return this.graphicalMusicSheet !== undefined;
- }
- protected unitPosTouched(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
- // Pass mouse click to click listener
- if (!this.SingleTouchDisabled) {
- const relPos: PointF2D = new PointF2D(relPosX, relPosY);
- this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.SingleTouch);
- for (const listener of this.listeners) {
- listener.userDisplayInteraction(relPos, PosInUnits, InteractionType.SingleTouch);
- }
- }
- }
- protected unitPosDoubleTouched(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
- if (!this.DoubleTouchDisabled) {
- const relPos: PointF2D = new PointF2D(relPosX, relPosY);
- this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.DoubleTouch);
- for (const listener of this.listeners) {
- listener.userDisplayInteraction(relPos, PosInUnits, InteractionType.DoubleTouch);
- }
- }
- }
- protected unitPosTouchDown(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
- const relPos: PointF2D = new PointF2D(relPosX, relPosY);
- this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.TouchDown);
- for (const listener of this.listeners) {
- listener.userDisplayInteraction(new PointF2D(relPosX, relPosY), PosInUnits, InteractionType.TouchDown);
- }
- this.yOffsetMouseDown = PosInUnits.y;
- }
- protected unitPosTouchUp(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
- const relPos: PointF2D = new PointF2D(relPosX, relPosY);
- this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.TouchUp);
- for (const listener of this.listeners) {
- listener.userDisplayInteraction(new PointF2D(relPosX, relPosY), PosInUnits, InteractionType.TouchUp);
- }
- if (this.displayInteractionManager.WasZoomGestureActive === false) {
- this.unlockFromCursorIfNecessary(PosInUnits);
- }
- this.yOffsetMouseDown = Number.MIN_VALUE;
- }
- protected unitPosMove(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
- const relPos: PointF2D = new PointF2D(relPosX, relPosY);
- this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.Move);
- for (const listener of this.listeners) {
- listener.userDisplayInteraction(new PointF2D(relPosX, relPosY), PosInUnits, InteractionType.Move);
- }
- this.unlockFromCursorIfNecessary(PosInUnits);
- }
- public get MainViewingRegion(): ScreenViewingRegion {
- return this.mainViewingRegion;
- }
- public TopBarHeightInPixel: number;
- public BottomBarHeightInPixel: number;
- public setMusicSheet(musicSheet: GraphicalMusicSheet): void {
- this.graphicalMusicSheet = musicSheet;
- this.adaptDisplayLimitsToSheet();
- this.setYOffset(0, true);
- }
- public viewportXChanged(offsetX: number, rangeX: number): void {
- if (this.graphicalMusicSheet === undefined) {
- return;
- }
- this.horizontalViewportChanged(offsetX, rangeX);
- }
- /**
- * Sets the vertical position and viewing height of the displayed area on the music score.
- */
- public viewportYChanged(offsetY: number, rangeY: number): void {
- if (this.graphicalMusicSheet === undefined) {
- return;
- }
- if (this.yOffsetMouseDown <= Number.MIN_VALUE + 0.5) {
- this.yOffsetMouseDown = offsetY;
- }
- this.verticalViewportChanged(offsetY, rangeY);
- }
- public displaySizeChanged(width: number, height: number): void {
- super.viewSizeChanged(width, height);
- if (Math.abs(width - 0) < 0.0000001 || Math.abs(height - 0) < 0.0000001) {
- return;
- }
- if (this.graphicalMusicSheet !== undefined) {
- this.graphicalMusicSheet.EnforceRedrawOfMusicSystems(); // probably not necessary, already handled by OSMD
- }
- this.mainViewingRegion.DisplaySizeInPixel = new SizeF2D (width, height);
- this.adaptDisplayLimitsToSheet();
- }
- public calcDisplayYPosition(system: MusicSystem): number {
- return system.PositionAndShape.AbsolutePosition.y + system.PositionAndShape.BorderMarginTop -
- this.topBarHeightInUnits() - this.relativeTopPosition * this.heightWithoutTopBottomBarsInUnits();
- }
- /**
- * The display scroll y-position to show the given system completely on the bottom of the screen
- */
- public yPositionForLastSystem(lastSystem: MusicSystem): number {
- return lastSystem.PositionAndShape.AbsolutePosition.y + lastSystem.PositionAndShape.BorderMarginBottom -
- this.topBarHeightInUnits() - (1 - this.relativeTopPosition) * this.heightWithoutTopBottomBarsInUnits();
- }
- // TODO MB: What is up with the unused variables here? Also: formatting of parameters.
- public scorePositionChanged(upperCursorPoint: PointF2D, enrolledTimeStamp: Fraction, sheetTimeStamp: Fraction,
- system: MusicSystem, resetOccurred: boolean, smoothAnimation: boolean): void {
- const positionY: number = this.calcDisplayYPosition(system);
- this.setYPosition(positionY, smoothAnimation);
- }
- public setXPosition(positionXInUnits: number, animated: boolean): void {
- if (this.LockDisplayToCursor) {
- this.setXOffset(positionXInUnits, animated);
- }
- }
- public setYPosition(positionYInUnits: number, animated: boolean): void {
- if (this.LockDisplayToCursor) {
- this.setYOffset(positionYInUnits, animated);
- }
- }
- public get DrawingParameters(): DrawingParameters {
- return this.musicSheetDrawer.drawingParameters;
- }
- public topBarHeightInUnits(): number {
- return this.mainViewingRegion.transformLengthYToUnitCoordinates(this.TopBarHeightInPixel);
- }
- public bottomBarHeightInUnits(): number {
- return this.mainViewingRegion.transformLengthYToUnitCoordinates(this.BottomBarHeightInPixel);
- }
- public heightWithoutTopBottomBarsInUnits(): number {
- return this.mainViewingRegion.ViewRegionInUnits.height - this.topBarHeightInUnits() - this.bottomBarHeightInUnits();
- }
- public activePositionToBottomBarHeight(): number {
- return (this.mainViewingRegion.ViewRegionInUnits.height - this.topBarHeightInUnits() - this.bottomBarHeightInUnits()) *
- (1 - 2 * this.relativeTopPosition);
- }
- public getClickPosition(relativePositionX: number, relativePositionY: number): PointF2D {
- return this.mainViewingRegion.transformToUnitCoordinates(new PointF2D(relativePositionX, relativePositionY));
- }
- public graphicalObjectIsVisible(boundingBox: BoundingBox): boolean {
- const isCompletelyInside: boolean = false;
- return this.mainViewingRegion.isVisible(boundingBox, isCompletelyInside);
- }
- /**
- * sets the size of the maximal musicpage seen including the extensions on top resp. bottom
- * !Caution!: settings/offsets have been changed for ScrollIndicator.. won't work anymore if changed again
- */
- public adaptDisplayLimitsToSheet(): void {
- if ( this.graphicalMusicSheet === undefined
- || this.graphicalMusicSheet.MusicPages.length === 0
- || this.graphicalMusicSheet.MusicPages[0].MusicSystems.length === 0) {
- return;
- }
- // set the new limits for viewing:
- this.offsetXMin = 0;
- this.rangeXMin = this.graphicalMusicSheet.MinAllowedSystemWidth;
- this.rangeXMax = 300;
- this.offsetYMin = -0.3 * this.RangeY;
- const lastPagePsi: BoundingBox = this.graphicalMusicSheet.MusicPages.last().PositionAndShape;
- this.offsetYMax = Math.max(0, lastPagePsi.BorderMarginBottom - 0.7 * this.RangeY);
- if (this.OffsetY > this.offsetYMax) {
- this.setYOffset(this.offsetYMax, true);
- }
- }
- protected horizontalViewportChanged(offsetX: number, rangeX: number): void {
- if (this.mainViewingRegion.WidthInUnits !== rangeX) {
- this.mainViewingRegion.WidthInUnits = rangeX;
- }
- }
- protected verticalViewportChanged(offsetY: number, rangeY: number): void {
- this.mainViewingRegion.UpperLeftPositionInUnits = new PointF2D(this.mainViewingRegion.UpperLeftPositionInUnits.x, offsetY);
- }
- private unlockFromCursorIfNecessary(PosInUnits: PointF2D): void {
- if (this.LockDisplayToCursor === false || this.ZoomActive) {
- return;
- }
- if (this.displayInteractionManager.ZoomGestureActive || this.displayInteractionManager.WasZoomGestureActive) {
- return;
- }
- // finally check for the movement distance, to not unlock already at little finger pressure changes...
- // TODO MB: Fix formatting.
- const ydiff: number = Math.abs((PosInUnits.y - this.yOffsetMouseDown) *
- this.mainViewingRegion.RegionSizeInPixel.height /
- this.mainViewingRegion.ViewRegionInUnits.height);
- if (ydiff > this.unlockCursorDistancePixel) {
- this.LockDisplayToCursor = false;
- }
- }
- protected getPositionInUnits(relativePositionX: number, relativePositionY: number): PointF2D {
- return this.mainViewingRegion.transformToUnitCoordinates(new PointF2D(relativePositionX, relativePositionY));
- }
- protected handleUserDisplayInteraction( relativePositionOnDisplay: PointF2D, positionOnMusicSheet: PointF2D,
- type: InteractionType): void {
- switch (type) {
- case InteractionType.TouchDown:
- case InteractionType.SingleTouch:
- case InteractionType.DoubleTouch: {
- const clickVe: GraphicalVoiceEntry = this.graphicalMusicSheet.GetNearestVoiceEntry(positionOnMusicSheet);
- // set cursor and/or start/end marker position
- if (clickVe) {
- if (clickVe.parentStaffEntry.parentVerticalContainer !== undefined) {
- const clickedTimeStamp: Fraction = clickVe.parentStaffEntry.parentVerticalContainer.AbsoluteTimestamp;
- this.setStartPosition(clickedTimeStamp);
- // playback clicked note
- if (clickVe.notes[0]?.sourceNote.Pitch !== undefined) {
- this.PlaybackManager?.playVoiceEntry(clickVe.parentVoiceEntry);
- }
- }
- }
- break;
- }
- case InteractionType.TouchUp: {
- break;
- }
- case InteractionType.TouchDown: {
- break;
- }
- case InteractionType.Move: {
- break;
- }
- default:
- throw new Error("type");
- }
- }
- protected setStartPosition(newStartPosition: Fraction): void {
- if (this.graphicalMusicSheet === undefined) {
- return;
- }
- this.graphicalMusicSheet.ParentMusicSheet.SelectionStart = newStartPosition;
- this.PlaybackManager?.reset();
- }
- }
|