优化撤销重做:组件的修改和删除
This commit is contained in:
@@ -136,6 +136,7 @@ public class Controller implements Initializable {
|
||||
// 创建新的Canvas
|
||||
PageContent pageContent = page.getPageContent();
|
||||
drawingCanvas = new DrawingCanvas(pageContent);
|
||||
drawingCanvas.setCurrentPage(page); // 设置当前页面
|
||||
drawingCanvas.setCommandHistory(commandHistory); // 设置命令历史
|
||||
drawingCanvasContainer.getChildren().add(drawingCanvas);
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ public class DrawingCanvas extends Pane {
|
||||
private double lastX, lastY;
|
||||
private Runnable onSelectionChanged;
|
||||
private CommandHistory commandHistory;
|
||||
private double startX, startY, startWidth, startHeight;
|
||||
private SlidePage currentPage;
|
||||
|
||||
// 缩放点有关的属性
|
||||
private ResizePoint resizePoint = ResizePoint.NONE;
|
||||
@@ -65,12 +67,22 @@ public class DrawingCanvas extends Pane {
|
||||
|
||||
// 如果已经有选中对象,先检查是否点击在调整点上
|
||||
if (selectedObject != null) {
|
||||
resizePoint = getResizePointAt(lastX, lastY, selectedObject);
|
||||
if (resizePoint != ResizePoint.NONE) {
|
||||
// 点击在调整点上,进入缩放模式
|
||||
return;
|
||||
}
|
||||
resizePoint = getResizePointAt(lastX, lastY, selectedObject);
|
||||
if (resizePoint != ResizePoint.NONE) {
|
||||
// 记录初始状态用于创建命令
|
||||
startX = selectedObject.getX();
|
||||
startY = selectedObject.getY();
|
||||
startWidth = selectedObject.getWidth();
|
||||
startHeight = selectedObject.getHeight();
|
||||
return;
|
||||
} else if (isPointInObject(lastX, lastY, selectedObject)) {
|
||||
// 记录移动前的位置
|
||||
startX = selectedObject.getX();
|
||||
startY = selectedObject.getY();
|
||||
startWidth = selectedObject.getWidth();
|
||||
startHeight = selectedObject.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
// 重置缩放模式
|
||||
resizePoint = ResizePoint.NONE;
|
||||
@@ -87,6 +99,14 @@ public class DrawingCanvas extends Pane {
|
||||
redraw();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查判断点是否在对象内
|
||||
*/
|
||||
private boolean isPointInObject(double x, double y, DrawableObject obj) {
|
||||
return x >= obj.getX() && x <= obj.getX() + obj.getWidth() &&
|
||||
y >= obj.getY() && y <= obj.getY() + obj.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取点击位置对应的调整点
|
||||
*/
|
||||
@@ -195,9 +215,23 @@ public class DrawingCanvas extends Pane {
|
||||
* 鼠标释放事件处理
|
||||
*/
|
||||
private void handleMouseReleased(MouseEvent event) {
|
||||
// 释放鼠标时,重置缩放模式
|
||||
resizePoint = ResizePoint.NONE;
|
||||
// 如果有选中对象且位置或尺寸发生了变化,创建命令
|
||||
if (selectedObject != null && commandHistory != null) {
|
||||
if (selectedObject.getX() != startX || selectedObject.getY() != startY ||
|
||||
selectedObject.getWidth() != startWidth || selectedObject.getHeight() != startHeight) {
|
||||
|
||||
Command command = new ModifyObjectCommand(
|
||||
selectedObject,
|
||||
startX, startY, startWidth, startHeight,
|
||||
selectedObject.getX(), selectedObject.getY(),
|
||||
selectedObject.getWidth(), selectedObject.getHeight()
|
||||
);
|
||||
commandHistory.execute(command);
|
||||
}
|
||||
}
|
||||
// 释放鼠标时,重置缩放模式
|
||||
resizePoint = ResizePoint.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加可绘制对象
|
||||
@@ -249,6 +283,27 @@ public class DrawingCanvas extends Pane {
|
||||
this.commandHistory = commandHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取命令历史
|
||||
*/
|
||||
public CommandHistory getCommandHistory() {
|
||||
return commandHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前页面
|
||||
*/
|
||||
public void setCurrentPage(SlidePage page) {
|
||||
this.currentPage = page;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前页面
|
||||
*/
|
||||
public SlidePage getCurrentPage() {
|
||||
return currentPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新绘制画布
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package dev.bytevibe.hyperpoint;
|
||||
|
||||
/**
|
||||
* 修改对象属性命令(除位置和尺寸外的其他属性)
|
||||
*/
|
||||
public class ModifyObjectPropertyCommand implements Command {
|
||||
private DrawableObject object;
|
||||
private String oldText;
|
||||
private String newText;
|
||||
private String oldFontFamily;
|
||||
private String newFontFamily;
|
||||
private double oldFontSize;
|
||||
private double newFontSize;
|
||||
private String oldFontStyle;
|
||||
private String newFontStyle;
|
||||
private String oldTextColor;
|
||||
private String newTextColor;
|
||||
private String oldFillColor;
|
||||
private String newFillColor;
|
||||
private String oldStrokeColor;
|
||||
private String newStrokeColor;
|
||||
private double oldStrokeWidth;
|
||||
private double newStrokeWidth;
|
||||
private double oldRotation;
|
||||
private double newRotation;
|
||||
private PropertyType propertyType;
|
||||
|
||||
// 定义属性类型枚举
|
||||
public enum PropertyType {
|
||||
TEXT, FONT, COLOR, ROTATION, SHAPE_STYLE
|
||||
}
|
||||
|
||||
// 文本内容修改构造函数
|
||||
public ModifyObjectPropertyCommand(TextObject object, String oldText, String newText, int nothing) {
|
||||
this.object = object;
|
||||
this.oldText = oldText;
|
||||
this.newText = newText;
|
||||
this.propertyType = PropertyType.TEXT;
|
||||
}
|
||||
|
||||
// 字体样式修改构造函数
|
||||
public ModifyObjectPropertyCommand(TextObject object,
|
||||
String oldFontFamily, String newFontFamily,
|
||||
double oldFontSize, double newFontSize,
|
||||
String oldFontStyle, String newFontStyle) {
|
||||
this.object = object;
|
||||
this.oldFontFamily = oldFontFamily;
|
||||
this.newFontFamily = newFontFamily;
|
||||
this.oldFontSize = oldFontSize;
|
||||
this.newFontSize = newFontSize;
|
||||
this.oldFontStyle = oldFontStyle;
|
||||
this.newFontStyle = newFontStyle;
|
||||
this.propertyType = PropertyType.FONT;
|
||||
}
|
||||
|
||||
// 文本颜色修改构造函数
|
||||
public ModifyObjectPropertyCommand(TextObject object, String oldTextColor, String newTextColor) {
|
||||
this.object = object;
|
||||
this.oldTextColor = oldTextColor;
|
||||
this.newTextColor = newTextColor;
|
||||
this.propertyType = PropertyType.COLOR;
|
||||
}
|
||||
|
||||
// 形状样式修改构造函数
|
||||
public ModifyObjectPropertyCommand(ShapeObject object,
|
||||
String oldFillColor, String newFillColor,
|
||||
String oldStrokeColor, String newStrokeColor,
|
||||
double oldStrokeWidth, double newStrokeWidth) {
|
||||
this.object = object;
|
||||
this.oldFillColor = oldFillColor;
|
||||
this.newFillColor = newFillColor;
|
||||
this.oldStrokeColor = oldStrokeColor;
|
||||
this.newStrokeColor = newStrokeColor;
|
||||
this.oldStrokeWidth = oldStrokeWidth;
|
||||
this.newStrokeWidth = newStrokeWidth;
|
||||
this.propertyType = PropertyType.SHAPE_STYLE;
|
||||
}
|
||||
|
||||
// 旋转属性修改构造函数
|
||||
public ModifyObjectPropertyCommand(DrawableObject object, double oldRotation, double newRotation) {
|
||||
this.object = object;
|
||||
this.oldRotation = oldRotation;
|
||||
this.newRotation = newRotation;
|
||||
this.propertyType = PropertyType.ROTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
applyChanges(newText, newFontFamily, newFontSize, newFontStyle,
|
||||
newTextColor, newFillColor, newStrokeColor, newStrokeWidth, newRotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
applyChanges(oldText, oldFontFamily, oldFontSize, oldFontStyle,
|
||||
oldTextColor, oldFillColor, oldStrokeColor, oldStrokeWidth, oldRotation);
|
||||
}
|
||||
|
||||
private void applyChanges(String text, String fontFamily, double fontSize, String fontStyle,
|
||||
String textColor, String fillColor, String strokeColor,
|
||||
double strokeWidth, double rotation) {
|
||||
// 应用旋转(所有对象都有旋转属性)
|
||||
object.setRotation(rotation);
|
||||
|
||||
// 根据对象类型应用其他属性
|
||||
if (object instanceof TextObject) {
|
||||
TextObject textObj = (TextObject) object;
|
||||
if (propertyType == PropertyType.TEXT) {
|
||||
textObj.setText(text);
|
||||
} else if (propertyType == PropertyType.FONT) {
|
||||
textObj.setFontFamily(fontFamily);
|
||||
textObj.setFontSize(fontSize);
|
||||
textObj.setFontStyle(fontStyle);
|
||||
} else if (propertyType == PropertyType.COLOR) {
|
||||
textObj.setTextColor(textColor);
|
||||
}
|
||||
} else if (object instanceof ShapeObject && propertyType == PropertyType.SHAPE_STYLE) {
|
||||
ShapeObject shapeObj = (ShapeObject) object;
|
||||
shapeObj.setFillColor(fillColor);
|
||||
shapeObj.setStrokeColor(strokeColor);
|
||||
shapeObj.setStrokeWidth(strokeWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,17 +175,6 @@ public class PropertyPanel extends VBox implements Initializable {
|
||||
textContentField.setOnKeyReleased(e -> updateTextContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新旋转
|
||||
*/
|
||||
private void updateRotation() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected != null) {
|
||||
selected.setRotation(rotationSlider.getValue());
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示文本控件
|
||||
*/
|
||||
@@ -256,40 +245,68 @@ public class PropertyPanel extends VBox implements Initializable {
|
||||
* 更新文本内容
|
||||
*/
|
||||
private void updateTextContent() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof TextObject) {
|
||||
((TextObject) selected).setText(textContentField.getText());
|
||||
canvas.redraw();
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof TextObject) {
|
||||
TextObject textObj = (TextObject) selected;
|
||||
String oldText = textObj.getText();
|
||||
String newText = textContentField.getText();
|
||||
|
||||
if (!oldText.equals(newText) && canvas.getCommandHistory() != null) {
|
||||
Command command = new ModifyObjectPropertyCommand(textObj, oldText, newText, 0);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文本风格
|
||||
*/
|
||||
private void updateTextStyle() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof TextObject) {
|
||||
TextObject textObj = (TextObject) selected;
|
||||
textObj.setFontFamily(fontFamilyCombo.getValue());
|
||||
textObj.setFontSize(fontSizeSpinner.getValue());
|
||||
textObj.setFontStyle(fontStyleCombo.getValue());
|
||||
canvas.redraw();
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof TextObject) {
|
||||
TextObject textObj = (TextObject) selected;
|
||||
String oldFontFamily = textObj.getFontFamily();
|
||||
double oldFontSize = textObj.getFontSize();
|
||||
String oldFontStyle = textObj.getFontStyle();
|
||||
|
||||
String newFontFamily = fontFamilyCombo.getValue();
|
||||
double newFontSize = fontSizeSpinner.getValue();
|
||||
String newFontStyle = fontStyleCombo.getValue();
|
||||
|
||||
if (!oldFontFamily.equals(newFontFamily) || oldFontSize != newFontSize ||
|
||||
!oldFontStyle.equals(newFontStyle) && canvas.getCommandHistory() != null) {
|
||||
|
||||
Command command = new ModifyObjectPropertyCommand(
|
||||
textObj, oldFontFamily, newFontFamily,
|
||||
oldFontSize, newFontSize,
|
||||
oldFontStyle, newFontStyle
|
||||
);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新文本颜色
|
||||
*/
|
||||
private void updateTextColor() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof TextObject) {
|
||||
if (selected instanceof TextObject && canvas.getCommandHistory() != null) {
|
||||
TextObject textObj = (TextObject) selected;
|
||||
String oldColor = textObj.getTextColor();
|
||||
|
||||
Color color = textColorPicker.getValue();
|
||||
String hexColor = String.format("%02X%02X%02X",
|
||||
String newColor = String.format("%02X%02X%02X",
|
||||
(int) (color.getRed() * 255),
|
||||
(int) (color.getGreen() * 255),
|
||||
(int) (color.getBlue() * 255));
|
||||
((TextObject) selected).setTextColor(hexColor);
|
||||
canvas.redraw();
|
||||
|
||||
if (!oldColor.equals(newColor)) {
|
||||
Command command = new ModifyObjectPropertyCommand(textObj, oldColor, newColor);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,14 +315,26 @@ public class PropertyPanel extends VBox implements Initializable {
|
||||
*/
|
||||
private void updateFillColor() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof ShapeObject) {
|
||||
if (selected instanceof ShapeObject && canvas.getCommandHistory() != null) {
|
||||
ShapeObject shapeObj = (ShapeObject) selected;
|
||||
String oldFillColor = shapeObj.getFillColor();
|
||||
|
||||
Color color = fillColorPicker.getValue();
|
||||
String hexColor = String.format("%02X%02X%02X",
|
||||
String newFillColor = String.format("%02X%02X%02X",
|
||||
(int) (color.getRed() * 255),
|
||||
(int) (color.getGreen() * 255),
|
||||
(int) (color.getBlue() * 255));
|
||||
((ShapeObject) selected).setFillColor(hexColor);
|
||||
canvas.redraw();
|
||||
|
||||
if (!oldFillColor.equals(newFillColor)) {
|
||||
Command command = new ModifyObjectPropertyCommand(
|
||||
shapeObj,
|
||||
oldFillColor, newFillColor,
|
||||
shapeObj.getStrokeColor(), shapeObj.getStrokeColor(),
|
||||
shapeObj.getStrokeWidth(), shapeObj.getStrokeWidth()
|
||||
);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,14 +343,26 @@ public class PropertyPanel extends VBox implements Initializable {
|
||||
*/
|
||||
private void updateStrokeColor() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof ShapeObject) {
|
||||
if (selected instanceof ShapeObject && canvas.getCommandHistory() != null) {
|
||||
ShapeObject shapeObj = (ShapeObject) selected;
|
||||
String oldStrokeColor = shapeObj.getStrokeColor();
|
||||
|
||||
Color color = strokeColorPicker.getValue();
|
||||
String hexColor = String.format("%02X%02X%02X",
|
||||
String newStrokeColor = String.format("%02X%02X%02X",
|
||||
(int) (color.getRed() * 255),
|
||||
(int) (color.getGreen() * 255),
|
||||
(int) (color.getBlue() * 255));
|
||||
((ShapeObject) selected).setStrokeColor(hexColor);
|
||||
canvas.redraw();
|
||||
|
||||
if (!oldStrokeColor.equals(newStrokeColor)) {
|
||||
Command command = new ModifyObjectPropertyCommand(
|
||||
shapeObj,
|
||||
shapeObj.getFillColor(), shapeObj.getFillColor(),
|
||||
oldStrokeColor, newStrokeColor,
|
||||
shapeObj.getStrokeWidth(), shapeObj.getStrokeWidth()
|
||||
);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,9 +371,38 @@ public class PropertyPanel extends VBox implements Initializable {
|
||||
*/
|
||||
private void updateStrokeWidth() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected instanceof ShapeObject) {
|
||||
((ShapeObject) selected).setStrokeWidth(strokeWidthSpinner.getValue());
|
||||
canvas.redraw();
|
||||
if (selected instanceof ShapeObject && canvas.getCommandHistory() != null) {
|
||||
ShapeObject shapeObj = (ShapeObject) selected;
|
||||
double oldWidth = shapeObj.getStrokeWidth();
|
||||
double newWidth = strokeWidthSpinner.getValue();
|
||||
|
||||
if (Math.abs(oldWidth - newWidth) > 0.01) {
|
||||
Command command = new ModifyObjectPropertyCommand(
|
||||
shapeObj,
|
||||
shapeObj.getFillColor(), shapeObj.getFillColor(),
|
||||
shapeObj.getStrokeColor(), shapeObj.getStrokeColor(),
|
||||
oldWidth, newWidth
|
||||
);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新旋转
|
||||
*/
|
||||
private void updateRotation() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected != null && canvas.getCommandHistory() != null) {
|
||||
double oldRotation = selected.getRotation();
|
||||
double newRotation = rotationSlider.getValue();
|
||||
|
||||
if (Math.abs(oldRotation - newRotation) > 0.01) {
|
||||
Command command = new ModifyObjectPropertyCommand(selected, oldRotation, newRotation);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,9 +411,15 @@ public class PropertyPanel extends VBox implements Initializable {
|
||||
*/
|
||||
private void deleteSelectedObject() {
|
||||
DrawableObject selected = canvas.getSelectedObject();
|
||||
if (selected != null) {
|
||||
canvas.removeObject(selected);
|
||||
updatePropertyPanel();
|
||||
if (selected != null && canvas.getCommandHistory() != null) {
|
||||
SlidePage currentPage = canvas.getCurrentPage();
|
||||
if (currentPage != null) {
|
||||
Command command = new DeleteObjectCommand(currentPage.getPageContent(), selected);
|
||||
canvas.getCommandHistory().execute(command);
|
||||
|
||||
canvas.setSelectedObject(null);
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user