Feat[controls]: Decouple stroke width from button size

This commit is contained in:
Mathias-Boulay 2023-05-16 15:29:59 +02:00 committed by ArtDev
parent fd5f46f243
commit b4a3e18b9a
5 changed files with 290 additions and 222 deletions

View File

@ -35,18 +35,16 @@ public class ControlData {
private static ControlData[] SPECIAL_BUTTONS; private static ControlData[] SPECIAL_BUTTONS;
private static List<String> SPECIAL_BUTTON_NAME_ARRAY; private static List<String> SPECIAL_BUTTON_NAME_ARRAY;
// Internal usage only
public boolean isHideable;
private static WeakReference<ExpressionBuilder> builder = new WeakReference<>(null); private static WeakReference<ExpressionBuilder> builder = new WeakReference<>(null);
private static WeakReference<ArrayMap<String , String>> conversionMap = new WeakReference<>(null); private static WeakReference<ArrayMap<String, String>> conversionMap = new WeakReference<>(null);
static { static {
buildExpressionBuilder(); buildExpressionBuilder();
buildConversionMap(); buildConversionMap();
} }
// Internal usage only
public boolean isHideable;
/** /**
* Both fields below are dynamic position data, auto updates * Both fields below are dynamic position data, auto updates
* X and Y position, unlike the original one which uses fixed * X and Y position, unlike the original one which uses fixed
@ -56,63 +54,29 @@ public class ControlData {
*/ */
public String dynamicX, dynamicY; public String dynamicX, dynamicY;
public boolean isDynamicBtn, isToggle, passThruEnabled; 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<String> buildSpecialButtonArray() {
if (SPECIAL_BUTTON_NAME_ARRAY == null) {
List<String> 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; 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 int[] keycodes; //Should store up to 4 keys
public float opacity; //Alpha value from 0 to 1; public float opacity; //Alpha value from 0 to 1;
public int bgColor; public int bgColor;
public int strokeColor; public int strokeColor;
public int strokeWidth; //0-100% public float strokeWidth; // Dp instead of % now
public float cornerRadius; //0-100% public float cornerRadius; //0-100%
public boolean isSwipeable; public boolean isSwipeable;
public boolean displayInGame; public boolean displayInGame;
public boolean displayInMenu; public boolean displayInMenu;
private float width; //Dp instead of Px now
private float height; //Dp instead of Px now
public ControlData() { public ControlData() {
this("button"); this("button");
} }
public ControlData(String name){ public ControlData(String name) {
this(name, new int[] {}); this(name, new int[]{});
} }
public ControlData(String name, int[] keycodes) { 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) { 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); 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){ 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); 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.name = name;
this.keycodes = inflateKeycodeArray(keycodes); this.keycodes = inflateKeycodeArray(keycodes);
this.dynamicX = dynamicX; this.dynamicX = dynamicX;
@ -167,7 +131,7 @@ public class ControlData {
} }
//Deep copy constructor //Deep copy constructor
public ControlData(ControlData controlData){ public ControlData(ControlData controlData) {
this( this(
controlData.name, controlData.name,
controlData.keycodes, controlData.keycodes,
@ -186,13 +150,36 @@ public class ControlData {
); );
} }
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),
public float insertDynamicPos(String dynamicPos) { new ControlData("MID", new int[]{SPECIALBTN_MOUSEMID}, "${margin}", "${margin}"),
// Insert value to ${variable} new ControlData("SCROLLUP", new int[]{SPECIALBTN_SCROLLUP}, "${margin}", "${margin}"),
String insertedPos = JSONUtils.insertSingleJSONValue(dynamicPos, fillConversionMap()); new ControlData("SCROLLDOWN", new int[]{SPECIALBTN_SCROLLDOWN}, "${margin}", "${margin}"),
new ControlData("MENU", new int[]{SPECIALBTN_MENU}, "${margin}", "${margin}")
};
}
// Calculate, because the dynamic position contains some math equations return SPECIAL_BUTTONS;
return calculate(insertedPos); }
public static List<String> buildSpecialButtonArray() {
if (SPECIAL_BUTTON_NAME_ARRAY == null) {
List<String> 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) { private static float calculate(String math) {
@ -200,44 +187,16 @@ public class ControlData {
return (float) builder.get().build().evaluate(); 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}; int[] inflatedArray = new int[]{GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN, GLFW_KEY_UNKNOWN};
System.arraycopy(keycodes, 0, inflatedArray, 0, keycodes.length); System.arraycopy(keycodes, 0, inflatedArray, 0, keycodes.length);
return inflatedArray; 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 * 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") ExpressionBuilder expressionBuilder = new ExpressionBuilder("1 + 1")
.function(new Function("dp", 1) { .function(new Function("dp", 1) {
@Override @Override
@ -256,10 +215,11 @@ public class ControlData {
/** /**
* wrapper for the WeakReference to the expressionField. * wrapper for the WeakReference to the expressionField.
*
* @param stringExpression the expression to set. * @param stringExpression the expression to set.
*/ */
private static void setExpression(String stringExpression){ private static void setExpression(String stringExpression) {
if(builder.get() == null) buildExpressionBuilder(); if (builder.get() == null) buildExpressionBuilder();
builder.get().expression(stringExpression); builder.get().expression(stringExpression);
} }
@ -276,7 +236,7 @@ public class ControlData {
keyValueMap.put("bottom", "DUMMY_BOTTOM"); keyValueMap.put("bottom", "DUMMY_BOTTOM");
keyValueMap.put("width", "DUMMY_WIDTH"); keyValueMap.put("width", "DUMMY_WIDTH");
keyValueMap.put("height", "DUMMY_HEIGHT"); 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("screen_height", "DUMMY_DATA");
keyValueMap.put("margin", Integer.toString((int) Tools.dpToPx(2))); keyValueMap.put("margin", Integer.toString((int) Tools.dpToPx(2)));
keyValueMap.put("preferred_scale", "DUMMY_DATA"); keyValueMap.put("preferred_scale", "DUMMY_DATA");
@ -284,14 +244,49 @@ public class ControlData {
conversionMap = new WeakReference<>(keyValueMap); 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. * Fill the conversionMap with controlData dependent values.
* The returned valueMap should NOT be kept in memory. * The returned valueMap should NOT be kept in memory.
*
* @return the valueMap to use. * @return the valueMap to use.
*/ */
private Map<String, String> fillConversionMap(){ private Map<String, String> fillConversionMap() {
ArrayMap<String, String> valueMap = conversionMap.get(); ArrayMap<String, String> valueMap = conversionMap.get();
if (valueMap == null){ if (valueMap == null) {
buildConversionMap(); buildConversionMap();
valueMap = conversionMap.get(); valueMap = conversionMap.get();
} }
@ -300,8 +295,8 @@ public class ControlData {
valueMap.put("bottom", Float.toString(CallbackBridge.physicalHeight - getHeight())); valueMap.put("bottom", Float.toString(CallbackBridge.physicalHeight - getHeight()));
valueMap.put("width", Float.toString(getWidth())); valueMap.put("width", Float.toString(getWidth()));
valueMap.put("height", Float.toString(getHeight())); valueMap.put("height", Float.toString(getHeight()));
valueMap.put("screen_width",Integer.toString(CallbackBridge.physicalWidth)); valueMap.put("screen_width", Integer.toString(CallbackBridge.physicalWidth));
valueMap.put("screen_height",Integer.toString(CallbackBridge.physicalHeight)); valueMap.put("screen_height", Integer.toString(CallbackBridge.physicalHeight));
valueMap.put("preferred_scale", Float.toString(LauncherPreferences.PREF_BUTTONSIZE)); valueMap.put("preferred_scale", Float.toString(LauncherPreferences.PREF_BUTTONSIZE));
return valueMap; return valueMap;

View File

@ -20,105 +20,159 @@ public class LayoutConverter {
try { try {
JSONObject layoutJobj = new JSONObject(jsonLayoutData); JSONObject layoutJobj = new JSONObject(jsonLayoutData);
if(!layoutJobj.has("version")) { //v1 layout if (!layoutJobj.has("version")) { //v1 layout
CustomControls layout = LayoutConverter.convertV1Layout(layoutJobj); CustomControls layout = LayoutConverter.convertV1Layout(layoutJobj);
layout.save(jsonPath); layout.save(jsonPath);
return layout; return layout;
}else if (layoutJobj.getInt("version") == 2) { } else if (layoutJobj.getInt("version") == 2) {
CustomControls layout = LayoutConverter.convertV2Layout(layoutJobj); CustomControls layout = LayoutConverter.convertV2Layout(layoutJobj);
layout.save(jsonPath); layout.save(jsonPath);
return layout; return layout;
}else if (layoutJobj.getInt("version") >= 3 && layoutJobj.getInt("version") <= 5) { }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); return Tools.GLOBAL_GSON.fromJson(jsonLayoutData, CustomControls.class);
}else{ } else {
return null; return null;
} }
}catch (JSONException e) { } catch (JSONException e) {
throw new JsonSyntaxException("Failed to load",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 { public static CustomControls convertV2Layout(JSONObject oldLayoutJson) throws JSONException {
CustomControls layout = Tools.GLOBAL_GSON.fromJson(oldLayoutJson.toString(), CustomControls.class); CustomControls layout = Tools.GLOBAL_GSON.fromJson(oldLayoutJson.toString(), CustomControls.class);
JSONArray layoutMainArray = oldLayoutJson.getJSONArray("mControlDataList"); JSONArray layoutMainArray = oldLayoutJson.getJSONArray("mControlDataList");
layout.mControlDataList = new ArrayList<>(layoutMainArray.length()); 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); JSONObject button = layoutMainArray.getJSONObject(i);
ControlData n_button = Tools.GLOBAL_GSON.fromJson(button.toString(), ControlData.class); 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 buttonC = button.getDouble("x");
double ratio = buttonC/CallbackBridge.physicalWidth; double ratio = buttonC / CallbackBridge.physicalWidth;
n_button.dynamicX = ratio + " * ${screen_width}"; 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 buttonC = button.getDouble("y");
double ratio = buttonC/CallbackBridge.physicalHeight; double ratio = buttonC / CallbackBridge.physicalHeight;
n_button.dynamicY = ratio + " * ${screen_height}"; n_button.dynamicY = ratio + " * ${screen_height}";
} }
layout.mControlDataList.add(n_button); layout.mControlDataList.add(n_button);
} }
JSONArray layoutDrawerArray = oldLayoutJson.getJSONArray("mDrawerDataList"); JSONArray layoutDrawerArray = oldLayoutJson.getJSONArray("mDrawerDataList");
layout.mDrawerDataList = new ArrayList<>(); 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 button = layoutDrawerArray.getJSONObject(i);
JSONObject buttonProperties = button.getJSONObject("properties"); JSONObject buttonProperties = button.getJSONObject("properties");
ControlDrawerData n_button = Tools.GLOBAL_GSON.fromJson(button.toString(), ControlDrawerData.class); 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 buttonC = buttonProperties.getDouble("x");
double ratio = buttonC/CallbackBridge.physicalWidth; double ratio = buttonC / CallbackBridge.physicalWidth;
n_button.properties.dynamicX = ratio + " * ${screen_width}"; 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 buttonC = buttonProperties.getDouble("y");
double ratio = buttonC/CallbackBridge.physicalHeight; double ratio = buttonC / CallbackBridge.physicalHeight;
n_button.properties.dynamicY = ratio + " * ${screen_height}"; n_button.properties.dynamicY = ratio + " * ${screen_height}";
} }
layout.mDrawerDataList.add(n_button); layout.mDrawerDataList.add(n_button);
} }
convertStrokeWidth(layout);
layout.version = 3; layout.version = 3;
return layout; return layout;
} }
public static CustomControls convertV1Layout(JSONObject oldLayoutJson) throws JSONException { public static CustomControls convertV1Layout(JSONObject oldLayoutJson) throws JSONException {
CustomControls empty = new CustomControls(); CustomControls empty = new CustomControls();
JSONArray layoutMainArray = oldLayoutJson.getJSONArray("mControlDataList"); 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); JSONObject button = layoutMainArray.getJSONObject(i);
ControlData n_button = new ControlData(); 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, LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN}; LwjglGlfwKeycode.GLFW_KEY_UNKNOWN};
n_button.isDynamicBtn = button.getBoolean("isDynamicBtn"); n_button.isDynamicBtn = button.getBoolean("isDynamicBtn");
n_button.dynamicX = button.getString("dynamicX"); n_button.dynamicX = button.getString("dynamicX");
n_button.dynamicY = button.getString("dynamicY"); 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 buttonC = button.getDouble("x");
double ratio = buttonC/CallbackBridge.physicalWidth; double ratio = buttonC / CallbackBridge.physicalWidth;
n_button.dynamicX = ratio + " * ${screen_width}"; 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 buttonC = button.getDouble("y");
double ratio = buttonC/CallbackBridge.physicalHeight; double ratio = buttonC / CallbackBridge.physicalHeight;
n_button.dynamicY = ratio + " * ${screen_height}"; n_button.dynamicY = ratio + " * ${screen_height}";
} }
n_button.name = button.getString("name"); 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.passThruEnabled = button.getBoolean("passThruEnabled");
n_button.isToggle = button.getBoolean("isToggle"); n_button.isToggle = button.getBoolean("isToggle");
n_button.setHeight(button.getInt("height")); n_button.setHeight(button.getInt("height"));
n_button.setWidth(button.getInt("width")); n_button.setWidth(button.getInt("width"));
n_button.bgColor = 0x4d000000; n_button.bgColor = 0x4d000000;
n_button.strokeWidth = 0; n_button.strokeWidth = 0;
if(button.getBoolean("isRound")) { n_button.cornerRadius = 35f; } if (button.getBoolean("isRound")) {
n_button.cornerRadius = 35f;
}
int next_idx = 0; int next_idx = 0;
if(button.getBoolean("holdShift")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT; next_idx++; } if (button.getBoolean("holdShift")) {
if(button.getBoolean("holdCtrl")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL; next_idx++; } keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT;
if(button.getBoolean("holdAlt")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT; next_idx++; } 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"); keycodes[next_idx] = button.getInt("keycode");
n_button.keycodes = keycodes; n_button.keycodes = keycodes;
empty.mControlDataList.add(n_button); empty.mControlDataList.add(n_button);
} }
empty.scaledAt = (float)oldLayoutJson.getDouble("scaledAt"); empty.scaledAt = (float) oldLayoutJson.getDouble("scaledAt");
empty.version = 3; empty.version = 3;
return empty; 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));
}
} }

