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}