all repos — mgba @ e902a253946efa4abcd2c8c930a7733998c5f337

mGBA Game Boy Advance Emulator

src/platform/qt/ActionMapper.cpp (view raw)

  1/* Copyright (c) 2013-2018 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "ActionMapper.h"
  7
  8#include "ConfigController.h"
  9#include "ShortcutController.h"
 10
 11#include <QMenu>
 12#include <QMenuBar>
 13
 14using namespace QGBA;
 15
 16void ActionMapper::addMenu(const QString& visibleName, const QString& name, const QString& parent) {
 17	QString mname(QString(".%1").arg(name));
 18	m_menus[parent].append(mname);
 19	m_reverseMenus[mname] = parent;
 20	m_menuNames[name] = visibleName;
 21}
 22
 23void ActionMapper::addHiddenMenu(const QString& visibleName, const QString& name, const QString& parent) {
 24	m_hiddenActions.insert(QString(".%1").arg(name));
 25	addMenu(visibleName, name, parent);
 26}
 27
 28void ActionMapper::clearMenu(const QString& name) {
 29	m_menus[name].clear();
 30	emit menuCleared(name);
 31}
 32
 33void ActionMapper::rebuildMenu(QMenuBar* menubar, QWidget* context, const ShortcutController& shortcuts) {
 34	menubar->clear();
 35	for (QAction* action : context->actions()) {
 36		context->removeAction(action);
 37	}
 38	for (const QString& m : m_menus[{}]) {
 39		if (m_hiddenActions.contains(m)) {
 40			continue;
 41		}
 42		QString menu = m.mid(1);
 43		QMenu* qmenu = menubar->addMenu(m_menuNames[menu]);
 44
 45		rebuildMenu(menu, qmenu, context, shortcuts);
 46	}
 47}
 48
 49void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* context, const ShortcutController& shortcuts) {
 50	for (const QString& actionName : m_menus[menu]) {
 51		if (actionName.isNull()) {
 52			qmenu->addSeparator();
 53			continue;
 54		}
 55		if (m_hiddenActions.contains(actionName)) {
 56			continue;
 57		}
 58		if (actionName[0] == '.') {
 59			QString name = actionName.mid(1);
 60			QMenu* newMenu = qmenu->addMenu(m_menuNames[name]);
 61			rebuildMenu(name, newMenu, context, shortcuts);
 62			continue;
 63		}
 64		Action* action = &m_actions[actionName];
 65		QAction* qaction = qmenu->addAction(action->visibleName());
 66		qaction->setEnabled(action->isEnabled());
 67		qaction->setShortcutContext(Qt::WidgetShortcut);
 68		if (action->isExclusive() || action->booleanAction()) {
 69			qaction->setCheckable(true);
 70		}
 71		if (action->isActive()) {
 72			qaction->setChecked(true);
 73		}
 74		const Shortcut* shortcut = shortcuts.shortcut(actionName);
 75		if (shortcut) {
 76			if (shortcut->shortcut() > 0) {
 77				qaction->setShortcut(QKeySequence(shortcut->shortcut()));
 78			}
 79		} else if (!m_defaultShortcuts[actionName].isEmpty()) {
 80			qaction->setShortcut(m_defaultShortcuts[actionName][0]);
 81		}
 82		QObject::connect(qaction, &QAction::triggered, [qaction, action](bool enabled) {
 83			if (qaction->isCheckable()) {
 84				action->trigger(enabled);
 85			} else {
 86				action->trigger();
 87			}
 88		});
 89		QObject::connect(action, &Action::enabled, qaction, &QAction::setEnabled);
 90		QObject::connect(action, &Action::activated, qaction, &QAction::setChecked);
 91		QObject::connect(action, &Action::destroyed, qaction, &QAction::deleteLater);
 92		if (shortcut) {
 93			QObject::connect(shortcut, &Shortcut::shortcutChanged, qaction, [qaction](int shortcut) {
 94				qaction->setShortcut(QKeySequence(shortcut));
 95			});
 96		}
 97		context->addAction(qaction);
 98	}
 99}
100
101void ActionMapper::addSeparator(const QString& menu) {
102	m_menus[menu].append(QString{});
103}
104
105Action* ActionMapper::addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut) {
106	m_actions.insert(name, act);
107	m_reverseMenus[name] = menu;
108	m_menus[menu].append(name);
109	if (!shortcut.isEmpty()) {
110		m_defaultShortcuts[name] = shortcut;
111	}
112	emit actionAdded(name);
113
114	return &m_actions[name];
115}
116
117Action* ActionMapper::addAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu, const QKeySequence& shortcut) {
118	return addAction(Action(action, name, visibleName), name, menu, shortcut);
119}
120
121Action* ActionMapper::addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu) {
122	return addAction(Action([option, variant]() {
123		option->setValue(variant);
124	}, option->name(), visibleName), QString("%1.%2").arg(option->name()).arg(variant.toString()), menu, {});
125}
126
127Action* ActionMapper::addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu, const QKeySequence& shortcut) {
128	return addAction(Action(action, name, visibleName), name, menu, shortcut);
129}
130
131Action* ActionMapper::addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu) {
132	return addAction(Action([option](bool value) {
133		option->setValue(value);
134	}, option->name(), visibleName), option->name(), menu, {});
135}
136
137Action* ActionMapper::addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu, const QKeySequence& shortcut) {
138	m_hiddenActions.insert(name);
139	m_heldActions.insert(name);
140	return addBooleanAction(visibleName, name, action, menu, shortcut);
141}
142
143Action* ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu, const QKeySequence& shortcut) {
144	m_hiddenActions.insert(name);
145	return addAction(visibleName, name, action, menu, shortcut);
146}
147
148QStringList ActionMapper::menuItems(const QString& menu) const {
149	return m_menus[menu];
150}
151
152QString ActionMapper::menuFor(const QString& menu) const {
153	return m_reverseMenus[menu];
154}
155
156QString ActionMapper::menuName(const QString& menu) const {
157	if (!menu.isNull() && menu[0] == '.') {
158		return m_menuNames[menu.mid(1)];
159	}
160	return m_menuNames[menu];
161}
162
163Action* ActionMapper::getAction(const QString& itemName) {
164	return &m_actions[itemName];
165}
166
167QKeySequence ActionMapper::defaultShortcut(const QString& itemName) {
168	return m_defaultShortcuts[itemName];
169}