mirror of
https://github.com/2009scape/2009Scape-mobile.git
synced 2025-12-14 10:30:13 -07:00
Feat|Refactor: New control editing workflow
The new worflow is mostly focused on the ability to change in real time visual features of a button. It also brings a new *export* button to easily export controls you made.
This commit is contained in:
parent
53cd15ac7d
commit
d1c88a19e0
41 changed files with 2082 additions and 2310 deletions
|
|
@ -105,6 +105,22 @@
|
|||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="share_file"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider"
|
||||
/>
|
||||
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package net.kdt.pojavlaunch;
|
||||
|
||||
import static androidx.core.content.FileProvider.getUriForFile;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.*;
|
||||
import android.net.Uri;
|
||||
import android.os.*;
|
||||
|
||||
import androidx.appcompat.app.*;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
|
@ -30,34 +34,39 @@ public class CustomControlsActivity extends BaseActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getIntent().getExtras() != null && getIntent().getExtras().getBoolean("fromMainActivity", false)) {
|
||||
// TODO translucent!
|
||||
// setTheme(androidx.appcompat.R.style.Theme_AppCompat_Translucent);
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_custom_controls);
|
||||
|
||||
mControlLayout = (ControlLayout) findViewById(R.id.customctrl_controllayout);
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.customctrl_drawerlayout);
|
||||
mDrawerNavigationView = (ListView) findViewById(R.id.customctrl_navigation_view);
|
||||
mControlLayout = findViewById(R.id.customctrl_controllayout);
|
||||
mDrawerLayout = findViewById(R.id.customctrl_drawerlayout);
|
||||
mDrawerNavigationView = findViewById(R.id.customctrl_navigation_view);
|
||||
View mPullDrawerButton = findViewById(R.id.drawer_button);
|
||||
|
||||
mDrawerNavigationView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,getResources().getStringArray(R.array.menu_customcontrol)));
|
||||
mPullDrawerButton.setOnClickListener(v -> mDrawerLayout.openDrawer(mDrawerNavigationView));
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||
|
||||
mDrawerNavigationView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,getResources().getStringArray(R.array.menu_customcontrol_customactivity)));
|
||||
mDrawerNavigationView.setOnItemClickListener((parent, view, position, id) -> {
|
||||
switch(position) {
|
||||
case 0:
|
||||
mControlLayout.addControlButton(new ControlData("New"));
|
||||
break;
|
||||
case 1:
|
||||
mControlLayout.addDrawer(new ControlDrawerData());
|
||||
break;
|
||||
case 2:
|
||||
load(mControlLayout);
|
||||
break;
|
||||
case 3:
|
||||
save(false, mControlLayout);
|
||||
break;
|
||||
case 4:
|
||||
dialogSelectDefaultCtrl(mControlLayout);
|
||||
case 0: mControlLayout.addControlButton(new ControlData("New")); break;
|
||||
case 1: mControlLayout.addDrawer(new ControlDrawerData()); break;
|
||||
//case 2: mControlLayout.addJoystickButton(new ControlData()); break;
|
||||
case 2: load(mControlLayout); break;
|
||||
case 3: save(false, mControlLayout); break;
|
||||
case 4: dialogSelectDefaultCtrl(mControlLayout); break;
|
||||
case 5: // Saving the currently shown control
|
||||
mControlLayout.save(Tools.DIR_DATA + "/files/" + sSelectedName + ".json");
|
||||
|
||||
Uri contentUri = getUriForFile(getBaseContext(), "share_file", new File(Tools.DIR_DATA, "/files/" + sSelectedName + ".json"));
|
||||
|
||||
Intent shareIntent = new Intent();
|
||||
shareIntent.setAction(Intent.ACTION_SEND);
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
shareIntent.setType("application/json");
|
||||
startActivity(shareIntent);
|
||||
|
||||
Intent sendIntent = Intent.createChooser(shareIntent, sSelectedName);
|
||||
startActivity(sendIntent);
|
||||
break;
|
||||
}
|
||||
mDrawerLayout.closeDrawers();
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ public class MainActivity extends BaseActivity {
|
|||
|
||||
private DrawerLayout drawerLayout;
|
||||
private ListView navDrawer;
|
||||
private View mDrawerPullButton;
|
||||
|
||||
private ArrayAdapter<String> gameActionArrayAdapter;
|
||||
private AdapterView.OnItemClickListener gameActionClickListener;
|
||||
|
|
@ -83,6 +84,9 @@ public class MainActivity extends BaseActivity {
|
|||
|
||||
initLayout(R.layout.activity_basemain);
|
||||
|
||||
mDrawerPullButton.setOnClickListener(v -> drawerLayout.openDrawer(navDrawer));
|
||||
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||
|
||||
// Set the sustained performance mode for available APIs
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
getWindow().setSustainedPerformanceMode(PREF_SUSTAINED_PERFORMANCE);
|
||||
|
|
@ -110,7 +114,7 @@ public class MainActivity extends BaseActivity {
|
|||
optionListener = MCOptionUtils::getMcScale;
|
||||
MCOptionUtils.addMCOptionListener(optionListener);
|
||||
|
||||
mControlLayout = findViewById(R.id.main_control_layout);
|
||||
|
||||
mControlLayout.setModifiable(false);
|
||||
try {
|
||||
mControlLayout.loadLayout(LauncherPreferences.PREF_DEFAULTCTRL_PATH);
|
||||
|
|
@ -131,14 +135,14 @@ public class MainActivity extends BaseActivity {
|
|||
|
||||
protected void initLayout(int resId) {
|
||||
setContentView(resId);
|
||||
bindViews();
|
||||
|
||||
try {
|
||||
Logger.getInstance().reset();
|
||||
// FIXME: is it safe fot multi thread?
|
||||
GLOBAL_CLIPBOARD = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
touchCharInput = findViewById(R.id.mainTouchCharInput);
|
||||
|
||||
touchCharInput.setCharacterSender(new LwjglCharSender());
|
||||
loggerView = findViewById(R.id.mainLoggerView);
|
||||
mControlLayout = findViewById(R.id.main_control_layout);
|
||||
|
||||
|
||||
LauncherProfiles.update();
|
||||
|
|
@ -175,10 +179,6 @@ public class MainActivity extends BaseActivity {
|
|||
|
||||
|
||||
// Menu
|
||||
drawerLayout = findViewById(R.id.main_drawer_options);
|
||||
|
||||
navDrawer = findViewById(R.id.main_navigation_view);
|
||||
|
||||
gameActionArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.menu_ingame));
|
||||
gameActionClickListener = (parent, view, position, id) -> {
|
||||
switch(position) {
|
||||
|
|
@ -205,10 +205,10 @@ public class MainActivity extends BaseActivity {
|
|||
navDrawer.setAdapter(gameActionArrayAdapter);
|
||||
navDrawer.setOnItemClickListener(gameActionClickListener);
|
||||
|
||||
touchpad = findViewById(R.id.main_touchpad);
|
||||
|
||||
|
||||
this.minecraftGLView = findViewById(R.id.main_game_render_view);
|
||||
|
||||
|
||||
this.drawerLayout.closeDrawers();
|
||||
|
||||
minecraftGLView.setSurfaceReadyListener(() -> {
|
||||
|
|
@ -375,9 +375,7 @@ public class MainActivity extends BaseActivity {
|
|||
}
|
||||
|
||||
public void leaveCustomControls() {
|
||||
if(this instanceof MainActivity) {
|
||||
try {
|
||||
mControlLayout.hideAllHandleViews();
|
||||
mControlLayout.loadLayout((CustomControls)null);
|
||||
mControlLayout.setModifiable(false);
|
||||
System.gc();
|
||||
|
|
@ -386,7 +384,6 @@ public class MainActivity extends BaseActivity {
|
|||
Tools.showError(this,e);
|
||||
}
|
||||
//((MainActivity) this).mControlLayout.loadLayout((CustomControls)null);
|
||||
}
|
||||
navDrawer.setAdapter(gameActionArrayAdapter);
|
||||
navDrawer.setOnItemClickListener(gameActionClickListener);
|
||||
isInEditor = false;
|
||||
|
|
@ -509,4 +506,16 @@ public class MainActivity extends BaseActivity {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void bindViews(){
|
||||
mControlLayout = findViewById(R.id.main_control_layout);
|
||||
minecraftGLView = findViewById(R.id.main_game_render_view);
|
||||
touchpad = findViewById(R.id.main_touchpad);
|
||||
drawerLayout = findViewById(R.id.main_drawer_options);
|
||||
navDrawer = findViewById(R.id.main_navigation_view);
|
||||
loggerView = findViewById(R.id.mainLoggerView);
|
||||
mControlLayout = findViewById(R.id.main_control_layout);
|
||||
touchCharInput = findViewById(R.id.mainTouchCharInput);
|
||||
mDrawerPullButton = findViewById(R.id.drawer_button);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ import android.widget.TextView;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
import net.kdt.pojavlaunch.utils.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
|
||||
|
|
@ -207,6 +209,9 @@ public class MinecraftGLSurface extends View {
|
|||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
// Kinda need to send this back to the layout
|
||||
if(((ControlLayout)getParent()).getModifiable()) return false;
|
||||
|
||||
// Looking for a mouse to handle, won't have an effect if no mouse exists.
|
||||
for (int i = 0; i < e.getPointerCount(); i++) {
|
||||
if(e.getToolType(i) != MotionEvent.TOOL_TYPE_MOUSE && e.getToolType(i) != MotionEvent.TOOL_TYPE_STYLUS ) continue;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,13 @@ import android.graphics.Paint;
|
|||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.core.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
|
||||
import top.defaults.checkerboarddrawable.CheckerboardDrawable;
|
||||
|
|
@ -26,7 +29,7 @@ public class AlphaView extends View {
|
|||
private int mSelectedAlpha;
|
||||
private float mAlphaDiv; // for quick pos->alpha multiplication
|
||||
private float mScreenDiv; // for quick alpha->pos multiplication
|
||||
private float mHeightThird; // 1/3 of the view size for cursor
|
||||
private float mWidthThird; // 1/3 of the view size for cursor
|
||||
public AlphaView(Context ctx, AttributeSet attrs) {
|
||||
super(ctx,attrs);
|
||||
mBlackPaint = new Paint();
|
||||
|
|
@ -46,9 +49,7 @@ public class AlphaView extends View {
|
|||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
mSelectedAlpha = (int) (mAlphaDiv * event.getX());
|
||||
if(mSelectedAlpha < 0) mSelectedAlpha = 0;
|
||||
if(mSelectedAlpha > 0xff) mSelectedAlpha = 0xff;
|
||||
mSelectedAlpha = (int) MathUtils.clamp(mAlphaDiv * event.getY(), 0, 0xff);
|
||||
if(mAlphaSelectionListener != null) mAlphaSelectionListener.onAlphaSelected(mSelectedAlpha);
|
||||
invalidate();
|
||||
return true;
|
||||
|
|
@ -58,11 +59,10 @@ public class AlphaView extends View {
|
|||
protected void onSizeChanged(int w, int h, int old_w, int old_h) {
|
||||
mViewSize.right = w;
|
||||
mViewSize.bottom = h;
|
||||
float h2 = mViewSize.bottom / 2f;
|
||||
mShaderPaint.setShader(new LinearGradient(0,h2,w,h2, 0, Color.BLACK, Shader.TileMode.REPEAT));
|
||||
mAlphaDiv = 255f / mViewSize.right;
|
||||
mScreenDiv = mViewSize.right / 255f;
|
||||
mHeightThird = mViewSize.bottom / 3f;
|
||||
mShaderPaint.setShader(new LinearGradient(0,0,0,h, 0, Color.WHITE, Shader.TileMode.REPEAT));
|
||||
mAlphaDiv = 255f / mViewSize.bottom;
|
||||
mScreenDiv = mViewSize.bottom / 255f;
|
||||
mWidthThird = mViewSize.right / 3f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -70,7 +70,7 @@ public class AlphaView extends View {
|
|||
mCheckerboardDrawable.draw(canvas);
|
||||
canvas.drawRect(mViewSize, mShaderPaint);
|
||||
float linePos = mSelectedAlpha * mScreenDiv;
|
||||
canvas.drawLine(linePos, 0 ,linePos, mHeightThird, mBlackPaint);
|
||||
canvas.drawLine(linePos, mHeightThird * 2 ,linePos, mViewSize.bottom, mBlackPaint);
|
||||
canvas.drawLine(0, linePos , mWidthThird, linePos, mBlackPaint);
|
||||
canvas.drawLine(mWidthThird * 2, linePos, getRight(),linePos, mBlackPaint);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,63 +8,68 @@ import android.text.Editable;
|
|||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
|
||||
public class ColorSelector implements HueSelectionListener, RectangleSelectionListener, AlphaSelectionListener, TextWatcher{
|
||||
private static final int ALPHA_MASK = ~(0xFF << 24);
|
||||
private final View mRootView;
|
||||
private final HueView mHueView;
|
||||
private final SVRectangleView mLuminosityIntensityView;
|
||||
private final AlphaView mAlphaView;
|
||||
private final ColorSideBySideView mColorView;
|
||||
private final EditText mTextView;
|
||||
private final AlertDialog mDialog;
|
||||
|
||||
private ColorSelectionListener mColorSelectionListener;
|
||||
private float[] mHueTemplate = new float[] {0,1,1};
|
||||
private float[] mHsvSelected = new float[] {360,1,1};
|
||||
private final float[] mHueTemplate = new float[] {0,1,1};
|
||||
private final float[] mHsvSelected = new float[] {360,1,1};
|
||||
private int mAlphaSelected = 0xff;
|
||||
private ColorStateList mTextColors;
|
||||
private final ColorStateList mTextColors;
|
||||
private boolean mWatch = true;
|
||||
|
||||
private boolean mAlphaEnabled = true;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a color selector dialog for this Context.
|
||||
* @param context Context used for this ColorSelector dialog
|
||||
* @param colorSelectionListener Color selection listener to which the events will be sent to. Can be null.
|
||||
*/
|
||||
public ColorSelector(Context context, ColorSelectionListener colorSelectionListener) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_color_selector,null);
|
||||
mHueView = view.findViewById(R.id.color_selector_hue_view);
|
||||
mLuminosityIntensityView = view.findViewById(R.id.color_selector_rectangle_view);
|
||||
mAlphaView = view.findViewById(R.id.color_selector_alpha_view);
|
||||
mColorView = view.findViewById(R.id.color_selector_color_view);
|
||||
mTextView = view.findViewById(R.id.color_selector_hex_edit);
|
||||
public ColorSelector(Context context, ViewGroup parent, @Nullable ColorSelectionListener colorSelectionListener) {
|
||||
|
||||
mRootView = LayoutInflater.from(context).inflate(R.layout.dialog_color_selector,parent, false);
|
||||
mHueView = mRootView.findViewById(R.id.color_selector_hue_view);
|
||||
mLuminosityIntensityView = mRootView.findViewById(R.id.color_selector_rectangle_view);
|
||||
mAlphaView = mRootView.findViewById(R.id.color_selector_alpha_view);
|
||||
mColorView = mRootView.findViewById(R.id.color_selector_color_view);
|
||||
mTextView = mRootView.findViewById(R.id.color_selector_hex_edit);
|
||||
runColor(Color.RED);
|
||||
mHueView.setHueSelectionListener(this);
|
||||
mLuminosityIntensityView.setRectSelectionListener(this);
|
||||
mAlphaView.setAlphaSelectionListener(this);
|
||||
mTextView.addTextChangedListener(this);
|
||||
mTextColors = mTextView.getTextColors();
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(android.R.string.ok,(dialog,which)->{
|
||||
if (mColorSelectionListener != null) {
|
||||
mColorSelectionListener.onColorSelected(Color.HSVToColor(mAlphaSelected, mHsvSelected));
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, ((dialog, which) -> {}));
|
||||
|
||||
mColorSelectionListener = colorSelectionListener;
|
||||
mDialog = builder.create();
|
||||
|
||||
parent.addView(mRootView);
|
||||
}
|
||||
|
||||
/** @return The root view, mainly for position manipulation purposes */
|
||||
public View getRootView(){
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the color selector with the default (red) color selected.
|
||||
*/
|
||||
public void show() {
|
||||
runColor(Color.RED);
|
||||
dispatchColorChange();
|
||||
mDialog.show();
|
||||
show(Color.RED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,7 +79,6 @@ public class ColorSelector implements HueSelectionListener, RectangleSelectionLi
|
|||
public void show(int previousColor) {
|
||||
runColor(previousColor); // initialize
|
||||
dispatchColorChange(); // set the hex text
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -113,9 +117,10 @@ public class ColorSelector implements HueSelectionListener, RectangleSelectionLi
|
|||
mColorView.setColor(color);
|
||||
mWatch = false;
|
||||
mTextView.setText(String.format("%08X",color));
|
||||
notifyColorSelector(color);
|
||||
}
|
||||
|
||||
//IUO: sets all Views to render the desired color. Used for initilaization and HEX color input
|
||||
//IUO: sets all Views to render the desired color. Used for initialization and HEX color input
|
||||
protected void runColor(int color) {
|
||||
Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color), mHsvSelected);
|
||||
mHueTemplate[0] = mHsvSelected[0];
|
||||
|
|
@ -123,7 +128,7 @@ public class ColorSelector implements HueSelectionListener, RectangleSelectionLi
|
|||
mLuminosityIntensityView.setColor(Color.HSVToColor(mHueTemplate), false);
|
||||
mLuminosityIntensityView.setLuminosityIntensity(mHsvSelected[2], mHsvSelected[1]);
|
||||
mAlphaSelected = Color.alpha(color);
|
||||
mAlphaView.setAlpha(mAlphaSelected);
|
||||
mAlphaView.setAlpha(mAlphaEnabled ? mAlphaSelected : 255);
|
||||
mColorView.setColor(color);
|
||||
}
|
||||
|
||||
|
|
@ -147,4 +152,18 @@ public class ColorSelector implements HueSelectionListener, RectangleSelectionLi
|
|||
mWatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setColorSelectionListener(ColorSelectionListener listener){
|
||||
mColorSelectionListener = listener;
|
||||
}
|
||||
|
||||
public void setAlphaEnabled(boolean alphaEnabled){
|
||||
mAlphaEnabled = alphaEnabled;
|
||||
mAlphaView.setVisibility(alphaEnabled ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void notifyColorSelector(int color){
|
||||
if(mColorSelectionListener != null)
|
||||
mColorSelectionListener.onColorSelected(color);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ public class HueView extends View {
|
|||
private Bitmap mGamma;
|
||||
private HueSelectionListener mHueSelectionListener;
|
||||
private float mSelectionHue;
|
||||
private float mWidthHueRatio;
|
||||
private float mHueWidthRatio;
|
||||
private float mHeightHueRatio;
|
||||
private float mHueHeightRatio;
|
||||
private float mWidth;
|
||||
private float mHeight;
|
||||
private float mHeightThird;
|
||||
private float mWidthThird;
|
||||
public HueView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
blackPaint.setColor(Color.BLACK);
|
||||
|
|
@ -43,7 +43,7 @@ public class HueView extends View {
|
|||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
mSelectionHue = event.getX() * mWidthHueRatio;
|
||||
mSelectionHue = event.getY() * mHeightHueRatio;
|
||||
invalidate();
|
||||
if(mHueSelectionListener != null) mHueSelectionListener.onHueSelected(mSelectionHue);
|
||||
return true;
|
||||
|
|
@ -52,16 +52,16 @@ public class HueView extends View {
|
|||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
canvas.drawBitmap(mGamma, 0, 0 ,null);
|
||||
float linePos = mSelectionHue * mHueWidthRatio;
|
||||
canvas.drawLine(linePos, 0 ,linePos, mHeightThird, blackPaint);
|
||||
canvas.drawLine(linePos, mHeightThird * 2 ,linePos, mHeight, blackPaint);
|
||||
float linePos = mSelectionHue * mHueHeightRatio;
|
||||
canvas.drawLine(0, linePos , mWidthThird, linePos, blackPaint);
|
||||
canvas.drawLine( mWidthThird * 2 ,linePos, mWidth, linePos, blackPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int old_w, int old_h) {
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
mHeightThird = mHeight / 3;
|
||||
mWidthThird = mWidth / 3;
|
||||
regenerateGammaBitmap();
|
||||
}
|
||||
|
||||
|
|
@ -71,13 +71,13 @@ public class HueView extends View {
|
|||
mGamma = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Paint paint = new Paint();
|
||||
Canvas canvas = new Canvas(mGamma);
|
||||
mWidthHueRatio = 360/ mWidth;
|
||||
mHueWidthRatio = mWidth / 360;
|
||||
mHeightHueRatio = 360/ mHeight;
|
||||
mHueHeightRatio = mHeight / 360;
|
||||
float[] hsvFiller = new float[] {0, 1, 1};
|
||||
for(float i = 0; i < mWidth; i++) {
|
||||
hsvFiller[0] = i * mWidthHueRatio;
|
||||
for(float i = 0; i < mHeight; i++) {
|
||||
hsvFiller[0] = i * mHeightHueRatio;
|
||||
paint.setColor(Color.HSVToColor(hsvFiller));
|
||||
canvas.drawLine(i,0,i, mHeight,paint);
|
||||
canvas.drawLine(0,i,mWidth, i,paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package net.kdt.pojavlaunch.customcontrols;
|
||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
|
||||
|
||||
import android.content.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.*;
|
||||
import com.google.gson.*;
|
||||
import java.io.*;
|
||||
|
|
@ -12,16 +16,24 @@ import java.util.HashMap;
|
|||
import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.HandleView;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.ActionRow;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.ControlHandleView;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.EditControlPopup;
|
||||
|
||||
import net.kdt.pojavlaunch.prefs.*;
|
||||
|
||||
public class ControlLayout extends FrameLayout {
|
||||
protected CustomControls mLayout;
|
||||
private boolean mModifiable;
|
||||
private boolean mModifiable = false;
|
||||
private CustomControlsActivity mActivity;
|
||||
private boolean mControlVisible = false;
|
||||
|
||||
private EditControlPopup mControlPopup = null;
|
||||
private ControlHandleView mHandleView;
|
||||
public ActionRow actionRow = null;
|
||||
|
||||
public ControlLayout(Context ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
|
@ -30,25 +42,22 @@ public class ControlLayout extends FrameLayout {
|
|||
super(ctx, attrs);
|
||||
}
|
||||
|
||||
public void hideAllHandleViews() {
|
||||
for(ControlButton button : getButtonChildren()){
|
||||
HandleView hv = button.getHandleView();
|
||||
if(hv != null) hv.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadLayout(String jsonPath) throws IOException, JsonSyntaxException {
|
||||
CustomControls layout = LayoutConverter.loadAndConvertIfNecessary(jsonPath);
|
||||
if(layout != null) {
|
||||
loadLayout(layout);
|
||||
}else{
|
||||
throw new IOException("Unsupported control layout version");
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IOException("Unsupported control layout version");
|
||||
}
|
||||
|
||||
public void loadLayout(CustomControls controlLayout) {
|
||||
if (mModifiable)
|
||||
hideAllHandleViews();
|
||||
if(actionRow == null){
|
||||
actionRow = new ActionRow(getContext());
|
||||
addView(actionRow);
|
||||
}
|
||||
|
||||
removeAllButtons();
|
||||
if(mLayout != null) {
|
||||
|
|
@ -73,9 +82,6 @@ public class ControlLayout extends FrameLayout {
|
|||
for(ControlDrawerData drawerData : controlLayout.mDrawerDataList){
|
||||
ControlDrawer drawer = addDrawerView(drawerData);
|
||||
if(mModifiable) drawer.areButtonsVisible = true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
mLayout.scaledAt = LauncherPreferences.PREF_BUTTONSIZE;
|
||||
|
|
@ -91,7 +97,7 @@ public class ControlLayout extends FrameLayout {
|
|||
|
||||
private void addControlView(ControlData controlButton) {
|
||||
final ControlButton view = new ControlButton(this, controlButton);
|
||||
view.setModifiable(mModifiable);
|
||||
|
||||
if (!mModifiable) {
|
||||
view.setAlpha(view.getProperties().opacity);
|
||||
view.setFocusable(false);
|
||||
|
|
@ -115,7 +121,7 @@ public class ControlLayout extends FrameLayout {
|
|||
private ControlDrawer addDrawerView(ControlDrawerData drawerData){
|
||||
|
||||
final ControlDrawer view = new ControlDrawer(this,drawerData == null ? mLayout.mDrawerDataList.get(mLayout.mDrawerDataList.size()-1) : drawerData);
|
||||
view.setModifiable(mModifiable);
|
||||
|
||||
if (!mModifiable) {
|
||||
view.setAlpha(view.getProperties().opacity);
|
||||
view.setFocusable(false);
|
||||
|
|
@ -138,9 +144,9 @@ public class ControlLayout extends FrameLayout {
|
|||
addSubView(drawer, drawer.getDrawerData().buttonProperties.get(drawer.getDrawerData().buttonProperties.size()-1 ));
|
||||
}
|
||||
|
||||
public void addSubView(ControlDrawer drawer, ControlData controlButton){
|
||||
private void addSubView(ControlDrawer drawer, ControlData controlButton){
|
||||
final ControlSubButton view = new ControlSubButton(this, controlButton, drawer);
|
||||
view.setModifiable(mModifiable);
|
||||
|
||||
if (!mModifiable) {
|
||||
view.setAlpha(view.getProperties().opacity);
|
||||
view.setFocusable(false);
|
||||
|
|
@ -155,9 +161,10 @@ public class ControlLayout extends FrameLayout {
|
|||
setModified(true);
|
||||
}
|
||||
|
||||
|
||||
private void removeAllButtons() {
|
||||
for(View v : getButtonChildren()){
|
||||
removeView(v);
|
||||
for(ControlInterface button : getButtonChildren()){
|
||||
removeView(button.getControlView());
|
||||
}
|
||||
|
||||
System.gc();
|
||||
|
|
@ -165,37 +172,6 @@ public class ControlLayout extends FrameLayout {
|
|||
//because if frames will slowly go down after many control changes it will be warm and bad
|
||||
}
|
||||
|
||||
public void removeControlButton(ControlButton controlButton) {
|
||||
mLayout.mControlDataList.remove(controlButton.getProperties());
|
||||
controlButton.setVisibility(View.GONE);
|
||||
removeView(controlButton);
|
||||
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public void removeControlDrawer(ControlDrawer controlDrawer){
|
||||
for(ControlSubButton subButton : controlDrawer.buttons){
|
||||
subButton.setVisibility(GONE);
|
||||
removeView(subButton);
|
||||
}
|
||||
mLayout.mDrawerDataList.remove(controlDrawer.getDrawerData());
|
||||
controlDrawer.setVisibility(GONE);
|
||||
removeView(controlDrawer);
|
||||
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public void removeControlSubButton(ControlSubButton subButton){
|
||||
subButton.parentDrawer.drawerData.buttonProperties.remove(subButton.getProperties());
|
||||
subButton.parentDrawer.buttons.remove(subButton);
|
||||
|
||||
subButton.parentDrawer.syncButtons();
|
||||
|
||||
subButton.setVisibility(GONE);
|
||||
removeView(subButton);
|
||||
|
||||
}
|
||||
|
||||
public void saveLayout(String path) throws Exception {
|
||||
mLayout.save(path);
|
||||
setModified(false);
|
||||
|
|
@ -214,22 +190,27 @@ public class ControlLayout extends FrameLayout {
|
|||
return mLayout.scaledAt;
|
||||
}
|
||||
|
||||
public CustomControls getLayout(){
|
||||
return mLayout;
|
||||
}
|
||||
|
||||
public void setControlVisible(boolean isVisible) {
|
||||
if (mModifiable) return; // Not using on custom controls activity
|
||||
|
||||
mControlVisible = isVisible;
|
||||
for(ControlButton button : getButtonChildren()){
|
||||
for(ControlInterface button : getButtonChildren()){
|
||||
button.setVisible(isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
public void setModifiable(boolean isModifiable) {
|
||||
mModifiable = isModifiable;
|
||||
for(ControlButton button : getButtonChildren()){
|
||||
button.setModifiable(isModifiable);
|
||||
if (!isModifiable)
|
||||
button.setAlpha(button.getProperties().opacity);
|
||||
if(isModifiable){
|
||||
}else {
|
||||
if(mModifiable)
|
||||
removeEditWindow();
|
||||
}
|
||||
|
||||
mModifiable = isModifiable;
|
||||
}
|
||||
|
||||
public boolean getModifiable(){
|
||||
|
|
@ -241,27 +222,74 @@ public class ControlLayout extends FrameLayout {
|
|||
|
||||
}
|
||||
|
||||
public ArrayList<ControlButton> getButtonChildren(){
|
||||
ArrayList<ControlButton> children = new ArrayList<>();
|
||||
public ArrayList<ControlInterface> getButtonChildren(){
|
||||
ArrayList<ControlInterface> children = new ArrayList<>();
|
||||
for(int i=0; i<getChildCount(); ++i){
|
||||
View v = getChildAt(i);
|
||||
if(v instanceof ControlButton)
|
||||
children.add(((ControlButton) v));
|
||||
if(v instanceof ControlInterface)
|
||||
children.add(((ControlInterface) v));
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
public void refreshControlButtonPositions(){
|
||||
for(ControlButton button : getButtonChildren()){
|
||||
for(ControlInterface button : getButtonChildren()){
|
||||
button.setDynamicX(button.getProperties().dynamicX);
|
||||
button.setDynamicY(button.getProperties().dynamicY);
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<View, ControlButton> mapTable = new HashMap<>();
|
||||
@Override
|
||||
public void onViewRemoved(View child) {
|
||||
super.onViewRemoved(child);
|
||||
if(child instanceof ControlInterface){
|
||||
mControlPopup.disappearColor();
|
||||
mControlPopup.disappear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the layout if needed, and pass down the burden of filling values
|
||||
* to the button at hand.
|
||||
*/
|
||||
public void editControlButton(ControlInterface button){
|
||||
if(mControlPopup == null){
|
||||
// When the panel is null, it needs to inflate first.
|
||||
// So inflate it, then process it on the next frame
|
||||
mControlPopup = new EditControlPopup(getContext(), this);
|
||||
post(() -> editControlButton(button));
|
||||
return;
|
||||
}
|
||||
|
||||
mControlPopup.internalChanges = true;
|
||||
mControlPopup.setCurrentlyEditedButton(button);
|
||||
button.loadEditValues(mControlPopup);
|
||||
|
||||
mControlPopup.internalChanges = false;
|
||||
|
||||
mControlPopup.appear(button.getControlView().getX() + button.getControlView().getWidth()/2f < currentDisplayMetrics.widthPixels/2f);
|
||||
mControlPopup.disappearColor();
|
||||
|
||||
if(mHandleView == null){
|
||||
mHandleView = new ControlHandleView(getContext());
|
||||
addView(mHandleView);
|
||||
}
|
||||
mHandleView.setControlButton(button);
|
||||
|
||||
//mHandleView.show();
|
||||
}
|
||||
|
||||
/** Swap the panel if the button position requires it */
|
||||
public void adaptPanelPosition(){
|
||||
if(mControlPopup != null)
|
||||
mControlPopup.adaptPanelPosition();
|
||||
}
|
||||
|
||||
|
||||
HashMap<View, ControlInterface> mapTable = new HashMap<>();
|
||||
//While this is called onTouch, this should only be called from a ControlButton.
|
||||
public boolean onTouch(View v, MotionEvent ev) {
|
||||
ControlButton lastControlButton = mapTable.get(v);
|
||||
ControlInterface lastControlButton = mapTable.get(v);
|
||||
|
||||
//Check if the action is cancelling, reset the lastControl button associated to the view
|
||||
if(ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_CANCEL){
|
||||
|
|
@ -274,8 +302,8 @@ public class ControlLayout extends FrameLayout {
|
|||
|
||||
//Optimization pass to avoid looking at all children again
|
||||
if(lastControlButton != null){
|
||||
if( ev.getRawX() > lastControlButton.getX() && ev.getRawX() < lastControlButton.getX() + lastControlButton.getWidth() &&
|
||||
ev.getRawY() > lastControlButton.getY() && ev.getRawY() < lastControlButton.getY() + lastControlButton.getHeight()){
|
||||
if( ev.getRawX() > lastControlButton.getControlView().getX() && ev.getRawX() < lastControlButton.getControlView().getX() + lastControlButton.getControlView().getWidth() &&
|
||||
ev.getRawY() > lastControlButton.getControlView().getY() && ev.getRawY() < lastControlButton.getControlView().getY() + lastControlButton.getControlView().getHeight()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -285,11 +313,11 @@ public class ControlLayout extends FrameLayout {
|
|||
mapTable.put(v, null);
|
||||
|
||||
//Look for another SWIPEABLE button
|
||||
for(ControlButton button : getButtonChildren()){
|
||||
for(ControlInterface button : getButtonChildren()){
|
||||
if(!button.getProperties().isSwipeable) continue;
|
||||
|
||||
if( ev.getRawX() > button.getX() && ev.getRawX() < button.getX() + button.getWidth() &&
|
||||
ev.getRawY() > button.getY() && ev.getRawY() < button.getY() + button.getHeight()){
|
||||
if( ev.getRawX() > button.getControlView().getX() && ev.getRawX() < button.getControlView().getX() + button.getControlView().getWidth() &&
|
||||
ev.getRawY() > button.getControlView().getY() && ev.getRawY() < button.getControlView().getY() + button.getControlView().getHeight()){
|
||||
|
||||
//Press the new key
|
||||
if(!button.equals(lastControlButton)){
|
||||
|
|
@ -302,4 +330,39 @@ public class ControlLayout extends FrameLayout {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mModifiable && event.getActionMasked() != MotionEvent.ACTION_UP || mControlPopup == null)
|
||||
return true;
|
||||
|
||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
|
||||
// When the input window cannot be hidden, it returns false
|
||||
if(!imm.hideSoftInputFromWindow(getWindowToken(), 0)){
|
||||
if(mControlPopup.disappearLayer()){
|
||||
actionRow.setFollowedButton(null);
|
||||
mHandleView.hide();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removeEditWindow() {
|
||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
|
||||
// When the input window cannot be hidden, it returns false
|
||||
imm.hideSoftInputFromWindow(getWindowToken(), 0);
|
||||
mControlPopup.disappearColor();
|
||||
mControlPopup.disappear();
|
||||
|
||||
actionRow.setFollowedButton(null);
|
||||
mHandleView.hide();
|
||||
}
|
||||
|
||||
public void save(String path){
|
||||
try {
|
||||
mLayout.save(path);
|
||||
} catch (IOException e) {Log.e("ControlLayout", "Failed to save the layout at:" + path);}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,11 @@ package net.kdt.pojavlaunch.customcontrols.buttons;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.*;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.view.View.*;
|
||||
import android.widget.*;
|
||||
|
||||
|
||||
|
||||
import androidx.core.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.*;
|
||||
|
|
@ -20,123 +15,56 @@ import net.kdt.pojavlaunch.*;
|
|||
import org.lwjgl.glfw.*;
|
||||
|
||||
import static net.kdt.pojavlaunch.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_BUTTONSIZE;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_BOTTOM_OFFSET;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_LEFT_OFFSET;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_RIGHT_OFFSET;
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_TOP_OFFSET;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener {
|
||||
@SuppressLint({"ViewConstructor", "AppCompatCustomView"})
|
||||
public class ControlButton extends TextView implements ControlInterface {
|
||||
private final Paint mRectPaint = new Paint();
|
||||
protected GestureDetector mGestureDetector;
|
||||
protected ControlData mProperties;
|
||||
protected SelectionEndHandleView mHandleView;
|
||||
protected boolean mModifiable = false;
|
||||
protected boolean mCanTriggerLongClick = true;
|
||||
|
||||
protected boolean mIsToggled = false;
|
||||
protected boolean mIsPointerOutOfBounds = false;
|
||||
|
||||
public ControlButton(ControlLayout layout, ControlData properties) {
|
||||
super(layout.getContext());
|
||||
setGravity(Gravity.CENTER);
|
||||
setAllCaps(true);
|
||||
setTextColor(Color.WHITE);
|
||||
setPadding(4, 4, 4, 4);
|
||||
|
||||
setOnLongClickListener(this);
|
||||
//setOnLongClickListener(this);
|
||||
|
||||
//When a button is created, the width/height has yet to be processed to fit the scaling.
|
||||
setProperties(preProcessProperties(properties, layout));
|
||||
setModified(false);
|
||||
|
||||
injectTouchEventBehavior();
|
||||
injectLayoutParamBehavior();
|
||||
}
|
||||
|
||||
public HandleView getHandleView() {
|
||||
return mHandleView;
|
||||
}
|
||||
@Override
|
||||
public View getControlView() {return this;}
|
||||
|
||||
public ControlData getProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
public void setProperties(ControlData properties) {
|
||||
setProperties(properties, true);
|
||||
}
|
||||
|
||||
public ControlData preProcessProperties(ControlData properties, ControlLayout layout){
|
||||
//When a button is created, properties have to be modified to fit the screen.
|
||||
//Size
|
||||
properties.setWidth(properties.getWidth() / layout.getLayoutScale() * PREF_BUTTONSIZE);
|
||||
properties.setHeight(properties.getHeight() / layout.getLayoutScale() * PREF_BUTTONSIZE);
|
||||
|
||||
//Visibility
|
||||
properties.isHideable = !properties.containsKeycode(ControlData.SPECIALBTN_TOGGLECTRL) && !properties.containsKeycode(ControlData.SPECIALBTN_VIRTUALMOUSE);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(ControlData properties, boolean changePos) {
|
||||
mProperties = properties;
|
||||
ControlInterface.super.setProperties(properties, changePos);
|
||||
|
||||
if(mProperties.isToggle){
|
||||
if (mProperties.isToggle) {
|
||||
//For the toggle layer
|
||||
final TypedValue value = new TypedValue();
|
||||
getContext().getTheme().resolveAttribute(R.attr.colorAccent, value, true);
|
||||
mRectPaint.setColor(value.data);
|
||||
mRectPaint.setAlpha(128);
|
||||
}else{
|
||||
} else {
|
||||
mRectPaint.setColor(Color.WHITE);
|
||||
mRectPaint.setAlpha(60);
|
||||
}
|
||||
|
||||
setText(properties.name);
|
||||
|
||||
if (changePos) {
|
||||
setX(properties.insertDynamicPos(mProperties.dynamicX));
|
||||
setY(properties.insertDynamicPos(mProperties.dynamicY));
|
||||
}
|
||||
|
||||
setLayoutParams(new FrameLayout.LayoutParams((int) properties.getWidth(), (int) properties.getHeight() ));
|
||||
}
|
||||
|
||||
public void setBackground(){
|
||||
GradientDrawable gd = new GradientDrawable();
|
||||
gd.setColor(mProperties.bgColor);
|
||||
gd.setStroke(computeStrokeWidth(mProperties.strokeWidth), mProperties.strokeColor);
|
||||
gd.setCornerRadius(computeCornerRadius(mProperties.cornerRadius));
|
||||
|
||||
setBackground(gd);
|
||||
}
|
||||
|
||||
public void setModifiable(boolean isModifiable) {
|
||||
mModifiable = isModifiable;
|
||||
}
|
||||
|
||||
private void setModified(boolean modified) {
|
||||
if (getParent() != null)
|
||||
((ControlLayout) getParent()).setModified(modified);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void setLayoutParams(ViewGroup.LayoutParams params) {
|
||||
super.setLayoutParams(params);
|
||||
|
||||
mProperties.setWidth(params.width);
|
||||
mProperties.setHeight(params.height);
|
||||
setBackground();
|
||||
|
||||
// Re-calculate position
|
||||
if(!mProperties.isDynamicBtn){
|
||||
setX(getX());
|
||||
setY(getY());
|
||||
}else {
|
||||
setX(mProperties.insertDynamicPos(mProperties.dynamicX));
|
||||
setY(mProperties.insertDynamicPos(mProperties.dynamicY));
|
||||
}
|
||||
|
||||
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
public void setVisible(boolean isVisible){
|
||||
|
|
@ -144,113 +72,6 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
|||
setVisibility(isVisible ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onVisibilityChanged(View changedView, int visibility) {
|
||||
super.onVisibilityChanged(changedView, visibility);
|
||||
setWillNotDraw(visibility == GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setX(float x) {
|
||||
// We have to account for control offset preference
|
||||
if(x + (mProperties.getWidth()/2f) > CallbackBridge.physicalWidth/2f){
|
||||
x -= PREF_CONTROL_RIGHT_OFFSET;
|
||||
}else{
|
||||
x += PREF_CONTROL_LEFT_OFFSET;
|
||||
}
|
||||
|
||||
super.setX(x);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setY(float y) {
|
||||
// We have to account for control offset preference
|
||||
if(y - PREF_CONTROL_TOP_OFFSET + (mProperties.getHeight()/2f) > CallbackBridge.physicalHeight/2f){
|
||||
y -= PREF_CONTROL_BOTTOM_OFFSET;
|
||||
}else{
|
||||
y += PREF_CONTROL_TOP_OFFSET;
|
||||
}
|
||||
|
||||
super.setY(y);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getX() {
|
||||
float x = super.getX();
|
||||
// We have to account for control offset preference
|
||||
if(x + (mProperties.getWidth()/2f) > (CallbackBridge.physicalWidth)/2f){
|
||||
x += PREF_CONTROL_RIGHT_OFFSET;
|
||||
}else{
|
||||
x -= PREF_CONTROL_LEFT_OFFSET;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getY(){
|
||||
// We have to account for control offset preference
|
||||
float y = super.getY();
|
||||
if(y + (mProperties.getHeight()/2f) > CallbackBridge.physicalHeight/2f){
|
||||
y += PREF_CONTROL_BOTTOM_OFFSET;
|
||||
}else{
|
||||
y -= PREF_CONTROL_TOP_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the dynamic equation on the x axis.
|
||||
* @param dynamicX The equation to compute the position from
|
||||
*/
|
||||
public void setDynamicX(String dynamicX){
|
||||
mProperties.dynamicX = dynamicX;
|
||||
setX(mProperties.insertDynamicPos(dynamicX));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the dynamic equation on the y axis.
|
||||
* @param dynamicY The equation to compute the position from
|
||||
*/
|
||||
public void setDynamicY(String dynamicY){
|
||||
mProperties.dynamicY = dynamicY;
|
||||
setY(mProperties.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
|
||||
*/
|
||||
public String generateDynamicX(float x){
|
||||
if(x + (mProperties.getWidth()/2f) > CallbackBridge.physicalWidth/2f){
|
||||
return (x + mProperties.getWidth()) / CallbackBridge.physicalWidth + " * ${screen_width} - ${width}";
|
||||
}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
|
||||
*/
|
||||
public String generateDynamicY(float y){
|
||||
if(y + (mProperties.getHeight()/2f) > CallbackBridge.physicalHeight/2f){
|
||||
return (y + mProperties.getHeight()) / CallbackBridge.physicalHeight + " * ${screen_height} - ${height}";
|
||||
}else{
|
||||
return y / CallbackBridge.physicalHeight + " * ${screen_height}";
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProperties() {
|
||||
setProperties(mProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
|
@ -258,63 +79,55 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
|||
canvas.drawRoundRect(0, 0, getWidth(), getHeight(), mProperties.cornerRadius, mProperties.cornerRadius, mRectPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (mCanTriggerLongClick && mModifiable) {
|
||||
//Instantiate on need only
|
||||
if(mHandleView == null) mHandleView = new SelectionEndHandleView(this);
|
||||
|
||||
if (mHandleView.isShowing()) {
|
||||
mHandleView.hide();
|
||||
} else {
|
||||
if (getParent() != null) {
|
||||
((ControlLayout) getParent()).hideAllHandleViews();
|
||||
public void loadEditValues(EditControlPopup editControlPopup){
|
||||
editControlPopup.loadValues(getProperties());
|
||||
}
|
||||
|
||||
try {
|
||||
mHandleView.show(this);
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
}
|
||||
/** Add another instance of the ControlButton to the parent layout */
|
||||
public void cloneButton(){
|
||||
ControlData cloneData = new ControlData(getProperties());
|
||||
cloneData.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) getParent()).addControlButton(cloneData);
|
||||
}
|
||||
|
||||
return mCanTriggerLongClick;
|
||||
/** Remove any trace of this button from the layout */
|
||||
public void removeButton() {
|
||||
getControlLayoutParent().getLayout().mControlDataList.remove(getProperties());
|
||||
getControlLayoutParent().removeView(this);
|
||||
}
|
||||
|
||||
protected float downX, downY;
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if(!mModifiable){
|
||||
mCanTriggerLongClick = false;
|
||||
|
||||
switch (event.getActionMasked()){
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
//Send the event to be taken as a mouse action
|
||||
if(mProperties.passThruEnabled && CallbackBridge.isGrabbing()){
|
||||
MinecraftGLSurface v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
|
||||
if(getProperties().passThruEnabled && CallbackBridge.isGrabbing()){
|
||||
MinecraftGLSurface v = getControlLayoutParent().findViewById(R.id.main_game_render_view);
|
||||
if (v != null) v.dispatchTouchEvent(event);
|
||||
}
|
||||
|
||||
//If out of bounds
|
||||
if(event.getX() < getLeft() || event.getX() > getRight() ||
|
||||
event.getY() < getTop() || event.getY() > getBottom()){
|
||||
if(mProperties.isSwipeable && !mIsPointerOutOfBounds){
|
||||
if(event.getX() < getControlView().getLeft() || event.getX() > getControlView().getRight() ||
|
||||
event.getY() < getControlView().getTop() || event.getY() > getControlView().getBottom()){
|
||||
if(getProperties().isSwipeable && !mIsPointerOutOfBounds){
|
||||
//Remove keys
|
||||
if(!triggerToggle()) {
|
||||
sendKeyPresses(false);
|
||||
}
|
||||
}
|
||||
mIsPointerOutOfBounds = true;
|
||||
((ControlLayout) getParent()).onTouch(this, event);
|
||||
getControlLayoutParent().onTouch(this, event);
|
||||
break;
|
||||
}
|
||||
|
||||
//Else if we now are in bounds
|
||||
if(mIsPointerOutOfBounds) {
|
||||
((ControlLayout) getParent()).onTouch(this, event);
|
||||
getControlLayoutParent().onTouch(this, event);
|
||||
//RE-press the button
|
||||
if(mProperties.isSwipeable && !mProperties.isToggle){
|
||||
if(getProperties().isSwipeable && !getProperties().isToggle){
|
||||
sendKeyPresses(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -323,7 +136,7 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
|||
|
||||
case MotionEvent.ACTION_DOWN: // 0
|
||||
case MotionEvent.ACTION_POINTER_DOWN: // 5
|
||||
if(!mProperties.isToggle){
|
||||
if(!getProperties().isToggle){
|
||||
sendKeyPresses(true);
|
||||
}
|
||||
break;
|
||||
|
|
@ -331,11 +144,11 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
|||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_CANCEL: // 3
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
if(mProperties.passThruEnabled){
|
||||
MinecraftGLSurface v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
|
||||
if(getProperties().passThruEnabled){
|
||||
MinecraftGLSurface v = getControlLayoutParent().findViewById(R.id.main_game_render_view);
|
||||
if (v != null) v.dispatchTouchEvent(event);
|
||||
}
|
||||
if(mIsPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event);
|
||||
if(mIsPointerOutOfBounds) getControlLayoutParent().onTouch(this, event);
|
||||
mIsPointerOutOfBounds = false;
|
||||
|
||||
if(!triggerToggle()) {
|
||||
|
|
@ -346,152 +159,11 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the button can be modified/moved */
|
||||
//Instantiate the gesture detector only when needed
|
||||
if(mGestureDetector == null) mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm());
|
||||
|
||||
if (mGestureDetector.onTouchEvent(event)) {
|
||||
mCanTriggerLongClick = true;
|
||||
onLongClick(this);
|
||||
}
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mCanTriggerLongClick = true;
|
||||
downX = event.getRawX() - getX();
|
||||
downY = event.getRawY() - getY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mCanTriggerLongClick = false;
|
||||
|
||||
if (!mProperties.isDynamicBtn) {
|
||||
snapAndAlign(
|
||||
MathUtils.clamp(event.getRawX() - downX, 0, CallbackBridge.physicalWidth - getWidth()),
|
||||
MathUtils.clamp(event.getRawY() - downY, 0, CallbackBridge.physicalHeight - getHeight())
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passe a series of checks to determine if the ControlButton is available to be snapped on.
|
||||
*
|
||||
* @param button The button to check
|
||||
* @return whether or not the button
|
||||
*/
|
||||
protected boolean canSnap(ControlButton button){
|
||||
float MIN_DISTANCE = Tools.dpToPx(8);
|
||||
|
||||
if(button == this) return false;
|
||||
if(net.kdt.pojavlaunch.utils.MathUtils.dist(
|
||||
button.getX() + button.getWidth()/2f,
|
||||
button.getY() + button.getHeight()/2f,
|
||||
getX() + getWidth()/2f,
|
||||
getY() + getHeight()/2f) > Math.max(button.getWidth()/2f + getWidth()/2f, button.getHeight()/2f + getHeight()/2f) + MIN_DISTANCE) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected void snapAndAlign(float x, float y){
|
||||
float MIN_DISTANCE = Tools.dpToPx(8);
|
||||
String dynamicX = generateDynamicX(x);
|
||||
String dynamicY = generateDynamicY(y);
|
||||
|
||||
setX(x);
|
||||
setY(y);
|
||||
|
||||
for(ControlButton button : ((ControlLayout) getParent()).getButtonChildren()){
|
||||
//Step 1: Filter unwanted buttons
|
||||
if(!canSnap(button)) continue;
|
||||
|
||||
//Step 2: Get Coordinates
|
||||
float button_top = button.getY();
|
||||
float button_bottom = button_top + button.getHeight();
|
||||
float button_left = button.getX();
|
||||
float button_right = button_left + button.getWidth();
|
||||
|
||||
float top = getY();
|
||||
float bottom = getY() + getHeight();
|
||||
float left = getX();
|
||||
float right = getX() + 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
|
||||
dynamicY = applySize(button.getProperties().dynamicY, button) + " - ${height} - ${margin}";
|
||||
}
|
||||
if(!dynamicY.equals(generateDynamicY(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
|
||||
dynamicX = applySize(button.getProperties().dynamicX, button) + applySize(" + ${width}", button) + " - ${width}";
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
dynamicX = applySize(button.getProperties().dynamicX, button) + applySize(" + ${width}", button) + " + ${margin}";
|
||||
}
|
||||
if(!dynamicX.equals(generateDynamicX(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
|
||||
dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " - ${height}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setDynamicX(dynamicX);
|
||||
setDynamicY(dynamicY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return The pre-processed equation as a String.
|
||||
*/
|
||||
private static String applySize(String equation, ControlButton button){
|
||||
return equation
|
||||
.replace("${right}", "(${screen_width} - ${width})")
|
||||
.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})");
|
||||
}
|
||||
|
||||
public int computeStrokeWidth(float widthInPercent){
|
||||
float maxSize = Math.max(mProperties.getWidth(), mProperties.getHeight());
|
||||
return (int)((maxSize/2) * (widthInPercent/100));
|
||||
}
|
||||
|
||||
public float computeCornerRadius(float radiusInPercent){
|
||||
float minSize = Math.min(mProperties.getWidth(), mProperties.getHeight());
|
||||
return (minSize/2) * (radiusInPercent/100);
|
||||
}
|
||||
|
||||
public boolean triggerToggle(){
|
||||
//returns true a the toggle system is triggered
|
||||
|
|
@ -552,4 +224,8 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOverlappingRendering() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ package net.kdt.pojavlaunch.customcontrols.buttons;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.EditControlPopup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -19,7 +21,7 @@ public class ControlDrawer extends ControlButton {
|
|||
|
||||
public ArrayList<ControlSubButton> buttons;
|
||||
public ControlDrawerData drawerData;
|
||||
public ControlLayout layout;
|
||||
public ControlLayout parentLayout;
|
||||
public boolean areButtonsVisible;
|
||||
|
||||
|
||||
|
|
@ -27,19 +29,19 @@ public class ControlDrawer extends ControlButton {
|
|||
super(layout, drawerData.properties);
|
||||
|
||||
buttons = new ArrayList<>(drawerData.buttonProperties.size());
|
||||
this.layout = layout;
|
||||
this.parentLayout = layout;
|
||||
this.drawerData = drawerData;
|
||||
areButtonsVisible = layout.getModifiable();
|
||||
}
|
||||
|
||||
|
||||
public void addButton(ControlData properties){
|
||||
addButton(new ControlSubButton(layout, properties, this));
|
||||
addButton(new ControlSubButton(parentLayout, properties, this));
|
||||
}
|
||||
|
||||
public void addButton(ControlSubButton button){
|
||||
buttons.add(button);
|
||||
setControlButtonVisibility(button, mModifiable || areButtonsVisible);
|
||||
setControlButtonVisibility(button, areButtonsVisible);
|
||||
syncButtons();
|
||||
}
|
||||
|
||||
|
|
@ -56,10 +58,10 @@ public class ControlDrawer extends ControlButton {
|
|||
|
||||
//Syncing stuff
|
||||
private void alignButtons(){
|
||||
|
||||
if(buttons == null) return;
|
||||
if(drawerData.orientation == ControlDrawerData.Orientation.FREE) return;
|
||||
for(int i=0; i < buttons.size(); ++i){
|
||||
|
||||
for(int i = 0; i < buttons.size(); ++i){
|
||||
switch (drawerData.orientation){
|
||||
case RIGHT:
|
||||
buttons.get(i).setDynamicX(generateDynamicX(getX() + (drawerData.properties.getWidth() + Tools.dpToPx(2))*(i+1) ));
|
||||
|
|
@ -107,7 +109,7 @@ public class ControlDrawer extends ControlButton {
|
|||
* @param button The button to look for
|
||||
* @return Whether the button is in the buttons list of the drawer.
|
||||
*/
|
||||
public boolean containsChild(ControlButton button){
|
||||
public boolean containsChild(ControlInterface button){
|
||||
for(ControlButton childButton : buttons){
|
||||
if (childButton == button) return true;
|
||||
}
|
||||
|
|
@ -129,7 +131,7 @@ public class ControlDrawer extends ControlButton {
|
|||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if(!mModifiable){
|
||||
if(!getControlLayoutParent().getModifiable()){
|
||||
switch (event.getActionMasked()){
|
||||
case MotionEvent.ACTION_UP: // 1
|
||||
case MotionEvent.ACTION_POINTER_UP: // 6
|
||||
|
|
@ -142,10 +144,6 @@ public class ControlDrawer extends ControlButton {
|
|||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSnap(ControlButton button) {
|
||||
return super.canSnap(button) && !containsChild(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setX(float x) {
|
||||
|
|
@ -165,8 +163,39 @@ public class ControlDrawer extends ControlButton {
|
|||
syncButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSnap(ControlInterface button) {
|
||||
boolean result = super.canSnap(button);
|
||||
return result && !containsChild(button);
|
||||
}
|
||||
|
||||
//Getters
|
||||
public ControlDrawerData getDrawerData() {
|
||||
return drawerData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadEditValues(EditControlPopup editControlPopup) {
|
||||
editControlPopup.loadValues(drawerData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneButton() {
|
||||
ControlDrawerData cloneData = new ControlDrawerData(getDrawerData());
|
||||
cloneData.properties.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.properties.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) getParent()).addDrawer(cloneData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeButton() {
|
||||
ControlLayout layout = getControlLayoutParent();
|
||||
for(ControlSubButton subButton : buttons){
|
||||
layout.removeView(subButton);
|
||||
}
|
||||
|
||||
layout.getLayout().mDrawerDataList.remove(getDrawerData());
|
||||
layout.removeView(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,345 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.buttons;
|
||||
|
||||
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_BUTTONSIZE;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.core.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.MinecraftGLSurface;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
import net.kdt.pojavlaunch.customcontrols.handleview.EditControlPopup;
|
||||
|
||||
import org.lwjgl.glfw.CallbackBridge;
|
||||
|
||||
/**
|
||||
* Interface injecting custom behavior to a View.
|
||||
* Most of the injected behavior is editing behavior,
|
||||
* sending keys has to be implemented by sub classes.
|
||||
*/
|
||||
public interface ControlInterface extends View.OnLongClickListener {
|
||||
|
||||
View getControlView();
|
||||
ControlData getProperties();
|
||||
|
||||
/** 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
|
||||
* 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 */
|
||||
void loadEditValues(EditControlPopup editControlPopup);
|
||||
|
||||
|
||||
default ControlLayout getControlLayoutParent(){
|
||||
return (ControlLayout) getControlView().getParent();
|
||||
}
|
||||
|
||||
/** 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);
|
||||
|
||||
//Visibility
|
||||
properties.isHideable = !properties.containsKeycode(ControlData.SPECIALBTN_TOGGLECTRL) && !properties.containsKeycode(ControlData.SPECIALBTN_VIRTUALMOUSE);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
default void updateProperties() {
|
||||
setProperties(getProperties());
|
||||
}
|
||||
|
||||
default void setProperties(ControlData properties) {
|
||||
setProperties(properties, true);
|
||||
}
|
||||
|
||||
/* This function should be overridden to store the properties */
|
||||
@CallSuper
|
||||
default void setProperties(ControlData properties, boolean changePos) {
|
||||
if (changePos) {
|
||||
getControlView().setX(properties.insertDynamicPos(getProperties().dynamicX));
|
||||
getControlView().setY(properties.insertDynamicPos(getProperties().dynamicY));
|
||||
}
|
||||
|
||||
// Recycle layout params
|
||||
ViewGroup.LayoutParams params = getControlView().getLayoutParams();
|
||||
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
|
||||
? (GradientDrawable) getControlView().getBackground()
|
||||
: new GradientDrawable();
|
||||
gd.setColor(getProperties().bgColor);
|
||||
gd.setStroke(computeStrokeWidth(getProperties().strokeWidth), getProperties().strokeColor);
|
||||
gd.setCornerRadius(computeCornerRadius(getProperties().cornerRadius));
|
||||
|
||||
getControlView().setBackground(gd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the dynamic equation on the x axis.
|
||||
* @param dynamicX The equation to compute the position from
|
||||
*/
|
||||
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){
|
||||
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){
|
||||
return (x + getProperties().getWidth()) / CallbackBridge.physicalWidth + " * ${screen_width} - ${width}";
|
||||
}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{
|
||||
return y / CallbackBridge.physicalHeight + " * ${screen_height}";
|
||||
}
|
||||
}
|
||||
|
||||
/** Regenerate and apply coordinates with supposedly modified properties */
|
||||
default void regenerateDynamicCoordinates(){
|
||||
getProperties().dynamicX = generateDynamicX(getControlView().getX());
|
||||
getProperties().dynamicY = generateDynamicY(getControlView().getY());
|
||||
updateProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return The pre-processed equation as a String.
|
||||
*/
|
||||
default String applySize(String equation, ControlInterface button){
|
||||
return equation
|
||||
.replace("${right}", "(${screen_width} - ${width})")
|
||||
.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){
|
||||
float minSize = Math.min(getProperties().getWidth(), getProperties().getHeight());
|
||||
return (minSize/2) * (radiusInPercent/100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Passe a series of checks to determine if the ControlButton is available to be snapped on.
|
||||
*
|
||||
* @param button The button to check
|
||||
* @return whether or not the button
|
||||
*/
|
||||
default boolean canSnap(ControlInterface button){
|
||||
float MIN_DISTANCE = Tools.dpToPx(8);
|
||||
|
||||
if(button == this) return false;
|
||||
if(net.kdt.pojavlaunch.utils.MathUtils.dist(
|
||||
button.getControlView().getX() + button.getControlView().getWidth()/2f,
|
||||
button.getControlView().getY() + button.getControlView().getHeight()/2f,
|
||||
getControlView().getX() + getControlView().getWidth()/2f,
|
||||
getControlView().getY() + getControlView().getHeight()/2f)
|
||||
> Math.max(button.getControlView().getWidth()/2f + getControlView().getWidth()/2f,
|
||||
button.getControlView().getHeight()/2f + getControlView().getHeight()/2f) + MIN_DISTANCE) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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){
|
||||
float MIN_DISTANCE = Tools.dpToPx(8);
|
||||
String dynamicX = generateDynamicX(x);
|
||||
String dynamicY = generateDynamicY(y);
|
||||
|
||||
getControlView().setX(x);
|
||||
getControlView().setY(y);
|
||||
|
||||
for(ControlInterface button : ((ControlLayout) getControlView().getParent()).getButtonChildren()){
|
||||
//Step 1: Filter unwanted buttons
|
||||
if(!canSnap(button)) continue;
|
||||
|
||||
//Step 2: Get Coordinates
|
||||
float button_top = button.getControlView().getY();
|
||||
float button_bottom = button_top + button.getControlView().getHeight();
|
||||
float button_left = button.getControlView().getX();
|
||||
float button_right = button_left + button.getControlView().getWidth();
|
||||
|
||||
float top = getControlView().getY();
|
||||
float bottom = getControlView().getY() + getControlView().getHeight();
|
||||
float left = getControlView().getX();
|
||||
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
|
||||
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
|
||||
dynamicX = applySize(button.getProperties().dynamicX, button);
|
||||
}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
|
||||
dynamicX = applySize(button.getProperties().dynamicX, button) + " - ${width} - ${margin}";
|
||||
}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
|
||||
dynamicY = applySize(button.getProperties().dynamicY, button);
|
||||
}else if(Math.abs(button_bottom - bottom) < MIN_DISTANCE){ //Bottom align snap
|
||||
dynamicY = applySize(button.getProperties().dynamicY, button) + applySize(" + ${height}", button) + " - ${height}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setDynamicX(dynamicX);
|
||||
setDynamicY(dynamicY);
|
||||
}
|
||||
|
||||
/** Inject a touch listener on the view to make editing controls straight forward */
|
||||
default void injectTouchEventBehavior(){
|
||||
getControlView().setOnTouchListener(new View.OnTouchListener() {
|
||||
private boolean mIsPointerOutOfBounds = false;
|
||||
private boolean mCanTriggerLongClick = true;
|
||||
private float downX, downY;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if(!getControlLayoutParent().getModifiable()){
|
||||
// Basically, editing behavior is forced while in game behavior is specific
|
||||
view.onTouchEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If the button can be modified/moved */
|
||||
//Instantiate the gesture detector only when needed
|
||||
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP && mCanTriggerLongClick) {
|
||||
//TODO change this.
|
||||
onLongClick(view);
|
||||
}
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mCanTriggerLongClick = true;
|
||||
downX = event.getRawX() - view.getX();
|
||||
downY = event.getRawY() - view.getY();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mCanTriggerLongClick = false;
|
||||
getControlLayoutParent().adaptPanelPosition();
|
||||
|
||||
if (!getProperties().isDynamicBtn) {
|
||||
snapAndAlign(
|
||||
MathUtils.clamp(event.getRawX() - downX, 0, CallbackBridge.physicalWidth - view.getWidth()),
|
||||
MathUtils.clamp(event.getRawY() - downY, 0, CallbackBridge.physicalHeight - view.getHeight())
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
default void injectLayoutParamBehavior(){
|
||||
getControlView().addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
getProperties().setWidth(right-left);
|
||||
getProperties().setHeight(bottom-top);
|
||||
setBackground();
|
||||
|
||||
// Re-calculate position
|
||||
if(!getProperties().isDynamicBtn){
|
||||
getControlView().setX(getControlView().getX());
|
||||
getControlView().setY(getControlView().getY());
|
||||
}else {
|
||||
getControlView().setX(getProperties().insertDynamicPos(getProperties().dynamicX));
|
||||
getControlView().setY(getProperties().insertDynamicPos(getProperties().dynamicY));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean onLongClick(View v){
|
||||
if (getControlLayoutParent().getModifiable()) {
|
||||
getControlLayoutParent().editControlButton(this);
|
||||
getControlLayoutParent().actionRow.setFollowedButton(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.buttons;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
|
@ -12,6 +11,7 @@ import net.kdt.pojavlaunch.customcontrols.ControlData;
|
|||
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ControlSubButton extends ControlButton {
|
||||
|
||||
public ControlDrawer parentDrawer;
|
||||
|
|
@ -19,9 +19,6 @@ public class ControlSubButton extends ControlButton {
|
|||
public ControlSubButton(ControlLayout layout, ControlData properties, ControlDrawer parentDrawer) {
|
||||
super(layout, properties);
|
||||
this.parentDrawer = parentDrawer;
|
||||
|
||||
|
||||
|
||||
filterProperties();
|
||||
}
|
||||
|
||||
|
|
@ -49,16 +46,40 @@ public class ControlSubButton extends ControlButton {
|
|||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if(!mModifiable || parentDrawer.drawerData.orientation == ControlDrawerData.Orientation.FREE){
|
||||
if(!getControlLayoutParent().getModifiable() || parentDrawer.drawerData.orientation == ControlDrawerData.Orientation.FREE){
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
if(mGestureDetector == null) mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm());
|
||||
|
||||
if (mGestureDetector.onTouchEvent(event)) {
|
||||
mCanTriggerLongClick = true;
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
|
||||
//mCanTriggerLongClick = true;
|
||||
onLongClick(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneButton() {
|
||||
ControlData cloneData = new ControlData(getProperties());
|
||||
cloneData.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) getParent()).addSubButton(parentDrawer, cloneData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeButton() {
|
||||
parentDrawer.drawerData.buttonProperties.remove(getProperties());
|
||||
parentDrawer.drawerData.buttonProperties.remove(getProperties());
|
||||
parentDrawer.buttons.remove(this);
|
||||
|
||||
parentDrawer.syncButtons();
|
||||
|
||||
super.removeButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void snapAndAlign(float x, float y) {
|
||||
if(parentDrawer.drawerData.orientation == ControlDrawerData.Orientation.FREE)
|
||||
super.snapAndAlign(x, y);
|
||||
// Else the button is forced into place
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
/** Interface defining the behavior of action buttons */
|
||||
public interface ActionButtonInterface extends View.OnClickListener {
|
||||
|
||||
/** HAS TO BE CALLED BY THE CONSTRUCTOR */
|
||||
void init();
|
||||
|
||||
/** Called when the button should be made aware of the current target */
|
||||
void setFollowedView(ControlInterface view);
|
||||
|
||||
/** Called when the button action should be executed on the target */
|
||||
void onClick();
|
||||
|
||||
/** Whether the button should be shown, given the current contextual information that it has */
|
||||
boolean shouldBeVisible();
|
||||
|
||||
@Override // Wrapper to remove the arg
|
||||
default void onClick(View v){onClick();}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class has been splited from android/widget/Editor$HandleView.java
|
||||
*/
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.content.*;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.view.*;
|
||||
import android.view.ViewGroup.*;
|
||||
import android.widget.*;
|
||||
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
import android.view.View.OnClickListener;
|
||||
import net.kdt.pojavlaunch.customcontrols.*;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton;
|
||||
|
||||
import androidx.appcompat.app.*;
|
||||
|
||||
public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListener {
|
||||
|
||||
private TextView mEditTextView;
|
||||
private TextView mDeleteTextView;
|
||||
private TextView mCloneTextView;
|
||||
|
||||
private final ControlButton mEditedButton;
|
||||
|
||||
public ActionPopupWindow(HandleView handleView, ControlButton button){
|
||||
super(handleView);
|
||||
this.mEditedButton = button;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createPopupWindow() {
|
||||
mPopupWindow = new PopupWindow(mHandleView.getContext(), null, android.R.attr.textSelectHandleWindowStyle);
|
||||
mPopupWindow.setClippingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initContentView() {
|
||||
LinearLayout linearLayout = new LinearLayout(mHandleView.getContext());
|
||||
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
mContentView = linearLayout;
|
||||
mContentView.setBackgroundResource(R.drawable.control_side_action_window);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) mHandleView.getContext().
|
||||
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
LayoutParams wrapContent = new LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
mEditTextView = (TextView) inflater.inflate(R.layout.control_action_popup_text, null);
|
||||
mEditTextView.setLayoutParams(wrapContent);
|
||||
mContentView.addView(mEditTextView);
|
||||
mEditTextView.setText(R.string.global_edit);
|
||||
mEditTextView.setOnClickListener(this);
|
||||
|
||||
mDeleteTextView = (TextView) inflater.inflate(R.layout.control_action_popup_text, null);
|
||||
mDeleteTextView.setLayoutParams(wrapContent);
|
||||
mContentView.addView(mDeleteTextView);
|
||||
mDeleteTextView.setText(R.string.global_remove);
|
||||
mDeleteTextView.setOnClickListener(this);
|
||||
|
||||
mCloneTextView = (TextView) inflater.inflate(R.layout.control_action_popup_text, null);
|
||||
mCloneTextView.setLayoutParams(wrapContent);
|
||||
mContentView.addView(mCloneTextView);
|
||||
mCloneTextView.setText(R.string.global_clone);
|
||||
mCloneTextView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
super.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
if (view == mEditTextView) {
|
||||
|
||||
if(mEditedButton instanceof ControlSubButton){
|
||||
new EditControlSubButtonPopup((ControlSubButton) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mEditedButton instanceof ControlDrawer){
|
||||
new EditControlDrawerPopup((ControlDrawer) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mEditedButton instanceof ControlButton){
|
||||
new EditControlButtonPopup((ControlButton) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
} else if (view == mDeleteTextView) {
|
||||
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(view.getContext());
|
||||
alertBuilder.setCancelable(false);
|
||||
alertBuilder.setMessage(view.getContext().getString(R.string.customctrl_remove, mHandleView.mView.getText()) + "?");
|
||||
|
||||
alertBuilder.setPositiveButton(R.string.global_remove, (p1, p2) -> {
|
||||
ControlLayout layout = ((ControlLayout) mHandleView.mView.getParent());
|
||||
|
||||
if(mEditedButton instanceof ControlSubButton){
|
||||
layout.removeControlSubButton((ControlSubButton) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mEditedButton instanceof ControlDrawer){
|
||||
layout.removeControlDrawer((ControlDrawer) mEditedButton);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mEditedButton instanceof ControlButton){
|
||||
layout.removeControlButton((ControlButton) mEditedButton);
|
||||
}
|
||||
|
||||
layout.removeControlButton(mHandleView.mView);
|
||||
});
|
||||
alertBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
alertBuilder.show();
|
||||
}else if(view == mCloneTextView) {
|
||||
if(mEditedButton instanceof ControlDrawer){
|
||||
ControlDrawerData cloneData = new ControlDrawerData(((ControlDrawer) mEditedButton).getDrawerData());
|
||||
cloneData.properties.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.properties.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) mHandleView.mView.getParent()).addDrawer(cloneData);
|
||||
}else if(mEditedButton instanceof ControlSubButton){
|
||||
ControlData cloneData = new ControlData(mEditedButton.getProperties());
|
||||
cloneData.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) mHandleView.mView.getParent()).addSubButton(((ControlSubButton) mEditedButton).parentDrawer, cloneData);
|
||||
}else{
|
||||
ControlData cloneData = new ControlData(mEditedButton.getProperties());
|
||||
cloneData.dynamicX = "0.5 * ${screen_width}";
|
||||
cloneData.dynamicY = "0.5 * ${screen_height}";
|
||||
((ControlLayout) mHandleView.mView.getParent()).addControlButton(cloneData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTextOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVerticalLocalPosition(int line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int clipVertically(int positionY) {
|
||||
return positionY;
|
||||
}
|
||||
|
||||
public static void setPercentageText(TextView textView, int progress){
|
||||
textView.setText(progress + " %");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.math.MathUtils;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
/**
|
||||
* Layout floating around a Control Button, displaying contextual actions
|
||||
*/
|
||||
public class ActionRow extends LinearLayout {
|
||||
|
||||
public static int SIDE_LEFT = 0x0;
|
||||
public static int SIDE_TOP = 0x1;
|
||||
public static int SIDE_RIGHT = 0x2;
|
||||
public static int SIDE_BOTTOM = 0x3;
|
||||
public static int SIDE_AUTO = 0x4;
|
||||
|
||||
public ActionRow(Context context) {
|
||||
super(context); init();
|
||||
}
|
||||
public ActionRow(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs); init();
|
||||
}
|
||||
|
||||
public final ViewTreeObserver.OnPreDrawListener mFollowedViewListener = new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
if(mFollowedView == null || !mFollowedView.isShown()){
|
||||
hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
setNewPosition();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private final ActionButtonInterface[] actionButtons = new ActionButtonInterface[3];
|
||||
private View mFollowedView = null;
|
||||
private int mSide = SIDE_TOP;
|
||||
|
||||
/** Add action buttons and configure them */
|
||||
private void init(){
|
||||
setVisibility(GONE);
|
||||
setOrientation(HORIZONTAL);
|
||||
setLayoutParams(new LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
getResources().getDimensionPixelOffset(R.dimen._40sdp)
|
||||
));
|
||||
|
||||
actionButtons[0] = new DeleteButton(getContext());
|
||||
actionButtons[1] = new CloneButton(getContext());
|
||||
actionButtons[2] = new AddSubButton(getContext());
|
||||
|
||||
// This is not pretty code, don't do this.
|
||||
for(ActionButtonInterface buttonInterface: actionButtons){
|
||||
View button = ((View)(buttonInterface));
|
||||
addView(button, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1F));
|
||||
}
|
||||
|
||||
setElevation(5F);
|
||||
}
|
||||
|
||||
public void setFollowedButton(ControlInterface controlInterface){
|
||||
if(mFollowedView != null)
|
||||
mFollowedView.getViewTreeObserver().removeOnPreDrawListener(mFollowedViewListener);
|
||||
|
||||
for(ActionButtonInterface buttonInterface: actionButtons){
|
||||
buttonInterface.setFollowedView(controlInterface);
|
||||
((View)(buttonInterface)).setVisibility(buttonInterface.shouldBeVisible() ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
setVisibility(VISIBLE);
|
||||
mFollowedView = (View) controlInterface;
|
||||
if(mFollowedView != null)
|
||||
mFollowedView.getViewTreeObserver().addOnPreDrawListener(mFollowedViewListener);
|
||||
}
|
||||
|
||||
private float getXPosition(int side){
|
||||
if(side == SIDE_LEFT){
|
||||
return mFollowedView.getX() - getWidth();
|
||||
}else if(side == SIDE_RIGHT){
|
||||
return mFollowedView.getX() + mFollowedView.getWidth();
|
||||
}else{
|
||||
return mFollowedView.getX() + mFollowedView.getWidth()/2f - getWidth()/2f;
|
||||
}
|
||||
}
|
||||
|
||||
private float getYPosition(int side){
|
||||
if(side == SIDE_TOP){
|
||||
return mFollowedView.getY() - getHeight();
|
||||
} else if(side == SIDE_BOTTOM){
|
||||
return mFollowedView.getY() + mFollowedView.getHeight();
|
||||
}else{
|
||||
return mFollowedView.getY() + mFollowedView.getHeight()/2f - getHeight()/2f;
|
||||
}
|
||||
}
|
||||
|
||||
private void setNewPosition(){
|
||||
if(mFollowedView == null) return;
|
||||
int side = pickSide();
|
||||
|
||||
setX(MathUtils.clamp(getXPosition(side), 0, currentDisplayMetrics.widthPixels - getWidth()));
|
||||
setY(getYPosition(side));
|
||||
}
|
||||
|
||||
private int pickSide(){
|
||||
if(mFollowedView == null) return mSide; //Value should not matter
|
||||
|
||||
if(mSide != SIDE_AUTO) return mSide;
|
||||
//TODO improve the "algo"
|
||||
ViewGroup parent = ((ViewGroup) mFollowedView.getParent());
|
||||
if(parent == null) return mSide;//Value should not matter
|
||||
|
||||
int side = mFollowedView.getX() + getWidth()/2f > parent.getWidth()/2f
|
||||
? SIDE_LEFT
|
||||
: SIDE_RIGHT;
|
||||
|
||||
float futurePos = getYPosition(side);
|
||||
if(futurePos + getHeight() > (parent.getHeight() + getHeight()/2)){
|
||||
side = SIDE_TOP;
|
||||
}else if (futurePos < -getHeight()/2){
|
||||
side = SIDE_BOTTOM;
|
||||
}
|
||||
|
||||
return side;
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
if(mFollowedView != null)
|
||||
mFollowedView.getViewTreeObserver().removeOnPreDrawListener(mFollowedViewListener);
|
||||
setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class AddSubButton extends Button implements ActionButtonInterface {
|
||||
public AddSubButton(Context context) {super(context); init();}
|
||||
public AddSubButton(Context context, @Nullable AttributeSet attrs) {super(context, attrs); init();}
|
||||
|
||||
public void init() {
|
||||
setText("Add Button");
|
||||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
private ControlInterface mCurrentlySelectedButton = null;
|
||||
|
||||
@Override
|
||||
public boolean shouldBeVisible() {
|
||||
return mCurrentlySelectedButton != null && mCurrentlySelectedButton instanceof ControlDrawer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFollowedView(ControlInterface view) {
|
||||
mCurrentlySelectedButton = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
if(mCurrentlySelectedButton instanceof ControlDrawer){
|
||||
((ControlDrawer)mCurrentlySelectedButton).getControlLayoutParent().addSubButton(
|
||||
(ControlDrawer)mCurrentlySelectedButton,
|
||||
new ControlData()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class CloneButton extends Button implements ActionButtonInterface {
|
||||
public CloneButton(Context context) {super(context); init();}
|
||||
public CloneButton(Context context, @Nullable AttributeSet attrs) {super(context, attrs); init();}
|
||||
|
||||
public void init() {
|
||||
setOnClickListener(this);
|
||||
setText("CLONE");
|
||||
}
|
||||
|
||||
private ControlInterface mCurrentlySelectedButton = null;
|
||||
|
||||
@Override
|
||||
public boolean shouldBeVisible() {
|
||||
return mCurrentlySelectedButton != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFollowedView(ControlInterface view) {
|
||||
mCurrentlySelectedButton = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
if(mCurrentlySelectedButton == null) return;
|
||||
|
||||
mCurrentlySelectedButton.cloneButton();
|
||||
mCurrentlySelectedButton.getControlLayoutParent().removeEditWindow();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DragEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
public class ControlHandleView extends View {
|
||||
public ControlHandleView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ControlHandleView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private final Drawable mDrawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_view_handle, getContext().getTheme());
|
||||
private ControlInterface mView;
|
||||
private float mXOffset, mYOffset;
|
||||
private final ViewTreeObserver.OnPreDrawListener mPositionListener = new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
if(mView == null || !mView.getControlView().isShown()){
|
||||
hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
setX(mView.getControlView().getX() + mView.getControlView().getWidth());
|
||||
setY(mView.getControlView().getY() + mView.getControlView().getHeight());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private void init(){
|
||||
int size = getResources().getDimensionPixelOffset(R.dimen._22sdp);
|
||||
mDrawable.setBounds(0,0,size,size);
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(size, size);
|
||||
setLayoutParams(params);
|
||||
setBackground(mDrawable);
|
||||
setElevation(3);
|
||||
}
|
||||
|
||||
public void setControlButton(ControlInterface controlInterface){
|
||||
if(mView != null) mView.getControlView().getViewTreeObserver().removeOnPreDrawListener(mPositionListener);
|
||||
|
||||
setVisibility(VISIBLE);
|
||||
mView = controlInterface;
|
||||
mView.getControlView().getViewTreeObserver().addOnPreDrawListener(mPositionListener);
|
||||
|
||||
setX(controlInterface.getControlView().getX() + controlInterface.getControlView().getWidth());
|
||||
setY(controlInterface.getControlView().getY() + controlInterface.getControlView().getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getActionMasked()){
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mXOffset = event.getX();
|
||||
mYOffset = event.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
setX(getX() + event.getX() - mXOffset);
|
||||
setY(getY() + event.getY() - mYOffset);
|
||||
|
||||
System.out.println(getX() - mView.getControlView().getX());
|
||||
System.out.println(getY() - mView.getControlView().getY());
|
||||
|
||||
|
||||
mView.getProperties().setWidth(getX() - mView.getControlView().getX());
|
||||
mView.getProperties().setHeight(getY() - mView.getControlView().getY());
|
||||
mView.regenerateDynamicCoordinates();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
if(mView != null)
|
||||
mView.getControlView().getViewTreeObserver().removeOnPreDrawListener(mPositionListener);
|
||||
setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
@SuppressLint("AppCompatCustomView")
|
||||
public class DeleteButton extends Button implements ActionButtonInterface {
|
||||
public DeleteButton(Context context) {super(context); init();}
|
||||
public DeleteButton(Context context, @Nullable AttributeSet attrs) {super(context, attrs); init();}
|
||||
|
||||
public void init() {
|
||||
setOnClickListener(this);
|
||||
setText("DELETE");
|
||||
|
||||
}
|
||||
|
||||
private ControlInterface mCurrentlySelectedButton = null;
|
||||
|
||||
@Override
|
||||
public boolean shouldBeVisible() {
|
||||
return mCurrentlySelectedButton != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFollowedView(ControlInterface view) {
|
||||
mCurrentlySelectedButton = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
if(mCurrentlySelectedButton == null) return;
|
||||
|
||||
mCurrentlySelectedButton.removeButton();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
|
||||
public class DrawerPullButton extends View {
|
||||
public DrawerPullButton(Context context) {super(context); init();}
|
||||
public DrawerPullButton(Context context, @Nullable AttributeSet attrs) {super(context, attrs); init();}
|
||||
|
||||
private final Paint mPaint = new Paint();
|
||||
private VectorDrawableCompat mDrawable;
|
||||
|
||||
private void init(){
|
||||
mDrawable = VectorDrawableCompat.create(getContext().getResources(), R.drawable.ic_sharp_settings_24, null);
|
||||
setAlpha(0.33f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mPaint.setColor(Color.BLACK);
|
||||
canvas.drawArc(0,-getHeight(),getWidth(), getHeight(), 0, 180, true, mPaint);
|
||||
|
||||
mPaint.setColor(Color.WHITE);
|
||||
mDrawable.setBounds(0, 0, canvas.getHeight(), canvas.getHeight());
|
||||
canvas.save();
|
||||
canvas.translate((canvas.getWidth()-canvas.getHeight())/2, 0);
|
||||
mDrawable.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,340 +0,0 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import net.kdt.pojavlaunch.EfficientAndroidLWJGLKeycode;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.colorselector.ColorSelector;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
|
||||
import top.defaults.checkerboarddrawable.CheckerboardDrawable;
|
||||
|
||||
import static net.kdt.pojavlaunch.customcontrols.handleview.ActionPopupWindow.setPercentageText;
|
||||
|
||||
public class EditControlButtonPopup {
|
||||
|
||||
protected AlertDialog mDialog;
|
||||
protected View mRootView;
|
||||
protected AlertDialog.Builder mBuilder;
|
||||
|
||||
protected EditText mNameEditText;
|
||||
protected Spinner[] mKeycodeSpinners;
|
||||
|
||||
protected CheckBox mToggleCheckbox;
|
||||
protected CheckBox mPassthroughCheckbox;
|
||||
protected CheckBox mSwipeableCheckbox;
|
||||
protected CheckBox mDynamicPositionCheckbox;
|
||||
|
||||
protected EditText mWidthEditText;
|
||||
protected EditText mHeightEditText;
|
||||
protected EditText mDynamicXEditText;
|
||||
protected EditText mDynamicYEditText;
|
||||
|
||||
protected SeekBar mOpacitySeekbar;
|
||||
protected SeekBar mCornerRadiusSeekbar;
|
||||
protected SeekBar mStrokeWidthSeekbar;
|
||||
|
||||
protected ImageButton mBackgroundColorButton;
|
||||
protected ImageButton mStrokeColorButton;
|
||||
|
||||
protected TextView mOpacityTextView;
|
||||
protected TextView mCornerRadiusTextView;
|
||||
protected TextView mStrokeWidthTextView;
|
||||
protected TextView mStrokeColorTextView;
|
||||
|
||||
protected ColorSelector mColorSelector;
|
||||
protected ImageView mEditingView;
|
||||
|
||||
protected final ControlButton mControlButton;
|
||||
protected final ControlData mProperties;
|
||||
|
||||
protected ArrayAdapter<String> mAdapter;
|
||||
protected String[] mSpecialArray;
|
||||
|
||||
|
||||
public EditControlButtonPopup(ControlButton button){
|
||||
this.mControlButton = button;
|
||||
this.mProperties = button.getProperties();
|
||||
|
||||
initializeEditDialog(button.getContext());
|
||||
|
||||
//Create the finalized dialog
|
||||
mDialog = mBuilder.create();
|
||||
mDialog.setOnShowListener(dialogInterface -> setEditDialogValues());
|
||||
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
protected void initializeEditDialog(Context ctx){
|
||||
//Create the editing dialog
|
||||
LayoutInflater layoutInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mRootView = layoutInflater.inflate(R.layout.dialog_control_button_setting,null);
|
||||
|
||||
mBuilder = new AlertDialog.Builder(ctx);
|
||||
mBuilder.setTitle(ctx.getResources().getString(R.string.customctrl_edit, mProperties.name));
|
||||
mBuilder.setView(mRootView);
|
||||
|
||||
//Linking a lot of stuff
|
||||
mNameEditText = mRootView.findViewById(R.id.editName_editText);
|
||||
|
||||
mKeycodeSpinners = new Spinner[]{
|
||||
mRootView.findViewById(R.id.editMapping_spinner_1),
|
||||
mRootView.findViewById(R.id.editMapping_spinner_2),
|
||||
mRootView.findViewById(R.id.editMapping_spinner_3),
|
||||
mRootView.findViewById(R.id.editMapping_spinner_4)
|
||||
};
|
||||
|
||||
mToggleCheckbox = mRootView.findViewById(R.id.checkboxToggle);
|
||||
mPassthroughCheckbox = mRootView.findViewById(R.id.checkboxPassThrough);
|
||||
mSwipeableCheckbox = mRootView.findViewById(R.id.checkboxSwipeable);
|
||||
|
||||
mWidthEditText = mRootView.findViewById(R.id.editSize_editTextX);
|
||||
mHeightEditText = mRootView.findViewById(R.id.editSize_editTextY);
|
||||
|
||||
mDynamicXEditText = mRootView.findViewById(R.id.editDynamicPositionX_editText);
|
||||
mDynamicYEditText = mRootView.findViewById(R.id.editDynamicPositionY_editText);
|
||||
|
||||
mOpacitySeekbar = mRootView.findViewById(R.id.editButtonOpacity_seekbar);
|
||||
mCornerRadiusSeekbar = mRootView.findViewById(R.id.editCornerRadius_seekbar);
|
||||
mStrokeWidthSeekbar = mRootView.findViewById(R.id.editStrokeWidth_seekbar);
|
||||
|
||||
SeekBar.OnSeekBarChangeListener changeListener = new SeekBar.OnSeekBarChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
|
||||
if(seekBar.equals(mCornerRadiusSeekbar)) {
|
||||
setPercentageText(mCornerRadiusTextView, i);
|
||||
return;
|
||||
}
|
||||
if(seekBar.equals(mOpacitySeekbar)) {
|
||||
setPercentageText(mOpacityTextView, i);
|
||||
return;
|
||||
}
|
||||
if(seekBar.equals(mStrokeWidthSeekbar)) {
|
||||
setPercentageText(mStrokeWidthTextView, i);
|
||||
mStrokeColorTextView.setVisibility(i == 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {/*STUB*/}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {/*STUB*/}
|
||||
};
|
||||
|
||||
//Add listeners, too bad I don't need all the methods
|
||||
mOpacitySeekbar.setOnSeekBarChangeListener(changeListener);
|
||||
mCornerRadiusSeekbar.setOnSeekBarChangeListener(changeListener);
|
||||
mStrokeWidthSeekbar.setOnSeekBarChangeListener(changeListener);
|
||||
|
||||
mBackgroundColorButton = mRootView.findViewById(R.id.editBackgroundColor_imageButton);
|
||||
mStrokeColorButton = mRootView.findViewById(R.id.editStrokeColor_imageButton);
|
||||
|
||||
mOpacityTextView = mRootView.findViewById(R.id.editButtonOpacity_textView_percent);
|
||||
mCornerRadiusTextView = mRootView.findViewById(R.id.editCornerRadius_textView_percent);
|
||||
mStrokeWidthTextView = mRootView.findViewById(R.id.editStrokeWidth_textView_percent);
|
||||
mStrokeColorTextView = mRootView.findViewById(R.id.editStrokeColor_textView);
|
||||
|
||||
mDynamicPositionCheckbox = mRootView.findViewById(R.id.checkboxDynamicPosition);
|
||||
mDynamicPositionCheckbox.setOnCheckedChangeListener((btn, checked) -> {
|
||||
mDynamicXEditText.setEnabled(checked);
|
||||
mDynamicYEditText.setEnabled(checked);
|
||||
});
|
||||
|
||||
|
||||
//Initialize adapter for keycodes
|
||||
mAdapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item);
|
||||
String[] oldSpecialArr = ControlData.buildSpecialButtonArray();
|
||||
mSpecialArray = new String[oldSpecialArr.length];
|
||||
for (int i = 0; i < mSpecialArray.length; i++) {
|
||||
mSpecialArray[i] = "SPECIAL_" + oldSpecialArr[mSpecialArray.length - i - 1];
|
||||
}
|
||||
mAdapter.addAll(mSpecialArray);
|
||||
mAdapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName());
|
||||
mAdapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
|
||||
|
||||
for (Spinner spinner : mKeycodeSpinners) {
|
||||
spinner.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
mColorSelector = new ColorSelector(ctx,color -> mEditingView.setImageDrawable(new ColorDrawable(color)));
|
||||
|
||||
//Set color imageButton behavior
|
||||
mBackgroundColorButton.setOnClickListener(view -> showColorEditor((ImageView) view));
|
||||
mStrokeColorButton.setOnClickListener(view -> showColorEditor((ImageView) view));
|
||||
|
||||
|
||||
//Set dialog buttons behavior
|
||||
setupDialogButtons();
|
||||
|
||||
hideUselessViews();
|
||||
|
||||
defineDynamicCheckChange();
|
||||
|
||||
setupCheckerboards();
|
||||
}
|
||||
|
||||
protected void showColorEditor(ImageView imgView) {
|
||||
mEditingView = imgView;
|
||||
mColorSelector.show(((ColorDrawable)(imgView.getDrawable())).getColor());
|
||||
}
|
||||
|
||||
protected void setupDialogButtons(){
|
||||
//Set dialog buttons behavior
|
||||
mBuilder.setPositiveButton(android.R.string.ok, (dialogInterface1, i) -> {
|
||||
if(!hasPropertiesErrors(mDialog.getContext())){
|
||||
saveProperties();
|
||||
}
|
||||
});
|
||||
mBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
}
|
||||
|
||||
protected void hideUselessViews(){
|
||||
(mRootView.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
|
||||
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
mDynamicXEditText.setVisibility(View.GONE);
|
||||
mDynamicYEditText.setVisibility(View.GONE);
|
||||
|
||||
//Hide the color choice if the width is 0.
|
||||
mStrokeColorTextView.setVisibility(mProperties.strokeWidth == 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
protected void defineDynamicCheckChange(){
|
||||
mDynamicPositionCheckbox.setOnCheckedChangeListener((compoundButton, b) -> {
|
||||
int visibility = b ? View.VISIBLE : View.GONE;
|
||||
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(visibility);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(visibility);
|
||||
mDynamicXEditText.setVisibility(visibility);
|
||||
mDynamicYEditText.setVisibility(visibility);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void setupCheckerboards(){
|
||||
CheckerboardDrawable drawable = new CheckerboardDrawable.Builder()
|
||||
.colorEven(Color.LTGRAY)
|
||||
.colorOdd(Color.WHITE)
|
||||
.size((int) Tools.dpToPx(20))
|
||||
.build();
|
||||
|
||||
mBackgroundColorButton.setBackground(drawable);
|
||||
mStrokeColorButton.setBackground(drawable);
|
||||
}
|
||||
|
||||
protected void setEditDialogValues(){
|
||||
|
||||
mNameEditText.setText(mProperties.name);
|
||||
|
||||
mToggleCheckbox.setChecked(mProperties.isToggle);
|
||||
mPassthroughCheckbox.setChecked(mProperties.passThruEnabled);
|
||||
mSwipeableCheckbox.setChecked(mProperties.isSwipeable);
|
||||
|
||||
mWidthEditText.setText(Float.toString(mProperties.getWidth()));
|
||||
mHeightEditText.setText(Float.toString(mProperties.getHeight()));
|
||||
|
||||
mDynamicXEditText.setEnabled(mProperties.isDynamicBtn);
|
||||
mDynamicYEditText.setEnabled(mProperties.isDynamicBtn);
|
||||
mDynamicXEditText.setText(mProperties.dynamicX);
|
||||
|
||||
mDynamicYEditText.setText(mProperties.dynamicY);
|
||||
|
||||
mOpacitySeekbar.setProgress((int) (mProperties.opacity*100));
|
||||
mStrokeWidthSeekbar.setProgress(mProperties.strokeWidth);
|
||||
mCornerRadiusSeekbar.setProgress((int) mProperties.cornerRadius);
|
||||
|
||||
mBackgroundColorButton.setImageDrawable(new ColorDrawable(mProperties.bgColor));
|
||||
mStrokeColorButton.setImageDrawable(new ColorDrawable(mProperties.strokeColor));
|
||||
|
||||
setPercentageText(mCornerRadiusTextView, mCornerRadiusSeekbar.getProgress());
|
||||
setPercentageText(mOpacityTextView, mOpacitySeekbar.getProgress());
|
||||
setPercentageText(mStrokeWidthTextView, mStrokeWidthSeekbar.getProgress());
|
||||
|
||||
mDynamicPositionCheckbox.setChecked(mProperties.isDynamicBtn);
|
||||
|
||||
for(int i = 0; i< mProperties.keycodes.length; i++){
|
||||
if (mProperties.keycodes[i] < 0) {
|
||||
mKeycodeSpinners[i].setSelection(mProperties.keycodes[i] + mSpecialArray.length);
|
||||
} else {
|
||||
mKeycodeSpinners[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(mProperties.keycodes[i]) + mSpecialArray.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean hasPropertiesErrors(Context ctx){
|
||||
if (mNameEditText.getText().toString().isEmpty()) {
|
||||
mNameEditText.setError(ctx.getResources().getString(R.string.global_error_field_empty));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mProperties.isDynamicBtn) {
|
||||
|
||||
int errorAt = 0;
|
||||
try {
|
||||
mProperties.insertDynamicPos(mDynamicXEditText.getText().toString());
|
||||
errorAt = 1;
|
||||
mProperties.insertDynamicPos(mDynamicYEditText.getText().toString());
|
||||
} catch (Throwable th) {
|
||||
(errorAt == 0 ? mDynamicXEditText : mDynamicYEditText).setError(th.getMessage());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void saveProperties(){
|
||||
//This method assumes there are no error.
|
||||
mProperties.name = mNameEditText.getText().toString();
|
||||
|
||||
//Keycodes
|
||||
for(int i = 0; i< mKeycodeSpinners.length; ++i){
|
||||
if (mKeycodeSpinners[i].getSelectedItemPosition() < mSpecialArray.length) {
|
||||
mProperties.keycodes[i] = mKeycodeSpinners[i].getSelectedItemPosition() - mSpecialArray.length;
|
||||
} else {
|
||||
mProperties.keycodes[i] = EfficientAndroidLWJGLKeycode.getValueByIndex(mKeycodeSpinners[i].getSelectedItemPosition() - mSpecialArray.length);
|
||||
}
|
||||
}
|
||||
|
||||
mProperties.opacity = mOpacitySeekbar.getProgress()/100f;
|
||||
mProperties.strokeWidth = mStrokeWidthSeekbar.getProgress();
|
||||
mProperties.cornerRadius = mCornerRadiusSeekbar.getProgress();
|
||||
|
||||
mProperties.bgColor = ((ColorDrawable) mBackgroundColorButton.getDrawable()).getColor();
|
||||
mProperties.strokeColor = ((ColorDrawable) mStrokeColorButton.getDrawable()).getColor();
|
||||
|
||||
mProperties.isToggle = mToggleCheckbox.isChecked();
|
||||
mProperties.passThruEnabled = mPassthroughCheckbox.isChecked();
|
||||
mProperties.isSwipeable = mSwipeableCheckbox.isChecked();
|
||||
|
||||
mProperties.setWidth(Float.parseFloat(mWidthEditText.getText().toString()));
|
||||
mProperties.setHeight(Float.parseFloat(mHeightEditText.getText().toString()));
|
||||
|
||||
mProperties.isDynamicBtn = mDynamicPositionCheckbox.isChecked();
|
||||
if(!mDynamicXEditText.getText().toString().isEmpty()) mProperties.dynamicX = mDynamicXEditText.getText().toString();
|
||||
if(!mDynamicYEditText.getText().toString().isEmpty()) mProperties.dynamicY = mDynamicYEditText.getText().toString();
|
||||
|
||||
mControlButton.updateProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
|
||||
|
||||
public class EditControlDrawerPopup extends EditControlButtonPopup{
|
||||
private Spinner mOrientationSpinner;
|
||||
|
||||
|
||||
private final ControlDrawer mDrawer;
|
||||
private final ControlDrawerData mDrawerData;
|
||||
|
||||
public EditControlDrawerPopup(ControlDrawer editedButton) {
|
||||
super(editedButton);
|
||||
mDrawer = editedButton;
|
||||
mDrawerData = editedButton.getDrawerData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void hideUselessViews() {
|
||||
(mRootView.findViewById(R.id.editMapping_textView)).setVisibility(View.GONE);
|
||||
mPassthroughCheckbox.setVisibility(View.GONE);
|
||||
mToggleCheckbox.setVisibility(View.GONE);
|
||||
mSwipeableCheckbox.setVisibility(View.GONE);
|
||||
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
mDynamicXEditText.setVisibility(View.GONE);
|
||||
mDynamicYEditText.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeEditDialog(Context ctx) {
|
||||
super.initializeEditDialog(ctx);
|
||||
|
||||
mOrientationSpinner = mRootView.findViewById(R.id.editOrientation_spinner);
|
||||
|
||||
ArrayAdapter<ControlDrawerData.Orientation> adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item);
|
||||
adapter.addAll(ControlDrawerData.getOrientations());
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
|
||||
|
||||
mOrientationSpinner.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEditDialogValues() {
|
||||
super.setEditDialogValues();
|
||||
|
||||
mOrientationSpinner.setSelection(ControlDrawerData.orientationToInt(mDrawerData.orientation));
|
||||
|
||||
|
||||
//Using the dialog to replace the button behavior allows us not to dismiss the window
|
||||
mDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(v -> {
|
||||
ControlLayout layout = (ControlLayout) mDrawer.getParent();
|
||||
ControlData controlData = new ControlData(mDrawerData.properties);
|
||||
controlData.name = "new";
|
||||
layout.addSubButton(mDrawer, controlData);
|
||||
|
||||
Context ctx = mDialog.getContext();
|
||||
Toast.makeText(ctx, ctx.getString(R.string.customctrl_add_subbutton_message,
|
||||
mDrawer.getDrawerData().buttonProperties.size()), Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupDialogButtons() {
|
||||
super.setupDialogButtons();
|
||||
|
||||
mBuilder.setNeutralButton(mRootView.getResources().getString(R.string.customctrl_addsubbutton), null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveProperties() {
|
||||
mDrawerData.orientation = ControlDrawerData.intToOrientation(mOrientationSpinner.getSelectedItemPosition());
|
||||
super.saveProperties();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,540 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.kdt.DefocusableScrollView;
|
||||
|
||||
import net.kdt.pojavlaunch.EfficientAndroidLWJGLKeycode;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.colorselector.ColorSelectionListener;
|
||||
import net.kdt.pojavlaunch.colorselector.ColorSelector;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlData;
|
||||
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Class providing a sort of popup on top of a Layout, allowing to edit a given ControlButton
|
||||
*/
|
||||
public class EditControlPopup {
|
||||
private final DefocusableScrollView mScrollView;
|
||||
private ConstraintLayout mRootView;
|
||||
private final ColorSelector mColorSelector;
|
||||
|
||||
private final ObjectAnimator mEditPopupAnimator;
|
||||
private final ObjectAnimator mColorEditorAnimator;
|
||||
private boolean mDisplaying = false;
|
||||
private boolean mDisplayingColor = false;
|
||||
public boolean internalChanges = false; // True when we programmatically change stuff.
|
||||
private ControlInterface mCurrentlyEditedButton;
|
||||
private final int mMargin;
|
||||
private final View.OnLayoutChangeListener mLayoutChangedListener = new View.OnLayoutChangeListener() {
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
if(internalChanges) return;
|
||||
|
||||
internalChanges = true;
|
||||
if(right != (int)safeParseFloat(mWidthEditText.getText().toString())){
|
||||
mWidthEditText.setText(String.valueOf(right - left));
|
||||
}
|
||||
if(bottom != (int) safeParseFloat(mHeightEditText.getText().toString())){
|
||||
mHeightEditText.setText(String.valueOf(bottom - top));
|
||||
}
|
||||
|
||||
internalChanges = false;
|
||||
}
|
||||
};
|
||||
|
||||
protected EditText mNameEditText, mWidthEditText, mHeightEditText;
|
||||
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
||||
protected Switch mToggleSwitch, mPassthroughSwitch, mSwipeableSwitch;
|
||||
protected Spinner mOrientationSpinner;
|
||||
protected Spinner[] mKeycodeSpinners = new Spinner[4];
|
||||
protected SeekBar mStrokeWidthSeekbar, mCornerRadiusSeekbar, mAlphaSeekbar;
|
||||
protected TextView mStrokePercentTextView, mCornerRadiusPercentTextView, mAlphaPercentTextView;
|
||||
protected TextView mSelectBackgroundColor, mSelectStrokeColor;
|
||||
protected ArrayAdapter<String> mAdapter;
|
||||
protected String[] mSpecialArray;
|
||||
|
||||
// Decorative textviews
|
||||
private TextView mOrientationTextView, mMappingTextView, mNameTextView, mCornerRadiusTextView;
|
||||
|
||||
|
||||
|
||||
public EditControlPopup(Context context, ViewGroup parent){
|
||||
mScrollView = (DefocusableScrollView) LayoutInflater.from(context).inflate(R.layout.dialog_control_button_setting, parent, false);
|
||||
parent.addView(mScrollView);
|
||||
|
||||
mMargin = context.getResources().getDimensionPixelOffset(R.dimen._20sdp);
|
||||
|
||||
mColorSelector = new ColorSelector(context, parent, null);
|
||||
mColorSelector.getRootView().setElevation(11);
|
||||
mColorSelector.getRootView().setX(-context.getResources().getDimensionPixelOffset(R.dimen._230sdp));
|
||||
|
||||
mEditPopupAnimator = ObjectAnimator.ofFloat(mScrollView, "x", 0).setDuration(1000);
|
||||
mColorEditorAnimator = ObjectAnimator.ofFloat(mColorSelector.getRootView(), "x", 0).setDuration(1000);
|
||||
Interpolator decelerate = new AccelerateDecelerateInterpolator();
|
||||
mEditPopupAnimator.setInterpolator(decelerate);
|
||||
mColorEditorAnimator.setInterpolator(decelerate);
|
||||
|
||||
mScrollView.setElevation(10);
|
||||
mScrollView.setX(-context.getResources().getDimensionPixelOffset(R.dimen._230sdp));
|
||||
|
||||
bindLayout();
|
||||
loadAdapter();
|
||||
|
||||
setupRealTimeListeners();
|
||||
}
|
||||
|
||||
|
||||
/** Slide the layout into the visible screen area */
|
||||
public void appear(boolean fromRight){
|
||||
disappearColor(); // When someone jumps from a button to another
|
||||
|
||||
if(fromRight){
|
||||
if(!mDisplaying || !isAtRight()){
|
||||
mEditPopupAnimator.setFloatValues(currentDisplayMetrics.widthPixels, currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin);
|
||||
mEditPopupAnimator.start();
|
||||
}
|
||||
}else{
|
||||
if (!mDisplaying || isAtRight()){
|
||||
mEditPopupAnimator.setFloatValues(-mScrollView.getWidth(), mMargin);
|
||||
mEditPopupAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
mDisplaying = true;
|
||||
}
|
||||
|
||||
/** Slide out the layout */
|
||||
public void disappear(){
|
||||
if(!mDisplaying) return;
|
||||
|
||||
mDisplaying = false;
|
||||
if(isAtRight())
|
||||
mEditPopupAnimator.setFloatValues(currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin, currentDisplayMetrics.widthPixels);
|
||||
else
|
||||
mEditPopupAnimator.setFloatValues(mMargin, -mScrollView.getWidth());
|
||||
|
||||
mEditPopupAnimator.start();
|
||||
}
|
||||
|
||||
/** Slide the layout into the visible screen area */
|
||||
public void appearColor(boolean fromRight, int color){
|
||||
if(fromRight){
|
||||
if(!mDisplayingColor || !isAtRight()){
|
||||
mColorEditorAnimator.setFloatValues(currentDisplayMetrics.widthPixels, currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin);
|
||||
mColorEditorAnimator.start();
|
||||
}
|
||||
}else{
|
||||
if (!mDisplayingColor || isAtRight()){
|
||||
mColorEditorAnimator.setFloatValues(-mScrollView.getWidth(), mMargin);
|
||||
mColorEditorAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
mDisplayingColor = true;
|
||||
if(color != -1)
|
||||
mColorSelector.show(color);
|
||||
}
|
||||
|
||||
/** Slide out the layout */
|
||||
public void disappearColor(){
|
||||
if(!mDisplayingColor) return;
|
||||
|
||||
mDisplayingColor = false;
|
||||
if(isAtRight())
|
||||
mColorEditorAnimator.setFloatValues(currentDisplayMetrics.widthPixels - mScrollView.getWidth() - mMargin, currentDisplayMetrics.widthPixels);
|
||||
else
|
||||
mColorEditorAnimator.setFloatValues(mMargin, -mScrollView.getWidth());
|
||||
|
||||
mColorEditorAnimator.start();
|
||||
}
|
||||
|
||||
/** Slide out the first visible layer.
|
||||
* @return True if the last layer is disappearing */
|
||||
public boolean disappearLayer(){
|
||||
if(mDisplayingColor){
|
||||
disappearColor();
|
||||
return false;
|
||||
}else{
|
||||
disappear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Switch the panels position if needed */
|
||||
public void adaptPanelPosition(){
|
||||
if(mDisplaying){
|
||||
boolean isAtRight = mCurrentlyEditedButton.getControlView().getX() + mCurrentlyEditedButton.getControlView().getWidth()/2f < currentDisplayMetrics.widthPixels/2f;
|
||||
appear(isAtRight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void destroy(){
|
||||
((ViewGroup) mScrollView.getParent()).removeView(mColorSelector.getRootView());
|
||||
((ViewGroup) mScrollView.getParent()).removeView(mScrollView);
|
||||
}
|
||||
|
||||
private void loadAdapter(){
|
||||
//Initialize adapter for keycodes
|
||||
mAdapter = new ArrayAdapter<>(mRootView.getContext(), R.layout.item_centered_textview);
|
||||
mSpecialArray = ControlData.buildSpecialButtonArray();
|
||||
for (int i = 0; i < mSpecialArray.length; i++) {
|
||||
//TODO this will break for sure
|
||||
mSpecialArray[i] = "SPECIAL_" + mSpecialArray[i];
|
||||
}
|
||||
Collections.reverse(Arrays.asList(mSpecialArray));
|
||||
mAdapter.addAll(mSpecialArray);
|
||||
mAdapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName());
|
||||
mAdapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
|
||||
|
||||
for (Spinner spinner : mKeycodeSpinners) {
|
||||
spinner.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
// Orientation spinner
|
||||
ArrayAdapter<ControlDrawerData.Orientation> adapter = new ArrayAdapter<>(mScrollView.getContext(), android.R.layout.simple_spinner_item);
|
||||
adapter.addAll(ControlDrawerData.getOrientations());
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
|
||||
|
||||
mOrientationSpinner.setAdapter(adapter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void setDefaultVisibilitySetting(){
|
||||
for(int i=0; i<mRootView.getChildCount(); ++i){
|
||||
mRootView.getChildAt(i).setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAtRight(){
|
||||
return mScrollView.getX() > currentDisplayMetrics.widthPixels/2f;
|
||||
}
|
||||
|
||||
|
||||
public static void setPercentageText(TextView textView, int progress){
|
||||
textView.setText(progress + " %");
|
||||
}
|
||||
|
||||
/* LOADING VALUES */
|
||||
|
||||
/** Load values for basic control data */
|
||||
public void loadValues(ControlData data){
|
||||
setDefaultVisibilitySetting();
|
||||
mOrientationTextView.setVisibility(GONE);
|
||||
mOrientationSpinner.setVisibility(GONE);
|
||||
|
||||
mNameEditText.setText(data.name);
|
||||
mWidthEditText.setText(String.valueOf(data.getWidth()));
|
||||
mHeightEditText.setText(String.valueOf(data.getHeight()));
|
||||
|
||||
mAlphaSeekbar.setProgress((int) (data.opacity*100));
|
||||
mStrokeWidthSeekbar.setProgress(data.strokeWidth);
|
||||
mCornerRadiusSeekbar.setProgress((int) data.cornerRadius);
|
||||
|
||||
setPercentageText(mAlphaPercentTextView, (int) (data.opacity*100));
|
||||
setPercentageText(mStrokePercentTextView, data.strokeWidth);
|
||||
setPercentageText(mCornerRadiusPercentTextView, (int) data.cornerRadius);
|
||||
|
||||
mToggleSwitch.setChecked(data.isToggle);
|
||||
mPassthroughSwitch.setChecked(data.passThruEnabled);
|
||||
mSwipeableSwitch.setChecked(data.isSwipeable);
|
||||
|
||||
for(int i = 0; i< data.keycodes.length; i++){
|
||||
if (data.keycodes[i] < 0) {
|
||||
mKeycodeSpinners[i].setSelection(data.keycodes[i] + mSpecialArray.length);
|
||||
} else {
|
||||
mKeycodeSpinners[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(data.keycodes[i]) + mSpecialArray.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Load values for extended control data */
|
||||
public void loadValues(ControlDrawerData data){
|
||||
loadValues(data.properties);
|
||||
|
||||
mOrientationSpinner.setSelection(
|
||||
ControlDrawerData.orientationToInt(data.orientation));
|
||||
|
||||
mMappingTextView.setVisibility(GONE);
|
||||
mKeycodeSpinners[0].setVisibility(GONE);
|
||||
mKeycodeSpinners[1].setVisibility(GONE);
|
||||
mKeycodeSpinners[2].setVisibility(GONE);
|
||||
mKeycodeSpinners[3].setVisibility(GONE);
|
||||
|
||||
mOrientationTextView.setVisibility(VISIBLE);
|
||||
mOrientationSpinner.setVisibility(VISIBLE);
|
||||
|
||||
mSwipeableSwitch.setVisibility(View.GONE);
|
||||
mPassthroughSwitch.setVisibility(View.GONE);
|
||||
mToggleSwitch.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
/** Load values for the joystick */
|
||||
public void loadJoystickValues(ControlData data){
|
||||
loadValues(data);
|
||||
|
||||
mMappingTextView.setVisibility(GONE);
|
||||
mKeycodeSpinners[0].setVisibility(GONE);
|
||||
mKeycodeSpinners[1].setVisibility(GONE);
|
||||
mKeycodeSpinners[2].setVisibility(GONE);
|
||||
mKeycodeSpinners[3].setVisibility(GONE);
|
||||
|
||||
mNameTextView.setVisibility(GONE);
|
||||
mNameEditText.setVisibility(GONE);
|
||||
|
||||
mCornerRadiusTextView.setVisibility(GONE);
|
||||
mCornerRadiusSeekbar.setVisibility(GONE);
|
||||
mCornerRadiusPercentTextView.setVisibility(GONE);
|
||||
|
||||
mSwipeableSwitch.setVisibility(View.GONE);
|
||||
mPassthroughSwitch.setVisibility(View.GONE);
|
||||
mToggleSwitch.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
private void bindLayout(){
|
||||
mRootView = mScrollView.findViewById(R.id.edit_layout);
|
||||
mNameEditText = mScrollView.findViewById(R.id.editName_editText);
|
||||
mWidthEditText = mScrollView.findViewById(R.id.editSize_editTextX);
|
||||
mHeightEditText = mScrollView.findViewById(R.id.editSize_editTextY);
|
||||
mToggleSwitch = mScrollView.findViewById(R.id.checkboxToggle);
|
||||
mPassthroughSwitch = mScrollView.findViewById(R.id.checkboxPassThrough);
|
||||
mSwipeableSwitch = mScrollView.findViewById(R.id.checkboxSwipeable);
|
||||
mKeycodeSpinners[0] = mScrollView.findViewById(R.id.editMapping_spinner_1);
|
||||
mKeycodeSpinners[1] = mScrollView.findViewById(R.id.editMapping_spinner_2);
|
||||
mKeycodeSpinners[2] = mScrollView.findViewById(R.id.editMapping_spinner_3);
|
||||
mKeycodeSpinners[3] = mScrollView.findViewById(R.id.editMapping_spinner_4);
|
||||
mOrientationSpinner = mScrollView.findViewById(R.id.editOrientation_spinner);
|
||||
mStrokeWidthSeekbar = mScrollView.findViewById(R.id.editStrokeWidth_seekbar);
|
||||
mCornerRadiusSeekbar = mScrollView.findViewById(R.id.editCornerRadius_seekbar);
|
||||
mAlphaSeekbar = mScrollView.findViewById(R.id.editButtonOpacity_seekbar);
|
||||
mSelectBackgroundColor = mScrollView.findViewById(R.id.editBackgroundColor_textView);
|
||||
mSelectStrokeColor = mScrollView.findViewById(R.id.editStrokeColor_textView);
|
||||
mStrokePercentTextView = mScrollView.findViewById(R.id.editStrokeWidth_textView_percent);
|
||||
mAlphaPercentTextView = mScrollView.findViewById(R.id.editButtonOpacity_textView_percent);
|
||||
mCornerRadiusPercentTextView = mScrollView.findViewById(R.id.editCornerRadius_textView_percent);
|
||||
|
||||
//Decorative stuff
|
||||
mMappingTextView = mScrollView.findViewById(R.id.editMapping_textView);
|
||||
mOrientationTextView = mScrollView.findViewById(R.id.editOrientation_textView);
|
||||
mNameTextView = mScrollView.findViewById(R.id.editName_textView);
|
||||
mCornerRadiusTextView = mScrollView.findViewById(R.id.editCornerRadius_textView);
|
||||
}
|
||||
|
||||
/**
|
||||
* A long function linking all the displayed data on the popup and,
|
||||
* the currently edited mCurrentlyEditedButton
|
||||
*/
|
||||
public void setupRealTimeListeners(){
|
||||
mNameEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if(internalChanges) return;
|
||||
|
||||
mCurrentlyEditedButton.getProperties().name = s.toString();
|
||||
|
||||
// Cheap and unoptimized, doesn't break the abstraction layer
|
||||
mCurrentlyEditedButton.setProperties(mCurrentlyEditedButton.getProperties(), false);
|
||||
}
|
||||
});
|
||||
|
||||
mWidthEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if(internalChanges) return;
|
||||
|
||||
mCurrentlyEditedButton.getProperties().setWidth(safeParseFloat(s.toString()));
|
||||
mCurrentlyEditedButton.updateProperties();
|
||||
}
|
||||
});
|
||||
|
||||
mHeightEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if(internalChanges) return;
|
||||
|
||||
mCurrentlyEditedButton.getProperties().setHeight(safeParseFloat(s.toString()));
|
||||
mCurrentlyEditedButton.updateProperties();
|
||||
}
|
||||
});
|
||||
|
||||
mSwipeableSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if(internalChanges) return;
|
||||
mCurrentlyEditedButton.getProperties().isSwipeable = isChecked;
|
||||
});
|
||||
mToggleSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if(internalChanges) return;
|
||||
mCurrentlyEditedButton.getProperties().isToggle = isChecked;
|
||||
});
|
||||
mPassthroughSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if(internalChanges) return;
|
||||
mCurrentlyEditedButton.getProperties().passThruEnabled = isChecked;
|
||||
});
|
||||
|
||||
mAlphaSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if(internalChanges) return;
|
||||
mCurrentlyEditedButton.getProperties().opacity = mAlphaSeekbar.getProgress()/100f;
|
||||
mCurrentlyEditedButton.getControlView().setAlpha(mAlphaSeekbar.getProgress()/100f);
|
||||
setPercentageText(mAlphaPercentTextView, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
|
||||
mStrokeWidthSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if(internalChanges) return;
|
||||
mCurrentlyEditedButton.getProperties().strokeWidth = mStrokeWidthSeekbar.getProgress();
|
||||
mCurrentlyEditedButton.setBackground();
|
||||
setPercentageText(mStrokePercentTextView, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
|
||||
mCornerRadiusSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if(internalChanges) return;
|
||||
mCurrentlyEditedButton.getProperties().cornerRadius = mCornerRadiusSeekbar.getProgress();
|
||||
mCurrentlyEditedButton.setBackground();
|
||||
setPercentageText(mCornerRadiusPercentTextView, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
|
||||
|
||||
for(int i = 0; i< mKeycodeSpinners.length; ++i){
|
||||
int finalI = i;
|
||||
mKeycodeSpinners[i].setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Side note, spinner listeners are fired later than all the other ones.
|
||||
// Meaning the internalChanges bool is useless here.
|
||||
if (position < mSpecialArray.length) {
|
||||
mCurrentlyEditedButton.getProperties().keycodes[finalI] = mKeycodeSpinners[finalI].getSelectedItemPosition() - mSpecialArray.length;
|
||||
} else {
|
||||
mCurrentlyEditedButton.getProperties().keycodes[finalI] = EfficientAndroidLWJGLKeycode.getValueByIndex(mKeycodeSpinners[finalI].getSelectedItemPosition() - mSpecialArray.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
mOrientationSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Side note, spinner listeners are fired later than all the other ones.
|
||||
// Meaning the internalChanges bool is useless here.
|
||||
|
||||
if(mCurrentlyEditedButton instanceof ControlDrawer){
|
||||
((ControlDrawer)mCurrentlyEditedButton).drawerData.orientation = ControlDrawerData.intToOrientation(mOrientationSpinner.getSelectedItemPosition());
|
||||
((ControlDrawer)mCurrentlyEditedButton).syncButtons();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {}
|
||||
});
|
||||
|
||||
|
||||
mSelectStrokeColor.setOnClickListener(v -> {
|
||||
mColorSelector.setAlphaEnabled(false);
|
||||
mColorSelector.setColorSelectionListener(color -> {
|
||||
mCurrentlyEditedButton.getProperties().strokeColor = color;
|
||||
mCurrentlyEditedButton.setBackground();
|
||||
});
|
||||
appearColor(isAtRight(), mCurrentlyEditedButton.getProperties().strokeColor);
|
||||
});
|
||||
|
||||
mSelectBackgroundColor.setOnClickListener(v -> {
|
||||
mColorSelector.setAlphaEnabled(true);
|
||||
mColorSelector.setColorSelectionListener(color -> {
|
||||
mCurrentlyEditedButton.getProperties().bgColor = color;
|
||||
mCurrentlyEditedButton.setBackground();
|
||||
});
|
||||
appearColor(isAtRight(), mCurrentlyEditedButton.getProperties().bgColor);
|
||||
});
|
||||
}
|
||||
|
||||
private float safeParseFloat(String string){
|
||||
float out = 10; // 10 px as a fallback
|
||||
try {
|
||||
out = Float.parseFloat(string);
|
||||
}catch (NumberFormatException e){
|
||||
Log.e("EditControlPopup", e.toString());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public void setCurrentlyEditedButton(ControlInterface button){
|
||||
if(mCurrentlyEditedButton != null)
|
||||
mCurrentlyEditedButton.getControlView().removeOnLayoutChangeListener(mLayoutChangedListener);
|
||||
mCurrentlyEditedButton = button;
|
||||
mCurrentlyEditedButton.getControlView().addOnLayoutChangeListener(mLayoutChangedListener);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
|
||||
public class EditControlSubButtonPopup extends EditControlButtonPopup{
|
||||
|
||||
|
||||
public EditControlSubButtonPopup(ControlButton button){
|
||||
super(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hideUselessViews() {
|
||||
(mRootView.findViewById(R.id.editSize_textView)).setVisibility(View.GONE);
|
||||
(mRootView.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
|
||||
|
||||
mDynamicPositionCheckbox.setVisibility(View.GONE);
|
||||
|
||||
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
|
||||
mDynamicXEditText.setVisibility(View.GONE);
|
||||
|
||||
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
|
||||
mDynamicYEditText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,405 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class has been splited from android/widget/Editor$HandleView.java
|
||||
*/
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.graphics.drawable.*;
|
||||
import android.os.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
|
||||
|
||||
public abstract class HandleView extends View implements ViewPositionListener, View.OnLongClickListener {
|
||||
protected Drawable mDrawable;
|
||||
protected Drawable mDrawableRtl;
|
||||
private final PopupWindow mContainer;
|
||||
// Position with respect to the parent TextView
|
||||
private int mPositionX, mPositionY;
|
||||
private boolean mIsDragging;
|
||||
// Offset from touch position to mPosition
|
||||
private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
|
||||
protected int mHotspotX;
|
||||
protected int mHorizontalGravity;
|
||||
// Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
|
||||
private float mTouchOffsetY;
|
||||
// Where the touch position should be on the handle to ensure a maximum cursor visibility
|
||||
private float mIdealVerticalOffset;
|
||||
// Parent's (TextView) previous position in window
|
||||
private int mLastParentX, mLastParentY;
|
||||
// Transient action popup window for Paste and Replace actions
|
||||
protected ActionPopupWindow mActionPopupWindow;
|
||||
// Previous text character offset
|
||||
private int mPreviousOffset = -1;
|
||||
// Previous text character offset
|
||||
private boolean mPositionHasChanged = true;
|
||||
// Used to delay the appearance of the action popup window
|
||||
private Runnable mActionPopupShower;
|
||||
// Minimum touch target size for handles
|
||||
private int mMinSize;
|
||||
protected ControlButton mView;
|
||||
|
||||
// MOD: Addition. Save old size of parent
|
||||
private int mDownWidth, mDownHeight;
|
||||
// int mWindowPosX, mWindowPosY;
|
||||
|
||||
private PositionListener mPositionListener;
|
||||
|
||||
// Touch-up filter: number of previous positions remembered
|
||||
private static final int HISTORY_SIZE = 5;
|
||||
private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
|
||||
private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
|
||||
private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
|
||||
private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
|
||||
private int mPreviousOffsetIndex = 0;
|
||||
private int mNumberPreviousOffsets = 0;
|
||||
|
||||
// Addition
|
||||
private float mDownX, mDownY;
|
||||
|
||||
|
||||
public HandleView(ControlButton view) {
|
||||
super(view.getContext());
|
||||
|
||||
mView = view;
|
||||
|
||||
mDownWidth = view.getLayoutParams().width;
|
||||
mDownHeight = view.getLayoutParams().height;
|
||||
|
||||
mContainer = new PopupWindow(view.getContext(), null, android.R.attr.textSelectHandleWindowStyle);
|
||||
mContainer.setSplitTouchEnabled(true);
|
||||
mContainer.setClippingEnabled(false);
|
||||
mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
|
||||
mContainer.setContentView(this);
|
||||
|
||||
mDrawableRtl = view.getContext().getDrawable(R.drawable.ic_view_handle);
|
||||
mMinSize = view.getContext().getResources().getDimensionPixelSize(R.dimen.text_handle_min_size);
|
||||
|
||||
setOnLongClickListener(this);
|
||||
|
||||
updateDrawable();
|
||||
|
||||
final int handleHeight = getPreferredHeight();
|
||||
mTouchOffsetY = -0.3f * handleHeight;
|
||||
mIdealVerticalOffset = 0.7f * handleHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(getPreferredWidth(), getPreferredHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas c) {
|
||||
final int drawWidth = mDrawable.getIntrinsicWidth();
|
||||
final int left = getHorizontalOffset();
|
||||
|
||||
mDrawable.setBounds(left, 0, left + drawWidth, mDrawable.getIntrinsicHeight());
|
||||
mDrawable.draw(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
ViewGroup.LayoutParams params = mView.getLayoutParams();
|
||||
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
startTouchUpFilter(getCurrentCursorOffset());
|
||||
mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
|
||||
mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
|
||||
|
||||
final PositionListener positionListener = getPositionListener();
|
||||
mLastParentX = positionListener.getPositionX();
|
||||
mLastParentY = positionListener.getPositionY();
|
||||
mIsDragging = true;
|
||||
|
||||
// MOD: Addition
|
||||
mDownX = ev.getRawX();
|
||||
mDownY = ev.getRawY();
|
||||
mDownWidth = params.width;
|
||||
mDownHeight = params.height;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final float rawX = ev.getRawX();
|
||||
final float rawY = ev.getRawY();
|
||||
|
||||
// Vertical hysteresis: vertical down movement tends to snap to ideal offset
|
||||
final float previousVerticalOffset = mTouchToWindowOffsetY - mLastParentY;
|
||||
final float currentVerticalOffset = rawY - mPositionY - mLastParentY;
|
||||
float newVerticalOffset;
|
||||
if (previousVerticalOffset < mIdealVerticalOffset) {
|
||||
newVerticalOffset = Math.min(currentVerticalOffset, mIdealVerticalOffset);
|
||||
newVerticalOffset = Math.max(newVerticalOffset, previousVerticalOffset);
|
||||
} else {
|
||||
newVerticalOffset = Math.max(currentVerticalOffset, mIdealVerticalOffset);
|
||||
newVerticalOffset = Math.min(newVerticalOffset, previousVerticalOffset);
|
||||
}
|
||||
mTouchToWindowOffsetY = newVerticalOffset + mLastParentY;
|
||||
|
||||
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
|
||||
final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
|
||||
|
||||
int newWidth = (int) (mDownWidth + (rawX - mDownX));
|
||||
int newHeight = (int) (mDownHeight + (rawY - mDownY));
|
||||
|
||||
// mDownX = rawX;
|
||||
// mDownY = rawY;
|
||||
|
||||
params.width = Math.max(50, newWidth);
|
||||
params.height = Math.max(50, newHeight);
|
||||
|
||||
mView.setLayoutParams(params);
|
||||
|
||||
updatePosition(newPosX, newPosY);
|
||||
// break;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
filterOnTouchUp();
|
||||
mIsDragging = false;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mIsDragging = false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public PositionListener getPositionListener() {
|
||||
if (mPositionListener == null) {
|
||||
mPositionListener = new PositionListener(mView);
|
||||
}
|
||||
return mPositionListener;
|
||||
}
|
||||
|
||||
protected void updateDrawable() {
|
||||
// final int offset = getCurrentCursorOffset();
|
||||
final boolean isRtlCharAtOffset = true; // mView.getLayout().isRtlCharAt(offset);
|
||||
mDrawable = mDrawableRtl; //isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
|
||||
mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
|
||||
mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset);
|
||||
}
|
||||
|
||||
protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun);
|
||||
protected abstract int getHorizontalGravity(boolean isRtlRun);
|
||||
|
||||
|
||||
|
||||
private void startTouchUpFilter(int offset) {
|
||||
mNumberPreviousOffsets = 0;
|
||||
addPositionToTouchUpFilter(offset);
|
||||
}
|
||||
|
||||
private void addPositionToTouchUpFilter(int offset) {
|
||||
mPreviousOffsetIndex = (mPreviousOffsetIndex + 1) % HISTORY_SIZE;
|
||||
mPreviousOffsets[mPreviousOffsetIndex] = offset;
|
||||
mPreviousOffsetsTimes[mPreviousOffsetIndex] = SystemClock.uptimeMillis();
|
||||
mNumberPreviousOffsets++;
|
||||
}
|
||||
|
||||
private void filterOnTouchUp() {
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
int i = 0;
|
||||
int index = mPreviousOffsetIndex;
|
||||
final int iMax = Math.min(mNumberPreviousOffsets, HISTORY_SIZE);
|
||||
while (i < iMax && (now - mPreviousOffsetsTimes[index]) < TOUCH_UP_FILTER_DELAY_AFTER) {
|
||||
i++;
|
||||
index = (mPreviousOffsetIndex - i + HISTORY_SIZE) % HISTORY_SIZE;
|
||||
}
|
||||
|
||||
if (i > 0 && i < iMax &&
|
||||
(now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
|
||||
positionAtCursorOffset(mPreviousOffsets[index], false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean offsetHasBeenChanged() {
|
||||
return mNumberPreviousOffsets > 1;
|
||||
}
|
||||
|
||||
private int getPreferredWidth() {
|
||||
return Math.max(mDrawable.getIntrinsicWidth(), mMinSize);
|
||||
}
|
||||
|
||||
private int getPreferredHeight() {
|
||||
return Math.max(mDrawable.getIntrinsicHeight(), mMinSize);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (isShowing()) return;
|
||||
|
||||
getPositionListener().addSubscriber(this, true /* local position may change */);
|
||||
|
||||
// Make sure the offset is always considered new, even when focusing at same position
|
||||
mPreviousOffset = -1;
|
||||
positionAtCursorOffset(getCurrentCursorOffset(), false);
|
||||
|
||||
hideActionPopupWindow();
|
||||
}
|
||||
|
||||
protected void dismiss() {
|
||||
mIsDragging = false;
|
||||
mContainer.dismiss();
|
||||
onDetached();
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
dismiss();
|
||||
|
||||
getPositionListener().removeSubscriber(this);
|
||||
}
|
||||
|
||||
void showActionPopupWindow(int delay, ControlButton button) {
|
||||
if (mActionPopupWindow == null) {
|
||||
mActionPopupWindow = new ActionPopupWindow(this, button);
|
||||
}
|
||||
if (mActionPopupShower == null) {
|
||||
mActionPopupShower = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
mActionPopupWindow.show();
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
mView.removeCallbacks(mActionPopupShower);
|
||||
}
|
||||
mView.postDelayed(mActionPopupShower, delay);
|
||||
}
|
||||
|
||||
protected void hideActionPopupWindow() {
|
||||
if (mActionPopupShower != null) {
|
||||
mView.removeCallbacks(mActionPopupShower);
|
||||
}
|
||||
if (mActionPopupWindow != null) {
|
||||
mActionPopupWindow.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mContainer.isShowing();
|
||||
}
|
||||
|
||||
private boolean isVisible() {
|
||||
// Always show a dragging handle.
|
||||
if (mIsDragging) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mView.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
public abstract int getCurrentCursorOffset();
|
||||
|
||||
protected abstract void updateSelection(int offset);
|
||||
|
||||
public abstract void updatePosition(float x, float y);
|
||||
|
||||
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
|
||||
mPositionX = mView.getWidth();
|
||||
mPositionY = mView.getHeight();
|
||||
|
||||
mPositionHasChanged = true;
|
||||
}
|
||||
|
||||
public void updatePosition(int parentPositionX, int parentPositionY,
|
||||
boolean parentPositionChanged, boolean parentScrolled) {
|
||||
positionAtCursorOffset(getCurrentCursorOffset(), parentScrolled);
|
||||
if (parentPositionChanged || mPositionHasChanged) {
|
||||
if (mIsDragging) {
|
||||
// Update touchToWindow offset in case of parent scrolling while dragging
|
||||
if (parentPositionX != mLastParentX || parentPositionY != mLastParentY) {
|
||||
mTouchToWindowOffsetX += parentPositionX - mLastParentX;
|
||||
mTouchToWindowOffsetY += parentPositionY - mLastParentY;
|
||||
mLastParentX = parentPositionX;
|
||||
mLastParentY = parentPositionY;
|
||||
}
|
||||
|
||||
onHandleMoved();
|
||||
}
|
||||
|
||||
if (isVisible()) {
|
||||
final int positionX = parentPositionX + mPositionX;
|
||||
final int positionY = parentPositionY + mPositionY;
|
||||
/*
|
||||
mWindowPosX = positionX;
|
||||
mWindowPosY = positionY;
|
||||
*/
|
||||
if (isShowing()) {
|
||||
mContainer.update(positionX, positionY, -1, -1);
|
||||
} else {
|
||||
mContainer.showAtLocation(mView, Gravity.NO_GRAVITY,
|
||||
positionX, positionY);
|
||||
}
|
||||
} else {
|
||||
if (isShowing()) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
mPositionHasChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private int getHorizontalOffset() {
|
||||
final int width = getPreferredWidth();
|
||||
final int drawWidth = mDrawable.getIntrinsicWidth();
|
||||
final int left;
|
||||
switch (mHorizontalGravity) {
|
||||
case Gravity.LEFT:
|
||||
left = 0;
|
||||
break;
|
||||
default:
|
||||
case Gravity.CENTER:
|
||||
left = (width - drawWidth) / 2;
|
||||
break;
|
||||
case Gravity.RIGHT:
|
||||
left = width - drawWidth;
|
||||
break;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
protected int getCursorOffset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isDragging() {
|
||||
return mIsDragging;
|
||||
}
|
||||
|
||||
void onHandleMoved() {
|
||||
hideActionPopupWindow();
|
||||
}
|
||||
|
||||
public void onDetached() {
|
||||
hideActionPopupWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class has been splited from android/widget/Editor$HandleView.java
|
||||
*/
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.view.ViewGroup.*;
|
||||
import android.widget.*;
|
||||
|
||||
public abstract class PinnedPopupWindow implements ViewPositionListener {
|
||||
protected PopupWindow mPopupWindow;
|
||||
protected ViewGroup mContentView;
|
||||
int mPositionX, mPositionY;
|
||||
|
||||
protected HandleView mHandleView;
|
||||
|
||||
protected abstract void createPopupWindow();
|
||||
protected abstract void initContentView();
|
||||
protected abstract int getTextOffset();
|
||||
protected abstract int getVerticalLocalPosition(int line);
|
||||
protected abstract int clipVertically(int positionY);
|
||||
|
||||
public PinnedPopupWindow(HandleView handleView) {
|
||||
mHandleView = handleView;
|
||||
|
||||
createPopupWindow();
|
||||
|
||||
mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
|
||||
mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
initContentView();
|
||||
|
||||
LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mContentView.setLayoutParams(wrapContent);
|
||||
|
||||
mPopupWindow.setContentView(mContentView);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
mHandleView.getPositionListener().addSubscriber(this, false /* offset is fixed */);
|
||||
|
||||
computeLocalPosition();
|
||||
|
||||
final PositionListener positionListener = mHandleView.getPositionListener();
|
||||
updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
|
||||
}
|
||||
|
||||
protected void measureContent() {
|
||||
final DisplayMetrics displayMetrics = mHandleView.getResources().getDisplayMetrics();
|
||||
mContentView.measure(
|
||||
View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
|
||||
View.MeasureSpec.AT_MOST),
|
||||
View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
|
||||
View.MeasureSpec.AT_MOST));
|
||||
}
|
||||
|
||||
/* The popup window will be horizontally centered on the getTextOffset() and vertically
|
||||
* positioned according to viewportToContentHorizontalOffset.
|
||||
*
|
||||
* This method assumes that mContentView has properly been measured from its content. */
|
||||
private void computeLocalPosition() {
|
||||
measureContent();
|
||||
|
||||
/*
|
||||
final int width = mContentView.getMeasuredWidth();
|
||||
final int offset = getTextOffset();
|
||||
mPositionX = (int) (mTextView.getLayout().getPrimaryHorizontal(offset) - width / 2.0f);
|
||||
mPositionX += mTextView.viewportToContentHorizontalOffset();
|
||||
|
||||
final int line = mTextView.getLayout().getLineForOffset(offset);
|
||||
mPositionY = getVerticalLocalPosition(line);
|
||||
mPositionY += mTextView.viewportToContentVerticalOffset();
|
||||
*/
|
||||
|
||||
/*
|
||||
mPositionX = (int) mHandleView.mView.getTranslationX();
|
||||
mPositionY = (int) mHandleView.mView.getTranslationY();
|
||||
*/
|
||||
|
||||
mPositionY = mHandleView.mView.getHeight();
|
||||
}
|
||||
|
||||
private void updatePosition(int parentPositionX, int parentPositionY) {
|
||||
int positionX = parentPositionX + mPositionX;
|
||||
int positionY = parentPositionY + mPositionY;
|
||||
|
||||
positionY = clipVertically(positionY);
|
||||
|
||||
// Horizontal clipping
|
||||
final DisplayMetrics displayMetrics = mHandleView.getResources().getDisplayMetrics();
|
||||
final int width = mContentView.getMeasuredWidth();
|
||||
positionX = Math.min(displayMetrics.widthPixels - width, positionX);
|
||||
positionX = Math.max(0, positionX);
|
||||
|
||||
if (isShowing()) {
|
||||
mPopupWindow.update(positionX, positionY, -1, -1);
|
||||
} else {
|
||||
mPopupWindow.showAtLocation(mHandleView, Gravity.NO_GRAVITY,
|
||||
positionX, positionY);
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
mPopupWindow.dismiss();
|
||||
mHandleView.getPositionListener().removeSubscriber(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePosition(int parentPositionX, int parentPositionY,
|
||||
boolean parentPositionChanged, boolean parentScrolled) {
|
||||
// Either parentPositionChanged or parentScrolled is true, check if still visible
|
||||
if (isShowing()) {
|
||||
if (parentScrolled) computeLocalPosition();
|
||||
updatePosition(parentPositionX, parentPositionY);
|
||||
} else {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopupWindow.isShowing();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class has been splited from android/widget/Editor$HandleView.java
|
||||
*/
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.view.*;
|
||||
|
||||
public class PositionListener implements ViewTreeObserver.OnPreDrawListener {
|
||||
// 3 handles
|
||||
// 3 ActionPopup [replace, suggestion, easyedit] (suggestionsPopup first hides the others)
|
||||
// 1 CursorAnchorInfoNotifier
|
||||
private final int MAXIMUM_NUMBER_OF_LISTENERS = 7;
|
||||
private ViewPositionListener[] mPositionListeners =
|
||||
new ViewPositionListener[MAXIMUM_NUMBER_OF_LISTENERS];
|
||||
private boolean mCanMove[] = new boolean[MAXIMUM_NUMBER_OF_LISTENERS];
|
||||
private boolean mPositionHasChanged = true;
|
||||
// Absolute position of the TextView with respect to its parent window
|
||||
private int mPositionX, mPositionY;
|
||||
private int mNumberOfListeners;
|
||||
private boolean mScrollHasChanged;
|
||||
final int[] mTempCoords = new int[2];
|
||||
private View mView;
|
||||
|
||||
public PositionListener(View view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public void addSubscriber(ViewPositionListener positionListener, boolean canMove) {
|
||||
if (mNumberOfListeners == 0) {
|
||||
updatePosition();
|
||||
ViewTreeObserver vto = mView.getViewTreeObserver();
|
||||
vto.addOnPreDrawListener(this);
|
||||
}
|
||||
|
||||
int emptySlotIndex = -1;
|
||||
for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
|
||||
ViewPositionListener listener = mPositionListeners[i];
|
||||
if (listener == positionListener) {
|
||||
return;
|
||||
} else if (emptySlotIndex < 0 && listener == null) {
|
||||
emptySlotIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
mPositionListeners[emptySlotIndex] = positionListener;
|
||||
mCanMove[emptySlotIndex] = canMove;
|
||||
mNumberOfListeners++;
|
||||
}
|
||||
|
||||
public void removeSubscriber(ViewPositionListener positionListener) {
|
||||
for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
|
||||
if (mPositionListeners[i] == positionListener) {
|
||||
mPositionListeners[i] = null;
|
||||
mNumberOfListeners--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mNumberOfListeners == 0) {
|
||||
ViewTreeObserver vto = mView.getViewTreeObserver();
|
||||
vto.removeOnPreDrawListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int getPositionX() {
|
||||
return mPositionX;
|
||||
}
|
||||
|
||||
public int getPositionY() {
|
||||
return mPositionY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
updatePosition();
|
||||
|
||||
for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
|
||||
if (mPositionHasChanged || mScrollHasChanged || mCanMove[i]) {
|
||||
ViewPositionListener positionListener = mPositionListeners[i];
|
||||
if (positionListener != null) {
|
||||
positionListener.updatePosition(mPositionX, mPositionY,
|
||||
mPositionHasChanged, mScrollHasChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mScrollHasChanged = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updatePosition() {
|
||||
mView.getLocationInWindow(mTempCoords);
|
||||
|
||||
mPositionHasChanged = mTempCoords[0] != mPositionX || mTempCoords[1] != mPositionY;
|
||||
|
||||
mPositionX = mTempCoords[0];
|
||||
mPositionY = mTempCoords[1];
|
||||
}
|
||||
|
||||
public void onScrollChanged() {
|
||||
mScrollHasChanged = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class has been splited from android/widget/Editor$HandleView.java
|
||||
*/
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
import android.graphics.drawable.*;
|
||||
import android.view.*;
|
||||
|
||||
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
|
||||
|
||||
|
||||
public class SelectionEndHandleView extends HandleView {
|
||||
public SelectionEndHandleView(ControlButton view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
|
||||
if (isRtlRun) {
|
||||
return (drawable.getIntrinsicWidth() * 3) / 4;
|
||||
} else {
|
||||
return drawable.getIntrinsicWidth() / 4;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHorizontalGravity(boolean isRtlRun) {
|
||||
return isRtlRun ? Gravity.LEFT : Gravity.RIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentCursorOffset() {
|
||||
return 0; // mView.getSelectionEnd();
|
||||
}
|
||||
|
||||
public void show(ControlButton button){
|
||||
super.show();
|
||||
showActionPopupWindow(0, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSelection(int offset) {
|
||||
// Selection.setSelection((Spannable) mView.getText(), mView.getSelectionStart(), offset);
|
||||
updateDrawable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePosition(float x, float y) {
|
||||
// updatePosition((int) x, (int) y, false, false);
|
||||
positionAtCursorOffset(0, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
//TODO stub
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This class has been splited from android/widget/Editor$HandleView.java
|
||||
*/
|
||||
package net.kdt.pojavlaunch.customcontrols.handleview;
|
||||
|
||||
public interface ViewPositionListener {
|
||||
void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19.44,12.99l-0.01,0.02c0.04,-0.33 0.08,-0.67 0.08,-1.01 0,-0.34 -0.03,-0.66 -0.07,-0.99l0.01,0.02 2.44,-1.92 -2.43,-4.22 -2.87,1.16 0.01,0.01c-0.52,-0.4 -1.09,-0.74 -1.71,-1h0.01L14.44,2H9.57l-0.44,3.07h0.01c-0.62,0.26 -1.19,0.6 -1.71,1l0.01,-0.01 -2.88,-1.17 -2.44,4.22 2.44,1.92 0.01,-0.02c-0.04,0.33 -0.07,0.65 -0.07,0.99 0,0.34 0.03,0.68 0.08,1.01l-0.01,-0.02 -2.1,1.65 -0.33,0.26 2.43,4.2 2.88,-1.15 -0.02,-0.04c0.53,0.41 1.1,0.75 1.73,1.01h-0.03L9.58,22h4.85s0.03,-0.18 0.06,-0.42l0.38,-2.65h-0.01c0.62,-0.26 1.2,-0.6 1.73,-1.01l-0.02,0.04 2.88,1.15 2.43,-4.2s-0.14,-0.12 -0.33,-0.26l-2.11,-1.66zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
</vector>
|
||||
BIN
app_pojavlauncher/src/main/res/drawable/spinner_arrow_right.png
Normal file
BIN
app_pojavlauncher/src/main/res/drawable/spinner_arrow_right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 200 B |
|
|
@ -44,6 +44,13 @@
|
|||
android:inputType="textFilter|textImeMultiLine|textAutoComplete|textAutoCorrect"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<net.kdt.pojavlaunch.customcontrols.handleview.DrawerPullButton
|
||||
android:id="@+id/drawer_button"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="12dp"
|
||||
android:elevation="10dp"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
|
||||
</net.kdt.pojavlaunch.customcontrols.ControlLayout>
|
||||
|
||||
<com.kdt.LoggerView
|
||||
|
|
|
|||
|
|
@ -7,15 +7,28 @@
|
|||
android:layout_alignParentRight="true"
|
||||
android:id="@+id/customctrl_drawerlayout">
|
||||
|
||||
<RelativeLayout
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content">
|
||||
|
||||
|
||||
<net.kdt.pojavlaunch.customcontrols.handleview.DrawerPullButton
|
||||
android:id="@+id/drawer_button"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="16dp"
|
||||
android:elevation="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:text="@string/hint_control_mapping"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_alignParentRight="true"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/hint_control_mapping"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<net.kdt.pojavlaunch.customcontrols.ControlLayout
|
||||
android:id="@+id/customctrl_controllayout"
|
||||
|
|
@ -24,7 +37,7 @@
|
|||
|
||||
</net.kdt.pojavlaunch.customcontrols.ControlLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/customctrl_navigation_view"
|
||||
|
|
|
|||
|
|
@ -1,69 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<net.kdt.pojavlaunch.colorselector.HueView
|
||||
android:id="@+id/color_selector_hue_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:focusable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/color_selector_rectangle_view" />
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/_230sdp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_app"
|
||||
android:paddingHorizontal="@dimen/_5sdp"
|
||||
android:paddingVertical="@dimen/_5sdp"
|
||||
android:id="@+id/color_picker_layout"
|
||||
android:layout_marginVertical="@dimen/_14sdp">
|
||||
|
||||
<net.kdt.pojavlaunch.colorselector.SVRectangleView
|
||||
android:id="@+id/color_selector_rectangle_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:focusable="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/color_selector_hex_edit"
|
||||
android:layout_marginEnd="8dp"
|
||||
|
||||
app:layout_constraintEnd_toStartOf="@+id/color_selector_alpha_view"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<net.kdt.pojavlaunch.colorselector.AlphaView
|
||||
android:id="@+id/color_selector_alpha_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintEnd_toEndOf="@+id/color_selector_hue_view"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/color_selector_hue_view" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/color_selector_hex_edit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="@string/color_default_hex"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text"
|
||||
android:minHeight="48dp"
|
||||
android:typeface="monospace"
|
||||
app:layout_constraintBottom_toTopOf="@+id/color_selector_hue_view"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<net.kdt.pojavlaunch.colorselector.ColorSideBySideView
|
||||
android:id="@+id/color_selector_color_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="94dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintEnd_toEndOf="@+id/color_selector_rectangle_view"
|
||||
app:layout_constraintStart_toStartOf="@+id/color_selector_rectangle_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/color_selector_rectangle_view" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/color_selector_hex_edit"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/color_default_hex"
|
||||
android:gravity="center"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text"
|
||||
android:minHeight="48dp"
|
||||
android:typeface="monospace"
|
||||
app:layout_constraintEnd_toEndOf="@+id/color_selector_color_view"
|
||||
app:layout_constraintStart_toStartOf="@+id/color_selector_color_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/color_selector_color_view" />
|
||||
|
||||
|
||||
|
||||
<net.kdt.pojavlaunch.colorselector.AlphaView
|
||||
android:id="@+id/color_selector_alpha_view"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/color_selector_hue_view"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<net.kdt.pojavlaunch.colorselector.HueView
|
||||
android:id="@+id/color_selector_hue_view"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/color_selector_hex_edit"
|
||||
android:focusable="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/color_selector_rectangle_view"
|
||||
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -1,13 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.kdt.DefocusableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.kdt.DefocusableScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="500dp"
|
||||
android:layout_width="@dimen/_230sdp"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="@color/background_app"
|
||||
android:layout_marginVertical="@dimen/_14sdp"
|
||||
>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/edit_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="@dimen/_5sdp"
|
||||
android:paddingVertical="@dimen/_5sdp"
|
||||
app:layout_optimizationLevel="standard|dimensions|chains">
|
||||
|
||||
|
||||
|
|
@ -15,129 +22,133 @@
|
|||
<TextView
|
||||
android:id="@+id/editName_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="40dp"
|
||||
android:text="@string/global_name"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/global_name"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editName_editText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:hint="Button Name"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:maxLines="1"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@+id/editName_textView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/editName_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editName_textView"
|
||||
/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editName_textView" />
|
||||
|
||||
<!-- SIZE SECTION -->
|
||||
<TextView
|
||||
android:id="@+id/editSize_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="45dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/customctrl_size"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_size"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editName_textView"
|
||||
app:layout_constraintTop_toBottomOf="@id/editName_editText"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editSize_editTextX"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="numberDecimal"
|
||||
|
||||
app:layout_constraintHorizontal_chainStyle="spread"
|
||||
app:layout_constraintStart_toEndOf="@id/editSize_textView"
|
||||
app:layout_constraintTop_toTopOf="@id/editSize_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editSize_textView"
|
||||
app:layout_constraintEnd_toStartOf="@id/editSize_editTextY"/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editSize_textView" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editSize_editTextY"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:gravity="center"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="numberDecimal"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editSize_editTextX"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/editSize_editTextX"
|
||||
app:layout_constraintTop_toTopOf="@id/editSize_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editSize_textView"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
app:layout_constraintTop_toTopOf="@+id/editSize_editTextX" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:text="x"
|
||||
android:gravity="center"
|
||||
android:text="x"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editSize_editTextX"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editSize_editTextX"
|
||||
app:layout_constraintEnd_toStartOf="@id/editSize_editTextY"
|
||||
app:layout_constraintTop_toTopOf="@id/editSize_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editSize_textView" />
|
||||
app:layout_constraintStart_toEndOf="@id/editSize_editTextX"
|
||||
app:layout_constraintTop_toTopOf="@+id/editSize_editTextX" />
|
||||
|
||||
<!-- MAPPING SECTION -->
|
||||
<TextView
|
||||
android:id="@+id/editMapping_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="70dp"
|
||||
android:text="@string/customctrl_mapping"
|
||||
android:paddingTop="8dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_mapping"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editSize_textView"/>
|
||||
app:layout_constraintTop_toBottomOf="@+id/editSize_editTextX" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/editMapping_spinner_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
|
||||
app:layout_constraintBottom_toTopOf="@id/editMapping_spinner_3"
|
||||
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_2"
|
||||
|
||||
app:layout_constraintHorizontal_chainStyle="spread"
|
||||
app:layout_constraintVertical_chainStyle="spread"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_textView"
|
||||
app:layout_constraintTop_toTopOf="@id/editMapping_textView"
|
||||
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_2"
|
||||
app:layout_constraintBottom_toTopOf="@id/editMapping_spinner_3"/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editMapping_textView"
|
||||
app:layout_constraintVertical_chainStyle="spread" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editMapping_plus_1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:text="+"
|
||||
android:gravity="center"
|
||||
android:text="+"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_1"
|
||||
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_2"
|
||||
app:layout_constraintTop_toTopOf="@id/editMapping_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editMapping_spinner_1"
|
||||
/>
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editMapping_spinner_1"
|
||||
app:layout_constraintEnd_toEndOf="@+id/editMapping_spinner_1"
|
||||
app:layout_constraintTop_toTopOf="@+id/editMapping_spinner_1" />
|
||||
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/editMapping_spinner_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_1"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editMapping_spinner_1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editMapping_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editMapping_spinner_1"
|
||||
/>
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_1"
|
||||
app:layout_constraintTop_toTopOf="@+id/editMapping_spinner_1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editMapping_plus_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:text="+"
|
||||
android:gravity="center"
|
||||
android:text="+"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
|
||||
app:layout_constraintEnd_toEndOf="@id/editMapping_textView"
|
||||
|
|
@ -148,311 +159,237 @@
|
|||
<Spinner
|
||||
android:id="@+id/editMapping_spinner_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_textView"
|
||||
app:layout_constraintTop_toBottomOf="@id/editMapping_spinner_1"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
|
||||
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_4"/>
|
||||
|
||||
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_4"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editMapping_spinner_1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editMapping_plus_3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:text="+"
|
||||
android:gravity="center"
|
||||
android:text="+"
|
||||
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_3"
|
||||
app:layout_constraintEnd_toStartOf="@id/editMapping_spinner_4"
|
||||
app:layout_constraintTop_toTopOf="@id/editMapping_spinner_4"
|
||||
|
||||
/>
|
||||
app:layout_constraintBottom_toBottomOf="@+id/editMapping_spinner_3"
|
||||
app:layout_constraintEnd_toEndOf="@+id/editMapping_spinner_3"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editMapping_spinner_1" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/editMapping_spinner_4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_3"
|
||||
app:layout_constraintTop_toBottomOf="@id/editMapping_spinner_2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editMapping_textView"
|
||||
/>
|
||||
app:layout_constraintStart_toEndOf="@id/editMapping_spinner_3"
|
||||
app:layout_constraintTop_toBottomOf="@id/editMapping_spinner_2" />
|
||||
|
||||
|
||||
<!-- ORIENTATION SECTION -->
|
||||
<TextView
|
||||
android:id="@+id/editOrientation_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="45dp"
|
||||
android:text="@string/customctrl_orientation"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_orientation"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editMapping_textView"
|
||||
/>
|
||||
app:layout_constraintTop_toBottomOf="@+id/editMapping_spinner_3" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/editOrientation_spinner"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@android:color/transparent"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editOrientation_textView"
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editOrientation_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editOrientation_textView"
|
||||
/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editOrientation_textView" />
|
||||
|
||||
<!-- TOGGLE SECTION -->
|
||||
<CheckBox
|
||||
<Switch
|
||||
android:id="@+id/checkboxToggle"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:text="@string/customctrl_toggle"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editOrientation_textView"
|
||||
/>
|
||||
app:layout_constraintTop_toBottomOf="@id/editOrientation_spinner"
|
||||
tools:ignore="UseSwitchCompatOrMaterialXml" />
|
||||
|
||||
<!-- MOUSE PASS THROUGH SECTION -->
|
||||
<CheckBox
|
||||
<Switch
|
||||
android:id="@+id/checkboxPassThrough"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:text="@string/customctrl_passthru"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkboxToggle"
|
||||
/>
|
||||
tools:ignore="UseSwitchCompatOrMaterialXml" />
|
||||
|
||||
<!-- SWIPEABLE BUTTON SECTION -->
|
||||
<CheckBox
|
||||
<Switch
|
||||
android:id="@+id/checkboxSwipeable"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:text="@string/customctrl_swipeable"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkboxPassThrough"
|
||||
/>
|
||||
tools:ignore="UseSwitchCompatOrMaterialXml" />
|
||||
|
||||
<!-- BACKGROUND COLOR SECTION -->
|
||||
<TextView
|
||||
<fr.spse.extended_view.ExtendedTextView
|
||||
android:id="@+id/editBackgroundColor_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="35dp"
|
||||
android:text="@string/customctrl_background_color"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkboxSwipeable"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/editBackgroundColor_imageButton"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginHorizontal="50dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:layout_height="35dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_background_color"
|
||||
android:drawableEnd="@drawable/spinner_arrow_right"
|
||||
app:drawableEndSize="20dp"
|
||||
app:drawableEndIntegerScaling="true"
|
||||
|
||||
android:background="#FFFFFFFF"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editBackgroundColor_textView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editBackgroundColor_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editBackgroundColor_textView"
|
||||
/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkboxSwipeable" />
|
||||
|
||||
|
||||
|
||||
<!-- STROKE WIDTH -->
|
||||
<TextView
|
||||
android:id="@+id/editStrokeWidth_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="35dp"
|
||||
android:text="@string/customctrl_stroke_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_stroke_width"
|
||||
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editBackgroundColor_textView"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/editStrokeColor_textView" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/editStrokeWidth_seekbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editStrokeWidth_textView"
|
||||
app:layout_constraintTop_toTopOf="@id/editStrokeWidth_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editStrokeWidth_textView"
|
||||
app:layout_constraintEnd_toStartOf="@id/editStrokeWidth_textView_percent"
|
||||
/>
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.538"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editStrokeWidth_textView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editStrokeWidth_textView_percent"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="100%"
|
||||
android:gravity="center"
|
||||
android:text="100%"
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editStrokeWidth_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editStrokeWidth_textView"
|
||||
/>
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editStrokeWidth_textView" />
|
||||
|
||||
<!-- STROKE COLOR VERSION -->
|
||||
<TextView
|
||||
<fr.spse.extended_view.ExtendedTextView
|
||||
android:id="@+id/editStrokeColor_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="35dp"
|
||||
android:text="@string/customctrl_stroke_color"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editStrokeWidth_textView"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/editStrokeColor_imageButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginHorizontal="50dp"
|
||||
android:layout_marginVertical="5dp"
|
||||
android:layout_height="35dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:drawableEnd="@drawable/spinner_arrow_right"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_stroke_color"
|
||||
app:drawableEndIntegerScaling="true"
|
||||
app:drawableEndSize="20dp"
|
||||
|
||||
android:background="#FFFFFFFF"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editStrokeColor_textView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editStrokeColor_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editStrokeColor_textView"
|
||||
/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editBackgroundColor_textView" />
|
||||
|
||||
|
||||
<!-- CORNER RADIUS SECTION -->
|
||||
<TextView
|
||||
android:id="@+id/editCornerRadius_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="35dp"
|
||||
android:text="@string/customctrl_corner_radius"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_corner_radius"
|
||||
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editStrokeColor_textView"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/editStrokeWidth_seekbar" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/editCornerRadius_seekbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editCornerRadius_textView"
|
||||
app:layout_constraintTop_toTopOf="@id/editCornerRadius_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editCornerRadius_textView"
|
||||
app:layout_constraintEnd_toStartOf="@id/editCornerRadius_textView_percent"
|
||||
/>
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/editCornerRadius_textView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editCornerRadius_textView_percent"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="100%"
|
||||
android:gravity="center"
|
||||
android:text="100%"
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editCornerRadius_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editCornerRadius_textView"
|
||||
/>
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editCornerRadius_textView" />
|
||||
|
||||
<!-- BUTTON OPACITY SECTION -->
|
||||
<TextView
|
||||
android:id="@+id/editButtonOpacity_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="35dp"
|
||||
android:text="@string/customctrl_button_opacity"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingEnd="5dp"
|
||||
android:text="@string/customctrl_button_opacity"
|
||||
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editCornerRadius_textView"/>
|
||||
app:layout_constraintTop_toBottomOf="@+id/editCornerRadius_seekbar" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/editButtonOpacity_seekbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_height="30dp"
|
||||
|
||||
app:layout_constraintStart_toEndOf="@id/editButtonOpacity_textView"
|
||||
app:layout_constraintTop_toTopOf="@id/editButtonOpacity_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editButtonOpacity_textView"
|
||||
app:layout_constraintEnd_toStartOf="@id/editButtonOpacity_textView_percent"
|
||||
/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editButtonOpacity_textView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editButtonOpacity_textView_percent"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="0dp"
|
||||
android:text="100%"
|
||||
android:gravity="center"
|
||||
android:text="100%"
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editButtonOpacity_textView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/editButtonOpacity_textView"
|
||||
/>
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/editButtonOpacity_textView" />
|
||||
|
||||
<!-- DYNAMIC BUTTON SECTION -->
|
||||
<CheckBox
|
||||
android:id="@+id/checkboxDynamicPosition"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/customctrl_dynamicpos"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editButtonOpacity_textView"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editDynamicPositionX_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/customctrl_dynamicpos_x"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkboxDynamicPosition"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editDynamicPositionX_editText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editDynamicPositionX_textView"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editDynamicPositionY_textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/customctrl_dynamicpos_y"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editDynamicPositionX_editText"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editDynamicPositionY_editText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/editDynamicPositionY_textView"
|
||||
/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
style="?android:attr/spinnerItemStyle"
|
||||
android:singleLine="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:textAlignment="inherit"
|
||||
android:gravity="center"/>
|
||||
|
|
@ -2,4 +2,12 @@
|
|||
<resources>
|
||||
<color name="control_button_color">#4CC4C4C4</color>
|
||||
<color name="control_button_pressed_color">#4D000000</color>
|
||||
|
||||
<color name="minebutton_color">#57CC33</color>
|
||||
<color name="background_app">#181818</color>
|
||||
<color name="background_status_bar">#242424</color>
|
||||
<color name="background_bottom_bar">#232323</color>
|
||||
|
||||
<color name="primary_text">#FFFFFF</color>
|
||||
<color name="secondary_text">#B2B2B2</color>
|
||||
</resources>
|
||||
|
|
@ -15,6 +15,15 @@
|
|||
<item name="4">@string/customctrl_selectdefault</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="menu_customcontrol_customactivity">
|
||||
<item name="0">@string/customctrl_addbutton</item>
|
||||
<item name="1">@string/customctrl_addbutton_drawer</item>
|
||||
<item name="2">@string/global_load</item>
|
||||
<item name="3">@string/global_save</item>
|
||||
<item name="4">@string/customctrl_selectdefault</item>
|
||||
<item name="5">@string/customctrl_export</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="menu_ingame">
|
||||
<item>@string/control_forceclose</item>
|
||||
<item>@string/control_viewout</item>
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@
|
|||
<string name="customctrl_add_subbutton_message">Sub-button n°%d has been added !</string>
|
||||
|
||||
<string name="customctrl_selectdefault">Select default Control json</string>
|
||||
<string name="customctrl_export">Export control</string>
|
||||
|
||||
|
||||
<string name="main_install_jar_file">Install .jar</string>
|
||||
|
|
|
|||
3
app_pojavlauncher/src/main/res/xml/provider.xml
Normal file
3
app_pojavlauncher/src/main/res/xml/provider.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<files-path name="files" path="/"/>
|
||||
</paths>
|
||||
Loading…
Add table
Add a link
Reference in a new issue