package com.twasyl.slideshowfx.controls.slideshow; import com.twasyl.slideshowfx.controls.PresentationBrowser; import com.twasyl.slideshowfx.utils.ResourceHelper; import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.beans.binding.DoubleBinding; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.geometry.Pos; import javafx.scene.input.KeyEvent; import javafx.scene.layout.StackPane; import javafx.scene.text.Text; import java.time.Duration; import java.time.LocalTime; /** * A pane that is used to display information about the presentation when the presentation mode is active. It displays * the current slide of the presentation, the next one and the time elapsed since the beginning of the presentation. * * @author Thierry Wasylczenko * @version 1.0.0 * @since SlideshowFX 1.0 */ public class InformationPane extends StackPane { private final Context context; private final Timeline timeline = new Timeline(); private final Text timeElapsed = new Text(); private final PresentationBrowser currentSlideBrowser = new PresentationBrowser(); private final PresentationBrowser nextSlideBrowser = new PresentationBrowser(); private LocalTime beginningTime; public InformationPane(final Context context) { super(); this.setAlignment(Pos.TOP_LEFT); this.getStylesheets().addAll( ResourceHelper.getExternalForm("/com/twasyl/slideshowfx/css/Default.css"), ResourceHelper.getExternalForm("/com/twasyl/slideshowfx/css/information-scene.css")); this.getStyleClass().add("information-scene"); this.context = context; this.initializeTimeElapsed(); this.initializeCurrentSlide(); this.initializeNextSlide(); } /** * Initialize the node that displays the time elapsed since the presentation has started. */ private final void initializeTimeElapsed() { this.timeElapsed.getStyleClass().add("time-elapsed"); final DoubleProperty fontSize = new SimpleDoubleProperty(0); this.timeElapsed.fontProperty().addListener((fontValue, oldFont, newFont) -> { if (newFont != null) { fontSize.set(newFont.getSize()); } }); this.timeElapsed.setTranslateX(50); this.timeElapsed.translateYProperty().bind(this.heightProperty().subtract(fontSize).subtract(50)); this.getChildren().add(this.timeElapsed); } /** * Initialize the node displaying the current slide of the presentation. */ private final void initializeCurrentSlide() { final DoubleBinding width = this.widthProperty().divide(1.8); final DoubleBinding height = this.heightProperty().divide(1.8); this.currentSlideBrowser.prefWidthProperty().bind(width); this.currentSlideBrowser.minWidthProperty().bind(width); this.currentSlideBrowser.maxWidthProperty().bind(width); this.currentSlideBrowser.prefHeightProperty().bind(height); this.currentSlideBrowser.minHeightProperty().bind(height); this.currentSlideBrowser.maxHeightProperty().bind(height); this.currentSlideBrowser.setTranslateX(50); this.currentSlideBrowser.setTranslateY(50); this.currentSlideBrowser.setInteractionAllowed(false); this.currentSlideBrowser.setBackend(this); this.getChildren().add(this.currentSlideBrowser); } /** * Initialize the node displaying the next slide of the presentation. */ private final void initializeNextSlide() { final DoubleBinding width = this.widthProperty().divide(3.5); final DoubleBinding height = this.heightProperty().divide(3.5); this.nextSlideBrowser.prefWidthProperty().bind(width); this.nextSlideBrowser.minWidthProperty().bind(width); this.nextSlideBrowser.maxWidthProperty().bind(width); this.nextSlideBrowser.prefHeightProperty().bind(height); this.nextSlideBrowser.minHeightProperty().bind(height); this.nextSlideBrowser.maxHeightProperty().bind(height); this.nextSlideBrowser.translateXProperty().bind(this.widthProperty().subtract(width).subtract(50)); this.nextSlideBrowser.setTranslateY(50); this.nextSlideBrowser.setInteractionAllowed(false); this.nextSlideBrowser.setBackend(this); this.getChildren().add(this.nextSlideBrowser); } /** * Start the information scene. This starts the monitoring of the time elapsed since the beginning of the presentation, * initialize the current and next slides. */ public void start() { this.beginningTime = LocalTime.now(); this.timeline.getKeyFrames().add(new KeyFrame(javafx.util.Duration.seconds(1), event -> { final Duration duration = Duration.between(this.beginningTime, LocalTime.now()); final long numberOfHours = duration.getSeconds() / 3600; final long numberOfMinutes = (duration.getSeconds() % 3600) / 60; final long numberOfSeconds = (duration.getSeconds() % 3600) % 60; this.timeElapsed.setText( String.format("%1$02d:%02$02d:%3$02d", numberOfHours, numberOfMinutes, numberOfSeconds) ); })); this.timeline.setCycleCount(Animation.INDEFINITE); this.timeline.playFromStart(); } /** * Stops the information scene. */ public void stop() { this.timeline.stop(); } public void sendKey(KeyEvent event) { this.currentSlideBrowser.fireEvent(event); this.nextSlideBrowser.fireEvent(event); } /** * Get the browser that displays the next slide of the presentation. * @return The browser displaying the next slide of the presentation. */ public PresentationBrowser getNextSlideBrowser() { return nextSlideBrowser; } /** * Get the browser that displays the current slide of the presentation. * @return The browser displaying the current slide of the presentation. */ public PresentationBrowser getCurrentSlideBrowser() { return currentSlideBrowser; } }