diff --git a/src/main/java/dev/bytevibe/hyperpoint/Controller.java b/src/main/java/dev/bytevibe/hyperpoint/Controller.java index e650f6a..2e4dffe 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/Controller.java +++ b/src/main/java/dev/bytevibe/hyperpoint/Controller.java @@ -1,5 +1,7 @@ package dev.bytevibe.hyperpoint; +import dev.bytevibe.hyperpoint.Utils.MyAlert; +import dev.bytevibe.hyperpoint.Utils.MyTextInputDialog; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; @@ -15,7 +17,7 @@ import java.util.ResourceBundle; public class Controller implements Initializable { @FXML - private Button openSlideButton; + private Button newSlideButton; @FXML private Button newPageButton; @FXML @@ -71,12 +73,12 @@ public class Controller implements Initializable { } /** - * 打开幻灯片按钮的事件处理 + * 新建幻灯片按钮的事件处理 */ @FXML - public void onOpenSlide(ActionEvent actionEvent) { - TextInputDialog dialog = new TextInputDialog("我的幻灯片"); - dialog.setTitle("打开/创建幻灯片"); + public void onNewSlide(ActionEvent actionEvent) { + MyTextInputDialog dialog = new MyTextInputDialog("我的幻灯片"); + dialog.setTitle("创建幻灯片"); dialog.setHeaderText("请输入幻灯片名称"); dialog.setContentText("幻灯片名称:"); @@ -86,10 +88,14 @@ public class Controller implements Initializable { currentSlide = new Slide(slideName); loadSlidePages(); - Alert alert = new Alert(Alert.AlertType.INFORMATION); + MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION); alert.setTitle("成功"); - alert.setHeaderText("幻灯片已打开"); - alert.setContentText("幻灯片 \"" + slideName + "\" 已打开,共包含 " + currentSlide.getPages().size() + " 个页面。"); + alert.setHeaderText("幻灯片已创建"); + alert.setContentText("幻灯片 \"" + slideName + "\" 已创建。"); + stage = (Stage) newSlideButton.getScene().getWindow(); + if (stage != null) { + stage.setTitle("Hyperpoint - " + slideName); + } alert.showAndWait(); } } @@ -155,7 +161,7 @@ public class Controller implements Initializable { return; } - TextInputDialog dialog = new TextInputDialog("页面 " + (currentSlide.getPages().size() + 1)); + MyTextInputDialog dialog = new MyTextInputDialog("页面 " + (currentSlide.getPages().size() + 1)); dialog.setTitle("新建页面"); dialog.setHeaderText("请输入页面名称"); dialog.setContentText("页面名称:"); @@ -169,7 +175,7 @@ public class Controller implements Initializable { pageListView.refresh(); pageListView.getSelectionModel().selectLast(); - Alert alert = new Alert(Alert.AlertType.INFORMATION); + MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION); alert.setTitle("成功"); alert.setHeaderText("页面已创建"); alert.setContentText("新页面 \"" + pageName + "\" 已添加。"); @@ -327,15 +333,12 @@ public class Controller implements Initializable { */ @FXML public void logout(ActionEvent actionEvent) { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + MyAlert alert = new MyAlert(Alert.AlertType.CONFIRMATION); alert.setTitle("退出"); alert.setHeaderText("您确定要退出吗?"); alert.setContentText("点击确定退出,点击取消返回。"); - ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE); - ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE); - alert.getButtonTypes().setAll(confirm, cancel); - if (alert.showAndWait().orElse(null) == confirm) { + if (alert.showAndWait().orElse(null) == MyAlert.isOK()) { stage = (Stage) logout.getScene().getWindow(); stage.close(); } diff --git a/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java b/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java index 27382a6..14302bf 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java +++ b/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java @@ -14,12 +14,22 @@ import javafx.scene.text.FontWeight; * 绘图Canvas组件,用于渲染和交互所有可绘制对象 */ public class DrawingCanvas extends Pane { + // 缩放点的枚举 + enum ResizePoint { + TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, NONE + } + private Canvas canvas; private PageContent pageContent; private DrawableObject selectedObject; private double lastX, lastY; private Runnable onSelectionChanged; + // 缩放点有关的属性 + private ResizePoint resizePoint = ResizePoint.NONE; + // 缩放点大小 + private static final double HANDLE_SIZE = 8; + public DrawingCanvas(PageContent pageContent) { this.pageContent = pageContent; this.canvas = new Canvas(); @@ -54,10 +64,21 @@ public class DrawingCanvas extends Pane { lastX = event.getX(); lastY = event.getY(); + // 如果已经有选中对象,先检查是否点击在调整点上 + if (selectedObject != null) { + resizePoint = getResizePointAt(lastX, lastY, selectedObject); + if (resizePoint != ResizePoint.NONE) { + // 点击在调整点上,进入缩放模式 + return; + } + } + + // 重置缩放模式 + resizePoint = ResizePoint.NONE; + // 查找被点击的对象 DrawableObject clicked = pageContent.findObjectAt(lastX, lastY); - // 如果点击在已选中对象上,保持选中状态 if (clicked == null) { setSelectedObject(null); } else { @@ -67,6 +88,40 @@ public class DrawingCanvas extends Pane { redraw(); } + /** + * 获取点击位置对应的调整点 + */ + private ResizePoint getResizePointAt(double x, double y, DrawableObject obj) { + double handleSize = HANDLE_SIZE; + double objX = obj.getX(); + double objY = obj.getY(); + double objW = obj.getWidth(); + double objH = obj.getHeight(); + + // 检查左上角 + if (x >= objX - handleSize && x <= objX + handleSize && + y >= objY - handleSize && y <= objY + handleSize) { + return ResizePoint.TOP_LEFT; + } + // 检查右上角 + if (x >= objX + objW - handleSize && x <= objX + objW + handleSize && + y >= objY - handleSize && y <= objY + handleSize) { + return ResizePoint.TOP_RIGHT; + } + // 检查左下角 + if (x >= objX - handleSize && x <= objX + handleSize && + y >= objY + objH - handleSize && y <= objY + objH + handleSize) { + return ResizePoint.BOTTOM_LEFT; + } + // 检查右下角 + if (x >= objX + objW - handleSize && x <= objX + objW + handleSize && + y >= objY + objH - handleSize && y <= objY + objH + handleSize) { + return ResizePoint.BOTTOM_RIGHT; + } + + return ResizePoint.NONE; + } + /** * 鼠标拖动事件处理 */ @@ -75,9 +130,14 @@ public class DrawingCanvas extends Pane { double dx = event.getX() - lastX; double dy = event.getY() - lastY; - // 更新选中对象的位置 - selectedObject.setX(selectedObject.getX() + dx); - selectedObject.setY(selectedObject.getY() + dy); + // 如果正在缩放 + if (resizePoint != ResizePoint.NONE) { + resizeObject(selectedObject, dx, dy, resizePoint); + } else { + // 移动对象 + selectedObject.setX(selectedObject.getX() + dx); + selectedObject.setY(selectedObject.getY() + dy); + } lastX = event.getX(); lastY = event.getY(); @@ -86,13 +146,58 @@ public class DrawingCanvas extends Pane { } } + /** + * 缩放对象 + */ + private void resizeObject(DrawableObject obj, double dx, double dy, ResizePoint point) { + // 最小尺寸限制 + final double MIN_SIZE = 20; + + switch (point) { + case TOP_LEFT: + // 从左上角缩放:x和y增加,width和height减少 + if (obj.getWidth() - dx >= MIN_SIZE && obj.getHeight() - dy >= MIN_SIZE) { + obj.setX(obj.getX() + dx); + obj.setY(obj.getY() + dy); + obj.setWidth(obj.getWidth() - dx); + obj.setHeight(obj.getHeight() - dy); + } + break; + case TOP_RIGHT: + // 从右上角缩放:y增加,width增加,height减少 + if (obj.getWidth() + dx >= MIN_SIZE && obj.getHeight() - dy >= MIN_SIZE) { + obj.setY(obj.getY() + dy); + obj.setWidth(obj.getWidth() + dx); + obj.setHeight(obj.getHeight() - dy); + } + break; + case BOTTOM_LEFT: + // 从左下角缩放:x增加,width减少,height增加 + if (obj.getWidth() - dx >= MIN_SIZE && obj.getHeight() + dy >= MIN_SIZE) { + obj.setX(obj.getX() + dx); + obj.setWidth(obj.getWidth() - dx); + obj.setHeight(obj.getHeight() + dy); + } + break; + case BOTTOM_RIGHT: + // 从右下角缩放:width和height增加 + if (obj.getWidth() + dx >= MIN_SIZE && obj.getHeight() + dy >= MIN_SIZE) { + obj.setWidth(obj.getWidth() + dx); + obj.setHeight(obj.getHeight() + dy); + } + break; + default: + break; + } + } /** * 鼠标释放事件处理 */ private void handleMouseReleased(MouseEvent event) { - // 可以在这里添加其他逻辑,如取消选中等 + // 释放鼠标时,重置缩放模式 + resizePoint = ResizePoint.NONE; } /** diff --git a/src/main/java/dev/bytevibe/hyperpoint/Main.java b/src/main/java/dev/bytevibe/hyperpoint/Main.java index 5688f1c..38e53a8 100644 --- a/src/main/java/dev/bytevibe/hyperpoint/Main.java +++ b/src/main/java/dev/bytevibe/hyperpoint/Main.java @@ -2,6 +2,7 @@ package dev.bytevibe.hyperpoint; +import dev.bytevibe.hyperpoint.Utils.MyAlert; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -9,6 +10,7 @@ import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; +import javafx.scene.image.Image; import javafx.stage.Stage; public class Main extends Application { @@ -18,6 +20,10 @@ public class Main extends Application { Parent root = FXMLLoader.load(getClass().getResource("main.fxml")); Scene scene = new Scene(root, 1200, 600); stage.setScene(scene); + + Image icon = new Image(getClass().getResourceAsStream("icon.png")); + stage.setTitle("Hyperpoint"); + stage.getIcons().add(icon); stage.show(); stage.setOnCloseRequest(event -> {this.logout(stage);}); @@ -29,15 +35,12 @@ public class Main extends Application { // 窗口退出键对应的action public void logout(Stage stage) { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + MyAlert alert = new MyAlert(Alert.AlertType.CONFIRMATION); alert.setTitle("退出登录"); alert.setHeaderText("您确定要退出登录吗?"); alert.setContentText("点击确定退出登录,点击取消返回。"); - ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE); - ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE); - alert.getButtonTypes().setAll(confirm, cancel); - if (alert.showAndWait().orElse(null) == confirm) { + if (alert.showAndWait().orElse(null) == MyAlert.isOK()) { stage.close(); } } diff --git a/src/main/java/dev/bytevibe/hyperpoint/Utils/MyAlert.java b/src/main/java/dev/bytevibe/hyperpoint/Utils/MyAlert.java new file mode 100644 index 0000000..ce965eb --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/Utils/MyAlert.java @@ -0,0 +1,24 @@ +package dev.bytevibe.hyperpoint.Utils; + +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; + +// 提示框,按钮设置为中文 +public class MyAlert extends Alert { + private static ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE); + private static ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE); + + public MyAlert(Alert.AlertType alertType) { + super(alertType); + if (alertType == Alert.AlertType.CONFIRMATION) { + getDialogPane().getButtonTypes().setAll(confirm, cancel); + } else if (alertType == Alert.AlertType.INFORMATION || alertType == Alert.AlertType.WARNING || alertType == Alert.AlertType.ERROR) { + getDialogPane().getButtonTypes().setAll(confirm); + } + } + + public static ButtonType isOK() { + return confirm; + } +} \ No newline at end of file diff --git a/src/main/java/dev/bytevibe/hyperpoint/Utils/MyTextInputDialog.java b/src/main/java/dev/bytevibe/hyperpoint/Utils/MyTextInputDialog.java new file mode 100644 index 0000000..732fd67 --- /dev/null +++ b/src/main/java/dev/bytevibe/hyperpoint/Utils/MyTextInputDialog.java @@ -0,0 +1,20 @@ +package dev.bytevibe.hyperpoint.Utils; + +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TextInputDialog; + +// 提示输入框,按钮设置为中文 +public class MyTextInputDialog extends TextInputDialog { + private static ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE); + private static ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE); + + public MyTextInputDialog(String defaultValue) { + super(defaultValue); + getDialogPane().getButtonTypes().setAll(confirm, cancel); + } + + public static ButtonType isOK() { + return confirm; + } +} \ No newline at end of file diff --git a/src/main/resources/dev/bytevibe/hyperpoint/main.fxml b/src/main/resources/dev/bytevibe/hyperpoint/main.fxml index 1ce55e7..505b505 100644 --- a/src/main/resources/dev/bytevibe/hyperpoint/main.fxml +++ b/src/main/resources/dev/bytevibe/hyperpoint/main.fxml @@ -14,7 +14,7 @@ -