Merge pull request #14769 from unknownbrackets/ui-ctrl-mapping

Add a visual means of control mapping
This commit is contained in:
Henrik Rydgård 2021-08-29 18:53:49 +02:00 committed by GitHub
commit 06ccadd5d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 469 additions and 14 deletions

View File

@ -311,6 +311,56 @@ void DrawBuffer::DrawImageRotated(ImageID atlas_image, float x, float y, float s
}
}
void DrawBuffer::DrawImageRotatedStretch(ImageID atlas_image, const Bounds &bounds, float scales[2], float angle, Color color, bool mirror_h) {
const AtlasImage *image = atlas->getImage(atlas_image);
if (!image)
return;
if (scales[0] == 0.0f || scales[1] == 0.0f) {
float rotatedSize[2]{ (float)image->w, (float)image->h };
rot(rotatedSize, angle, 0.0f, 0.0f);
// With that, we calculate the scale to stretch to, and rotate it back.
scales[0] = bounds.w / rotatedSize[0];
scales[1] = bounds.h / rotatedSize[1];
rot(scales, -angle, 0.0f, 0.0f);
}
float w = (float)image->w * scales[0];
float h = (float)image->h * scales[1];
float x1 = bounds.centerX() - w / 2;
float x2 = bounds.centerX() + w / 2;
float y1 = bounds.centerY() - h / 2;
float y2 = bounds.centerY() + h / 2;
float v[6][2] = {
{x1, y1},
{x2, y1},
{x2, y2},
{x1, y1},
{x2, y2},
{x1, y2},
};
float u1 = image->u1;
float u2 = image->u2;
if (mirror_h) {
float temp = u1;
u1 = u2;
u2 = temp;
}
const float uv[6][2] = {
{u1, image->v1},
{u2, image->v1},
{u2, image->v2},
{u1, image->v1},
{u2, image->v2},
{u1, image->v2},
};
for (int i = 0; i < 6; i++) {
rot(v[i], angle, bounds.centerX(), bounds.centerY());
V(v[i][0], v[i][1], 0, color, uv[i][0], uv[i][1]);
}
}
// TODO: add arc support
void DrawBuffer::Circle(float xc, float yc, float radius, float thickness, int segments, float startAngle, uint32_t color, float u_mul) {
float angleDelta = PI * 2 / segments;

View File

@ -116,6 +116,7 @@ public:
DrawImageStretch(atlas_image, bounds.x, bounds.y, bounds.x2(), bounds.y2(), color);
}
void DrawImageRotated(ImageID atlas_image, float x, float y, float scale, float angle, Color color = COLOR(0xFFFFFF), bool mirror_h = false); // Always centers
void DrawImageRotatedStretch(ImageID atlas_image, const Bounds &bounds, float scales[2], float angle, Color color = COLOR(0xFFFFFF), bool mirror_h = false);
void DrawTexRect(float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2, Color color);
void DrawTexRect(const Bounds &bounds, float u1, float v1, float u2, float v2, Color color) {
DrawTexRect(bounds.x, bounds.y, bounds.x2(), bounds.y2(), u1, v1, u2, v2, color);

View File

@ -296,6 +296,10 @@ void PopupScreen::SetPopupOrigin(const UI::View *view) {
popupOrigin_ = view->GetBounds().Center();
}
void PopupScreen::SetPopupOffset(float y) {
offsetY_ = y;
}
void PopupScreen::TriggerFinish(DialogResult result) {
if (CanComplete(result)) {
finishFrame_ = frames_;
@ -320,7 +324,7 @@ void PopupScreen::CreateViews() {
float yres = screenManager()->getUIContext()->GetBounds().h;
box_ = new LinearLayout(ORIENT_VERTICAL,
new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, dc.GetBounds().centerX(), dc.GetBounds().centerY(), NONE, NONE, true));
new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true));
root_->Add(box_);
box_->SetBG(dc.theme->popupStyle.background);

View File

@ -81,6 +81,7 @@ public:
virtual void TriggerFinish(DialogResult result) override;
void SetPopupOrigin(const UI::View *view);
void SetPopupOffset(float y);
protected:
virtual bool FillVertical() const { return false; }
@ -109,6 +110,7 @@ private:
DialogResult finishResult_;
bool hasPopupOrigin_ = false;
Point popupOrigin_;
float offsetY_ = 0.0f;
};
class ListPopupScreen : public PopupScreen {

View File

@ -1197,7 +1197,8 @@ void AnchorLayout::Layout() {
if (vBounds.w > bounds_.w) vBounds.w = bounds_.w;
if (vBounds.h > bounds_.h) vBounds.h = bounds_.h;
float left = 0, top = 0, right = 0, bottom = 0, center = false;
float left = 0, top = 0, right = 0, bottom = 0;
bool center = false;
if (params) {
left = params->left;
top = params->top;

View File

@ -43,7 +43,8 @@ namespace KeyMap {
KeyDef AxisDef(int deviceId, int axisId, int direction);
KeyMapping g_controllerMap;
int g_controllerMapGeneration = 0; // Just used to check if we need to update the Windows menu or not.
// Incremented on modification, so we know when to update menus.
int g_controllerMapGeneration = 0;
std::set<std::string> g_seenPads;
std::set<int> g_seenDeviceIds;
@ -622,6 +623,7 @@ void SetAxisMapping(int btn, int deviceId, int axisId, int direction, bool repla
void RestoreDefault() {
g_controllerMap.clear();
g_controllerMapGeneration++;
#if PPSSPP_PLATFORM(WINDOWS)
SetDefaultKeyMap(DEFAULT_MAPPING_KEYBOARD, true);
SetDefaultKeyMap(DEFAULT_MAPPING_XINPUT, false);
@ -765,4 +767,12 @@ void SwapAxis() {
g_swapped_keys = !g_swapped_keys;
}
bool HasChanged(int &prevGeneration) {
if (prevGeneration != g_controllerMapGeneration) {
prevGeneration = g_controllerMapGeneration;
return true;
}
return false;
}
} // KeyMap

View File

@ -158,4 +158,6 @@ namespace KeyMap {
void AutoConfForPad(const std::string &name);
bool IsKeyMapped(int device, int key);
bool HasChanged(int &prevGeneration);
}

View File

@ -19,6 +19,7 @@
#include <algorithm>
#include <deque>
#include <mutex>
#include <unordered_map>
#include "Common/Render/TextureAtlas.h"
#include "Common/UI/Root.h"
@ -242,6 +243,8 @@ void ControlMappingScreen::CreateViews() {
leftColumn->Add(new Choice(km->T("Autoconfigure")))->OnClick.Handle(this, &ControlMappingScreen::OnAutoConfigure);
}
leftColumn->Add(new Choice(km->T("Show PSP")))->OnClick.Handle(this, &ControlMappingScreen::OnVisualizeMapping);
leftColumn->Add(new Spacer(new LinearLayoutParams(1.0f)));
AddStandardBack(leftColumn);
@ -261,17 +264,26 @@ void ControlMappingScreen::CreateViews() {
new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
mappers_.push_back(mapper);
}
keyMapGeneration_ = KeyMap::g_controllerMapGeneration;
}
void ControlMappingScreen::update() {
if (KeyMap::HasChanged(keyMapGeneration_)) {
RecreateViews();
}
UIDialogScreenWithBackground::update();
}
UI::EventReturn ControlMappingScreen::OnClearMapping(UI::EventParams &params) {
KeyMap::g_controllerMap.clear();
RecreateViews();
KeyMap::g_controllerMapGeneration++;
return UI::EVENT_DONE;
}
UI::EventReturn ControlMappingScreen::OnDefaultMapping(UI::EventParams &params) {
KeyMap::RestoreDefault();
RecreateViews();
return UI::EVENT_DONE;
}
@ -289,11 +301,16 @@ UI::EventReturn ControlMappingScreen::OnAutoConfigure(UI::EventParams &params) {
return UI::EVENT_DONE;
}
UI::EventReturn ControlMappingScreen::OnVisualizeMapping(UI::EventParams &params) {
VisualMappingScreen *visualMapping = new VisualMappingScreen();
screenManager()->push(visualMapping);
return UI::EVENT_DONE;
}
void ControlMappingScreen::dialogFinished(const Screen *dialog, DialogResult result) {
if (result == DR_OK && dialog->tag() == "listpopup") {
ListPopupScreen *popup = (ListPopupScreen *)dialog;
KeyMap::AutoConfForPad(popup->GetChoiceString());
RecreateViews();
}
}
@ -325,7 +342,7 @@ bool KeyMappingNewKeyDialog::key(const KeyInput &key) {
mapped_ = true;
KeyDef kdf(key.deviceId, key.keyCode);
TriggerFinish(DR_OK);
TriggerFinish(DR_YES);
if (callback_)
callback_(kdf);
}
@ -352,7 +369,7 @@ bool KeyMappingNewMouseKeyDialog::key(const KeyInput &key) {
mapped_ = true;
KeyDef kdf(key.deviceId, key.keyCode);
TriggerFinish(DR_OK);
TriggerFinish(DR_YES);
g_Config.bMapMouse = false;
if (callback_)
callback_(kdf);
@ -390,7 +407,7 @@ bool KeyMappingNewKeyDialog::axis(const AxisInput &axis) {
if (axis.value > AXIS_BIND_THRESHOLD) {
mapped_ = true;
KeyDef kdf(axis.deviceId, KeyMap::TranslateKeyCodeFromAxis(axis.axisId, 1));
TriggerFinish(DR_OK);
TriggerFinish(DR_YES);
if (callback_)
callback_(kdf);
}
@ -398,7 +415,7 @@ bool KeyMappingNewKeyDialog::axis(const AxisInput &axis) {
if (axis.value < -AXIS_BIND_THRESHOLD) {
mapped_ = true;
KeyDef kdf(axis.deviceId, KeyMap::TranslateKeyCodeFromAxis(axis.axisId, -1));
TriggerFinish(DR_OK);
TriggerFinish(DR_YES);
if (callback_)
callback_(kdf);
}
@ -414,7 +431,7 @@ bool KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) {
if (axis.value > AXIS_BIND_THRESHOLD) {
mapped_ = true;
KeyDef kdf(axis.deviceId, KeyMap::TranslateKeyCodeFromAxis(axis.axisId, 1));
TriggerFinish(DR_OK);
TriggerFinish(DR_YES);
if (callback_)
callback_(kdf);
}
@ -422,7 +439,7 @@ bool KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) {
if (axis.value < -AXIS_BIND_THRESHOLD) {
mapped_ = true;
KeyDef kdf(axis.deviceId, KeyMap::TranslateKeyCodeFromAxis(axis.axisId, -1));
TriggerFinish(DR_OK);
TriggerFinish(DR_YES);
if (callback_)
callback_(kdf);
}
@ -840,3 +857,343 @@ UI::EventReturn TouchTestScreen::OnRecreateActivity(UI::EventParams &e) {
RecreateActivity();
return UI::EVENT_DONE;
}
class Backplate : public UI::InertView {
public:
Backplate(float scale, UI::LayoutParams *layoutParams = nullptr) : InertView(layoutParams), scale_(scale) {
}
void Draw(UIContext &dc) override {
using namespace UI;
const AtlasImage *whiteImage = dc.Draw()->GetAtlas()->getImage(dc.theme->whiteImage);
float centerU = (whiteImage->u1 + whiteImage->u2) * 0.5f;
float centerV = (whiteImage->v1 + whiteImage->v2) * 0.5f;
const uint32_t color = 0xB01C1818;
auto V = [&](float x, float y) {
dc.Draw()->V(bounds_.x + x * scale_, bounds_.y + y * scale_, color, centerU, centerV);
};
auto R = [&](float x1, float y1, float x2, float y2) {
V(x1, y1); V(x2, y1); V(x2, y2);
V(x1, y1); V(x2, y2); V(x1, y2);
};
// Curved left side.
V(12.0f, 44.0f); V(30.0f, 16.0f); V(30.0f, 44.0f);
V(0.0f, 80.0f); V(12.0f, 44.0f); V(12.0f, 80.0f);
R(12.0f, 44.0f, 30.0f, 80.0f);
R(0.0f, 80.0f, 30.0f, 114.0f);
V(0.0f, 114.0f); V(12.0f, 114.0f); V(12.0f, 154.0f);
R(12.0f, 114.0f, 30.0f, 154.0f);
V(12.0f, 154.0f); V(30.0f, 154.0f); V(30.0f, 180.0f);
// Left side.
V(30.0f, 16.0f); V(64.0f, 13.0f); V(64.0f, 184.0f);
V(30.0f, 16.0f); V(64.0f, 184.0f); V(30.0f, 180.0f);
V(64.0f, 13.0f); V(76.0f, 0.0f); V(76.0f, 13.0f);
V(64.0f, 184.0f); V(76.0f, 200.0f); V(76.0f, 184.0f);
R(64.0f, 13.0f, 76.0f, 184.0f);
// Center.
V(76.0f, 0.0f); V(400.0f, 0.0f); V(400.0f, 200.0f);
V(76.0f, 0.0f); V(400.0f, 200.0f); V(76.0f, 200.0f);
// Right side.
V(400.0f, 0.0f); V(412.0f, 13.0f); V(400.0f, 13.0f);
V(400.0f, 184.0f); V(412.0f, 184.0f); V(400.0f, 200.0f);
R(400.0f, 13.0f, 412.0f, 184.0f);
V(412.0f, 13.0f); V(446.0f, 16.0f); V(446.0f, 180.0f);
V(412.0f, 13.0f); V(446.0f, 180.0f); V(412.0f, 184.0f);
// Curved right side.
V(446.0f, 16.0f); V(462.0f, 44.0f); V(446.0f, 44.0f);
V(462.0f, 44.0f); V(474.0f, 80.0f); V(462.0f, 80.0f);
R(446.0f, 44.0f, 462.0f, 80.0f);
R(446.0f, 80.0f, 474.0f, 114.0f);
V(462.0f, 114.0f); V(474.0f, 114.0f); V(462.0f, 154.0f);
R(446.0f, 114.0f, 462.0f, 154.0f);
V(446.0f, 154.0f); V(462.0f, 154.0f); V(446.0f, 180.0f);
}
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override {
w = 474.0f * scale_;
h = 200.0f * scale_;
}
protected:
float scale_ = 1.0f;
};
class MockScreen : public UI::InertView {
public:
MockScreen(UI::LayoutParams *layoutParams = nullptr) : InertView(layoutParams) {
}
void Draw(UIContext &dc) override {
ImageID bg = ImageID("I_BG");
dc.Draw()->DrawImageStretch(bg, bounds_, 0xFFFFFFFF);
if (System_GetPropertyBool(SYSPROP_APP_GOLD)) {
dc.Draw()->DrawImage(ImageID("I_ICONGOLD"), bounds_.centerX() - 120, bounds_.centerY() - 30, 1.2f, 0xFFFFFFFF, ALIGN_CENTER);
} else {
dc.Draw()->DrawImage(ImageID("I_ICON"), bounds_.centerX() - 120, bounds_.centerY() - 30, 1.2f, 0xFFFFFFFF, ALIGN_CENTER);
}
dc.Draw()->DrawImage(ImageID("I_LOGO"), bounds_.centerX() + 40, bounds_.centerY() - 30, 1.5f, 0xFFFFFFFF, ALIGN_CENTER);
}
};
class MockButton : public UI::Clickable {
public:
MockButton(int button, ImageID img, ImageID bg, float angle, UI::LayoutParams *layoutParams = nullptr)
: Clickable(layoutParams), button_(button), img_(img), bgImg_(bg), angle_(angle) {
}
void Draw(UIContext &dc) override {
uint32_t c = 0xFFFFFFFF;
if (HasFocus() || Selected())
c = dc.theme->buttonFocusedStyle.background.color;
float scales[2]{};
if (bgImg_.isValid())
dc.Draw()->DrawImageRotatedStretch(bgImg_, bounds_, scales, angle_, c, flipHBG_);
if (img_.isValid()) {
scales[0] *= scale_;
scales[1] *= scale_;
dc.Draw()->DrawImageRotatedStretch(img_, bounds_.Offset(offsetX_, offsetY_), scales, angle_, c);
}
}
MockButton *SetScale(float s) {
scale_ = s;
return this;
}
MockButton *SetFlipHBG(float f) {
flipHBG_ = f;
return this;
}
MockButton *SetOffset(float x, float y) {
offsetX_ = x;
offsetY_ = y;
return this;
}
MockButton *SetSelectedButton(int *s) {
selectedButton_ = s;
return this;
}
bool Selected() {
return selectedButton_ && *selectedButton_ == button_;
}
int Button() {
return button_;
}
private:
int button_;
ImageID img_;
ImageID bgImg_;
float angle_;
float scale_ = 1.0f;
float offsetX_ = 0.0f;
float offsetY_ = 0.0f;
bool flipHBG_ = false;
int *selectedButton_ = nullptr;
};
class MockPSP : public UI::AnchorLayout {
public:
static constexpr float SCALE = 1.4f;
MockPSP(UI::LayoutParams *layoutParams = nullptr);
void SelectButton(int btn);
float GetPopupOffset();
UI::Event ButtonClick;
private:
UI::AnchorLayoutParams *LayoutAt(float l, float t, float r, float b);
UI::AnchorLayoutParams *LayoutSize(float w, float h, float l, float t);
MockButton *AddButton(int button, ImageID img, ImageID bg, float angle, UI::LayoutParams *lp);
UI::EventReturn OnSelectButton(UI::EventParams &e);
std::unordered_map<int, MockButton *> buttons_;
int selectedButton_ = 0;
};
MockPSP::MockPSP(UI::LayoutParams *layoutParams) : AnchorLayout(layoutParams) {
Add(new Backplate(SCALE));
Add(new MockScreen(LayoutAt(99.0f, 13.0f, 97.0f, 33.0f)));
// Left side.
AddButton(VIRTKEY_AXIS_Y_MAX, ImageID("I_STICK_LINE"), ImageID("I_STICK_BG_LINE"), 0.0f, LayoutSize(34.0f, 34.0f, 35.0f, 133.0f));
AddButton(CTRL_LEFT, ImageID("I_ARROW"), ImageID("I_DIR_LINE"), M_PI * 0.0f, LayoutSize(28.0f, 20.0f, 14.0f, 75.0f))->SetOffset(-4.0f * SCALE, 0.0f);
AddButton(CTRL_UP, ImageID("I_ARROW"), ImageID("I_DIR_LINE"), M_PI * 0.5f, LayoutSize(20.0f, 28.0f, 40.0f, 50.0f))->SetOffset(0.0f, -4.0f * SCALE);
AddButton(CTRL_RIGHT, ImageID("I_ARROW"), ImageID("I_DIR_LINE"), M_PI * 1.0f, LayoutSize(28.0f, 20.0f, 58.0f, 75.0f))->SetOffset(4.0f * SCALE, 0.0f);
AddButton(CTRL_DOWN, ImageID("I_ARROW"), ImageID("I_DIR_LINE"), M_PI * 1.5f, LayoutSize(20.0f, 28.0f, 40.0f, 92.0f))->SetOffset(0.0f, 4.0f * SCALE);
// Top.
AddButton(CTRL_LTRIGGER, ImageID("I_L"), ImageID("I_SHOULDER_LINE"), 0.0f, LayoutSize(50.0f, 16.0f, 29.0f, 0.0f));
AddButton(CTRL_RTRIGGER, ImageID("I_R"), ImageID("I_SHOULDER_LINE"), 0.0f, LayoutSize(50.0f, 16.0f, 397.0f, 0.0f))->SetFlipHBG(true);
// Bottom.
AddButton(CTRL_HOME, ImageID("I_ICON"), ImageID("I_RECT_LINE"), 0.0f, LayoutSize(28.0f, 14.0f, 88.0f, 181.0f))->SetScale(0.4f);
AddButton(CTRL_SELECT, ImageID("I_SELECT"), ImageID("I_RECT_LINE"), 0.0f, LayoutSize(28.0f, 14.0f, 330.0f, 181.0f));
AddButton(CTRL_START, ImageID("I_START"), ImageID("I_RECT_LINE"), 0.0f, LayoutSize(28.0f, 14.0f, 361.0f, 181.0f));
// Right side.
AddButton(CTRL_TRIANGLE, ImageID("I_TRIANGLE"), ImageID("I_ROUND_LINE"), 0.0f, LayoutSize(23.0f, 23.0f, 419.0f, 46.0f))->SetScale(0.7f)->SetOffset(0.0f, -1.0f * SCALE);
AddButton(CTRL_CIRCLE, ImageID("I_CIRCLE"), ImageID("I_ROUND_LINE"), 0.0f, LayoutSize(23.0f, 23.0f, 446.0f, 74.0f))->SetScale(0.7f);
AddButton(CTRL_CROSS, ImageID("I_CROSS"), ImageID("I_ROUND_LINE"), 0.0f, LayoutSize(23.0f, 23.0f, 419.0f, 102.0f))->SetScale(0.7f);
AddButton(CTRL_SQUARE, ImageID("I_SQUARE"), ImageID("I_ROUND_LINE"), 0.0f, LayoutSize(23.0f, 23.0f, 392.0f, 74.0f))->SetScale(0.7f);
}
void MockPSP::SelectButton(int btn) {
selectedButton_ = btn;
}
float MockPSP::GetPopupOffset() {
MockButton *view = buttons_[selectedButton_];
if (!view)
return 0.0f;
float ypos = view->GetBounds().centerY();
if (ypos > bounds_.centerY()) {
return -0.25f;
}
return 0.25f;
}
UI::AnchorLayoutParams *MockPSP::LayoutAt(float l, float t, float r, float b) {
return new UI::AnchorLayoutParams(l * SCALE, t * SCALE, r * SCALE, b * SCALE);
}
UI::AnchorLayoutParams *MockPSP::LayoutSize(float w, float h, float l, float t) {
return new UI::AnchorLayoutParams(w * SCALE, h * SCALE, l * SCALE, t * SCALE, UI::NONE, UI::NONE);
}
MockButton *MockPSP::AddButton(int button, ImageID img, ImageID bg, float angle, UI::LayoutParams *lp) {
MockButton *view = Add(new MockButton(button, img, bg, angle, lp));
view->OnClick.Handle(this, &MockPSP::OnSelectButton);
view->SetSelectedButton(&selectedButton_);
buttons_[button] = view;
return view;
}
UI::EventReturn MockPSP::OnSelectButton(UI::EventParams &e) {
auto view = (MockButton *)e.v;
e.a = view->Button();
return ButtonClick.Dispatch(e);
}
static std::vector<int> bindAllOrder{
CTRL_LTRIGGER,
CTRL_RTRIGGER,
CTRL_UP,
CTRL_DOWN,
CTRL_LEFT,
CTRL_RIGHT,
VIRTKEY_AXIS_Y_MAX,
VIRTKEY_AXIS_Y_MIN,
VIRTKEY_AXIS_X_MIN,
VIRTKEY_AXIS_X_MAX,
CTRL_HOME,
CTRL_SELECT,
CTRL_START,
CTRL_CROSS,
CTRL_CIRCLE,
CTRL_TRIANGLE,
CTRL_SQUARE,
};
void VisualMappingScreen::CreateViews() {
using namespace UI;
auto km = GetI18NCategory("KeyMapping");
root_ = new LinearLayout(ORIENT_HORIZONTAL);
constexpr float leftColumnWidth = 200.0f;
LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(leftColumnWidth, FILL_PARENT, Margins(10, 0, 0, 10)));
leftColumn->Add(new Choice(km->T("Bind All")))->OnClick.Handle(this, &VisualMappingScreen::OnBindAll);
leftColumn->Add(new CheckBox(&replace_, km->T("Replace"), ""));
leftColumn->Add(new Spacer(new LinearLayoutParams(1.0f)));
AddStandardBack(leftColumn);
Bounds bounds = screenManager()->getUIContext()->GetLayoutBounds();
// Account for left side.
bounds.w -= leftColumnWidth + 10.0f;
AnchorLayout *rightColumn = new AnchorLayout(new LinearLayoutParams(bounds.w, FILL_PARENT, 1.0f));
psp_ = rightColumn->Add(new MockPSP(new AnchorLayoutParams(bounds.centerX(), bounds.centerY(), NONE, NONE, true)));
psp_->ButtonClick.Handle(this, &VisualMappingScreen::OnMapButton);
root_->Add(leftColumn);
root_->Add(rightColumn);
}
void VisualMappingScreen::resized() {
UIDialogScreenWithBackground::resized();
RecreateViews();
}
UI::EventReturn VisualMappingScreen::OnMapButton(UI::EventParams &e) {
nextKey_ = e.a;
MapNext();
return UI::EVENT_DONE;
}
UI::EventReturn VisualMappingScreen::OnBindAll(UI::EventParams &e) {
bindAll_ = 0;
nextKey_ = bindAllOrder[bindAll_];
MapNext();
return UI::EVENT_DONE;
}
void VisualMappingScreen::HandleKeyMapping(KeyDef key) {
KeyMap::SetKeyMapping(nextKey_, key, replace_);
if (bindAll_ < 0) {
// For analog, we do each direction in a row.
if (nextKey_ == VIRTKEY_AXIS_Y_MAX)
nextKey_ = VIRTKEY_AXIS_Y_MIN;
else if (nextKey_ == VIRTKEY_AXIS_Y_MIN)
nextKey_ = VIRTKEY_AXIS_X_MIN;
else if (nextKey_ == VIRTKEY_AXIS_X_MIN)
nextKey_ = VIRTKEY_AXIS_X_MAX;
else
nextKey_ = 0;
} else if ((size_t)bindAll_ + 1 < bindAllOrder.size()) {
bindAll_++;
nextKey_ = bindAllOrder[bindAll_];
} else {
bindAll_ = -1;
nextKey_ = 0;
}
}
void VisualMappingScreen::dialogFinished(const Screen *dialog, DialogResult result) {
if (result == DR_YES && nextKey_ != 0) {
MapNext();
} else {
nextKey_ = 0;
bindAll_ = -1;
psp_->SelectButton(0);
}
}
void VisualMappingScreen::MapNext() {
auto km = GetI18NCategory("KeyMapping");
if (nextKey_ == VIRTKEY_AXIS_Y_MIN || nextKey_ == VIRTKEY_AXIS_X_MIN || nextKey_ == VIRTKEY_AXIS_X_MAX) {
psp_->SelectButton(VIRTKEY_AXIS_Y_MAX);
} else {
psp_->SelectButton(nextKey_);
}
auto dialog = new KeyMappingNewKeyDialog(nextKey_, true, std::bind(&VisualMappingScreen::HandleKeyMapping, this, std::placeholders::_1), km);
Bounds bounds = screenManager()->getUIContext()->GetLayoutBounds();
dialog->SetPopupOffset(psp_->GetPopupOffset() * bounds.h);
screenManager()->push(dialog);
}

View File

@ -39,16 +39,20 @@ public:
std::string tag() const override { return "control mapping"; }
protected:
virtual void CreateViews() override;
void CreateViews() override;
void update() override;
private:
UI::EventReturn OnDefaultMapping(UI::EventParams &params);
UI::EventReturn OnClearMapping(UI::EventParams &params);
UI::EventReturn OnAutoConfigure(UI::EventParams &params);
UI::EventReturn OnVisualizeMapping(UI::EventParams &params);
virtual void dialogFinished(const Screen *dialog, DialogResult result) override;
UI::ScrollView *rightScroll_;
std::vector<SingleControlMapper *> mappers_;
int keyMapGeneration_ = -1;
};
class KeyMappingNewKeyDialog : public PopupScreen {
@ -158,3 +162,27 @@ protected:
UI::EventReturn OnRenderingBackend(UI::EventParams &e);
UI::EventReturn OnRecreateActivity(UI::EventParams &e);
};
class MockPSP;
class VisualMappingScreen : public UIDialogScreenWithBackground {
public:
VisualMappingScreen() {}
protected:
void CreateViews() override;
void dialogFinished(const Screen *dialog, DialogResult result) override;
void resized() override;
private:
UI::EventReturn OnMapButton(UI::EventParams &e);
UI::EventReturn OnBindAll(UI::EventParams &e);
void HandleKeyMapping(KeyDef key);
void MapNext();
MockPSP *psp_ = nullptr;
int nextKey_ = 0;
int bindAll_ = -1;
bool replace_ = false;
};

View File

@ -351,7 +351,7 @@ namespace MainWindow {
bool changed = false;
const std::string curLanguageID = i18nrepo.LanguageID();
if (curLanguageID != menuLanguageID || menuKeymapGeneration != KeyMap::g_controllerMapGeneration) {
if (curLanguageID != menuLanguageID || KeyMap::HasChanged(menuKeymapGeneration)) {
DoTranslateMenus(hWnd, menu);
menuLanguageID = curLanguageID;
changed = true;