View File

@ -30,27 +30,37 @@ import org.lwjgl.glfw.CallbackBridge;
public interface ControlInterface extends View.OnLongClickListener, GrabListener { public interface ControlInterface extends View.OnLongClickListener, GrabListener {
View getControlView(); View getControlView();
ControlData getProperties(); 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. * You need to use {getControlParent()} for this.
*/ */
void removeButton(); 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. * Relies on the ControlLayout for the implementation.
*/ */
void cloneButton(); void cloneButton();
void setVisible(boolean isVisible); void setVisible(boolean isVisible);
void sendKeyPresses(boolean isDown); void sendKeyPresses(boolean isDown);
/** Load the values and hide non useful forms */ /**
* Load the values and hide non useful forms
*/
void loadEditValues(EditControlPopup editControlPopup); void loadEditValues(EditControlPopup editControlPopup);
@Override @Override
default void onGrabState(boolean isGrabbing) { 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)); setVisible((getProperties().displayInGame && isGrabbing) || (getProperties().displayInMenu && !isGrabbing));
} }
@ -58,8 +68,10 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
return (ControlLayout) getControlView().getParent(); 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 //Size
properties.setWidth(properties.getWidth() / layout.getLayoutScale() * PREF_BUTTONSIZE); properties.setWidth(properties.getWidth() / layout.getLayoutScale() * PREF_BUTTONSIZE);
properties.setHeight(properties.getHeight() / 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()); setProperties(getProperties());
} }
default void setProperties(ControlData properties) {
setProperties(properties, true);
}
/* This function should be overridden to store the properties */ /* This function should be overridden to store the properties */
@CallSuper @CallSuper
default void setProperties(ControlData properties, boolean changePos) { default void setProperties(ControlData properties, boolean changePos) {
@ -88,19 +96,22 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
// Recycle layout params // Recycle layout params
ViewGroup.LayoutParams params = getControlView().getLayoutParams(); 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.width = (int) properties.getWidth();
params.height = (int) properties.getHeight(); params.height = (int) properties.getHeight();
getControlView().setLayoutParams(params); getControlView().setLayoutParams(params);
} }
/** Apply the background according to properties */ /**
default void setBackground(){ * Apply the background according to properties
*/
default void setBackground() {
GradientDrawable gd = getControlView().getBackground() instanceof GradientDrawable GradientDrawable gd = getControlView().getBackground() instanceof GradientDrawable
? (GradientDrawable) getControlView().getBackground() ? (GradientDrawable) getControlView().getBackground()
: new GradientDrawable(); : new GradientDrawable();
gd.setColor(getProperties().bgColor); 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)); gd.setCornerRadius(computeCornerRadius(getProperties().cornerRadius));
getControlView().setBackground(gd); getControlView().setBackground(gd);
@ -108,50 +119,56 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
/** /**
* Apply the dynamic equation on the x axis. * Apply the dynamic equation on the x axis.
*
* @param dynamicX The equation to compute the position from * @param dynamicX The equation to compute the position from
*/ */
default void setDynamicX(String dynamicX){ default void setDynamicX(String dynamicX) {
getProperties().dynamicX = dynamicX; getProperties().dynamicX = dynamicX;
getControlView().setX(getProperties().insertDynamicPos(dynamicX)); getControlView().setX(getProperties().insertDynamicPos(dynamicX));
} }
/** /**
* Apply the dynamic equation on the y axis. * Apply the dynamic equation on the y axis.
*
* @param dynamicY The equation to compute the position from * @param dynamicY The equation to compute the position from
*/ */
default void setDynamicY(String dynamicY){ default void setDynamicY(String dynamicY) {
getProperties().dynamicY = dynamicY; getProperties().dynamicY = dynamicY;
getControlView().setY(getProperties().insertDynamicPos(dynamicY)); getControlView().setY(getProperties().insertDynamicPos(dynamicY));
} }
/** /**
* Generate a dynamic equation from an absolute position, used to scale properly across devices * Generate a dynamic equation from an absolute position, used to scale properly across devices
*
* @param x The absolute position on the horizontal axis * @param x The absolute position on the horizontal axis
* @return The equation as a String * @return The equation as a String
*/ */
default String generateDynamicX(float x){ default String generateDynamicX(float x) {
if(x + (getProperties().getWidth()/2f) > CallbackBridge.physicalWidth/2f){ if (x + (getProperties().getWidth() / 2f) > CallbackBridge.physicalWidth / 2f) {
return (x + getProperties().getWidth()) / CallbackBridge.physicalWidth + " * ${screen_width} - ${width}"; return (x + getProperties().getWidth()) / CallbackBridge.physicalWidth + " * ${screen_width} - ${width}";
}else{ } else {
return x / CallbackBridge.physicalWidth + " * ${screen_width}"; return x / CallbackBridge.physicalWidth + " * ${screen_width}";
} }
} }
/** /**
* Generate a dynamic equation from an absolute position, used to scale properly across devices * Generate a dynamic equation from an absolute position, used to scale properly across devices
*
* @param y The absolute position on the vertical axis * @param y The absolute position on the vertical axis
* @return The equation as a String * @return The equation as a String
*/ */
default String generateDynamicY(float y){ default String generateDynamicY(float y) {
if(y + (getProperties().getHeight()/2f) > CallbackBridge.physicalHeight/2f){ if (y + (getProperties().getHeight() / 2f) > CallbackBridge.physicalHeight / 2f) {
return (y + getProperties().getHeight()) / CallbackBridge.physicalHeight + " * ${screen_height} - ${height}"; return (y + getProperties().getHeight()) / CallbackBridge.physicalHeight + " * ${screen_height} - ${height}";
}else{ } else {
return y / CallbackBridge.physicalHeight + " * ${screen_height}"; 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().dynamicX = generateDynamicX(getControlView().getX());
getProperties().dynamicY = generateDynamicY(getControlView().getY()); getProperties().dynamicY = generateDynamicY(getControlView().getY());
updateProperties(); updateProperties();
@ -160,30 +177,28 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
/** /**
* Do a pre-conversion of an equation using values from a button, * Do a pre-conversion of an equation using values from a button,
* so the variables can be used for another button * so the variables can be used for another button
* * <p>
* Internal use only. * Internal use only.
*
* @param equation The dynamic position as a String * @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. * @return The pre-processed equation as a String.
*/ */
default String applySize(String equation, ControlInterface button){ default String applySize(String equation, ControlInterface button) {
return equation return equation
.replace("${right}", "(${screen_width} - ${width})") .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("${height}", "(px(" + Tools.pxToDp(button.getProperties().getHeight()) + ") /" + PREF_BUTTONSIZE + " * ${preferred_scale})")
.replace("${width}", "(px(" + Tools.pxToDp(button.getProperties().getWidth()) + ") / " + 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()); 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 * @return whether or not the button
*/ */
@SuppressWarnings("BooleanMethodIsAlwaysInverted") @SuppressWarnings("BooleanMethodIsAlwaysInverted")
default boolean canSnap(ControlInterface button){ default boolean canSnap(ControlInterface button) {
float MIN_DISTANCE = Tools.dpToPx(8); float MIN_DISTANCE = Tools.dpToPx(8);
if(button == this) return false; if (button == this) return false;
return !(net.kdt.pojavlaunch.utils.MathUtils.dist( return !(net.kdt.pojavlaunch.utils.MathUtils.dist(
button.getControlView().getX() + button.getControlView().getWidth() / 2f, button.getControlView().getX() + button.getControlView().getWidth() / 2f,
button.getControlView().getY() + button.getControlView().getHeight() / 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. * Try to snap, then align to neighboring buttons, given the provided coordinates.
* The new position is automatically applied to the View, * The new position is automatically applied to the View,
* regardless of if the View snapped or not. * regardless of if the View snapped or not.
* * <p>
* The new position is always dynamic, thus replacing previous dynamic positions * The new position is always dynamic, thus replacing previous dynamic positions
* *
* @param x Coordinate on the x axis * @param x Coordinate on the x axis
* @param y Coordinate on the y 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); float MIN_DISTANCE = Tools.dpToPx(8);
String dynamicX = generateDynamicX(x); String dynamicX = generateDynamicX(x);
String dynamicY = generateDynamicY(y); String dynamicY = generateDynamicY(y);
@ -224,9 +239,9 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
getControlView().setX(x); getControlView().setX(x);
getControlView().setY(y); getControlView().setY(y);
for(ControlInterface button : ((ControlLayout) getControlView().getParent()).getButtonChildren()){ for (ControlInterface button : ((ControlLayout) getControlView().getParent()).getButtonChildren()) {
//Step 1: Filter unwanted buttons //Step 1: Filter unwanted buttons
if(!canSnap(button)) continue; if (!canSnap(button)) continue;
//Step 2: Get Coordinates //Step 2: Get Coordinates
float button_top = button.getControlView().getY(); float button_top = button.getControlView().getY();
@ -240,28 +255,28 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
float right = getControlView().getX() + getControlView().getWidth(); float right = getControlView().getX() + getControlView().getWidth();
//Step 3: For each axis, we try to snap to the nearest //Step 3: For each axis, we try to snap to the nearest
if(Math.abs(top - button_bottom) < MIN_DISTANCE){ // Bottom snap if (Math.abs(top - button_bottom) < MIN_DISTANCE) { // Bottom snap
dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " + ${margin}" ; dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " + ${margin}";
}else if(Math.abs(button_top - bottom) < MIN_DISTANCE){ //Top snap } else if (Math.abs(button_top - bottom) < MIN_DISTANCE) { //Top snap
dynamicY = applySize(button.getProperties().dynamicY, button) + " - ${height} - ${margin}"; dynamicY = applySize(button.getProperties().dynamicY, button) + " - ${height} - ${margin}";
} }
if(!dynamicY.equals(generateDynamicY(getControlView().getY()))){ //If we snapped if (!dynamicY.equals(generateDynamicY(getControlView().getY()))) { //If we snapped
if(Math.abs(button_left - left) < MIN_DISTANCE){ //Left align snap if (Math.abs(button_left - left) < MIN_DISTANCE) { //Left align snap
dynamicX = applySize(button.getProperties().dynamicX, button); 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}"; 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}"; 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}"; dynamicX = applySize(button.getProperties().dynamicX, button) + applySize(" + ${width}", button) + " + ${margin}";
} }
if(!dynamicX.equals(generateDynamicX(getControlView().getX()))){ //If we snapped if (!dynamicX.equals(generateDynamicX(getControlView().getX()))) { //If we snapped
if(Math.abs(button_top - top) < MIN_DISTANCE){ //Top align snap if (Math.abs(button_top - top) < MIN_DISTANCE) { //Top align snap
dynamicY = applySize(button.getProperties().dynamicY, button); 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}"; dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " - ${height}";
} }
} }
@ -272,17 +287,21 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
setDynamicY(dynamicY); setDynamicY(dynamicY);
} }
/** Wrapper for multiple injections at once */ /**
default void injectBehaviors(){ * Wrapper for multiple injections at once
*/
default void injectBehaviors() {
injectProperties(); injectProperties();
injectTouchEventBehavior(); injectTouchEventBehavior();
injectLayoutParamBehavior(); injectLayoutParamBehavior();
injectGrabListenerBehavior(); injectGrabListenerBehavior();
} }
/** Inject the grab listener, remove it when the view is gone */ /**
default void injectGrabListenerBehavior(){ * Inject the grab listener, remove it when the view is gone
if(getControlView() == null){ */
default void injectGrabListenerBehavior() {
if (getControlView() == null) {
Log.e(ControlInterface.class.toString(), "Failed to inject grab listener behavior !"); Log.e(ControlInterface.class.toString(), "Failed to inject grab listener behavior !");
return; return;
} }
@ -304,12 +323,14 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
} }
default void injectProperties(){ default void injectProperties() {
getControlView().post(() -> getControlView().setTranslationZ(10)); 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() { getControlView().setOnTouchListener(new View.OnTouchListener() {
private boolean mCanTriggerLongClick = true; private boolean mCanTriggerLongClick = true;
private float downX, downY; private float downX, downY;
@ -318,7 +339,7 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
public boolean onTouch(View view, MotionEvent event) { public boolean onTouch(View view, MotionEvent event) {
if(!getControlLayoutParent().getModifiable()){ if (!getControlLayoutParent().getModifiable()) {
// Basically, editing behavior is forced while in game behavior is specific // Basically, editing behavior is forced while in game behavior is specific
view.onTouchEvent(event); view.onTouchEvent(event);
return true; return true;
@ -342,7 +363,7 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
break; break;
case MotionEvent.ACTION_MOVE: 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; mCanTriggerLongClick = false;
getControlLayoutParent().adaptPanelPosition(); 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) -> { getControlView().addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
getProperties().setWidth(right-left); getProperties().setWidth(right - left);
getProperties().setHeight(bottom-top); getProperties().setHeight(bottom - top);
setBackground(); setBackground();
// Re-calculate position // Re-calculate position
if(!getProperties().isDynamicBtn){ if (!getProperties().isDynamicBtn) {
getControlView().setX(getControlView().getX()); getControlView().setX(getControlView().getX());
getControlView().setY(getControlView().getY()); getControlView().setY(getControlView().getY());
}else { } else {
getControlView().setX(getProperties().insertDynamicPos(getProperties().dynamicX)); getControlView().setX(getProperties().insertDynamicPos(getProperties().dynamicX));
getControlView().setY(getProperties().insertDynamicPos(getProperties().dynamicY)); getControlView().setY(getProperties().insertDynamicPos(getProperties().dynamicY));
} }
@ -378,7 +399,7 @@ public interface ControlInterface extends View.OnLongClickListener, GrabListener
} }
@Override @Override
default boolean onLongClick(View v){ default boolean onLongClick(View v) {
if (getControlLayoutParent().getModifiable()) { if (getControlLayoutParent().getModifiable()) {
getControlLayoutParent().editControlButton(this); getControlLayoutParent().editControlButton(this);
getControlLayoutParent().mActionRow.setFollowedButton(this); getControlLayoutParent().mActionRow.setFollowedButton(this);

View File

@ -26,26 +26,28 @@ import io.github.controlwear.virtual.joystick.android.JoystickView;
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
public class ControlJoystick extends JoystickView implements ControlInterface { 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; 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 // Directions keycode
private final int[] mDirectionForwardLock = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL}; private final int[] mDirectionForwardLock = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL};
private final int[] mDirectionForward = new int[]{LwjglGlfwKeycode.GLFW_KEY_W}; private final int[] mDirectionForward = new int[]{LwjglGlfwKeycode.GLFW_KEY_W};
private final int[] mDirectionRight = new int[]{LwjglGlfwKeycode.GLFW_KEY_D}; private final int[] mDirectionRight = new int[]{LwjglGlfwKeycode.GLFW_KEY_D};
private final int[] mDirectionBackward = new int[]{LwjglGlfwKeycode.GLFW_KEY_S}; private final int[] mDirectionBackward = new int[]{LwjglGlfwKeycode.GLFW_KEY_S};
private final int[] mDirectionLeft = new int[]{LwjglGlfwKeycode.GLFW_KEY_A}; 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; mControlData = data;
setProperties(preProcessProperties(data, layout)); setProperties(preProcessProperties(data, layout));
setDeadzone(35); setDeadzone(35);
@ -61,7 +63,7 @@ public class ControlJoystick extends JoystickView implements ControlInterface {
mLastDirectionInt = mCurrentDirectionInt; mLastDirectionInt = mCurrentDirectionInt;
mCurrentDirectionInt = getDirectionInt(angle, strength); mCurrentDirectionInt = getDirectionInt(angle, strength);
if(mLastDirectionInt != mCurrentDirectionInt){ if (mLastDirectionInt != mCurrentDirectionInt) {
sendDirectionalKeycode(mLastDirectionInt, false); sendDirectionalKeycode(mLastDirectionInt, false);
sendDirectionalKeycode(mCurrentDirectionInt, true); sendDirectionalKeycode(mCurrentDirectionInt, true);
} }
@ -75,7 +77,9 @@ public class ControlJoystick extends JoystickView implements ControlInterface {
} }
@Override @Override
public View getControlView() {return this;} public View getControlView() {
return this;
}
@Override @Override
public ControlData getProperties() { public ControlData getProperties() {
@ -107,7 +111,7 @@ public class ControlJoystick extends JoystickView implements ControlInterface {
@Override @Override
public void setBackground() { public void setBackground() {
setBorderWidth(computeStrokeWidth(getProperties().strokeWidth)); setBorderWidth((int) Tools.dpToPx(getProperties().strokeWidth));
setBorderColor(getProperties().strokeColor); setBorderColor(getProperties().strokeColor);
setBackgroundColor(getProperties().bgColor); setBackgroundColor(getProperties().bgColor);
} }
@ -120,13 +124,13 @@ public class ControlJoystick extends JoystickView implements ControlInterface {
editControlPopup.loadJoystickValues(mControlData); editControlPopup.loadJoystickValues(mControlData);
} }
private int getDirectionInt(int angle, int intensity){ private int getDirectionInt(int angle, int intensity) {
if(intensity == 0) return DIRECTION_NONE; if (intensity == 0) return DIRECTION_NONE;
return (int) (((angle+22.5)/45) % 8); return (int) (((angle + 22.5) / 45) % 8);
} }
private void sendDirectionalKeycode(int direction, boolean isDown){ private void sendDirectionalKeycode(int direction, boolean isDown) {
switch (direction){ switch (direction) {
case DIRECTION_NORTH: case DIRECTION_NORTH:
sendInput(mDirectionForward, isDown); sendInput(mDirectionForward, isDown);
break; 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);
}
}
} }

View File

@ -269,11 +269,11 @@ public class EditControlPopup {
mHeightEditText.setText(String.valueOf(data.getHeight())); mHeightEditText.setText(String.valueOf(data.getHeight()));
mAlphaSeekbar.setProgress((int) (data.opacity * 100)); mAlphaSeekbar.setProgress((int) (data.opacity * 100));
mStrokeWidthSeekbar.setProgress(data.strokeWidth); mStrokeWidthSeekbar.setProgress((int) data.strokeWidth * 10);
mCornerRadiusSeekbar.setProgress((int) data.cornerRadius); mCornerRadiusSeekbar.setProgress((int) data.cornerRadius);
setPercentageText(mAlphaPercentTextView, (int) (data.opacity * 100)); setPercentageText(mAlphaPercentTextView, (int) (data.opacity * 100));
setPercentageText(mStrokePercentTextView, data.strokeWidth); setPercentageText(mStrokePercentTextView, (int) data.strokeWidth * 10);
setPercentageText(mCornerRadiusPercentTextView, (int) data.cornerRadius); setPercentageText(mCornerRadiusPercentTextView, (int) data.cornerRadius);
mToggleSwitch.setChecked(data.isToggle); mToggleSwitch.setChecked(data.isToggle);
@ -498,7 +498,7 @@ public class EditControlPopup {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (internalChanges) return; if (internalChanges) return;
mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress(); mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress() / 10F;
mCurrentlyEditedButton.setBackground(); mCurrentlyEditedButton.setBackground();
setPercentageText(mStrokePercentTextView, progress); setPercentageText(mStrokePercentTextView, progress);
} }