mirror of https://github.com/mgba-emu/mgba.git
Qt: Revamp actions
This commit is contained in:
parent
609d5314ec
commit
bf8fde59c6
|
@ -0,0 +1,106 @@
|
|||
/* Copyright (c) 2013-2018 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "Action.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
Action::Action(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Action::Action(Function function, const QString& name, const QString& visibleName, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_function(function)
|
||||
, m_name(name)
|
||||
, m_visibleName(visibleName)
|
||||
{
|
||||
}
|
||||
|
||||
Action::Action(Action::BooleanFunction function, const QString& name, const QString& visibleName, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_booleanFunction(function)
|
||||
, m_name(name)
|
||||
, m_visibleName(visibleName)
|
||||
{
|
||||
}
|
||||
|
||||
Action::Action(const QString& name, const QString& visibleName, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_name(name)
|
||||
, m_visibleName(visibleName)
|
||||
{
|
||||
}
|
||||
|
||||
Action::Action(const Action& other)
|
||||
: QObject(other.parent())
|
||||
, m_enabled(other.m_enabled)
|
||||
, m_active(other.m_active)
|
||||
, m_function(other.m_function)
|
||||
, m_booleanFunction(other.m_booleanFunction)
|
||||
, m_name(other.m_name)
|
||||
, m_visibleName(other.m_visibleName)
|
||||
{
|
||||
}
|
||||
|
||||
Action::Action(Action& other)
|
||||
: QObject(other.parent())
|
||||
, m_enabled(other.m_enabled)
|
||||
, m_active(other.m_active)
|
||||
, m_function(other.m_function)
|
||||
, m_booleanFunction(other.m_booleanFunction)
|
||||
, m_name(other.m_name)
|
||||
, m_visibleName(other.m_visibleName)
|
||||
{
|
||||
}
|
||||
|
||||
void Action::connect(Function func) {
|
||||
m_booleanFunction = {};
|
||||
m_function = func;
|
||||
}
|
||||
|
||||
void Action::trigger(bool active) {
|
||||
if (!m_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_function && active) {
|
||||
m_function();
|
||||
}
|
||||
if (m_booleanFunction) {
|
||||
m_booleanFunction(active);
|
||||
}
|
||||
|
||||
m_active = active;
|
||||
emit activated(active);
|
||||
}
|
||||
|
||||
void Action::setEnabled(bool e) {
|
||||
if (m_enabled == e) {
|
||||
return;
|
||||
}
|
||||
m_enabled = e;
|
||||
emit enabled(e);
|
||||
}
|
||||
|
||||
void Action::setActive(bool a) {
|
||||
if (m_active == a) {
|
||||
return;
|
||||
}
|
||||
m_active = a;
|
||||
emit activated(a);
|
||||
}
|
||||
|
||||
Action& Action::operator=(const Action& other) {
|
||||
setParent(other.parent());
|
||||
m_enabled = other.m_enabled;
|
||||
m_active = other.m_active;
|
||||
m_function = other.m_function;
|
||||
m_booleanFunction = other.m_booleanFunction;
|
||||
m_name = other.m_name;
|
||||
m_visibleName = other.m_visibleName;
|
||||
return *this;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* Copyright (c) 2013-2018 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class Action : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef std::function<void ()> Function;
|
||||
typedef std::function<void (bool)> BooleanFunction;
|
||||
|
||||
Action(Function, const QString& name, const QString& visibleName, QObject* parent = nullptr);
|
||||
Action(BooleanFunction, const QString& name, const QString& visibleName, QObject* parent = nullptr);
|
||||
Action(const QString& name, const QString& visibleName, QObject* parent = nullptr);
|
||||
|
||||
Action(QObject* parent = nullptr);
|
||||
Action(Action&);
|
||||
Action(const Action&);
|
||||
|
||||
Function action() const { return m_function; }
|
||||
BooleanFunction booleanAction() const { return m_booleanFunction; }
|
||||
|
||||
const QString& name() const { return m_name; }
|
||||
const QString& visibleName() const { return m_visibleName; }
|
||||
|
||||
bool operator==(const Action& other) const {
|
||||
if (m_name.isNull()) {
|
||||
return this == &other;
|
||||
}
|
||||
return m_name == other.m_name;
|
||||
}
|
||||
|
||||
void connect(Function);
|
||||
|
||||
bool isEnabled() const { return m_enabled; }
|
||||
bool isActive() const { return m_active; }
|
||||
bool isExclusive() const { return m_exclusive; }
|
||||
|
||||
void setExclusive(bool exclusive = true) { m_exclusive = exclusive; }
|
||||
|
||||
Action& operator=(const Action&);
|
||||
|
||||
public slots:
|
||||
void trigger(bool = true);
|
||||
void setEnabled(bool = true);
|
||||
void setActive(bool = true);
|
||||
|
||||
signals:
|
||||
void enabled(bool);
|
||||
void activated(bool);
|
||||
|
||||
private:
|
||||
bool m_enabled = true;
|
||||
bool m_active = false;
|
||||
bool m_exclusive = false;
|
||||
|
||||
Function m_function;
|
||||
BooleanFunction m_booleanFunction;
|
||||
|
||||
QString m_name;
|
||||
QString m_visibleName;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/* Copyright (c) 2013-2018 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "ActionMapper.h"
|
||||
|
||||
#include "ConfigController.h"
|
||||
#include "ShortcutController.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
void ActionMapper::addMenu(const QString& visibleName, const QString& name, const QString& parent) {
|
||||
QString mname(QString(".%1").arg(name));
|
||||
m_menus[parent].append(mname);
|
||||
m_reverseMenus[mname] = parent;
|
||||
m_menuNames[name] = visibleName;
|
||||
}
|
||||
|
||||
void ActionMapper::addHiddenMenu(const QString& visibleName, const QString& name, const QString& parent) {
|
||||
m_hiddenActions.insert(QString(".%1").arg(name));
|
||||
addMenu(visibleName, name, parent);
|
||||
}
|
||||
|
||||
void ActionMapper::clearMenu(const QString& name) {
|
||||
m_menus[name].clear();
|
||||
emit menuCleared(name);
|
||||
}
|
||||
|
||||
void ActionMapper::rebuildMenu(QMenuBar* menubar, const ShortcutController& shortcuts) {
|
||||
menubar->clear();
|
||||
for (const QString& m : m_menus[{}]) {
|
||||
if (m_hiddenActions.contains(m)) {
|
||||
continue;
|
||||
}
|
||||
QString menu = m.mid(1);
|
||||
QMenu* qmenu = menubar->addMenu(m_menuNames[menu]);
|
||||
|
||||
rebuildMenu(menu, qmenu, shortcuts);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, const ShortcutController& shortcuts) {
|
||||
for (const QString& actionName : m_menus[menu]) {
|
||||
if (actionName.isNull()) {
|
||||
qmenu->addSeparator();
|
||||
continue;
|
||||
}
|
||||
if (m_hiddenActions.contains(actionName)) {
|
||||
continue;
|
||||
}
|
||||
if (actionName[0] == '.') {
|
||||
QString name = actionName.mid(1);
|
||||
QMenu* newMenu = qmenu->addMenu(m_menuNames[name]);
|
||||
rebuildMenu(name, newMenu, shortcuts);
|
||||
continue;
|
||||
}
|
||||
Action* action = &m_actions[actionName];
|
||||
QAction* qaction = qmenu->addAction(action->visibleName());
|
||||
qaction->setEnabled(action->isEnabled());
|
||||
if (action->isExclusive() || action->booleanAction()) {
|
||||
qaction->setCheckable(true);
|
||||
}
|
||||
if (action->isActive()) {
|
||||
qaction->setChecked(true);
|
||||
}
|
||||
const Shortcut* shortcut = shortcuts.shortcut(actionName);
|
||||
if (shortcut && shortcut->shortcut() > 0) {
|
||||
qaction->setShortcut(QKeySequence(shortcut->shortcut()));
|
||||
} else if (!m_defaultShortcuts[actionName].isEmpty()) {
|
||||
qaction->setShortcut(m_defaultShortcuts[actionName][0]);
|
||||
}
|
||||
QObject::connect(qaction, &QAction::triggered, [qaction, action](bool enabled) {
|
||||
if (qaction->isCheckable()) {
|
||||
action->trigger(enabled);
|
||||
} else {
|
||||
action->trigger();
|
||||
}
|
||||
});
|
||||
QObject::connect(action, &Action::enabled, qaction, &QAction::setEnabled);
|
||||
QObject::connect(action, &Action::activated, qaction, &QAction::setChecked);
|
||||
QObject::connect(action, &Action::destroyed, qaction, &QAction::deleteLater);
|
||||
if (shortcut) {
|
||||
QObject::connect(shortcut, &Shortcut::shortcutChanged, qaction, [qaction](int shortcut) {
|
||||
qaction->setShortcut(QKeySequence(shortcut));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActionMapper::addSeparator(const QString& menu) {
|
||||
m_menus[menu].append(QString{});
|
||||
}
|
||||
|
||||
Action* ActionMapper::addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut) {
|
||||
m_actions.insert(name, act);
|
||||
m_reverseMenus[name] = menu;
|
||||
m_menus[menu].append(name);
|
||||
if (!shortcut.isEmpty()) {
|
||||
m_defaultShortcuts[name] = shortcut;
|
||||
}
|
||||
emit actionAdded(name);
|
||||
|
||||
return &m_actions[name];
|
||||
}
|
||||
|
||||
Action* ActionMapper::addAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu, const QKeySequence& shortcut) {
|
||||
return addAction(Action(action, name, visibleName), name, menu, shortcut);
|
||||
}
|
||||
|
||||
Action* ActionMapper::addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu) {
|
||||
return addAction(Action([option, variant]() {
|
||||
option->setValue(variant);
|
||||
}, option->name(), visibleName), QString("%1.%2").arg(option->name()).arg(variant.toString()), menu, {});
|
||||
}
|
||||
|
||||
Action* ActionMapper::addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu, const QKeySequence& shortcut) {
|
||||
return addAction(Action(action, name, visibleName), name, menu, shortcut);
|
||||
}
|
||||
|
||||
Action* ActionMapper::addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu) {
|
||||
return addAction(Action([option](bool value) {
|
||||
option->setValue(value);
|
||||
}, option->name(), visibleName), option->name(), menu, {});
|
||||
}
|
||||
|
||||
Action* ActionMapper::addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu, const QKeySequence& shortcut) {
|
||||
m_hiddenActions.insert(name);
|
||||
m_heldActions.insert(name);
|
||||
return addBooleanAction(visibleName, name, action, menu, shortcut);
|
||||
}
|
||||
|
||||
Action* ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu, const QKeySequence& shortcut) {
|
||||
m_hiddenActions.insert(name);
|
||||
return addAction(visibleName, name, action, menu, shortcut);
|
||||
}
|
||||
|
||||
QStringList ActionMapper::menuItems(const QString& menu) const {
|
||||
return m_menus[menu];
|
||||
}
|
||||
|
||||
QString ActionMapper::menuFor(const QString& menu) const {
|
||||
return m_reverseMenus[menu];
|
||||
}
|
||||
|
||||
QString ActionMapper::menuName(const QString& menu) const {
|
||||
if (!menu.isNull() && menu[0] == '.') {
|
||||
return m_menuNames[menu.mid(1)];
|
||||
}
|
||||
return m_menuNames[menu];
|
||||
}
|
||||
|
||||
Action* ActionMapper::getAction(const QString& itemName) {
|
||||
return &m_actions[itemName];
|
||||
}
|
||||
|
||||
QKeySequence ActionMapper::defaultShortcut(const QString& itemName) {
|
||||
return m_defaultShortcuts[itemName];
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* Copyright (c) 2013-2018 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QKeySequence>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
#include <functional>
|
||||
|
||||
class QMenu;
|
||||
class QMenuBar;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class ConfigOption;
|
||||
class ShortcutController;
|
||||
|
||||
class ActionMapper : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void addMenu(const QString& visibleName, const QString& name, const QString& parent = {});
|
||||
void addHiddenMenu(const QString& visibleName, const QString& name, const QString& parent = {});
|
||||
void clearMenu(const QString& name);
|
||||
void rebuildMenu(QMenuBar*, const ShortcutController&);
|
||||
|
||||
void addSeparator(const QString& menu);
|
||||
|
||||
Action* addAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {});
|
||||
template<typename T, typename V> Action* addAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu = {}, const QKeySequence& = {});
|
||||
Action* addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu = {});
|
||||
|
||||
Action* addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {});
|
||||
Action* addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu = {});
|
||||
|
||||
Action* addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {});
|
||||
|
||||
Action* addHiddenAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {});
|
||||
template<typename T, typename V> Action* addHiddenAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu = {}, const QKeySequence& = {});
|
||||
|
||||
bool isHeld(const QString& name) const { return m_heldActions.contains(name); }
|
||||
|
||||
QStringList menuItems(const QString& menu = QString()) const;
|
||||
QString menuFor(const QString& action) const;
|
||||
QString menuName(const QString& menu) const;
|
||||
|
||||
Action* getAction(const QString& action);
|
||||
QKeySequence defaultShortcut(const QString& action);
|
||||
|
||||
signals:
|
||||
void actionAdded(const QString& name);
|
||||
void menuCleared(const QString& name);
|
||||
|
||||
private:
|
||||
void rebuildMenu(const QString& menu, QMenu* qmenu, const ShortcutController&);
|
||||
Action* addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut);
|
||||
|
||||
QHash<QString, Action> m_actions;
|
||||
QHash<QString, QStringList> m_menus;
|
||||
QHash<QString, QString> m_reverseMenus;
|
||||
QHash<QString, QString> m_menuNames;
|
||||
QHash<QString, QKeySequence> m_defaultShortcuts;
|
||||
QSet<QString> m_hiddenActions;
|
||||
QSet<QString> m_heldActions;
|
||||
};
|
||||
|
||||
template<typename T, typename V>
|
||||
Action* ActionMapper::addAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) {
|
||||
return addAction(visibleName, name, std::bind(method, obj), menu, shortcut);
|
||||
}
|
||||
|
||||
template<typename T, typename V>
|
||||
Action* ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) {
|
||||
m_hiddenActions.insert(name);
|
||||
return addAction(visibleName, name, obj, method, menu, shortcut);
|
||||
}
|
||||
|
||||
}
|
|
@ -67,6 +67,8 @@ endif()
|
|||
set(SOURCE_FILES
|
||||
AboutScreen.cpp
|
||||
AbstractUpdater.cpp
|
||||
Action.cpp
|
||||
ActionMapper.cpp
|
||||
AssetTile.cpp
|
||||
AssetView.cpp
|
||||
AudioProcessor.cpp
|
||||
|
@ -111,6 +113,7 @@ set(SOURCE_FILES
|
|||
SettingsView.cpp
|
||||
ShaderSelector.cpp
|
||||
ShortcutController.cpp
|
||||
ShortcutModel.cpp
|
||||
ShortcutView.cpp
|
||||
Swatch.cpp
|
||||
TilePainter.cpp
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "ConfigController.h"
|
||||
|
||||
#include "ActionMapper.h"
|
||||
#include "CoreController.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QDir>
|
||||
#include <QMenu>
|
||||
|
||||
|
@ -15,51 +15,58 @@
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
ConfigOption::ConfigOption(QObject* parent)
|
||||
ConfigOption::ConfigOption(const QString& name, QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigOption::connect(std::function<void(const QVariant&)> slot, QObject* parent) {
|
||||
m_slots[parent] = slot;
|
||||
QObject::connect(parent, &QAction::destroyed, [this, slot, parent]() {
|
||||
QObject::connect(parent, &QObject::destroyed, [this, slot, parent]() {
|
||||
m_slots.remove(parent);
|
||||
});
|
||||
}
|
||||
|
||||
QAction* ConfigOption::addValue(const QString& text, const QVariant& value, QMenu* parent) {
|
||||
QAction* action = new QAction(text, parent);
|
||||
action->setCheckable(true);
|
||||
QObject::connect(action, &QAction::triggered, [this, value]() {
|
||||
Action* ConfigOption::addValue(const QString& text, const QVariant& value, ActionMapper* actions, const QString& menu) {
|
||||
Action* action;
|
||||
auto function = [this, value]() {
|
||||
emit valueChanged(value);
|
||||
});
|
||||
if (parent) {
|
||||
QObject::connect(parent, &QAction::destroyed, [this, action, value]() {
|
||||
m_actions.removeAll(qMakePair(action, value));
|
||||
});
|
||||
parent->addAction(action);
|
||||
};
|
||||
QString name = QString("%1.%2").arg(m_name).arg(value.toString());
|
||||
if (actions) {
|
||||
action = actions->addAction(text, name, function, menu);
|
||||
} else {
|
||||
action = new Action(function, name, text);
|
||||
}
|
||||
m_actions.append(qMakePair(action, value));
|
||||
action->setExclusive();
|
||||
QObject::connect(action, &QObject::destroyed, [this, action, value]() {
|
||||
m_actions.removeAll(std::make_pair(action, value));
|
||||
});
|
||||
m_actions.append(std::make_pair(action, value));
|
||||
return action;
|
||||
}
|
||||
|
||||
QAction* ConfigOption::addValue(const QString& text, const char* value, QMenu* parent) {
|
||||
return addValue(text, QString(value), parent);
|
||||
Action* ConfigOption::addValue(const QString& text, const char* value, ActionMapper* actions, const QString& menu) {
|
||||
return addValue(text, QString(value), actions, menu);
|
||||
}
|
||||
|
||||
QAction* ConfigOption::addBoolean(const QString& text, QMenu* parent) {
|
||||
QAction* action = new QAction(text, parent);
|
||||
action->setCheckable(true);
|
||||
QObject::connect(action, &QAction::triggered, [this, action]() {
|
||||
emit valueChanged(action->isChecked());
|
||||
});
|
||||
if (parent) {
|
||||
QObject::connect(parent, &QAction::destroyed, [this, action]() {
|
||||
m_actions.removeAll(qMakePair(action, 1));
|
||||
});
|
||||
parent->addAction(action);
|
||||
Action* ConfigOption::addBoolean(const QString& text, ActionMapper* actions, const QString& menu) {
|
||||
Action* action;
|
||||
auto function = [this](bool value) {
|
||||
emit valueChanged(value);
|
||||
};
|
||||
if (actions) {
|
||||
action = actions->addBooleanAction(text, m_name, function, menu);
|
||||
} else {
|
||||
action = new Action(function, m_name, text);
|
||||
}
|
||||
m_actions.append(qMakePair(action, 1));
|
||||
|
||||
QObject::connect(action, &QObject::destroyed, [this, action]() {
|
||||
m_actions.removeAll(std::make_pair(action, 1));
|
||||
});
|
||||
m_actions.append(std::make_pair(action, 1));
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
|
@ -80,10 +87,8 @@ void ConfigOption::setValue(const char* value) {
|
|||
}
|
||||
|
||||
void ConfigOption::setValue(const QVariant& value) {
|
||||
for (QPair<QAction*, QVariant>& action : m_actions) {
|
||||
bool signalsEnabled = action.first->blockSignals(true);
|
||||
action.first->setChecked(value == action.second);
|
||||
action.first->blockSignals(signalsEnabled);
|
||||
for (std::pair<Action*, QVariant>& action : m_actions) {
|
||||
action.first->setActive(value == action.second);
|
||||
}
|
||||
for (std::function<void(const QVariant&)>& slot : m_slots.values()) {
|
||||
slot(value);
|
||||
|
@ -142,7 +147,7 @@ ConfigOption* ConfigController::addOption(const char* key) {
|
|||
if (m_optionSet.contains(optionName)) {
|
||||
return m_optionSet[optionName];
|
||||
}
|
||||
ConfigOption* newOption = new ConfigOption(this);
|
||||
ConfigOption* newOption = new ConfigOption(optionName, this);
|
||||
m_optionSet[optionName] = newOption;
|
||||
connect(newOption, &ConfigOption::valueChanged, [this, key](const QVariant& value) {
|
||||
setOption(key, value);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <mgba-util/configuration.h>
|
||||
#include <mgba/feature/commandline.h>
|
||||
|
||||
class QAction;
|
||||
class QMenu;
|
||||
|
||||
struct mArguments;
|
||||
|
@ -26,17 +25,22 @@ struct GBACartridgeOverride;
|
|||
|
||||
namespace QGBA {
|
||||
|
||||
class Action;
|
||||
class ActionMapper;
|
||||
|
||||
class ConfigOption : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ConfigOption(QObject* parent = nullptr);
|
||||
ConfigOption(const QString& name, QObject* parent = nullptr);
|
||||
|
||||
void connect(std::function<void(const QVariant&)>, QObject* parent = nullptr);
|
||||
|
||||
QAction* addValue(const QString& text, const QVariant& value, QMenu* parent = nullptr);
|
||||
QAction* addValue(const QString& text, const char* value, QMenu* parent = nullptr);
|
||||
QAction* addBoolean(const QString& text, QMenu* parent = nullptr);
|
||||
Action* addValue(const QString& text, const QVariant& value, ActionMapper* actions = nullptr, const QString& menu = {});
|
||||
Action* addValue(const QString& text, const char* value, ActionMapper* actions = nullptr, const QString& menu = {});
|
||||
Action* addBoolean(const QString& text, ActionMapper* actions = nullptr, const QString& menu = {});
|
||||
|
||||
QString name() const { return m_name; }
|
||||
|
||||
public slots:
|
||||
void setValue(bool value);
|
||||
|
@ -50,7 +54,8 @@ signals:
|
|||
|
||||
private:
|
||||
QMap<QObject*, std::function<void(const QVariant&)>> m_slots;
|
||||
QList<QPair<QAction*, QVariant>> m_actions;
|
||||
QList<std::pair<Action*, QVariant>> m_actions;
|
||||
QString m_name;
|
||||
};
|
||||
|
||||
class ConfigController : public QObject {
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
#include <QAction>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QRegularExpression>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
ShortcutController::ShortcutController(QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -24,202 +25,27 @@ void ShortcutController::setConfigController(ConfigController* controller) {
|
|||
m_config = controller;
|
||||
}
|
||||
|
||||
QVariant ShortcutController::data(const QModelIndex& index, int role) const {
|
||||
if (role != Qt::DisplayRole || !index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
int row = index.row();
|
||||
const ShortcutItem* item = static_cast<const ShortcutItem*>(index.internalPointer());
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return item->visibleName();
|
||||
case 1:
|
||||
return QKeySequence(item->shortcut()).toString(QKeySequence::NativeText);
|
||||
case 2:
|
||||
if (item->button() >= 0) {
|
||||
return item->button();
|
||||
}
|
||||
if (item->axis() >= 0) {
|
||||
char d = '\0';
|
||||
if (item->direction() == GamepadAxisEvent::POSITIVE) {
|
||||
d = '+';
|
||||
}
|
||||
if (item->direction() == GamepadAxisEvent::NEGATIVE) {
|
||||
d = '-';
|
||||
}
|
||||
return QString("%1%2").arg(d).arg(item->axis());
|
||||
}
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
void ShortcutController::setActionMapper(ActionMapper* actions) {
|
||||
m_actions = actions;
|
||||
connect(actions, &ActionMapper::actionAdded, this, &ShortcutController::generateItem);
|
||||
connect(actions, &ActionMapper::menuCleared, this, &ShortcutController::menuCleared);
|
||||
rebuildItems();
|
||||
}
|
||||
|
||||
QVariant ShortcutController::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
if (orientation == Qt::Horizontal) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Action");
|
||||
case 1:
|
||||
return tr("Keyboard");
|
||||
case 2:
|
||||
return tr("Gamepad");
|
||||
}
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
QModelIndex ShortcutController::index(int row, int column, const QModelIndex& parent) const {
|
||||
const ShortcutItem* pmenu = &m_rootMenu;
|
||||
if (parent.isValid()) {
|
||||
pmenu = static_cast<ShortcutItem*>(parent.internalPointer());
|
||||
}
|
||||
return createIndex(row, column, const_cast<ShortcutItem*>(&pmenu->items()[row]));
|
||||
}
|
||||
|
||||
QModelIndex ShortcutController::parent(const QModelIndex& index) const {
|
||||
if (!index.isValid() || !index.internalPointer()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
ShortcutItem* item = static_cast<ShortcutItem*>(index.internalPointer());
|
||||
if (!item->parent() || !item->parent()->parent()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(item->parent()->parent()->items().indexOf(*item->parent()), 0, item->parent());
|
||||
}
|
||||
|
||||
int ShortcutController::columnCount(const QModelIndex& index) const {
|
||||
return 3;
|
||||
}
|
||||
|
||||
int ShortcutController::rowCount(const QModelIndex& index) const {
|
||||
if (!index.isValid()) {
|
||||
return m_rootMenu.items().count();
|
||||
}
|
||||
const ShortcutItem* item = static_cast<const ShortcutItem*>(index.internalPointer());
|
||||
return item->items().count();
|
||||
}
|
||||
|
||||
void ShortcutController::addAction(QMenu* menu, QAction* action, const QString& name) {
|
||||
ShortcutItem* smenu = m_menuMap[menu];
|
||||
if (!smenu) {
|
||||
return;
|
||||
}
|
||||
ShortcutItem* pmenu = smenu->parent();
|
||||
int row = pmenu->items().indexOf(*smenu);
|
||||
QModelIndex parent = createIndex(row, 0, smenu);
|
||||
beginInsertRows(parent, smenu->items().count(), smenu->items().count());
|
||||
smenu->addAction(action, name);
|
||||
endInsertRows();
|
||||
ShortcutItem* item = &smenu->items().last();
|
||||
if (m_config) {
|
||||
loadShortcuts(item);
|
||||
}
|
||||
emit dataChanged(createIndex(smenu->items().count() - 1, 0, item),
|
||||
createIndex(smenu->items().count() - 1, 2, item));
|
||||
}
|
||||
|
||||
void ShortcutController::addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
|
||||
int shortcut, const QString& visibleName, const QString& name) {
|
||||
ShortcutItem* smenu = m_menuMap[menu];
|
||||
if (!smenu) {
|
||||
return;
|
||||
}
|
||||
ShortcutItem* pmenu = smenu->parent();
|
||||
int row = pmenu->items().indexOf(*smenu);
|
||||
QModelIndex parent = createIndex(row, 0, smenu);
|
||||
beginInsertRows(parent, smenu->items().count(), smenu->items().count());
|
||||
smenu->addFunctions(qMakePair(press, release), shortcut, visibleName, name);
|
||||
endInsertRows();
|
||||
ShortcutItem* item = &smenu->items().last();
|
||||
bool loadedShortcut = false;
|
||||
if (m_config) {
|
||||
loadedShortcut = loadShortcuts(item);
|
||||
}
|
||||
if (!loadedShortcut && !m_heldKeys.contains(shortcut)) {
|
||||
m_heldKeys[shortcut] = item;
|
||||
}
|
||||
emit dataChanged(createIndex(smenu->items().count() - 1, 0, item),
|
||||
createIndex(smenu->items().count() - 1, 2, item));
|
||||
}
|
||||
|
||||
void ShortcutController::addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
|
||||
const QKeySequence& shortcut, const QString& visibleName, const QString& name) {
|
||||
addFunctions(menu, press, release, shortcut[0], visibleName, name);
|
||||
}
|
||||
|
||||
void ShortcutController::addMenu(QMenu* menu, QMenu* parentMenu) {
|
||||
ShortcutItem* smenu = m_menuMap[parentMenu];
|
||||
if (!smenu) {
|
||||
smenu = &m_rootMenu;
|
||||
}
|
||||
QModelIndex parent;
|
||||
ShortcutItem* pmenu = smenu->parent();
|
||||
if (pmenu) {
|
||||
int row = pmenu->items().indexOf(*smenu);
|
||||
parent = createIndex(row, 0, smenu);
|
||||
}
|
||||
beginInsertRows(parent, smenu->items().count(), smenu->items().count());
|
||||
smenu->addSubmenu(menu);
|
||||
endInsertRows();
|
||||
ShortcutItem* item = &smenu->items().last();
|
||||
emit dataChanged(createIndex(smenu->items().count() - 1, 0, item),
|
||||
createIndex(smenu->items().count() - 1, 2, item));
|
||||
m_menuMap[menu] = item;
|
||||
}
|
||||
|
||||
ShortcutController::ShortcutItem* ShortcutController::itemAt(const QModelIndex& index) {
|
||||
if (!index.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<ShortcutItem*>(index.internalPointer());
|
||||
}
|
||||
|
||||
const ShortcutController::ShortcutItem* ShortcutController::itemAt(const QModelIndex& index) const {
|
||||
if (!index.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<const ShortcutItem*>(index.internalPointer());
|
||||
}
|
||||
|
||||
int ShortcutController::shortcutAt(const QModelIndex& index) const {
|
||||
const ShortcutItem* item = itemAt(index);
|
||||
void ShortcutController::updateKey(const QString& name, int keySequence) {
|
||||
auto item = m_items[name];
|
||||
if (!item) {
|
||||
return 0;
|
||||
}
|
||||
return item->shortcut();
|
||||
}
|
||||
|
||||
bool ShortcutController::isMenuAt(const QModelIndex& index) const {
|
||||
const ShortcutItem* item = itemAt(index);
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
return item->menu();
|
||||
}
|
||||
|
||||
void ShortcutController::updateKey(const QModelIndex& index, int keySequence) {
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
const QModelIndex& parent = index.parent();
|
||||
if (!parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
ShortcutItem* item = itemAt(index);
|
||||
updateKey(item, keySequence);
|
||||
if (m_config) {
|
||||
m_config->setQtOption(item->name(), QKeySequence(keySequence).toString(), KEY_SECTION);
|
||||
}
|
||||
emit dataChanged(createIndex(index.row(), 0, index.internalPointer()),
|
||||
createIndex(index.row(), 2, index.internalPointer()));
|
||||
}
|
||||
|
||||
void ShortcutController::updateKey(ShortcutItem* item, int keySequence) {
|
||||
void ShortcutController::updateKey(std::shared_ptr<Shortcut> item, int keySequence) {
|
||||
int oldShortcut = item->shortcut();
|
||||
if (item->functions().first) {
|
||||
if (m_actions->isHeld(item->name())) {
|
||||
if (oldShortcut > 0) {
|
||||
m_heldKeys.take(oldShortcut);
|
||||
}
|
||||
|
@ -231,51 +57,41 @@ void ShortcutController::updateKey(ShortcutItem* item, int keySequence) {
|
|||
item->setShortcut(keySequence);
|
||||
}
|
||||
|
||||
void ShortcutController::updateButton(const QModelIndex& index, int button) {
|
||||
if (!index.isValid()) {
|
||||
void ShortcutController::updateButton(const QString& name, int button) {
|
||||
auto item = m_items[name];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const QModelIndex& parent = index.parent();
|
||||
if (!parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
ShortcutItem* item = itemAt(index);
|
||||
int oldButton = item->button();
|
||||
if (oldButton >= 0) {
|
||||
m_buttons.take(oldButton);
|
||||
}
|
||||
updateAxis(index, -1, GamepadAxisEvent::NEUTRAL);
|
||||
item->setButton(button);
|
||||
if (button >= 0) {
|
||||
clearAxis(name);
|
||||
m_buttons[button] = item;
|
||||
}
|
||||
if (m_config) {
|
||||
m_config->setQtOption(item->name(), button, BUTTON_SECTION);
|
||||
m_config->setQtOption(name, button, BUTTON_SECTION);
|
||||
if (!m_profileName.isNull()) {
|
||||
m_config->setQtOption(item->name(), button, BUTTON_PROFILE_SECTION + m_profileName);
|
||||
m_config->setQtOption(name, button, BUTTON_PROFILE_SECTION + m_profileName);
|
||||
}
|
||||
}
|
||||
emit dataChanged(createIndex(index.row(), 0, index.internalPointer()),
|
||||
createIndex(index.row(), 2, index.internalPointer()));
|
||||
}
|
||||
|
||||
void ShortcutController::updateAxis(const QModelIndex& index, int axis, GamepadAxisEvent::Direction direction) {
|
||||
if (!index.isValid()) {
|
||||
void ShortcutController::updateAxis(const QString& name, int axis, GamepadAxisEvent::Direction direction) {
|
||||
auto item = m_items[name];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const QModelIndex& parent = index.parent();
|
||||
if (!parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
ShortcutItem* item = itemAt(index);
|
||||
int oldAxis = item->axis();
|
||||
GamepadAxisEvent::Direction oldDirection = item->direction();
|
||||
if (oldAxis >= 0) {
|
||||
m_axes.take(qMakePair(oldAxis, oldDirection));
|
||||
m_axes.take(std::make_pair(oldAxis, oldDirection));
|
||||
}
|
||||
if (axis >= 0 && direction != GamepadAxisEvent::NEUTRAL) {
|
||||
updateButton(index, -1);
|
||||
m_axes[qMakePair(axis, direction)] = item;
|
||||
clearButton(name);
|
||||
m_axes[std::make_pair(axis, direction)] = item;
|
||||
}
|
||||
item->setAxis(axis, direction);
|
||||
if (m_config) {
|
||||
|
@ -286,21 +102,31 @@ void ShortcutController::updateAxis(const QModelIndex& index, int axis, GamepadA
|
|||
if (direction == GamepadAxisEvent::NEGATIVE) {
|
||||
d = '-';
|
||||
}
|
||||
m_config->setQtOption(item->name(), QString("%1%2").arg(d).arg(axis), AXIS_SECTION);
|
||||
m_config->setQtOption(name, QString("%1%2").arg(d).arg(axis), AXIS_SECTION);
|
||||
if (!m_profileName.isNull()) {
|
||||
m_config->setQtOption(item->name(), QString("%1%2").arg(d).arg(axis), AXIS_PROFILE_SECTION + m_profileName);
|
||||
m_config->setQtOption(name, QString("%1%2").arg(d).arg(axis), AXIS_PROFILE_SECTION + m_profileName);
|
||||
}
|
||||
}
|
||||
emit dataChanged(createIndex(index.row(), 0, index.internalPointer()),
|
||||
createIndex(index.row(), 2, index.internalPointer()));
|
||||
}
|
||||
|
||||
void ShortcutController::clearKey(const QModelIndex& index) {
|
||||
updateKey(index, 0);
|
||||
void ShortcutController::clearKey(const QString& name) {
|
||||
updateKey(name, 0);
|
||||
}
|
||||
|
||||
void ShortcutController::clearButton(const QModelIndex& index) {
|
||||
updateButton(index, -1);
|
||||
void ShortcutController::clearButton(const QString& name) {
|
||||
updateButton(name, -1);
|
||||
}
|
||||
|
||||
void ShortcutController::clearAxis(const QString& name) {
|
||||
updateAxis(name, -1, GamepadAxisEvent::NEUTRAL);
|
||||
}
|
||||
|
||||
void ShortcutController::rebuildItems() {
|
||||
m_items.clear();
|
||||
m_buttons.clear();
|
||||
m_axes.clear();
|
||||
m_heldKeys.clear();
|
||||
onSubitems({}, std::bind(&ShortcutController::generateItem, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
bool ShortcutController::eventFilter(QObject*, QEvent* event) {
|
||||
|
@ -317,16 +143,8 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
|
|||
}
|
||||
auto item = m_heldKeys.find(key);
|
||||
if (item != m_heldKeys.end()) {
|
||||
ShortcutItem::Functions pair = item.value()->functions();
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
if (pair.first) {
|
||||
pair.first();
|
||||
}
|
||||
} else {
|
||||
if (pair.second) {
|
||||
pair.second();
|
||||
}
|
||||
}
|
||||
Action::BooleanFunction fn = item.value()->action()->booleanAction();
|
||||
fn(event->type() == QEvent::KeyPress);
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
@ -336,14 +154,10 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
|
|||
if (item == m_buttons.end()) {
|
||||
return false;
|
||||
}
|
||||
QAction* action = item.value()->action();
|
||||
if (action && action->isEnabled()) {
|
||||
Action* action = item.value()->action();
|
||||
if (action) {
|
||||
action->trigger();
|
||||
}
|
||||
ShortcutItem::Functions pair = item.value()->functions();
|
||||
if (pair.first) {
|
||||
pair.first();
|
||||
}
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
@ -352,34 +166,22 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
|
|||
if (item == m_buttons.end()) {
|
||||
return false;
|
||||
}
|
||||
ShortcutItem::Functions pair = item.value()->functions();
|
||||
if (pair.second) {
|
||||
pair.second();
|
||||
Action* action = item.value()->action();
|
||||
if (action) {
|
||||
action->trigger(false);
|
||||
}
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
if (event->type() == GamepadAxisEvent::Type()) {
|
||||
GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event);
|
||||
auto item = m_axes.find(qMakePair(gae->axis(), gae->direction()));
|
||||
auto item = m_axes.find(std::make_pair(gae->axis(), gae->direction()));
|
||||
if (item == m_axes.end()) {
|
||||
return false;
|
||||
}
|
||||
if (gae->isNew()) {
|
||||
QAction* action = item.value()->action();
|
||||
if (action && action->isEnabled()) {
|
||||
action->trigger();
|
||||
}
|
||||
}
|
||||
ShortcutItem::Functions pair = item.value()->functions();
|
||||
if (gae->isNew()) {
|
||||
if (pair.first) {
|
||||
pair.first();
|
||||
}
|
||||
} else {
|
||||
if (pair.second) {
|
||||
pair.second();
|
||||
}
|
||||
Action* action = item.value()->action();
|
||||
if (action) {
|
||||
action->trigger(gae->isNew());
|
||||
}
|
||||
event->accept();
|
||||
return true;
|
||||
|
@ -387,7 +189,20 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ShortcutController::loadShortcuts(ShortcutItem* item) {
|
||||
void ShortcutController::generateItem(const QString& itemName) {
|
||||
if (itemName.isNull() || itemName[0] == '.') {
|
||||
return;
|
||||
}
|
||||
Action* action = m_actions->getAction(itemName);
|
||||
if (action) {
|
||||
std::shared_ptr<Shortcut> item = std::make_shared<Shortcut>(action);
|
||||
m_items[itemName] = item;
|
||||
loadShortcuts(item);
|
||||
}
|
||||
emit shortcutAdded(itemName);
|
||||
}
|
||||
|
||||
bool ShortcutController::loadShortcuts(std::shared_ptr<Shortcut> item) {
|
||||
if (item->name().isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -400,11 +215,17 @@ bool ShortcutController::loadShortcuts(ShortcutItem* item) {
|
|||
updateKey(item, QKeySequence(shortcut.toString())[0]);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
QKeySequence defaultShortcut = m_actions->defaultShortcut(item->name());
|
||||
if (!defaultShortcut.isEmpty()) {
|
||||
updateKey(item, defaultShortcut[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
|
||||
void ShortcutController::loadGamepadShortcuts(std::shared_ptr<Shortcut> item) {
|
||||
if (item->name().isNull()) {
|
||||
return;
|
||||
}
|
||||
|
@ -429,7 +250,7 @@ void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
|
|||
int oldAxis = item->axis();
|
||||
GamepadAxisEvent::Direction oldDirection = item->direction();
|
||||
if (oldAxis >= 0) {
|
||||
m_axes.take(qMakePair(oldAxis, oldDirection));
|
||||
m_axes.take(std::make_pair(oldAxis, oldDirection));
|
||||
item->setAxis(-1, GamepadAxisEvent::NEUTRAL);
|
||||
}
|
||||
if (axis.isNull() && m_profile) {
|
||||
|
@ -453,7 +274,7 @@ void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
|
|||
int axis = axisDesc.mid(1).toInt(&ok);
|
||||
if (ok) {
|
||||
item->setAxis(axis, direction);
|
||||
m_axes[qMakePair(axis, direction)] = item;
|
||||
m_axes[std::make_pair(axis, direction)] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -462,15 +283,29 @@ void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
|
|||
void ShortcutController::loadProfile(const QString& profile) {
|
||||
m_profileName = profile;
|
||||
m_profile = InputProfile::findProfile(profile);
|
||||
onSubitems(&m_rootMenu, [this](ShortcutItem* item) {
|
||||
onSubitems({}, [this](std::shared_ptr<Shortcut> item) {
|
||||
loadGamepadShortcuts(item);
|
||||
});
|
||||
}
|
||||
|
||||
void ShortcutController::onSubitems(ShortcutItem* item, std::function<void(ShortcutItem*)> func) {
|
||||
for (ShortcutItem& subitem : item->items()) {
|
||||
func(&subitem);
|
||||
onSubitems(&subitem, func);
|
||||
void ShortcutController::onSubitems(const QString& menu, std::function<void(std::shared_ptr<Shortcut>)> func) {
|
||||
for (const QString& subitem : m_actions->menuItems(menu)) {
|
||||
auto item = m_items[subitem];
|
||||
if (item) {
|
||||
func(item);
|
||||
}
|
||||
if (subitem.size() && subitem[0] == '.') {
|
||||
onSubitems(subitem.mid(1), func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutController::onSubitems(const QString& menu, std::function<void(const QString&)> func) {
|
||||
for (const QString& subitem : m_actions->menuItems(menu)) {
|
||||
func(subitem);
|
||||
if (subitem.size() && subitem[0] == '.') {
|
||||
onSubitems(subitem.mid(1), func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,62 +369,83 @@ int ShortcutController::toModifierKey(int key) {
|
|||
|
||||
}
|
||||
|
||||
ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent)
|
||||
const Shortcut* ShortcutController::shortcut(const QString& action) const {
|
||||
return m_items[action].get();
|
||||
}
|
||||
|
||||
QString ShortcutController::name(int index, const QString& parent) const {
|
||||
QStringList menu = m_actions->menuItems(parent.isNull() || parent[0] != '.' ? parent : parent.mid(1));
|
||||
menu.removeAll({});
|
||||
if (index >= menu.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return menu[index];
|
||||
}
|
||||
|
||||
QString ShortcutController::parent(const QString& action) const {
|
||||
return QString(".%1").arg(m_actions->menuFor(action));
|
||||
}
|
||||
|
||||
QString ShortcutController::visibleName(const QString& action) const {
|
||||
if (action.isNull()) {
|
||||
return {};
|
||||
}
|
||||
QString name;
|
||||
if (action[0] == '.') {
|
||||
name = m_actions->menuName(action.mid(1));
|
||||
} else {
|
||||
name = m_actions->getAction(action)->visibleName();
|
||||
}
|
||||
return name.replace(QRegularExpression("&(.)"), "\\1");
|
||||
}
|
||||
|
||||
int ShortcutController::indexIn(const QString& action) const {
|
||||
QString name = m_actions->menuFor(action);
|
||||
QStringList menu = m_actions->menuItems(name);
|
||||
menu.removeAll({});
|
||||
return menu.indexOf(action);
|
||||
}
|
||||
|
||||
int ShortcutController::count(const QString& name) const {
|
||||
QStringList menu;
|
||||
if (name.isNull()) {
|
||||
menu = m_actions->menuItems();
|
||||
} else if (name[0] != '.') {
|
||||
return 0;
|
||||
} else {
|
||||
menu = m_actions->menuItems(name.mid(1));
|
||||
}
|
||||
menu.removeAll({});
|
||||
return menu.count();
|
||||
}
|
||||
|
||||
Shortcut::Shortcut(Action* action)
|
||||
: m_action(action)
|
||||
, m_shortcut(action->shortcut().isEmpty() ? 0 : action->shortcut()[0])
|
||||
, m_name(name)
|
||||
, m_direction(GamepadAxisEvent::NEUTRAL)
|
||||
, m_parent(parent)
|
||||
{
|
||||
m_visibleName = action->text()
|
||||
.remove(QRegExp("&(?!&)"))
|
||||
.remove("...");
|
||||
}
|
||||
|
||||
ShortcutController::ShortcutItem::ShortcutItem(ShortcutController::ShortcutItem::Functions functions, int shortcut, const QString& visibleName, const QString& name, ShortcutItem* parent)
|
||||
: m_shortcut(shortcut)
|
||||
, m_functions(functions)
|
||||
, m_name(name)
|
||||
, m_visibleName(visibleName)
|
||||
, m_direction(GamepadAxisEvent::NEUTRAL)
|
||||
, m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ShortcutController::ShortcutItem::ShortcutItem(QMenu* menu, ShortcutItem* parent)
|
||||
: m_menu(menu)
|
||||
, m_direction(GamepadAxisEvent::NEUTRAL)
|
||||
, m_parent(parent)
|
||||
{
|
||||
if (menu) {
|
||||
m_visibleName = menu->title()
|
||||
.remove(QRegExp("&(?!&)"))
|
||||
.remove("...");
|
||||
void Shortcut::setShortcut(int shortcut) {
|
||||
if (m_shortcut == shortcut) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutController::ShortcutItem::addAction(QAction* action, const QString& name) {
|
||||
m_items.append(ShortcutItem(action, name, this));
|
||||
}
|
||||
|
||||
void ShortcutController::ShortcutItem::addFunctions(ShortcutController::ShortcutItem::Functions functions,
|
||||
int shortcut, const QString& visibleName,
|
||||
const QString& name) {
|
||||
m_items.append(ShortcutItem(functions, shortcut, visibleName, name, this));
|
||||
}
|
||||
|
||||
void ShortcutController::ShortcutItem::addSubmenu(QMenu* menu) {
|
||||
m_items.append(ShortcutItem(menu, this));
|
||||
}
|
||||
|
||||
void ShortcutController::ShortcutItem::setShortcut(int shortcut) {
|
||||
m_shortcut = shortcut;
|
||||
if (m_action) {
|
||||
m_action->setShortcut(QKeySequence(shortcut));
|
||||
}
|
||||
emit shortcutChanged(shortcut);
|
||||
}
|
||||
|
||||
void ShortcutController::ShortcutItem::setAxis(int axis, GamepadAxisEvent::Direction direction) {
|
||||
void Shortcut::setButton(int button) {
|
||||
if (m_button == button) {
|
||||
return;
|
||||
}
|
||||
m_button = button;
|
||||
emit buttonChanged(button);
|
||||
}
|
||||
|
||||
void Shortcut::setAxis(int axis, GamepadAxisEvent::Direction direction) {
|
||||
if (m_axis == axis && m_direction == direction) {
|
||||
return;
|
||||
}
|
||||
m_axis = axis;
|
||||
m_direction = direction;
|
||||
emit axisChanged(axis, direction);
|
||||
}
|
||||
|
|
|
@ -5,23 +5,60 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include "ActionMapper.h"
|
||||
#include "GamepadAxisEvent.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
class QAction;
|
||||
class QKeyEvent;
|
||||
class QMenu;
|
||||
class QString;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class ConfigController;
|
||||
class InputProfile;
|
||||
|
||||
class ShortcutController : public QAbstractItemModel {
|
||||
class Shortcut : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Shortcut(Action* action);
|
||||
|
||||
Action* action() { return m_action; }
|
||||
const Action* action() const { return m_action; }
|
||||
const int shortcut() const { return m_shortcut; }
|
||||
QString visibleName() const { return m_action ? m_action->visibleName() : QString(); }
|
||||
QString name() const { return m_action ? m_action->name() : QString(); }
|
||||
int button() const { return m_button; }
|
||||
int axis() const { return m_axis; }
|
||||
GamepadAxisEvent::Direction direction() const { return m_direction; }
|
||||
|
||||
bool operator==(const Shortcut& other) const {
|
||||
return m_action == other.m_action;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void setShortcut(int sequence);
|
||||
void setButton(int button);
|
||||
void setAxis(int axis, GamepadAxisEvent::Direction direction);
|
||||
|
||||
signals:
|
||||
void shortcutChanged(int sequence);
|
||||
void buttonChanged(int button);
|
||||
void axisChanged(int axis, GamepadAxisEvent::Direction direction);
|
||||
|
||||
private:
|
||||
Action* m_action = nullptr;
|
||||
int m_shortcut = 0;
|
||||
int m_button = -1;
|
||||
int m_axis = -1;
|
||||
GamepadAxisEvent::Direction m_direction;
|
||||
};
|
||||
|
||||
class ShortcutController : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
@ -31,112 +68,57 @@ private:
|
|||
constexpr static const char* const BUTTON_PROFILE_SECTION = "shortcutProfileButton.";
|
||||
constexpr static const char* const AXIS_PROFILE_SECTION = "shortcutProfileAxis.";
|
||||
|
||||
class ShortcutItem {
|
||||
public:
|
||||
typedef QPair<std::function<void ()>, std::function<void ()>> Functions;
|
||||
|
||||
ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent = nullptr);
|
||||
ShortcutItem(Functions functions, int shortcut, const QString& visibleName, const QString& name,
|
||||
ShortcutItem* parent = nullptr);
|
||||
ShortcutItem(QMenu* action, ShortcutItem* parent = nullptr);
|
||||
|
||||
QAction* action() { return m_action; }
|
||||
const QAction* action() const { return m_action; }
|
||||
const int shortcut() const { return m_shortcut; }
|
||||
Functions functions() const { return m_functions; }
|
||||
QMenu* menu() { return m_menu; }
|
||||
const QMenu* menu() const { return m_menu; }
|
||||
const QString& visibleName() const { return m_visibleName; }
|
||||
const QString& name() const { return m_name; }
|
||||
QList<ShortcutItem>& items() { return m_items; }
|
||||
const QList<ShortcutItem>& items() const { return m_items; }
|
||||
ShortcutItem* parent() { return m_parent; }
|
||||
const ShortcutItem* parent() const { return m_parent; }
|
||||
void addAction(QAction* action, const QString& name);
|
||||
void addFunctions(Functions functions, int shortcut, const QString& visibleName,
|
||||
const QString& name);
|
||||
void addSubmenu(QMenu* menu);
|
||||
int button() const { return m_button; }
|
||||
void setShortcut(int sequence);
|
||||
void setButton(int button) { m_button = button; }
|
||||
int axis() const { return m_axis; }
|
||||
GamepadAxisEvent::Direction direction() const { return m_direction; }
|
||||
void setAxis(int axis, GamepadAxisEvent::Direction direction);
|
||||
|
||||
bool operator==(const ShortcutItem& other) const {
|
||||
return m_menu == other.m_menu && m_action == other.m_action;
|
||||
}
|
||||
|
||||
private:
|
||||
QAction* m_action = nullptr;
|
||||
int m_shortcut = 0;
|
||||
QMenu* m_menu = nullptr;
|
||||
Functions m_functions;
|
||||
QString m_name;
|
||||
QString m_visibleName;
|
||||
int m_button = -1;
|
||||
int m_axis = -1;
|
||||
GamepadAxisEvent::Direction m_direction;
|
||||
QList<ShortcutItem> m_items;
|
||||
ShortcutItem* m_parent;
|
||||
};
|
||||
|
||||
public:
|
||||
ShortcutController(QObject* parent = nullptr);
|
||||
|
||||
void setConfigController(ConfigController* controller);
|
||||
void setActionMapper(ActionMapper* actionMapper);
|
||||
|
||||
void setProfile(const QString& profile);
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
void updateKey(const QString& action, int keySequence);
|
||||
void updateButton(const QString& action, int button);
|
||||
void updateAxis(const QString& action, int axis, GamepadAxisEvent::Direction direction);
|
||||
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override;
|
||||
virtual QModelIndex parent(const QModelIndex& index) const override;
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
void addAction(QMenu* menu, QAction* action, const QString& name);
|
||||
void addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
|
||||
int shortcut, const QString& visibleName, const QString& name);
|
||||
void addFunctions(QMenu* menu, std::function<void()> press, std::function<void()> release,
|
||||
const QKeySequence& shortcut, const QString& visibleName, const QString& name);
|
||||
void addMenu(QMenu* menu, QMenu* parent = nullptr);
|
||||
|
||||
QAction* getAction(const QString& name);
|
||||
int shortcutAt(const QModelIndex& index) const;
|
||||
bool isMenuAt(const QModelIndex& index) const;
|
||||
|
||||
void updateKey(const QModelIndex& index, int keySequence);
|
||||
void updateButton(const QModelIndex& index, int button);
|
||||
void updateAxis(const QModelIndex& index, int axis, GamepadAxisEvent::Direction direction);
|
||||
|
||||
void clearKey(const QModelIndex& index);
|
||||
void clearButton(const QModelIndex& index);
|
||||
void clearKey(const QString& action);
|
||||
void clearButton(const QString& action);
|
||||
void clearAxis(const QString& action);
|
||||
|
||||
static int toModifierShortcut(const QString& shortcut);
|
||||
static bool isModifierKey(int key);
|
||||
static int toModifierKey(int key);
|
||||
|
||||
const Shortcut* shortcut(const QString& action) const;
|
||||
int indexIn(const QString& action) const;
|
||||
int count(const QString& menu = {}) const;
|
||||
QString parent(const QString& action) const;
|
||||
QString name(int index, const QString& parent = {}) const;
|
||||
QString visibleName(const QString& item) const;
|
||||
|
||||
signals:
|
||||
void shortcutAdded(const QString& name);
|
||||
void menuCleared(const QString& name);
|
||||
|
||||
public slots:
|
||||
void loadProfile(const QString& profile);
|
||||
void rebuildItems();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject*, QEvent*) override;
|
||||
|
||||
private:
|
||||
ShortcutItem* itemAt(const QModelIndex& index);
|
||||
const ShortcutItem* itemAt(const QModelIndex& index) const;
|
||||
bool loadShortcuts(ShortcutItem*);
|
||||
void loadGamepadShortcuts(ShortcutItem*);
|
||||
void onSubitems(ShortcutItem*, std::function<void(ShortcutItem*)> func);
|
||||
void updateKey(ShortcutItem* item, int keySequence);
|
||||
void generateItem(const QString& itemName);
|
||||
bool loadShortcuts(std::shared_ptr<Shortcut>);
|
||||
void loadGamepadShortcuts(std::shared_ptr<Shortcut>);
|
||||
void onSubitems(const QString& menu, std::function<void(std::shared_ptr<Shortcut>)> func);
|
||||
void onSubitems(const QString& menu, std::function<void(const QString&)> func);
|
||||
void updateKey(std::shared_ptr<Shortcut> item, int keySequence);
|
||||
|
||||
ShortcutItem m_rootMenu{nullptr};
|
||||
QMap<QMenu*, ShortcutItem*> m_menuMap;
|
||||
QMap<int, ShortcutItem*> m_buttons;
|
||||
QMap<QPair<int, GamepadAxisEvent::Direction>, ShortcutItem*> m_axes;
|
||||
QMap<int, ShortcutItem*> m_heldKeys;
|
||||
QHash<QString, std::shared_ptr<Shortcut>> m_items;
|
||||
QHash<int, std::shared_ptr<Shortcut>> m_buttons;
|
||||
QHash<std::pair<int, GamepadAxisEvent::Direction>, std::shared_ptr<Shortcut>> m_axes;
|
||||
QHash<int, std::shared_ptr<Shortcut>> m_heldKeys;
|
||||
ActionMapper* m_actions = nullptr;
|
||||
ConfigController* m_config = nullptr;
|
||||
QString m_profileName;
|
||||
const InputProfile* m_profile = nullptr;
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/* Copyright (c) 2013-2019 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "ShortcutModel.h"
|
||||
|
||||
#include "ShortcutController.h"
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
ShortcutModel::ShortcutModel(QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ShortcutModel::setController(ShortcutController* controller) {
|
||||
beginResetModel();
|
||||
m_controller = controller;
|
||||
m_cache.clear();
|
||||
connect(controller, &ShortcutController::shortcutAdded, this, &ShortcutModel::addRowNamed);
|
||||
connect(controller, &ShortcutController::menuCleared, this, &ShortcutModel::clearMenu);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariant ShortcutModel::data(const QModelIndex& index, int role) const {
|
||||
if (role != Qt::DisplayRole || !index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
int row = index.row();
|
||||
const Item* item = static_cast<Item*>(index.internalPointer());
|
||||
const Shortcut* shortcut = item->shortcut;
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return m_controller->visibleName(item->name);
|
||||
case 1:
|
||||
return shortcut ? QKeySequence(shortcut->shortcut()).toString(QKeySequence::NativeText) : QVariant();
|
||||
case 2:
|
||||
if (!shortcut) {
|
||||
return QVariant();
|
||||
}
|
||||
if (shortcut->button() >= 0) {
|
||||
return shortcut->button();
|
||||
}
|
||||
if (shortcut->axis() >= 0) {
|
||||
char d = '\0';
|
||||
if (shortcut->direction() == GamepadAxisEvent::POSITIVE) {
|
||||
d = '+';
|
||||
}
|
||||
if (shortcut->direction() == GamepadAxisEvent::NEGATIVE) {
|
||||
d = '-';
|
||||
}
|
||||
return QString("%1%2").arg(d).arg(shortcut->axis());
|
||||
}
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ShortcutModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
if (orientation == Qt::Horizontal) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Action");
|
||||
case 1:
|
||||
return tr("Keyboard");
|
||||
case 2:
|
||||
return tr("Gamepad");
|
||||
}
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
QModelIndex ShortcutModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
QString pmenu;
|
||||
if (parent.isValid()) {
|
||||
pmenu = static_cast<Item*>(parent.internalPointer())->name;
|
||||
}
|
||||
QString name = m_controller->name(row, pmenu);
|
||||
Item* item = &(*const_cast<QHash<QString, Item>*>(&m_cache))[name];
|
||||
item->name = name;
|
||||
item->shortcut = m_controller->shortcut(name);
|
||||
return createIndex(row, column, item);
|
||||
}
|
||||
|
||||
QModelIndex ShortcutModel::parent(const QModelIndex& index) const {
|
||||
if (!index.isValid() || !index.internalPointer()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
Item* item = static_cast<Item*>(index.internalPointer());
|
||||
QString parent = m_controller->parent(item->name);
|
||||
if (parent.isNull()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
Item* pitem = &(*const_cast<QHash<QString, Item>*>(&m_cache))[parent];
|
||||
pitem->name = parent;
|
||||
pitem->shortcut = m_controller->shortcut(parent);
|
||||
return createIndex(m_controller->indexIn(parent), 0, pitem);
|
||||
}
|
||||
|
||||
int ShortcutModel::columnCount(const QModelIndex& index) const {
|
||||
return 3;
|
||||
}
|
||||
|
||||
int ShortcutModel::rowCount(const QModelIndex& index) const {
|
||||
if (!index.isValid()) {
|
||||
return m_controller->count();
|
||||
}
|
||||
Item* item = static_cast<Item*>(index.internalPointer());
|
||||
return m_controller->count(item->name);
|
||||
}
|
||||
|
||||
QString ShortcutModel::name(const QModelIndex& index) const {
|
||||
if (!index.isValid()) {
|
||||
return {};
|
||||
}
|
||||
Item* item = static_cast<Item*>(index.internalPointer());
|
||||
return item->name;
|
||||
}
|
||||
|
||||
void ShortcutModel::addRowNamed(const QString& name) {
|
||||
QString parent = m_controller->parent(name);
|
||||
Item* item = &m_cache[parent];
|
||||
item->name = parent;
|
||||
item->shortcut = m_controller->shortcut(parent);
|
||||
int index = m_controller->indexIn(name);
|
||||
beginInsertRows(createIndex(m_controller->indexIn(parent), 0, item), index, index + 1);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void ShortcutModel::clearMenu(const QString& name) {
|
||||
// TODO
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/* Copyright (c) 2013-2019 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class ShortcutController;
|
||||
class Shortcut;
|
||||
|
||||
class ShortcutModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ShortcutModel(QObject* parent = nullptr);
|
||||
|
||||
void setController(ShortcutController* controller);
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
|
||||
virtual QModelIndex parent(const QModelIndex& index) const override;
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
QString name(const QModelIndex&) const;
|
||||
|
||||
private slots:
|
||||
void addRowNamed(const QString&);
|
||||
void clearMenu(const QString&);
|
||||
|
||||
private:
|
||||
ShortcutController* m_controller = nullptr;
|
||||
|
||||
struct Item {
|
||||
QString name;
|
||||
const Shortcut* shortcut = nullptr;
|
||||
};
|
||||
|
||||
QHash<QString, Item> m_cache;
|
||||
};
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
#include "GamepadButtonEvent.h"
|
||||
#include "InputController.h"
|
||||
#include "ShortcutController.h"
|
||||
#include "ShortcutModel.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
@ -41,7 +42,9 @@ ShortcutView::~ShortcutView() {
|
|||
|
||||
void ShortcutView::setController(ShortcutController* controller) {
|
||||
m_controller = controller;
|
||||
m_ui.shortcutTable->setModel(controller);
|
||||
m_model = new ShortcutModel(this);
|
||||
m_model->setController(controller);
|
||||
m_ui.shortcutTable->setModel(m_model);
|
||||
}
|
||||
|
||||
void ShortcutView::setInputController(InputController* controller) {
|
||||
|
@ -56,10 +59,12 @@ void ShortcutView::load(const QModelIndex& index) {
|
|||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
if (m_controller->isMenuAt(index)) {
|
||||
QString name = m_model->name(index);
|
||||
const Shortcut* item = m_controller->shortcut(name);
|
||||
if (!item->action()) {
|
||||
return;
|
||||
}
|
||||
int shortcut = m_controller->shortcutAt(index);
|
||||
int shortcut = item->shortcut();
|
||||
if (index.column() == 1) {
|
||||
m_ui.keyboardButton->click();
|
||||
} else if (index.column() == 2) {
|
||||
|
@ -80,35 +85,47 @@ void ShortcutView::clear() {
|
|||
return;
|
||||
}
|
||||
QModelIndex index = m_ui.shortcutTable->selectionModel()->currentIndex();
|
||||
if (m_controller->isMenuAt(index)) {
|
||||
QString name = m_model->name(index);
|
||||
const Shortcut* item = m_controller->shortcut(name);
|
||||
if (!item->action()) {
|
||||
return;
|
||||
}
|
||||
if (m_ui.gamepadButton->isChecked()) {
|
||||
m_controller->clearButton(index);
|
||||
m_controller->clearButton(name);
|
||||
m_controller->clearAxis(name);
|
||||
m_ui.keyEdit->setValueButton(-1);
|
||||
} else {
|
||||
m_controller->clearKey(index);
|
||||
m_controller->clearKey(name);
|
||||
m_ui.keyEdit->setValueKey(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutView::updateButton(int button) {
|
||||
if (!m_controller || m_controller->isMenuAt(m_ui.shortcutTable->selectionModel()->currentIndex())) {
|
||||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
QString name = m_model->name(m_ui.shortcutTable->selectionModel()->currentIndex());
|
||||
const Shortcut* item = m_controller->shortcut(name);
|
||||
if (!item->action()) {
|
||||
return;
|
||||
}
|
||||
if (m_ui.gamepadButton->isChecked()) {
|
||||
m_controller->updateButton(m_ui.shortcutTable->selectionModel()->currentIndex(), button);
|
||||
m_controller->updateButton(name, button);
|
||||
} else {
|
||||
m_controller->updateKey(m_ui.shortcutTable->selectionModel()->currentIndex(), button);
|
||||
m_controller->updateKey(name, button);
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutView::updateAxis(int axis, int direction) {
|
||||
if (!m_controller || m_controller->isMenuAt(m_ui.shortcutTable->selectionModel()->currentIndex())) {
|
||||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
m_controller->updateAxis(m_ui.shortcutTable->selectionModel()->currentIndex(), axis,
|
||||
static_cast<GamepadAxisEvent::Direction>(direction));
|
||||
QString name = m_model->name(m_ui.shortcutTable->selectionModel()->currentIndex());
|
||||
const Shortcut* item = m_controller->shortcut(name);
|
||||
if (!item->action()) {
|
||||
return;
|
||||
}
|
||||
m_controller->updateAxis(name, axis, static_cast<GamepadAxisEvent::Direction>(direction));
|
||||
}
|
||||
|
||||
void ShortcutView::closeEvent(QCloseEvent*) {
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace QGBA {
|
|||
|
||||
class InputController;
|
||||
class ShortcutController;
|
||||
class ShortcutModel;
|
||||
|
||||
class ShortcutView : public QWidget {
|
||||
Q_OBJECT
|
||||
|
@ -40,6 +41,7 @@ private:
|
|||
Ui::ShortcutView m_ui;
|
||||
|
||||
ShortcutController* m_controller = nullptr;
|
||||
ShortcutModel* m_model = nullptr;
|
||||
InputController* m_input = nullptr;
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,8 +15,10 @@
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/thread.h>
|
||||
|
||||
#include "ActionMapper.h"
|
||||
#include "InputController.h"
|
||||
#include "LoadSaveState.h"
|
||||
#include "LogController.h"
|
||||
|
@ -156,8 +158,9 @@ private:
|
|||
template <typename T, typename... A> std::function<void()> openTView(A... arg);
|
||||
template <typename T, typename... A> std::function<void()> openControllerTView(A... arg);
|
||||
|
||||
QAction* addControlledAction(QMenu* menu, QAction* action, const QString& name);
|
||||
QAction* addHiddenAction(QMenu* menu, QAction* action, const QString& name);
|
||||
Action* addGameAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {});
|
||||
template<typename T, typename V> Action* addGameAction(const QString& visibleName, const QString& name, T* obj, V (T::*action)(), const QString& menu = {}, const QKeySequence& = {});
|
||||
Action* addGameAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {});
|
||||
|
||||
void updateTitle(float fps = -1);
|
||||
|
||||
|
@ -170,14 +173,17 @@ private:
|
|||
|
||||
std::unique_ptr<Display> m_display;
|
||||
int m_savedScale;
|
||||
|
||||
// TODO: Move these to a new class
|
||||
QList<QAction*> m_gameActions;
|
||||
QList<QAction*> m_nonMpActions;
|
||||
ActionMapper m_actions;
|
||||
QList<Action*> m_gameActions;
|
||||
QList<Action*> m_nonMpActions;
|
||||
#ifdef M_CORE_GBA
|
||||
QList<QAction*> m_gbaActions;
|
||||
QMultiMap<mPlatform, Action*> m_platformActions;
|
||||
#endif
|
||||
QAction* m_multiWindow;
|
||||
QMap<int, QAction*> m_frameSizes;
|
||||
Action* m_multiWindow;
|
||||
QMap<int, Action*> m_frameSizes;
|
||||
|
||||
LogController m_log{0};
|
||||
LogView* m_logView;
|
||||
#ifdef USE_DEBUGGERS
|
||||
|
@ -192,9 +198,6 @@ private:
|
|||
QElapsedTimer m_frameTimer;
|
||||
QTimer m_fpsTimer;
|
||||
QList<QString> m_mruFiles;
|
||||
QMenu* m_mruMenu = nullptr;
|
||||
QMenu* m_videoLayers;
|
||||
QMenu* m_audioChannels;
|
||||
ShortcutController* m_shortcutController;
|
||||
#if defined(BUILD_GL) || defined(BUILD_GLES2)
|
||||
std::unique_ptr<ShaderSelector> m_shaderView;
|
||||
|
|
Loading…
Reference in New Issue