diff --git a/src.csharp/AlphaTab.Windows/WinForms/WinFormsUiFacade.cs b/src.csharp/AlphaTab.Windows/WinForms/WinFormsUiFacade.cs index e9ac90b64..6359bfe8c 100644 --- a/src.csharp/AlphaTab.Windows/WinForms/WinFormsUiFacade.cs +++ b/src.csharp/AlphaTab.Windows/WinForms/WinFormsUiFacade.cs @@ -81,6 +81,7 @@ public override void Initialize(AlphaTabApiBase api, base.Initialize(api, control); api.Settings = control.Settings; control.SettingsChanged += OnSettingsChanged; + api.SettingsUpdated.On(OnSettingsUpdated); } private void OnSettingsChanged(Settings s) @@ -104,6 +105,7 @@ public override void Destroy() { SettingsContainer.SettingsChanged -= OnSettingsChanged; _layoutPanel.Controls.Clear(); + Api.SettingsUpdated.Off(OnSettingsUpdated); } public override IContainer CreateCanvasElement() @@ -216,6 +218,14 @@ public override void BeginAppendRenderResults(RenderFinishedEventArgs? r) }), r); } + private void OnSettingsUpdated() + { + foreach (Control control in _layoutPanel.Controls) + { + control.BackColor = _layoutPanel.ForeColor; + } + } + public override void DestroyCursors() { diff --git a/src.csharp/AlphaTab.Windows/Wpf/WpfUiFacade.cs b/src.csharp/AlphaTab.Windows/Wpf/WpfUiFacade.cs index 409377821..5c15f7c07 100644 --- a/src.csharp/AlphaTab.Windows/Wpf/WpfUiFacade.cs +++ b/src.csharp/AlphaTab.Windows/Wpf/WpfUiFacade.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Windows; using System.Windows.Controls; +using System.Windows.Data; using System.Windows.Media; +using System.Windows.Shapes; using AlphaTab.Synth; using AlphaTab.Platform; using AlphaTab.Platform.CSharp; @@ -245,18 +247,25 @@ public override Cursors CreateCursors() var selectionWrapper = new Canvas(); - var barCursor = new System.Windows.Shapes.Rectangle + var barCursor = new Rectangle { - Fill = SettingsContainer.BarCursorFill, IsHitTestVisible = false }; - var beatCursor = new System.Windows.Shapes.Rectangle + barCursor.SetBinding(Shape.FillProperty, new Binding(nameof(SettingsContainer.BarCursorFill)) + { + Source = SettingsContainer + }); + + var beatCursor = new Rectangle { - Fill = SettingsContainer.BeatCursorFill, IsHitTestVisible = false, Width = 3 }; + beatCursor.SetBinding(Shape.FillProperty, new Binding(nameof(SettingsContainer.BeatCursorFill)) + { + Source = SettingsContainer + }); cursorWrapper.Children.Add(selectionWrapper); cursorWrapper.Children.Add(barCursor); @@ -289,11 +298,16 @@ public override void HighlightElements(string groupId, double masterBarIndex) public override IContainer CreateSelectionElement() { - var selection = new System.Windows.Shapes.Rectangle + var selection = new Rectangle { Fill = SettingsContainer.SelectionFill, IsHitTestVisible = false }; + selection.SetBinding(Shape.FillProperty, + new Binding(nameof(SettingsContainer.SelectionFill)) + { + Source = SettingsContainer + }); return new FrameworkElementContainer(selection); } diff --git a/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/AlphaTabView.kt b/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/AlphaTabView.kt index 0af7eea3c..a43ac8c60 100644 --- a/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/AlphaTabView.kt +++ b/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/AlphaTabView.kt @@ -49,27 +49,21 @@ class AlphaTabView : RelativeLayout { get() = _barCursorFillColor set(value) { _barCursorFillColor = value - (barCursorFillColorChanged as EventEmitter).trigger() } - public val barCursorFillColorChanged: IEventEmitter = EventEmitter() private var _beatCursorFillColor: Int = Color.argb(191, 64, 64, 255) public var beatCursorFillColor: Int get() = _beatCursorFillColor set(value) { _beatCursorFillColor = value - (beatCursorFillColorChanged as EventEmitter).trigger() } - public val beatCursorFillColorChanged: IEventEmitter = EventEmitter() private var _selectionFillColor: Int = Color.argb(25, 64, 64, 255) public var selectionFillColor: Int get() = _selectionFillColor set(value) { _selectionFillColor = value - (selectionFillColorChanged as EventEmitter).trigger() } - public val selectionFillColorChanged: IEventEmitter = EventEmitter() public val api: AlphaTabApiBase get() = _api diff --git a/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/platform/android/AndroidUiFacade.kt b/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/platform/android/AndroidUiFacade.kt index 7347f313a..ba7de9c87 100644 --- a/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/platform/android/AndroidUiFacade.kt +++ b/src.kotlin/alphaTab/alphaTab/src/androidMain/kotlin/alphaTab/platform/android/AndroidUiFacade.kt @@ -115,26 +115,7 @@ internal class AndroidUiFacade : IUiFacade { api.renderer.renderResult(it) } settings.settingsChanged.on(this::onSettingsChanged) - settingsContainer.barCursorFillColorChanged.on { - (this._cursors?.barCursor as AndroidViewContainer?)?.view?.setBackgroundColor( - settingsContainer.barCursorFillColor - ) - } - settingsContainer.beatCursorFillColorChanged.on { - (this._cursors?.beatCursor as AndroidViewContainer?)?.view?.setBackgroundColor( - settingsContainer.barCursorFillColor - ) - } - settingsContainer.selectionFillColorChanged.on { - val selectionWrapper = (this._cursors?.selectionWrapper as AndroidViewContainer?)?.view - if (selectionWrapper is ViewGroup) { - for (c in selectionWrapper.children) { - c.setBackgroundColor( - settingsContainer.selectionFillColor - ) - } - } - } + api.settingsUpdated.on(this::onSettingsUpdated) } private fun onSettingsChanged() { @@ -143,6 +124,24 @@ internal class AndroidUiFacade : IUiFacade { api.render() } + private fun onSettingsUpdated() { + (this._cursors?.barCursor as AndroidViewContainer?)?.view?.setBackgroundColor( + settingsContainer.barCursorFillColor + ) + (this._cursors?.beatCursor as AndroidViewContainer?)?.view?.setBackgroundColor( + settingsContainer.beatCursorFillColor + ) + + val selectionWrapper = (this._cursors?.selectionWrapper as AndroidViewContainer?)?.view + if (selectionWrapper is ViewGroup) { + for (c in selectionWrapper.children) { + c.setBackgroundColor( + settingsContainer.selectionFillColor + ) + } + } + } + override fun createWorkerRenderer(): IScoreRenderer { return AndroidThreadScoreRenderer(api.settings, this::beginInvoke) } @@ -183,6 +182,7 @@ internal class AndroidUiFacade : IUiFacade { override fun destroy() { settingsContainer.settingsChanged.off(this::onSettingsChanged) (rootContainer as AndroidRootViewContainer).destroy() + api.settingsUpdated.off(this::onSettingsUpdated) } override fun triggerEvent( diff --git a/src/AlphaTabApiBase.ts b/src/AlphaTabApiBase.ts index 695301041..bc886a494 100644 --- a/src/AlphaTabApiBase.ts +++ b/src/AlphaTabApiBase.ts @@ -190,6 +190,7 @@ export class AlphaTabApiBase { } else { this.destroyPlayer(); } + this.onSettingsUpdated(); } /** @@ -546,10 +547,13 @@ export class AlphaTabApiBase { } this.player.destroy(); this.player = null; + this._previousTick = 0; + this._playerState = PlayerState.Paused; this.destroyCursors(); } private setupPlayer(): void { + this.updateCursors(); if (this.player) { return; } @@ -752,25 +756,29 @@ export class AlphaTabApiBase { this._barCursor = null; this._beatCursor = null; this._selectionWrapper = null; - this._previousTick = 0; - this._playerState = PlayerState.Paused; } - private setupPlayerEvents(): void { + private updateCursors() { if (this.settings.player.enableCursor && !this._cursorWrapper) { // // Create cursors let cursors = this.uiFacade.createCursors(); - if (!cursors) { - return; + if (cursors) { + // store options and created elements for fast access + this._cursorWrapper = cursors.cursorWrapper; + this._barCursor = cursors.barCursor; + this._beatCursor = cursors.beatCursor; + this._selectionWrapper = cursors.selectionWrapper; + } + if (this._currentBeat !== null) { + this.cursorUpdateBeat(this._currentBeat!, false, this._previousTick > 10, true); } - // store options and created elements for fast access - this._cursorWrapper = cursors.cursorWrapper; - this._barCursor = cursors.barCursor; - this._beatCursor = cursors.beatCursor; - this._selectionWrapper = cursors.selectionWrapper; + } else if (!this.settings.player.enableCursor && this._cursorWrapper) { + this.destroyCursors(); } + } + private setupPlayerEvents(): void { // // Hook into events this._previousTick = 0; @@ -823,7 +831,12 @@ export class AlphaTabApiBase { /** * updates the cursors to highlight the specified beat */ - private cursorUpdateBeat(lookupResult: MidiTickLookupFindBeatResult, stop: boolean, shouldScroll: boolean): void { + private cursorUpdateBeat( + lookupResult: MidiTickLookupFindBeatResult, + stop: boolean, + shouldScroll: boolean, + forceUpdate: boolean = false + ): void { const beat: Beat = lookupResult.currentBeat; const nextBeat: Beat | null = lookupResult.nextBeat; const duration: number = lookupResult.duration; @@ -839,7 +852,12 @@ export class AlphaTabApiBase { let previousBeat = this._currentBeat; let previousCache: BoundsLookup | null = this._previousCursorCache; let previousState: PlayerState | null = this._previousStateForCursor; - if (beat === previousBeat?.currentBeat && cache === previousCache && previousState === this._playerState) { + if ( + !forceUpdate && + beat === previousBeat?.currentBeat && + cache === previousCache && + previousState === this._playerState + ) { return; } let beatBoundings: BeatBounds | null = cache.findBeat(beat); @@ -958,7 +976,6 @@ export class AlphaTabApiBase { this._currentBarBounds = barBoundings; - if (barCursor) { barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h); } @@ -971,7 +988,6 @@ export class AlphaTabApiBase { beatCursor.setBounds(beatBoundings.visualBounds.x, barBounds.y, 1, barBounds.h); } - // if playing, animate the cursor to the next beat if (this.settings.player.enableElementHighlighting) { this.uiFacade.removeHighlights(); @@ -1001,7 +1017,7 @@ export class AlphaTabApiBase { if ( nextBeatBoundings && nextBeatBoundings.barBounds.masterBarBounds.staveGroupBounds === - barBoundings.staveGroupBounds + barBoundings.staveGroupBounds ) { nextBeatX = nextBeatBoundings.visualBounds.x; } @@ -1011,7 +1027,7 @@ export class AlphaTabApiBase { // we need to put the transition to an own animation frame // otherwise the stop animation above is not applied. this.uiFacade.beginInvoke(() => { - if(beatCursor) { + if (beatCursor) { beatCursor.transitionToX(duration / this.playbackSpeed, nextBeatX); } }); @@ -1028,7 +1044,7 @@ export class AlphaTabApiBase { // trigger an event for others to indicate which beat/bar is played if (shouldNotifyBeatChange) { this.onPlayedBeatChanged(beat); - this.onActiveBeatsChanged(new ActiveBeatsChangedEventArgs(beatsToHighlight)) + this.onActiveBeatsChanged(new ActiveBeatsChangedEventArgs(beatsToHighlight)); } } @@ -1041,7 +1057,8 @@ export class AlphaTabApiBase { this.uiFacade.triggerEvent(this.container, 'playedBeatChanged', beat); } - public activeBeatsChanged: IEventEmitterOfT = new EventEmitterOfT(); + public activeBeatsChanged: IEventEmitterOfT = + new EventEmitterOfT(); private onActiveBeatsChanged(e: ActiveBeatsChangedEventArgs): void { if (this._isDestroyed) { return; @@ -1170,7 +1187,6 @@ export class AlphaTabApiBase { this._beatMouseDown = false; } - private onNoteMouseUp(originalEvent: IMouseEventArgs, note: Note | null): void { if (this._isDestroyed) { return; @@ -1218,7 +1234,6 @@ export class AlphaTabApiBase { this.onNoteMouseDown(e, note); } } - } }); this.canvasElement.mouseMove.on(e => { @@ -1255,8 +1270,7 @@ export class AlphaTabApiBase { if (beat) { const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null; this.onNoteMouseUp(e, note); - } - else { + } else { this.onNoteMouseUp(e, null); } } @@ -1504,4 +1518,16 @@ export class AlphaTabApiBase { (this.playbackRangeChanged as EventEmitterOfT).trigger(e); this.uiFacade.triggerEvent(this.container, 'playbackRangeChanged', e); } + + /** + * @internal + */ + public settingsUpdated: IEventEmitter = new EventEmitter(); + private onSettingsUpdated(): void { + if (this._isDestroyed) { + return; + } + (this.settingsUpdated as EventEmitter).trigger(); + this.uiFacade.triggerEvent(this.container, 'settingsUpdated', null); + } }