From 63950edc968c5fa0fb3daec8a1d97b15caf8ded5 Mon Sep 17 00:00:00 2001 From: coolGi Date: Thu, 23 Mar 2023 18:08:36 +1030 Subject: [PATCH] Sava commit for the new Config UI --- .../lod/core/config/gui/AbstractScreen.java | 1 + .../core/config/gui/EmbeddedFrameUtil.java | 146 ++++++++++++++++++ .../core/config/gui/JavaFXConfigScreen.java | 60 +++++++ .../seibel/lod/core/jar/DarkModeDetector.java | 4 +- .../java/com/seibel/lod/core/jar/JarMain.java | 17 -- .../com/seibel/lod/core/jar/JarUtils.java | 15 ++ 6 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 core/src/main/java/com/seibel/lod/core/config/gui/EmbeddedFrameUtil.java diff --git a/core/src/main/java/com/seibel/lod/core/config/gui/AbstractScreen.java b/core/src/main/java/com/seibel/lod/core/config/gui/AbstractScreen.java index dcbd4f1f6..e81cbfd96 100644 --- a/core/src/main/java/com/seibel/lod/core/config/gui/AbstractScreen.java +++ b/core/src/main/java/com/seibel/lod/core/config/gui/AbstractScreen.java @@ -10,6 +10,7 @@ import java.util.List; * @author coolGi */ public abstract class AbstractScreen { + public long minecraftWindow; public int width; public int height; public int mouseX = 0; diff --git a/core/src/main/java/com/seibel/lod/core/config/gui/EmbeddedFrameUtil.java b/core/src/main/java/com/seibel/lod/core/config/gui/EmbeddedFrameUtil.java new file mode 100644 index 000000000..53d39226c --- /dev/null +++ b/core/src/main/java/com/seibel/lod/core/config/gui/EmbeddedFrameUtil.java @@ -0,0 +1,146 @@ +package com.seibel.lod.core.config.gui; + +import com.seibel.lod.core.jar.JarUtils; +import org.lwjgl.system.*; +import org.lwjgl.system.jawt.JAWT; +import org.lwjgl.system.macosx.*; + +import java.awt.*; +import java.lang.reflect.*; +import java.util.regex.*; + +import static org.lwjgl.glfw.GLFWNativeCocoa.*; +import static org.lwjgl.glfw.GLFWNativeWin32.*; +import static org.lwjgl.glfw.GLFWNativeX11.*; +import static org.lwjgl.system.JNI.*; +import static org.lwjgl.system.jawt.JAWTFunctions.*; +import static org.lwjgl.system.macosx.ObjCRuntime.*; + +// Some of the code is from https://github.com/LWJGL/lwjgl3/blob/master/modules/samples/src/test/java/org/lwjgl/demo/system/jawt/EmbeddedFrameUtil.java +// which is licensed under https://www.lwjgl.org/license + +public final class EmbeddedFrameUtil { + + private static final int JAVA_VERSION; + + private static final JAWT awt; + + static { + System.setProperty("java.awt.headless", "false"); + + Pattern p = Pattern.compile("^(?:1[.])?([1-9][0-9]*)[.-]"); + Matcher m = p.matcher(System.getProperty("java.version")); + + if (!m.find()) { + throw new IllegalStateException("Failed to parse java.version"); + } + + JAVA_VERSION = Integer.parseInt(m.group(1)); + + awt = JAWT.calloc(); + awt.version(JAVA_VERSION < 9 ? JAWT_VERSION_1_4 : JAWT_VERSION_9); +// if (!JAWT_GetAWT(awt)) { +// throw new RuntimeException("GetAWT failed"); +// } + } + + private static String getEmbeddedFrameImpl() { + switch (JarUtils.getOperatingSystem()) { + case LINUX: + return "sun.awt.X11.XEmbeddedFrame"; + case WINDOWS: + return "sun.awt.windows.WEmbeddedFrame"; + case MACOS: + return "sun.lwawt.macosx.CViewEmbeddedFrame"; + default: + throw new IllegalStateException(); // TODO: Find a compromise for other os' + } + } + + private static long getEmbeddedFrameHandle(long window) { + switch (Platform.get()) { + case LINUX: + return glfwGetX11Window(window); + case WINDOWS: + return glfwGetWin32Window(window); + case MACOSX: + long objc_msgSend = ObjCRuntime.getLibrary().getFunctionAddress("objc_msgSend"); + return invokePPP(glfwGetCocoaWindow(window), sel_getUid("contentView"), objc_msgSend); + default: + throw new IllegalStateException(); + } + } + + public static Frame embeddedFrameCreate(long window) { + if (JAVA_VERSION < 9) { + try { + @SuppressWarnings("unchecked") + Class EmdeddedFrame = (Class)Class.forName(getEmbeddedFrameImpl()); + Constructor c = EmdeddedFrame.getConstructor(long.class); + + return c.newInstance(getEmbeddedFrameHandle(window)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + return nJAWT_CreateEmbeddedFrame(getEmbeddedFrameHandle(window), awt.CreateEmbeddedFrame()); + } + } + + static void embeddedFrameSynthesizeWindowActivation(Frame embeddedFrame, boolean doActivate) { + if (JAVA_VERSION < 9) { + try { + embeddedFrame + .getClass() + .getMethod("synthesizeWindowActivation", boolean.class) + .invoke(embeddedFrame, doActivate); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + JAWT_SynthesizeWindowActivation(embeddedFrame, doActivate, awt.SynthesizeWindowActivation()); + } + } + + public static void embeddedFrameSetBounds(Frame embeddedFrame, int x, int y, int width, int height) { + if (JAVA_VERSION < 9) { + try { + Method setLocationPrivate = embeddedFrame + .getClass() + .getSuperclass() + .getDeclaredMethod("setBoundsPrivate", int.class, int.class, int.class, int.class); + setLocationPrivate.setAccessible(true); + setLocationPrivate.invoke(embeddedFrame, x, y, width, height); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + JAWT_SetBounds(embeddedFrame, x, y, width, height, awt.SetBounds()); + } + } + + // The code below is by me + + public static void hideFrame(Frame embeddedFrame) { + if (embeddedFrame != null) { + embeddedFrame.setVisible(false); + embeddedFrameSynthesizeWindowActivation(embeddedFrame, false); + } + } + + public static void showFrame(Frame embeddedFrame) { + if (embeddedFrame != null) { + embeddedFrameSynthesizeWindowActivation(embeddedFrame, true); + embeddedFrame.setVisible(true); + } + } + + public static void placeAtCenter(Frame embeddedFrame, int windowWidth, int windowHeight, int frameWidth, int frameHeight, float scale) { + float scaleFactor = (100.0F - scale) / 100.0F; + float newWidth = frameWidth * scaleFactor; + float newHeight = frameHeight * scaleFactor; + float newX = (windowWidth - newWidth) / 2F; + float newY = (windowHeight - newHeight) / 2F; + embeddedFrameSetBounds(embeddedFrame, Math.round(newX), Math.round(newY), Math.round(newWidth), Math.round(newHeight)); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/seibel/lod/core/config/gui/JavaFXConfigScreen.java b/core/src/main/java/com/seibel/lod/core/config/gui/JavaFXConfigScreen.java index 46bcfa0b0..55547b053 100644 --- a/core/src/main/java/com/seibel/lod/core/config/gui/JavaFXConfigScreen.java +++ b/core/src/main/java/com/seibel/lod/core/config/gui/JavaFXConfigScreen.java @@ -1,9 +1,69 @@ package com.seibel.lod.core.config.gui; +import com.seibel.lod.core.jar.JarUtils; +import javafx.embed.swing.JFXPanel; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.application.Platform; +import javafx.embed.swing.SwingNode; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.layout.StackPane; +import javafx.scene.text.Text; +import javafx.stage.Stage; +import javax.swing.*; +import java.awt.*; +import javafx.application.Platform; +import javafx.embed.swing.JFXPanel; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.Text; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + public class JavaFXConfigScreen extends AbstractScreen { @Override public void init() { + Frame frame = EmbeddedFrameUtil.embeddedFrameCreate(this.minecraftWindow); + + final JFXPanel fxPanel = new JFXPanel(); + frame.add(fxPanel); + frame.setSize(300, 200); + frame.setVisible(true); + + Platform.runLater(new Runnable() { + @Override + public void run() { + initFX(fxPanel); + } + }); + + EmbeddedFrameUtil.placeAtCenter(frame, this.width, this.height, 100, 100, 1); + } + + + private static void initFX(JFXPanel fxPanel) { + // This method is invoked on the JavaFX thread + Scene scene = createScene(); + fxPanel.setScene(scene); + } + + private static Scene createScene() { + Group root = new Group(); + Scene scene = new Scene(root, Color.ALICEBLUE); + Text text = new Text(); + + text.setX(40); + text.setY(100); + text.setFont(new Font(25)); + text.setText("Welcome JavaFX!"); + + root.getChildren().add(text); + + return (scene); } @Override diff --git a/core/src/main/java/com/seibel/lod/core/jar/DarkModeDetector.java b/core/src/main/java/com/seibel/lod/core/jar/DarkModeDetector.java index 122d5c3e8..db0e7e403 100644 --- a/core/src/main/java/com/seibel/lod/core/jar/DarkModeDetector.java +++ b/core/src/main/java/com/seibel/lod/core/jar/DarkModeDetector.java @@ -3,8 +3,6 @@ package com.seibel.lod.core.jar; import java.io.*; import java.util.regex.Pattern; -import static com.seibel.lod.core.jar.JarMain.getOperatingSystem; - /** * A fork of iris'is dark mode detector (https://github.com/IrisShaders/Iris-Installer/blob/master/src/main/java/net/hypercubemc/iris_installer/DarkModeDetector.java) * Which is a fork of HanSolo's dark mode detector (https://gist.github.com/HanSolo/7cf10b86efff8ca2845bf5ec2dd0fe1d) @@ -21,7 +19,7 @@ public class DarkModeDetector { private static final String DARK_THEME_CMD = REGQUERY_UTIL + "\"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\"" + " /v AppsUseLightTheme"; public static boolean isDarkMode() { - switch (getOperatingSystem()) { + switch (JarUtils.getOperatingSystem()) { case WINDOWS: return isWindowsDarkMode(); case MACOS: diff --git a/core/src/main/java/com/seibel/lod/core/jar/JarMain.java b/core/src/main/java/com/seibel/lod/core/jar/JarMain.java index 524ecbb8b..6d2e606c5 100644 --- a/core/src/main/java/com/seibel/lod/core/jar/JarMain.java +++ b/core/src/main/java/com/seibel/lod/core/jar/JarMain.java @@ -81,21 +81,4 @@ public class JarMain extends Application { return; } } - - - - - public enum OperatingSystem {WINDOWS, MACOS, LINUX, NONE} // Easy to use enum for the 3 main os's - public static OperatingSystem getOperatingSystem() { // Get the os and turn it into that enum - String os = System.getProperty("os.name").toLowerCase(); - if (os.contains("win")) { - return OperatingSystem.WINDOWS; - } else if (os.contains("mac")) { - return OperatingSystem.MACOS; - } else if (os.contains("nix") || os.contains("nux")) { - return OperatingSystem.LINUX; - } else { - return OperatingSystem.NONE; - } - } } diff --git a/core/src/main/java/com/seibel/lod/core/jar/JarUtils.java b/core/src/main/java/com/seibel/lod/core/jar/JarUtils.java index c79aceece..d071f8f84 100644 --- a/core/src/main/java/com/seibel/lod/core/jar/JarUtils.java +++ b/core/src/main/java/com/seibel/lod/core/jar/JarUtils.java @@ -103,4 +103,19 @@ public class JarUtils { //return complete hash return sb.toString(); } + + + public enum OperatingSystem {WINDOWS, MACOS, LINUX, NONE} // Easy to use enum for the 3 main os's + public static OperatingSystem getOperatingSystem() { // Get the os and turn it into that enum + String os = System.getProperty("os.name").toLowerCase(); + if (os.contains("win")) { + return OperatingSystem.WINDOWS; + } else if (os.contains("mac")) { + return OperatingSystem.MACOS; + } else if (os.contains("nix") || os.contains("nux")) { + return OperatingSystem.LINUX; + } else { + return OperatingSystem.NONE; + } + } }