[libbluray-devel] [Git][videolan/libbluray][master] Actionable HAVI component implementation
Petri Hintukainen (@hpi)
gitlab at videolan.org
Mon Jun 8 18:31:26 UTC 2026
Petri Hintukainen pushed to branch master at VideoLAN / libbluray
Commits:
db77318f by Shaya Potter at 2026-06-08T17:30:29+00:00
Actionable HAVI component implementation
- - - - -
3 changed files:
- + src/libbluray/bdj/java/org/havi/ui/HActionableHelper.java
- src/libbluray/bdj/java/org/havi/ui/HGraphicButton.java
- src/libbluray/bdj/java/org/havi/ui/HTextButton.java
Changes:
=====================================
src/libbluray/bdj/java/org/havi/ui/HActionableHelper.java
=====================================
@@ -0,0 +1,141 @@
+/*
+ * This file is part of libbluray
+ * Copyright (C) 2026 libbluray project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Based on XletView implementation by Martin Sveden.
+ */
+
+package org.havi.ui;
+
+import java.awt.event.KeyEvent;
+
+import org.havi.ui.event.HActionEvent;
+import org.havi.ui.event.HActionListener;
+
+/**
+ * Helper class that implements HActionable functionality.
+ * This encapsulates the action handling logic for use by HGraphicButton, HTextButton, etc.
+ */
+public final class HActionableHelper {
+
+ transient HActionListener hActionListener;
+ private HSound actionSound;
+ private String actionCommand;
+ private HVisible hVisible;
+
+ public HActionableHelper(HVisible hVisible) {
+ this.hVisible = hVisible;
+ }
+
+ /**
+ * Adds an HActionListener to receive action events.
+ */
+ public synchronized void addHActionListener(HActionListener listener) {
+ if (listener == null) {
+ return;
+ }
+ hActionListener = HEventMulticaster.add(hActionListener, listener);
+ }
+
+ /**
+ * Removes an HActionListener.
+ */
+ public synchronized void removeHActionListener(HActionListener listener) {
+ if (listener == null) {
+ return;
+ }
+ hActionListener = HEventMulticaster.remove(hActionListener, listener);
+ }
+
+ /**
+ * Sets the action command string for action events.
+ */
+ public void setActionCommand(String command) {
+ actionCommand = command;
+ }
+
+ /**
+ * Gets the action command string.
+ */
+ public String getActionCommand() {
+ return actionCommand;
+ }
+
+ /**
+ * Sets the sound to play when an action occurs.
+ */
+ public void setActionSound(HSound sound) {
+ actionSound = sound;
+ }
+
+ /**
+ * Gets the action sound.
+ */
+ public HSound getActionSound() {
+ return actionSound;
+ }
+
+ /**
+ * Processes an HActionEvent and returns the new interaction state.
+ * Notifies registered HActionListeners and plays the action sound.
+ *
+ * @param evt The HActionEvent to process
+ * @return The current interaction state (unchanged by action events)
+ */
+ public int processHActionEvent(HActionEvent evt) {
+ // Get current state - action events don't change the state
+ int state = hVisible.getInteractionState();
+
+ // Play action sound
+ if (actionSound != null) {
+ actionSound.play();
+ }
+
+ // Notify action listeners
+ if (hActionListener != null) {
+ hActionListener.actionPerformed(evt);
+ }
+
+ return state;
+ }
+
+ /**
+ * Processes a KeyEvent for action.
+ * Handles ENTER key by firing an HActionEvent.
+ *
+ * @param e The KeyEvent to process
+ * @return true if the event was handled, false otherwise
+ */
+ public boolean processKeyEvent(KeyEvent e) {
+ // Only handle KEY_PRESSED
+ if (e.getID() != KeyEvent.KEY_PRESSED) {
+ return false;
+ }
+
+ // Only handle ENTER key
+ if (e.getKeyCode() != KeyEvent.VK_ENTER) {
+ return false;
+ }
+
+ // Fire action event (cast is safe - this helper is only used by HActionable components)
+ HActionEvent actionEvent = new HActionEvent(
+ (HActionInputPreferred) hVisible, HActionEvent.ACTION_PERFORMED, actionCommand);
+ processHActionEvent(actionEvent);
+
+ return true;
+ }
+}
=====================================
src/libbluray/bdj/java/org/havi/ui/HGraphicButton.java
=====================================
@@ -1,6 +1,7 @@
/*
* This file is part of libbluray
* Copyright (C) 2010 William Hahne
+ * Copyright (C) 2026 libbluray project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,130 +21,113 @@
package org.havi.ui;
import java.awt.Image;
+import java.awt.event.KeyEvent;
import org.havi.ui.event.HActionEvent;
import org.havi.ui.event.HActionListener;
import org.havi.ui.event.HFocusEvent;
import org.havi.ui.event.HFocusListener;
+import org.videolan.BDJXletContext;
+
public class HGraphicButton extends HIcon implements HActionable {
+
+ private HActionableHelper actionHelper;
+
public HGraphicButton() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ super();
+ initAction();
}
public HGraphicButton(Image image, int x, int y, int width, int height) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ super(image, x, y, width, height);
+ initAction();
}
public HGraphicButton(Image imageNormal, Image imageFocused,
Image imageActioned, int x, int y, int width, int height) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ super(imageNormal, imageFocused, x, y, width, height);
+ setGraphicContent(imageActioned, ACTIONED_STATE);
+ initAction();
}
public HGraphicButton(Image image) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ super(image);
+ initAction();
}
public HGraphicButton(Image imageNormal, Image imageFocused,
Image imageActioned) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- }
-
- public static void setDefaultLook(HGraphicLook hlook) {
- DefaultLook = hlook;
- }
-
- public static HGraphicLook getDefaultLook() {
- if (DefaultLook == null)
- org.videolan.Logger.unimplemented("", "getDefaultLook");
- return DefaultLook;
- }
-
- public void setMove(int keyCode, HNavigable target) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- }
-
- public HNavigable getMove(int keyCode) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return null;
- }
-
- public void setFocusTraversal(HNavigable up, HNavigable down,
- HNavigable left, HNavigable right) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- }
-
- public boolean isSelected() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return false;
+ this(imageNormal, imageFocused, imageActioned, 0, 0, 0, 0);
}
- public void setGainFocusSound(HSound sound) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ private void initAction() {
+ actionHelper = new HActionableHelper(this);
}
- public void setLoseFocusSound(HSound sound) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- }
-
- public HSound getGainFocusSound() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return null;
- }
-
- public HSound getLoseFocusSound() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return null;
- }
-
- public void addHFocusListener(HFocusListener l) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- }
-
- public void removeHFocusListener(HFocusListener l) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ public static void setDefaultLook(HGraphicLook hlook) {
+ BDJXletContext.setXletDefaultLook(PROPERTY_LOOK, hlook);
}
- public int[] getNavigationKeys() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return null;
+ public static HGraphicLook getDefaultLook() {
+ return (HGraphicLook)BDJXletContext.getXletDefaultLook(PROPERTY_LOOK, DEFAULT_LOOK);
}
- public void processHFocusEvent(HFocusEvent evt) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- }
+ // --- HActionable implementation ---
public void addHActionListener(HActionListener l) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ actionHelper.addHActionListener(l);
}
public void removeHActionListener(HActionListener l) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ actionHelper.removeHActionListener(l);
}
public void setActionCommand(String command) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ actionHelper.setActionCommand(command);
}
public void setActionSound(HSound sound) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ actionHelper.setActionSound(sound);
}
public HSound getActionSound() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return null;
+ return actionHelper.getActionSound();
}
public void processHActionEvent(HActionEvent evt) {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
+ int state = getInteractionState();
+ int newState = actionHelper.processHActionEvent(evt);
+
+ if (state != newState) {
+ setInteractionState(newState);
+ }
}
public String getActionCommand() {
- org.videolan.Logger.unimplemented(HGraphicButton.class.getName(), "");
- return "";
+ return actionHelper.getActionCommand();
+ }
+
+ // HNavigable methods are inherited from HIcon
+ // Focus handling is inherited from HIcon
+
+ /**
+ * Process key events for HAVI navigation and action.
+ * Handles ENTER via actionHelper, delegates navigation to parent.
+ */
+ protected void processKeyEvent(KeyEvent e) {
+ // Let actionHelper handle ENTER key
+ if (actionHelper.processKeyEvent(e)) {
+ e.consume();
+ return;
+ }
+
+ // Delegate navigation (arrows) to parent HIcon
+ super.processKeyEvent(e);
}
- private static HGraphicLook DefaultLook = null;
+ static final Class DEFAULT_LOOK = HGraphicLook.class;
+ private static final String PROPERTY_LOOK = HGraphicButton.class.getName();
private static final long serialVersionUID = 5167775411684840800L;
}
=====================================
src/libbluray/bdj/java/org/havi/ui/HTextButton.java
=====================================
@@ -1,6 +1,7 @@
/*
* This file is part of libbluray
* Copyright (C) 2010 William Hahne
+ * Copyright (C) 2024 libbluray project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,131 +22,111 @@ package org.havi.ui;
import java.awt.Color;
import java.awt.Font;
+import java.awt.event.KeyEvent;
+
import org.havi.ui.event.HActionEvent;
import org.havi.ui.event.HActionListener;
import org.havi.ui.event.HFocusEvent;
import org.havi.ui.event.HFocusListener;
+import org.videolan.BDJXletContext;
+
public class HTextButton extends HText implements HActionable {
+
+ private HActionableHelper actionHelper;
+
public HTextButton() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ super();
+ initAction();
}
public HTextButton(String text, int x, int y, int width, int height) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ super(text, x, y, width, height);
+ initAction();
}
public HTextButton(String text, int x, int y, int width, int height,
Font font, Color foreground, Color background,
HTextLayoutManager tlm) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ super(text, x, y, width, height, font, foreground, background, tlm);
+ initAction();
}
public HTextButton(String text) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ super(text);
+ initAction();
}
public HTextButton(String text, Font font, Color foreground,
Color background, HTextLayoutManager tlm) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ super(text, font, foreground, background, tlm);
+ initAction();
}
- public static void setDefaultLook(HTextLook hlook) {
- DefaultLook = hlook;
+ private void initAction() {
+ actionHelper = new HActionableHelper(this);
}
- public static HTextLook getDefaultLook() {
- if (DefaultLook == null)
- org.videolan.Logger.unimplemented("", "getDefaultLook");
- return DefaultLook;
- }
-
- public void setMove(int keyCode, HNavigable target) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- }
-
- public HNavigable getMove(int keyCode)
- {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return null;
- }
-
- public void setFocusTraversal(HNavigable up, HNavigable down,
- HNavigable left, HNavigable right) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- }
-
- public boolean isSelected() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return false;
- }
-
- public void setGainFocusSound(HSound sound) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- }
-
- public void setLoseFocusSound(HSound sound) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- }
-
- public HSound getGainFocusSound() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return null;
- }
-
- public HSound getLoseFocusSound() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return null;
- }
-
- public void addHFocusListener(HFocusListener l) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- }
-
- public void removeHFocusListener(HFocusListener l) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ public static void setDefaultLook(HTextLook hlook) {
+ BDJXletContext.setXletDefaultLook(PROPERTY_LOOK, hlook);
}
- public int[] getNavigationKeys() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return null;
+ public static HTextLook getDefaultLook() {
+ return (HTextLook) BDJXletContext.getXletDefaultLook(PROPERTY_LOOK, DEFAULT_LOOK);
}
- public void processHFocusEvent(HFocusEvent evt) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- }
+ // --- HActionable implementation ---
public void addHActionListener(HActionListener l) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ actionHelper.addHActionListener(l);
}
public void removeHActionListener(HActionListener l) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ actionHelper.removeHActionListener(l);
}
public void setActionCommand(String command) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ actionHelper.setActionCommand(command);
}
public void setActionSound(HSound sound) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ actionHelper.setActionSound(sound);
}
public HSound getActionSound() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return null;
+ return actionHelper.getActionSound();
}
public void processHActionEvent(HActionEvent evt) {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
+ int state = getInteractionState();
+ int newState = actionHelper.processHActionEvent(evt);
+
+ if (state != newState) {
+ setInteractionState(newState);
+ }
}
public String getActionCommand() {
- org.videolan.Logger.unimplemented(HTextButton.class.getName(), "");
- return null;
+ return actionHelper.getActionCommand();
+ }
+
+ // HNavigable methods are inherited from HText
+ // Focus handling is inherited from HText
+
+ /**
+ * Process key events for HAVI navigation and action.
+ * Handles ENTER via actionHelper, delegates navigation to parent.
+ */
+ protected void processKeyEvent(KeyEvent e) {
+ if (actionHelper.processKeyEvent(e)) {
+ e.consume();
+ return;
+ }
+ super.processKeyEvent(e);
}
- private static HTextLook DefaultLook = null;
+ static final Class DEFAULT_LOOK = HTextLook.class;
+ private static final String PROPERTY_LOOK = HTextButton.class.getName();
private static final long serialVersionUID = 7563558661769889160L;
}
View it on GitLab: https://code.videolan.org/videolan/libbluray/-/commit/db77318fc4cb4720187983e67b689bdbae033eeb
--
View it on GitLab: https://code.videolan.org/videolan/libbluray/-/commit/db77318fc4cb4720187983e67b689bdbae033eeb
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the libbluray-devel
mailing list