mirror of
https://github.com/badvision/jace.git
synced 2025-01-01 05:29:49 +00:00
BUGFIX: All rendering is halted when a file chooser is open for any reason. For whatever reason, background canvas updates kill the CPU when file dialog is open so this is fixed now.
NEW: Memory inspector view lets you monitor read/write operations on a specific memory cell BUGFIX: Retina screens are detected to prevent the memoryview canvas from getting too large.
This commit is contained in:
parent
b17c5d6d94
commit
8942d6462e
@ -163,7 +163,6 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
// watchValue.setText("00");
|
||||
// }
|
||||
// }
|
||||
|
||||
// public static void updateBreakpointList(final DebuggerPanel panel) {
|
||||
// java.awt.EventQueue.invokeLater(() -> {
|
||||
// Integer address;
|
||||
@ -200,7 +199,7 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
public static void runFile() {
|
||||
Emulator.computer.pause();
|
||||
FileChooser select = new FileChooser();
|
||||
File binary = select.showOpenDialog(null);
|
||||
File binary = select.showOpenDialog(JaceApplication.getApplication().primaryStage);
|
||||
if (binary == null) {
|
||||
Emulator.computer.resume();
|
||||
return;
|
||||
@ -336,7 +335,7 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
Emulator.computer.pause();
|
||||
Image i = Emulator.computer.getVideo().getFrameBuffer();
|
||||
// BufferedImage bufImageARGB = SwingFXUtils.fromFXImage(i, null);
|
||||
File targetFile = select.showSaveDialog(null);
|
||||
File targetFile = select.showSaveDialog(JaceApplication.getApplication().primaryStage);
|
||||
if (targetFile == null) {
|
||||
return;
|
||||
}
|
||||
@ -375,7 +374,7 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@InvokableAction(
|
||||
name = "Open IDE",
|
||||
category = "development",
|
||||
@ -404,12 +403,15 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
}
|
||||
|
||||
static final Map<Object, Set<Label>> INDICATORS = new HashMap<>();
|
||||
|
||||
static public void addIndicator(Object owner, Label icon) {
|
||||
addIndicator(owner, icon, 250);
|
||||
}
|
||||
|
||||
|
||||
static public void addIndicator(Object owner, Label icon, long TTL) {
|
||||
if (JaceApplication.singleton == null) return;
|
||||
if (JaceApplication.getApplication() == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (INDICATORS) {
|
||||
Set<Label> ind = INDICATORS.get(owner);
|
||||
if (ind == null) {
|
||||
@ -417,12 +419,14 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
INDICATORS.put(owner, ind);
|
||||
}
|
||||
ind.add(icon);
|
||||
JaceApplication.singleton.controller.addIndicator(icon);
|
||||
JaceApplication.getApplication().controller.addIndicator(icon);
|
||||
}
|
||||
}
|
||||
|
||||
static public void removeIndicator(Object owner, Label icon) {
|
||||
if (JaceApplication.singleton == null) return;
|
||||
if (JaceApplication.singleton == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (INDICATORS) {
|
||||
Set<Label> ind = INDICATORS.get(owner);
|
||||
if (ind != null) {
|
||||
@ -433,7 +437,9 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
}
|
||||
|
||||
static public void removeIndicators(Object owner) {
|
||||
if (JaceApplication.singleton == null) return;
|
||||
if (JaceApplication.singleton == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (INDICATORS) {
|
||||
Set<Label> ind = INDICATORS.get(owner);
|
||||
if (ind == null) {
|
||||
@ -445,7 +451,7 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
INDICATORS.remove(owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public void addMouseListener(EventHandler<MouseEvent> handler) {
|
||||
if (JaceApplication.singleton != null) {
|
||||
JaceApplication.singleton.controller.addMouseListener(handler);
|
||||
@ -459,7 +465,7 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
}
|
||||
|
||||
public static void simulateCtrlAppleReset() {
|
||||
Computer computer = JaceApplication.singleton.controller.computer;
|
||||
Computer computer = JaceApplication.singleton.controller.computer;
|
||||
computer.keyboard.openApple(true);
|
||||
computer.warmStart();
|
||||
Platform.runLater(() -> {
|
||||
@ -471,7 +477,7 @@ public class EmulatorUILogic implements Reconfigurable {
|
||||
computer.keyboard.openApple(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Jace User Interface";
|
||||
|
@ -29,7 +29,7 @@ public class JaceApplication extends Application {
|
||||
|
||||
static JaceApplication singleton;
|
||||
|
||||
Stage primaryStage;
|
||||
public Stage primaryStage;
|
||||
JaceUIController controller;
|
||||
|
||||
static boolean romStarted = false;
|
||||
|
@ -463,7 +463,7 @@ public class MOS65C02 extends CPU {
|
||||
}
|
||||
implied = false;
|
||||
} else if (fmt.contains("R")) {
|
||||
this.f1 = fmt.substring(0, fmt.indexOf("R"));
|
||||
this.f1 = fmt.substring(0, fmt.indexOf('R'));
|
||||
f2 = "";
|
||||
relative = true;
|
||||
implied = false;
|
||||
@ -552,8 +552,7 @@ public class MOS65C02 extends CPU {
|
||||
@Override
|
||||
public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
|
||||
int mask = 0x0ff ^ (1 << bit);
|
||||
value &= mask;
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) (value & mask), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,8 +567,7 @@ public class MOS65C02 extends CPU {
|
||||
@Override
|
||||
public void processCommand(int address, int value, MODE addressMode, MOS65C02 cpu) {
|
||||
int mask = 1 << bit;
|
||||
value |= mask;
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) (value | mask), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -823,7 +821,7 @@ public class MOS65C02 extends CPU {
|
||||
cpu.push((byte) cpu.A);
|
||||
}),
|
||||
PHP((address, value, addressMode, cpu) -> {
|
||||
cpu.push((byte) (cpu.getStatus()));
|
||||
cpu.push((cpu.getStatus()));
|
||||
}),
|
||||
PHX((address, value, addressMode, cpu) -> {
|
||||
cpu.push((byte) cpu.X);
|
||||
@ -975,13 +973,11 @@ public class MOS65C02 extends CPU {
|
||||
}),
|
||||
TRB((address, value, addressMode, cpu) -> {
|
||||
cpu.C = (value & cpu.A) != 0 ? 1 : 0;
|
||||
value &= ~cpu.A;
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) (value & ~cpu.A), true, false);
|
||||
}),
|
||||
TSB((address, value, addressMode, cpu) -> {
|
||||
cpu.C = (value & cpu.A) != 0 ? 1 : 0;
|
||||
value |= cpu.A;
|
||||
cpu.getMemory().write(address, (byte) value, true, false);
|
||||
cpu.getMemory().write(address, (byte) (value | cpu.A), true, false);
|
||||
}),
|
||||
TSX((address, value, addressMode, cpu) -> {
|
||||
cpu.X = cpu.STACK;
|
||||
@ -1098,9 +1094,6 @@ public class MOS65C02 extends CPU {
|
||||
+ Integer.toHexString(op)
|
||||
+ " at " + Integer.toHexString(pc));
|
||||
}
|
||||
if (isLogEnabled()) {
|
||||
dumpTrace();
|
||||
}
|
||||
if (breakOnBadOpcode) {
|
||||
OPCODE.BRK.execute(this);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package jace.apple2e;
|
||||
|
||||
import jace.JaceApplication;
|
||||
import jace.config.ConfigurableField;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Device;
|
||||
@ -59,7 +60,7 @@ public class Speaker extends Device {
|
||||
fileOutputActive = false;
|
||||
} else {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
File f = fileChooser.showSaveDialog(null);
|
||||
File f = fileChooser.showSaveDialog(JaceApplication.getApplication().primaryStage);
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -27,7 +27,9 @@ public class MemoryCell implements Comparable<MemoryCell> {
|
||||
public IntegerProperty writeCount = new SimpleIntegerProperty();
|
||||
public BooleanBinding hasCount = readCount.add(execCount).add(writeCount).greaterThan(0);
|
||||
public ObservableList<Integer> readInstructions = FXCollections.observableList(new ArrayList<>());
|
||||
public ObservableList<String> readInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>());
|
||||
public ObservableList<Integer> writeInstructions = FXCollections.observableList(new ArrayList<>());
|
||||
public ObservableList<String> writeInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>());
|
||||
private int x;
|
||||
private int y;
|
||||
private int width;
|
||||
@ -76,6 +78,5 @@ public class MemoryCell implements Comparable<MemoryCell> {
|
||||
|
||||
public boolean hasCounts() {
|
||||
return hasCount.get();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package jace.cheat;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.JaceApplication;
|
||||
import jace.core.CPU;
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAM;
|
||||
import jace.core.RAMEvent;
|
||||
@ -15,8 +16,11 @@ import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
@ -327,10 +331,18 @@ public class MetaCheat extends Cheats {
|
||||
}
|
||||
}
|
||||
|
||||
AtomicInteger pendingInspectorUpdates = new AtomicInteger(0);
|
||||
public void onInspectorChanged() {
|
||||
pendingInspectorUpdates.set(0);
|
||||
}
|
||||
|
||||
private void processMemoryEvent(RAMEvent e) {
|
||||
MemoryCell cell = getMemoryCell(e.getAddress());
|
||||
if (cell != null) {
|
||||
int programCounter = Emulator.computer.getCpu().getProgramCounter();
|
||||
CPU cpu = Emulator.computer.getCpu();
|
||||
if (!cpu.isLogEnabled()) {
|
||||
cpu.traceLength = 1;
|
||||
}
|
||||
switch (e.getType()) {
|
||||
case EXECUTE:
|
||||
case READ_OPERAND:
|
||||
@ -338,16 +350,52 @@ public class MetaCheat extends Cheats {
|
||||
break;
|
||||
case WRITE:
|
||||
cell.writeCount.set(Math.min(255, cell.writeCount.get() + lightRate));
|
||||
cell.writeInstructions.add(programCounter);
|
||||
if (cell.writeInstructions.size() > historyLength) {
|
||||
cell.writeInstructions.remove(0);
|
||||
if (ui.isInspecting(cell.address)) {
|
||||
if (pendingInspectorUpdates.incrementAndGet() < 5) {
|
||||
int pc = cpu.getProgramCounter();
|
||||
String trace = cpu.getLastTrace();
|
||||
Platform.runLater(() -> {
|
||||
pendingInspectorUpdates.decrementAndGet();
|
||||
cell.writeInstructions.add(pc);
|
||||
cell.writeInstructionsDisassembly.add(trace);
|
||||
if (cell.writeInstructions.size() > historyLength) {
|
||||
cell.writeInstructions.remove(0);
|
||||
cell.writeInstructionsDisassembly.remove(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
cell.writeInstructions.add(cpu.getProgramCounter());
|
||||
cell.writeInstructionsDisassembly.add(cpu.getLastTrace());
|
||||
if (cell.writeInstructions.size() > historyLength) {
|
||||
cell.writeInstructions.remove(0);
|
||||
cell.writeInstructionsDisassembly.remove(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cell.readCount.set(Math.min(255, cell.readCount.get() + lightRate));
|
||||
cell.readInstructions.add(programCounter);
|
||||
if (cell.readInstructions.size() > historyLength) {
|
||||
cell.readInstructions.remove(0);
|
||||
if (ui.isInspecting(cell.address)) {
|
||||
if (pendingInspectorUpdates.incrementAndGet() < 5) {
|
||||
int pc = cpu.getProgramCounter();
|
||||
String trace = cpu.getLastTrace();
|
||||
Platform.runLater(() -> {
|
||||
pendingInspectorUpdates.decrementAndGet();
|
||||
cell.readInstructions.add(pc);
|
||||
cell.readInstructionsDisassembly.add(trace);
|
||||
if (cell.readInstructions.size() > historyLength) {
|
||||
cell.readInstructions.remove(0);
|
||||
cell.readInstructionsDisassembly.remove(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
cell.readInstructions.add(cpu.getProgramCounter());
|
||||
cell.readInstructionsDisassembly.add(cpu.getLastTrace());
|
||||
if (cell.readInstructions.size() > historyLength) {
|
||||
cell.readInstructions.remove(0);
|
||||
cell.readInstructionsDisassembly.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
cell.value.set(e.getNewValue());
|
||||
@ -380,7 +428,7 @@ public class MetaCheat extends Cheats {
|
||||
in = new BufferedReader(new FileReader(saveFile));
|
||||
StringBuilder guts = new StringBuilder();
|
||||
String line;
|
||||
while ((line=in.readLine()) != null) {
|
||||
while ((line = in.readLine()) != null) {
|
||||
DynamicCheat cheat = DynamicCheat.deserialize(line);
|
||||
addCheat(cheat);
|
||||
}
|
||||
|
@ -71,6 +71,14 @@ public abstract class CPU extends Device {
|
||||
}
|
||||
traceLog.add(line);
|
||||
}
|
||||
|
||||
public String getLastTrace() {
|
||||
if (traceLog.isEmpty()) {
|
||||
return "???";
|
||||
} else {
|
||||
return traceLog.get(traceLog.size()-1);
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpTrace() {
|
||||
computer.pause();
|
||||
|
@ -131,7 +131,9 @@ public abstract class Video extends Device {
|
||||
public static int MIN_SCREEN_REFRESH = 15;
|
||||
|
||||
Runnable redrawScreen = () -> {
|
||||
visible.getPixelWriter().setPixels(0, 0, 560, 192, video.getPixelReader(), 0, 0);
|
||||
if (computer.getRunningProperty().get()) {
|
||||
visible.getPixelWriter().setPixels(0, 0, 560, 192, video.getPixelReader(), 0, 0);
|
||||
}
|
||||
};
|
||||
public void redraw() {
|
||||
screenDirty = false;
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
package jace.ide;
|
||||
|
||||
import jace.JaceApplication;
|
||||
import jace.ide.Program.DocumentType;
|
||||
import jace.ide.Program.Option;
|
||||
import java.io.File;
|
||||
@ -149,7 +150,7 @@ public class IdeController {
|
||||
chooser.getExtensionFilters().addAll(
|
||||
new FileChooser.ExtensionFilter("All Files", "*.*")
|
||||
);
|
||||
File file = chooser.showOpenDialog(null);
|
||||
File file = chooser.showOpenDialog(JaceApplication.getApplication().primaryStage);
|
||||
if (file != null && file.isFile() && file.exists()) {
|
||||
DocumentType type = DocumentType.fromFile(file);
|
||||
createTab(type, file);
|
||||
@ -196,7 +197,7 @@ public class IdeController {
|
||||
new FileChooser.ExtensionFilter(type.name(), type.extensions),
|
||||
new FileChooser.ExtensionFilter("All Files", "*.*")
|
||||
);
|
||||
return chooser.showSaveDialog(null);
|
||||
return chooser.showSaveDialog(JaceApplication.getApplication().primaryStage);
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
@ -2,6 +2,7 @@ package jace.ui;
|
||||
|
||||
import com.sun.glass.ui.Application;
|
||||
import jace.Emulator;
|
||||
import jace.JaceApplication;
|
||||
import jace.cheat.DynamicCheat;
|
||||
import jace.cheat.MemoryCell;
|
||||
import jace.cheat.MetaCheat;
|
||||
@ -47,11 +48,14 @@ import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.TilePane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Screen;
|
||||
import javafx.util.converter.DefaultStringConverter;
|
||||
import javafx.util.converter.IntegerStringConverter;
|
||||
|
||||
public class MetacheatUI {
|
||||
|
||||
boolean isRetina;
|
||||
double drawScale;
|
||||
|
||||
@FXML
|
||||
private Button pauseButton;
|
||||
|
||||
@ -127,6 +131,15 @@ public class MetacheatUI {
|
||||
@FXML
|
||||
private TableView<DynamicCheat> cheatsTableView;
|
||||
|
||||
@FXML
|
||||
private TextField codeInspectorAddress;
|
||||
|
||||
@FXML
|
||||
private ListView<String> codeInspectorWriteList;
|
||||
|
||||
@FXML
|
||||
private ListView<String> codeInspectorReadList;
|
||||
|
||||
@FXML
|
||||
void createSnapshot(ActionEvent event) {
|
||||
|
||||
@ -154,24 +167,32 @@ public class MetacheatUI {
|
||||
|
||||
@FXML
|
||||
void loadCheats(ActionEvent event) {
|
||||
boolean resume = Emulator.computer.pause();
|
||||
FileChooser chooser = new FileChooser();
|
||||
chooser.setTitle("Load cheats");
|
||||
chooser.setInitialFileName("cheat.txt");
|
||||
File saveFile = chooser.showOpenDialog(null);
|
||||
File saveFile = chooser.showOpenDialog(JaceApplication.getApplication().primaryStage);
|
||||
if (saveFile != null) {
|
||||
cheatEngine.loadCheats(saveFile);
|
||||
}
|
||||
}
|
||||
if (resume) {
|
||||
Emulator.computer.resume();
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
void saveCheats(ActionEvent event) {
|
||||
boolean resume = Emulator.computer.pause();
|
||||
FileChooser chooser = new FileChooser();
|
||||
chooser.setTitle("Save current cheats");
|
||||
chooser.setInitialFileName("cheat.txt");
|
||||
File saveFile = chooser.showSaveDialog(null);
|
||||
File saveFile = chooser.showSaveDialog(JaceApplication.getApplication().primaryStage);
|
||||
if (saveFile != null) {
|
||||
cheatEngine.saveCheats(saveFile);
|
||||
}
|
||||
if (resume) {
|
||||
Emulator.computer.resume();
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
@ -234,9 +255,16 @@ public class MetacheatUI {
|
||||
assert searchResultsListView != null : "fx:id=\"searchResultsListView\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
assert watchesPane != null : "fx:id=\"watchesPane\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
assert snapshotsListView != null : "fx:id=\"snapshotsListView\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
assert codeInspectorAddress != null : "fx:id=\"codeInspectorAddress\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
assert codeInspectorWriteList != null : "fx:id=\"codeInspectorWriteList\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
assert codeInspectorReadList != null : "fx:id=\"codeInspectorReadList\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
assert cheatsTableView != null : "fx:id=\"cheatsTableView\" was not injected: check your FXML file 'Metacheat.fxml'.";
|
||||
|
||||
Emulator.computer.getRunningProperty().addListener((val, oldVal, newVal) -> pauseButton.setText(newVal ? "Pause" : "Resume"));
|
||||
isRetina = Screen.getPrimary().getDpi() >= 110;
|
||||
|
||||
Emulator.computer.getRunningProperty().addListener((val, oldVal, newVal) -> {
|
||||
Platform.runLater(() -> pauseButton.setText(newVal ? "Pause" : "Resume"));
|
||||
});
|
||||
|
||||
searchTypesTabPane.getTabs().get(0).setUserData(SearchType.VALUE);
|
||||
searchTypesTabPane.getTabs().get(1).setUserData(SearchType.CHANGE);
|
||||
@ -281,7 +309,9 @@ public class MetacheatUI {
|
||||
}
|
||||
});
|
||||
memoryViewPane.boundsInParentProperty().addListener((prop, oldVal, newVal) -> redrawMemoryView());
|
||||
memoryViewCanvas.widthProperty().bind(memoryViewPane.widthProperty());
|
||||
drawScale = isRetina ? 0.5 : 1.0;
|
||||
memoryViewCanvas.widthProperty().bind(memoryViewPane.widthProperty().multiply(drawScale));
|
||||
setZoom(1/drawScale);
|
||||
|
||||
watchesPane.setHgap(5);
|
||||
watchesPane.setVgap(5);
|
||||
@ -316,6 +346,18 @@ public class MetacheatUI {
|
||||
TableColumn<DynamicCheat, String> exprColumn = (TableColumn<DynamicCheat, String>) cheatsTableView.getColumns().get(3);
|
||||
exprColumn.setCellValueFactory(new PropertyValueFactory<>("expression"));
|
||||
exprColumn.setCellFactory((TableColumn<DynamicCheat, String> param) -> new TextFieldTableCell<>(new DefaultStringConverter()));
|
||||
|
||||
codeInspectorAddress.textProperty().addListener((prop, oldValue, newValue) -> {
|
||||
try {
|
||||
int address = cheatEngine.parseInt(newValue);
|
||||
MemoryCell cell = cheatEngine.getMemoryCell(address);
|
||||
currentlyInspecting = address;
|
||||
cheatEngine.onInspectorChanged();
|
||||
codeInspectorReadList.setItems(cell.readInstructionsDisassembly);
|
||||
codeInspectorWriteList.setItems(cell.writeInstructionsDisassembly);
|
||||
} catch (NumberFormatException ex) {
|
||||
}
|
||||
});
|
||||
}
|
||||
MetaCheat cheatEngine = null;
|
||||
|
||||
@ -354,8 +396,8 @@ public class MetacheatUI {
|
||||
currentWatch.disconnect();
|
||||
}
|
||||
|
||||
double x = e.getX();
|
||||
double y = e.getY();
|
||||
double x = e.getX() / drawScale;
|
||||
double y = e.getY() / drawScale;
|
||||
int col = (int) (x / MEMORY_BOX_TOTAL_SIZE);
|
||||
int row = (int) (y / MEMORY_BOX_TOTAL_SIZE);
|
||||
int addr = cheatEngine.getStartAddress() + row * memoryViewColumns + col;
|
||||
@ -388,10 +430,13 @@ public class MetacheatUI {
|
||||
}
|
||||
|
||||
private void processMemoryViewUpdates() {
|
||||
if (!Emulator.computer.getRunningProperty().get()) {
|
||||
return;
|
||||
}
|
||||
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
||||
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
|
||||
redrawNodes.clear();
|
||||
Application.invokeLater(() -> {
|
||||
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
||||
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
|
||||
redrawNodes.clear();
|
||||
draw.stream().forEach((jace.cheat.MemoryCell cell) -> {
|
||||
if (showValuesCheckbox.isSelected()) {
|
||||
int val = cell.value.get() & 0x0ff;
|
||||
@ -416,7 +461,7 @@ public class MetacheatUI {
|
||||
boolean resume = Emulator.computer.pause();
|
||||
|
||||
if (animationTimer == null) {
|
||||
animationTimer = new ScheduledThreadPoolExecutor(10);
|
||||
animationTimer = new ScheduledThreadPoolExecutor(1);
|
||||
}
|
||||
|
||||
if (animationFuture != null) {
|
||||
@ -427,9 +472,18 @@ public class MetacheatUI {
|
||||
|
||||
cheatEngine.initMemoryView();
|
||||
int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE;
|
||||
memoryViewColumns = ((int) memoryViewPane.getWidth()) / pixelsPerBlock * 16;
|
||||
memoryViewColumns = (int) (memoryViewPane.getWidth() / pixelsPerBlock * 16);
|
||||
memoryViewRows = ((cheatEngine.getEndAddress() - cheatEngine.getStartAddress()) / memoryViewColumns) + 1;
|
||||
int canvasHeight = memoryViewRows * MEMORY_BOX_TOTAL_SIZE;
|
||||
double canvasHeight = memoryViewRows * MEMORY_BOX_TOTAL_SIZE * drawScale;
|
||||
|
||||
// Guard against asking for a big texture because bad things will happen!
|
||||
while (canvasHeight >= 16384) {
|
||||
memoryViewColumns += 16;
|
||||
memoryViewRows = ((cheatEngine.getEndAddress() - cheatEngine.getStartAddress()) / memoryViewColumns) + 1;
|
||||
canvasHeight = memoryViewRows * MEMORY_BOX_TOTAL_SIZE * drawScale;
|
||||
}
|
||||
double canvasWidth = memoryViewColumns * MEMORY_BOX_TOTAL_SIZE * drawScale;
|
||||
|
||||
memoryViewContents.setPrefHeight(canvasHeight);
|
||||
memoryViewCanvas.setHeight(canvasHeight);
|
||||
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
||||
@ -439,12 +493,18 @@ public class MetacheatUI {
|
||||
int col = (addr - cheatEngine.getStartAddress()) % memoryViewColumns;
|
||||
int row = (addr - cheatEngine.getStartAddress()) / memoryViewColumns;
|
||||
MemoryCell cell = cheatEngine.getMemoryCell(addr);
|
||||
cell.setRect(col * MEMORY_BOX_TOTAL_SIZE, row * MEMORY_BOX_TOTAL_SIZE, MEMORY_BOX_SIZE, MEMORY_BOX_SIZE);
|
||||
cell.setRect(
|
||||
(int) (col * MEMORY_BOX_TOTAL_SIZE * drawScale),
|
||||
(int) (row * MEMORY_BOX_TOTAL_SIZE * drawScale),
|
||||
(int) (MEMORY_BOX_SIZE * drawScale),
|
||||
(int) (MEMORY_BOX_SIZE * drawScale));
|
||||
redrawNodes.add(cell);
|
||||
}
|
||||
MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> {
|
||||
redrawNodes.add(newCell);
|
||||
});
|
||||
|
||||
setZoom(1/drawScale);
|
||||
|
||||
if (resume) {
|
||||
Emulator.computer.resume();
|
||||
@ -455,6 +515,12 @@ public class MetacheatUI {
|
||||
if (memoryViewCanvas != null) {
|
||||
double zoom = memoryViewCanvas.getScaleX();
|
||||
zoom += amount;
|
||||
setZoom(zoom);
|
||||
}
|
||||
}
|
||||
|
||||
private void setZoom(double zoom) {
|
||||
if (memoryViewCanvas != null) {
|
||||
memoryViewCanvas.setScaleX(zoom);
|
||||
memoryViewCanvas.setScaleY(zoom);
|
||||
StackPane scrollArea = (StackPane) memoryViewCanvas.getParent();
|
||||
@ -509,4 +575,14 @@ public class MetacheatUI {
|
||||
private void addCheat(int addr, int val) {
|
||||
cheatEngine.addCheat(new DynamicCheat(addr, String.valueOf(val)));
|
||||
}
|
||||
|
||||
int currentlyInspecting = 0;
|
||||
|
||||
public void inspectAddress(int address) {
|
||||
codeInspectorAddress.setText("$" + Integer.toHexString(address));
|
||||
}
|
||||
|
||||
public boolean isInspecting(int address) {
|
||||
return currentlyInspecting == address;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package jace.ui;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.cheat.MemoryCell;
|
||||
import jace.core.RAMListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -19,6 +20,7 @@ import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.layout.CornerRadii;
|
||||
@ -32,6 +34,7 @@ import javafx.scene.text.TextAlignment;
|
||||
* @author blurry
|
||||
*/
|
||||
class Watch extends VBox {
|
||||
|
||||
private static final int GRAPH_WIDTH = 50;
|
||||
private static final double GRAPH_HEIGHT = 50;
|
||||
int address;
|
||||
@ -41,11 +44,13 @@ class Watch extends VBox {
|
||||
int value = 0;
|
||||
BooleanProperty holding = null;
|
||||
private final MetacheatUI outer;
|
||||
MemoryCell cell;
|
||||
|
||||
public Watch(int address, final MetacheatUI outer) {
|
||||
super();
|
||||
this.outer = outer;
|
||||
this.address = address;
|
||||
cell = outer.cheatEngine.getMemoryCell(address);
|
||||
redraw = outer.animationTimer.scheduleAtFixedRate(this::redraw, MetacheatUI.FRAME_RATE, MetacheatUI.FRAME_RATE, TimeUnit.MILLISECONDS);
|
||||
setBackground(new Background(new BackgroundFill(Color.NAVY, CornerRadii.EMPTY, Insets.EMPTY)));
|
||||
Label addrLabel = new Label("$" + Integer.toHexString(address));
|
||||
@ -53,6 +58,12 @@ class Watch extends VBox {
|
||||
addrLabel.setMinWidth(GRAPH_WIDTH);
|
||||
addrLabel.setFont(new Font(Font.getDefault().getFamily(), 14));
|
||||
addrLabel.setTextFill(Color.WHITE);
|
||||
addrLabel.setMouseTransparent(false);
|
||||
addrLabel.setOnMouseClicked((MouseEvent evt)-> {
|
||||
if (evt.isPrimaryButtonDown()) {
|
||||
outer.inspectAddress(address);
|
||||
}
|
||||
});
|
||||
graph = new Canvas(GRAPH_WIDTH, GRAPH_HEIGHT);
|
||||
getChildren().add(addrLabel);
|
||||
getChildren().add(graph);
|
||||
@ -68,7 +79,10 @@ class Watch extends VBox {
|
||||
}
|
||||
|
||||
public void redraw() {
|
||||
int val = outer.cheatEngine.getMemoryCell(address).value.get() & 0x0ff;
|
||||
if (!Emulator.computer.getRunningProperty().get()) {
|
||||
return;
|
||||
}
|
||||
int val = cell.value.get() & 0x0ff;
|
||||
if (!holding.get()) {
|
||||
value = val;
|
||||
}
|
||||
@ -117,5 +131,5 @@ class Watch extends VBox {
|
||||
holding.set(false);
|
||||
redraw.cancel(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -194,6 +194,41 @@
|
||||
</BorderPane>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Inspector" VBox.vgrow="SOMETIMES">
|
||||
<content>
|
||||
<VBox>
|
||||
<children>
|
||||
<HBox prefHeight="33.0" prefWidth="236.0" spacing="4.0" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<Label alignment="CENTER_RIGHT" prefHeight="26.0" prefWidth="68.0" text="Address" textAlignment="RIGHT" HBox.hgrow="NEVER">
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
</opaqueInsets>
|
||||
</Label>
|
||||
<TextField fx:id="codeInspectorAddress" prefHeight="26.0" prefWidth="94.0" HBox.hgrow="ALWAYS" />
|
||||
</children>
|
||||
<opaqueInsets>
|
||||
<Insets />
|
||||
</opaqueInsets>
|
||||
</HBox>
|
||||
<TabPane minHeight="-Infinity" prefHeight="102.0" prefWidth="236.0" side="LEFT" tabClosingPolicy="UNAVAILABLE" VBox.vgrow="SOMETIMES">
|
||||
<tabs>
|
||||
<Tab text="W">
|
||||
<content>
|
||||
<ListView fx:id="codeInspectorWriteList" editable="true" />
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab text="R">
|
||||
<content>
|
||||
<ListView fx:id="codeInspectorReadList" editable="true" />
|
||||
</content>
|
||||
</Tab>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
</children>
|
||||
</VBox>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane expanded="false" text="Snapshots" VBox.vgrow="NEVER">
|
||||
<content>
|
||||
<BorderPane minWidth="-Infinity">
|
||||
|
Loading…
Reference in New Issue
Block a user