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 @@
+
+
+
+
+
+
+
+