Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pandroid: add option to change screen gamepad, buttons position. #359

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading