Skip to content

Commit

Permalink
Pandroid: add option to change screen gamepad, buttons position. (#359)
Browse files Browse the repository at this point in the history
* Add change screen gamepad: initial commit

* Add change gamepad positions: part 2

* Peach fixes

* Bonk

---------

Co-authored-by: wheremyfoodat <[email protected]>
  • Loading branch information
GabrielBRDeveloper and wheremyfoodat authored Jan 3, 2024
1 parent 7094544 commit c849af4
Show file tree
Hide file tree
Showing 32 changed files with 1,028 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,22 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {

try {
Class<?> clazz = getClassLoader().loadClass(intent.getStringExtra(Constants.ACTIVITY_PARAMETER_FRAGMENT));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, (Fragment) clazz.newInstance()).commitNow();
Fragment fragment = (Fragment) clazz.newInstance();
fragment.setArguments(intent.getExtras());
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commitNow();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static void launch(Context context, Class<? extends Fragment> clazz) {
launch(context, clazz, new Intent());
}

public static void launch(Context context, Class<? extends Fragment> clazz, Intent extras) {
context.startActivity(new Intent(context, PreferenceActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtras(extras)
.putExtra(Constants.ACTIVITY_PARAMETER_FRAGMENT, clazz.getName()));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.panda3ds.pandroid.app.base;

import android.content.Context;
import android.view.Gravity;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.appcompat.widget.LinearLayoutCompat;

import com.panda3ds.pandroid.R;
import com.panda3ds.pandroid.lang.Function;

public class BottomAlertDialog extends AlertDialog.Builder {
private final LinearLayoutCompat layoutCompat;

public BottomAlertDialog(@NonNull Context context) {
super(context, R.style.AlertDialog);
layoutCompat = new LinearLayoutCompat(context);
layoutCompat.setOrientation(LinearLayoutCompat.VERTICAL);

int padding = getContext().getResources().getDimensionPixelSize(androidx.appcompat.R.dimen.abc_dialog_padding_material);
layoutCompat.setPadding(padding, 0, padding, 0);

setView(layoutCompat);
}

@NonNull
@Override
public AlertDialog create() {
AlertDialog dialog = super.create();
dialog.getWindow().setGravity(Gravity.BOTTOM | Gravity.CENTER);
dialog.getWindow().getAttributes().y = Math.round(getContext().getResources().getDisplayMetrics().density * 15);
return dialog;
}

public BottomAlertDialog setTextInput(String hint, Function<String> listener) {
AppCompatEditText edit = new AppCompatEditText(getContext());
edit.setHint(hint);
int margin = layoutCompat.getPaddingLeft() / 2;
LinearLayoutCompat.LayoutParams params = new LinearLayoutCompat.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(0, margin, 0, margin);
layoutCompat.addView(edit, params);
setPositiveButton(android.R.string.ok, (dialog, which) -> listener.run(String.valueOf(edit.getText())));
setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss());
return this;
}

@Override
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();

return dialog;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
import com.panda3ds.pandroid.R;
import com.panda3ds.pandroid.app.PreferenceActivity;
import com.panda3ds.pandroid.app.base.BasePreferenceFragment;
import com.panda3ds.pandroid.app.preferences.InputMapPreferences;
import com.panda3ds.pandroid.app.preferences.AppearancePreferences;
import com.panda3ds.pandroid.app.preferences.InputPreferences;

public class SettingsFragment extends BasePreferenceFragment {
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
setPreferencesFromResource(R.xml.start_preferences, rootKey);
setItemClick("inputMap", (item) -> PreferenceActivity.launch(requireContext(), InputMapPreferences.class));
setItemClick("input", (item) -> PreferenceActivity.launch(requireContext(), InputPreferences.class));
setItemClick("appearance", (item)-> PreferenceActivity.launch(requireContext(), AppearancePreferences.class));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.panda3ds.pandroid.app.preferences;

import android.app.Activity;
import android.os.Bundle;

import androidx.annotation.Nullable;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.panda3ds.pandroid.app.preferences;

import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.panda3ds.pandroid.R;
import com.panda3ds.pandroid.app.BaseActivity;
import com.panda3ds.pandroid.app.base.BottomAlertDialog;
import com.panda3ds.pandroid.view.controller.mapping.ControllerMapper;
import com.panda3ds.pandroid.view.controller.mapping.ControllerProfileManager;
import com.panda3ds.pandroid.view.controller.mapping.ControllerItem;
import com.panda3ds.pandroid.view.controller.mapping.Profile;

public class ControllerMapperPreferences extends Fragment {
private Profile currentProfile;
private ControllerMapper mapper;
private View saveButton;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.preference_controller_mapper, container, false);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);


currentProfile = ControllerProfileManager.get(getArguments().getString("profile")).clone();

((BaseActivity) requireActivity()).getSupportActionBar().hide();
mapper = view.findViewById(R.id.mapper);
mapper.initialize(this::onLocationChanged, currentProfile);

view.findViewById(R.id.change_visibility).setOnClickListener(v -> {
BottomAlertDialog builder = new BottomAlertDialog(v.getContext());
builder.setTitle("Visibility");
boolean[] visibleList = {
currentProfile.isVisible(ControllerItem.START),
currentProfile.isVisible(ControllerItem.SELECT),
currentProfile.isVisible(ControllerItem.L),
currentProfile.isVisible(ControllerItem.R),
currentProfile.isVisible(ControllerItem.DPAD),
currentProfile.isVisible(ControllerItem.JOYSTICK),
currentProfile.isVisible(ControllerItem.GAMEPAD),
};
builder.setMultiChoiceItems(new CharSequence[]{
"Start", "Select", "L", "R", "Dpad", getString(R.string.axis), "A/B/X/Y"
}, visibleList, (dialog, index, visibility) -> {
visibleList[index] = visibility;
}).setPositiveButton(android.R.string.ok, (dialog, which) -> {

saveButton.setVisibility(View.VISIBLE);

currentProfile.setVisible(ControllerItem.START, visibleList[0]);
currentProfile.setVisible(ControllerItem.SELECT, visibleList[1]);
currentProfile.setVisible(ControllerItem.L, visibleList[2]);
currentProfile.setVisible(ControllerItem.R, visibleList[3]);
currentProfile.setVisible(ControllerItem.DPAD, visibleList[4]);
currentProfile.setVisible(ControllerItem.JOYSTICK, visibleList[5]);
currentProfile.setVisible(ControllerItem.GAMEPAD, visibleList[6]);

mapper.refreshLayout();
}).setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss());
builder.show();
});

saveButton = view.findViewById(R.id.save);
saveButton.setOnClickListener(v -> {
ControllerProfileManager.add(currentProfile);
Toast.makeText(v.getContext(), R.string.saved, Toast.LENGTH_SHORT).show();
requireActivity().finish();
});

view.findViewById(R.id.delete).setOnClickListener(v -> {
ControllerProfileManager.remove(currentProfile.getId());
requireActivity().finish();
});

view.findViewById(R.id.rotate).setOnClickListener(v -> {
requireActivity().setRequestedOrientation(mapper.getCurrentWidth() > mapper.getCurrentHeight() ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
});

view.findViewById(R.id.delete).setVisibility(ControllerProfileManager.getProfileCount() > 1 ? View.VISIBLE : View.GONE);

saveButton.setVisibility(View.GONE);
}

public void onLocationChanged(ControllerItem id) {
saveButton.setVisibility(View.VISIBLE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.panda3ds.pandroid.app.preferences;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

import com.panda3ds.pandroid.R;
import com.panda3ds.pandroid.app.BaseActivity;
import com.panda3ds.pandroid.app.PreferenceActivity;
import com.panda3ds.pandroid.app.base.BasePreferenceFragment;
import com.panda3ds.pandroid.app.base.BottomAlertDialog;
import com.panda3ds.pandroid.view.controller.mapping.ControllerProfileManager;
import com.panda3ds.pandroid.view.controller.mapping.Profile;

import java.util.List;
import java.util.Objects;

public class InputPreferences extends BasePreferenceFragment {

public static final String ID_DEFAULT_CONTROLLER_PROFILE = "defaultControllerProfile";
public static final String ID_INPUT_MAP = "inputMap";
public static final String ID_CREATE_PROFILE = "createProfile";
private static final CharSequence ID_GAMEPAD_PROFILE_LIST = "gamepadProfileList";

@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
setPreferencesFromResource(R.xml.input_preference, rootKey);
setItemClick(ID_INPUT_MAP, (item) -> PreferenceActivity.launch(requireContext(), InputMapPreferences.class));
setItemClick(ID_CREATE_PROFILE, (item) -> {
new BottomAlertDialog(requireContext())
.setTextInput(getString(R.string.name), (name) -> {
name = formatName(name);
if (name.length() > 0) {
Profile profile = ControllerProfileManager.makeDefaultProfile();
profile.setName(name);
ControllerProfileManager.add(profile);
refreshScreenProfileList();
} else {
Toast.makeText(requireContext(), R.string.invalid_name, Toast.LENGTH_SHORT).show();
}
}).setTitle(R.string.create_profile).show();
});

setItemClick(ID_DEFAULT_CONTROLLER_PROFILE, (item) -> {
List<Profile> profiles = ControllerProfileManager.listAll();
String defaultProfileId = ControllerProfileManager.getDefaultProfile().getId();
int defaultProfileIndex = 0;
CharSequence[] names = new CharSequence[profiles.size()];
for (int i = 0; i < names.length; i++) {
names[i] = profiles.get(i).getName();
if (Objects.equals(profiles.get(i).getId(), defaultProfileId)) {
defaultProfileIndex = i;
}
}
new BottomAlertDialog(item.getContext())
.setSingleChoiceItems(names, defaultProfileIndex, (dialog, which) -> {
dialog.dismiss();
ControllerProfileManager.setDefaultProfileId(profiles.get(which).getId());
item.setSummary(profiles.get(which).getName());
}).setTitle(R.string.pref_default_controller_title).show();
});

((BaseActivity) requireActivity()).getSupportActionBar().setTitle(R.string.input);
}

public String formatName(String name) {
return name.trim().replaceAll("\\s\\s", " ");
}

private void refresh() {
findPreference(ID_DEFAULT_CONTROLLER_PROFILE).setSummary(ControllerProfileManager.getDefaultProfile().getName());
refreshScreenProfileList();
}

@SuppressLint("RestrictedApi")
private void refreshScreenProfileList() {
PreferenceCategory category = findPreference(ID_GAMEPAD_PROFILE_LIST);
Preference add = category.getPreference(category.getPreferenceCount() - 1);
category.removeAll();
category.setOrderingAsAdded(true);

for (Profile profile : ControllerProfileManager.listAll()) {
Preference item = new Preference(category.getContext());
item.setOnPreferenceClickListener(preference -> {
category.performClick();
PreferenceActivity.launch(requireActivity(), ControllerMapperPreferences.class, new Intent().putExtra("profile", profile.getId()));
return false;
});
item.setOrder(category.getPreferenceCount());
item.setIconSpaceReserved(false);
item.setTitle(profile.getName());
category.addPreference(item);
}

add.setOrder(category.getPreferenceCount());
category.addPreference(add);
}

@Override
public void onResume() {
super.onResume();
refresh();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.panda3ds.pandroid.data;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.panda3ds.pandroid.lang.Task;
import com.panda3ds.pandroid.utils.FileUtils;

public class GsonConfigParser {
private final Gson gson = new Gson();
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
private final String name;

public GsonConfigParser(String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ public class Constants {
public static final String PREF_GLOBAL_CONFIG = "app.GlobalConfig";
public static final String PREF_GAME_UTILS = "app.GameUtils";
public static final String PREF_INPUT_MAP = "app.InputMap";
public static final String PREF_SCREEN_CONTROLLER_PROFILES = "app.input.ScreenControllerManager";
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@
import com.panda3ds.pandroid.R;
import com.panda3ds.pandroid.utils.Constants;
import com.panda3ds.pandroid.view.controller.ControllerLayout;
import com.panda3ds.pandroid.view.controller.mapping.ControllerProfileManager;
import com.panda3ds.pandroid.view.controller.mapping.ControllerItem;
import com.panda3ds.pandroid.view.controller.mapping.Profile;
import com.panda3ds.pandroid.view.controller.nodes.Button;
import com.panda3ds.pandroid.view.controller.nodes.Joystick;

public class PandaLayoutController extends ControllerLayout {

private int width = -1;
private int height = -1;

public PandaLayoutController(Context context) { super(context); }
public PandaLayoutController(Context context, AttributeSet attrs) { super(context, attrs); }
public PandaLayoutController(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
Expand Down Expand Up @@ -44,5 +51,31 @@ public void initialize() {
});

refreshChildren();
measure(MeasureSpec.EXACTLY, MeasureSpec.EXACTLY);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();

if (measuredWidth != width || measuredHeight != height) {
width = measuredWidth;
height = measuredHeight;
applyProfileMap();
}
}

private void applyProfileMap() {
Profile profile = ControllerProfileManager.getDefaultProfile();

profile.applyToView(ControllerItem.L,findViewById(R.id.button_l), width, height);
profile.applyToView(ControllerItem.R, findViewById(R.id.button_r), width, height);
profile.applyToView(ControllerItem.START, findViewById(R.id.button_start), width, height);
profile.applyToView(ControllerItem.SELECT, findViewById(R.id.button_select), width, height);
profile.applyToView(ControllerItem.JOYSTICK, findViewById(R.id.left_analog), width, height);
profile.applyToView(ControllerItem.GAMEPAD, findViewById(R.id.gamepad), width, height);
profile.applyToView(ControllerItem.DPAD, findViewById(R.id.dpad), width, height);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.panda3ds.pandroid.view.controller.mapping;

public enum ControllerItem {
START,
SELECT,
L,R,
GAMEPAD,
DPAD, JOYSTICK
}
Loading

0 comments on commit c849af4

Please sign in to comment.