diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java new file mode 100644 index 0000000000000000000000000000000000000000..3287ca97157df9df9aac614b43ccd21baa49e94a --- /dev/null +++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java @@ -0,0 +1,26 @@ +package de.tobias.playpad.pad.fade; + +import javafx.animation.Transition; + +/** + * A fade controller implementation, that handles fade scala linear. + * + * @author tobias + * @since 7.1.0 + */ +public class LinearFadeController extends AbstractFadeController { + + public LinearFadeController(FadeControllerDelegate fadeDelegate) { + super(fadeDelegate); + } + + @Override + protected void interpolate(Transition transition, double frac, double from, double to) { + double diff = Math.abs(to - from); + if (from < to) { // Fade In + fadeDelegate.onFadeLevelChange(diff * frac); + } else { // Fade Out + fadeDelegate.onFadeLevelChange(from - (diff * frac)); + } + } +} diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala index f24e07c07f97cc10b2c677d56974e8596c77b64b..90bc30425035955ac49b0833f9381792c7a1a7b4 100644 --- a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala +++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala @@ -45,6 +45,7 @@ class ContentPlayerViewController extends NVC { val mediaView = mediaViews(mediaPlayer) mediaView.setUserData(padIndex) + mediaView.setOpacity(1.0) if (!getChildren.contains(mediaView)) { val index = activePlayers.indexOf(padIndex) @@ -58,6 +59,13 @@ class ContentPlayerViewController extends NVC { } } + def setFadeValue(mediaPlayer: MediaPlayer, value: Double): Unit ={ + if (mediaViews.contains(mediaPlayer)) { + val mediaView = mediaViews(mediaPlayer) + mediaView.setOpacity(value) + } + } + def highlight(on: Boolean): Unit = { if (on) { setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY))) @@ -69,7 +77,7 @@ class ContentPlayerViewController extends NVC { override def toString: String = f"MediaPlayerStack: ${getChildren.stream().map(view => f"MediaView: ${view.getUserData}").collect(Collectors.joining(", "))}" } - private val mediaPlayers: ListBuffer[MediaPlayerStack] = ListBuffer.empty + private val mediaStacks: ListBuffer[MediaPlayerStack] = ListBuffer.empty load("view", "PlayerView") applyViewControllerToStage @@ -89,7 +97,7 @@ class ContentPlayerViewController extends NVC { } def showMediaPlayer(padIndex: PadIndex, mediaPlayer: MediaPlayer, zones: Seq[PlayerInstance]): Unit = { - val iterator = this.mediaPlayers.iterator + val iterator = this.mediaStacks.iterator while (iterator.hasNext) { val mediaPlayerStack = iterator.next() if (zones.contains(mediaPlayerStack.playerInstance)) { @@ -99,7 +107,7 @@ class ContentPlayerViewController extends NVC { } def disconnectMediaPlayer(mediaPlayer: MediaPlayer, zones: Seq[PlayerInstance]): Unit = { - val iterator = this.mediaPlayers.iterator + val iterator = this.mediaStacks.iterator while (iterator.hasNext) { val mediaPlayerStack = iterator.next() if (zones.contains(mediaPlayerStack.playerInstance)) { @@ -112,10 +120,10 @@ class ContentPlayerViewController extends NVC { val parent = getParent.asInstanceOf[Pane] parent.getChildren.clear() - mediaPlayers.clear() + mediaStacks.clear() configuration.instances.forEach(player => { val mediaPlayerStack = new MediaPlayerStack(player) - mediaPlayers.addOne(mediaPlayerStack) + mediaStacks.addOne(mediaPlayerStack) parent.getChildren.add(mediaPlayerStack) }) @@ -134,15 +142,24 @@ class ContentPlayerViewController extends NVC { }) } - def addActivePadToList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = mediaPlayers - .filter(mediaPlayer => zones.contains(mediaPlayer.playerInstance)) - .foreach(mediaPlayer => mediaPlayer.addActivePad(padIndex)) + def addActivePadToList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = getMediaStacks(zones) + .foreach(mediaStack => mediaStack.addActivePad(padIndex)) - def removeActivePadFromList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = mediaPlayers - .filter(mediaPlayer => zones.contains(mediaPlayer.playerInstance)) - .foreach(mediaPlayer => mediaPlayer.removeActivePad(padIndex)) + def removeActivePadFromList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = getMediaStacks(zones) + .foreach(mediaStack => mediaStack.removeActivePad(padIndex)) def highlight(zone: PlayerInstance, on: Boolean): Unit = { - mediaPlayers.filter(mediaPlayer => zone == mediaPlayer.playerInstance).head.highlight(on) + getMediaStack(zone).head.highlight(on) + } + + def setFadeValue(mediaPlayer: MediaPlayer, zones: Seq[PlayerInstance], value: Double): Unit = getMediaStacks(zones) + .foreach(mediaStack => mediaStack.setFadeValue(mediaPlayer, value)) + + private def getMediaStack(zone: PlayerInstance): ListBuffer[MediaPlayerStack] = { + getMediaStacks(List(zone)) + } + + private def getMediaStacks(zones: Seq[PlayerInstance]): ListBuffer[MediaPlayerStack] = { + mediaStacks.filter(mediaPlayer => zones.contains(mediaPlayer.playerInstance)) } } diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala index 2a4248de50c6b5f50a797a9a8bb47b7e7234282b..005aad995945036e872e3e3d1001944ebbbf1321 100644 --- a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala +++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala @@ -6,6 +6,7 @@ import java.util.stream.Collectors import de.tobias.playpad.pad.content.play.{Durationable, Pauseable} import de.tobias.playpad.pad.content.{PadContent, Playlistable} +import de.tobias.playpad.pad.fade.{Fadeable, LinearFadeController} import de.tobias.playpad.pad.mediapath.MediaPath import de.tobias.playpad.pad.{Pad, PadStatus} import de.tobias.playpad.plugin.content.ContentPluginMain @@ -21,7 +22,7 @@ import javafx.util.Duration import scala.jdk.CollectionConverters._ -class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadContent(pad) with Pauseable with Durationable with Playlistable { +class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadContent(pad) with Pauseable with Durationable with Playlistable with Fadeable { private class MediaPlayerContainer(val path: MediaPath, val mediaPlayer: MediaPlayer) { def play(): Unit = { @@ -32,6 +33,8 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte mediaPlayer.seek(Duration.ZERO) mediaPlayer.play() + getPad.setEof(false) + currentRunningIndexProperty.set(mediaPlayers.indexOf(this)) val controller = getPad.getController @@ -84,6 +87,9 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte private var showingLastFrame: Boolean = false private var isPause: Boolean = false + private val fadeController = new LinearFadeController(value => ContentPluginMain.playerViewController + .setFadeValue(mediaPlayers(currentPlayingMediaIndex).mediaPlayer, getSelectedZones, value)) + override def getType: String = `type` override def currentPlayingMediaIndex: Int = currentRunningIndexProperty.get() @@ -128,7 +134,10 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte } def onEof(): Unit = { - if (shouldShowLastFrame() && !showingLastFrame && !pad.getPadSettings.isLoop) { + if (shouldShowLastFrame() && !showingLastFrame // Only is settings is enabled and not already in last frame state + && !pad.getPadSettings.isLoop // Only go to last frame state, is looping is disabled + && !isFadeActive // Only go to last frame state, if no fade is active (if eof is reached while fade out, the last frame should not be hold) + ) { getPad.setStatus(PadStatus.PAUSE) showingLastFrame = true return @@ -172,6 +181,36 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte .toArray(size => new Array[ReadOnlyObjectProperty[Duration]](size)): _*) } + /* + Fadeable + */ + + override def fadeIn(): Unit = { + val fadeIn = getPad.getPadSettings.getFade.getFadeIn + if (fadeIn.toMillis > 0) { + fadeController.fadeIn(fadeIn) + } + } + + override def fadeOut(onFinish: Runnable): Unit = { + val fadeOut = getPad.getPadSettings.getFade.getFadeOut + if (fadeOut.toMillis > 0) { + fadeController.fadeOut(fadeOut, () => { + if (onFinish != null) onFinish.run() + updateVolume() + }) + } + else { + onFinish.run() + } + } + + override def isFadeActive: Boolean = fadeController.isFading + + override def fade(from: Double, to: Double, duration: Duration, onFinish: Runnable): Unit = { + fadeController.fade(from, to, duration, onFinish) + } + /* Loading */