Fire onChapter on chapter boundaries; M returns to menu via onMenu

The menu state machine advances via onChapter events when a video crosses a
chapter marker, which we never emitted - so the menu never opened naturally.
Track chapter boundaries from the playlist markers and fire onChapter. Also
change M to invoke the onMenu dispatcher (returns to the menu video) rather
than drawing menu items directly.
This commit is contained in:
2026-09-16 08:41:13 -04:00
parent 0e7accad19
commit 43cc8f420c
2 changed files with 25 additions and 6 deletions
@@ -80,6 +80,8 @@ public class MoviePlayer extends BaseNativeObject {
if (!previousMenuMode && this.menuMode) { if (!previousMenuMode && this.menuMode) {
VsmxBaseObject callback = controller.getPropertyValue("onMenu"); VsmxBaseObject callback = controller.getPropertyValue("onMenu");
System.err.println("[menu] onMenu fires, callback=" + callback
+ " (" + (callback == null ? "null" : callback.getClass().getSimpleName()) + ")");
if (callback instanceof VsmxFunction function) { if (callback instanceof VsmxFunction function) {
interpreter.interpretFunction(function, null, new VsmxBaseObject[0]); interpreter.interpretFunction(function, null, new VsmxBaseObject[0]);
} }
@@ -70,6 +70,7 @@ public final class PlayerApp extends Application {
private volatile VsmxInterpreter menuInterpreter; private volatile VsmxInterpreter menuInterpreter;
private volatile VsmxBaseObject mmActivate; private volatile VsmxBaseObject mmActivate;
private volatile VsmxNativeObject controllerObject;
@Override @Override
public void start(Stage stage) { public void start(Stage stage) {
@@ -146,11 +147,14 @@ public final class PlayerApp extends Application {
} }
private void openMenuDirectly() { private void openMenuDirectly() {
VsmxBaseObject fn = mmActivate;
VsmxInterpreter interpreter = menuInterpreter; VsmxInterpreter interpreter = menuInterpreter;
if (fn instanceof VsmxFunction function && interpreter != null) { VsmxNativeObject c = controllerObject;
System.err.println("[debug] opening menu directly"); if (interpreter != null && c != null) {
interpreter.interpretFunction(function, null, new VsmxBaseObject[0]); VsmxBaseObject callback = c.getPropertyValue("onMenu");
if (callback instanceof VsmxFunction function) {
System.err.println("[debug] returning to menu");
interpreter.interpretFunction(function, null, new VsmxBaseObject[0]);
}
} }
} }
@@ -181,7 +185,7 @@ public final class PlayerApp extends Application {
int audioFlag, int subtitleNumber, int subtitleFlag) { int audioFlag, int subtitleNumber, int subtitleFlag) {
Playlist.Stream stream = playlist.streamForPlayListNumber(playListNumber); Playlist.Stream stream = playlist.streamForPlayListNumber(playListNumber);
if (stream != null) { if (stream != null) {
startPlayback(isoPath, stream.name(), playListNumber); startPlayback(isoPath, stream, playListNumber);
} }
} }
@@ -209,13 +213,15 @@ public final class PlayerApp extends Application {
moviePlayer = (MoviePlayer) movieplayer.getObject(); moviePlayer = (MoviePlayer) movieplayer.getObject();
menuInterpreter = interpreter; menuInterpreter = interpreter;
mmActivate = globals.getPropertyValue("mm_activate"); mmActivate = globals.getPropertyValue("mm_activate");
this.controllerObject = controllerObject;
controller.callCallback(interpreter, "onAutoPlay", null); controller.callCallback(interpreter, "onAutoPlay", null);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private void startPlayback(String isoPath, String streamName, int playListNumber) { private void startPlayback(String isoPath, Playlist.Stream stream, int playListNumber) {
String streamName = stream.name();
Thread player = new Thread(() -> { Thread player = new Thread(() -> {
try (UmdIsoReader iso = new UmdIsoReader(Path.of(isoPath)); try (UmdIsoReader iso = new UmdIsoReader(Path.of(isoPath));
PlaybackEngine engine = PlaybackEngine.open(iso, streamName, 0)) { PlaybackEngine engine = PlaybackEngine.open(iso, streamName, 0)) {
@@ -232,11 +238,22 @@ public final class PlayerApp extends Application {
long baseNanos = clockStartNanos; long baseNanos = clockStartNanos;
PlaybackEngine.VideoFrame frame; PlaybackEngine.VideoFrame frame;
int lastChapter = -2;
while ((frame = engine.nextVideoFrame()) != null) { while ((frame = engine.nextVideoFrame()) != null) {
if (skipRequested) { if (skipRequested) {
skipRequested = false; skipRequested = false;
break; break;
} }
int chapter = stream.getChapterNumber(frame.pts());
if (chapter != lastChapter) {
if (lastChapter != -2) {
MoviePlayer mp = moviePlayer;
if (mp != null) {
mp.onChapter(chapter + 1);
}
}
lastChapter = chapter;
}
int index = videoBufferIndex++ & 1; int index = videoBufferIndex++ & 1;
int[] argb = argbBuffers[index]; int[] argb = argbBuffers[index];
int pixelCount = frame.width() * frame.height(); int pixelCount = frame.width() * frame.height();