<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="CopilotDiffPersistence">
    <option name="pendingDiffs">
      <map>
        <entry key="$PROJECT_DIR$/pom.xml">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/pom.xml" />
              <option name="originalContent" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;&#10;         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&#10;         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;&#10;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;&#10;&#10;    &lt;groupId&gt;dev.bytevibe&lt;/groupId&gt;&#10;    &lt;artifactId&gt;hyperpoint&lt;/artifactId&gt;&#10;    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;&#10;    &lt;name&gt;hyperpoint&lt;/name&gt;&#10;&#10;    &lt;properties&gt;&#10;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;&#10;        &lt;junit.version&gt;5.12.1&lt;/junit.version&gt;&#10;        &lt;javafx.version&gt;25.0.1&lt;/javafx.version&gt;&#10;    &lt;/properties&gt;&#10;&#10;    &lt;dependencies&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-controls&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-fxml&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-swing&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;&#10;        &lt;!-- Gson库，用于JSON序列化 --&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;com.google.code.gson&lt;/groupId&gt;&#10;            &lt;artifactId&gt;gson&lt;/artifactId&gt;&#10;            &lt;version&gt;2.10.1&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;&#10;        &lt;!-- iText库，用于PDF生成 --&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;com.itextpdf&lt;/groupId&gt;&#10;            &lt;artifactId&gt;itextpdf&lt;/artifactId&gt;&#10;            &lt;version&gt;5.5.13.3&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt;&#10;            &lt;artifactId&gt;junit-jupiter-api&lt;/artifactId&gt;&#10;            &lt;version&gt;${junit.version}&lt;/version&gt;&#10;            &lt;scope&gt;test&lt;/scope&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt;&#10;            &lt;artifactId&gt;junit-jupiter-engine&lt;/artifactId&gt;&#10;            &lt;version&gt;${junit.version}&lt;/version&gt;&#10;            &lt;scope&gt;test&lt;/scope&gt;&#10;        &lt;/dependency&gt;&#10;    &lt;/dependencies&gt;&#10;&#10;&#10;&#10;    &lt;build&gt;&#10;        &lt;plugins&gt;&#10;            &lt;plugin&gt;&#10;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&#10;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;&#10;                &lt;version&gt;3.13.0&lt;/version&gt;&#10;                &lt;configuration&gt;&#10;                    &lt;source&gt;25&lt;/source&gt;&#10;                    &lt;target&gt;25&lt;/target&gt;&#10;                &lt;/configuration&gt;&#10;            &lt;/plugin&gt;&#10;            &lt;plugin&gt;&#10;                &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;                &lt;artifactId&gt;javafx-maven-plugin&lt;/artifactId&gt;&#10;                &lt;version&gt;0.0.8&lt;/version&gt;&#10;                &lt;executions&gt;&#10;                    &lt;execution&gt;&#10;                        &lt;!-- Default configuration for running with: mvn clean javafx:run --&gt;&#10;                        &lt;id&gt;default-cli&lt;/id&gt;&#10;                        &lt;configuration&gt;&#10;                            &lt;mainClass&gt;dev.bytevibe.hyperpoint/dev.bytevibe.hyperpoint.Main&lt;/mainClass&gt;&#10;                            &lt;launcher&gt;app&lt;/launcher&gt;&#10;                            &lt;jlinkZipName&gt;app&lt;/jlinkZipName&gt;&#10;                            &lt;jlinkImageName&gt;app&lt;/jlinkImageName&gt;&#10;                            &lt;noManPages&gt;true&lt;/noManPages&gt;&#10;                            &lt;stripDebug&gt;true&lt;/stripDebug&gt;&#10;                            &lt;noHeaderFiles&gt;true&lt;/noHeaderFiles&gt;&#10;                        &lt;/configuration&gt;&#10;                    &lt;/execution&gt;&#10;                &lt;/executions&gt;&#10;            &lt;/plugin&gt;&#10;        &lt;/plugins&gt;&#10;    &lt;/build&gt;&#10;&lt;/project&gt;" />
              <option name="updatedContent" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;&#10;         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&#10;         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;&#10;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;&#10;&#10;    &lt;groupId&gt;dev.bytevibe&lt;/groupId&gt;&#10;    &lt;artifactId&gt;hyperpoint&lt;/artifactId&gt;&#10;    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;&#10;    &lt;name&gt;hyperpoint&lt;/name&gt;&#10;&#10;    &lt;properties&gt;&#10;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;&#10;        &lt;junit.version&gt;5.12.1&lt;/junit.version&gt;&#10;        &lt;javafx.version&gt;25.0.1&lt;/javafx.version&gt;&#10;    &lt;/properties&gt;&#10;&#10;    &lt;dependencies&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-controls&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-fxml&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-graphics&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;            &lt;artifactId&gt;javafx-swing&lt;/artifactId&gt;&#10;            &lt;version&gt;${javafx.version}&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;&#10;        &lt;!-- Gson库，用于JSON序列化 --&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;com.google.code.gson&lt;/groupId&gt;&#10;            &lt;artifactId&gt;gson&lt;/artifactId&gt;&#10;            &lt;version&gt;2.10.1&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;&#10;        &lt;!-- iText库，用于PDF生成 --&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;com.itextpdf&lt;/groupId&gt;&#10;            &lt;artifactId&gt;itextpdf&lt;/artifactId&gt;&#10;            &lt;version&gt;5.5.13.3&lt;/version&gt;&#10;        &lt;/dependency&gt;&#10;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt;&#10;            &lt;artifactId&gt;junit-jupiter-api&lt;/artifactId&gt;&#10;            &lt;version&gt;${junit.version}&lt;/version&gt;&#10;            &lt;scope&gt;test&lt;/scope&gt;&#10;        &lt;/dependency&gt;&#10;        &lt;dependency&gt;&#10;            &lt;groupId&gt;org.junit.jupiter&lt;/groupId&gt;&#10;            &lt;artifactId&gt;junit-jupiter-engine&lt;/artifactId&gt;&#10;            &lt;version&gt;${junit.version}&lt;/version&gt;&#10;            &lt;scope&gt;test&lt;/scope&gt;&#10;        &lt;/dependency&gt;&#10;    &lt;/dependencies&gt;&#10;&#10;&#10;&#10;    &lt;build&gt;&#10;        &lt;plugins&gt;&#10;            &lt;plugin&gt;&#10;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&#10;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;&#10;                &lt;version&gt;3.13.0&lt;/version&gt;&#10;                &lt;configuration&gt;&#10;                    &lt;source&gt;25&lt;/source&gt;&#10;                    &lt;target&gt;25&lt;/target&gt;&#10;                &lt;/configuration&gt;&#10;            &lt;/plugin&gt;&#10;            &lt;plugin&gt;&#10;                &lt;groupId&gt;org.openjfx&lt;/groupId&gt;&#10;                &lt;artifactId&gt;javafx-maven-plugin&lt;/artifactId&gt;&#10;                &lt;version&gt;0.0.8&lt;/version&gt;&#10;                &lt;executions&gt;&#10;                    &lt;execution&gt;&#10;                        &lt;!-- Default configuration for running with: mvn clean javafx:run --&gt;&#10;                        &lt;id&gt;default-cli&lt;/id&gt;&#10;                        &lt;configuration&gt;&#10;                            &lt;mainClass&gt;dev.bytevibe.hyperpoint/dev.bytevibe.hyperpoint.Main&lt;/mainClass&gt;&#10;                            &lt;launcher&gt;app&lt;/launcher&gt;&#10;                            &lt;jlinkZipName&gt;app&lt;/jlinkZipName&gt;&#10;                            &lt;jlinkImageName&gt;app&lt;/jlinkImageName&gt;&#10;                            &lt;noManPages&gt;true&lt;/noManPages&gt;&#10;                            &lt;stripDebug&gt;true&lt;/stripDebug&gt;&#10;                            &lt;noHeaderFiles&gt;true&lt;/noHeaderFiles&gt;&#10;                        &lt;/configuration&gt;&#10;                    &lt;/execution&gt;&#10;                &lt;/executions&gt;&#10;            &lt;/plugin&gt;&#10;        &lt;/plugins&gt;&#10;    &lt;/build&gt;&#10;&lt;/project&gt;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/AddObjectCommand.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/AddObjectCommand.java" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;/**&#10; * 添加对象命令&#10; */&#10;public class AddObjectCommand implements Command {&#10;    private PageContent pageContent;&#10;    private DrawableObject object;&#10;&#10;    public AddObjectCommand(PageContent pageContent, DrawableObject object) {&#10;        this.pageContent = pageContent;&#10;        this.object = object;&#10;    }&#10;&#10;    @Override&#10;    public void execute() {&#10;        pageContent.addObject(object);&#10;    }&#10;&#10;    @Override&#10;    public void undo() {&#10;        pageContent.removeObject(object);&#10;    }&#10;}&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/Command.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/Command.java" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;/**&#10; * 命令接口，用于撤销和重做功能&#10; */&#10;public interface Command {&#10;    /**&#10;     * 执行命令&#10;     */&#10;    void execute();&#10;&#10;    /**&#10;     * 撤销命令&#10;     */&#10;    void undo();&#10;}&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/CommandHistory.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/CommandHistory.java" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import java.util.Stack;&#10;&#10;/**&#10; * 命令历史管理器，支持撤销和重做&#10; */&#10;public class CommandHistory {&#10;    private Stack&lt;Command&gt; undoStack;&#10;    private Stack&lt;Command&gt; redoStack;&#10;    private Runnable onHistoryChanged;&#10;&#10;    public CommandHistory() {&#10;        this.undoStack = new Stack&lt;&gt;();&#10;        this.redoStack = new Stack&lt;&gt;();&#10;    }&#10;&#10;    /**&#10;     * 执行命令并将其添加到历史记录&#10;     */&#10;    public void execute(Command command) {&#10;        command.execute();&#10;        undoStack.push(command);&#10;        redoStack.clear();  // 执行新命令后，清空重做栈&#10;        notifyHistoryChanged();&#10;    }&#10;&#10;    /**&#10;     * 撤销上一个命令&#10;     */&#10;    public void undo() {&#10;        if (!undoStack.isEmpty()) {&#10;            Command command = undoStack.pop();&#10;            command.undo();&#10;            redoStack.push(command);&#10;            notifyHistoryChanged();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 重做上一个被撤销的命令&#10;     */&#10;    public void redo() {&#10;        if (!redoStack.isEmpty()) {&#10;            Command command = redoStack.pop();&#10;            command.execute();&#10;            undoStack.push(command);&#10;            notifyHistoryChanged();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 检查是否可以撤销&#10;     */&#10;    public boolean canUndo() {&#10;        return !undoStack.isEmpty();&#10;    }&#10;&#10;    /**&#10;     * 检查是否可以重做&#10;     */&#10;    public boolean canRedo() {&#10;        return !redoStack.isEmpty();&#10;    }&#10;&#10;    /**&#10;     * 清空历史记录&#10;     */&#10;    public void clear() {&#10;        undoStack.clear();&#10;        redoStack.clear();&#10;        notifyHistoryChanged();&#10;    }&#10;&#10;    /**&#10;     * 设置历史记录变化监听器&#10;     */&#10;    public void setOnHistoryChanged(Runnable callback) {&#10;        this.onHistoryChanged = callback;&#10;    }&#10;&#10;    /**&#10;     * 通知历史记录已改变&#10;     */&#10;    private void notifyHistoryChanged() {&#10;        if (onHistoryChanged != null) {&#10;            onHistoryChanged.run();&#10;        }&#10;    }&#10;}&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/Controller.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/Controller.java" />
              <option name="originalContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import dev.bytevibe.hyperpoint.Utils.MyAlert;&#10;import dev.bytevibe.hyperpoint.Utils.MyTextInputDialog;&#10;import javafx.event.ActionEvent;&#10;import javafx.fxml.FXML;&#10;import javafx.fxml.Initializable;&#10;import javafx.scene.control.*;&#10;import javafx.scene.layout.AnchorPane;&#10;import javafx.scene.layout.VBox;&#10;import javafx.stage.FileChooser;&#10;import javafx.stage.Stage;&#10;&#10;import java.io.File;&#10;import java.net.URL;&#10;import java.util.ResourceBundle;&#10;&#10;public class Controller implements Initializable {&#10;    @FXML&#10;    private ListView&lt;SlidePage&gt; pageListView;&#10;    @FXML&#10;    private Label pageNameLabel;&#10;    @FXML&#10;    private AnchorPane drawingCanvasContainer;&#10;    @FXML&#10;    private VBox propertyPanelContainer;&#10;    @FXML&#10;    private AnchorPane scenePane;&#10;&#10;    private Slide currentSlide;&#10;    private DrawingCanvas drawingCanvas;&#10;    private PropertyPanel propertyPanelComponent;&#10;    Stage stage;&#10;&#10;    @Override&#10;    public void initialize(URL url, ResourceBundle resourceBundle) {&#10;        pageListView.setDisable(true);&#10;&#10;        // 添加页面列表选择监听&#10;        pageListView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -&gt; {&#10;            if (newVal != null) {&#10;                displayPageContent(newVal);&#10;            }&#10;        });&#10;    }&#10;&#10;    /**&#10;     * 新建幻灯片按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onNewSlide(ActionEvent actionEvent) {&#10;        MyTextInputDialog dialog = new MyTextInputDialog(&quot;我的幻灯片&quot;);&#10;        dialog.setTitle(&quot;创建幻灯片&quot;);&#10;        dialog.setHeaderText(&quot;请输入幻灯片名称&quot;);&#10;        dialog.setContentText(&quot;幻灯片名称:&quot;);&#10;&#10;        if (dialog.showAndWait().isPresent()) {&#10;            String slideName = dialog.getResult();&#10;            if (!slideName.trim().isEmpty()) {&#10;                currentSlide = new Slide(slideName);&#10;                loadSlidePages();&#10;&#10;                MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;幻灯片已创建&quot;);&#10;                alert.setContentText(&quot;幻灯片 \&quot;&quot; + slideName + &quot;\&quot; 已创建。&quot;);&#10;                stage = (Stage) scenePane.getScene().getWindow();&#10;                if (stage != null) {&#10;                    stage.setTitle(&quot;Hyperpoint - &quot; + slideName);&#10;                }&#10;                alert.showAndWait();&#10;            } else {&#10;                showWarning(&quot;无效名称&quot;, &quot;幻灯片名称不能为空。&quot;);&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 加载幻灯片的所有页面到列表中&#10;     */&#10;    private void loadSlidePages() {&#10;        if (currentSlide != null) {&#10;            pageListView.setItems(currentSlide.getPages());&#10;            pageListView.setDisable(false);&#10;&#10;            if (!currentSlide.getPages().isEmpty()) {&#10;                pageListView.getSelectionModel().selectFirst();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 显示页面内容&#10;     */&#10;    private void displayPageContent(SlidePage page) {&#10;        if (page != null) {&#10;            pageNameLabel.setText(&quot;页面名称: &quot; + page.getTitle());&#10;&#10;            // 移除旧的Canvas&#10;            drawingCanvasContainer.getChildren().clear();&#10;            propertyPanelContainer.getChildren().clear();&#10;&#10;            // 创建新的Canvas&#10;            PageContent pageContent = page.getPageContent();&#10;            drawingCanvas = new DrawingCanvas(pageContent);&#10;            drawingCanvasContainer.getChildren().add(drawingCanvas);&#10;&#10;            // 使用AnchorPane的约束来填充容器&#10;            AnchorPane.setTopAnchor(drawingCanvas, 0.0);&#10;            AnchorPane.setLeftAnchor(drawingCanvas, 0.0);&#10;            AnchorPane.setRightAnchor(drawingCanvas, 0.0);&#10;            AnchorPane.setBottomAnchor(drawingCanvas, 0.0);&#10;&#10;            // 创建属性面板&#10;            propertyPanelComponent = new PropertyPanel(drawingCanvas);&#10;            propertyPanelContainer.getChildren().add(propertyPanelComponent);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 新建页面按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onNewPage(ActionEvent actionEvent) {&#10;        if (currentSlide == null) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先打开或创建一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;&#10;        MyTextInputDialog dialog = new MyTextInputDialog(&quot;页面 &quot; + (currentSlide.getPages().size() + 1));&#10;        dialog.setTitle(&quot;新建页面&quot;);&#10;        dialog.setHeaderText(&quot;请输入页面名称&quot;);&#10;        dialog.setContentText(&quot;页面名称:&quot;);&#10;&#10;        if (dialog.showAndWait().isPresent()) {&#10;            String pageName = dialog.getResult();&#10;            if (!pageName.trim().isEmpty()) {&#10;                SlidePage newPage = new SlidePage(pageName);&#10;                currentSlide.addPage(newPage);&#10;&#10;                pageListView.refresh();&#10;                pageListView.getSelectionModel().selectLast();&#10;&#10;                MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;页面已创建&quot;);&#10;                alert.setContentText(&quot;新页面 \&quot;&quot; + pageName + &quot;\&quot; 已添加。&quot;);&#10;                alert.showAndWait();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 删除页面按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onDeletePage(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无法删除&quot;, &quot;没有可删除的页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        int selectedIndex = pageListView.getSelectionModel().getSelectedIndex();&#10;        if (selectedIndex &lt; 0) {&#10;            showWarning(&quot;请选择页面&quot;, &quot;请先选择要删除的页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        Alert confirmAlert = new Alert(Alert.AlertType.CONFIRMATION);&#10;        confirmAlert.setTitle(&quot;确认删除&quot;);&#10;        confirmAlert.setHeaderText(&quot;确认删除该页面？&quot;);&#10;        confirmAlert.setContentText(&quot;删除后无法恢复，确定继续吗？&quot;);&#10;&#10;        var result = confirmAlert.showAndWait();&#10;        if (result.isPresent() &amp;&amp; result.get() == ButtonType.OK) {&#10;            if (currentSlide.removePage(selectedIndex)) {&#10;                pageListView.refresh();&#10;&#10;                if (selectedIndex &gt;= currentSlide.getPages().size()) {&#10;                    pageListView.getSelectionModel().selectLast();&#10;                } else {&#10;                    pageListView.getSelectionModel().select(selectedIndex);&#10;                }&#10;&#10;                Alert alert = new Alert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;页面已删除&quot;);&#10;                alert.showAndWait();&#10;            } else {&#10;                showWarning(&quot;无法删除&quot;, &quot;幻灯片至少需要保留一个页面。&quot;);&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加文本按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddText(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        TextInputDialog dialog = new TextInputDialog(&quot;输入文本&quot;);&#10;        dialog.setTitle(&quot;添加文本&quot;);&#10;        dialog.setHeaderText(&quot;请输入要添加的文本&quot;);&#10;        dialog.setContentText(&quot;文本内容:&quot;);&#10;&#10;        if (dialog.showAndWait().isPresent()) {&#10;            String text = dialog.getResult();&#10;            if (!text.trim().isEmpty()) {&#10;                TextObject textObj = new TextObject(50, 50, text);&#10;                drawingCanvas.addObject(textObj);&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加直线按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddLine(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject line = new ShapeObject(50, 50, 100, 100, ShapeObject.ShapeType.LINE);&#10;        drawingCanvas.addObject(line);&#10;    }&#10;&#10;    /**&#10;     * 添加矩形按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddRectangle(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject rect = new ShapeObject(50, 50, 100, 60, ShapeObject.ShapeType.RECTANGLE);&#10;        drawingCanvas.addObject(rect);&#10;    }&#10;&#10;    /**&#10;     * 添加圆形按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddCircle(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject circle = new ShapeObject(50, 50, 100, 100, ShapeObject.ShapeType.CIRCLE);&#10;        drawingCanvas.addObject(circle);&#10;    }&#10;&#10;    /**&#10;     * 添加椭圆按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddEllipse(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject ellipse = new ShapeObject(50, 50, 150, 80, ShapeObject.ShapeType.ELLIPSE);&#10;        drawingCanvas.addObject(ellipse);&#10;    }&#10;&#10;    /**&#10;     * 添加图片按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddImage(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;选择图片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;图片文件&quot;, &quot;*.png&quot;, &quot;*.jpg&quot;, &quot;*.jpeg&quot;, &quot;*.gif&quot;, &quot;*.bmp&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showOpenDialog(stage);&#10;&#10;        if (file != null) {&#10;            ImageObject imgObj = new ImageObject(50, 50, 200, 150, file.getAbsolutePath());&#10;            drawingCanvas.addObject(imgObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 退出按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void logout(ActionEvent actionEvent) {&#10;        MyAlert alert = new MyAlert(Alert.AlertType.CONFIRMATION);&#10;        alert.setTitle(&quot;退出&quot;);&#10;        alert.setHeaderText(&quot;您确定要退出吗？&quot;);&#10;        alert.setContentText(&quot;点击确定退出，点击取消返回。&quot;);&#10;&#10;        if (alert.showAndWait().orElse(null) == MyAlert.isOK()) {&#10;            stage = (Stage) scenePane.getScene().getWindow();&#10;            stage.close();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 打开幻灯片文件&#10;     */&#10;    @FXML&#10;    public void onOpenSlideFile(ActionEvent actionEvent) {&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;打开幻灯片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;幻灯片文件 (*.hyperpoint)&quot;, &quot;*.hyperpoint&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showOpenDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                Presentation presentation = JsonSerializationUtil.loadFromJson(file);&#10;                currentSlide = presentation.getSlides().isEmpty() ? null : presentation.getSlides().get(0);&#10;&#10;                if (currentSlide != null) {&#10;                    loadSlidePages();&#10;                    stage.setTitle(&quot;Hyperpoint - &quot; + presentation.getName());&#10;&#10;                    MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                    alert.setTitle(&quot;成功&quot;);&#10;                    alert.setHeaderText(&quot;幻灯片已打开&quot;);&#10;                    alert.setContentText(&quot;幻灯片 \&quot;&quot; + presentation.getName() + &quot;\&quot; 已成功加载，包含 &quot; + currentSlide.getPages().size() + &quot; 个页面。&quot;);&#10;                    alert.showAndWait();&#10;                } else {&#10;                    showWarning(&quot;加载失败&quot;, &quot;幻灯片中没有找到任何页面。&quot;);&#10;                }&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法加载幻灯片文件: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 保存幻灯片文件&#10;     */&#10;    @FXML&#10;    public void onSaveSlide(ActionEvent actionEvent) {&#10;        if (currentSlide == null) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;保存幻灯片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;幻灯片文件&quot;, &quot;*.hyperpoint&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;        fileChooser.setInitialFileName(currentSlide.getName() + &quot;.hyperpoint&quot;);&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showSaveDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                // 创建临时演示文稿对象用于保存&#10;                Presentation tempPresentation = new Presentation(currentSlide.getName());&#10;                tempPresentation.addSlide(currentSlide);&#10;&#10;                JsonSerializationUtil.saveToJson(tempPresentation, file);&#10;&#10;                MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;幻灯片已保存&quot;);&#10;                alert.setContentText(&quot;幻灯片已保存到: &quot; + file.getAbsolutePath());&#10;                alert.showAndWait();&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法保存幻灯片文件: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 导出页面为图片&#10;     */&#10;    @FXML&#10;    public void onExportPage(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;导出页面为图片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;PNG图片 (*.png)&quot;, &quot;*.png&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;JPG图片 (*.jpg)&quot;, &quot;*.jpg&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;&#10;        SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;        if (currentPage != null) {&#10;            fileChooser.setInitialFileName(currentPage.getTitle() + &quot;.png&quot;);&#10;        }&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showSaveDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                String format = file.getName().endsWith(&quot;.jpg&quot;) || file.getName().endsWith(&quot;.jpeg&quot;) ? &quot;jpg&quot; : &quot;png&quot;;&#10;                ExportUtil.exportPageAsImage(drawingCanvas, file, format);&#10;&#10;                Alert alert = new Alert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;页面已导出&quot;);&#10;                alert.setContentText(&quot;页面已导出到: &quot; + file.getAbsolutePath());&#10;                alert.showAndWait();&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法导出页面: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 导出幻灯片为PDF&#10;     */&#10;    @FXML&#10;    public void onExportSlide(ActionEvent actionEvent) {&#10;        if (currentSlide == null) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;导出幻灯片为PDF&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;PDF文件 (*.pdf)&quot;, &quot;*.pdf&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;        fileChooser.setInitialFileName(currentSlide.getName() + &quot;.pdf&quot;);&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showSaveDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                ExportUtil.exportSlideToPDF(currentSlide, file);&#10;&#10;                Alert alert = new Alert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;幻灯片已导出为PDF&quot;);&#10;                alert.setContentText(&quot;PDF已导出到: &quot; + file.getAbsolutePath());&#10;                alert.showAndWait();&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法导出PDF: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 开始演示（默认淡出淡入效果）&#10;     */&#10;    @FXML&#10;    public void onStartPresentation(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.FADE);&#10;    }&#10;&#10;    /**&#10;     * 使用淡出淡入效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithFade(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.FADE);&#10;    }&#10;&#10;    /**&#10;     * 使用从右推入效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithPushLeft(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.PUSH_LEFT);&#10;    }&#10;&#10;    /**&#10;     * 使用从左推入效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithPushRight(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.PUSH_RIGHT);&#10;    }&#10;&#10;    /**&#10;     * 使用缩放放大效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithZoomIn(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.ZOOM_IN);&#10;    }&#10;&#10;    /**&#10;     * 使用旋转翻页效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithRotate(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.ROTATE);&#10;    }&#10;&#10;    /**&#10;     * 启动演示&#10;     */&#10;    private void startPresentation(TransitionEffect transition) {&#10;        PresentationWindow presentationWindow = new PresentationWindow(currentSlide, transition);&#10;        presentationWindow.show();&#10;    }&#10;&#10;    /**&#10;     * 显示警告对话框&#10;     */&#10;    private void showWarning(String title, String message) {&#10;        MyAlert alert = new MyAlert(Alert.AlertType.WARNING);&#10;        alert.setTitle(title);&#10;        alert.setHeaderText(title);&#10;        alert.setContentText(message);&#10;        alert.showAndWait();&#10;    }&#10;}&#10;" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import dev.bytevibe.hyperpoint.Utils.MyAlert;&#10;import dev.bytevibe.hyperpoint.Utils.MyTextInputDialog;&#10;import javafx.event.ActionEvent;&#10;import javafx.fxml.FXML;&#10;import javafx.fxml.Initializable;&#10;import javafx.scene.control.*;&#10;import javafx.scene.layout.AnchorPane;&#10;import javafx.scene.layout.VBox;&#10;import javafx.stage.FileChooser;&#10;import javafx.stage.Stage;&#10;&#10;import java.io.File;&#10;import java.net.URL;&#10;import java.util.ResourceBundle;&#10;&#10;public class Controller implements Initializable {&#10;    @FXML&#10;    private ListView&lt;SlidePage&gt; pageListView;&#10;    @FXML&#10;    private Label pageNameLabel;&#10;    @FXML&#10;    private AnchorPane drawingCanvasContainer;&#10;    @FXML&#10;    private VBox propertyPanelContainer;&#10;    @FXML&#10;    private AnchorPane scenePane;&#10;    @FXML&#10;    private MenuItem undoMenuItem;&#10;    @FXML&#10;    private MenuItem redoMenuItem;&#10;&#10;    private Slide currentSlide;&#10;    private DrawingCanvas drawingCanvas;&#10;    private PropertyPanel propertyPanelComponent;&#10;    private CommandHistory commandHistory;&#10;    Stage stage;&#10;&#10;    @Override&#10;    public void initialize(URL url, ResourceBundle resourceBundle) {&#10;        // 初始化命令历史&#10;        commandHistory = new CommandHistory();&#10;        commandHistory.setOnHistoryChanged(this::updateUndoRedoButtons);&#10;&#10;        pageListView.setDisable(true);&#10;&#10;        // 添加页面列表选择监听&#10;        pageListView.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -&gt; {&#10;            if (newVal != null) {&#10;                displayPageContent(newVal);&#10;            }&#10;        });&#10;    }&#10;&#10;    /**&#10;     * 新建幻灯片按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onNewSlide(ActionEvent actionEvent) {&#10;        MyTextInputDialog dialog = new MyTextInputDialog(&quot;我的幻灯片&quot;);&#10;        dialog.setTitle(&quot;创建幻灯片&quot;);&#10;        dialog.setHeaderText(&quot;请输入幻灯片名称&quot;);&#10;        dialog.setContentText(&quot;幻灯片名称:&quot;);&#10;&#10;        if (dialog.showAndWait().isPresent()) {&#10;            String slideName = dialog.getResult();&#10;            if (!slideName.trim().isEmpty()) {&#10;                currentSlide = new Slide(slideName);&#10;                loadSlidePages();&#10;&#10;                MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;幻灯片已创建&quot;);&#10;                alert.setContentText(&quot;幻灯片 \&quot;&quot; + slideName + &quot;\&quot; 已创建。&quot;);&#10;                stage = (Stage) scenePane.getScene().getWindow();&#10;                if (stage != null) {&#10;                    stage.setTitle(&quot;Hyperpoint - &quot; + slideName);&#10;                }&#10;                alert.showAndWait();&#10;            } else {&#10;                showWarning(&quot;无效名称&quot;, &quot;幻灯片名称不能为空。&quot;);&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 加载幻灯片的所有页面到列表中&#10;     */&#10;    private void loadSlidePages() {&#10;        if (currentSlide != null) {&#10;            pageListView.setItems(currentSlide.getPages());&#10;            pageListView.setDisable(false);&#10;&#10;            if (!currentSlide.getPages().isEmpty()) {&#10;                pageListView.getSelectionModel().selectFirst();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 显示页面内容&#10;     */&#10;    private void displayPageContent(SlidePage page) {&#10;        if (page != null) {&#10;            pageNameLabel.setText(&quot;页面名称: &quot; + page.getTitle());&#10;&#10;            // 移除旧的Canvas&#10;            drawingCanvasContainer.getChildren().clear();&#10;            propertyPanelContainer.getChildren().clear();&#10;&#10;            // 创建新的Canvas&#10;            PageContent pageContent = page.getPageContent();&#10;            drawingCanvas = new DrawingCanvas(pageContent);&#10;            drawingCanvas.setCommandHistory(commandHistory);  // 设置命令历史&#10;            drawingCanvasContainer.getChildren().add(drawingCanvas);&#10;&#10;            // 使用AnchorPane的约束来填充容器&#10;            AnchorPane.setTopAnchor(drawingCanvas, 0.0);&#10;            AnchorPane.setLeftAnchor(drawingCanvas, 0.0);&#10;            AnchorPane.setRightAnchor(drawingCanvas, 0.0);&#10;            AnchorPane.setBottomAnchor(drawingCanvas, 0.0);&#10;&#10;            // 创建属性面板&#10;            propertyPanelComponent = new PropertyPanel(drawingCanvas);&#10;            propertyPanelContainer.getChildren().add(propertyPanelComponent);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 新建页面按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onNewPage(ActionEvent actionEvent) {&#10;        if (currentSlide == null) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先打开或创建一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;&#10;        MyTextInputDialog dialog = new MyTextInputDialog(&quot;页面 &quot; + (currentSlide.getPages().size() + 1));&#10;        dialog.setTitle(&quot;新建页面&quot;);&#10;        dialog.setHeaderText(&quot;请输入页面名称&quot;);&#10;        dialog.setContentText(&quot;页面名称:&quot;);&#10;&#10;        if (dialog.showAndWait().isPresent()) {&#10;            String pageName = dialog.getResult();&#10;            if (!pageName.trim().isEmpty()) {&#10;                SlidePage newPage = new SlidePage(pageName);&#10;                currentSlide.addPage(newPage);&#10;&#10;                pageListView.refresh();&#10;                pageListView.getSelectionModel().selectLast();&#10;&#10;                MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;页面已创建&quot;);&#10;                alert.setContentText(&quot;新页面 \&quot;&quot; + pageName + &quot;\&quot; 已添加。&quot;);&#10;                alert.showAndWait();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 删除页面按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onDeletePage(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无法删除&quot;, &quot;没有可删除的页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        int selectedIndex = pageListView.getSelectionModel().getSelectedIndex();&#10;        if (selectedIndex &lt; 0) {&#10;            showWarning(&quot;请选择页面&quot;, &quot;请先选择要删除的页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        Alert confirmAlert = new Alert(Alert.AlertType.CONFIRMATION);&#10;        confirmAlert.setTitle(&quot;确认删除&quot;);&#10;        confirmAlert.setHeaderText(&quot;确认删除该页面？&quot;);&#10;        confirmAlert.setContentText(&quot;删除后无法恢复，确定继续吗？&quot;);&#10;&#10;        var result = confirmAlert.showAndWait();&#10;        if (result.isPresent() &amp;&amp; result.get() == ButtonType.OK) {&#10;            if (currentSlide.removePage(selectedIndex)) {&#10;                pageListView.refresh();&#10;&#10;                if (selectedIndex &gt;= currentSlide.getPages().size()) {&#10;                    pageListView.getSelectionModel().selectLast();&#10;                } else {&#10;                    pageListView.getSelectionModel().select(selectedIndex);&#10;                }&#10;&#10;                Alert alert = new Alert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;页面已删除&quot;);&#10;                alert.showAndWait();&#10;            } else {&#10;                showWarning(&quot;无法删除&quot;, &quot;幻灯片至少需要保留一个页面。&quot;);&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加文本按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddText(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        TextInputDialog dialog = new TextInputDialog(&quot;输入文本&quot;);&#10;        dialog.setTitle(&quot;添加文本&quot;);&#10;        dialog.setHeaderText(&quot;请输入要添加的文本&quot;);&#10;        dialog.setContentText(&quot;文本内容:&quot;);&#10;&#10;        if (dialog.showAndWait().isPresent()) {&#10;            String text = dialog.getResult();&#10;            if (!text.trim().isEmpty()) {&#10;                TextObject textObj = new TextObject(50, 50, text);&#10;                // 使用命令历史记录此操作&#10;                SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;                if (currentPage != null) {&#10;                    AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), textObj);&#10;                    commandHistory.execute(command);&#10;                    drawingCanvas.redraw();&#10;                } else {&#10;                    drawingCanvas.addObject(textObj);&#10;                }&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加直线按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddLine(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject line = new ShapeObject(50, 50, 100, 100, ShapeObject.ShapeType.LINE);&#10;        SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;        if (currentPage != null) {&#10;            AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), line);&#10;            commandHistory.execute(command);&#10;            drawingCanvas.redraw();&#10;        } else {&#10;            drawingCanvas.addObject(line);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加矩形按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddRectangle(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject rect = new ShapeObject(50, 50, 100, 60, ShapeObject.ShapeType.RECTANGLE);&#10;        SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;        if (currentPage != null) {&#10;            AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), rect);&#10;            commandHistory.execute(command);&#10;            drawingCanvas.redraw();&#10;        } else {&#10;            drawingCanvas.addObject(rect);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加圆形按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddCircle(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject circle = new ShapeObject(50, 50, 100, 100, ShapeObject.ShapeType.CIRCLE);&#10;        SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;        if (currentPage != null) {&#10;            AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), circle);&#10;            commandHistory.execute(command);&#10;            drawingCanvas.redraw();&#10;        } else {&#10;            drawingCanvas.addObject(circle);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加椭圆按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddEllipse(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;        ShapeObject ellipse = new ShapeObject(50, 50, 150, 80, ShapeObject.ShapeType.ELLIPSE);&#10;        SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;        if (currentPage != null) {&#10;            AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), ellipse);&#10;            commandHistory.execute(command);&#10;            drawingCanvas.redraw();&#10;        } else {&#10;            drawingCanvas.addObject(ellipse);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 添加图片按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void onAddImage(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;选择图片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;图片文件&quot;, &quot;*.png&quot;, &quot;*.jpg&quot;, &quot;*.jpeg&quot;, &quot;*.gif&quot;, &quot;*.bmp&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showOpenDialog(stage);&#10;&#10;        if (file != null) {&#10;            ImageObject imgObj = new ImageObject(50, 50, 200, 150, file.getAbsolutePath());&#10;            SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;            if (currentPage != null) {&#10;                AddObjectCommand command = new AddObjectCommand(currentPage.getPageContent(), imgObj);&#10;                commandHistory.execute(command);&#10;                drawingCanvas.redraw();&#10;            } else {&#10;                drawingCanvas.addObject(imgObj);&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 退出按钮的事件处理&#10;     */&#10;    @FXML&#10;    public void logout(ActionEvent actionEvent) {&#10;        MyAlert alert = new MyAlert(Alert.AlertType.CONFIRMATION);&#10;        alert.setTitle(&quot;退出&quot;);&#10;        alert.setHeaderText(&quot;您确定要退出吗？&quot;);&#10;        alert.setContentText(&quot;点击确定退出，点击取消返回。&quot;);&#10;&#10;        if (alert.showAndWait().orElse(null) == MyAlert.isOK()) {&#10;            stage = (Stage) scenePane.getScene().getWindow();&#10;            stage.close();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 打开幻灯片文件&#10;     */&#10;    @FXML&#10;    public void onOpenSlideFile(ActionEvent actionEvent) {&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;打开幻灯片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;幻灯片文件 (*.hyperpoint)&quot;, &quot;*.hyperpoint&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showOpenDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                Presentation presentation = JsonSerializationUtil.loadFromJson(file);&#10;                currentSlide = presentation.getSlides().isEmpty() ? null : presentation.getSlides().get(0);&#10;&#10;                if (currentSlide != null) {&#10;                    loadSlidePages();&#10;                    stage.setTitle(&quot;Hyperpoint - &quot; + presentation.getName());&#10;&#10;                    MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                    alert.setTitle(&quot;成功&quot;);&#10;                    alert.setHeaderText(&quot;幻灯片已打开&quot;);&#10;                    alert.setContentText(&quot;幻灯片 \&quot;&quot; + presentation.getName() + &quot;\&quot; 已成功加载，包含 &quot; + currentSlide.getPages().size() + &quot; 个页面。&quot;);&#10;                    alert.showAndWait();&#10;                } else {&#10;                    showWarning(&quot;加载失败&quot;, &quot;幻灯片中没有找到任何页面。&quot;);&#10;                }&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法加载幻灯片文件: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 保存幻灯片文件&#10;     */&#10;    @FXML&#10;    public void onSaveSlide(ActionEvent actionEvent) {&#10;        if (currentSlide == null) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;保存幻灯片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;幻灯片文件&quot;, &quot;*.hyperpoint&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;        fileChooser.setInitialFileName(currentSlide.getName() + &quot;.hyperpoint&quot;);&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showSaveDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                // 创建临时演示文稿对象用于保存&#10;                Presentation tempPresentation = new Presentation(currentSlide.getName());&#10;                tempPresentation.addSlide(currentSlide);&#10;&#10;                JsonSerializationUtil.saveToJson(tempPresentation, file);&#10;&#10;                MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;幻灯片已保存&quot;);&#10;                alert.setContentText(&quot;幻灯片已保存到: &quot; + file.getAbsolutePath());&#10;                alert.showAndWait();&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法保存幻灯片文件: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 导出页面为图片&#10;     */&#10;    @FXML&#10;    public void onExportPage(ActionEvent actionEvent) {&#10;        if (drawingCanvas == null) {&#10;            showWarning(&quot;请先选择页面&quot;, &quot;请先选择一个页面。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;导出页面为图片&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;PNG图片 (*.png)&quot;, &quot;*.png&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;JPG图片 (*.jpg)&quot;, &quot;*.jpg&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;&#10;        SlidePage currentPage = pageListView.getSelectionModel().getSelectedItem();&#10;        if (currentPage != null) {&#10;            fileChooser.setInitialFileName(currentPage.getTitle() + &quot;.png&quot;);&#10;        }&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showSaveDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                String format = file.getName().endsWith(&quot;.jpg&quot;) || file.getName().endsWith(&quot;.jpeg&quot;) ? &quot;jpg&quot; : &quot;png&quot;;&#10;                ExportUtil.exportPageAsImage(drawingCanvas, file, format);&#10;&#10;                Alert alert = new Alert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;页面已导出&quot;);&#10;                alert.setContentText(&quot;页面已导出到: &quot; + file.getAbsolutePath());&#10;                alert.showAndWait();&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法导出页面: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 导出幻灯片为PDF&#10;     */&#10;    @FXML&#10;    public void onExportSlide(ActionEvent actionEvent) {&#10;        if (currentSlide == null) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;&#10;        FileChooser fileChooser = new FileChooser();&#10;        fileChooser.setTitle(&quot;导出幻灯片为PDF&quot;);&#10;        fileChooser.getExtensionFilters().addAll(&#10;                new FileChooser.ExtensionFilter(&quot;PDF文件 (*.pdf)&quot;, &quot;*.pdf&quot;),&#10;                new FileChooser.ExtensionFilter(&quot;所有文件&quot;, &quot;*.*&quot;)&#10;        );&#10;        fileChooser.setInitialFileName(currentSlide.getName() + &quot;.pdf&quot;);&#10;&#10;        stage = (Stage) scenePane.getScene().getWindow();&#10;        File file = fileChooser.showSaveDialog(stage);&#10;&#10;        if (file != null) {&#10;            try {&#10;                ExportUtil.exportSlideToPDF(currentSlide, file);&#10;&#10;                Alert alert = new Alert(Alert.AlertType.INFORMATION);&#10;                alert.setTitle(&quot;成功&quot;);&#10;                alert.setHeaderText(&quot;幻灯片已导出为PDF&quot;);&#10;                alert.setContentText(&quot;PDF已导出到: &quot; + file.getAbsolutePath());&#10;                alert.showAndWait();&#10;            } catch (Exception e) {&#10;                showWarning(&quot;错误&quot;, &quot;无法导出PDF: &quot; + e.getMessage());&#10;                e.printStackTrace();&#10;            }&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 开始演示（默认淡出淡入效果）&#10;     */&#10;    @FXML&#10;    public void onStartPresentation(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.FADE);&#10;    }&#10;&#10;    /**&#10;     * 使用淡出淡入效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithFade(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.FADE);&#10;    }&#10;&#10;    /**&#10;     * 使用从右推入效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithPushLeft(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.PUSH_LEFT);&#10;    }&#10;&#10;    /**&#10;     * 使用从左推入效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithPushRight(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.PUSH_RIGHT);&#10;    }&#10;&#10;    /**&#10;     * 使用缩放放大效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithZoomIn(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.ZOOM_IN);&#10;    }&#10;&#10;    /**&#10;     * 使用旋转翻页效果播放演示&#10;     */&#10;    @FXML&#10;    public void onPresentationWithRotate(ActionEvent actionEvent) {&#10;        if (currentSlide == null || currentSlide.getPages().isEmpty()) {&#10;            showWarning(&quot;无幻灯片&quot;, &quot;请先创建或打开一个幻灯片。&quot;);&#10;            return;&#10;        }&#10;        startPresentation(TransitionEffect.ROTATE);&#10;    }&#10;&#10;    /**&#10;     * 启动演示&#10;     */&#10;    private void startPresentation(TransitionEffect transition) {&#10;        PresentationWindow presentationWindow = new PresentationWindow(currentSlide, transition);&#10;        presentationWindow.show();&#10;    }&#10;&#10;    /**&#10;     * 撤销操作&#10;     */&#10;    @FXML&#10;    public void onUndo(ActionEvent actionEvent) {&#10;        commandHistory.undo();&#10;        if (drawingCanvas != null) {&#10;            drawingCanvas.redraw();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 重做操作&#10;     */&#10;    @FXML&#10;    public void onRedo(ActionEvent actionEvent) {&#10;        commandHistory.redo();&#10;        if (drawingCanvas != null) {&#10;            drawingCanvas.redraw();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 更新撤销和重做按钮的状态&#10;     */&#10;    private void updateUndoRedoButtons() {&#10;        // 确保菜单项不为null&#10;        if (undoMenuItem != null) {&#10;            undoMenuItem.setDisable(!commandHistory.canUndo());&#10;        }&#10;        if (redoMenuItem != null) {&#10;            redoMenuItem.setDisable(!commandHistory.canRedo());&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 获取命令历史&#10;     */&#10;    public CommandHistory getCommandHistory() {&#10;        return commandHistory;&#10;    }&#10;&#10;    /**&#10;     * 显示警告对话框&#10;     */&#10;    private void showWarning(String title, String message) {&#10;        MyAlert alert = new MyAlert(Alert.AlertType.WARNING);&#10;        alert.setTitle(title);&#10;        alert.setHeaderText(title);&#10;        alert.setContentText(message);&#10;        alert.showAndWait();&#10;    }&#10;}&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/DeleteObjectCommand.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/DeleteObjectCommand.java" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;/**&#10; * 删除对象命令&#10; */&#10;public class DeleteObjectCommand implements Command {&#10;    private PageContent pageContent;&#10;    private DrawableObject object;&#10;    private int originalIndex;&#10;&#10;    public DeleteObjectCommand(PageContent pageContent, DrawableObject object) {&#10;        this.pageContent = pageContent;&#10;        this.object = object;&#10;        this.originalIndex = pageContent.getObjectIndex(object);&#10;    }&#10;&#10;    @Override&#10;    public void execute() {&#10;        pageContent.removeObject(object);&#10;    }&#10;&#10;    @Override&#10;    public void undo() {&#10;        pageContent.addObjectAt(originalIndex, object);&#10;    }&#10;}&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/DrawingCanvas.java" />
              <option name="originalContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import javafx.scene.canvas.Canvas;&#10;import javafx.scene.canvas.GraphicsContext;&#10;import javafx.scene.image.Image;&#10;import javafx.scene.input.MouseEvent;&#10;import javafx.scene.layout.Pane;&#10;import javafx.scene.paint.Color;&#10;import javafx.scene.text.Font;&#10;import javafx.scene.text.FontPosture;&#10;import javafx.scene.text.FontWeight;&#10;&#10;/**&#10; * 绘图Canvas组件，用于渲染和交互所有可绘制对象&#10; */&#10;public class DrawingCanvas extends Pane {&#10;    // 页面标准尺寸（与全屏播放保持一致）&#10;    public static final double PAGE_WIDTH = 1024;&#10;    public static final double PAGE_HEIGHT = 768;&#10;&#10;    // 缩放点的枚举&#10;    enum ResizePoint {&#10;        TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, NONE&#10;    }&#10;&#10;    private Canvas canvas;&#10;    private PageContent pageContent;&#10;    private DrawableObject selectedObject;&#10;    private double lastX, lastY;&#10;    private Runnable onSelectionChanged;&#10;&#10;    // 缩放点有关的属性&#10;    private ResizePoint resizePoint = ResizePoint.NONE;&#10;    // 缩放点大小&#10;    private static final double HANDLE_SIZE = 8;&#10;&#10;    public DrawingCanvas(PageContent pageContent) {&#10;        this.pageContent = pageContent;&#10;        this.canvas = new Canvas(PAGE_WIDTH, PAGE_HEIGHT);&#10;&#10;        getChildren().add(canvas);&#10;&#10;        // 设置鼠标事件处理&#10;        setOnMousePressed(this::handleMousePressed);&#10;        setOnMouseDragged(this::handleMouseDragged);&#10;        setOnMouseReleased(this::handleMouseReleased);&#10;&#10;        setStyle(&quot;-fx-border-color: #e0e0e0; -fx-border-width: 1;&quot;);&#10;&#10;        // 设置Pane的首选大小为页面尺寸，这样编辑界面显示时会按页面比例显示&#10;        setPrefWidth(PAGE_WIDTH);&#10;        setPrefHeight(PAGE_HEIGHT);&#10;&#10;        // 初始绘制&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 鼠标按下事件处理&#10;     */&#10;    private void handleMousePressed(MouseEvent event) {&#10;        lastX = event.getX();&#10;        lastY = event.getY();&#10;&#10;        // 如果已经有选中对象，先检查是否点击在调整点上&#10;        if (selectedObject != null) {&#10;            resizePoint = getResizePointAt(lastX, lastY, selectedObject);&#10;            if (resizePoint != ResizePoint.NONE) {&#10;                // 点击在调整点上，进入缩放模式&#10;                return;&#10;            }&#10;        }&#10;&#10;        // 重置缩放模式&#10;        resizePoint = ResizePoint.NONE;&#10;&#10;        // 查找被点击的对象&#10;        DrawableObject clicked = pageContent.findObjectAt(lastX, lastY);&#10;&#10;        if (clicked == null) {&#10;            setSelectedObject(null);&#10;        } else {&#10;            setSelectedObject(clicked);&#10;        }&#10;&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 获取点击位置对应的调整点&#10;     */&#10;    private ResizePoint getResizePointAt(double x, double y, DrawableObject obj) {&#10;        double handleSize = HANDLE_SIZE;&#10;        double objX = obj.getX();&#10;        double objY = obj.getY();&#10;        double objW = obj.getWidth();&#10;        double objH = obj.getHeight();&#10;&#10;        // 检查左上角&#10;        if (x &gt;= objX - handleSize &amp;&amp; x &lt;= objX + handleSize &amp;&amp;&#10;            y &gt;= objY - handleSize &amp;&amp; y &lt;= objY + handleSize) {&#10;            return ResizePoint.TOP_LEFT;&#10;        }&#10;        // 检查右上角&#10;        if (x &gt;= objX + objW - handleSize &amp;&amp; x &lt;= objX + objW + handleSize &amp;&amp;&#10;            y &gt;= objY - handleSize &amp;&amp; y &lt;= objY + handleSize) {&#10;            return ResizePoint.TOP_RIGHT;&#10;        }&#10;        // 检查左下角&#10;        if (x &gt;= objX - handleSize &amp;&amp; x &lt;= objX + handleSize &amp;&amp;&#10;            y &gt;= objY + objH - handleSize &amp;&amp; y &lt;= objY + objH + handleSize) {&#10;            return ResizePoint.BOTTOM_LEFT;&#10;        }&#10;        // 检查右下角&#10;        if (x &gt;= objX + objW - handleSize &amp;&amp; x &lt;= objX + objW + handleSize &amp;&amp;&#10;            y &gt;= objY + objH - handleSize &amp;&amp; y &lt;= objY + objH + handleSize) {&#10;            return ResizePoint.BOTTOM_RIGHT;&#10;        }&#10;&#10;        return ResizePoint.NONE;&#10;    }&#10;&#10;    /**&#10;     * 鼠标拖动事件处理&#10;     */&#10;    private void handleMouseDragged(MouseEvent event) {&#10;        if (selectedObject != null) {&#10;            double dx = event.getX() - lastX;&#10;            double dy = event.getY() - lastY;&#10;&#10;            // 如果正在缩放&#10;            if (resizePoint != ResizePoint.NONE) {&#10;                resizeObject(selectedObject, dx, dy, resizePoint);&#10;            } else {&#10;                // 移动对象&#10;                selectedObject.setX(selectedObject.getX() + dx);&#10;                selectedObject.setY(selectedObject.getY() + dy);&#10;            }&#10;&#10;            lastX = event.getX();&#10;            lastY = event.getY();&#10;&#10;            redraw();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 缩放对象&#10;     */&#10;    private void resizeObject(DrawableObject obj, double dx, double dy, ResizePoint point) {&#10;        // 最小尺寸限制&#10;        final double MIN_SIZE = 20;&#10;&#10;        switch (point) {&#10;            case TOP_LEFT:&#10;                // 从左上角缩放：x和y增加，width和height减少&#10;                if (obj.getWidth() - dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() - dy &gt;= MIN_SIZE) {&#10;                    obj.setX(obj.getX() + dx);&#10;                    obj.setY(obj.getY() + dy);&#10;                    obj.setWidth(obj.getWidth() - dx);&#10;                    obj.setHeight(obj.getHeight() - dy);&#10;                }&#10;                break;&#10;            case TOP_RIGHT:&#10;                // 从右上角缩放：y增加，width增加，height减少&#10;                if (obj.getWidth() + dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() - dy &gt;= MIN_SIZE) {&#10;                    obj.setY(obj.getY() + dy);&#10;                    obj.setWidth(obj.getWidth() + dx);&#10;                    obj.setHeight(obj.getHeight() - dy);&#10;                }&#10;                break;&#10;            case BOTTOM_LEFT:&#10;                // 从左下角缩放：x增加，width减少，height增加&#10;                if (obj.getWidth() - dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() + dy &gt;= MIN_SIZE) {&#10;                    obj.setX(obj.getX() + dx);&#10;                    obj.setWidth(obj.getWidth() - dx);&#10;                    obj.setHeight(obj.getHeight() + dy);&#10;                }&#10;                break;&#10;            case BOTTOM_RIGHT:&#10;                // 从右下角缩放：width和height增加&#10;                if (obj.getWidth() + dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() + dy &gt;= MIN_SIZE) {&#10;                    obj.setWidth(obj.getWidth() + dx);&#10;                    obj.setHeight(obj.getHeight() + dy);&#10;                }&#10;                break;&#10;            default:&#10;                break;&#10;        }&#10;    }&#10;&#10;&#10;    /**&#10;     * 鼠标释放事件处理&#10;     */&#10;    private void handleMouseReleased(MouseEvent event) {&#10;        // 释放鼠标时，重置缩放模式&#10;        resizePoint = ResizePoint.NONE;&#10;    }&#10;&#10;    /**&#10;     * 添加可绘制对象&#10;     */&#10;    public void addObject(DrawableObject object) {&#10;        pageContent.addObject(object);&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 移除可绘制对象&#10;     */&#10;    public void removeObject(DrawableObject object) {&#10;        if (selectedObject == object) {&#10;            selectedObject = null;&#10;        }&#10;        pageContent.removeObject(object);&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 设置选中的对象&#10;     */&#10;    public void setSelectedObject(DrawableObject object) {&#10;        selectedObject = object;&#10;        if (onSelectionChanged != null) {&#10;            onSelectionChanged.run();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 获取选中的对象&#10;     */&#10;    public DrawableObject getSelectedObject() {&#10;        return selectedObject;&#10;    }&#10;&#10;    /**&#10;     * 设置选择变化回调&#10;     */&#10;    public void setOnSelectionChanged(Runnable callback) {&#10;        this.onSelectionChanged = callback;&#10;    }&#10;&#10;    /**&#10;     * 重新绘制画布&#10;     */&#10;    public void redraw() {&#10;        GraphicsContext gc = canvas.getGraphicsContext2D();&#10;&#10;        // 清除画布（白色背景）&#10;        gc.setFill(Color.WHITE);&#10;        gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());&#10;&#10;        // 绘制边框&#10;        gc.setStroke(Color.web(&quot;#cccccc&quot;));&#10;        gc.setLineWidth(1);&#10;        gc.strokeRect(0, 0, canvas.getWidth(), canvas.getHeight());&#10;&#10;        // 绘制所有对象&#10;        for (DrawableObject obj : pageContent.getDrawableObjects()) {&#10;            drawObject(gc, obj, obj == selectedObject);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制单个对象&#10;     */&#10;    private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) {&#10;        if (obj instanceof TextObject) {&#10;            drawTextObject(gc, (TextObject) obj, selected);&#10;        } else if (obj instanceof ShapeObject) {&#10;            drawShapeObject(gc, (ShapeObject) obj, selected);&#10;        } else if (obj instanceof ImageObject) {&#10;            drawImageObject(gc, (ImageObject) obj, selected);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制文本对象&#10;     */&#10;    private void drawTextObject(GraphicsContext gc, TextObject textObj, boolean selected) {&#10;        // 设置字体和风格&#10;        Font font = createFont(textObj.getFontFamily(), textObj.getFontSize(), textObj.getFontStyle());&#10;        gc.setFont(font);&#10;&#10;        // 绘制背景&#10;        gc.setFill(Color.WHITE);&#10;        gc.fillRect(textObj.getX(), textObj.getY(), textObj.getWidth(), textObj.getHeight());&#10;        gc.setStroke(Color.LIGHTGRAY);&#10;        gc.strokeRect(textObj.getX(), textObj.getY(), textObj.getWidth(), textObj.getHeight());&#10;&#10;        // 设置文字颜色&#10;        gc.setFill(textObj.getTextColorAsColor());&#10;&#10;        // 获取排版后的文本行并绘制&#10;        double lineHeight = textObj.getFontSize() * 1.2;&#10;        double currentY = textObj.getY() + 5;&#10;&#10;        for (String line : textObj.getLayoutLines()) {&#10;            currentY += lineHeight;&#10;            gc.fillText(line, textObj.getX() + 5, currentY);&#10;        }&#10;&#10;        // 如果选中，绘制边框&#10;        if (selected) {&#10;            drawSelectionBorder(gc, textObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 创建字体对象&#10;     */&#10;    private Font createFont(String family, double size, String style) {&#10;        FontWeight weight = style.contains(&quot;BOLD&quot;) ? FontWeight.BOLD : FontWeight.NORMAL;&#10;        FontPosture posture = style.contains(&quot;ITALIC&quot;) ? FontPosture.ITALIC : FontPosture.REGULAR;&#10;        return Font.font(family, weight, posture, size);&#10;    }&#10;&#10;    /**&#10;     * 绘制形状对象&#10;     */&#10;    private void drawShapeObject(GraphicsContext gc, ShapeObject shapeObj, boolean selected) {&#10;        gc.setFill(shapeObj.getFillColorAsColor());&#10;        gc.setStroke(shapeObj.getStrokeColorAsColor());&#10;        gc.setLineWidth(shapeObj.getStrokeWidth());&#10;&#10;        switch (shapeObj.getShapeType()) {&#10;            case RECTANGLE:&#10;                gc.fillRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                gc.strokeRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                break;&#10;            case CIRCLE:&#10;                double radius = Math.min(shapeObj.getWidth(), shapeObj.getHeight()) / 2;&#10;                double centerX = shapeObj.getX() + shapeObj.getWidth() / 2;&#10;                double centerY = shapeObj.getY() + shapeObj.getHeight() / 2;&#10;                gc.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);&#10;                gc.strokeOval(centerX - radius, centerY - radius, radius * 2, radius * 2);&#10;                break;&#10;            case ELLIPSE:&#10;                gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                break;&#10;            case LINE:&#10;                gc.strokeLine(shapeObj.getX(), shapeObj.getY(),&#10;                        shapeObj.getX() + shapeObj.getWidth(), shapeObj.getY() + shapeObj.getHeight());&#10;                break;&#10;        }&#10;&#10;        // 如果选中，绘制边框&#10;        if (selected) {&#10;            drawSelectionBorder(gc, shapeObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制图片对象&#10;     */&#10;    private void drawImageObject(GraphicsContext gc, ImageObject imageObj, boolean selected) {&#10;        try {&#10;            Image image = new Image(&quot;file:&quot; + imageObj.getImagePath());&#10;            gc.drawImage(image, imageObj.getX(), imageObj.getY(), imageObj.getWidth(), imageObj.getHeight());&#10;        } catch (Exception e) {&#10;            // 如果图片加载失败，绘制占位符&#10;            gc.setFill(Color.LIGHTGRAY);&#10;            gc.fillRect(imageObj.getX(), imageObj.getY(), imageObj.getWidth(), imageObj.getHeight());&#10;            gc.setFill(Color.BLACK);&#10;            gc.fillText(&quot;[Image Not Found]&quot;, imageObj.getX() + 5, imageObj.getY() + 15);&#10;        }&#10;&#10;        // 如果选中，绘制边框&#10;        if (selected) {&#10;            drawSelectionBorder(gc, imageObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制选中对象的边框和句柄&#10;     */&#10;    private void drawSelectionBorder(GraphicsContext gc, DrawableObject obj) {&#10;        gc.setStroke(Color.BLUE);&#10;        gc.setLineWidth(2);&#10;        gc.strokeRect(obj.getX() - 2, obj.getY() - 2, obj.getWidth() + 4, obj.getHeight() + 4);&#10;&#10;        // 绘制8个调整点&#10;        drawResizeHandle(gc, obj.getX() - 4, obj.getY() - 4); // 左上&#10;        drawResizeHandle(gc, obj.getX() + obj.getWidth(), obj.getY() - 4); // 右上&#10;        drawResizeHandle(gc, obj.getX() - 4, obj.getY() + obj.getHeight()); // 左下&#10;        drawResizeHandle(gc, obj.getX() + obj.getWidth(), obj.getY() + obj.getHeight()); // 右下&#10;    }&#10;&#10;    /**&#10;     * 绘制调整点&#10;     */&#10;    private void drawResizeHandle(GraphicsContext gc, double x, double y) {&#10;        gc.setFill(Color.BLUE);&#10;        gc.fillRect(x, y, 8, 8);&#10;        gc.setStroke(Color.WHITE);&#10;        gc.setLineWidth(1);&#10;        gc.strokeRect(x, y, 8, 8);&#10;    }&#10;&#10;    /**&#10;     * 调整Canvas大小&#10;     */&#10;    public void resize(double width, double height) {&#10;        canvas.setWidth(width);&#10;        canvas.setHeight(height);&#10;        setPrefSize(width, height);&#10;        redraw();&#10;    }&#10;}&#10;&#10;" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import javafx.scene.canvas.Canvas;&#10;import javafx.scene.canvas.GraphicsContext;&#10;import javafx.scene.image.Image;&#10;import javafx.scene.input.MouseEvent;&#10;import javafx.scene.layout.Pane;&#10;import javafx.scene.paint.Color;&#10;import javafx.scene.text.Font;&#10;import javafx.scene.text.FontPosture;&#10;import javafx.scene.text.FontWeight;&#10;&#10;/**&#10; * 绘图Canvas组件，用于渲染和交互所有可绘制对象&#10; */&#10;public class DrawingCanvas extends Pane {&#10;    // 页面标准尺寸（与全屏播放保持一致）&#10;    public static final double PAGE_WIDTH = 1024;&#10;    public static final double PAGE_HEIGHT = 768;&#10;&#10;    // 缩放点的枚举&#10;    enum ResizePoint {&#10;        TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, NONE&#10;    }&#10;&#10;    private Canvas canvas;&#10;    private PageContent pageContent;&#10;    private DrawableObject selectedObject;&#10;    private double lastX, lastY;&#10;    private Runnable onSelectionChanged;&#10;    private CommandHistory commandHistory;&#10;&#10;    // 缩放点有关的属性&#10;    private ResizePoint resizePoint = ResizePoint.NONE;&#10;    // 缩放点大小&#10;    private static final double HANDLE_SIZE = 8;&#10;&#10;    public DrawingCanvas(PageContent pageContent) {&#10;        this.pageContent = pageContent;&#10;        this.canvas = new Canvas(PAGE_WIDTH, PAGE_HEIGHT);&#10;&#10;        getChildren().add(canvas);&#10;&#10;        // 设置鼠标事件处理&#10;        setOnMousePressed(this::handleMousePressed);&#10;        setOnMouseDragged(this::handleMouseDragged);&#10;        setOnMouseReleased(this::handleMouseReleased);&#10;&#10;        setStyle(&quot;-fx-border-color: #e0e0e0; -fx-border-width: 1;&quot;);&#10;&#10;        // 设置Pane的首选大小为页面尺寸，这样编辑界面显示时会按页面比例显示&#10;        setPrefWidth(PAGE_WIDTH);&#10;        setPrefHeight(PAGE_HEIGHT);&#10;&#10;        // 初始绘制&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 鼠标按下事件处理&#10;     */&#10;    private void handleMousePressed(MouseEvent event) {&#10;        lastX = event.getX();&#10;        lastY = event.getY();&#10;&#10;        // 如果已经有选中对象，先检查是否点击在调整点上&#10;        if (selectedObject != null) {&#10;            resizePoint = getResizePointAt(lastX, lastY, selectedObject);&#10;            if (resizePoint != ResizePoint.NONE) {&#10;                // 点击在调整点上，进入缩放模式&#10;                return;&#10;            }&#10;        }&#10;&#10;        // 重置缩放模式&#10;        resizePoint = ResizePoint.NONE;&#10;&#10;        // 查找被点击的对象&#10;        DrawableObject clicked = pageContent.findObjectAt(lastX, lastY);&#10;&#10;        if (clicked == null) {&#10;            setSelectedObject(null);&#10;        } else {&#10;            setSelectedObject(clicked);&#10;        }&#10;&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 获取点击位置对应的调整点&#10;     */&#10;    private ResizePoint getResizePointAt(double x, double y, DrawableObject obj) {&#10;        double handleSize = HANDLE_SIZE;&#10;        double objX = obj.getX();&#10;        double objY = obj.getY();&#10;        double objW = obj.getWidth();&#10;        double objH = obj.getHeight();&#10;&#10;        // 检查左上角&#10;        if (x &gt;= objX - handleSize &amp;&amp; x &lt;= objX + handleSize &amp;&amp;&#10;            y &gt;= objY - handleSize &amp;&amp; y &lt;= objY + handleSize) {&#10;            return ResizePoint.TOP_LEFT;&#10;        }&#10;        // 检查右上角&#10;        if (x &gt;= objX + objW - handleSize &amp;&amp; x &lt;= objX + objW + handleSize &amp;&amp;&#10;            y &gt;= objY - handleSize &amp;&amp; y &lt;= objY + handleSize) {&#10;            return ResizePoint.TOP_RIGHT;&#10;        }&#10;        // 检查左下角&#10;        if (x &gt;= objX - handleSize &amp;&amp; x &lt;= objX + handleSize &amp;&amp;&#10;            y &gt;= objY + objH - handleSize &amp;&amp; y &lt;= objY + objH + handleSize) {&#10;            return ResizePoint.BOTTOM_LEFT;&#10;        }&#10;        // 检查右下角&#10;        if (x &gt;= objX + objW - handleSize &amp;&amp; x &lt;= objX + objW + handleSize &amp;&amp;&#10;            y &gt;= objY + objH - handleSize &amp;&amp; y &lt;= objY + objH + handleSize) {&#10;            return ResizePoint.BOTTOM_RIGHT;&#10;        }&#10;&#10;        return ResizePoint.NONE;&#10;    }&#10;&#10;    /**&#10;     * 鼠标拖动事件处理&#10;     */&#10;    private void handleMouseDragged(MouseEvent event) {&#10;        if (selectedObject != null) {&#10;            double dx = event.getX() - lastX;&#10;            double dy = event.getY() - lastY;&#10;&#10;            // 如果正在缩放&#10;            if (resizePoint != ResizePoint.NONE) {&#10;                resizeObject(selectedObject, dx, dy, resizePoint);&#10;            } else {&#10;                // 移动对象&#10;                selectedObject.setX(selectedObject.getX() + dx);&#10;                selectedObject.setY(selectedObject.getY() + dy);&#10;            }&#10;&#10;            lastX = event.getX();&#10;            lastY = event.getY();&#10;&#10;            redraw();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 缩放对象&#10;     */&#10;    private void resizeObject(DrawableObject obj, double dx, double dy, ResizePoint point) {&#10;        // 最小尺寸限制&#10;        final double MIN_SIZE = 20;&#10;&#10;        switch (point) {&#10;            case TOP_LEFT:&#10;                // 从左上角缩放：x和y增加，width和height减少&#10;                if (obj.getWidth() - dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() - dy &gt;= MIN_SIZE) {&#10;                    obj.setX(obj.getX() + dx);&#10;                    obj.setY(obj.getY() + dy);&#10;                    obj.setWidth(obj.getWidth() - dx);&#10;                    obj.setHeight(obj.getHeight() - dy);&#10;                }&#10;                break;&#10;            case TOP_RIGHT:&#10;                // 从右上角缩放：y增加，width增加，height减少&#10;                if (obj.getWidth() + dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() - dy &gt;= MIN_SIZE) {&#10;                    obj.setY(obj.getY() + dy);&#10;                    obj.setWidth(obj.getWidth() + dx);&#10;                    obj.setHeight(obj.getHeight() - dy);&#10;                }&#10;                break;&#10;            case BOTTOM_LEFT:&#10;                // 从左下角缩放：x增加，width减少，height增加&#10;                if (obj.getWidth() - dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() + dy &gt;= MIN_SIZE) {&#10;                    obj.setX(obj.getX() + dx);&#10;                    obj.setWidth(obj.getWidth() - dx);&#10;                    obj.setHeight(obj.getHeight() + dy);&#10;                }&#10;                break;&#10;            case BOTTOM_RIGHT:&#10;                // 从右下角缩放：width和height增加&#10;                if (obj.getWidth() + dx &gt;= MIN_SIZE &amp;&amp; obj.getHeight() + dy &gt;= MIN_SIZE) {&#10;                    obj.setWidth(obj.getWidth() + dx);&#10;                    obj.setHeight(obj.getHeight() + dy);&#10;                }&#10;                break;&#10;            default:&#10;                break;&#10;        }&#10;    }&#10;&#10;&#10;    /**&#10;     * 鼠标释放事件处理&#10;     */&#10;    private void handleMouseReleased(MouseEvent event) {&#10;        // 释放鼠标时，重置缩放模式&#10;        resizePoint = ResizePoint.NONE;&#10;    }&#10;&#10;    /**&#10;     * 添加可绘制对象&#10;     */&#10;    public void addObject(DrawableObject object) {&#10;        pageContent.addObject(object);&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 移除可绘制对象&#10;     */&#10;    public void removeObject(DrawableObject object) {&#10;        if (selectedObject == object) {&#10;            selectedObject = null;&#10;        }&#10;        pageContent.removeObject(object);&#10;        redraw();&#10;    }&#10;&#10;    /**&#10;     * 设置选中的对象&#10;     */&#10;    public void setSelectedObject(DrawableObject object) {&#10;        selectedObject = object;&#10;        if (onSelectionChanged != null) {&#10;            onSelectionChanged.run();&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 获取选中的对象&#10;     */&#10;    public DrawableObject getSelectedObject() {&#10;        return selectedObject;&#10;    }&#10;&#10;    /**&#10;     * 设置选择变化回调&#10;     */&#10;    public void setOnSelectionChanged(Runnable callback) {&#10;        this.onSelectionChanged = callback;&#10;    }&#10;&#10;    /**&#10;     * 设置命令历史&#10;     */&#10;    public void setCommandHistory(CommandHistory commandHistory) {&#10;        this.commandHistory = commandHistory;&#10;    }&#10;&#10;    /**&#10;     * 重新绘制画布&#10;     */&#10;    public void redraw() {&#10;        GraphicsContext gc = canvas.getGraphicsContext2D();&#10;&#10;        // 清除画布（白色背景）&#10;        gc.setFill(Color.WHITE);&#10;        gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());&#10;&#10;        // 绘制边框&#10;        gc.setStroke(Color.web(&quot;#cccccc&quot;));&#10;        gc.setLineWidth(1);&#10;        gc.strokeRect(0, 0, canvas.getWidth(), canvas.getHeight());&#10;&#10;        // 绘制所有对象&#10;        for (DrawableObject obj : pageContent.getDrawableObjects()) {&#10;            drawObject(gc, obj, obj == selectedObject);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制单个对象&#10;     */&#10;    private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) {&#10;        if (obj instanceof TextObject) {&#10;            drawTextObject(gc, (TextObject) obj, selected);&#10;        } else if (obj instanceof ShapeObject) {&#10;            drawShapeObject(gc, (ShapeObject) obj, selected);&#10;        } else if (obj instanceof ImageObject) {&#10;            drawImageObject(gc, (ImageObject) obj, selected);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制文本对象&#10;     */&#10;    private void drawTextObject(GraphicsContext gc, TextObject textObj, boolean selected) {&#10;        // 设置字体和风格&#10;        Font font = createFont(textObj.getFontFamily(), textObj.getFontSize(), textObj.getFontStyle());&#10;        gc.setFont(font);&#10;&#10;        // 绘制背景&#10;        gc.setFill(Color.WHITE);&#10;        gc.fillRect(textObj.getX(), textObj.getY(), textObj.getWidth(), textObj.getHeight());&#10;        gc.setStroke(Color.LIGHTGRAY);&#10;        gc.strokeRect(textObj.getX(), textObj.getY(), textObj.getWidth(), textObj.getHeight());&#10;&#10;        // 设置文字颜色&#10;        gc.setFill(textObj.getTextColorAsColor());&#10;&#10;        // 获取排版后的文本行并绘制&#10;        double lineHeight = textObj.getFontSize() * 1.2;&#10;        double currentY = textObj.getY() + 5;&#10;&#10;        for (String line : textObj.getLayoutLines()) {&#10;            currentY += lineHeight;&#10;            gc.fillText(line, textObj.getX() + 5, currentY);&#10;        }&#10;&#10;        // 如果选中，绘制边框&#10;        if (selected) {&#10;            drawSelectionBorder(gc, textObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 创建字体对象&#10;     */&#10;    private Font createFont(String family, double size, String style) {&#10;        FontWeight weight = style.contains(&quot;BOLD&quot;) ? FontWeight.BOLD : FontWeight.NORMAL;&#10;        FontPosture posture = style.contains(&quot;ITALIC&quot;) ? FontPosture.ITALIC : FontPosture.REGULAR;&#10;        return Font.font(family, weight, posture, size);&#10;    }&#10;&#10;    /**&#10;     * 绘制形状对象&#10;     */&#10;    private void drawShapeObject(GraphicsContext gc, ShapeObject shapeObj, boolean selected) {&#10;        gc.setFill(shapeObj.getFillColorAsColor());&#10;        gc.setStroke(shapeObj.getStrokeColorAsColor());&#10;        gc.setLineWidth(shapeObj.getStrokeWidth());&#10;&#10;        switch (shapeObj.getShapeType()) {&#10;            case RECTANGLE:&#10;                gc.fillRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                gc.strokeRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                break;&#10;            case CIRCLE:&#10;                double radius = Math.min(shapeObj.getWidth(), shapeObj.getHeight()) / 2;&#10;                double centerX = shapeObj.getX() + shapeObj.getWidth() / 2;&#10;                double centerY = shapeObj.getY() + shapeObj.getHeight() / 2;&#10;                gc.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);&#10;                gc.strokeOval(centerX - radius, centerY - radius, radius * 2, radius * 2);&#10;                break;&#10;            case ELLIPSE:&#10;                gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());&#10;                break;&#10;            case LINE:&#10;                gc.strokeLine(shapeObj.getX(), shapeObj.getY(),&#10;                        shapeObj.getX() + shapeObj.getWidth(), shapeObj.getY() + shapeObj.getHeight());&#10;                break;&#10;        }&#10;&#10;        // 如果选中，绘制边框&#10;        if (selected) {&#10;            drawSelectionBorder(gc, shapeObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制图片对象&#10;     */&#10;    private void drawImageObject(GraphicsContext gc, ImageObject imageObj, boolean selected) {&#10;        try {&#10;            Image image = new Image(&quot;file:&quot; + imageObj.getImagePath());&#10;            gc.drawImage(image, imageObj.getX(), imageObj.getY(), imageObj.getWidth(), imageObj.getHeight());&#10;        } catch (Exception e) {&#10;            // 如果图片加载失败，绘制占位符&#10;            gc.setFill(Color.LIGHTGRAY);&#10;            gc.fillRect(imageObj.getX(), imageObj.getY(), imageObj.getWidth(), imageObj.getHeight());&#10;            gc.setFill(Color.BLACK);&#10;            gc.fillText(&quot;[Image Not Found]&quot;, imageObj.getX() + 5, imageObj.getY() + 15);&#10;        }&#10;&#10;        // 如果选中，绘制边框&#10;        if (selected) {&#10;            drawSelectionBorder(gc, imageObj);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 绘制选中对象的边框和句柄&#10;     */&#10;    private void drawSelectionBorder(GraphicsContext gc, DrawableObject obj) {&#10;        gc.setStroke(Color.BLUE);&#10;        gc.setLineWidth(2);&#10;        gc.strokeRect(obj.getX() - 2, obj.getY() - 2, obj.getWidth() + 4, obj.getHeight() + 4);&#10;&#10;        // 绘制8个调整点&#10;        drawResizeHandle(gc, obj.getX() - 4, obj.getY() - 4); // 左上&#10;        drawResizeHandle(gc, obj.getX() + obj.getWidth(), obj.getY() - 4); // 右上&#10;        drawResizeHandle(gc, obj.getX() - 4, obj.getY() + obj.getHeight()); // 左下&#10;        drawResizeHandle(gc, obj.getX() + obj.getWidth(), obj.getY() + obj.getHeight()); // 右下&#10;    }&#10;&#10;    /**&#10;     * 绘制调整点&#10;     */&#10;    private void drawResizeHandle(GraphicsContext gc, double x, double y) {&#10;        gc.setFill(Color.BLUE);&#10;        gc.fillRect(x, y, 8, 8);&#10;        gc.setStroke(Color.WHITE);&#10;        gc.setLineWidth(1);&#10;        gc.strokeRect(x, y, 8, 8);&#10;    }&#10;&#10;    /**&#10;     * 调整Canvas大小&#10;     */&#10;    public void resize(double width, double height) {&#10;        canvas.setWidth(width);&#10;        canvas.setHeight(height);&#10;        setPrefSize(width, height);&#10;        redraw();&#10;    }&#10;}" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/ModifyObjectCommand.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/ModifyObjectCommand.java" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;/**&#10; * 修改对象命令&#10; */&#10;public class ModifyObjectCommand implements Command {&#10;    private DrawableObject object;&#10;    private double oldX, oldY, oldWidth, oldHeight;&#10;    private double newX, newY, newWidth, newHeight;&#10;&#10;    public ModifyObjectCommand(DrawableObject object, &#10;                               double oldX, double oldY, double oldWidth, double oldHeight,&#10;                               double newX, double newY, double newWidth, double newHeight) {&#10;        this.object = object;&#10;        this.oldX = oldX;&#10;        this.oldY = oldY;&#10;        this.oldWidth = oldWidth;&#10;        this.oldHeight = oldHeight;&#10;        this.newX = newX;&#10;        this.newY = newY;&#10;        this.newWidth = newWidth;&#10;        this.newHeight = newHeight;&#10;    }&#10;&#10;    @Override&#10;    public void execute() {&#10;        object.setX(newX);&#10;        object.setY(newY);&#10;        object.setWidth(newWidth);&#10;        object.setHeight(newHeight);&#10;    }&#10;&#10;    @Override&#10;    public void undo() {&#10;        object.setX(oldX);&#10;        object.setY(oldY);&#10;        object.setWidth(oldWidth);&#10;        object.setHeight(oldHeight);&#10;    }&#10;}&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/PageContent.java">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/java/dev/bytevibe/hyperpoint/PageContent.java" />
              <option name="originalContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import javafx.collections.FXCollections;&#10;import javafx.collections.ObservableList;&#10;&#10;import java.io.Serializable;&#10;&#10;/**&#10; * 页面内容容器，用于保存页面上的所有可绘制对象&#10; */&#10;public class PageContent implements Serializable {&#10;    private ObservableList&lt;DrawableObject&gt; drawableObjects;&#10;&#10;    public PageContent() {&#10;        this.drawableObjects = FXCollections.observableArrayList();&#10;    }&#10;&#10;    public ObservableList&lt;DrawableObject&gt; getDrawableObjects() {&#10;        return drawableObjects;&#10;    }&#10;&#10;    /**&#10;     * 添加可绘制对象&#10;     */&#10;    public void addObject(DrawableObject object) {&#10;        if (object != null) {&#10;            drawableObjects.add(object);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 移除可绘制对象&#10;     */&#10;    public void removeObject(DrawableObject object) {&#10;        drawableObjects.remove(object);&#10;    }&#10;&#10;    /**&#10;     * 查找包含指定点的对象（从后到前，越后面的优先级越高）&#10;     */&#10;    public DrawableObject findObjectAt(double x, double y) {&#10;        for (int i = drawableObjects.size() - 1; i &gt;= 0; i--) {&#10;            DrawableObject obj = drawableObjects.get(i);&#10;            if (obj.contains(x, y)) {&#10;                return obj;&#10;            }&#10;        }&#10;        return null;&#10;    }&#10;&#10;    /**&#10;     * 获取对象列表大小&#10;     */&#10;    public int size() {&#10;        return drawableObjects.size();&#10;    }&#10;&#10;    /**&#10;     * 清空所有对象&#10;     */&#10;    public void clear() {&#10;        drawableObjects.clear();&#10;    }&#10;}&#10;&#10;" />
              <option name="updatedContent" value="package dev.bytevibe.hyperpoint;&#10;&#10;import javafx.collections.FXCollections;&#10;import javafx.collections.ObservableList;&#10;&#10;import java.io.Serializable;&#10;&#10;/**&#10; * 页面内容容器，用于保存页面上的所有可绘制对象&#10; */&#10;public class PageContent implements Serializable {&#10;    private ObservableList&lt;DrawableObject&gt; drawableObjects;&#10;&#10;    public PageContent() {&#10;        this.drawableObjects = FXCollections.observableArrayList();&#10;    }&#10;&#10;    public ObservableList&lt;DrawableObject&gt; getDrawableObjects() {&#10;        return drawableObjects;&#10;    }&#10;&#10;    /**&#10;     * 添加可绘制对象&#10;     */&#10;    public void addObject(DrawableObject object) {&#10;        if (object != null) {&#10;            drawableObjects.add(object);&#10;        }&#10;    }&#10;&#10;    /**&#10;     * 移除可绘制对象&#10;     */&#10;    public void removeObject(DrawableObject object) {&#10;        drawableObjects.remove(object);&#10;    }&#10;&#10;    /**&#10;     * 查找包含指定点的对象（从后到前，越后面的优先级越高）&#10;     */&#10;    public DrawableObject findObjectAt(double x, double y) {&#10;        for (int i = drawableObjects.size() - 1; i &gt;= 0; i--) {&#10;            DrawableObject obj = drawableObjects.get(i);&#10;            if (obj.contains(x, y)) {&#10;                return obj;&#10;            }&#10;        }&#10;        return null;&#10;    }&#10;&#10;    /**&#10;     * 获取对象列表大小&#10;     */&#10;    public int size() {&#10;        return drawableObjects.size();&#10;    }&#10;&#10;    /**&#10;     * 清空所有对象&#10;     */&#10;    public void clear() {&#10;        drawableObjects.clear();&#10;    }&#10;&#10;    /**&#10;     * 获取对象在列表中的索引&#10;     */&#10;    public int getObjectIndex(DrawableObject object) {&#10;        return drawableObjects.indexOf(object);&#10;    }&#10;&#10;    /**&#10;     * 在指定索引处添加对象&#10;     */&#10;    public void addObjectAt(int index, DrawableObject object) {&#10;        if (object != null &amp;&amp; index &gt;= 0 &amp;&amp; index &lt;= drawableObjects.size()) {&#10;            drawableObjects.add(index, object);&#10;        }&#10;    }&#10;}" />
            </PendingDiffInfo>
          </value>
        </entry>
        <entry key="$PROJECT_DIR$/src/main/resources/dev/bytevibe/hyperpoint/main.fxml">
          <value>
            <PendingDiffInfo>
              <option name="filePath" value="$PROJECT_DIR$/src/main/resources/dev/bytevibe/hyperpoint/main.fxml" />
              <option name="originalContent" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&#10;&lt;?import javafx.scene.control.Button?&gt;&#10;&lt;?import javafx.scene.control.Label?&gt;&#10;&lt;?import javafx.scene.control.ListView?&gt;&#10;&lt;?import javafx.scene.layout.AnchorPane?&gt;&#10;&lt;?import javafx.scene.layout.HBox?&gt;&#10;&lt;?import javafx.scene.layout.VBox?&gt;&#10;&#10;&lt;?import javafx.scene.control.MenuButton?&gt;&#10;&lt;?import javafx.scene.control.MenuItem?&gt;&#10;&lt;AnchorPane fx:id=&quot;scenePane&quot; maxHeight=&quot;-Infinity&quot; maxWidth=&quot;-Infinity&quot; minHeight=&quot;-Infinity&quot; minWidth=&quot;-Infinity&quot; prefHeight=&quot;700.0&quot; prefWidth=&quot;1300.0&quot; xmlns=&quot;http://javafx.com/javafx/25&quot; xmlns:fx=&quot;http://javafx.com/fxml/1&quot; fx:controller=&quot;dev.bytevibe.hyperpoint.Controller&quot;&gt;&#10;   &lt;children&gt;&#10;      &lt;!-- 顶部菜单栏 --&gt;&#10;      &lt;VBox layoutX=&quot;0&quot; layoutY=&quot;0&quot; prefHeight=&quot;50.0&quot; prefWidth=&quot;1300.0&quot; style=&quot;-fx-border-color: #cccccc; -fx-border-width: 0 0 1 0;&quot;&gt;&#10;         &lt;children&gt;&#10;            &lt;HBox spacing=&quot;5&quot; style=&quot;-fx-padding: 5;&quot;&gt;&#10;               &lt;children&gt;&#10;                   &lt;!-- 文件菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;文件&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onNewSlide&quot; text=&quot;新建幻灯片&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onOpenSlideFile&quot; text=&quot;打开幻灯片&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onSaveSlide&quot; text=&quot;保存幻灯片&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onExportSlide&quot; text=&quot;导出幻灯片(PDF)&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 页面菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;页面&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onNewPage&quot; text=&quot;新建页面&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onDeletePage&quot; text=&quot;删除页面&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onExportPage&quot; text=&quot;导出页面(图片)&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 插入菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;插入&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddText&quot; text=&quot;文本框&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddLine&quot; text=&quot;直线&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddRectangle&quot; text=&quot;矩形&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddCircle&quot; text=&quot;圆形&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddEllipse&quot; text=&quot;椭圆&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddImage&quot; text=&quot;图片&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 演示菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;演示&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onStartPresentation&quot; text=&quot;开始演示(F5)&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithFade&quot; text=&quot;淡出淡入效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithPushLeft&quot; text=&quot;从右推入效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithPushRight&quot; text=&quot;从左推入效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithZoomIn&quot; text=&quot;缩放放大效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithRotate&quot; text=&quot;旋转翻页效果演示&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;Label text=&quot; | &quot; /&gt;&#10;&#10;                   &lt;!-- 退出菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;更多&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#logout&quot; text=&quot;退出应用&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;               &lt;/children&gt;&#10;            &lt;/HBox&gt;&#10;         &lt;/children&gt;&#10;      &lt;/VBox&gt;&#10;&#10;      &lt;!-- 主内容区域 --&gt;&#10;      &lt;HBox layoutX=&quot;0&quot; layoutY=&quot;50&quot; prefHeight=&quot;652.0&quot; prefWidth=&quot;1300.0&quot;&gt;&#10;         &lt;!-- 左侧页面列表 --&gt;&#10;         &lt;VBox prefHeight=&quot;657.0&quot; prefWidth=&quot;200.0&quot; style=&quot;-fx-border-color: #e0e0e0; -fx-border-width: 0 1 0 0;&quot;&gt;&#10;            &lt;Label style=&quot;-fx-padding: 5; -fx-font-weight: bold;&quot; text=&quot;页面列表&quot; /&gt;&#10;            &lt;ListView fx:id=&quot;pageListView&quot; prefHeight=&quot;619.0&quot; prefWidth=&quot;195.0&quot; VBox.vgrow=&quot;ALWAYS&quot; /&gt;&#10;         &lt;/VBox&gt;&#10;&#10;         &lt;!-- 右侧编辑区域 --&gt;&#10;         &lt;VBox spacing=&quot;10&quot; style=&quot;-fx-padding: 10;&quot; HBox.hgrow=&quot;ALWAYS&quot;&gt;&#10;            &lt;Label fx:id=&quot;pageNameLabel&quot; style=&quot;-fx-font-size: 14; -fx-font-weight: bold;&quot; text=&quot;页面名称:&quot; /&gt;&#10;            &lt;!-- 绘图Canvas将在这里动态添加 --&gt;&#10;            &lt;AnchorPane fx:id=&quot;drawingCanvasContainer&quot; HBox.hgrow=&quot;ALWAYS&quot; VBox.vgrow=&quot;ALWAYS&quot; /&gt;&#10;         &lt;/VBox&gt;&#10;&#10;         &lt;!-- 右侧属性编辑面板 --&gt;&#10;         &lt;VBox fx:id=&quot;propertyPanelContainer&quot; prefWidth=&quot;200.0&quot; /&gt;&#10;      &lt;/HBox&gt;&#10;   &lt;/children&gt;&#10;&lt;/AnchorPane&gt;&#10;" />
              <option name="updatedContent" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&#10;&lt;?import javafx.scene.control.Button?&gt;&#10;&lt;?import javafx.scene.control.Label?&gt;&#10;&lt;?import javafx.scene.control.ListView?&gt;&#10;&lt;?import javafx.scene.layout.AnchorPane?&gt;&#10;&lt;?import javafx.scene.layout.HBox?&gt;&#10;&lt;?import javafx.scene.layout.VBox?&gt;&#10;&#10;&lt;?import javafx.scene.control.MenuButton?&gt;&#10;&lt;?import javafx.scene.control.MenuItem?&gt;&#10;&lt;AnchorPane fx:id=&quot;scenePane&quot; maxHeight=&quot;-Infinity&quot; maxWidth=&quot;-Infinity&quot; minHeight=&quot;-Infinity&quot; minWidth=&quot;-Infinity&quot; prefHeight=&quot;700.0&quot; prefWidth=&quot;1300.0&quot; xmlns=&quot;http://javafx.com/javafx/25&quot; xmlns:fx=&quot;http://javafx.com/fxml/1&quot; fx:controller=&quot;dev.bytevibe.hyperpoint.Controller&quot;&gt;&#10;   &lt;children&gt;&#10;      &lt;!-- 顶部菜单栏 --&gt;&#10;      &lt;VBox layoutX=&quot;0&quot; layoutY=&quot;0&quot; prefHeight=&quot;50.0&quot; prefWidth=&quot;1300.0&quot; style=&quot;-fx-border-color: #cccccc; -fx-border-width: 0 0 1 0;&quot;&gt;&#10;         &lt;children&gt;&#10;            &lt;HBox spacing=&quot;5&quot; style=&quot;-fx-padding: 5;&quot;&gt;&#10;               &lt;children&gt;&#10;                   &lt;!-- 文件菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;文件&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onNewSlide&quot; text=&quot;新建幻灯片&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onOpenSlideFile&quot; text=&quot;打开幻灯片&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onSaveSlide&quot; text=&quot;保存幻灯片&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onExportSlide&quot; text=&quot;导出幻灯片(PDF)&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 编辑菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;编辑&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem fx:id=&quot;undoMenuItem&quot; mnemonicParsing=&quot;false&quot; onAction=&quot;#onUndo&quot; text=&quot;撤销(Ctrl+Z)&quot; /&gt;&#10;                           &lt;MenuItem fx:id=&quot;redoMenuItem&quot; mnemonicParsing=&quot;false&quot; onAction=&quot;#onRedo&quot; text=&quot;重做(Ctrl+Y)&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 页面菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;页面&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onNewPage&quot; text=&quot;新建页面&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onDeletePage&quot; text=&quot;删除页面&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onExportPage&quot; text=&quot;导出页面(图片)&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 插入菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;插入&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddText&quot; text=&quot;文本框&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddLine&quot; text=&quot;直线&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddRectangle&quot; text=&quot;矩形&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddCircle&quot; text=&quot;圆形&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddEllipse&quot; text=&quot;椭圆&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onAddImage&quot; text=&quot;图片&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;!-- 演示菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;演示&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onStartPresentation&quot; text=&quot;开始演示(F5)&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithFade&quot; text=&quot;淡出淡入效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithPushLeft&quot; text=&quot;从右推入效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithPushRight&quot; text=&quot;从左推入效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithZoomIn&quot; text=&quot;缩放放大效果演示&quot; /&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#onPresentationWithRotate&quot; text=&quot;旋转翻页效果演示&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;&#10;                   &lt;Label text=&quot; | &quot; /&gt;&#10;&#10;                   &lt;!-- 退出菜单 --&gt;&#10;                   &lt;MenuButton mnemonicParsing=&quot;false&quot; text=&quot;更多&quot;&gt;&#10;                       &lt;items&gt;&#10;                           &lt;MenuItem mnemonicParsing=&quot;false&quot; onAction=&quot;#logout&quot; text=&quot;退出应用&quot; /&gt;&#10;                       &lt;/items&gt;&#10;                   &lt;/MenuButton&gt;&#10;               &lt;/children&gt;&#10;            &lt;/HBox&gt;&#10;         &lt;/children&gt;&#10;      &lt;/VBox&gt;&#10;&#10;      &lt;!-- 主内容区域 --&gt;&#10;      &lt;HBox layoutX=&quot;0&quot; layoutY=&quot;50&quot; prefHeight=&quot;652.0&quot; prefWidth=&quot;1300.0&quot;&gt;&#10;         &lt;!-- 左侧页面列表 --&gt;&#10;         &lt;VBox prefHeight=&quot;657.0&quot; prefWidth=&quot;200.0&quot; style=&quot;-fx-border-color: #e0e0e0; -fx-border-width: 0 1 0 0;&quot;&gt;&#10;            &lt;Label style=&quot;-fx-padding: 5; -fx-font-weight: bold;&quot; text=&quot;页面列表&quot; /&gt;&#10;            &lt;ListView fx:id=&quot;pageListView&quot; prefHeight=&quot;619.0&quot; prefWidth=&quot;195.0&quot; VBox.vgrow=&quot;ALWAYS&quot; /&gt;&#10;         &lt;/VBox&gt;&#10;&#10;         &lt;!-- 右侧编辑区域 --&gt;&#10;         &lt;VBox spacing=&quot;10&quot; style=&quot;-fx-padding: 10;&quot; HBox.hgrow=&quot;ALWAYS&quot;&gt;&#10;            &lt;Label fx:id=&quot;pageNameLabel&quot; style=&quot;-fx-font-size: 14; -fx-font-weight: bold;&quot; text=&quot;页面名称:&quot; /&gt;&#10;            &lt;!-- 绘图Canvas将在这里动态添加 --&gt;&#10;            &lt;AnchorPane fx:id=&quot;drawingCanvasContainer&quot; HBox.hgrow=&quot;ALWAYS&quot; VBox.vgrow=&quot;ALWAYS&quot; /&gt;&#10;         &lt;/VBox&gt;&#10;&#10;         &lt;!-- 右侧属性编辑面板 --&gt;&#10;         &lt;VBox fx:id=&quot;propertyPanelContainer&quot; prefWidth=&quot;200.0&quot; /&gt;&#10;      &lt;/HBox&gt;&#10;   &lt;/children&gt;&#10;&lt;/AnchorPane&gt;&#10;" />
            </PendingDiffInfo>
          </value>
        </entry>
      </map>
    </option>
  </component>
</project>