From 9f55ccd61b8edc3999d2f85b02f7c200964e09a4 Mon Sep 17 00:00:00 2001
From: yangkui <752544765@qq.com>
Date: Mon, 30 Jan 2023 12:33:11 +0800
Subject: [PATCH] fix bug
---
app/pom.xml | 6 -
.../navclub/nes4j/app/control/IconPopup.java | 72 ++++++++++++
.../nes4j/app/control/StatusIndicator.java | 104 ------------------
.../nes4j/app/control/skin/IconPopupSkin.java | 44 ++++++++
.../cn/navclub/nes4j/app/view/GameWorld.java | 16 ++-
.../app/assets/css/{common.css => Common.css} | 2 +-
.../nes4j/app/assets/css/DException.css | 2 +-
.../navclub/nes4j/app/assets/css/DHandle.css | 2 +-
.../nes4j/app/assets/css/DNesHeaderStyle.css | 2 +-
.../nes4j/app/assets/css/DebuggerStyle.css | 2 +-
.../nes4j/app/assets/css/GameHallStyle.css | 7 +-
.../cn/navclub/nes4j/app/assets/css/Nes4j.css | 2 +-
.../nes4j/app/assets/css/SystemPalette.css | 2 +-
.../nes4j/app/assets/css/TextPopup.css | 9 ++
.../cn/navclub/nes4j/app/assets/img/speed.png | Bin 0 -> 5116 bytes
.../main/java/cn/navclub/nes4j/bin/NES.java | 17 ++-
build/icon/nes4j.ico | Bin 0 -> 67646 bytes
build/jpackage.sh | 5 +-
18 files changed, 168 insertions(+), 126 deletions(-)
create mode 100644 app/src/main/java/cn/navclub/nes4j/app/control/IconPopup.java
delete mode 100644 app/src/main/java/cn/navclub/nes4j/app/control/StatusIndicator.java
create mode 100644 app/src/main/java/cn/navclub/nes4j/app/control/skin/IconPopupSkin.java
rename app/src/main/resources/cn/navclub/nes4j/app/assets/css/{common.css => Common.css} (99%)
create mode 100644 app/src/main/resources/cn/navclub/nes4j/app/assets/css/TextPopup.css
create mode 100644 app/src/main/resources/cn/navclub/nes4j/app/assets/img/speed.png
create mode 100644 build/icon/nes4j.ico
diff --git a/app/pom.xml b/app/pom.xml
index d3311e9..8d79b56 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -36,12 +36,6 @@
javafx-fxml
${javafx.version}
-
-
- org.controlsfx
- controlsfx
- 11.1.2
-
cn.navclub
nes4j-bin
diff --git a/app/src/main/java/cn/navclub/nes4j/app/control/IconPopup.java b/app/src/main/java/cn/navclub/nes4j/app/control/IconPopup.java
new file mode 100644
index 0000000..063b3e3
--- /dev/null
+++ b/app/src/main/java/cn/navclub/nes4j/app/control/IconPopup.java
@@ -0,0 +1,72 @@
+package cn.navclub.nes4j.app.control;
+
+import cn.navclub.nes4j.app.control.skin.IconPopupSkin;
+import javafx.animation.FadeTransition;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.scene.control.PopupControl;
+import javafx.scene.control.Skin;
+import javafx.scene.image.Image;
+import javafx.stage.Screen;
+import javafx.util.Duration;
+
+/**
+ * A icon popup implement.
+ *
+ * @author GZYangKui
+ */
+public class IconPopup extends PopupControl {
+ private final FadeTransition transition;
+ private final ObjectProperty image;
+
+ public IconPopup() {
+ this.setAutoFix(true);
+ this.transition = new FadeTransition();
+ this.transition.setToValue(0);
+ this.transition.setFromValue(1.0);
+ this.transition.setOnFinished(event -> this.hide());
+ this.transition.setDuration(Duration.millis(1000));
+ this.image = new SimpleObjectProperty<>(this, "image", null);
+
+ this.setOnShown(event -> {
+ this.transition.stop();
+ this.transition.setNode(this.getSkin().getNode());
+ this.transition.setDelay(Duration.millis(500));
+ this.transition.play();
+ this.calculateXY();
+ });
+ }
+
+ public IconPopup(Image image) {
+ this();
+ this.setImage(image);
+ }
+
+ @Override
+ protected Skin> createDefaultSkin() {
+ return new IconPopupSkin(this);
+ }
+
+ public Image getImage() {
+ return image.get();
+ }
+
+ public ObjectProperty imageProperty() {
+ return image;
+ }
+
+ public void setImage(Image image) {
+ this.image.set(image);
+ }
+
+ private void calculateXY() {
+ var screen = Screen.getPrimary();
+ var rect = screen.getVisualBounds();
+
+ var x = (rect.getWidth() - this.getWidth()) / 2;
+ var y = (rect.getHeight() - this.getHeight()) - 10;
+
+ this.setX(x);
+ this.setY(y);
+ }
+}
diff --git a/app/src/main/java/cn/navclub/nes4j/app/control/StatusIndicator.java b/app/src/main/java/cn/navclub/nes4j/app/control/StatusIndicator.java
deleted file mode 100644
index d577fd1..0000000
--- a/app/src/main/java/cn/navclub/nes4j/app/control/StatusIndicator.java
+++ /dev/null
@@ -1,104 +0,0 @@
-//package cn.navclub.nes4j.app.control;
-//
-//import cn.navclub.nes4j.app.assets.FXResource;
-//import javafx.animation.FadeTransition;
-//import javafx.beans.property.ObjectProperty;
-//import javafx.beans.property.SimpleObjectProperty;
-//import javafx.collections.ListChangeListener;
-//import javafx.scene.Node;
-//import javafx.scene.Parent;
-//
-//import javafx.scene.image.Image;
-//import javafx.scene.image.ImageView;
-//import javafx.scene.layout.VBox;
-//import javafx.util.Duration;
-//
-///**
-// * Custom status indicator control,current implement only support {@link Parent} and subclass.
-// *
-// * @author GZYangKui
-// */
-//public class StatusIndicator extends VBox {
-// private static final Image DEFAULT_IMAGE = FXResource.loadImage("empty.png");
-// private static final Image DEFAULT_ERROR_IMAGE = FXResource.loadImage("error.png");
-//
-// private final ImageView icon;
-// private ObjectProperty attach;
-// private final ObjectProperty type;
-// private ListChangeListener listChangeListener;
-//
-// public StatusIndicator() {
-// this.icon = new ImageView();
-// this.type = new SimpleObjectProperty<>(this, "type", null);
-//
-// this.getStyleClass().add("status-indicator");
-// this.getChildren().add(this.icon);
-//
-//
-// //listener type change
-// this.type.addListener(((observable, oldValue, newValue) -> {
-// var image = switch (newValue) {
-// case ERROR -> DEFAULT_ERROR_IMAGE;
-// case LOAD -> DEFAULT_LOAD_IMAGE;
-// default -> DEFAULT_IMAGE;
-// };
-// this.icon.setImage(image);
-// }));
-// }
-//
-// private ListChangeListener listChangeListener() {
-// return c -> {
-// var children = this.getAttach().getChildrenUnmodifiable();
-// if (children.size() > 0) {
-// transition.play();
-// } else {
-// this.setVisible(true);
-// }
-// };
-// }
-//
-// public Parent getAttach() {
-// return this.attachProperty().get();
-// }
-//
-// public ObjectProperty attachProperty() {
-// if (this.attach == null) {
-// this.attach = new SimpleObjectProperty<>(this, "attach", null);
-// }
-// return attach;
-// }
-//
-// public void setAttach(Parent attach) {
-// var oldValue = this.getAttach();
-// if (oldValue == attach) {
-// return;
-// }
-// if (oldValue != null) {
-// oldValue.getChildrenUnmodifiable().removeListener(this.listChangeListener);
-// }
-// this.listChangeListener = this.listChangeListener();
-// attach.getChildrenUnmodifiable().addListener(this.listChangeListener);
-// this.attachProperty().set(attach);
-// }
-//
-// public Type getType() {
-// return type.get();
-// }
-//
-// public ObjectProperty typeProperty() {
-// return type;
-// }
-//
-// public void setType(Type type) {
-// this.type.set(type);
-// }
-//
-// public enum Type {
-// //Empty
-// EMPTY,
-// //Load
-// LOAD,
-// //error
-// ERROR
-// }
-//}
diff --git a/app/src/main/java/cn/navclub/nes4j/app/control/skin/IconPopupSkin.java b/app/src/main/java/cn/navclub/nes4j/app/control/skin/IconPopupSkin.java
new file mode 100644
index 0000000..bc9d20f
--- /dev/null
+++ b/app/src/main/java/cn/navclub/nes4j/app/control/skin/IconPopupSkin.java
@@ -0,0 +1,44 @@
+package cn.navclub.nes4j.app.control.skin;
+
+import cn.navclub.nes4j.app.assets.FXResource;
+import cn.navclub.nes4j.app.control.IconPopup;
+import javafx.scene.Node;
+import javafx.scene.control.Skin;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.VBox;
+
+
+public class IconPopupSkin implements Skin {
+ private VBox node;
+ @SuppressWarnings("all")
+ private final ImageView icon;
+ private final IconPopup popup;
+
+ public IconPopupSkin(IconPopup popup) {
+ this.popup = popup;
+ this.node = new VBox();
+ this.icon = new ImageView();
+
+ this.icon.imageProperty().bind(popup.imageProperty());
+
+ this.node.getChildren().add(this.icon);
+ this.node.getStyleClass().add("text-popup");
+ this.node.getStylesheets().add(FXResource.loadStyleSheet("TextPopup.css"));
+ }
+
+ @Override
+ public IconPopup getSkinnable() {
+ return this.popup;
+ }
+
+ @Override
+ public Node getNode() {
+ return node;
+ }
+
+ @Override
+ public void dispose() {
+ this.node = null;
+ this.icon.imageProperty().unbind();
+ }
+}
diff --git a/app/src/main/java/cn/navclub/nes4j/app/view/GameWorld.java b/app/src/main/java/cn/navclub/nes4j/app/view/GameWorld.java
index 02707ff..c300aaa 100644
--- a/app/src/main/java/cn/navclub/nes4j/app/view/GameWorld.java
+++ b/app/src/main/java/cn/navclub/nes4j/app/view/GameWorld.java
@@ -3,6 +3,7 @@
import cn.navclub.nes4j.app.assets.FXResource;
import cn.navclub.nes4j.app.INes;
import cn.navclub.nes4j.app.audio.JavaXAudio;
+import cn.navclub.nes4j.app.control.IconPopup;
import cn.navclub.nes4j.app.service.TaskService;
import cn.navclub.nes4j.app.dialog.DHandle;
import cn.navclub.nes4j.app.event.FPSTracer;
@@ -24,6 +25,7 @@
import javafx.scene.control.*;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritableImage;
+import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
@@ -56,16 +58,17 @@ public class GameWorld extends Stage {
private volatile int fps;
private Debugger debugger;
private TaskService service;
+ private final IconPopup speedPopup;
public GameWorld() {
var scene = new Scene(FXResource.loadFXML(this));
this.scale = 3;
-
this.ctx = canvas.getGraphicsContext2D();
this.eventQueue = new LinkedBlockingDeque<>();
this.tracer = new FPSTracer(it -> this.fps = it);
+ this.speedPopup = new IconPopup(FXResource.loadImage("speed.png"));
this.intBuffer = IntBuffer.allocate(this.scale * this.scale);
this.image = new WritableImage(this.scale * Frame.width, this.scale * Frame.height);
@@ -74,7 +77,7 @@ public GameWorld() {
this.setHeight(600);
this.setScene(scene);
this.setResizable(false);
- this.getScene().getStylesheets().add(FXResource.loadStyleSheet("common.css"));
+ this.getScene().getStylesheets().add(FXResource.loadStyleSheet("Common.css"));
this.setOnCloseRequest(event -> this.dispose(null));
@@ -94,6 +97,15 @@ public GameWorld() {
}
}
}
+
+ //Change emulator speed
+ if (code == KeyCode.ADD || code == KeyCode.SUBTRACT) {
+ if (log.isDebugEnabled()) {
+ log.debug("Change ppu output frame action:{}", code);
+ }
+ this.instance.speed(code == KeyCode.ADD ? -1 : 1);
+ this.speedPopup.show(this);
+ }
});
}
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/common.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/Common.css
similarity index 99%
rename from app/src/main/resources/cn/navclub/nes4j/app/assets/css/common.css
rename to app/src/main/resources/cn/navclub/nes4j/app/assets/css/Common.css
index 43bbb0a..b418faf 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/common.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/Common.css
@@ -16,7 +16,7 @@
/**Game hall text color**/
-nes4j-game-hall-text-fill: #000000;
/**Game hall list-cell select background color**/
- -nes4j-game-hall-list-cell-active: linear-gradient(to right, #D6E0F0, #DDE4EF, #E6EAEF, #EAEBED);
+ -nes4j-game-hall-list-cell-active: linear-gradient(to right, #b4cbf3, #c6d6ef, #cfddef, #e4e7ef);
/**Game hall list-cell select text fill*/
-nes4j-game-hall-list-cell-text: #5185fd;
/**Default list view select row background color**/
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DException.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DException.css
index f7c724f..937dc3f 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DException.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DException.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
.text-area {
-fx-padding: 0;
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DHandle.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DHandle.css
index f8a9713..e5e15a0 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DHandle.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DHandle.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
.box, .content {
-fx-spacing: 2em;
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DNesHeaderStyle.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DNesHeaderStyle.css
index 2db39f1..128b9c2 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DNesHeaderStyle.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DNesHeaderStyle.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
GridPane {
-fx-hgap: 1em;
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DebuggerStyle.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DebuggerStyle.css
index 097056c..3acd8d3 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DebuggerStyle.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/DebuggerStyle.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
GridPane {
-fx-vgap: 1em;
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/GameHallStyle.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/GameHallStyle.css
index b7fdd7c..bf76958 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/GameHallStyle.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/GameHallStyle.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
.navbar *, .assort, .flow-pane .game-tray .label, .empty .label {
-fx-font-size: 1.4em;
@@ -53,6 +53,7 @@
}
.assort {
+ -fx-padding: 0;
-fx-background-insets: 0;
}
@@ -68,12 +69,12 @@
-fx-shape: 'M970.666667 213.333333H546.586667a10.573333 10.573333 0 0 1-7.54-3.126666L429.793333 100.953333A52.986667 52.986667 0 0 0 392.08 85.333333H96a53.393333 53.393333 0 0 0-53.333333 53.333334v704a53.393333 53.393333 0 0 0 53.333333 53.333333h874.666667a53.393333 53.393333 0 0 0 53.333333-53.333333V266.666667a53.393333 53.393333 0 0 0-53.333333-53.333334z m-275.866667 374.82c-25.486667 33.926667-71.333333 74.92-148.666667 132.913334a21.333333 21.333333 0 0 1-25.6 0c-77.333333-58-123.18-98.986667-148.666666-132.913334S341.333333 528.273333 341.333333 497.233333C341.333333 434.793333 392.126667 384 454.566667 384A112.893333 112.893333 0 0 1 533.333333 415.9 112.893333 112.893333 0 0 1 612.1 384c62.44 0 113.233333 50.793333 113.233333 113.233333 0 31.04-5.106667 57.08-30.533333 90.92z';
}
-.assort .list-cell {
+.assort .tree-cell {
-fx-background-color: -nes4j-game-hall-list-view;
-fx-focus-traversable: false;
}
-.assort .list-cell:selected {
+.assort .tree-cell:selected {
-fx-text-fill: -nes4j-game-hall-list-cell-text;
-fx-background-color: -nes4j-game-hall-list-cell-active;
}
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/Nes4j.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/Nes4j.css
index 87b9082..e24a9ea 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/Nes4j.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/Nes4j.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
.left-box, .right-box {
-fx-spacing: .5em;
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/SystemPalette.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/SystemPalette.css
index 3098a08..0e1940f 100644
--- a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/SystemPalette.css
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/SystemPalette.css
@@ -1,4 +1,4 @@
-@import "common.css";
+@import "Common.css";
VBox {
-fx-spacing: 1em;
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/css/TextPopup.css b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/TextPopup.css
new file mode 100644
index 0000000..1405096
--- /dev/null
+++ b/app/src/main/resources/cn/navclub/nes4j/app/assets/css/TextPopup.css
@@ -0,0 +1,9 @@
+@import "Common.css";
+
+.text-popup {
+ -fx-padding: 2em 3em;
+ -fx-alignment: CENTER;
+ -fx-border-radius: .5em;
+ -fx-background-radius: .5em;
+ -fx-background-color: rgba(0, 0, 0, .8);
+}
\ No newline at end of file
diff --git a/app/src/main/resources/cn/navclub/nes4j/app/assets/img/speed.png b/app/src/main/resources/cn/navclub/nes4j/app/assets/img/speed.png
new file mode 100644
index 0000000000000000000000000000000000000000..2910fa3b155a05e911280cf4b5b2e211fe09d9e8
GIT binary patch
literal 5116
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
elZ8h3^Zx^NtPtvl1hHQL0000 gameLoopCallback;
//cpu stall cycle
private int stall;
- @Setter
private int speed;
//APU mute
@Setter
@@ -157,7 +156,7 @@ public void stop() {
}
/**
- * 在debug模式下用于执行下一个断点所用
+ * Execute next break line
*/
public synchronized void release() {
if (this.thread == null) {
@@ -166,6 +165,20 @@ public synchronized void release() {
LockSupport.unpark(this.thread);
}
+ /**
+ * Manual change emulator speed
+ *
+ * @param span offset value
+ */
+ public int speed(int span) {
+ var temp = this.speed + span;
+ if (temp < 0) {
+ temp = 0;
+ }
+ this.speed = temp;
+ return this.speed;
+ }
+
public static class NESBuilder {
private File file;
private byte[] buffer;
diff --git a/build/icon/nes4j.ico b/build/icon/nes4j.ico
new file mode 100644
index 0000000000000000000000000000000000000000..18e0e5e9c281ec2647550d8964f3e180bc812531
GIT binary patch
literal 67646
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
literal 0
HcmV?d00001
diff --git a/build/jpackage.sh b/build/jpackage.sh
index 41a9e29..b07cf3f 100644
--- a/build/jpackage.sh
+++ b/build/jpackage.sh
@@ -19,6 +19,7 @@ fi
PROGRAM_NAME="nes4j"
PROGRAM_ICON="icon/nes4j.png"
MAIN_CLASS="cn.navclub.nes4j.app/cn.navclub.nes4j.app.Launcher"
-
+CMD="jpackage -n $PROGRAM_NAME -p $1 -m $MAIN_CLASS --icon $PROGRAM_ICON --license-file ../LICENSE --linux-package-name $PROGRAM_NAME --linux-app-category game"
+echo "Jpackage command:$CMD"
# shellcheck disable=SC2091
-$(jpackage -n "$PROGRAM_NAME" -p "$1" -m "${MAIN_CLASS}" --icon "$PROGRAM_ICON" --license-file ../LICENSE --linux-package-name "$PROGRAM_NAME")
+$($CMD)