diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle index ab5b93bb8a..1bd61db567 100644 --- a/app_pojavlauncher/build.gradle +++ b/app_pojavlauncher/build.gradle @@ -187,6 +187,7 @@ dependencies { implementation 'com.github.PojavLauncherTeam:portrait-ssp:6c02fd739b' implementation 'com.github.Mathias-Boulay:ExtendedView:1.0.0' implementation 'com.github.Mathias-Boulay:android_gamepad_remapper:eb92e3a5bb' + implementation 'com.github.Mathias-Boulay:virtual-joystick-android:cb7bf45ba5' // implementation 'com.intuit.sdp:sdp-android:1.0.5' diff --git a/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar b/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar index 4b12ae0922..de7650cc03 100644 Binary files a/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar and b/app_pojavlauncher/src/main/assets/components/lwjgl3/lwjgl-glfw-classes.jar differ diff --git a/app_pojavlauncher/src/main/assets/components/lwjgl3/version b/app_pojavlauncher/src/main/assets/components/lwjgl3/version index 3a511f8cbd..f4d001ea1f 100644 --- a/app_pojavlauncher/src/main/assets/components/lwjgl3/version +++ b/app_pojavlauncher/src/main/assets/components/lwjgl3/version @@ -1 +1 @@ -1689180036097 \ No newline at end of file +1687078018167 \ No newline at end of file diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java index b8f3e5a4e1..c913162ef5 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java @@ -12,6 +12,7 @@ import net.kdt.pojavlaunch.customcontrols.ControlData; import net.kdt.pojavlaunch.customcontrols.ControlDrawerData; +import net.kdt.pojavlaunch.customcontrols.ControlJoystickData; import net.kdt.pojavlaunch.customcontrols.ControlLayout; import net.kdt.pojavlaunch.customcontrols.EditorExitable; import net.kdt.pojavlaunch.prefs.LauncherPreferences; @@ -43,11 +44,11 @@ protected void onCreate(Bundle savedInstanceState) { switch(position) { case 0: mControlLayout.addControlButton(new ControlData("New")); break; case 1: mControlLayout.addDrawer(new ControlDrawerData()); break; - //case 2: mControlLayout.addJoystickButton(new ControlData()); break; - case 2: mControlLayout.openLoadDialog(); break; - case 3: mControlLayout.openSaveDialog(this); break; - case 4: mControlLayout.openSetDefaultDialog(); break; - case 5: // Saving the currently shown control + case 2: mControlLayout.addJoystickButton(new ControlJoystickData()); break; + case 3: mControlLayout.openLoadDialog(); break; + case 4: mControlLayout.openSaveDialog(this); break; + case 5: mControlLayout.openSetDefaultDialog(); break; + case 6: // Saving the currently shown control try { Uri contentUri = DocumentsContract.buildDocumentUri(getString(R.string.storageProviderAuthorities), mControlLayout.saveToDirectory(mControlLayout.mLayoutFileName)); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java index 5b753efa59..c865e3a0bf 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/JMinecraftVersionList.java @@ -39,6 +39,7 @@ public static class Version extends FileProperties { public static class JavaVersionInfo { public String component; public int majorVersion; + public int version; // parameter used by LabyMod 4 } @Keep public static class LoggingConfig { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java index acd65d4c74..054bb8d9f3 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java @@ -446,9 +446,11 @@ public boolean dispatchCapturedPointerEvent(MotionEvent e) { CallbackBridge.mouseX += (e.getX()* mScaleFactor); CallbackBridge.mouseY += (e.getY()* mScaleFactor); + // Position is updated by many events, hence it is send regardless of the event value + CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); + switch (e.getActionMasked()) { case MotionEvent.ACTION_MOVE: - CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); return true; case MotionEvent.ACTION_BUTTON_PRESS: return sendMouseButtonUnconverted(e.getActionButton(), true); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 6b32ff9a98..8610650be8 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -618,6 +618,34 @@ private static boolean checkRules(JMinecraftVersionList.Arguments.ArgValue.ArgRu } return true; // allow if none match } + + private static void preProcessLibraries(DependentLibrary[] libraries) { + for (int i = 0; i < libraries.length; i++) { + DependentLibrary libItem = libraries[i]; + String[] version = libItem.name.split(":")[2].split("\\."); + if (libItem.name.startsWith("net.java.dev.jna:jna:")) { + // Special handling for LabyMod 1.8.9, Forge 1.12.2(?) and oshi + // we have libjnidispatch 5.13.0 in jniLibs directory + if (Integer.parseInt(version[0]) >= 5 && Integer.parseInt(version[1]) >= 13) return; + Log.d(APP_NAME, "Library " + libItem.name + " has been changed to version 5.13.0"); + libItem.name = "net.java.dev.jna:jna:5.13.0"; + libItem.downloads.artifact.path = "net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar"; + libItem.downloads.artifact.sha1 = "1200e7ebeedbe0d10062093f32925a912020e747"; + libItem.downloads.artifact.url = "https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar"; + } else if (libItem.name.startsWith("com.github.oshi:oshi-core:")) { + //if (Integer.parseInt(version[0]) >= 6 && Integer.parseInt(version[1]) >= 3) return; + // FIXME: ensure compatibility + + if (Integer.parseInt(version[0]) != 6 || Integer.parseInt(version[1]) != 2) return; + Log.d(APP_NAME, "Library " + libItem.name + " has been changed to version 6.3.0"); + libItem.name = "com.github.oshi:oshi-core:6.3.0"; + libItem.downloads.artifact.path = "com/github/oshi/oshi-core/6.3.0/oshi-core-6.3.0.jar"; + libItem.downloads.artifact.sha1 = "9e98cf55be371cafdb9c70c35d04ec2a8c2b42ac"; + libItem.downloads.artifact.url = "https://repo1.maven.org/maven2/com/github/oshi/oshi-core/6.3.0/oshi-core-6.3.0.jar"; + } + } + } + public static String[] generateLibClasspath(JMinecraftVersionList.Version info) { List libDir = new ArrayList<>(); for (DependentLibrary libItem: info.libraries) { @@ -636,7 +664,7 @@ public static JMinecraftVersionList.Version getVersionInfo(String versionName, b try { JMinecraftVersionList.Version customVer = Tools.GLOBAL_GSON.fromJson(read(DIR_HOME_VERSION + "/" + versionName + "/" + versionName + ".json"), JMinecraftVersionList.Version.class); if (skipInheriting || customVer.inheritsFrom == null || customVer.inheritsFrom.equals(customVer.id)) { - return customVer; + preProcessLibraries(customVer.libraries); } else { JMinecraftVersionList.Version inheritsVer; //If it won't download, just search for it @@ -674,6 +702,7 @@ public static JMinecraftVersionList.Version getVersionInfo(String versionName, b } } finally { inheritsVer.libraries = libList.toArray(new DependentLibrary[0]); + preProcessLibraries(inheritsVer.libraries); } // Inheriting Minecraft 1.13+ with append custom args @@ -711,8 +740,14 @@ public static JMinecraftVersionList.Version getVersionInfo(String versionName, b inheritsVer.arguments.game = totalArgList.toArray(new Object[0]); } - return inheritsVer; + customVer = inheritsVer; + } + + // LabyMod 4 sets version instead of majorVersion + if (customVer.javaVersion.majorVersion == 0) { + customVer.javaVersion.majorVersion = customVer.javaVersion.version; } + return customVer; } catch (Exception e) { throw new RuntimeException(e); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java index 4d50ba9832..5f39ec0c25 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlData.java @@ -32,21 +32,19 @@ public class ControlData { public static final int SPECIALBTN_SCROLLUP = -7; public static final int SPECIALBTN_SCROLLDOWN = -8; public static final int SPECIALBTN_MENU = -9; - + private static ControlData[] SPECIAL_BUTTONS; private static List SPECIAL_BUTTON_NAME_ARRAY; - - // Internal usage only - public boolean isHideable; - private static WeakReference builder = new WeakReference<>(null); - private static WeakReference> conversionMap = new WeakReference<>(null); + private static WeakReference> conversionMap = new WeakReference<>(null); + static { buildExpressionBuilder(); buildConversionMap(); } - + // Internal usage only + public boolean isHideable; /** * Both fields below are dynamic position data, auto updates * X and Y position, unlike the original one which uses fixed @@ -56,60 +54,29 @@ public class ControlData { */ public String dynamicX, dynamicY; public boolean isDynamicBtn, isToggle, passThruEnabled; - - public static ControlData[] getSpecialButtons(){ - if (SPECIAL_BUTTONS == null) { - SPECIAL_BUTTONS = new ControlData[]{ - new ControlData("Keyboard", new int[]{SPECIALBTN_KEYBOARD}, "${margin} * 3 + ${width} * 2", "${margin}", false), - new ControlData("GUI", new int[]{SPECIALBTN_TOGGLECTRL}, "${margin}", "${bottom} - ${margin}"), - new ControlData("PRI", new int[]{SPECIALBTN_MOUSEPRI}, "${margin}", "${screen_height} - ${margin} * 3 - ${height} * 3"), - new ControlData("SEC", new int[]{SPECIALBTN_MOUSESEC}, "${margin} * 3 + ${width} * 2", "${screen_height} - ${margin} * 3 - ${height} * 3"), - new ControlData("Mouse", new int[]{SPECIALBTN_VIRTUALMOUSE}, "${right}", "${margin}", false), - - new ControlData("MID", new int[]{SPECIALBTN_MOUSEMID}, "${margin}", "${margin}"), - new ControlData("SCROLLUP", new int[]{SPECIALBTN_SCROLLUP}, "${margin}", "${margin}"), - new ControlData("SCROLLDOWN", new int[]{SPECIALBTN_SCROLLDOWN}, "${margin}", "${margin}"), - new ControlData("MENU", new int[]{SPECIALBTN_MENU}, "${margin}", "${margin}") - }; - } - - return SPECIAL_BUTTONS; - } - - public static List buildSpecialButtonArray() { - if (SPECIAL_BUTTON_NAME_ARRAY == null) { - List nameList = new ArrayList<>(); - for (ControlData btn : getSpecialButtons()) { - nameList.add("SPECIAL_" + btn.name); - } - SPECIAL_BUTTON_NAME_ARRAY = nameList; - Collections.reverse(SPECIAL_BUTTON_NAME_ARRAY); - } - - return SPECIAL_BUTTON_NAME_ARRAY; - } - public String name; - private float width; //Dp instead of Px now - private float height; //Dp instead of Px now public int[] keycodes; //Should store up to 4 keys public float opacity; //Alpha value from 0 to 1; public int bgColor; public int strokeColor; - public int strokeWidth; //0-100% + public float strokeWidth; // Dp instead of % now public float cornerRadius; //0-100% public boolean isSwipeable; + public boolean displayInGame; + public boolean displayInMenu; + private float width; //Dp instead of Px now + private float height; //Dp instead of Px now public ControlData() { this("button"); } - public ControlData(String name){ - this(name, new int[] {}); + public ControlData(String name) { + this(name, new int[]{}); } public ControlData(String name, int[] keycodes) { - this(name, keycodes, Tools.currentDisplayMetrics.widthPixels/2f, Tools.currentDisplayMetrics.heightPixels/2f); + this(name, keycodes, Tools.currentDisplayMetrics.widthPixels / 2f, Tools.currentDisplayMetrics.heightPixels / 2f); } public ControlData(String name, int[] keycodes, float x, float y) { @@ -141,11 +108,11 @@ public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY this(name, keycodes, dynamicX, dynamicY, isSquare ? 50 : 80, isSquare ? 50 : 30, false); } - public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, float width, float height, boolean isToggle){ - this(name, keycodes, dynamicX, dynamicY, width, height, isToggle, 1,0x4D000000, 0xFFFFFFFF,0,0); + public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, float width, float height, boolean isToggle) { + this(name, keycodes, dynamicX, dynamicY, width, height, isToggle, 1, 0x4D000000, 0xFFFFFFFF, 0, 0, true, true); } - public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, float width, float height, boolean isToggle, float opacity, int bgColor, int strokeColor, int strokeWidth, float cornerRadius) { + public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY, float width, float height, boolean isToggle, float opacity, int bgColor, int strokeColor, float strokeWidth, float cornerRadius, boolean displayInGame, boolean displayInMenu) { this.name = name; this.keycodes = inflateKeycodeArray(keycodes); this.dynamicX = dynamicX; @@ -159,10 +126,12 @@ public ControlData(String name, int[] keycodes, String dynamicX, String dynamicY this.strokeColor = strokeColor; this.strokeWidth = strokeWidth; this.cornerRadius = cornerRadius; + this.displayInGame = displayInGame; + this.displayInMenu = displayInMenu; } //Deep copy constructor - public ControlData(ControlData controlData){ + public ControlData(ControlData controlData) { this( controlData.name, controlData.keycodes, @@ -175,17 +144,42 @@ public ControlData(ControlData controlData){ controlData.bgColor, controlData.strokeColor, controlData.strokeWidth, - controlData.cornerRadius + controlData.cornerRadius, + controlData.displayInGame, + controlData.displayInMenu ); } - - public float insertDynamicPos(String dynamicPos) { - // Insert value to ${variable} - String insertedPos = JSONUtils.insertSingleJSONValue(dynamicPos, fillConversionMap()); - - // Calculate, because the dynamic position contains some math equations - return calculate(insertedPos); + public static ControlData[] getSpecialButtons() { + if (SPECIAL_BUTTONS == null) { + SPECIAL_BUTTONS = new ControlData[]{ + new ControlData("Keyboard", new int[]{SPECIALBTN_KEYBOARD}, "${margin} * 3 + ${width} * 2", "${margin}", false), + new ControlData("GUI", new int[]{SPECIALBTN_TOGGLECTRL}, "${margin}", "${bottom} - ${margin}"), + new ControlData("PRI", new int[]{SPECIALBTN_MOUSEPRI}, "${margin}", "${screen_height} - ${margin} * 3 - ${height} * 3"), + new ControlData("SEC", new int[]{SPECIALBTN_MOUSESEC}, "${margin} * 3 + ${width} * 2", "${screen_height} - ${margin} * 3 - ${height} * 3"), + new ControlData("Mouse", new int[]{SPECIALBTN_VIRTUALMOUSE}, "${right}", "${margin}", false), + + new ControlData("MID", new int[]{SPECIALBTN_MOUSEMID}, "${margin}", "${margin}"), + new ControlData("SCROLLUP", new int[]{SPECIALBTN_SCROLLUP}, "${margin}", "${margin}"), + new ControlData("SCROLLDOWN", new int[]{SPECIALBTN_SCROLLDOWN}, "${margin}", "${margin}"), + new ControlData("MENU", new int[]{SPECIALBTN_MENU}, "${margin}", "${margin}") + }; + } + + return SPECIAL_BUTTONS; + } + + public static List buildSpecialButtonArray() { + if (SPECIAL_BUTTON_NAME_ARRAY == null) { + List nameList = new ArrayList<>(); + for (ControlData btn : getSpecialButtons()) { + nameList.add("SPECIAL_" + btn.name); + } + SPECIAL_BUTTON_NAME_ARRAY = nameList; + Collections.reverse(SPECIAL_BUTTON_NAME_ARRAY); + } + + return SPECIAL_BUTTON_NAME_ARRAY; } private static float calculate(String math) { @@ -193,44 +187,16 @@ private static float calculate(String math) { return (float) builder.get().build().evaluate(); } - private static int[] inflateKeycodeArray(int[] keycodes){ + private static int[] inflateKeycodeArray(int[] keycodes) { int[] inflatedArray = new int[]{GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN}; System.arraycopy(keycodes, 0, inflatedArray, 0, keycodes.length); return inflatedArray; } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - public boolean containsKeycode(int keycodeToCheck){ - for(int keycode : keycodes) - if(keycodeToCheck == keycode) - return true; - - return false; - } - - //Getters || setters (with conversion for ease of use) - public float getWidth() { - return Tools.dpToPx(width); - } - - public float getHeight(){ - return Tools.dpToPx(height); - } - - - public void setWidth(float widthInPx){ - width = Tools.pxToDp(widthInPx); - } - - public void setHeight(float heightInPx){ - height = Tools.pxToDp(heightInPx); - } - /** * Create a builder, keep a weak reference to it to use it with all views on first inflation */ - private static void buildExpressionBuilder(){ + private static void buildExpressionBuilder() { ExpressionBuilder expressionBuilder = new ExpressionBuilder("1 + 1") .function(new Function("dp", 1) { @Override @@ -249,10 +215,11 @@ public double apply(double... args) { /** * wrapper for the WeakReference to the expressionField. + * * @param stringExpression the expression to set. */ - private static void setExpression(String stringExpression){ - if(builder.get() == null) buildExpressionBuilder(); + private static void setExpression(String stringExpression) { + if (builder.get() == null) buildExpressionBuilder(); builder.get().expression(stringExpression); } @@ -269,7 +236,7 @@ private static void buildConversionMap() { keyValueMap.put("bottom", "DUMMY_BOTTOM"); keyValueMap.put("width", "DUMMY_WIDTH"); keyValueMap.put("height", "DUMMY_HEIGHT"); - keyValueMap.put("screen_width", "DUMMY_DATA" ); + keyValueMap.put("screen_width", "DUMMY_DATA"); keyValueMap.put("screen_height", "DUMMY_DATA"); keyValueMap.put("margin", Integer.toString((int) Tools.dpToPx(2))); keyValueMap.put("preferred_scale", "DUMMY_DATA"); @@ -277,14 +244,49 @@ private static void buildConversionMap() { conversionMap = new WeakReference<>(keyValueMap); } + public float insertDynamicPos(String dynamicPos) { + // Insert value to ${variable} + String insertedPos = JSONUtils.insertSingleJSONValue(dynamicPos, fillConversionMap()); + + // Calculate, because the dynamic position contains some math equations + return calculate(insertedPos); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean containsKeycode(int keycodeToCheck) { + for (int keycode : keycodes) + if (keycodeToCheck == keycode) + return true; + + return false; + } + + //Getters || setters (with conversion for ease of use) + public float getWidth() { + return Tools.dpToPx(width); + } + + public void setWidth(float widthInPx) { + width = Tools.pxToDp(widthInPx); + } + + public float getHeight() { + return Tools.dpToPx(height); + } + + public void setHeight(float heightInPx) { + height = Tools.pxToDp(heightInPx); + } + /** * Fill the conversionMap with controlData dependent values. * The returned valueMap should NOT be kept in memory. + * * @return the valueMap to use. */ - private Map fillConversionMap(){ + private Map fillConversionMap() { ArrayMap valueMap = conversionMap.get(); - if (valueMap == null){ + if (valueMap == null) { buildConversionMap(); valueMap = conversionMap.get(); } @@ -293,8 +295,8 @@ private Map fillConversionMap(){ valueMap.put("bottom", Float.toString(CallbackBridge.physicalHeight - getHeight())); valueMap.put("width", Float.toString(getWidth())); valueMap.put("height", Float.toString(getHeight())); - valueMap.put("screen_width",Integer.toString(CallbackBridge.physicalWidth)); - valueMap.put("screen_height",Integer.toString(CallbackBridge.physicalHeight)); + valueMap.put("screen_width", Integer.toString(CallbackBridge.physicalWidth)); + valueMap.put("screen_height", Integer.toString(CallbackBridge.physicalHeight)); valueMap.put("preferred_scale", Float.toString(LauncherPreferences.PREF_BUTTONSIZE)); return valueMap; diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlJoystickData.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlJoystickData.java new file mode 100644 index 0000000000..9944895946 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlJoystickData.java @@ -0,0 +1,15 @@ +package net.kdt.pojavlaunch.customcontrols; + +public class ControlJoystickData extends ControlData { + + /* Whether the joystick can stay forward */ + public boolean forwardLock = false; + + public ControlJoystickData(){ + super(); + } + + public ControlJoystickData(ControlData properties) { + super(properties); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java index 9c50008942..671db9e3b8 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java @@ -1,8 +1,11 @@ package net.kdt.pojavlaunch.customcontrols; import static android.content.Context.INPUT_METHOD_SERVICE; +import static net.kdt.pojavlaunch.MainActivity.mControlLayout; import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics; +import static org.lwjgl.glfw.CallbackBridge.isGrabbing; + import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; @@ -27,6 +30,7 @@ import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer; import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlJoystick; import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton; import net.kdt.pojavlaunch.customcontrols.handleview.ActionRow; import net.kdt.pojavlaunch.customcontrols.handleview.ControlHandleView; @@ -107,6 +111,12 @@ public void loadLayout(CustomControls controlLayout) { if(mModifiable) drawer.areButtonsVisible = true; } + // Joystick(s) + for(ControlJoystickData joystick : mLayout.mJoystickDataList){ + addJoystickView(joystick); + } + + mLayout.scaledAt = LauncherPreferences.PREF_BUTTONSIZE; setModified(false); @@ -177,15 +187,26 @@ private void addSubView(ControlDrawer drawer, ControlData controlButton){ view.setFocusable(false); view.setFocusableInTouchMode(false); }else{ - view.setVisible(drawer.areButtonsVisible); + view.setVisible(true); } - drawer.addButton(view); addView(view); + drawer.addButton(view); + setModified(true); } + // JOYSTICK BUTTON + public void addJoystickButton(ControlJoystickData data){ + mLayout.mJoystickDataList.add(data); + addJoystickView(data); + } + + private void addJoystickView(ControlJoystickData data){ + addView(new ControlJoystick(this, data)); + } + private void removeAllButtons() { for(ControlInterface button : getButtonChildren()){ @@ -220,7 +241,7 @@ public void setControlVisible(boolean isVisible) { mControlVisible = isVisible; for(ControlInterface button : getButtonChildren()){ - button.setVisible(isVisible); + button.setVisible(((button.getProperties().displayInGame && isGrabbing()) || (button.getProperties().displayInMenu && !isGrabbing())) && isVisible); } } @@ -229,6 +250,12 @@ public void setModifiable(boolean isModifiable) { removeEditWindow(); } mModifiable = isModifiable; + if(isModifiable){ + // In edit mode, all controls have to be shown + for(ControlInterface button : getButtonChildren()){ + button.setVisible(true); + } + } } public boolean getModifiable(){ diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java index 0dc96a0069..ffff12d1c6 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java @@ -13,16 +13,18 @@ public class CustomControls { public float scaledAt; public List mControlDataList; public List mDrawerDataList; + public List mJoystickDataList; public CustomControls() { - this(new ArrayList<>(), new ArrayList<>()); + this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } - public CustomControls(List mControlDataList, List mDrawerDataList) { + public CustomControls(List mControlDataList, List mDrawerDataList, List mJoystickDataList) { this.mControlDataList = mControlDataList; this.mDrawerDataList = mDrawerDataList; - this.scaledAt = 100f; + this.mJoystickDataList = mJoystickDataList; + this.scaledAt = 100f; } // Generate default control @@ -51,14 +53,14 @@ public CustomControls(Context ctx) { this.mControlDataList.add(shiftData); this.mControlDataList.add(new ControlData(ctx, R.string.control_jump, new int[]{LwjglGlfwKeycode.GLFW_KEY_SPACE}, "${right} - ${margin} * 2 - ${width}", "${bottom} - ${margin} * 2 - ${height}", true)); - //The default controls are conform to the V2 - version = 4; + //The default controls are conform to the V3 + version = 6; } public void save(String path) throws IOException { - //Current version is the V2.5 so the version as to be marked as 4 ! - version = 4; + //Current version is the V3.0 so the version as to be marked as 6 ! + version = 6; Tools.write(path, Tools.GLOBAL_GSON.toJson(this)); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java index d8e20a9079..89786b011e 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java @@ -20,105 +20,159 @@ public static CustomControls loadAndConvertIfNecessary(String jsonPath) throws I try { JSONObject layoutJobj = new JSONObject(jsonLayoutData); - if(!layoutJobj.has("version")) { //v1 layout + if (!layoutJobj.has("version")) { //v1 layout CustomControls layout = LayoutConverter.convertV1Layout(layoutJobj); layout.save(jsonPath); return layout; - }else if (layoutJobj.getInt("version") == 2) { + } else if (layoutJobj.getInt("version") == 2) { CustomControls layout = LayoutConverter.convertV2Layout(layoutJobj); layout.save(jsonPath); return layout; - }else if (layoutJobj.getInt("version") == 3 || layoutJobj.getInt("version") == 4) { + }else if (layoutJobj.getInt("version") >= 3 && layoutJobj.getInt("version") <= 5) { + return LayoutConverter.convertV3_4Layout(layoutJobj); + } else if (layoutJobj.getInt("version") == 6) { return Tools.GLOBAL_GSON.fromJson(jsonLayoutData, CustomControls.class); - }else{ + } else { return null; } - }catch (JSONException e) { - throw new JsonSyntaxException("Failed to load",e); + } catch (JSONException e) { + throw new JsonSyntaxException("Failed to load", e); } } + + + /** + * Normalize the layout to v6 from v3/4: The stroke width is no longer dependant on the button size + */ + public static CustomControls convertV3_4Layout(JSONObject oldLayoutJson) { + CustomControls layout = Tools.GLOBAL_GSON.fromJson(oldLayoutJson.toString(), CustomControls.class); + convertStrokeWidth(layout); + layout.version = 6; + return layout; + } + + public static CustomControls convertV2Layout(JSONObject oldLayoutJson) throws JSONException { CustomControls layout = Tools.GLOBAL_GSON.fromJson(oldLayoutJson.toString(), CustomControls.class); JSONArray layoutMainArray = oldLayoutJson.getJSONArray("mControlDataList"); layout.mControlDataList = new ArrayList<>(layoutMainArray.length()); - for(int i = 0; i < layoutMainArray.length(); i++) { + for (int i = 0; i < layoutMainArray.length(); i++) { JSONObject button = layoutMainArray.getJSONObject(i); ControlData n_button = Tools.GLOBAL_GSON.fromJson(button.toString(), ControlData.class); - if(!Tools.isValidString(n_button.dynamicX) && button.has("x")) { + if (!Tools.isValidString(n_button.dynamicX) && button.has("x")) { double buttonC = button.getDouble("x"); - double ratio = buttonC/CallbackBridge.physicalWidth; + double ratio = buttonC / CallbackBridge.physicalWidth; n_button.dynamicX = ratio + " * ${screen_width}"; } - if(!Tools.isValidString(n_button.dynamicY) && button.has("y")) { + if (!Tools.isValidString(n_button.dynamicY) && button.has("y")) { double buttonC = button.getDouble("y"); - double ratio = buttonC/CallbackBridge.physicalHeight; + double ratio = buttonC / CallbackBridge.physicalHeight; n_button.dynamicY = ratio + " * ${screen_height}"; } layout.mControlDataList.add(n_button); } JSONArray layoutDrawerArray = oldLayoutJson.getJSONArray("mDrawerDataList"); layout.mDrawerDataList = new ArrayList<>(); - for(int i = 0; i < layoutDrawerArray.length(); i++) { + for (int i = 0; i < layoutDrawerArray.length(); i++) { JSONObject button = layoutDrawerArray.getJSONObject(i); JSONObject buttonProperties = button.getJSONObject("properties"); ControlDrawerData n_button = Tools.GLOBAL_GSON.fromJson(button.toString(), ControlDrawerData.class); - if(!Tools.isValidString(n_button.properties.dynamicX) && buttonProperties.has("x")) { + if (!Tools.isValidString(n_button.properties.dynamicX) && buttonProperties.has("x")) { double buttonC = buttonProperties.getDouble("x"); - double ratio = buttonC/CallbackBridge.physicalWidth; + double ratio = buttonC / CallbackBridge.physicalWidth; n_button.properties.dynamicX = ratio + " * ${screen_width}"; } - if(!Tools.isValidString(n_button.properties.dynamicY) && buttonProperties.has("y")) { + if (!Tools.isValidString(n_button.properties.dynamicY) && buttonProperties.has("y")) { double buttonC = buttonProperties.getDouble("y"); - double ratio = buttonC/CallbackBridge.physicalHeight; + double ratio = buttonC / CallbackBridge.physicalHeight; n_button.properties.dynamicY = ratio + " * ${screen_height}"; } layout.mDrawerDataList.add(n_button); } + convertStrokeWidth(layout); + layout.version = 3; return layout; } + public static CustomControls convertV1Layout(JSONObject oldLayoutJson) throws JSONException { CustomControls empty = new CustomControls(); JSONArray layoutMainArray = oldLayoutJson.getJSONArray("mControlDataList"); - for(int i = 0; i < layoutMainArray.length(); i++) { + for (int i = 0; i < layoutMainArray.length(); i++) { JSONObject button = layoutMainArray.getJSONObject(i); ControlData n_button = new ControlData(); - int[] keycodes = new int[] {LwjglGlfwKeycode.GLFW_KEY_UNKNOWN, + int[] keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_UNKNOWN, LwjglGlfwKeycode.GLFW_KEY_UNKNOWN, LwjglGlfwKeycode.GLFW_KEY_UNKNOWN, LwjglGlfwKeycode.GLFW_KEY_UNKNOWN}; n_button.isDynamicBtn = button.getBoolean("isDynamicBtn"); n_button.dynamicX = button.getString("dynamicX"); n_button.dynamicY = button.getString("dynamicY"); - if(!Tools.isValidString(n_button.dynamicX) && button.has("x")) { + if (!Tools.isValidString(n_button.dynamicX) && button.has("x")) { double buttonC = button.getDouble("x"); - double ratio = buttonC/CallbackBridge.physicalWidth; + double ratio = buttonC / CallbackBridge.physicalWidth; n_button.dynamicX = ratio + " * ${screen_width}"; } - if(!Tools.isValidString(n_button.dynamicY) && button.has("y")) { + if (!Tools.isValidString(n_button.dynamicY) && button.has("y")) { double buttonC = button.getDouble("y"); - double ratio = buttonC/CallbackBridge.physicalHeight; + double ratio = buttonC / CallbackBridge.physicalHeight; n_button.dynamicY = ratio + " * ${screen_height}"; } n_button.name = button.getString("name"); - n_button.opacity = ((float)((button.getInt("transparency")-100)*-1))/100f; + n_button.opacity = ((float) ((button.getInt("transparency") - 100) * -1)) / 100f; n_button.passThruEnabled = button.getBoolean("passThruEnabled"); n_button.isToggle = button.getBoolean("isToggle"); n_button.setHeight(button.getInt("height")); n_button.setWidth(button.getInt("width")); n_button.bgColor = 0x4d000000; n_button.strokeWidth = 0; - if(button.getBoolean("isRound")) { n_button.cornerRadius = 35f; } + if (button.getBoolean("isRound")) { + n_button.cornerRadius = 35f; + } int next_idx = 0; - if(button.getBoolean("holdShift")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT; next_idx++; } - if(button.getBoolean("holdCtrl")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL; next_idx++; } - if(button.getBoolean("holdAlt")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT; next_idx++; } + if (button.getBoolean("holdShift")) { + keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT; + next_idx++; + } + if (button.getBoolean("holdCtrl")) { + keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL; + next_idx++; + } + if (button.getBoolean("holdAlt")) { + keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT; + next_idx++; + } keycodes[next_idx] = button.getInt("keycode"); n_button.keycodes = keycodes; empty.mControlDataList.add(n_button); } - empty.scaledAt = (float)oldLayoutJson.getDouble("scaledAt"); + empty.scaledAt = (float) oldLayoutJson.getDouble("scaledAt"); empty.version = 3; return empty; } + + + /** + * Convert the layout stroke width to the V5 form + */ + private static void convertStrokeWidth(CustomControls layout) { + for (ControlData data : layout.mControlDataList) { + data.strokeWidth = Tools.pxToDp(computeStrokeWidth(data.strokeWidth, data.getWidth(), data.getHeight())); + } + + for (ControlDrawerData data : layout.mDrawerDataList) { + data.properties.strokeWidth = Tools.pxToDp(computeStrokeWidth(data.properties.strokeWidth, data.properties.getWidth(), data.properties.getHeight())); + for (ControlData subButtonData : data.buttonProperties) { + subButtonData.strokeWidth = Tools.pxToDp(computeStrokeWidth(subButtonData.strokeWidth, data.properties.getWidth(), data.properties.getWidth())); + } + } + } + + /** + * Convert a size percentage into a px size, used by older layout versions + */ + static int computeStrokeWidth(float widthInPercent, float width, float height) { + float maxSize = Math.max(width, height); + return (int) ((maxSize / 2) * (widthInPercent / 100)); + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java index abfd6cb7d8..888c85e5de 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlButton.java @@ -31,6 +31,9 @@ public class ControlButton extends TextView implements ControlInterface { protected ControlData mProperties; private final ControlLayout mControlLayout; + /* Cache value from the ControlData radius for drawing purposes */ + private float mComputedRadius; + protected boolean mIsToggled = false; protected boolean mIsPointerOutOfBounds = false; @@ -42,6 +45,7 @@ public ControlButton(ControlLayout layout, ControlData properties) { setTextColor(Color.WHITE); setPadding(4, 4, 4, 4); setTextSize(14); // Nullify the default size setting + setOutlineProvider(null); // Disable shadow casting, removing one drawing pass //setOnLongClickListener(this); @@ -61,6 +65,7 @@ public ControlData getProperties() { public void setProperties(ControlData properties, boolean changePos) { mProperties = properties; ControlInterface.super.setProperties(properties, changePos); + mComputedRadius = ControlInterface.super.computeCornerRadius(mProperties.cornerRadius); if (mProperties.isToggle) { //For the toggle layer @@ -76,16 +81,11 @@ public void setProperties(ControlData properties, boolean changePos) { setText(properties.name); } - public void setVisible(boolean isVisible){ - if(mProperties.isHideable) - setVisibility(isVisible ? VISIBLE : GONE); - } - @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mIsToggled || (!mProperties.isToggle && isActivated())) - canvas.drawRoundRect(0, 0, getWidth(), getHeight(), mProperties.cornerRadius, mProperties.cornerRadius, mRectPaint); + canvas.drawRoundRect(0, 0, getWidth(), getHeight(), mComputedRadius, mComputedRadius, mRectPaint); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java index ccacc83232..cc022ea479 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlDrawer.java @@ -2,7 +2,9 @@ import android.annotation.SuppressLint; import android.view.MotionEvent; +import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.customcontrols.ControlData; @@ -40,18 +42,19 @@ public void addButton(ControlData properties){ public void addButton(ControlSubButton button){ buttons.add(button); - setControlButtonVisibility(button, areButtonsVisible); syncButtons(); + setControlButtonVisibility(button, areButtonsVisible); } private void setControlButtonVisibility(ControlButton button, boolean isVisible){ - button.setVisible(isVisible); + button.getControlView().setVisibility(isVisible ? VISIBLE : GONE); } private void switchButtonVisibility(){ areButtonsVisible = !areButtonsVisible; + int visibility = areButtonsVisible ? VISIBLE : GONE; for(ControlButton button : buttons){ - button.setVisible(areButtonsVisible); + button.getControlView().setVisibility(visibility); } } @@ -88,7 +91,7 @@ private void alignButtons(){ private void resizeButtons(){ - if (buttons == null) return; + if (buttons == null || drawerData.orientation == ControlDrawerData.Orientation.FREE) return; for(ControlSubButton subButton : buttons){ subButton.mProperties.setWidth(mProperties.getWidth()); subButton.mProperties.setHeight(mProperties.getHeight()); @@ -124,8 +127,13 @@ public ControlData preProcessProperties(ControlData properties, ControlLayout la @Override public void setVisible(boolean isVisible) { - //TODO replicate changes to his children ? - setVisibility(isVisible ? VISIBLE : GONE); + int visibility = isVisible ? VISIBLE : GONE; + setVisibility(visibility); + if(visibility == GONE || areButtonsVisible) { + for(ControlSubButton button : buttons){ + button.getControlView().setVisibility(isVisible ? VISIBLE : (!mProperties.isHideable && getVisibility() == GONE) ? VISIBLE : View.GONE); + } + } } @SuppressLint("ClickableViewAccessibility") diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlInterface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlInterface.java index 3f3e6fae99..d979ac95d2 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlInterface.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlInterface.java @@ -1,17 +1,22 @@ package net.kdt.pojavlaunch.customcontrols.buttons; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_BUTTONSIZE; import android.annotation.SuppressLint; import android.graphics.drawable.GradientDrawable; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; import androidx.core.math.MathUtils; +import net.kdt.pojavlaunch.GrabListener; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.customcontrols.ControlData; import net.kdt.pojavlaunch.customcontrols.ControlLayout; @@ -24,34 +29,54 @@ * Most of the injected behavior is editing behavior, * sending keys has to be implemented by sub classes. */ -public interface ControlInterface extends View.OnLongClickListener { +public interface ControlInterface extends View.OnLongClickListener, GrabListener { View getControlView(); + ControlData getProperties(); - /** Remove the button presence from the CustomControl object + default void setProperties(ControlData properties) { + setProperties(properties, true); + } + + /** + * Remove the button presence from the CustomControl object * You need to use {getControlParent()} for this. */ void removeButton(); - /** Duplicate the data of the button and add a view with the duplicated data + /** + * Duplicate the data of the button and add a view with the duplicated data * Relies on the ControlLayout for the implementation. */ void cloneButton(); - void setVisible(boolean isVisible); + default void setVisible(boolean isVisible) { + if(getProperties().isHideable) + getControlView().setVisibility(isVisible ? VISIBLE : GONE); + } + void sendKeyPresses(boolean isDown); - /** Load the values and hide non useful forms */ + /** + * Load the values and hide non useful forms + */ void loadEditValues(EditControlPopup editControlPopup); + @Override + default void onGrabState(boolean isGrabbing) { + if (getControlLayoutParent() != null && getControlLayoutParent().getModifiable()) return; // Disable when edited + setVisible((getProperties().displayInGame && isGrabbing) || (getProperties().displayInMenu && !isGrabbing)); + } - default ControlLayout getControlLayoutParent(){ + default ControlLayout getControlLayoutParent() { return (ControlLayout) getControlView().getParent(); } - /** Apply conversion steps for when the view is created */ - default ControlData preProcessProperties(ControlData properties, ControlLayout layout){ + /** + * Apply conversion steps for when the view is created + */ + default ControlData preProcessProperties(ControlData properties, ControlLayout layout) { //Size properties.setWidth(properties.getWidth() / layout.getLayoutScale() * PREF_BUTTONSIZE); properties.setHeight(properties.getHeight() / layout.getLayoutScale() * PREF_BUTTONSIZE); @@ -66,10 +91,6 @@ default void updateProperties() { setProperties(getProperties()); } - default void setProperties(ControlData properties) { - setProperties(properties, true); - } - /* This function should be overridden to store the properties */ @CallSuper default void setProperties(ControlData properties, boolean changePos) { @@ -80,19 +101,22 @@ default void setProperties(ControlData properties, boolean changePos) { // Recycle layout params ViewGroup.LayoutParams params = getControlView().getLayoutParams(); - if(params == null) params = new FrameLayout.LayoutParams((int) properties.getWidth(), (int) properties.getHeight()); + if (params == null) + params = new FrameLayout.LayoutParams((int) properties.getWidth(), (int) properties.getHeight()); params.width = (int) properties.getWidth(); params.height = (int) properties.getHeight(); getControlView().setLayoutParams(params); } - /** Apply the background according to properties */ - default void setBackground(){ - GradientDrawable gd = getControlView().getBackground() instanceof GradientDrawable + /** + * Apply the background according to properties + */ + default void setBackground() { + GradientDrawable gd = getControlView().getBackground() instanceof GradientDrawable ? (GradientDrawable) getControlView().getBackground() : new GradientDrawable(); gd.setColor(getProperties().bgColor); - gd.setStroke(computeStrokeWidth(getProperties().strokeWidth), getProperties().strokeColor); + gd.setStroke((int) Tools.dpToPx(getProperties().strokeWidth), getProperties().strokeColor); gd.setCornerRadius(computeCornerRadius(getProperties().cornerRadius)); getControlView().setBackground(gd); @@ -100,50 +124,56 @@ default void setBackground(){ /** * Apply the dynamic equation on the x axis. + * * @param dynamicX The equation to compute the position from */ - default void setDynamicX(String dynamicX){ + default void setDynamicX(String dynamicX) { getProperties().dynamicX = dynamicX; getControlView().setX(getProperties().insertDynamicPos(dynamicX)); } /** * Apply the dynamic equation on the y axis. + * * @param dynamicY The equation to compute the position from */ - default void setDynamicY(String dynamicY){ + default void setDynamicY(String dynamicY) { getProperties().dynamicY = dynamicY; getControlView().setY(getProperties().insertDynamicPos(dynamicY)); } /** * Generate a dynamic equation from an absolute position, used to scale properly across devices + * * @param x The absolute position on the horizontal axis * @return The equation as a String */ - default String generateDynamicX(float x){ - if(x + (getProperties().getWidth()/2f) > CallbackBridge.physicalWidth/2f){ + default String generateDynamicX(float x) { + if (x + (getProperties().getWidth() / 2f) > CallbackBridge.physicalWidth / 2f) { return (x + getProperties().getWidth()) / CallbackBridge.physicalWidth + " * ${screen_width} - ${width}"; - }else{ + } else { return x / CallbackBridge.physicalWidth + " * ${screen_width}"; } } /** * Generate a dynamic equation from an absolute position, used to scale properly across devices + * * @param y The absolute position on the vertical axis * @return The equation as a String */ - default String generateDynamicY(float y){ - if(y + (getProperties().getHeight()/2f) > CallbackBridge.physicalHeight/2f){ - return (y + getProperties().getHeight()) / CallbackBridge.physicalHeight + " * ${screen_height} - ${height}"; - }else{ + default String generateDynamicY(float y) { + if (y + (getProperties().getHeight() / 2f) > CallbackBridge.physicalHeight / 2f) { + return (y + getProperties().getHeight()) / CallbackBridge.physicalHeight + " * ${screen_height} - ${height}"; + } else { return y / CallbackBridge.physicalHeight + " * ${screen_height}"; } } - /** Regenerate and apply coordinates with supposedly modified properties */ - default void regenerateDynamicCoordinates(){ + /** + * Regenerate and apply coordinates with supposedly modified properties + */ + default void regenerateDynamicCoordinates() { getProperties().dynamicX = generateDynamicX(getControlView().getX()); getProperties().dynamicY = generateDynamicY(getControlView().getY()); updateProperties(); @@ -152,30 +182,28 @@ default void regenerateDynamicCoordinates(){ /** * Do a pre-conversion of an equation using values from a button, * so the variables can be used for another button - * + *

* Internal use only. + * * @param equation The dynamic position as a String - * @param button The button to get the values from. + * @param button The button to get the values from. * @return The pre-processed equation as a String. */ - default String applySize(String equation, ControlInterface button){ + default String applySize(String equation, ControlInterface button) { return equation .replace("${right}", "(${screen_width} - ${width})") - .replace("${bottom}","(${screen_height} - ${height})") + .replace("${bottom}", "(${screen_height} - ${height})") .replace("${height}", "(px(" + Tools.pxToDp(button.getProperties().getHeight()) + ") /" + PREF_BUTTONSIZE + " * ${preferred_scale})") .replace("${width}", "(px(" + Tools.pxToDp(button.getProperties().getWidth()) + ") / " + PREF_BUTTONSIZE + " * ${preferred_scale})"); } - /** Convert a size percentage into a px size */ - default int computeStrokeWidth(float widthInPercent){ - float maxSize = Math.max(getProperties().getWidth(), getProperties().getHeight()); - return (int)((maxSize/2) * (widthInPercent/100)); - } - /** Convert a corner radius percentage into a px corner radius */ - default float computeCornerRadius(float radiusInPercent){ + /** + * Convert a corner radius percentage into a px corner radius + */ + default float computeCornerRadius(float radiusInPercent) { float minSize = Math.min(getProperties().getWidth(), getProperties().getHeight()); - return (minSize/2) * (radiusInPercent/100); + return (minSize / 2) * (radiusInPercent / 100); } /** @@ -185,10 +213,10 @@ default float computeCornerRadius(float radiusInPercent){ * @return whether or not the button */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") - default boolean canSnap(ControlInterface button){ + default boolean canSnap(ControlInterface button) { float MIN_DISTANCE = Tools.dpToPx(8); - if(button == this) return false; + if (button == this) return false; return !(net.kdt.pojavlaunch.utils.MathUtils.dist( button.getControlView().getX() + button.getControlView().getWidth() / 2f, button.getControlView().getY() + button.getControlView().getHeight() / 2f, @@ -202,13 +230,13 @@ default boolean canSnap(ControlInterface button){ * Try to snap, then align to neighboring buttons, given the provided coordinates. * The new position is automatically applied to the View, * regardless of if the View snapped or not. - * + *

* The new position is always dynamic, thus replacing previous dynamic positions * * @param x Coordinate on the x axis * @param y Coordinate on the y axis */ - default void snapAndAlign(float x, float y){ + default void snapAndAlign(float x, float y) { float MIN_DISTANCE = Tools.dpToPx(8); String dynamicX = generateDynamicX(x); String dynamicY = generateDynamicY(y); @@ -216,9 +244,9 @@ default void snapAndAlign(float x, float y){ getControlView().setX(x); getControlView().setY(y); - for(ControlInterface button : ((ControlLayout) getControlView().getParent()).getButtonChildren()){ + for (ControlInterface button : ((ControlLayout) getControlView().getParent()).getButtonChildren()) { //Step 1: Filter unwanted buttons - if(!canSnap(button)) continue; + if (!canSnap(button)) continue; //Step 2: Get Coordinates float button_top = button.getControlView().getY(); @@ -232,28 +260,28 @@ default void snapAndAlign(float x, float y){ float right = getControlView().getX() + getControlView().getWidth(); //Step 3: For each axis, we try to snap to the nearest - if(Math.abs(top - button_bottom) < MIN_DISTANCE){ // Bottom snap - dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " + ${margin}" ; - }else if(Math.abs(button_top - bottom) < MIN_DISTANCE){ //Top snap + if (Math.abs(top - button_bottom) < MIN_DISTANCE) { // Bottom snap + dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " + ${margin}"; + } else if (Math.abs(button_top - bottom) < MIN_DISTANCE) { //Top snap dynamicY = applySize(button.getProperties().dynamicY, button) + " - ${height} - ${margin}"; } - if(!dynamicY.equals(generateDynamicY(getControlView().getY()))){ //If we snapped - if(Math.abs(button_left - left) < MIN_DISTANCE){ //Left align snap + if (!dynamicY.equals(generateDynamicY(getControlView().getY()))) { //If we snapped + if (Math.abs(button_left - left) < MIN_DISTANCE) { //Left align snap dynamicX = applySize(button.getProperties().dynamicX, button); - }else if(Math.abs(button_right - right) < MIN_DISTANCE){ //Right align snap + } else if (Math.abs(button_right - right) < MIN_DISTANCE) { //Right align snap dynamicX = applySize(button.getProperties().dynamicX, button) + applySize(" + ${width}", button) + " - ${width}"; } } - if(Math.abs(button_left - right) < MIN_DISTANCE){ //Left snap + if (Math.abs(button_left - right) < MIN_DISTANCE) { //Left snap dynamicX = applySize(button.getProperties().dynamicX, button) + " - ${width} - ${margin}"; - }else if(Math.abs(left - button_right) < MIN_DISTANCE){ //Right snap + } else if (Math.abs(left - button_right) < MIN_DISTANCE) { //Right snap dynamicX = applySize(button.getProperties().dynamicX, button) + applySize(" + ${width}", button) + " + ${margin}"; } - if(!dynamicX.equals(generateDynamicX(getControlView().getX()))){ //If we snapped - if(Math.abs(button_top - top) < MIN_DISTANCE){ //Top align snap + if (!dynamicX.equals(generateDynamicX(getControlView().getX()))) { //If we snapped + if (Math.abs(button_top - top) < MIN_DISTANCE) { //Top align snap dynamicY = applySize(button.getProperties().dynamicY, button); - }else if(Math.abs(button_bottom - bottom) < MIN_DISTANCE){ //Bottom align snap + } else if (Math.abs(button_bottom - bottom) < MIN_DISTANCE) { //Bottom align snap dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " - ${height}"; } } @@ -264,19 +292,50 @@ default void snapAndAlign(float x, float y){ setDynamicY(dynamicY); } - /** Wrapper for multiple injections at once */ - default void injectBehaviors(){ + /** + * Wrapper for multiple injections at once + */ + default void injectBehaviors() { injectProperties(); injectTouchEventBehavior(); injectLayoutParamBehavior(); + injectGrabListenerBehavior(); + } + + /** + * Inject the grab listener, remove it when the view is gone + */ + default void injectGrabListenerBehavior() { + if (getControlView() == null) { + Log.e(ControlInterface.class.toString(), "Failed to inject grab listener behavior !"); + return; + } + + + getControlView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(@NonNull View v) { + CallbackBridge.addGrabListener(ControlInterface.this); + } + + @Override + public void onViewDetachedFromWindow(@NonNull View v) { + getControlView().removeOnAttachStateChangeListener(this); + CallbackBridge.removeGrabListener(ControlInterface.this); + } + }); + + } - default void injectProperties(){ + default void injectProperties() { getControlView().post(() -> getControlView().setTranslationZ(10)); } - /** Inject a touch listener on the view to make editing controls straight forward */ - default void injectTouchEventBehavior(){ + /** + * Inject a touch listener on the view to make editing controls straight forward + */ + default void injectTouchEventBehavior() { getControlView().setOnTouchListener(new View.OnTouchListener() { private boolean mCanTriggerLongClick = true; private float downX, downY; @@ -285,7 +344,7 @@ default void injectTouchEventBehavior(){ @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View view, MotionEvent event) { - if(!getControlLayoutParent().getModifiable()){ + if (!getControlLayoutParent().getModifiable()) { // Basically, editing behavior is forced while in game behavior is specific view.onTouchEvent(event); return true; @@ -309,7 +368,7 @@ public boolean onTouch(View view, MotionEvent event) { break; case MotionEvent.ACTION_MOVE: - if(Math.abs(event.getRawX() - downRawX) > 8 || Math.abs(event.getRawY() - downRawY) > 8) + if (Math.abs(event.getRawX() - downRawX) > 8 || Math.abs(event.getRawY() - downRawY) > 8) mCanTriggerLongClick = false; getControlLayoutParent().adaptPanelPosition(); @@ -327,17 +386,17 @@ public boolean onTouch(View view, MotionEvent event) { }); } - default void injectLayoutParamBehavior(){ + default void injectLayoutParamBehavior() { getControlView().addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - getProperties().setWidth(right-left); - getProperties().setHeight(bottom-top); + getProperties().setWidth(right - left); + getProperties().setHeight(bottom - top); setBackground(); // Re-calculate position - if(!getProperties().isDynamicBtn){ + if (!getProperties().isDynamicBtn) { getControlView().setX(getControlView().getX()); getControlView().setY(getControlView().getY()); - }else { + } else { getControlView().setX(getProperties().insertDynamicPos(getProperties().dynamicX)); getControlView().setY(getProperties().insertDynamicPos(getProperties().dynamicY)); } @@ -345,7 +404,7 @@ default void injectLayoutParamBehavior(){ } @Override - default boolean onLongClick(View v){ + default boolean onLongClick(View v) { if (getControlLayoutParent().getModifiable()) { getControlLayoutParent().editControlButton(this); getControlLayoutParent().mActionRow.setFollowedButton(this); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java new file mode 100644 index 0000000000..34c21c4249 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java @@ -0,0 +1,166 @@ +package net.kdt.pojavlaunch.customcontrols.buttons; + +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NONE; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_WEST; + +import android.annotation.SuppressLint; +import android.view.View; + +import net.kdt.pojavlaunch.LwjglGlfwKeycode; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.customcontrols.ControlData; +import net.kdt.pojavlaunch.customcontrols.ControlJoystickData; +import net.kdt.pojavlaunch.customcontrols.ControlLayout; +import net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick; +import net.kdt.pojavlaunch.customcontrols.handleview.EditControlPopup; + +import org.lwjgl.glfw.CallbackBridge; + +import io.github.controlwear.virtual.joystick.android.JoystickView; + +@SuppressLint("ViewConstructor") +public class ControlJoystick extends JoystickView implements ControlInterface { + public final static int DIRECTION_FORWARD_LOCK = 8; + // Directions keycode + private final int[] mDirectionForwardLock = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL}; + private final int[] mDirectionForward = new int[]{LwjglGlfwKeycode.GLFW_KEY_W}; + private final int[] mDirectionRight = new int[]{LwjglGlfwKeycode.GLFW_KEY_D}; + private final int[] mDirectionBackward = new int[]{LwjglGlfwKeycode.GLFW_KEY_S}; + private final int[] mDirectionLeft = new int[]{LwjglGlfwKeycode.GLFW_KEY_A}; + private ControlJoystickData mControlData; + private int mLastDirectionInt = GamepadJoystick.DIRECTION_NONE; + private int mCurrentDirectionInt = GamepadJoystick.DIRECTION_NONE; + public ControlJoystick(ControlLayout parent, ControlJoystickData data) { + super(parent.getContext()); + init(data, parent); + } + + private static void sendInput(int[] keys, boolean isDown) { + for (int key : keys) { + CallbackBridge.sendKeyPress(key, CallbackBridge.getCurrentMods(), isDown); + } + } + + private void init(ControlJoystickData data, ControlLayout layout) { + mControlData = data; + setProperties(preProcessProperties(data, layout)); + setDeadzone(35); + setFixedCenter(false); + setAutoReCenterButton(true); + + injectBehaviors(); + + setOnMoveListener(new OnMoveListener() { + @Override + public void onMove(int angle, int strength) { + mLastDirectionInt = mCurrentDirectionInt; + mCurrentDirectionInt = getDirectionInt(angle, strength); + + if (mLastDirectionInt != mCurrentDirectionInt) { + sendDirectionalKeycode(mLastDirectionInt, false); + sendDirectionalKeycode(mCurrentDirectionInt, true); + } + } + + @Override + public void onForwardLock(boolean isLocked) { + sendInput(mDirectionForwardLock, isLocked); + } + }); + } + + @Override + public View getControlView() { + return this; + } + + @Override + public ControlData getProperties() { + return mControlData; + } + + @Override + public void setProperties(ControlData properties, boolean changePos) { + mControlData = (ControlJoystickData) properties; + mControlData.isHideable = true; + ControlInterface.super.setProperties(properties, changePos); + postDelayed(() -> setForwardLockDistance(mControlData.forwardLock ? (int) Tools.dpToPx(60) : 0), 10); + } + + @Override + public void removeButton() { + getControlLayoutParent().getLayout().mJoystickDataList.remove(getProperties()); + getControlLayoutParent().removeView(this); + } + + @Override + public void cloneButton() { + ControlData data = new ControlJoystickData(getProperties()); + getControlLayoutParent().addJoystickButton((ControlJoystickData) data); + } + + + @Override + public void setBackground() { + setBorderWidth((int) Tools.dpToPx(getProperties().strokeWidth)); + setBorderColor(getProperties().strokeColor); + setBackgroundColor(getProperties().bgColor); + } + + @Override + public void sendKeyPresses(boolean isDown) {/*STUB since non swipeable*/ } + + @Override + public void loadEditValues(EditControlPopup editControlPopup) { + editControlPopup.loadJoystickValues(mControlData); + } + + private int getDirectionInt(int angle, int intensity) { + if (intensity == 0) return DIRECTION_NONE; + return (int) (((angle + 22.5) / 45) % 8); + } + + private void sendDirectionalKeycode(int direction, boolean isDown) { + switch (direction) { + case DIRECTION_NORTH: + sendInput(mDirectionForward, isDown); + break; + case DIRECTION_NORTH_EAST: + sendInput(mDirectionForward, isDown); + sendInput(mDirectionRight, isDown); + break; + case DIRECTION_EAST: + sendInput(mDirectionRight, isDown); + break; + case DIRECTION_SOUTH_EAST: + sendInput(mDirectionRight, isDown); + sendInput(mDirectionBackward, isDown); + break; + case DIRECTION_SOUTH: + sendInput(mDirectionBackward, isDown); + break; + case DIRECTION_SOUTH_WEST: + sendInput(mDirectionBackward, isDown); + sendInput(mDirectionLeft, isDown); + break; + case DIRECTION_WEST: + sendInput(mDirectionLeft, isDown); + break; + case DIRECTION_NORTH_WEST: + sendInput(mDirectionForward, isDown); + sendInput(mDirectionLeft, isDown); + break; + case DIRECTION_FORWARD_LOCK: + sendInput(mDirectionForwardLock, isDown); + break; + } + } + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java index cd24b8dc9f..fdb5cfc03c 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlSubButton.java @@ -8,6 +8,7 @@ import net.kdt.pojavlaunch.customcontrols.ControlData; import net.kdt.pojavlaunch.customcontrols.ControlDrawerData; import net.kdt.pojavlaunch.customcontrols.ControlLayout; +import net.kdt.pojavlaunch.customcontrols.handleview.EditControlPopup; @SuppressLint("ViewConstructor") public class ControlSubButton extends ControlButton { @@ -21,8 +22,10 @@ public ControlSubButton(ControlLayout layout, ControlData properties, ControlDra } private void filterProperties(){ - mProperties.setHeight(parentDrawer.getProperties().getHeight()); - mProperties.setWidth(parentDrawer.getProperties().getWidth()); + if (parentDrawer != null && parentDrawer.drawerData.orientation != ControlDrawerData.Orientation.FREE) { + mProperties.setHeight(parentDrawer.getProperties().getHeight()); + mProperties.setWidth(parentDrawer.getProperties().getWidth()); + } mProperties.isDynamicBtn = false; setProperties(mProperties, false); @@ -30,12 +33,18 @@ private void filterProperties(){ @Override public void setVisible(boolean isVisible) { - setVisibility(isVisible ? (parentDrawer.areButtonsVisible ? VISIBLE : GONE) : (!mProperties.isHideable && parentDrawer.getVisibility() == GONE) ? VISIBLE : View.GONE); + // STUB, visibility handled by the ControlDrawer + //setVisibility(isVisible ? VISIBLE : (!mProperties.isHideable && parentDrawer.getVisibility() == GONE) ? VISIBLE : View.GONE); + } + + @Override + public void onGrabState(boolean isGrabbing) { + // STUB, visibility lifecycle handled by the ControlDrawer } @Override public void setLayoutParams(ViewGroup.LayoutParams params) { - if(parentDrawer != null){ + if(parentDrawer != null && parentDrawer.drawerData.orientation != ControlDrawerData.Orientation.FREE){ params.width = (int)parentDrawer.mProperties.getWidth(); params.height = (int)parentDrawer.mProperties.getHeight(); } @@ -81,4 +90,9 @@ public void snapAndAlign(float x, float y) { super.snapAndAlign(x, y); // Else the button is forced into place } + + @Override + public void loadEditValues(EditControlPopup editControlPopup) { + editControlPopup.loadSubButtonValues(getProperties(), parentDrawer.drawerData.orientation); + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java index 738e915c85..3d799ecbc4 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java @@ -19,6 +19,8 @@ import android.view.animation.Interpolator; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.SeekBar; import android.widget.Spinner; @@ -34,6 +36,7 @@ import net.kdt.pojavlaunch.colorselector.ColorSelector; import net.kdt.pojavlaunch.customcontrols.ControlData; import net.kdt.pojavlaunch.customcontrols.ControlDrawerData; +import net.kdt.pojavlaunch.customcontrols.ControlJoystickData; import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer; import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface; @@ -43,54 +46,54 @@ * Class providing a sort of popup on top of a Layout, allowing to edit a given ControlButton */ public class EditControlPopup { + protected final Spinner[] mKeycodeSpinners = new Spinner[4]; private final DefocusableScrollView mScrollView; - private ConstraintLayout mRootView; private final ColorSelector mColorSelector; private final ObjectAnimator mEditPopupAnimator; private final ObjectAnimator mColorEditorAnimator; - private boolean mDisplaying = false; - private boolean mDisplayingColor = false; - public boolean internalChanges = false; // True when we programmatically change stuff. - private ControlInterface mCurrentlyEditedButton; private final int mMargin; + public boolean internalChanges = false; // True when we programmatically change stuff. private final View.OnLayoutChangeListener mLayoutChangedListener = new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - if(internalChanges) return; + if (internalChanges) return; internalChanges = true; - int width = (int)(safeParseFloat(mWidthEditText.getText().toString())); + int width = (int) (safeParseFloat(mWidthEditText.getText().toString())); - if(width >= 0 && Math.abs(right - width) > 1){ + if (width >= 0 && Math.abs(right - width) > 1) { mWidthEditText.setText(String.valueOf(right - left)); } - int height = (int)(safeParseFloat(mHeightEditText.getText().toString())); - if(height >= 0 && Math.abs(bottom - height) > 1){ + int height = (int) (safeParseFloat(mHeightEditText.getText().toString())); + if (height >= 0 && Math.abs(bottom - height) > 1) { mHeightEditText.setText(String.valueOf(bottom - top)); } internalChanges = false; } }; - protected EditText mNameEditText, mWidthEditText, mHeightEditText; @SuppressLint("UseSwitchCompatOrMaterialCode") - protected Switch mToggleSwitch, mPassthroughSwitch, mSwipeableSwitch; + protected Switch mToggleSwitch, mPassthroughSwitch, mSwipeableSwitch, mForwardLockSwitch; protected Spinner mOrientationSpinner; - protected final Spinner[] mKeycodeSpinners = new Spinner[4]; + protected TextView[] mKeycodeTextviews = new TextView[4]; protected SeekBar mStrokeWidthSeekbar, mCornerRadiusSeekbar, mAlphaSeekbar; protected TextView mStrokePercentTextView, mCornerRadiusPercentTextView, mAlphaPercentTextView; protected TextView mSelectBackgroundColor, mSelectStrokeColor; protected ArrayAdapter mAdapter; protected List mSpecialArray; - + protected CheckBox mDisplayInGameCheckbox, mDisplayInMenuCheckbox; + private ConstraintLayout mRootView; + private boolean mDisplaying = false; + private boolean mDisplayingColor = false; + private ControlInterface mCurrentlyEditedButton; // Decorative textviews - private TextView mOrientationTextView, mMappingTextView, mNameTextView, mCornerRadiusTextView; + private TextView mOrientationTextView, mMappingTextView, mNameTextView, + mCornerRadiusTextView, mVisibilityTextView, mSizeTextview, mSizeXTextView; - - public EditControlPopup(Context context, ViewGroup parent){ + public EditControlPopup(Context context, ViewGroup parent) { mScrollView = (DefocusableScrollView) LayoutInflater.from(context).inflate(R.layout.dialog_control_button_setting, parent, false); parent.addView(mScrollView); @@ -101,8 +104,8 @@ public EditControlPopup(Context context, ViewGroup parent){ mColorSelector.getRootView().setTranslationZ(11); mColorSelector.getRootView().setX(-context.getResources().getDimensionPixelOffset(R.dimen._280sdp)); - mEditPopupAnimator = ObjectAnimator.ofFloat(mScrollView, "x", 0).setDuration(1000); - mColorEditorAnimator = ObjectAnimator.ofFloat(mColorSelector.getRootView(), "x", 0).setDuration(1000); + mEditPopupAnimator = ObjectAnimator.ofFloat(mScrollView, "x", 0).setDuration(600); + mColorEditorAnimator = ObjectAnimator.ofFloat(mColorSelector.getRootView(), "x", 0).setDuration(600); Interpolator decelerate = new AccelerateDecelerateInterpolator(); mEditPopupAnimator.setInterpolator(decelerate); mColorEditorAnimator.setInterpolator(decelerate); @@ -117,18 +120,23 @@ public EditControlPopup(Context context, ViewGroup parent){ setupRealTimeListeners(); } + public static void setPercentageText(TextView textView, int progress) { + textView.setText(textView.getContext().getString(R.string.percent_format, progress)); + } - /** Slide the layout into the visible screen area */ - public void appear(boolean fromRight){ + /** + * Slide the layout into the visible screen area + */ + public void appear(boolean fromRight) { disappearColor(); // When someone jumps from a button to another - if(fromRight){ - if(!mDisplaying || !isAtRight()){ + if (fromRight) { + if (!mDisplaying || !isAtRight()) { mEditPopupAnimator.setFloatValues(currentDisplayMetrics.widthPixels, currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin); mEditPopupAnimator.start(); } - }else{ - if (!mDisplaying || isAtRight()){ + } else { + if (!mDisplaying || isAtRight()) { mEditPopupAnimator.setFloatValues(-mScrollView.getWidth(), mMargin); mEditPopupAnimator.start(); } @@ -137,12 +145,14 @@ public void appear(boolean fromRight){ mDisplaying = true; } - /** Slide out the layout */ - public void disappear(){ - if(!mDisplaying) return; + /** + * Slide out the layout + */ + public void disappear() { + if (!mDisplaying) return; mDisplaying = false; - if(isAtRight()) + if (isAtRight()) mEditPopupAnimator.setFloatValues(currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin, currentDisplayMetrics.widthPixels); else mEditPopupAnimator.setFloatValues(mMargin, -mScrollView.getWidth()); @@ -150,30 +160,39 @@ public void disappear(){ mEditPopupAnimator.start(); } - /** Slide the layout into the visible screen area */ - public void appearColor(boolean fromRight, int color){ - if(fromRight){ - if(!mDisplayingColor || !isAtRight()){ + /** + * Slide the layout into the visible screen area + */ + public void appearColor(boolean fromRight, int color) { + if (fromRight) { + if (!mDisplayingColor || !isAtRight()) { mColorEditorAnimator.setFloatValues(currentDisplayMetrics.widthPixels, currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin); mColorEditorAnimator.start(); } - }else{ - if (!mDisplayingColor || isAtRight()){ + } else { + if (!mDisplayingColor || isAtRight()) { mColorEditorAnimator.setFloatValues(-mScrollView.getWidth(), mMargin); mColorEditorAnimator.start(); } } + // Adjust the color selector to have the same size as the control settings + ViewGroup.LayoutParams params = mColorSelector.getRootView().getLayoutParams(); + params.height = mScrollView.getHeight(); + mColorSelector.getRootView().setLayoutParams(params); + mDisplayingColor = true; mColorSelector.show(color == -1 ? Color.WHITE : color); } - /** Slide out the layout */ - public void disappearColor(){ - if(!mDisplayingColor) return; + /** + * Slide out the layout + */ + public void disappearColor() { + if (!mDisplayingColor) return; mDisplayingColor = false; - if(isAtRight()) + if (isAtRight()) mColorEditorAnimator.setFloatValues(currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin, currentDisplayMetrics.widthPixels); else mColorEditorAnimator.setFloatValues(mMargin, -mScrollView.getWidth()); @@ -181,33 +200,37 @@ public void disappearColor(){ mColorEditorAnimator.start(); } - /** Slide out the first visible layer. - * @return True if the last layer is disappearing */ - public boolean disappearLayer(){ - if(mDisplayingColor){ + /** + * Slide out the first visible layer. + * + * @return True if the last layer is disappearing + */ + public boolean disappearLayer() { + if (mDisplayingColor) { disappearColor(); return false; - }else{ + } else { disappear(); return true; } } - /** Switch the panels position if needed */ - public void adaptPanelPosition(){ - if(mDisplaying){ - boolean isAtRight = mCurrentlyEditedButton.getControlView().getX() + mCurrentlyEditedButton.getControlView().getWidth()/2f < currentDisplayMetrics.widthPixels/2f; + /** + * Switch the panels position if needed + */ + public void adaptPanelPosition() { + if (mDisplaying) { + boolean isAtRight = mCurrentlyEditedButton.getControlView().getX() + mCurrentlyEditedButton.getControlView().getWidth() / 2f < currentDisplayMetrics.widthPixels / 2f; appear(isAtRight); } } - - public void destroy(){ + public void destroy() { ((ViewGroup) mScrollView.getParent()).removeView(mColorSelector.getRootView()); ((ViewGroup) mScrollView.getParent()).removeView(mScrollView); } - private void loadAdapter(){ + private void loadAdapter() { //Initialize adapter for keycodes mAdapter = new ArrayAdapter<>(mRootView.getContext(), R.layout.item_centered_textview); mSpecialArray = ControlData.buildSpecialButtonArray(); @@ -228,48 +251,50 @@ private void loadAdapter(){ mOrientationSpinner.setAdapter(adapter); } - - - private void setDefaultVisibilitySetting(){ - for(int i=0; i currentDisplayMetrics.widthPixels/2f; - } - - - public static void setPercentageText(TextView textView, int progress){ - textView.setText(textView.getContext().getString(R.string.percent_format, progress)); + private boolean isAtRight() { + return mScrollView.getX() > currentDisplayMetrics.widthPixels / 2f; } /* LOADING VALUES */ - /** Load values for basic control data */ - public void loadValues(ControlData data){ + /** + * Load values for basic control data + */ + public void loadValues(ControlData data) { setDefaultVisibilitySetting(); mOrientationTextView.setVisibility(GONE); mOrientationSpinner.setVisibility(GONE); + mForwardLockSwitch.setVisibility(GONE); mNameEditText.setText(data.name); mWidthEditText.setText(String.valueOf(data.getWidth())); mHeightEditText.setText(String.valueOf(data.getHeight())); - mAlphaSeekbar.setProgress((int) (data.opacity*100)); - mStrokeWidthSeekbar.setProgress(data.strokeWidth); + mAlphaSeekbar.setProgress((int) (data.opacity * 100)); + mStrokeWidthSeekbar.setProgress((int) data.strokeWidth * 10); mCornerRadiusSeekbar.setProgress((int) data.cornerRadius); - setPercentageText(mAlphaPercentTextView, (int) (data.opacity*100)); - setPercentageText(mStrokePercentTextView, data.strokeWidth); + setPercentageText(mAlphaPercentTextView, (int) (data.opacity * 100)); + setPercentageText(mStrokePercentTextView, (int) data.strokeWidth * 10); setPercentageText(mCornerRadiusPercentTextView, (int) data.cornerRadius); mToggleSwitch.setChecked(data.isToggle); mPassthroughSwitch.setChecked(data.passThruEnabled); mSwipeableSwitch.setChecked(data.isSwipeable); - for(int i = 0; i< data.keycodes.length; i++){ + mDisplayInGameCheckbox.setChecked(data.displayInGame); + mDisplayInMenuCheckbox.setChecked(data.displayInMenu); + + for (int i = 0; i < data.keycodes.length; i++) { if (data.keycodes[i] < 0) { mKeycodeSpinners[i].setSelection(data.keycodes[i] + mSpecialArray.size()); } else { @@ -278,18 +303,20 @@ public void loadValues(ControlData data){ } } - /** Load values for extended control data */ - public void loadValues(ControlDrawerData data){ + /** + * Load values for extended control data + */ + public void loadValues(ControlDrawerData data) { loadValues(data.properties); mOrientationSpinner.setSelection( ControlDrawerData.orientationToInt(data.orientation)); mMappingTextView.setVisibility(GONE); - mKeycodeSpinners[0].setVisibility(GONE); - mKeycodeSpinners[1].setVisibility(GONE); - mKeycodeSpinners[2].setVisibility(GONE); - mKeycodeSpinners[3].setVisibility(GONE); + for (int i = 0; i < mKeycodeSpinners.length; i++) { + mKeycodeSpinners[i].setVisibility(GONE); + mKeycodeTextviews[i].setVisibility(GONE); + } mOrientationTextView.setVisibility(VISIBLE); mOrientationSpinner.setVisibility(VISIBLE); @@ -299,15 +326,17 @@ public void loadValues(ControlDrawerData data){ mToggleSwitch.setVisibility(View.GONE); } - /** Load values for the joystick */ - @SuppressWarnings("unused") public void loadJoystickValues(ControlData data){ + /** + * Load values for the joystick + */ + public void loadJoystickValues(ControlJoystickData data) { loadValues(data); mMappingTextView.setVisibility(GONE); - mKeycodeSpinners[0].setVisibility(GONE); - mKeycodeSpinners[1].setVisibility(GONE); - mKeycodeSpinners[2].setVisibility(GONE); - mKeycodeSpinners[3].setVisibility(GONE); + for (int i = 0; i < mKeycodeSpinners.length; i++) { + mKeycodeSpinners[i].setVisibility(GONE); + mKeycodeTextviews[i].setVisibility(GONE); + } mNameTextView.setVisibility(GONE); mNameEditText.setVisibility(GONE); @@ -319,10 +348,33 @@ public void loadValues(ControlDrawerData data){ mSwipeableSwitch.setVisibility(View.GONE); mPassthroughSwitch.setVisibility(View.GONE); mToggleSwitch.setVisibility(View.GONE); + + mForwardLockSwitch.setVisibility(VISIBLE); + mForwardLockSwitch.setChecked(data.forwardLock); } + /** + * Load values for sub buttons + */ + public void loadSubButtonValues(ControlData data, ControlDrawerData.Orientation drawerOrientation) { + loadValues(data); - private void bindLayout(){ + // Size linked to the parent drawer depending on the drawer settings + if(drawerOrientation != ControlDrawerData.Orientation.FREE){ + mSizeTextview.setVisibility(GONE); + mSizeXTextView.setVisibility(GONE); + mWidthEditText.setVisibility(GONE); + mHeightEditText.setVisibility(GONE); + } + + // No conditional, already depends on the parent drawer visibility + mVisibilityTextView.setVisibility(GONE); + mDisplayInMenuCheckbox.setVisibility(GONE); + mDisplayInGameCheckbox.setVisibility(GONE); + } + + + private void bindLayout() { mRootView = mScrollView.findViewById(R.id.edit_layout); mNameEditText = mScrollView.findViewById(R.id.editName_editText); mWidthEditText = mScrollView.findViewById(R.id.editSize_editTextX); @@ -330,10 +382,15 @@ private void bindLayout(){ mToggleSwitch = mScrollView.findViewById(R.id.checkboxToggle); mPassthroughSwitch = mScrollView.findViewById(R.id.checkboxPassThrough); mSwipeableSwitch = mScrollView.findViewById(R.id.checkboxSwipeable); + mForwardLockSwitch = mScrollView.findViewById(R.id.checkboxForwardLock); mKeycodeSpinners[0] = mScrollView.findViewById(R.id.editMapping_spinner_1); mKeycodeSpinners[1] = mScrollView.findViewById(R.id.editMapping_spinner_2); mKeycodeSpinners[2] = mScrollView.findViewById(R.id.editMapping_spinner_3); mKeycodeSpinners[3] = mScrollView.findViewById(R.id.editMapping_spinner_4); + mKeycodeTextviews[0] = mScrollView.findViewById(R.id.mapping_1_textview); + mKeycodeTextviews[1] = mScrollView.findViewById(R.id.mapping_2_textview); + mKeycodeTextviews[2] = mScrollView.findViewById(R.id.mapping_3_textview); + mKeycodeTextviews[3] = mScrollView.findViewById(R.id.mapping_4_textview); mOrientationSpinner = mScrollView.findViewById(R.id.editOrientation_spinner); mStrokeWidthSeekbar = mScrollView.findViewById(R.id.editStrokeWidth_seekbar); mCornerRadiusSeekbar = mScrollView.findViewById(R.id.editCornerRadius_seekbar); @@ -343,28 +400,36 @@ private void bindLayout(){ mStrokePercentTextView = mScrollView.findViewById(R.id.editStrokeWidth_textView_percent); mAlphaPercentTextView = mScrollView.findViewById(R.id.editButtonOpacity_textView_percent); mCornerRadiusPercentTextView = mScrollView.findViewById(R.id.editCornerRadius_textView_percent); + mDisplayInGameCheckbox = mScrollView.findViewById(R.id.visibility_game_checkbox); + mDisplayInMenuCheckbox = mScrollView.findViewById(R.id.visibility_menu_checkbox); //Decorative stuff mMappingTextView = mScrollView.findViewById(R.id.editMapping_textView); mOrientationTextView = mScrollView.findViewById(R.id.editOrientation_textView); mNameTextView = mScrollView.findViewById(R.id.editName_textView); mCornerRadiusTextView = mScrollView.findViewById(R.id.editCornerRadius_textView); + mVisibilityTextView = mScrollView.findViewById(R.id.visibility_textview); + mSizeTextview = mScrollView.findViewById(R.id.editSize_textView); + mSizeXTextView = mScrollView.findViewById(R.id.editSize_x_textView); } /** * A long function linking all the displayed data on the popup and, * the currently edited mCurrentlyEditedButton */ - public void setupRealTimeListeners(){ + public void setupRealTimeListeners() { mNameEditText.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} + public void onTextChanged(CharSequence s, int start, int before, int count) { + } @Override public void afterTextChanged(Editable s) { - if(internalChanges) return; + if (internalChanges) return; mCurrentlyEditedButton.getProperties().name = s.toString(); @@ -375,16 +440,19 @@ public void afterTextChanged(Editable s) { mWidthEditText.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} + public void onTextChanged(CharSequence s, int start, int before, int count) { + } @Override public void afterTextChanged(Editable s) { - if(internalChanges) return; + if (internalChanges) return; float width = safeParseFloat(s.toString()); - if(width >= 0){ + if (width >= 0) { mCurrentlyEditedButton.getProperties().setWidth(width); mCurrentlyEditedButton.updateProperties(); } @@ -393,16 +461,19 @@ public void afterTextChanged(Editable s) { mHeightEditText.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} + public void onTextChanged(CharSequence s, int start, int before, int count) { + } @Override public void afterTextChanged(Editable s) { - if(internalChanges) return; + if (internalChanges) return; float height = safeParseFloat(s.toString()); - if(height >= 0){ + if (height >= 0) { mCurrentlyEditedButton.getProperties().setHeight(height); mCurrentlyEditedButton.updateProperties(); } @@ -410,66 +481,83 @@ public void afterTextChanged(Editable s) { }); mSwipeableSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { - if(internalChanges) return; + if (internalChanges) return; mCurrentlyEditedButton.getProperties().isSwipeable = isChecked; }); mToggleSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { - if(internalChanges) return; + if (internalChanges) return; mCurrentlyEditedButton.getProperties().isToggle = isChecked; }); mPassthroughSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { - if(internalChanges) return; + if (internalChanges) return; mCurrentlyEditedButton.getProperties().passThruEnabled = isChecked; }); + mForwardLockSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (internalChanges) return; + if(mCurrentlyEditedButton.getProperties() instanceof ControlJoystickData){ + ((ControlJoystickData) mCurrentlyEditedButton.getProperties()).forwardLock = isChecked; + } + }); mAlphaSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if(internalChanges) return; - mCurrentlyEditedButton.getProperties().opacity = mAlphaSeekbar.getProgress()/100f; - mCurrentlyEditedButton.getControlView().setAlpha(mAlphaSeekbar.getProgress()/100f); + if (internalChanges) return; + mCurrentlyEditedButton.getProperties().opacity = mAlphaSeekbar.getProgress() / 100f; + mCurrentlyEditedButton.getControlView().setAlpha(mAlphaSeekbar.getProgress() / 100f); setPercentageText(mAlphaPercentTextView, progress); } @Override - public void onStartTrackingTouch(SeekBar seekBar) {} + public void onStartTrackingTouch(SeekBar seekBar) { + } + @Override - public void onStopTrackingTouch(SeekBar seekBar) {} + public void onStopTrackingTouch(SeekBar seekBar) { + } }); mStrokeWidthSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if(internalChanges) return; - mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress(); + if (internalChanges) return; + mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress() / 10F; mCurrentlyEditedButton.setBackground(); setPercentageText(mStrokePercentTextView, progress); } @Override - public void onStartTrackingTouch(SeekBar seekBar) {} + public void onStartTrackingTouch(SeekBar seekBar) { + } + @Override - public void onStopTrackingTouch(SeekBar seekBar) {} + public void onStopTrackingTouch(SeekBar seekBar) { + } }); mCornerRadiusSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if(internalChanges) return; + if (internalChanges) return; mCurrentlyEditedButton.getProperties().cornerRadius = mCornerRadiusSeekbar.getProgress(); mCurrentlyEditedButton.setBackground(); setPercentageText(mCornerRadiusPercentTextView, progress); } @Override - public void onStartTrackingTouch(SeekBar seekBar) {} + public void onStartTrackingTouch(SeekBar seekBar) { + } + @Override - public void onStopTrackingTouch(SeekBar seekBar) {} + public void onStopTrackingTouch(SeekBar seekBar) { + } }); - for(int i = 0; i< mKeycodeSpinners.length; ++i){ + for (int i = 0; i < mKeycodeSpinners.length; ++i) { int finalI = i; + mKeycodeTextviews[i].setOnClickListener(v -> mKeycodeSpinners[finalI].performClick()); + mKeycodeSpinners[i].setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { @@ -480,10 +568,12 @@ public void onItemSelected(AdapterView parent, View view, int position, long } else { mCurrentlyEditedButton.getProperties().keycodes[finalI] = EfficientAndroidLWJGLKeycode.getValueByIndex(mKeycodeSpinners[finalI].getSelectedItemPosition() - mSpecialArray.size()); } + mKeycodeTextviews[finalI].setText((String) mKeycodeSpinners[finalI].getSelectedItem()); } @Override - public void onNothingSelected(AdapterView parent) {} + public void onNothingSelected(AdapterView parent) { + } }); } @@ -494,16 +584,26 @@ public void onItemSelected(AdapterView parent, View view, int position, long // Side note, spinner listeners are fired later than all the other ones. // Meaning the internalChanges bool is useless here. - if(mCurrentlyEditedButton instanceof ControlDrawer){ - ((ControlDrawer)mCurrentlyEditedButton).drawerData.orientation = ControlDrawerData.intToOrientation(mOrientationSpinner.getSelectedItemPosition()); - ((ControlDrawer)mCurrentlyEditedButton).syncButtons(); + if (mCurrentlyEditedButton instanceof ControlDrawer) { + ((ControlDrawer) mCurrentlyEditedButton).drawerData.orientation = ControlDrawerData.intToOrientation(mOrientationSpinner.getSelectedItemPosition()); + ((ControlDrawer) mCurrentlyEditedButton).syncButtons(); } } @Override - public void onNothingSelected(AdapterView parent) {} + public void onNothingSelected(AdapterView parent) { + } }); + mDisplayInGameCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (internalChanges) return; + mCurrentlyEditedButton.getProperties().displayInGame = isChecked; + }); + + mDisplayInMenuCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (internalChanges) return; + mCurrentlyEditedButton.getProperties().displayInMenu = isChecked; + }); mSelectStrokeColor.setOnClickListener(v -> { mColorSelector.setAlphaEnabled(false); @@ -524,18 +624,18 @@ public void onNothingSelected(AdapterView parent) {} }); } - private float safeParseFloat(String string){ + private float safeParseFloat(String string) { float out = -1; // -1 try { out = Float.parseFloat(string); - }catch (NumberFormatException e){ + } catch (NumberFormatException e) { Log.e("EditControlPopup", e.toString()); } return out; } - public void setCurrentlyEditedButton(ControlInterface button){ - if(mCurrentlyEditedButton != null) + public void setCurrentlyEditedButton(ControlInterface button) { + if (mCurrentlyEditedButton != null) mCurrentlyEditedButton.getControlView().removeOnLayoutChangeListener(mLayoutChangedListener); mCurrentlyEditedButton = button; mCurrentlyEditedButton.getControlView().addOnLayoutChangeListener(mLayoutChangedListener); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileEditorFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileEditorFragment.java index 5df28efa78..f01ee94077 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileEditorFragment.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ProfileEditorFragment.java @@ -75,7 +75,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat List renderList = new ArrayList<>(5); Collections.addAll(renderList, getResources().getStringArray(R.array.renderer)); renderList.add("Default"); - mDefaultRenderer.setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, renderList)); + mDefaultRenderer.setAdapter(new ArrayAdapter<>(getContext(), R.layout.item_simple_list_1, renderList)); // Set up behaviors mSaveButton.setOnClickListener(v -> { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/RTSpinnerAdapter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/RTSpinnerAdapter.java index e5548fceb8..f7de373748 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/RTSpinnerAdapter.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/multirt/RTSpinnerAdapter.java @@ -56,7 +56,7 @@ public boolean hasStableIds() { public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { View view = convertView != null? convertView: - LayoutInflater.from(mContext).inflate(android.R.layout.simple_list_item_1, parent,false); + LayoutInflater.from(mContext).inflate(R.layout.item_simple_list_1, parent,false); Runtime runtime = mRuntimes.get(position); if(position == mRuntimes.size() - 1 ){ diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java index d17f12e3da..46b5a9815f 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java @@ -332,6 +332,7 @@ public static List getJavaArgs(Context ctx, String runtimeHome, String u ArrayList overridableArguments = new ArrayList<>(Arrays.asList( "-Djava.home=" + runtimeHome, "-Djava.io.tmpdir=" + Tools.DIR_CACHE.getAbsolutePath(), + "-Djna.boot.library.path=" + NATIVE_LIB_DIR, "-Duser.home=" + Tools.DIR_GAME_HOME, "-Duser.language=" + System.getProperty("user.language"), "-Dos.name=Linux", @@ -340,7 +341,9 @@ public static List getJavaArgs(Context ctx, String runtimeHome, String u "-Dpojav.path.private.account=" + Tools.DIR_ACCOUNT_NEW, "-Duser.timezone=" + TimeZone.getDefault().getID(), + "-Dorg.lwjgl.vulkan.libname=libvulkan.so", //LWJGL 3 DEBUG FLAGS + "-Dorg.lwjgl.util.NoChecks=true", //"-Dorg.lwjgl.util.Debug=true", //"-Dorg.lwjgl.util.DebugFunctions=true", //"-Dorg.lwjgl.util.DebugLoader=true", diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 91f1e5b621..00f708aad5 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -46,15 +46,10 @@ struct PotatoBridge potatoBridge; #define RENDERER_GL4ES 1 #define RENDERER_VK_ZINK 2 +#define RENDERER_VULKAN 4 void* gbuffer; -void pojav_openGLOnLoad() { -} -void pojav_openGLOnUnload() { - -} - void pojavTerminate() { printf("EGLBridge: Terminating\n"); @@ -225,7 +220,10 @@ int pojavInit() { pojav_environ->savedWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow); pojav_environ->savedHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow); ANativeWindow_setBuffersGeometry(pojav_environ->pojavWindow,pojav_environ->savedWidth,pojav_environ->savedHeight,AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM); + return 1; +} +int pojavInitOpenGL() { // Only affects GL4ES as of now const char *forceVsync = getenv("FORCE_VSYNC"); if (strcmp(forceVsync, "true") == 0) @@ -269,6 +267,25 @@ int pojavInit() { return 0; } + +void pojavSetWindowHint(int hint, int value) { + if (hint != GLFW_CLIENT_API) return; + switch (value) { + case GLFW_NO_API: + pojav_environ->config_renderer = RENDERER_VULKAN; + /* Nothing to do: initialization is handled in Java-side */ + // pojavInitVulkan(); + break; + case GLFW_OPENGL_API: + /* Nothing to do: initialization is called in pojavCreateContext */ + // pojavInitOpenGL(); + break; + default: + printf("GLFW: Unimplemented API 0x%x\n", value); + abort(); + } +} + ANativeWindow_Buffer buf; int32_t stride; bool stopSwapBuffers; @@ -344,6 +361,12 @@ Java_org_lwjgl_glfw_GLFW_nativeEglDetachOnCurrentThread(JNIEnv *env, jclass claz */ void* pojavCreateContext(void* contextSrc) { + if (pojav_environ->config_renderer == RENDERER_VULKAN) { + return (void *)pojav_environ->pojavWindow; + } + + pojavInitOpenGL(); + if (pojav_environ->config_renderer == RENDERER_GL4ES) { /*const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, atoi(getenv("LIBGL_ES")), diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libjnidispatch.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libjnidispatch.so index d42762d360..b58816595f 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libjnidispatch.so and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libjnidispatch.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl.so index ffd734d0ee..aa8acb31ea 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl.so and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_nanovg.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_nanovg.so new file mode 100644 index 0000000000..c78fa1565a Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_nanovg.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_opengl.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_opengl.so index b8b4705925..bad44ab625 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_opengl.so and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_opengl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_stb.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_stb.so index b5e49839fc..57ee82465f 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_stb.so and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_stb.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_tinyfd.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_tinyfd.so new file mode 100644 index 0000000000..42af1df5f5 Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/liblwjgl_tinyfd.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/libjnidispatch.so b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/libjnidispatch.so index c411147d78..1d02dca9da 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/libjnidispatch.so and b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/libjnidispatch.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl.so b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl.so index f795db9de7..b94f9b9319 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl.so and b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_nanovg.so b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_nanovg.so new file mode 100644 index 0000000000..aea966adab Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_nanovg.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so index 9312f05e32..44dff1b806 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so and b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so index d7b3c67fcf..fd8ce114c9 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so and b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_tinyfd.so b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_tinyfd.so new file mode 100644 index 0000000000..d30a1539aa Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/armeabi-v7a/liblwjgl_tinyfd.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86/libjnidispatch.so b/app_pojavlauncher/src/main/jniLibs/x86/libjnidispatch.so index bb9058cbd2..336aad7b9f 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86/libjnidispatch.so and b/app_pojavlauncher/src/main/jniLibs/x86/libjnidispatch.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl.so b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl.so index e84adaeac2..798847f893 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl.so and b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_nanovg.so b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_nanovg.so new file mode 100644 index 0000000000..8bf786578e Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_nanovg.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_opengl.so b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_opengl.so index 82c66a0267..bf0f05c706 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_opengl.so and b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_opengl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_stb.so b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_stb.so index 3b0c3d68c0..7aebedf416 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_stb.so and b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_stb.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_tinyfd.so b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_tinyfd.so new file mode 100644 index 0000000000..4c9d5eaa24 Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/x86/liblwjgl_tinyfd.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86_64/libjnidispatch.so b/app_pojavlauncher/src/main/jniLibs/x86_64/libjnidispatch.so index 72ad7b9726..4af42fc527 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86_64/libjnidispatch.so and b/app_pojavlauncher/src/main/jniLibs/x86_64/libjnidispatch.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl.so b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl.so index 372fb2900e..c9efd01150 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl.so and b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_nanovg.so b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_nanovg.so new file mode 100644 index 0000000000..283728cdce Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_nanovg.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_opengl.so b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_opengl.so index 3c81abb3e5..b863fdf785 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_opengl.so and b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_opengl.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_stb.so b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_stb.so index 35e27f2485..ae0d6450a1 100644 Binary files a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_stb.so and b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_stb.so differ diff --git a/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_tinyfd.so b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_tinyfd.so new file mode 100644 index 0000000000..500ae098f5 Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/x86_64/liblwjgl_tinyfd.so differ diff --git a/app_pojavlauncher/src/main/res/drawable/background_control_editor.xml b/app_pojavlauncher/src/main/res/drawable/background_control_editor.xml new file mode 100644 index 0000000000..5e350dd5b1 --- /dev/null +++ b/app_pojavlauncher/src/main/res/drawable/background_control_editor.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app_pojavlauncher/src/main/res/drawable/background_line_selected.xml b/app_pojavlauncher/src/main/res/drawable/background_line_selected.xml index 56fa839b79..f962a81899 100644 --- a/app_pojavlauncher/src/main/res/drawable/background_line_selected.xml +++ b/app_pojavlauncher/src/main/res/drawable/background_line_selected.xml @@ -7,10 +7,6 @@ - - diff --git a/app_pojavlauncher/src/main/res/drawable/background_line_unselected.xml b/app_pojavlauncher/src/main/res/drawable/background_line_unselected.xml index d1cd8fabac..1c95d5431e 100644 --- a/app_pojavlauncher/src/main/res/drawable/background_line_unselected.xml +++ b/app_pojavlauncher/src/main/res/drawable/background_line_unselected.xml @@ -8,8 +8,8 @@ + android:bottom="@dimen/padding_input_bottom" + android:top="@dimen/padding_input_top" /> + android:layout_marginVertical="@dimen/padding_heavy" + android:layout_gravity="center_vertical" + > - @@ -58,7 +58,7 @@ + + app:layout_constraintTop_toBottomOf="@+id/editMapping_textView" /> - + + + app:layout_constraintTop_toTopOf="@+id/mapping_3_textview" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintStart_toStartOf="parent" /> + + + + + app:layout_constraintBottom_toBottomOf="@+id/mapping_1_textview" + app:layout_constraintEnd_toEndOf="@+id/mapping_1_textview" + app:layout_constraintStart_toEndOf="@id/mapping_1_textview" + app:layout_constraintTop_toTopOf="@+id/mapping_1_textview" /> - + + + app:layout_constraintTop_toBottomOf="@id/mapping_1_textview" + + tools:text="HELLO" /> + app:layout_constraintBottom_toBottomOf="@+id/mapping_3_textview" + app:layout_constraintEnd_toEndOf="@+id/mapping_3_textview" + app:layout_constraintStart_toEndOf="@id/mapping_3_textview" + app:layout_constraintTop_toBottomOf="@+id/mapping_1_textview" /> - + app:layout_constraintStart_toEndOf="@id/mapping_3_textview" + app:layout_constraintTop_toTopOf="@id/mapping_3_textview" + + tools:text="HELLO" /> @@ -198,17 +267,18 @@ android:id="@+id/editOrientation_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginTop="@dimen/_2sdp" android:gravity="center" android:paddingEnd="5dp" android:text="@string/customctrl_orientation" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/editMapping_spinner_3" /> + app:layout_constraintTop_toBottomOf="@+id/mapping_3_textview" /> + + + - + app:layout_constraintTop_toBottomOf="@id/checkboxForwardLock" /> @@ -274,6 +354,7 @@ android:id="@+id/editStrokeWidth_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginTop="@dimen/_5sdp" android:gravity="center" android:paddingEnd="5dp" android:text="@string/customctrl_stroke_width" @@ -285,7 +366,7 @@ + + + + + + + diff --git a/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml b/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml index 435b4d8f17..919f871a84 100644 --- a/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml +++ b/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml @@ -63,8 +63,11 @@