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 e132b8a12..5f39ec0c2 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,63 +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) { @@ -144,11 +108,11 @@ public class ControlData { 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, true, true); + 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, boolean displayInGame, boolean displayInMenu) { + 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; @@ -167,7 +131,7 @@ public class ControlData { } //Deep copy constructor - public ControlData(ControlData controlData){ + public ControlData(ControlData controlData) { this( controlData.name, controlData.keycodes, @@ -186,13 +150,36 @@ public class ControlData { ); } - - 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) { @@ -200,44 +187,16 @@ public class ControlData { 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 @@ -256,10 +215,11 @@ public class ControlData { /** * 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); } @@ -276,7 +236,7 @@ public class ControlData { 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"); @@ -284,14 +244,49 @@ public class ControlData { 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(); } @@ -300,8 +295,8 @@ public class ControlData { 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/LayoutConverter.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/LayoutConverter.java index f5dd33f9b..ce4e0e678 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 class LayoutConverter { 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") <= 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 v5 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 = 5; + 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/ControlInterface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlInterface.java index 274880f92..08673a77a 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 @@ -30,27 +30,37 @@ import org.lwjgl.glfw.CallbackBridge; 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); + 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 + if (getControlLayoutParent() != null && getControlLayoutParent().getModifiable()) return; // Disable when edited setVisible((getProperties().displayInGame && isGrabbing) || (getProperties().displayInMenu && !isGrabbing)); } @@ -58,8 +68,10 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener 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); @@ -74,10 +86,6 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener 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) { @@ -88,19 +96,22 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener // 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); @@ -108,50 +119,56 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener /** * 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(); @@ -160,30 +177,28 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener /** * 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); } /** @@ -193,10 +208,10 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener * @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, @@ -210,13 +225,13 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener * 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); @@ -224,9 +239,9 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener 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(); @@ -240,28 +255,28 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener 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}"; } } @@ -272,17 +287,21 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener 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){ + /** + * 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; } @@ -304,12 +323,14 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener } - 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; @@ -318,7 +339,7 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener @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; @@ -342,7 +363,7 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener 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(); @@ -360,17 +381,17 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener }); } - 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)); } @@ -378,7 +399,7 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener } @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 index 4b11df406..f0a3a1261 100644 --- 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 @@ -26,26 +26,28 @@ import io.github.controlwear.virtual.joystick.android.JoystickView; @SuppressLint("ViewConstructor") public class ControlJoystick extends JoystickView implements ControlInterface { - public ControlJoystick(ControlLayout parent, ControlData data) { - super(parent.getContext()); - init(data, parent); - } - - public final static int DIRECTION_FORWARD_LOCK = 8; - - private ControlData mControlData; - private int mLastDirectionInt = GamepadJoystick.DIRECTION_NONE; - private int mCurrentDirectionInt = GamepadJoystick.DIRECTION_NONE; - // 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 ControlData mControlData; + private int mLastDirectionInt = GamepadJoystick.DIRECTION_NONE; + private int mCurrentDirectionInt = GamepadJoystick.DIRECTION_NONE; + public ControlJoystick(ControlLayout parent, ControlData data) { + super(parent.getContext()); + init(data, parent); + } - private void init(ControlData data, ControlLayout layout){ + private static void sendInput(int[] keys, boolean isDown) { + for (int key : keys) { + CallbackBridge.sendKeyPress(key, CallbackBridge.getCurrentMods(), isDown); + } + } + + private void init(ControlData data, ControlLayout layout) { mControlData = data; setProperties(preProcessProperties(data, layout)); setDeadzone(35); @@ -61,7 +63,7 @@ public class ControlJoystick extends JoystickView implements ControlInterface { mLastDirectionInt = mCurrentDirectionInt; mCurrentDirectionInt = getDirectionInt(angle, strength); - if(mLastDirectionInt != mCurrentDirectionInt){ + if (mLastDirectionInt != mCurrentDirectionInt) { sendDirectionalKeycode(mLastDirectionInt, false); sendDirectionalKeycode(mCurrentDirectionInt, true); } @@ -75,7 +77,9 @@ public class ControlJoystick extends JoystickView implements ControlInterface { } @Override - public View getControlView() {return this;} + public View getControlView() { + return this; + } @Override public ControlData getProperties() { @@ -107,7 +111,7 @@ public class ControlJoystick extends JoystickView implements ControlInterface { @Override public void setBackground() { - setBorderWidth(computeStrokeWidth(getProperties().strokeWidth)); + setBorderWidth((int) Tools.dpToPx(getProperties().strokeWidth)); setBorderColor(getProperties().strokeColor); setBackgroundColor(getProperties().bgColor); } @@ -120,13 +124,13 @@ public class ControlJoystick extends JoystickView implements ControlInterface { editControlPopup.loadJoystickValues(mControlData); } - private int getDirectionInt(int angle, int intensity){ - if(intensity == 0) return DIRECTION_NONE; - return (int) (((angle+22.5)/45) % 8); + 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){ + private void sendDirectionalKeycode(int direction, boolean isDown) { + switch (direction) { case DIRECTION_NORTH: sendInput(mDirectionForward, isDown); break; @@ -161,10 +165,4 @@ public class ControlJoystick extends JoystickView implements ControlInterface { } } - private static void sendInput(int[] keys, boolean isDown){ - for(int key : keys){ - CallbackBridge.sendKeyPress(key, CallbackBridge.getCurrentMods(), isDown); - } - } - } 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 222bdafa5..628d1b7d1 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 @@ -269,11 +269,11 @@ public class EditControlPopup { mHeightEditText.setText(String.valueOf(data.getHeight())); mAlphaSeekbar.setProgress((int) (data.opacity * 100)); - mStrokeWidthSeekbar.setProgress(data.strokeWidth); + mStrokeWidthSeekbar.setProgress((int) data.strokeWidth * 10); mCornerRadiusSeekbar.setProgress((int) data.cornerRadius); setPercentageText(mAlphaPercentTextView, (int) (data.opacity * 100)); - setPercentageText(mStrokePercentTextView, data.strokeWidth); + setPercentageText(mStrokePercentTextView, (int) data.strokeWidth * 10); setPercentageText(mCornerRadiusPercentTextView, (int) data.cornerRadius); mToggleSwitch.setChecked(data.isToggle); @@ -498,7 +498,7 @@ public class EditControlPopup { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (internalChanges) return; - mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress(); + mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress() / 10F; mCurrentlyEditedButton.setBackground(); setPercentageText(mStrokePercentTextView, progress); }