diff --git a/src/main/java/dev/bytevibe/hyperpoint/Controller.java b/src/main/java/dev/bytevibe/hyperpoint/Controller.java index b49316f..aa5659c 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/Controller.java +++ b/src/main/java/dev/bytevibe/hyperpoint/Controller.java @@ -470,6 +470,86 @@ public class Controller implements Initializable { } } + /** + * 开始演示(默认淡出淡入效果) + */ + @FXML + public void onStartPresentation(ActionEvent actionEvent) { + if (currentSlide == null || currentSlide.getPages().isEmpty()) { + showWarning("无幻灯片", "请先创建或打开一个幻灯片。"); + return; + } + startPresentation(TransitionEffect.FADE); + } + + /** + * 使用淡出淡入效果播放演示 + */ + @FXML + public void onPresentationWithFade(ActionEvent actionEvent) { + if (currentSlide == null || currentSlide.getPages().isEmpty()) { + showWarning("无幻灯片", "请先创建或打开一个幻灯片。"); + return; + } + startPresentation(TransitionEffect.FADE); + } + + /** + * 使用从右推入效果播放演示 + */ + @FXML + public void onPresentationWithPushLeft(ActionEvent actionEvent) { + if (currentSlide == null || currentSlide.getPages().isEmpty()) { + showWarning("无幻灯片", "请先创建或打开一个幻灯片。"); + return; + } + startPresentation(TransitionEffect.PUSH_LEFT); + } + + /** + * 使用从左推入效果播放演示 + */ + @FXML + public void onPresentationWithPushRight(ActionEvent actionEvent) { + if (currentSlide == null || currentSlide.getPages().isEmpty()) { + showWarning("无幻灯片", "请先创建或打开一个幻灯片。"); + return; + } + startPresentation(TransitionEffect.PUSH_RIGHT); + } + + /** + * 使用缩放放大效果播放演示 + */ + @FXML + public void onPresentationWithZoomIn(ActionEvent actionEvent) { + if (currentSlide == null || currentSlide.getPages().isEmpty()) { + showWarning("无幻灯片", "请先创建或打开一个幻灯片。"); + return; + } + startPresentation(TransitionEffect.ZOOM_IN); + } + + /** + * 使用旋转翻页效果播放演示 + */ + @FXML + public void onPresentationWithRotate(ActionEvent actionEvent) { + if (currentSlide == null || currentSlide.getPages().isEmpty()) { + showWarning("无幻灯片", "请先创建或打开一个幻灯片。"); + return; + } + startPresentation(TransitionEffect.ROTATE); + } + + /** + * 启动演示 + */ + private void startPresentation(TransitionEffect transition) { + PresentationWindow presentationWindow = new PresentationWindow(currentSlide, transition); + presentationWindow.show(); + } + /** * 显示警告对话框 */ diff --git a/src/main/java/dev/bytevibe/hyperpoint/PresentationWindow.java b/src/main/java/dev/bytevibe/hyperpoint/PresentationWindow.java new file mode 100644 index 0000000..cc782a4 --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/PresentationWindow.java @@ -0,0 +1,677 @@ +package dev.bytevibe.hyperpoint; + +import javafx.animation.*; +import javafx.geometry.Bounds; +import javafx.scene.Scene; +import javafx.scene.canvas.Canvas; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.scene.transform.Rotate; +import javafx.stage.Stage; +import javafx.stage.StageStyle; +import javafx.util.Duration; + +/** + * 全屏演示窗口,支持翻页和动画效果 + */ +public class PresentationWindow { + private final Slide slide; + private final Stage stage; + private final Canvas canvas; + private final StackPane root; + private int currentPageIndex = 0; + private TransitionEffect currentTransition = TransitionEffect.FADE; + private boolean isTransitioning = false; + + public PresentationWindow(Slide slide, TransitionEffect transition) { + this.slide = slide; + this.currentTransition = transition; + this.stage = new Stage(); + this.canvas = new Canvas(); + this.root = new StackPane(); + + initializeStage(); + } + + private void initializeStage() { + // 页面标准宽高比 (4:3) + final double PAGE_WIDTH = 1024; + final double PAGE_HEIGHT = 768; + final double ASPECT_RATIO = PAGE_WIDTH / PAGE_HEIGHT; // 4:3 = 1.333... + + // 设置全屏,获取屏幕分辨率 + stage.setFullScreen(true); + stage.setFullScreenExitHint(""); + stage.initStyle(StageStyle.UNDECORATED); + + // 绑定Canvas大小到root,Canvas会根据root大小自动调整 + canvas.widthProperty().bind(root.widthProperty()); + canvas.heightProperty().bind(root.heightProperty()); + + // 添加键盘和鼠标事件处理 + root.setOnKeyPressed(this::handleKeyEvent); + root.setOnMouseClicked(this::handleMouseClick); + + root.getChildren().add(canvas); + root.setStyle("-fx-background-color: #000000;"); + root.setFocusTraversable(true); + + Scene scene = new Scene(root); + stage.setScene(scene); + + // 监听Scene大小变化,计算缩放因子 + scene.widthProperty().addListener((obs, oldVal, newVal) -> drawCurrentPage(null)); + scene.heightProperty().addListener((obs, oldVal, newVal) -> drawCurrentPage(null)); + + // 显示第一页 + drawCurrentPage(null); + } + + /** + * 显示演示窗口 + */ + public void show() { + stage.show(); + root.requestFocus(); + } + + /** + * 处理键盘事件 + */ + private void handleKeyEvent(KeyEvent event) { + if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.SPACE) { + nextPage(); + } else if (event.getCode() == KeyCode.LEFT) { + previousPage(); + } else if (event.getCode() == KeyCode.ESCAPE) { + exitPresentation(); + } + } + + /** + * 处理鼠标点击事件 + */ + private void handleMouseClick(MouseEvent event) { + if (event.getClickCount() == 1) { + nextPage(); + } + } + + /** + * 下一页 + */ + private void nextPage() { + if (isTransitioning || currentPageIndex >= slide.getPages().size() - 1) { + return; + } + currentPageIndex++; + playTransition(currentTransition); + } + + /** + * 上一页 + */ + private void previousPage() { + if (isTransitioning || currentPageIndex <= 0) { + return; + } + currentPageIndex--; + playTransition(currentTransition); + } + + /** + * 播放过渡动画 + */ + private void playTransition(TransitionEffect effect) { + isTransitioning = true; + + switch (effect) { + case FADE: + playFadeTransition(); + break; + case PUSH_LEFT: + playPushTransition(-canvas.getWidth(), 0); + break; + case PUSH_RIGHT: + playPushTransition(canvas.getWidth(), 0); + break; + case PUSH_DOWN: + playPushTransition(0, canvas.getHeight()); + break; + case PUSH_UP: + playPushTransition(0, -canvas.getHeight()); + break; + case ZOOM_IN: + playZoomTransition(0.5, 1.0); + break; + case ZOOM_OUT: + playZoomTransition(1.0, 0.5); + break; + case ROTATE: + playRotateTransition(); + break; + default: + drawCurrentPage(null); + isTransitioning = false; + } + } + + /** + * 淡出淡入动画 + */ + private void playFadeTransition() { + int duration = currentTransition.getDuration(); + int halfDuration = duration / 2; + + // 保存当前页面索引 + int previousPageIndex = currentPageIndex - 1; + if (previousPageIndex < 0) previousPageIndex = slide.getPages().size() - 1; + + // 淡出旧页面,显示黑屏,淡入新页面 + AnimationTimer animationTimer = new AnimationTimer() { + private long startTime = System.currentTimeMillis(); + private final long fadeOutDuration = halfDuration; + private final long fadeInDuration = halfDuration; + + @Override + public void handle(long now) { + long elapsed = System.currentTimeMillis() - startTime; + + if (elapsed < fadeOutDuration) { + // 淡出阶段 + double progress = (double) elapsed / fadeOutDuration; + drawFadeTransition(progress, true); + } else if (elapsed < fadeOutDuration + fadeInDuration) { + // 淡入阶段 + double progress = (double) (elapsed - fadeOutDuration) / fadeInDuration; + drawFadeTransition(progress, false); + } else { + // 动画完成 + drawCurrentPage(null); + isTransitioning = false; + stop(); + } + } + }; + + animationTimer.start(); + } + + /** + * 绘制淡出淡入过渡 + */ + private void drawFadeTransition(double progress, boolean fadeOut) { + GraphicsContext gc = canvas.getGraphicsContext2D(); + double canvasWidth = canvas.getWidth(); + double canvasHeight = canvas.getHeight(); + + final double PAGE_WIDTH = 1024; + final double PAGE_HEIGHT = 768; + + double scaleX = canvasWidth / PAGE_WIDTH; + double scaleY = canvasHeight / PAGE_HEIGHT; + double scale = Math.min(scaleX, scaleY); + + double scaledWidth = PAGE_WIDTH * scale; + double scaledHeight = PAGE_HEIGHT * scale; + + double offsetX = (canvasWidth - scaledWidth) / 2; + double offsetY = (canvasHeight - scaledHeight) / 2; + + if (fadeOut) { + // 绘制当前页面并淡出 + drawCurrentPage(null); + gc.setFill(Color.BLACK.interpolate(Color.TRANSPARENT, 1 - progress)); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + } else { + // 绘制黑屏并淡入下一页 + gc.setFill(Color.BLACK); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + + gc.setFill(Color.WHITE); + gc.fillRect(offsetX, offsetY, scaledWidth, scaledHeight); + + gc.save(); + gc.translate(offsetX, offsetY); + gc.scale(scale, scale); + + SlidePage page = slide.getPages().get(currentPageIndex); + for (DrawableObject obj : page.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + + gc.restore(); + + // 淡入效果 + gc.setFill(Color.color(1, 1, 1, 1 - progress)); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + } + } + + /** + * 推送动画 + */ + private void playPushTransition(double offsetX, double offsetY) { + int duration = currentTransition.getDuration(); + + AnimationTimer animationTimer = new AnimationTimer() { + private long startTime = System.currentTimeMillis(); + + @Override + public void handle(long now) { + long elapsed = System.currentTimeMillis() - startTime; + + if (elapsed < duration) { + double progress = (double) elapsed / duration; + drawPushTransition(progress, offsetX, offsetY); + } else { + drawCurrentPage(null); + isTransitioning = false; + stop(); + } + } + }; + + animationTimer.start(); + } + + /** + * 绘制推送过渡 + */ + private void drawPushTransition(double progress, double offsetX, double offsetY) { + GraphicsContext gc = canvas.getGraphicsContext2D(); + double canvasWidth = canvas.getWidth(); + double canvasHeight = canvas.getHeight(); + + final double PAGE_WIDTH = 1024; + final double PAGE_HEIGHT = 768; + + double scaleX = canvasWidth / PAGE_WIDTH; + double scaleY = canvasHeight / PAGE_HEIGHT; + double scale = Math.min(scaleX, scaleY); + + double scaledWidth = PAGE_WIDTH * scale; + double scaledHeight = PAGE_HEIGHT * scale; + + double centerOffsetX = (canvasWidth - scaledWidth) / 2; + double centerOffsetY = (canvasHeight - scaledHeight) / 2; + + // 清空背景 + gc.setFill(Color.BLACK); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + + // 获取前一页索引(确保有效) + int prevPageIndex = currentPageIndex - 1; + if (prevPageIndex < 0) { + prevPageIndex = slide.getPages().size() - 1; // 循环到最后一页 + } + + // 绘制旧页面 + SlidePage prevPage = slide.getPages().get(prevPageIndex); + double slideOffsetX = offsetX * progress; + double slideOffsetY = offsetY * progress; + + gc.save(); + gc.translate(centerOffsetX + slideOffsetX, centerOffsetY + slideOffsetY); + gc.scale(scale, scale); + gc.setFill(Color.WHITE); + gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT); + for (DrawableObject obj : prevPage.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + gc.restore(); + + // 绘制新页面推入 + SlidePage newPage = slide.getPages().get(currentPageIndex); + double newPageOffsetX = centerOffsetX - offsetX * (1 - progress); + double newPageOffsetY = centerOffsetY - offsetY * (1 - progress); + + gc.save(); + gc.translate(newPageOffsetX, newPageOffsetY); + gc.scale(scale, scale); + gc.setFill(Color.WHITE); + gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT); + for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + gc.restore(); + } + + /** + * 缩放动画 + */ + private void playZoomTransition(double startScale, double endScale) { + int duration = currentTransition.getDuration(); + + AnimationTimer animationTimer = new AnimationTimer() { + private long startTime = System.currentTimeMillis(); + + @Override + public void handle(long now) { + long elapsed = System.currentTimeMillis() - startTime; + + if (elapsed < duration) { + double progress = (double) elapsed / duration; + double currentScale = startScale + (endScale - startScale) * progress; + drawZoomTransition(currentScale, progress); + } else { + drawCurrentPage(null); + isTransitioning = false; + stop(); + } + } + }; + + animationTimer.start(); + } + + /** + * 绘制缩放过渡 + */ + private void drawZoomTransition(double zoomScale, double progress) { + GraphicsContext gc = canvas.getGraphicsContext2D(); + double canvasWidth = canvas.getWidth(); + double canvasHeight = canvas.getHeight(); + + final double PAGE_WIDTH = 1024; + final double PAGE_HEIGHT = 768; + + double scaleX = canvasWidth / PAGE_WIDTH; + double scaleY = canvasHeight / PAGE_HEIGHT; + double scale = Math.min(scaleX, scaleY); + + double scaledWidth = PAGE_WIDTH * scale; + double scaledHeight = PAGE_HEIGHT * scale; + + double offsetX = (canvasWidth - scaledWidth) / 2; + double offsetY = (canvasHeight - scaledHeight) / 2; + + // 清空背景 + gc.setFill(Color.BLACK); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + + // 获取前一页索引(确保有效) + int prevPageIndex = currentPageIndex - 1; + if (prevPageIndex < 0) { + prevPageIndex = slide.getPages().size() - 1; // 循环到最后一页 + } + + // 绘制旧页面,逐渐缩小 + SlidePage prevPage = slide.getPages().get(prevPageIndex); + double oldPageScale = scale * (1 - progress * 0.3); // 缩小30% + double oldPageWidth = PAGE_WIDTH * oldPageScale; + double oldPageHeight = PAGE_HEIGHT * oldPageScale; + double oldPageOffsetX = (canvasWidth - oldPageWidth) / 2; + double oldPageOffsetY = (canvasHeight - oldPageHeight) / 2; + + gc.save(); + gc.translate(oldPageOffsetX, oldPageOffsetY); + gc.scale(oldPageScale / scale, oldPageScale / scale); + gc.setFill(Color.WHITE); + gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT); + for (DrawableObject obj : prevPage.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + gc.restore(); + + // 绘制新页面,逐渐放大 + SlidePage newPage = slide.getPages().get(currentPageIndex); + double newPageScale = scale * (0.7 + progress * 0.3); // 从70%放大到100% + double newPageWidth = PAGE_WIDTH * newPageScale; + double newPageHeight = PAGE_HEIGHT * newPageScale; + double newPageOffsetX = (canvasWidth - newPageWidth) / 2; + double newPageOffsetY = (canvasHeight - newPageHeight) / 2; + + gc.save(); + gc.translate(newPageOffsetX, newPageOffsetY); + gc.scale(newPageScale / scale, newPageScale / scale); + gc.setFill(Color.WHITE); + gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT); + for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + gc.restore(); + } + + /** + * 旋转动画 + */ + private void playRotateTransition() { + int duration = currentTransition.getDuration(); + + AnimationTimer animationTimer = new AnimationTimer() { + private long startTime = System.currentTimeMillis(); + + @Override + public void handle(long now) { + long elapsed = System.currentTimeMillis() - startTime; + + if (elapsed < duration) { + double progress = (double) elapsed / duration; + double rotation = progress * 360; // 360度旋转 + drawRotateTransition(rotation, progress); + } else { + drawCurrentPage(null); + isTransitioning = false; + stop(); + } + } + }; + + animationTimer.start(); + } + + /** + * 绘制旋转过渡 + */ + private void drawRotateTransition(double rotation, double progress) { + GraphicsContext gc = canvas.getGraphicsContext2D(); + double canvasWidth = canvas.getWidth(); + double canvasHeight = canvas.getHeight(); + + final double PAGE_WIDTH = 1024; + final double PAGE_HEIGHT = 768; + + double scaleX = canvasWidth / PAGE_WIDTH; + double scaleY = canvasHeight / PAGE_HEIGHT; + double scale = Math.min(scaleX, scaleY); + + double scaledWidth = PAGE_WIDTH * scale; + double scaledHeight = PAGE_HEIGHT * scale; + + double offsetX = (canvasWidth - scaledWidth) / 2; + double offsetY = (canvasHeight - scaledHeight) / 2; + + // 清空背景 + gc.setFill(Color.BLACK); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + + // 绘制旋转的页面 + SlidePage newPage = slide.getPages().get(currentPageIndex); + + gc.save(); + // 移到中心,旋转,再移回 + double centerX = offsetX + scaledWidth / 2; + double centerY = offsetY + scaledHeight / 2; + + gc.translate(centerX, centerY); + gc.rotate(rotation); + gc.translate(-scaledWidth / 2, -scaledHeight / 2); + gc.scale(scale, scale); + + gc.setFill(Color.WHITE); + gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT); + for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + + gc.restore(); + } + + /** + * 绘制当前页面 + */ + private void drawCurrentPage(Animation animation) { + if (currentPageIndex < 0 || currentPageIndex >= slide.getPages().size()) { + return; + } + + GraphicsContext gc = canvas.getGraphicsContext2D(); + double canvasWidth = canvas.getWidth(); + double canvasHeight = canvas.getHeight(); + + // 页面标准宽高比 + final double PAGE_WIDTH = 1024; + final double PAGE_HEIGHT = 768; + + // 计算缩放因子,保持宽高比 + double scaleX = canvasWidth / PAGE_WIDTH; + double scaleY = canvasHeight / PAGE_HEIGHT; + double scale = Math.min(scaleX, scaleY); + + // 计算内容区域的实际宽高 + double scaledWidth = PAGE_WIDTH * scale; + double scaledHeight = PAGE_HEIGHT * scale; + + // 计算居中偏移 + double offsetX = (canvasWidth - scaledWidth) / 2; + double offsetY = (canvasHeight - scaledHeight) / 2; + + // 清空背景(黑色) + gc.setFill(Color.BLACK); + gc.fillRect(0, 0, canvasWidth, canvasHeight); + + // 白色背景区域 + gc.setFill(Color.WHITE); + gc.fillRect(offsetX, offsetY, scaledWidth, scaledHeight); + + SlidePage page = slide.getPages().get(currentPageIndex); + + // 保存绘图上下文 + gc.save(); + + // 应用缩放和平移变换 + gc.translate(offsetX, offsetY); + gc.scale(scale, scale); + + // 绘制所有对象 + for (DrawableObject obj : page.getPageContent().getDrawableObjects()) { + drawObject(gc, obj); + } + + gc.restore(); + + // 绘制页码(不受缩放影响) + drawPageNumber(gc, canvasWidth, canvasHeight); + } + + /** + * 绘制单个对象 + */ + private void drawObject(GraphicsContext gc, DrawableObject obj) { + if (obj instanceof TextObject) { + drawTextObject(gc, (TextObject) obj); + } else if (obj instanceof ShapeObject) { + drawShapeObject(gc, (ShapeObject) obj); + } else if (obj instanceof ImageObject) { + drawImageObject(gc, (ImageObject) obj); + } + } + + /** + * 绘制文本对象 + */ + private void drawTextObject(GraphicsContext gc, TextObject textObj) { + gc.setFill(textObj.getTextColorAsColor()); + gc.setFont(new javafx.scene.text.Font(textObj.getFontFamily(), textObj.getFontSize())); + + double lineHeight = textObj.getFontSize() * 1.2; + double currentY = textObj.getY(); + + for (String line : textObj.getLayoutLines()) { + currentY += lineHeight; + gc.fillText(line, textObj.getX() + 5, currentY); + } + } + + /** + * 绘制形状对象 + */ + private void drawShapeObject(GraphicsContext gc, ShapeObject shapeObj) { + gc.setFill(Color.web("#" + shapeObj.getFillColor())); + gc.setStroke(Color.web("#" + shapeObj.getStrokeColor())); + gc.setLineWidth(shapeObj.getStrokeWidth()); + + switch (shapeObj.getShapeType()) { + case RECTANGLE: + gc.fillRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight()); + gc.strokeRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight()); + break; + case CIRCLE: + double radius = Math.min(shapeObj.getWidth(), shapeObj.getHeight()) / 2; + gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight()); + gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight()); + break; + case ELLIPSE: + gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight()); + gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight()); + break; + case LINE: + gc.strokeLine(shapeObj.getX(), shapeObj.getY(), + shapeObj.getX() + shapeObj.getWidth(), shapeObj.getY() + shapeObj.getHeight()); + break; + } + } + + /** + * 绘制图片对象 + */ + private void drawImageObject(GraphicsContext gc, ImageObject imgObj) { + try { + javafx.scene.image.Image image = new javafx.scene.image.Image("file:" + imgObj.getImagePath()); + gc.drawImage(image, imgObj.getX(), imgObj.getY(), imgObj.getWidth(), imgObj.getHeight()); + } catch (Exception e) { + // 图片加载失败,显示占位符 + gc.setFill(Color.LIGHTGRAY); + gc.fillRect(imgObj.getX(), imgObj.getY(), imgObj.getWidth(), imgObj.getHeight()); + gc.setFill(Color.BLACK); + gc.fillText("图片加载失败", imgObj.getX() + 10, imgObj.getY() + 20); + } + } + + /** + * 绘制页码(不受缩放影响) + */ + private void drawPageNumber(GraphicsContext gc, double canvasWidth, double canvasHeight) { + gc.setFill(Color.BLACK); + gc.setFont(new javafx.scene.text.Font(16)); + String pageNum = String.format("%d / %d", currentPageIndex + 1, slide.getPages().size()); + gc.fillText(pageNum, canvasWidth - 100, canvasHeight - 20); + } + + /** + * 设置翻页动画 + */ + public void setTransitionEffect(TransitionEffect effect) { + this.currentTransition = effect; + } + + /** + * 退出演示 + */ + private void exitPresentation() { + stage.close(); + } + + /** + * 获取舞台 + */ + public Stage getStage() { + return stage; + } +} + diff --git a/src/main/java/dev/bytevibe/hyperpoint/TransitionEffect.java b/src/main/java/dev/bytevibe/hyperpoint/TransitionEffect.java new file mode 100644 index 0000000..80f1d60 --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/TransitionEffect.java @@ -0,0 +1,68 @@ +package dev.bytevibe.hyperpoint; + +/** + * 演示/播放模式下支持的翻页动画效果 + */ +public enum TransitionEffect { + /** + * 无动画,直接切换 + */ + NONE("无动画", 0), + + /** + * 淡出/淡入效果 + */ + FADE("淡出淡入", 500), + + /** + * 从右向左推送效果 + */ + PUSH_LEFT("从右推入", 400), + + /** + * 从左向右推送效果 + */ + PUSH_RIGHT("从左推入", 400), + + /** + * 从上向下推送效果 + */ + PUSH_DOWN("从上推入", 400), + + /** + * 从下向上推送效果 + */ + PUSH_UP("从下推入", 400), + + /** + * 缩放效果 - 从小到大 + */ + ZOOM_IN("缩放放大", 500), + + /** + * 缩放效果 - 从大到小 + */ + ZOOM_OUT("缩放缩小", 500), + + /** + * 旋转效果 + */ + ROTATE("旋转翻页", 600); + + private final String displayName; + private final int duration; // 毫秒 + + TransitionEffect(String displayName, int duration) { + this.displayName = displayName; + this.duration = duration; + } + + public String getDisplayName() { + return displayName; + } + + public int getDuration() { + return duration; + } +} + diff --git a/src/main/resources/dev/bytevibe/hyperpoint/main.fxml b/src/main/resources/dev/bytevibe/hyperpoint/main.fxml index 086a7ab..d1cb44c 100644 --- a/src/main/resources/dev/bytevibe/hyperpoint/main.fxml +++ b/src/main/resources/dev/bytevibe/hyperpoint/main.fxml @@ -47,6 +47,18 @@ + + + + + + + + + + + +