diff --git a/.idea/copilotDiffState.xml b/.idea/copilotDiffState.xml new file mode 100644 index 0000000..e554f47 --- /dev/null +++ b/.idea/copilotDiffState.xml @@ -0,0 +1,94 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6c21848..69ee196 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,11 @@ javafx-fxml ${javafx.version} + + org.openjfx + javafx-graphics + ${javafx.version} + org.openjfx javafx-swing diff --git a/src/main/java/dev/bytevibe/hyperpoint/AddObjectCommand.java b/src/main/java/dev/bytevibe/hyperpoint/AddObjectCommand.java new file mode 100644 index 0000000..0ac5dff --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/AddObjectCommand.java @@ -0,0 +1,25 @@ +package dev.bytevibe.hyperpoint; + +/** + * 添加对象命令 + */ +public class AddObjectCommand implements Command { + private PageContent pageContent; + private DrawableObject object; + + public AddObjectCommand(PageContent pageContent, DrawableObject object) { + this.pageContent = pageContent; + this.object = object; + } + + @Override + public void execute() { + pageContent.addObject(object); + } + + @Override + public void undo() { + pageContent.removeObject(object); + } +} + diff --git a/src/main/java/dev/bytevibe/hyperpoint/Command.java b/src/main/java/dev/bytevibe/hyperpoint/Command.java new file mode 100644 index 0000000..5ac9127 --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/Command.java @@ -0,0 +1,17 @@ +package dev.bytevibe.hyperpoint; + +/** + * 命令接口,用于撤销和重做功能 + */ +public interface Command { + /** + * 执行命令 + */ + void execute(); + + /** + * 撤销命令 + */ + void undo(); +} + diff --git a/src/main/java/dev/bytevibe/hyperpoint/CommandHistory.java b/src/main/java/dev/bytevibe/hyperpoint/CommandHistory.java new file mode 100644 index 0000000..ad0b1ad --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/CommandHistory.java @@ -0,0 +1,91 @@ +package dev.bytevibe.hyperpoint; + +import java.util.Stack; + +/** + * 命令历史管理器,支持撤销和重做 + */ +public class CommandHistory { + private Stack undoStack; + private Stack redoStack; + private Runnable onHistoryChanged; + + public CommandHistory() { + this.undoStack = new Stack<>(); + this.redoStack = new Stack<>(); + } + + /** + * 执行命令并将其添加到历史记录 + */ + public void execute(Command command) { + command.execute(); + undoStack.push(command); + redoStack.clear(); // 执行新命令后,清空重做栈 + notifyHistoryChanged(); + } + + /** + * 撤销上一个命令 + */ + public void undo() { + if (!undoStack.isEmpty()) { + Command command = undoStack.pop(); + command.undo(); + redoStack.push(command); + notifyHistoryChanged(); + } + } + + /** + * 重做上一个被撤销的命令 + */ + public void redo() { + if (!redoStack.isEmpty()) { + Command command = redoStack.pop(); + command.execute(); + undoStack.push(command); + notifyHistoryChanged(); + } + } + + /** + * 检查是否可以撤销 + */ + public boolean canUndo() { + return !undoStack.isEmpty(); + } + + /** + * 检查是否可以重做 + */ + public boolean canRedo() { + return !redoStack.isEmpty(); + } + + /** + * 清空历史记录 + */ + public void clear() { + undoStack.clear(); + redoStack.clear(); + notifyHistoryChanged(); + } + + /** + * 设置历史记录变化监听器 + */ + public void setOnHistoryChanged(Runnable callback) { + this.onHistoryChanged = callback; + } + + /** + * 通知历史记录已改变 + */ + private void notifyHistoryChanged() { + if (onHistoryChanged != null) { + onHistoryChanged.run(); + } + } +} + diff --git a/src/main/java/dev/bytevibe/hyperpoint/Controller.java b/src/main/java/dev/bytevibe/hyperpoint/Controller.java index aa5659c..818c310 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/Controller.java +++ b/src/main/java/dev/bytevibe/hyperpoint/Controller.java @@ -26,14 +26,23 @@ public class Controller implements Initializable { private VBox propertyPanelContainer; @FXML private AnchorPane scenePane; + @FXML + private MenuItem undoMenuItem; + @FXML + private MenuItem redoMenuItem; private Slide currentSlide; private DrawingCanvas drawingCanvas; private PropertyPanel propertyPanelComponent; + private CommandHistory commandHistory; Stage stage; @Override public void initialize(URL url, ResourceBundle resourceBundle) { + // 初始化命令历史 + commandHistory = new CommandHistory(); + commandHistory.setOnHistoryChanged(this::updateUndoRedoButtons); + pageListView.setDisable(true); // 添加页面列表选择监听 @@ -103,6 +112,7 @@ public class Controller implements Initializable { // 创建新的Canvas PageContent pageContent = page.getPageContent(); drawingCanvas = new DrawingCanvas(pageContent); + drawingCanvas.setCommandHistory(commandHistory); // 设置命令历史 drawingCanvasContainer.getChildren().add(drawingCanvas); // 使用AnchorPane的约束来填充容器 @@ -211,7 +221,15 @@ public class Controller implements Initializable { String text = dialog.getResult(); if (!text.trim().isEmpty()) { TextObject textObj = new TextObject(50, 50, text); - drawingCanvas.addObject(textObj); + // 使用命令历史记录此操作 + SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem(); + if (currentPage != null) { + AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), textObj); + commandHistory.execute(command); + drawingCanvas.redraw(); + } else { + drawingCanvas.addObject(textObj); + } } } } @@ -226,7 +244,14 @@ public class Controller implements Initializable { return; } ShapeObject line = new ShapeObject(50, 50, 100, 100, ShapeObject.ShapeType.LINE); - drawingCanvas.addObject(line); + SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem(); + if (currentPage != null) { + AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), line); + commandHistory.execute(command); + drawingCanvas.redraw(); + } else { + drawingCanvas.addObject(line); + } } /** @@ -239,7 +264,14 @@ public class Controller implements Initializable { return; } ShapeObject rect = new ShapeObject(50, 50, 100, 60, ShapeObject.ShapeType.RECTANGLE); - drawingCanvas.addObject(rect); + SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem(); + if (currentPage != null) { + AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), rect); + commandHistory.execute(command); + drawingCanvas.redraw(); + } else { + drawingCanvas.addObject(rect); + } } /** @@ -252,7 +284,14 @@ public class Controller implements Initializable { return; } ShapeObject circle = new ShapeObject(50, 50, 100, 100, ShapeObject.ShapeType.CIRCLE); - drawingCanvas.addObject(circle); + SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem(); + if (currentPage != null) { + AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), circle); + commandHistory.execute(command); + drawingCanvas.redraw(); + } else { + drawingCanvas.addObject(circle); + } } /** @@ -265,7 +304,14 @@ public class Controller implements Initializable { return; } ShapeObject ellipse = new ShapeObject(50, 50, 150, 80, ShapeObject.ShapeType.ELLIPSE); - drawingCanvas.addObject(ellipse); + SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem(); + if (currentPage != null) { + AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), ellipse); + commandHistory.execute(command); + drawingCanvas.redraw(); + } else { + drawingCanvas.addObject(ellipse); + } } /** @@ -290,7 +336,14 @@ public class Controller implements Initializable { if (file != null) { ImageObject imgObj = new ImageObject(50, 50, 200, 150, file.getAbsolutePath()); - drawingCanvas.addObject(imgObj); + SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem(); + if (currentPage != null) { + AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), imgObj); + commandHistory.execute(command); + drawingCanvas.redraw(); + } else { + drawingCanvas.addObject(imgObj); + } } } @@ -550,6 +603,48 @@ public class Controller implements Initializable { presentationWindow.show(); } + /** + * 撤销操作 + */ + @FXML + public void onUndo(ActionEvent actionEvent) { + commandHistory.undo(); + if (drawingCanvas != null) { + drawingCanvas.redraw(); + } + } + + /** + * 重做操作 + */ + @FXML + public void onRedo(ActionEvent actionEvent) { + commandHistory.redo(); + if (drawingCanvas != null) { + drawingCanvas.redraw(); + } + } + + /** + * 更新撤销和重做按钮的状态 + */ + private void updateUndoRedoButtons() { + // 确保菜单项不为null + if (undoMenuItem != null) { + undoMenuItem.setDisable(!commandHistory.canUndo()); + } + if (redoMenuItem != null) { + redoMenuItem.setDisable(!commandHistory.canRedo()); + } + } + + /** + * 获取命令历史 + */ + public CommandHistory getCommandHistory() { + return commandHistory; + } + /** * 显示警告对话框 */ diff --git a/src/main/java/dev/bytevibe/hyperpoint/DeleteObjectCommand.java b/src/main/java/dev/bytevibe/hyperpoint/DeleteObjectCommand.java new file mode 100644 index 0000000..d2b9934 --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/DeleteObjectCommand.java @@ -0,0 +1,27 @@ +package dev.bytevibe.hyperpoint; + +/** + * 删除对象命令 + */ +public class DeleteObjectCommand implements Command { + private PageContent pageContent; + private DrawableObject object; + private int originalIndex; + + public DeleteObjectCommand(PageContent pageContent, DrawableObject object) { + this.pageContent = pageContent; + this.object = object; + this.originalIndex = pageContent.getObjectIndex(object); + } + + @Override + public void execute() { + pageContent.removeObject(object); + } + + @Override + public void undo() { + pageContent.addObjectAt(originalIndex, object); + } +} + diff --git a/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java b/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java index 06fc0ce..d58c311 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java +++ b/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java @@ -28,6 +28,7 @@ public class DrawingCanvas extends Pane { private DrawableObject selectedObject; private double lastX, lastY; private Runnable onSelectionChanged; + private CommandHistory commandHistory; // 缩放点有关的属性 private ResizePoint resizePoint = ResizePoint.NONE; @@ -241,6 +242,13 @@ public class DrawingCanvas extends Pane { this.onSelectionChanged = callback; } + /** + * 设置命令历史 + */ + public void setCommandHistory(CommandHistory commandHistory) { + this.commandHistory = commandHistory; + } + /** * 重新绘制画布 */ @@ -409,4 +417,3 @@ public class DrawingCanvas extends Pane { redraw(); } } - diff --git a/src/main/java/dev/bytevibe/hyperpoint/ModifyObjectCommand.java b/src/main/java/dev/bytevibe/hyperpoint/ModifyObjectCommand.java new file mode 100644 index 0000000..a6e77c2 --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/ModifyObjectCommand.java @@ -0,0 +1,41 @@ +package dev.bytevibe.hyperpoint; + +/** + * 修改对象命令 + */ +public class ModifyObjectCommand implements Command { + private DrawableObject object; + private double oldX, oldY, oldWidth, oldHeight; + private double newX, newY, newWidth, newHeight; + + public ModifyObjectCommand(DrawableObject object, + double oldX, double oldY, double oldWidth, double oldHeight, + double newX, double newY, double newWidth, double newHeight) { + this.object = object; + this.oldX = oldX; + this.oldY = oldY; + this.oldWidth = oldWidth; + this.oldHeight = oldHeight; + this.newX = newX; + this.newY = newY; + this.newWidth = newWidth; + this.newHeight = newHeight; + } + + @Override + public void execute() { + object.setX(newX); + object.setY(newY); + object.setWidth(newWidth); + object.setHeight(newHeight); + } + + @Override + public void undo() { + object.setX(oldX); + object.setY(oldY); + object.setWidth(oldWidth); + object.setHeight(oldHeight); + } +} + diff --git a/src/main/java/dev/bytevibe/hyperpoint/PageContent.java b/src/main/java/dev/bytevibe/hyperpoint/PageContent.java index 015d64a..933b3cd 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/PageContent.java +++ b/src/main/java/dev/bytevibe/hyperpoint/PageContent.java @@ -61,5 +61,20 @@ public class PageContent implements Serializable { public void clear() { drawableObjects.clear(); } -} + /** + * 获取对象在列表中的索引 + */ + public int getObjectIndex(DrawableObject object) { + return drawableObjects.indexOf(object); + } + + /** + * 在指定索引处添加对象 + */ + public void addObjectAt(int index, DrawableObject object) { + if (object != null && index >= 0 && index <= drawableObjects.size()) { + drawableObjects.add(index, object); + } + } +} diff --git a/src/main/resources/dev/bytevibe/hyperpoint/main.fxml b/src/main/resources/dev/bytevibe/hyperpoint/main.fxml index d1cb44c..0fbbc08 100644 --- a/src/main/resources/dev/bytevibe/hyperpoint/main.fxml +++ b/src/main/resources/dev/bytevibe/hyperpoint/main.fxml @@ -26,6 +26,14 @@ + + + + + + + +