Refactoring Phase 3: AnimPreview + AnimSet aus EditorApp extrahiert
AnimPreviewController und AnimSetController in de.blight.editor.toolset.anim/ extrahiert (~1500 Zeilen raus). EditorApp: 13.187 → 11.650 Zeilen. ToolContext um registry-Parameter erweitert, damit AnimSetController sich nach Picker-Dialog selbst aktivieren kann. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ import java.util.function.Supplier;
|
||||
* @param viewportSupplier Liefert den JME3-Viewport-StackPane
|
||||
* @param assetRoot Wurzelpfad der blight-assets (für Dateidialoge / IO)
|
||||
* @param switchToWorld Wechselt zurück zum Welteneditor (für "← Welteneditor"-Buttons)
|
||||
* @param registry ToolRegistry (damit Controller sich selbst aktivieren können)
|
||||
*/
|
||||
public record ToolContext(
|
||||
SharedInput input,
|
||||
@@ -36,5 +37,6 @@ public record ToolContext(
|
||||
Consumer<Node> setMainToolbar,
|
||||
Supplier<StackPane> viewportSupplier,
|
||||
Path assetRoot,
|
||||
Runnable switchToWorld
|
||||
Runnable switchToWorld,
|
||||
ToolRegistry registry
|
||||
) {}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
package de.blight.editor.toolset.anim;
|
||||
|
||||
import de.blight.editor.ToolContext;
|
||||
import de.blight.editor.ToolController;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.*;
|
||||
|
||||
import static de.blight.editor.toolset.UiHelper.*;
|
||||
|
||||
public class AnimPreviewController implements ToolController {
|
||||
|
||||
private final ToolContext ctx;
|
||||
|
||||
private ImageView animPreviewView;
|
||||
private ListView<String> animClipListView;
|
||||
private Label animPreviewStatusLabel;
|
||||
private ComboBox<String> animPreviewModelCombo; // immer null — dead-code-Stub, null-Guards schützen
|
||||
private String animCurrentModelPath = null;
|
||||
private double animPrevDragX, animPrevDragY;
|
||||
|
||||
public AnimPreviewController(ToolContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toolId() { return "animpreview"; }
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
ctx.input().animPreviewSequenceQueue.clear();
|
||||
|
||||
animPreviewView = new ImageView(ctx.input().animPreviewImage);
|
||||
animPreviewView.setPreserveRatio(true);
|
||||
animPreviewView.setSmooth(true);
|
||||
|
||||
StackPane previewPane = new StackPane(animPreviewView);
|
||||
previewPane.setStyle("-fx-background-color: #2e2e38;");
|
||||
|
||||
previewPane.widthProperty().addListener((obs, ov, nv) -> {
|
||||
animPreviewView.setFitWidth(nv.doubleValue());
|
||||
ctx.input().animPreviewW = Math.max(64, nv.intValue());
|
||||
});
|
||||
previewPane.heightProperty().addListener((obs, ov, nv) -> {
|
||||
animPreviewView.setFitHeight(nv.doubleValue());
|
||||
ctx.input().animPreviewH = Math.max(64, nv.intValue());
|
||||
});
|
||||
previewPane.setOnMousePressed(e -> {
|
||||
animPrevDragX = e.getSceneX();
|
||||
animPrevDragY = e.getSceneY();
|
||||
});
|
||||
previewPane.setOnMouseDragged(e -> {
|
||||
double dx = e.getSceneX() - animPrevDragX;
|
||||
double dy = e.getSceneY() - animPrevDragY;
|
||||
animPrevDragX = e.getSceneX();
|
||||
animPrevDragY = e.getSceneY();
|
||||
ctx.input().animPreviewRotY += (float) (dx * 0.5);
|
||||
ctx.input().animPreviewRotX = (float) Math.max(-80, Math.min(80,
|
||||
ctx.input().animPreviewRotX - dy * 0.3));
|
||||
});
|
||||
previewPane.setOnScroll(e -> {
|
||||
double factor = e.getDeltaY() > 0 ? 0.9 : 1.1;
|
||||
ctx.input().animPreviewZoom = (float) Math.max(0.05,
|
||||
Math.min(20.0, ctx.input().animPreviewZoom * factor));
|
||||
});
|
||||
|
||||
ctx.setCenterView().accept(previewPane);
|
||||
ctx.setMainToolbar().accept(buildAnimPreviewToolBar());
|
||||
ctx.setRightPanel().accept(buildAnimPreviewPanel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {}
|
||||
|
||||
@Override
|
||||
public void onFrame() {
|
||||
if (ctx.input().animPreviewResized) {
|
||||
ctx.input().animPreviewResized = false;
|
||||
if (animPreviewView != null) {
|
||||
animPreviewView.setImage(ctx.input().animPreviewImage);
|
||||
}
|
||||
}
|
||||
java.util.List<String> newClips = ctx.input().animPreviewClips.getAndSet(null);
|
||||
if (newClips != null && animClipListView != null) {
|
||||
animClipListView.getItems().setAll(newClips);
|
||||
if (!newClips.isEmpty()) animClipListView.getSelectionModel().selectFirst();
|
||||
}
|
||||
String loadedPath = ctx.input().animPreviewLoadedPath.getAndSet(null);
|
||||
if (loadedPath != null) {
|
||||
animCurrentModelPath = loadedPath;
|
||||
}
|
||||
String animStatus = ctx.input().animPreviewStatus;
|
||||
if (animStatus != null) {
|
||||
ctx.input().animPreviewStatus = null;
|
||||
if (animPreviewStatusLabel != null) animPreviewStatusLabel.setText(animStatus);
|
||||
}
|
||||
String animOp = ctx.input().animOpStatus;
|
||||
if (animOp != null) {
|
||||
ctx.input().animOpStatus = null;
|
||||
if (animPreviewStatusLabel != null) animPreviewStatusLabel.setText(animOp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Wird vom EditorApp-Baum-Handler aufgerufen, wenn ein Modell angeklickt wird. */
|
||||
public void setStatusText(String text) {
|
||||
if (animPreviewStatusLabel != null) animPreviewStatusLabel.setText(text);
|
||||
}
|
||||
|
||||
/** Wird vom EditorApp-Baum-Handler aufgerufen, bevor ein neues Modell geladen wird. */
|
||||
public void clearClipList() {
|
||||
if (animClipListView != null) animClipListView.getItems().clear();
|
||||
}
|
||||
|
||||
private ToolBar buildAnimPreviewToolBar() {
|
||||
Button backBtn = new Button("← Welteneditor");
|
||||
backBtn.setOnAction(e -> ctx.switchToWorld().run());
|
||||
Label label = new Label("Animations Viewer");
|
||||
label.setStyle("-fx-font-weight: bold; -fx-font-size: 13;");
|
||||
ToolBar tb = new ToolBar();
|
||||
tb.getItems().addAll(backBtn, new Separator(Orientation.VERTICAL), label);
|
||||
return tb;
|
||||
}
|
||||
|
||||
private VBox buildAnimPreviewPanel() {
|
||||
VBox inner = new VBox(8);
|
||||
inner.setPadding(new Insets(10));
|
||||
|
||||
// ── Animationen ────────────────────────────────────────────────────────
|
||||
inner.getChildren().addAll(sectionTitle("Animationen"), new Separator());
|
||||
animClipListView = new ListView<>();
|
||||
animClipListView.setPrefHeight(200);
|
||||
animClipListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
|
||||
Button playBtn = new Button("▶ Abspielen");
|
||||
Button stopBtn = new Button("■ Stop");
|
||||
playBtn.setMaxWidth(Double.MAX_VALUE);
|
||||
stopBtn.setMaxWidth(Double.MAX_VALUE);
|
||||
playBtn.setStyle("-fx-font-weight: bold;");
|
||||
playBtn.setOnAction(e -> {
|
||||
String clip = animClipListView.getSelectionModel().getSelectedItem();
|
||||
if (clip != null) ctx.input().animPreviewPlayClip = clip;
|
||||
});
|
||||
stopBtn.setOnAction(e -> ctx.input().animPreviewPlayClip = "");
|
||||
animClipListView.setOnMouseClicked(e -> {
|
||||
if (e.getClickCount() == 2) {
|
||||
String clip = animClipListView.getSelectionModel().getSelectedItem();
|
||||
if (clip != null) ctx.input().animPreviewPlayClip = clip;
|
||||
}
|
||||
});
|
||||
HBox btnRow = new HBox(6, playBtn, stopBtn);
|
||||
HBox.setHgrow(playBtn, Priority.ALWAYS);
|
||||
HBox.setHgrow(stopBtn, Priority.ALWAYS);
|
||||
inner.getChildren().addAll(animClipListView, btnRow);
|
||||
|
||||
// ── Steuerung ──────────────────────────────────────────────────────────
|
||||
inner.getChildren().addAll(new Separator(), sectionTitle("Steuerung"), new Separator());
|
||||
|
||||
CheckBox loopCB = new CheckBox("Loop");
|
||||
loopCB.setSelected(true);
|
||||
loopCB.setOnAction(e -> ctx.input().animPreviewLoop = loopCB.isSelected());
|
||||
|
||||
Label speedLbl = new Label("Geschwindigkeit");
|
||||
Slider speedSlider = new Slider(0.1, 3.0, 1.0);
|
||||
speedSlider.setShowTickMarks(true);
|
||||
speedSlider.setShowTickLabels(true);
|
||||
speedSlider.setMajorTickUnit(1.0);
|
||||
speedSlider.valueProperty().addListener((obs, ov, nv) ->
|
||||
ctx.input().animPreviewSpeed = nv.floatValue());
|
||||
inner.getChildren().addAll(loopCB, speedLbl, withField(speedSlider, "%.2f"));
|
||||
|
||||
// ── Status ─────────────────────────────────────────────────────────────
|
||||
inner.getChildren().add(new Separator());
|
||||
animPreviewStatusLabel = new Label("");
|
||||
animPreviewStatusLabel.setWrapText(true);
|
||||
animPreviewStatusLabel.setStyle("-fx-font-size: 11; -fx-text-fill: #c00;");
|
||||
inner.getChildren().add(animPreviewStatusLabel);
|
||||
|
||||
ScrollPane scroll = new ScrollPane(inner);
|
||||
scroll.setFitToWidth(true);
|
||||
scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
scroll.setStyle("-fx-background-color: transparent; -fx-background: transparent;");
|
||||
VBox panel = new VBox(scroll);
|
||||
VBox.setVgrow(scroll, Priority.ALWAYS);
|
||||
panel.setPrefWidth(270);
|
||||
panel.setStyle("-fx-background-color: #f0f0f0; -fx-border-color: #ccc; -fx-border-width: 0 0 0 1;");
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user