diff --git a/chunky/src/java/se/llbit/chunky/ui/ChunkMap.java b/chunky/src/java/se/llbit/chunky/ui/ChunkMap.java index 8ef9b3dd5c..53576579fa 100644 --- a/chunky/src/java/se/llbit/chunky/ui/ChunkMap.java +++ b/chunky/src/java/se/llbit/chunky/ui/ChunkMap.java @@ -172,11 +172,7 @@ public ChunkMap(WorldMapLoader loader, ChunkyFxController controller, selectVisible.setGraphic(new ImageView(Icon.eye.fxImage())); selectVisible.setOnAction(event -> { - ChunkView chunkView = new ChunkView(view); // Make thread-local copy. - if (controller.getChunky().sceneInitialized()) { - controller.getChunky().getRenderController().getSceneProvider().withSceneProtected( - scene -> selectVisibleChunks(chunkView, scene)); - } + selectCameraVisibleChunks(); }); MenuItem exportZip = new MenuItem("Export selected chunks…"); @@ -214,6 +210,8 @@ public ChunkMap(WorldMapLoader loader, ChunkyFxController controller, loadSelection.setDisable(noChunksSelected); exportZip.setDisable(noChunksSelected); deleteChunks.setDisable(noChunksSelected); + + controller.disableMapMenuItems(noChunksSelected); }); } @@ -425,6 +423,14 @@ public int getHeight() { return mapView.getMapView().height; } + public void selectCameraVisibleChunks() { + ChunkView chunkView = new ChunkView(view); // Make thread-local copy. + if (controller.getChunky().sceneInitialized()) { + controller.getChunky().getRenderController().getSceneProvider().withSceneProtected( + scene -> selectVisibleChunks(chunkView, scene)); + } + } + public void onKeyPressed(KeyEvent keyEvent) { switch (keyEvent.getCode()) { case CONTROL: diff --git a/chunky/src/java/se/llbit/chunky/ui/RenderCanvasFx.java b/chunky/src/java/se/llbit/chunky/ui/RenderCanvasFx.java index f56985f843..3974faf8d8 100644 --- a/chunky/src/java/se/llbit/chunky/ui/RenderCanvasFx.java +++ b/chunky/src/java/se/llbit/chunky/ui/RenderCanvasFx.java @@ -72,7 +72,7 @@ public class RenderCanvasFx extends ScrollPane implements Repaintable, SceneStat private final AtomicBoolean painting = new AtomicBoolean(false); private final Canvas canvas; - private final Group guideGroup; + private final Group guideGroup = new Group(); private final StackPane canvasPane; private final Label noChunksLabel; private final RenderManager renderManager; @@ -81,6 +81,22 @@ public class RenderCanvasFx extends ScrollPane implements Repaintable, SceneStat private Vector2 target = new Vector2(0, 0); private Tooltip tooltip = new Tooltip(); + private CheckMenuItem showGuides = new CheckMenuItem("Show guides"); + private Line hGuide1 = new Line(); + private Line hGuide2 = new Line(); + private Line vGuide1 = new Line(); + private Line vGuide2 = new Line(); + + private RadioMenuItem percent25 = new RadioMenuItem(String.format("%d%%", 25)); + private RadioMenuItem percent50 = new RadioMenuItem(String.format("%d%%", 50)); + private RadioMenuItem percent75 = new RadioMenuItem(String.format("%d%%", 75)); + private RadioMenuItem percent100 = new RadioMenuItem(String.format("%d%%", 100)); + private RadioMenuItem percent150 = new RadioMenuItem(String.format("%d%%", 150)); + private RadioMenuItem percent200 = new RadioMenuItem(String.format("%d%%", 200)); + private RadioMenuItem percent300 = new RadioMenuItem(String.format("%d%%", 300)); + private RadioMenuItem percent400 = new RadioMenuItem(String.format("%d%%", 400)); + private RadioMenuItem fit = new RadioMenuItem("Fit to screen"); + private boolean fitToScreen = PersistentSettings.getCanvasFitToScreen(); private RenderStatusListener renderListener; @@ -110,11 +126,6 @@ public RenderCanvasFx(ChunkyFxController chunkyFxController, noChunksLabel.setTextAlignment(TextAlignment.CENTER); canvasPane.getChildren().add(noChunksLabel); - guideGroup = new Group(); - Line hGuide1 = new Line(); - Line hGuide2 = new Line(); - Line vGuide1 = new Line(); - Line vGuide2 = new Line(); guideGroup.getChildren().addAll(hGuide1, hGuide2, vGuide1, vGuide2); canvasPane.getChildren().add(guideGroup); @@ -183,44 +194,84 @@ public RenderCanvasFx(ChunkyFxController chunkyFxController, }); contextMenu.getItems().add(setTarget); - CheckMenuItem showGuides = new CheckMenuItem("Show guides"); showGuides.setSelected(false); showGuides.selectedProperty().addListener((observable, oldValue, newValue) -> { - hGuide1.setVisible(newValue); - hGuide2.setVisible(newValue); - vGuide1.setVisible(newValue); - vGuide2.setVisible(newValue); + changeShowGuides(newValue); + chunkyFxController.syncShowGuides(newValue); }); contextMenu.getItems().add(showGuides); Menu canvasScale = new Menu("Canvas scale"); ToggleGroup scaleGroup = new ToggleGroup(); - for (int percent : new int[] { 25, 50, 75, 100, 150, 200, 300, 400 }) { - RadioMenuItem item = new RadioMenuItem(String.format("%d%%", percent)); - item.setToggleGroup(scaleGroup); - item.setSelected(PersistentSettings.getCanvasScale() == percent && !fitToScreen); - item.setOnAction(e -> { - updateCanvasScale(percent / 100.0); - PersistentSettings.setCanvasScale(percent); - if (fitToScreen) { - fitToScreen = false; - PersistentSettings.setCanvasFitToScreen(false); - } - }); - canvasScale.getItems().add(item); - } - contextMenu.getItems().add(canvasScale); + percent25.setToggleGroup(scaleGroup); + percent50.setToggleGroup(scaleGroup); + percent75.setToggleGroup(scaleGroup); + percent100.setToggleGroup(scaleGroup); + percent150.setToggleGroup(scaleGroup); + percent200.setToggleGroup(scaleGroup); + percent300.setToggleGroup(scaleGroup); + percent400.setToggleGroup(scaleGroup); + fit.setToggleGroup(scaleGroup); - RadioMenuItem fit = new RadioMenuItem("Fit to Screen"); + percent25.setSelected(PersistentSettings.getCanvasScale() == 25 && !fitToScreen); + percent50.setSelected(PersistentSettings.getCanvasScale() == 50 && !fitToScreen); + percent75.setSelected(PersistentSettings.getCanvasScale() == 75 && !fitToScreen); + percent100.setSelected(PersistentSettings.getCanvasScale() == 100 && !fitToScreen); + percent150.setSelected(PersistentSettings.getCanvasScale() == 150 && !fitToScreen); + percent200.setSelected(PersistentSettings.getCanvasScale() == 200 && !fitToScreen); + percent300.setSelected(PersistentSettings.getCanvasScale() == 300 && !fitToScreen); + percent400.setSelected(PersistentSettings.getCanvasScale() == 400 && !fitToScreen); fit.setSelected(fitToScreen); - fit.setToggleGroup(scaleGroup); + + percent25.setOnAction(e -> { + changeCanvasScale(25); + chunkyFxController.syncCanvasScale(25); + }); + percent50.setOnAction(e -> { + changeCanvasScale(50); + chunkyFxController.syncCanvasScale(50); + }); + percent75.setOnAction(e -> { + changeCanvasScale(75); + chunkyFxController.syncCanvasScale(75); + }); + percent100.setOnAction(e -> { + changeCanvasScale(100); + chunkyFxController.syncCanvasScale(100); + }); + percent150.setOnAction(e -> { + changeCanvasScale(150); + chunkyFxController.syncCanvasScale(150); + }); + percent200.setOnAction(e -> { + changeCanvasScale(200); + chunkyFxController.syncCanvasScale(200); + }); + percent300.setOnAction(e -> { + changeCanvasScale(300); + chunkyFxController.syncCanvasScale(300); + }); + percent400.setOnAction(e -> { + changeCanvasScale(400); + chunkyFxController.syncCanvasScale(400); + }); fit.setOnAction(e -> { - fitToScreen = true; - PersistentSettings.setCanvasFitToScreen(true); - updateCanvasFit(); + changeFitToScreen(); + chunkyFxController.syncFitToScreen(); }); + + canvasScale.getItems().add(percent25); + canvasScale.getItems().add(percent50); + canvasScale.getItems().add(percent75); + canvasScale.getItems().add(percent100); + canvasScale.getItems().add(percent150); + canvasScale.getItems().add(percent200); + canvasScale.getItems().add(percent300); + canvasScale.getItems().add(percent400); canvasScale.getItems().add(fit); + contextMenu.getItems().add(canvasScale); + if (fitToScreen) { updateCanvasFit(); } else { @@ -341,6 +392,56 @@ public RenderCanvasFx(ChunkyFxController chunkyFxController, }); } + public void changeShowGuides(boolean value) { + hGuide1.setVisible(value); + hGuide2.setVisible(value); + vGuide1.setVisible(value); + vGuide2.setVisible(value); + } + + public void syncShowGuides(boolean value) { + showGuides.setSelected(value); + } + + public void changeCanvasScale(int percent) { + updateCanvasScale(percent / 100.0); + PersistentSettings.setCanvasScale(percent); + if (fitToScreen) { + fitToScreen = false; + PersistentSettings.setCanvasFitToScreen(false); + } + } + + public void syncCanvasScale(int percent) { + if (percent == 25) { + percent25.setSelected(true); + } else if (percent == 50) { + percent50.setSelected(true); + } else if (percent == 75) { + percent75.setSelected(true); + } else if (percent == 100) { + percent100.setSelected(true); + } else if (percent == 150) { + percent150.setSelected(true); + } else if (percent == 200) { + percent200.setSelected(true); + } else if (percent == 300) { + percent300.setSelected(true); + } else if (percent == 400) { + percent400.setSelected(true); + } + } + + public void changeFitToScreen() { + fitToScreen = true; + PersistentSettings.setCanvasFitToScreen(true); + updateCanvasFit(); + } + + public void syncFitToScreen() { + fit.setSelected(true); + } + private void updateCanvasPane() { Bounds bounds = getViewportBounds(); canvasPane.setMinWidth(Math.max(canvas.getWidth() * canvas.getScaleX(), bounds.getWidth())); diff --git a/chunky/src/java/se/llbit/chunky/ui/controller/ChunkyFxController.java b/chunky/src/java/se/llbit/chunky/ui/controller/ChunkyFxController.java index 65f248c607..1268d06518 100644 --- a/chunky/src/java/se/llbit/chunky/ui/controller/ChunkyFxController.java +++ b/chunky/src/java/se/llbit/chunky/ui/controller/ChunkyFxController.java @@ -133,6 +133,29 @@ public class ChunkyFxController @FXML private MenuItem saveSceneCopy; @FXML private MenuItem loadScene; @FXML private MenuItem loadSceneFile; + + @FXML private MenuItem newScene; + @FXML private MenuItem loadSelection; + @FXML private MenuItem clearSelection; + @FXML private MenuItem selectVisible; + @FXML private MenuItem exportZip; + @FXML private MenuItem exportPng; + @FXML private MenuItem deleteChunks; + + @FXML private CheckMenuItem showGuides; + @FXML private Menu canvasScale; + @FXML private RadioMenuItem percent25; + @FXML private RadioMenuItem percent50; + @FXML private RadioMenuItem percent75; + @FXML private RadioMenuItem percent100; + @FXML private RadioMenuItem percent150; + @FXML private RadioMenuItem percent200; + @FXML private RadioMenuItem percent300; + @FXML private RadioMenuItem percent400; + @FXML private RadioMenuItem fit; + @FXML private MenuItem saveCurrentFrame; + @FXML private MenuItem copyFrame; + @FXML private MenuItem creditsMenuItem; @FXML private ProgressBar progressBar; @@ -147,6 +170,8 @@ public class ChunkyFxController @FXML private ToggleButton pause; @FXML private ToggleButton reset; + private boolean fitToScreen = PersistentSettings.getCanvasFitToScreen(); + RenderControlsFxController sceneControls; private File saveFrameDirectory = new File(System.getProperty("user.dir")); @@ -459,6 +484,98 @@ public File getSceneFile(String fileName) { } }); + newScene.setGraphic(new ImageView(Icon.sky.fxImage())); + newScene.setOnAction(event -> { + SceneManager sceneManager = getRenderController().getSceneManager(); + sceneManager + .loadFreshChunks(mapLoader.getWorld(), getChunkSelection().getSelection()); + }); + newScene.setDisable(chunkSelection.isEmpty()); + + loadSelection.setOnAction(event -> { + SceneManager sceneManager = getRenderController().getSceneManager(); + sceneManager + .loadChunks(mapLoader.getWorld(), getChunkSelection().getSelection()); + }); + loadSelection.setDisable(chunkSelection.isEmpty()); + + clearSelection.setGraphic(new ImageView(Icon.clear.fxImage())); + clearSelection.setOnAction(event -> chunkSelection.clearSelection()); + clearSelection.setDisable(chunkSelection.isEmpty()); + + selectVisible.setGraphic(new ImageView(Icon.eye.fxImage())); + selectVisible.setOnAction(event -> map.selectCameraVisibleChunks()); + + exportZip.setOnAction(e -> exportZip()); + exportZip.setDisable(chunkSelection.size() == 0); + + exportPng.setOnAction(e -> exportMapView()); + + ImageView deleteChunksIcon = new ImageView(Icon.tntSide.fxImage()); + deleteChunksIcon.setFitHeight(16); + deleteChunksIcon.setPreserveRatio(true); + deleteChunks.setGraphic(deleteChunksIcon); + deleteChunks.setOnAction(e -> promptDeleteSelectedChunks()); + deleteChunks.setDisable(chunkSelection.size() == 0); + + showGuides.setSelected(false); + showGuides.selectedProperty().addListener((observable, oldValue, newValue) -> { + canvas.changeShowGuides(newValue); + canvas.syncShowGuides(newValue); + }); + + percent25.setSelected(PersistentSettings.getCanvasScale() == 25 && !fitToScreen); + percent50.setSelected(PersistentSettings.getCanvasScale() == 50 && !fitToScreen); + percent75.setSelected(PersistentSettings.getCanvasScale() == 75 && !fitToScreen); + percent100.setSelected(PersistentSettings.getCanvasScale() == 100 && !fitToScreen); + percent150.setSelected(PersistentSettings.getCanvasScale() == 150 && !fitToScreen); + percent200.setSelected(PersistentSettings.getCanvasScale() == 200 && !fitToScreen); + percent300.setSelected(PersistentSettings.getCanvasScale() == 300 && !fitToScreen); + percent400.setSelected(PersistentSettings.getCanvasScale() == 400 && !fitToScreen); + fit.setSelected(fitToScreen); + + percent25.setOnAction(e -> { + canvas.changeCanvasScale(25); + canvas.syncCanvasScale(25); + }); + percent50.setOnAction(e -> { + canvas.changeCanvasScale(50); + canvas.syncCanvasScale(50); + }); + percent75.setOnAction(e -> { + canvas.changeCanvasScale(75); + canvas.syncCanvasScale(75); + }); + percent100.setOnAction(e -> { + canvas.changeCanvasScale(100); + canvas.syncCanvasScale(100); + }); + percent150.setOnAction(e -> { + canvas.changeCanvasScale(150); + canvas.syncCanvasScale(150); + }); + percent200.setOnAction(e -> { + canvas.changeCanvasScale(200); + + canvas.syncCanvasScale(200); + }); + percent300.setOnAction(e -> { + canvas.changeCanvasScale(300); + canvas.syncCanvasScale(300); + }); + percent400.setOnAction(e -> { + canvas.changeCanvasScale(400); + canvas.syncCanvasScale(400); + }); + fit.setOnAction(e -> { + canvas.changeFitToScreen(); + canvas.syncFitToScreen(); + }); + + saveCurrentFrame.setOnAction(e -> saveCurrentFrame()); + + copyFrame.setOnAction(e -> copyCurrentFrame()); + Log.setReceiver(new UILogReceiver(), Level.ERROR, Level.WARNING); mapLoader = new WorldMapLoader(this, mapView); @@ -719,6 +836,42 @@ public File getSceneFile(String fileName) { PersistentSettings.setSppTargetDefault(scene.getTargetSpp())); } + public void disableMapMenuItems(boolean value) { + newScene.setDisable(value); + loadSelection.setDisable(value); + clearSelection.setDisable(value); + exportZip.setDisable(value); + deleteChunks.setDisable(value); + } + + public void syncShowGuides(boolean value) { + showGuides.setSelected(value); + } + + public void syncCanvasScale(int percent) { + if (percent == 25) { + percent25.setSelected(true); + } else if (percent == 50) { + percent50.setSelected(true); + } else if (percent == 75) { + percent75.setSelected(true); + } else if (percent == 100) { + percent100.setSelected(true); + } else if (percent == 150) { + percent150.setSelected(true); + } else if (percent == 200) { + percent200.setSelected(true); + } else if (percent == 300) { + percent300.setSelected(true); + } else if (percent == 400) { + percent400.setSelected(true); + } + } + + public void syncFitToScreen() { + fit.setSelected(true); + } + public void openSceneChooser() { try { if (this.sceneChooser == null) { diff --git a/chunky/src/res/se/llbit/chunky/ui/Chunky.fxml b/chunky/src/res/se/llbit/chunky/ui/Chunky.fxml index 5b1f555ced..befcacb330 100644 --- a/chunky/src/res/se/llbit/chunky/ui/Chunky.fxml +++ b/chunky/src/res/se/llbit/chunky/ui/Chunky.fxml @@ -21,8 +21,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +