Support saving any page snapshot to a file

This commit is contained in:
mkpaz 2023-05-19 22:52:54 +04:00
parent bbec330216
commit 38ce8e9446
7 changed files with 72 additions and 4 deletions

@ -40,7 +40,8 @@ public class Launcher extends Application {
public static final List<KeyCodeCombination> SUPPORTED_HOTKEYS = List.of(
new KeyCodeCombination(KeyCode.SLASH),
new KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN)
new KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN),
new KeyCodeCombination(KeyCode.W, KeyCombination.CONTROL_DOWN)
);
public static void main(String[] args) {

@ -6,20 +6,30 @@ import static atlantafx.sampler.event.PageEvent.Action;
import static javafx.scene.layout.Priority.ALWAYS;
import atlantafx.sampler.event.DefaultEventBus;
import atlantafx.sampler.event.HotkeyEvent;
import atlantafx.sampler.event.PageEvent;
import atlantafx.sampler.event.ThemeEvent;
import atlantafx.sampler.layout.MainModel.SubLayer;
import atlantafx.sampler.page.Page;
import atlantafx.sampler.theme.ThemeManager;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;
import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import javafx.util.Duration;
import javax.imageio.ImageIO;
class MainLayer extends BorderPane {
@ -42,6 +52,38 @@ class MainLayer extends BorderPane {
// keyboard navigation won't work without focus
Platform.runLater(sidebar::begForFocus);
var snapshotKeys = new KeyCodeCombination(KeyCode.W, KeyCombination.CONTROL_DOWN);
DefaultEventBus.getInstance().subscribe(HotkeyEvent.class, e -> {
if (Objects.equals(e.getKeys(), snapshotKeys)) {
final Page page = (Page) subLayerPane.getChildren().stream()
.filter(c -> c instanceof Page)
.findFirst()
.orElse(null);
if (page == null || page.getSnapshotTarget() == null) {
return;
}
var fileChooser = new FileChooser();
fileChooser.setInitialDirectory(Paths.get(System.getProperty("user.home")).toFile());
fileChooser.setInitialFileName("snapshot.png");
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("Image Files", "*.png")
);
var file = fileChooser.showSaveDialog(getScene().getWindow());
if (file == null) {
return;
}
try {
WritableImage img = page.getSnapshotTarget().snapshot(new SnapshotParameters(), null);
ImageIO.write(SwingFXUtils.fromFXImage(img, null), "png", file);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
});
}
private void createView() {

@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable;
public abstract class AbstractPage extends StackPane implements Page {
protected final VBox userContent = new VBox();
protected final StackPane userContentArea = new StackPane(userContent);
protected Overlay overlay;
protected boolean isRendered = false;
@ -33,7 +34,6 @@ public abstract class AbstractPage extends StackPane implements Page {
}
protected void createPageLayout() {
var userContentArea = new StackPane(userContent);
userContentArea.setAlignment(Pos.TOP_CENTER);
userContent.setMinWidth(Math.min(Page.MAX_WIDTH, 800));
userContent.setMaxWidth(Math.min(Page.MAX_WIDTH, 800));
@ -65,6 +65,11 @@ public abstract class AbstractPage extends StackPane implements Page {
return URI.create(String.format(JFX_JAVADOC_URI_TEMPLATE, "control/" + getName()));
}
@Override
public Node getSnapshotTarget() {
return userContentArea;
}
@Override
public void reset() {
}

@ -37,6 +37,7 @@ public abstract class OutlinePage extends StackPane implements Page {
protected final ScrollPane scrollPane = new ScrollPane();
protected final VBox userContent = new VBox();
protected final StackPane userContentArea = new StackPane(userContent);
protected final Outline outline = new Outline(createOutlineHandler());
protected Overlay overlay;
@ -52,7 +53,6 @@ public abstract class OutlinePage extends StackPane implements Page {
}
protected void createPageLayout() {
var userContentArea = new StackPane(userContent);
StackPane.setMargin(userContent, new Insets(0, OUTLINE_WIDTH, 0, 0));
userContent.setMinWidth(Page.MAX_WIDTH - OUTLINE_WIDTH - 100);
userContent.setMaxWidth(Page.MAX_WIDTH - OUTLINE_WIDTH - 100);
@ -177,6 +177,11 @@ public abstract class OutlinePage extends StackPane implements Page {
return URI.create(String.format(JFX_JAVADOC_URI_TEMPLATE, "control/" + getName()));
}
@Override
public Node getSnapshotTarget() {
return userContentArea;
}
@Override
public void reset() {
}

@ -27,6 +27,7 @@ import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import net.datafaker.Faker;
import org.jetbrains.annotations.Nullable;
import org.kordamp.ikonli.feather.Feather;
@ -58,6 +59,8 @@ public interface Page {
@Nullable URI getJavadocUri();
@Nullable Node getSnapshotTarget();
void reset();
default <T> List<T> generate(Supplier<T> supplier, int count) {

@ -11,6 +11,7 @@ import java.io.IOException;
import java.net.URI;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Pane;
@ -21,6 +22,7 @@ import org.jetbrains.annotations.Nullable;
public final class OverviewPage extends ScrollPane implements Page {
public static final String NAME = "Overview";
private VBox wrapper;
@Override
public String getName() {
@ -31,7 +33,7 @@ public final class OverviewPage extends ScrollPane implements Page {
super();
try {
var wrapper = new VBox();
wrapper = new VBox();
wrapper.setAlignment(Pos.TOP_CENTER);
var loader = new FXMLLoader(
@ -72,6 +74,11 @@ public final class OverviewPage extends ScrollPane implements Page {
return null;
}
@Override
public Node getSnapshotTarget() {
return wrapper;
}
@Override
public void reset() {
}

@ -111,6 +111,11 @@ public abstract class ShowcasePage extends StackPane implements Page {
return null;
}
@Override
public Node getSnapshotTarget() {
return showCaseContent;
}
@Override
public void reset() {
}