Don't use KeyboardShortcuts singleton for temporal changes in Keyboard Shortcuts dialog

Main changes:

- Improve the "Keyboard Shortcuts" dialog because instead of changing
  global shortcuts/menu keys and rollback everything if we select
  "Cancel", here we make a copy of all shortcuts, modify them in the
  dialog UI, and finally "commit" to the global shortcuts if the user
  confirms the dialog.
- Fix "Reset" button in "Keyboard Shortcuts" dialog for mouse wheel
  customization
This commit is contained in:
David Capello 2018-07-23 15:15:04 -03:00
parent c5fda62173
commit 413603a71a
9 changed files with 244 additions and 226 deletions

View File

@ -11,7 +11,6 @@
#include "app/app.h"
#include "app/app_menus.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/context.h"
#include "app/file_selector.h"
#include "app/i18n/strings.h"
@ -44,8 +43,7 @@
#include "keyboard_shortcuts.xml.h"
#include <algorithm>
#include <set>
#include <map>
#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys"
@ -57,6 +55,8 @@ using namespace ui;
namespace {
typedef std::map<AppMenuItem*, KeyPtr> MenuKeys;
class HeaderSplitter : public Splitter {
public:
HeaderSplitter() : Splitter(Splitter::ByPixel, HORIZONTAL) {
@ -126,12 +126,16 @@ class KeyItem : public ListItem {
};
public:
KeyItem(const std::string& text,
KeyItem(KeyboardShortcuts& keys,
MenuKeys& menuKeys,
const std::string& text,
const KeyPtr& key,
AppMenuItem* menuitem,
const int level,
HeaderItem* headerItem)
: ListItem(text)
, m_keys(keys)
, m_menuKeys(menuKeys)
, m_key(key)
, m_keyOrig(key ? new Key(*key): nullptr)
, m_menuitem(menuitem)
@ -148,14 +152,6 @@ public:
KeyPtr key() { return m_key; }
AppMenuItem* menuitem() const { return m_menuitem; }
void restoreKeys() {
if (m_key && m_keyOrig)
*m_key = *m_keyOrig;
if (m_menuitem && !m_keyOrig)
m_menuitem->setKey(nullptr);
}
std::string searchableText() const {
if (m_menuitem) {
Widget* w = m_menuitem;
@ -187,22 +183,18 @@ public:
private:
void onAccelChange(const Accelerator& accel);
void onChangeAccel(int index) {
LockButtons lock(this);
Accelerator origAccel = m_key->accels()[index];
SelectAccelerator window(origAccel,
m_key->keycontext(),
KeyboardShortcuts::instance()->keys());
m_keys);
window.openWindowInForeground();
if (window.isModified()) {
onAccelChange(window.accel());
m_key->disableAccel(origAccel);
if (!window.accel().isEmpty())
m_key->add(window.accel(), KeySource::UserDefined);
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
}
this->window()->layout();
@ -229,7 +221,7 @@ private:
ui::Accelerator accel;
SelectAccelerator window(accel,
m_key ? m_key->keycontext(): KeyContext::Any,
KeyboardShortcuts::instance()->keys());
m_keys);
window.openWindowInForeground();
if ((window.isModified()) ||
@ -240,15 +232,16 @@ private:
if (!m_menuitem)
return;
m_key = app::KeyboardShortcuts::instance()->command(
ASSERT(m_menuitem->getCommand());
m_key = m_keys.command(
m_menuitem->getCommand()->id().c_str(),
m_menuitem->getParams());
m_menuitem->setKey(m_key);
m_menuKeys[m_menuitem] = m_key;
}
onAccelChange(window.accel());
m_key->add(window.accel(), KeySource::UserDefined);
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
}
this->window()->layout();
@ -462,6 +455,8 @@ private:
}
}
KeyboardShortcuts& m_keys;
MenuKeys& m_menuKeys;
KeyPtr m_key;
KeyPtr m_keyOrig;
AppMenuItem* m_menuitem;
@ -480,8 +475,12 @@ private:
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
public:
KeyboardShortcutsWindow(const std::string& searchText)
: m_searchChange(false)
KeyboardShortcutsWindow(app::KeyboardShortcuts& keys,
MenuKeys& menuKeys,
const std::string& searchText)
: m_keys(keys)
, m_menuKeys(menuKeys)
, m_searchChange(false)
, m_wasDefault(false) {
setAutoRemap(false);
@ -498,20 +497,13 @@ public:
#endif
wheelBehavior()->setSelectedItem(
app::KeyboardShortcuts::instance()->hasMouseWheelCustomization() ? 1: 0);
m_keys.hasMouseWheelCustomization() ? 1: 0);
if (isDefaultWheelBehavior()) {
m_wheelKeys = app::KeyboardShortcuts::instance()
->getDefaultMouseWheelTable(wheelZoom()->isSelected());
m_keys.setDefaultMouseWheelKeys(wheelZoom()->isSelected());
m_wasDefault = true;
}
else {
for (const KeyPtr& key : *app::KeyboardShortcuts::instance()) {
if (key->type() == KeyType::WheelAction)
m_wheelKeys.push_back(std::make_shared<Key>(*key));
}
}
m_keys.addMissingMouseWheelKeys();
updateSlideZoomText();
addMissingWheelKeys();
onWheelBehaviorChange();
@ -536,31 +528,10 @@ public:
deleteAllKeyItems();
}
void restoreKeys() {
for (KeyItem* keyItem : m_allKeyItems) {
keyItem->restoreKeys();
}
}
const Keys& wheelKeys() {
return m_wheelKeys;
}
bool isDefaultWheelBehavior() {
return (wheelBehavior()->selectedItem() == 0);
}
void disableWheelKey(const Accelerator& accel) {
for (KeyPtr& key : m_wheelKeys) {
for (int i=0; i<key->accels().size(); ++i) {
if (key->accels()[i] == accel) {
key->disableAccel(accel);
break;
}
}
}
}
private:
void deleteAllKeyItems() {
deleteList(searchList());
@ -569,7 +540,6 @@ private:
deleteList(tools());
deleteList(actions());
deleteList(wheelActions());
ASSERT(m_allKeyItems.empty());
}
void fillAllLists() {
@ -578,8 +548,9 @@ private:
// Load keyboard shortcuts
fillMenusList(menus(), AppMenus::instance()->getRootMenu(), 0);
fillToolsList(tools(), App::instance()->toolBox());
fillWheelActionsList();
for (const KeyPtr& key : *app::KeyboardShortcuts::instance()) {
for (const KeyPtr& key : m_keys) {
if (key->type() == KeyType::Tool ||
key->type() == KeyType::Quicktool ||
key->type() == KeyType::WheelAction) {
@ -600,7 +571,8 @@ private:
+ ": " + text;
break;
}
KeyItem* keyItem = new KeyItem(text, key, nullptr, 0, &m_headerItem);
KeyItem* keyItem = new KeyItem(m_keys, m_menuKeys, text, key,
nullptr, 0, &m_headerItem);
ListBox* listBox = nullptr;
switch (key->type()) {
@ -613,18 +585,14 @@ private:
}
ASSERT(listBox);
if (listBox) {
m_allKeyItems.push_back(keyItem);
if (listBox)
listBox->addChild(keyItem);
}
}
commands()->sortItems();
tools()->sortItems();
actions()->sortItems();
fillWheelActionsList();
section()->selectIndex(0);
updateViews();
}
@ -636,11 +604,6 @@ private:
while (listbox->lastChild()) {
Widget* item = listbox->lastChild();
listbox->removeChild(item);
auto it = std::find(m_allKeyItems.begin(), m_allKeyItems.end(), item);
if (it != m_allKeyItems.end())
m_allKeyItems.erase(it);
delete item;
}
}
@ -667,15 +630,12 @@ private:
}
KeyItem* copyItem =
new KeyItem(itemText,
keyItem->key(),
keyItem->menuitem(), 0,
&m_headerItem);
new KeyItem(m_keys, m_menuKeys, itemText, keyItem->key(),
keyItem->menuitem(), 0, &m_headerItem);
if (!item->isEnabled())
copyItem->setEnabled(false);
m_allKeyItems.push_back(copyItem);
searchList()->addChild(copyItem);
}
}
@ -690,17 +650,18 @@ private:
wheelZoom()->setVisible(isDefault);
if (isDefault) {
m_wheelKeys = app::KeyboardShortcuts::instance()
->getDefaultMouseWheelTable(wheelZoom()->isSelected());
m_keys.setDefaultMouseWheelKeys(wheelZoom()->isSelected());
m_wasDefault = true;
}
else if (m_wasDefault) {
m_wasDefault = false;
for (KeyPtr& key : m_wheelKeys)
key->copyOriginalToUser();
for (KeyPtr& key : m_keys) {
if (key->type() == KeyType::WheelAction)
key->copyOriginalToUser();
}
}
m_keys.addMissingMouseWheelKeys();
updateSlideZoomText();
addMissingWheelKeys();
fillWheelActionsList();
updateViews();
@ -715,10 +676,13 @@ private:
void fillWheelActionsList() {
deleteList(wheelActions());
for (const KeyPtr& key : m_wheelKeys) {
KeyItem* keyItem = new KeyItem(
key->triggerString(), key, nullptr, 0, &m_headerItem);
wheelActions()->addChild(keyItem);
for (const KeyPtr& key : m_keys) {
if (key->type() == KeyType::WheelAction) {
KeyItem* keyItem = new KeyItem(
m_keys, m_menuKeys, key->triggerString(), key,
nullptr, 0, &m_headerItem);
wheelActions()->addChild(keyItem);
}
}
wheelActions()->sortItems();
}
@ -780,8 +744,7 @@ private:
ASSERT(!filename.empty());
app::KeyboardShortcuts::instance()->importFile(
filename.front(), KeySource::UserDefined);
m_keys.importFile(filename.front(), KeySource::UserDefined);
fillAllLists();
}
@ -797,12 +760,12 @@ private:
ASSERT(!filename.empty());
app::KeyboardShortcuts::instance()->exportFile(filename.front());
m_keys.exportFile(filename.front());
}
void onReset() {
if (ui::Alert::show(Strings::alerts_restore_all_shortcuts()) == 1) {
app::KeyboardShortcuts::instance()->reset();
m_keys.reset();
listsPlaceholder()->layout();
}
}
@ -814,11 +777,12 @@ private:
continue;
KeyItem* keyItem = new KeyItem(
m_keys, m_menuKeys,
menuItem->text().c_str(),
menuItem->key(), menuItem, level,
m_menuKeys[menuItem],
menuItem, level,
&m_headerItem);
m_allKeyItems.push_back(keyItem);
listbox->addChild(keyItem);
if (menuItem->hasSubmenu())
@ -831,54 +795,27 @@ private:
for (Tool* tool : *toolbox) {
std::string text = tool->getText();
KeyPtr key = app::KeyboardShortcuts::instance()->tool(tool);
KeyItem* keyItem = new KeyItem(text, key, nullptr, 0,
&m_headerItem);
m_allKeyItems.push_back(keyItem);
KeyPtr key = m_keys.tool(tool);
KeyItem* keyItem = new KeyItem(m_keys, m_menuKeys, text, key,
nullptr, 0, &m_headerItem);
listbox->addChild(keyItem);
text += " (quick)";
key = app::KeyboardShortcuts::instance()->quicktool(tool);
keyItem = new KeyItem(text, key, nullptr, 0,
&m_headerItem);
m_allKeyItems.push_back(keyItem);
key = m_keys.quicktool(tool);
keyItem = new KeyItem(m_keys, m_menuKeys, text, key,
nullptr, 0, &m_headerItem);
listbox->addChild(keyItem);
}
}
// Adds missing WhellAction in m_wheelKeys
void addMissingWheelKeys() {
for (int wheelAction=int(WheelAction::First);
wheelAction<=int(WheelAction::Last); ++wheelAction) {
auto it = std::find_if(
m_wheelKeys.begin(), m_wheelKeys.end(),
[wheelAction](const KeyPtr& key) -> bool {
return key->wheelAction() == (WheelAction)wheelAction;
});
if (it == m_wheelKeys.end()) {
KeyPtr key = std::make_shared<Key>((WheelAction)wheelAction);
m_wheelKeys.push_back(key);
}
}
}
app::KeyboardShortcuts& m_keys;
MenuKeys& m_menuKeys;
std::vector<ListBox*> m_listBoxes;
std::vector<KeyItem*> m_allKeyItems;
bool m_searchChange;
bool m_wasDefault;
HeaderItem m_headerItem;
Keys m_wheelKeys;
};
void KeyItem::onAccelChange(const Accelerator& accel)
{
if (m_key && m_key->type() == KeyType::WheelAction) {
auto window = dynamic_cast<KeyboardShortcutsWindow*>(this->window());
if (window)
window->disableWheelKey(accel);
}
}
} // anonymous namespace
class KeyboardShortcutsCommand : public Command {
@ -891,7 +828,8 @@ protected:
void onExecute(Context* context) override;
private:
void addMissingKeyboardShortcutsForCommands();
void fillMenusKeys(app::KeyboardShortcuts& keys,
MenuKeys& menuKeys, Menu* menu);
std::string m_search;
};
@ -908,14 +846,20 @@ void KeyboardShortcutsCommand::onLoadParams(const Params& params)
void KeyboardShortcutsCommand::onExecute(Context* context)
{
addMissingKeyboardShortcutsForCommands();
app::KeyboardShortcuts* globalKeys = app::KeyboardShortcuts::instance();
app::KeyboardShortcuts keys;
keys.setKeys(*globalKeys, true);
keys.addMissingKeysForCommands();
MenuKeys menuKeys;
fillMenusKeys(keys, menuKeys, AppMenus::instance()->getRootMenu());
// Here we copy the m_search field because
// KeyboardShortcutsWindow::fillAllLists() modifies this same
// KeyboardShortcutsCommand instance (so m_search will be "")
// TODO Seeing this, we need a complete new way to handle UI commands execution
std::string neededSearchCopy = m_search;
KeyboardShortcutsWindow window(neededSearchCopy);
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy);
window.setBounds(gfx::Rect(0, 0, ui::display_w()*3/4, ui::display_h()*3/4));
@ -924,7 +868,9 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
window.openWindowInForeground();
if (window.closer() == window.ok()) {
KeyboardShortcuts::instance()->UserChange();
globalKeys->setKeys(keys, false);
for (const auto& p : menuKeys)
p.first->setKey(p.second);
// Save preferences in widgets that are bound to options automatically
{
@ -933,65 +879,36 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
window.sendMessage(msg);
}
if (window.isDefaultWheelBehavior()) {
for (KeyPtr& key : *KeyboardShortcuts::instance()) {
if (key->type() == KeyType::WheelAction)
key->reset();
}
}
else {
for (const KeyPtr& srcKey : window.wheelKeys()) {
KeyPtr dstKey = KeyboardShortcuts::instance()->wheelAction(srcKey->wheelAction());
*dstKey = *srcKey;
}
}
// Save keyboard shortcuts in configuration file
{
ResourceFinder rf;
rf.includeUserDir("user." KEYBOARD_FILENAME_EXTENSION);
std::string fn = rf.getFirstOrCreateDefault();
KeyboardShortcuts::instance()->exportFile(fn);
globalKeys->exportFile(fn);
}
}
else {
window.restoreKeys();
}
AppMenus::instance()->syncNativeMenuItemKeyShortcuts();
}
void KeyboardShortcutsCommand::addMissingKeyboardShortcutsForCommands()
void KeyboardShortcutsCommand::fillMenusKeys(app::KeyboardShortcuts& keys,
MenuKeys& menuKeys,
Menu* menu)
{
std::set<std::string> commandsAlreadyAdded;
auto keys = app::KeyboardShortcuts::instance();
for (const KeyPtr& key : *keys) {
if (key->type() != KeyType::Command)
continue;
for (auto child : menu->children()) {
if (AppMenuItem* menuItem = dynamic_cast<AppMenuItem*>(child)) {
if (menuItem == AppMenus::instance()->getRecentListMenuitem())
continue;
if (key->params().empty())
commandsAlreadyAdded.insert(key->command()->id());
}
if (menuItem->getCommand()) {
menuKeys[menuItem] =
keys.command(menuItem->getCommand()->id().c_str(),
menuItem->getParams());
}
std::vector<std::string> ids;
Commands* commands = Commands::instance();
commands->getAllIds(ids);
for (const std::string& id : ids) {
Command* command = commands->byId(id.c_str());
// Don't add commands that need params (they will be added to
// the list using the list of keyboard shortcuts from gui.xml).
if (command->needsParams())
continue;
auto it = commandsAlreadyAdded.find(command->id());
if (it != commandsAlreadyAdded.end())
continue;
// Create the new Key element in KeyboardShortcuts for this
// command without params.
keys->command(command->id().c_str());
if (menuItem->hasSubmenu())
fillMenusKeys(keys, menuKeys, menuItem->getSubmenu());
}
}
}

View File

@ -105,9 +105,9 @@ private:
bool onProcessMessage(ui::Message* msg) override {
switch (msg->type()) {
case ui::kKeyDownMessage: {
const KeyPtr key =
KeyboardShortcuts::instance()->command(CommandId::SwitchColors());
if (key && key->isPressed(msg)) {
KeyboardShortcuts* keys = KeyboardShortcuts::instance();
const KeyPtr key = keys->command(CommandId::SwitchColors());
if (key && key->isPressed(msg, *keys)) {
// Switch colors
app::Color from = m_fromButton->getColor();
app::Color to = m_toButton->getColor();

View File

@ -365,7 +365,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
}
break;
case kKeyDownMessage:
case kKeyDownMessage: {
#if ENABLE_DEVMODE
if (onProcessDevModeKeyDown(static_cast<KeyMessage*>(msg)))
return true;
@ -377,8 +377,9 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
if (Manager::onProcessMessage(msg))
return true;
for (const KeyPtr& key : *KeyboardShortcuts::instance()) {
if (key->isPressed(msg)) {
KeyboardShortcuts* keys = KeyboardShortcuts::instance();
for (const KeyPtr& key : *keys) {
if (key->isPressed(msg, *keys)) {
// Cancel menu-bar loops (to close any popup menu)
App::instance()->mainWindow()->getMenuBar()->cancelMenuLoop();
@ -393,7 +394,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
// Collect all tools with the pressed keyboard-shortcut
for (tools::Tool* tool : *toolbox) {
const KeyPtr key = KeyboardShortcuts::instance()->tool(tool);
if (key && key->isPressed(msg))
if (key && key->isPressed(msg, *keys))
possibles.push_back(tool);
}
@ -451,6 +452,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
}
}
break;
}
case kTimerMessage:
if (static_cast<TimerMessage*>(msg)->timer() == defered_invalid_timer) {

View File

@ -113,15 +113,17 @@ protected:
case kKeyDownMessage:
case kKeyUpMessage:
if (static_cast<KeyMessage*>(msg)->repeat() == 0) {
KeyPtr lmb = KeyboardShortcuts::instance()->action(KeyAction::LeftMouseButton);
KeyPtr rmb = KeyboardShortcuts::instance()->action(KeyAction::RightMouseButton);
KeyboardShortcuts* keys = KeyboardShortcuts::instance();
KeyPtr lmb = keys->action(KeyAction::LeftMouseButton);
KeyPtr rmb = keys->action(KeyAction::RightMouseButton);
// Convert action keys into mouse messages.
if (lmb->isPressed(msg) || rmb->isPressed(msg)) {
if (lmb->isPressed(msg, *keys) ||
rmb->isPressed(msg, *keys)) {
MouseMessage mouseMsg(
(msg->type() == kKeyDownMessage ? kMouseDownMessage: kMouseUpMessage),
PointerType::Unknown,
(lmb->isPressed(msg) ? kButtonLeft: kButtonRight),
(lmb->isPressed(msg, *keys) ? kButtonLeft: kButtonRight),
msg->modifiers(),
ui::get_mouse_position());

View File

@ -22,6 +22,7 @@ namespace ui {
namespace app {
class Command;
class KeyboardShortcuts;
namespace tools {
class Tool;
@ -110,8 +111,11 @@ namespace app {
const ui::Accelerators& userAccels() const { return m_users; }
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
void add(const ui::Accelerator& accel, KeySource source);
bool isPressed(const ui::Message* msg) const;
void add(const ui::Accelerator& accel,
const KeySource source,
KeyboardShortcuts& globalKeys);
bool isPressed(const ui::Message* msg,
KeyboardShortcuts& globalKeys) const;
bool isPressed() const;
bool isLooselyPressed() const;

View File

@ -14,6 +14,7 @@
#include "app/app_menus.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/doc.h"
#include "app/tools/ink.h"
@ -25,6 +26,10 @@
#include "ui/accelerator.h"
#include "ui/message.h"
#include <algorithm>
#include <set>
#include <vector>
#define XML_KEYBOARD_FILE_VERSION "1"
namespace {
@ -237,7 +242,9 @@ Key::Key(WheelAction wheelAction)
{
}
void Key::add(const ui::Accelerator& accel, KeySource source)
void Key::add(const ui::Accelerator& accel,
const KeySource source,
KeyboardShortcuts& globalKeys)
{
Accelerators* accels = &m_accels;
@ -251,7 +258,7 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
// Remove the accelerator from other commands
if (source == KeySource::UserDefined) {
KeyboardShortcuts::instance()->disableAccel(accel, m_keycontext, this);
globalKeys.disableAccel(accel, m_keycontext, this);
m_userRemoved.remove(accel);
}
@ -259,7 +266,8 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
accels->add(accel);
}
bool Key::isPressed(const Message* msg) const
bool Key::isPressed(const Message* msg,
KeyboardShortcuts& globalKeys) const
{
if (auto keyMsg = dynamic_cast<const KeyMessage*>(msg)) {
for (const Accelerator& accel : accels()) {
@ -267,7 +275,7 @@ bool Key::isPressed(const Message* msg) const
keyMsg->scancode(),
keyMsg->unicodeChar()) &&
(m_keycontext == KeyContext::Any ||
m_keycontext == KeyboardShortcuts::instance()->getCurrentKeyContext())) {
m_keycontext == globalKeys.getCurrentKeyContext())) {
return true;
}
}
@ -378,6 +386,19 @@ KeyboardShortcuts::~KeyboardShortcuts()
clear();
}
void KeyboardShortcuts::setKeys(const KeyboardShortcuts& keys,
const bool cloneKeys)
{
if (cloneKeys) {
for (const KeyPtr& key : keys)
m_keys.push_back(std::make_shared<Key>(*key));
}
else {
m_keys = keys.m_keys;
}
UserChange();
}
void KeyboardShortcuts::clear()
{
m_keys.clear();
@ -428,7 +449,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
Accelerator accel(command_key);
if (!removed) {
key->add(accel, source);
key->add(accel, source, *this);
// Add the shortcut to the menuitems with this command
// (this is only visual, the
@ -467,7 +488,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
Accelerator accel(tool_key);
if (!removed)
key->add(accel, source);
key->add(accel, source, *this);
else
key->disableAccel(accel);
}
@ -495,7 +516,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
Accelerator accel(tool_key);
if (!removed)
key->add(accel, source);
key->add(accel, source, *this);
else
key->disableAccel(accel);
}
@ -524,7 +545,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
Accelerator accel(action_key);
if (!removed)
key->add(accel, source);
key->add(accel, source, *this);
else
key->disableAccel(accel);
}
@ -553,7 +574,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
Accelerator accel(action_key);
if (!removed)
key->add(accel, source);
key->add(accel, source, *this);
else
key->disableAccel(accel);
}
@ -780,7 +801,8 @@ KeyContext KeyboardShortcuts::getCurrentKeyContext()
bool KeyboardShortcuts::getCommandFromKeyMessage(const Message* msg, Command** command, Params* params)
{
for (KeyPtr& key : m_keys) {
if (key->type() == KeyType::Command && key->isPressed(msg)) {
if (key->type() == KeyType::Command &&
key->isPressed(msg, *this)) {
if (command) *command = key->command();
if (params) *params = key->params();
return true;
@ -833,7 +855,7 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
for (const KeyPtr& key : m_keys) {
if (key->type() == KeyType::WheelAction &&
key->keycontext() == context &&
key->isPressed(msg))
key->isPressed(msg, *this))
return key->wheelAction();
}
return WheelAction::None;
@ -849,40 +871,104 @@ bool KeyboardShortcuts::hasMouseWheelCustomization() const
return false;
}
Keys KeyboardShortcuts::getDefaultMouseWheelTable(const bool zoomWithWheel) const
void KeyboardShortcuts::clearMouseWheelKeys()
{
Keys keys;
KeyPtr key;
for (auto it=m_keys.begin(); it!=m_keys.end(); ) {
if ((*it)->type() == KeyType::WheelAction)
it = m_keys.erase(it);
else
++it;
}
}
void KeyboardShortcuts::addMissingMouseWheelKeys()
{
for (int wheelAction=int(WheelAction::First);
wheelAction<=int(WheelAction::Last); ++wheelAction) {
auto it = std::find_if(
m_keys.begin(), m_keys.end(),
[wheelAction](const KeyPtr& key) -> bool {
return key->wheelAction() == (WheelAction)wheelAction;
});
if (it == m_keys.end()) {
KeyPtr key = std::make_shared<Key>((WheelAction)wheelAction);
m_keys.push_back(key);
}
}
}
void KeyboardShortcuts::setDefaultMouseWheelKeys(const bool zoomWithWheel)
{
clearMouseWheelKeys();
KeyPtr key;
key = std::make_shared<Key>(WheelAction::Zoom);
key->add(Accelerator(zoomWithWheel ? kKeyNoneModifier: kKeyCtrlModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key->add(Accelerator(zoomWithWheel ? kKeyNoneModifier:
kKeyCtrlModifier, kKeyNil, 0),
KeySource::Original, *this);
m_keys.push_back(key);
if (!zoomWithWheel) {
key = std::make_shared<Key>(WheelAction::VScroll);
key->add(Accelerator(kKeyNoneModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key->add(Accelerator(kKeyNoneModifier, kKeyNil, 0),
KeySource::Original, *this);
m_keys.push_back(key);
}
key = std::make_shared<Key>(WheelAction::HScroll);
key->add(Accelerator(kKeyShiftModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key->add(Accelerator(kKeyShiftModifier, kKeyNil, 0),
KeySource::Original, *this);
m_keys.push_back(key);
key = std::make_shared<Key>(WheelAction::FgColor);
key->add(Accelerator(kKeyAltModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key->add(Accelerator(kKeyAltModifier, kKeyNil, 0),
KeySource::Original, *this);
m_keys.push_back(key);
key = std::make_shared<Key>(WheelAction::BgColor);
key->add(Accelerator((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key->add(Accelerator((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0),
KeySource::Original, *this);
m_keys.push_back(key);
if (zoomWithWheel) {
key = std::make_shared<Key>(WheelAction::Frame);
key->add(Accelerator(kKeyCtrlModifier, kKeyNil, 0), KeySource::Original);
keys.push_back(key);
key->add(Accelerator(kKeyCtrlModifier, kKeyNil, 0),
KeySource::Original, *this);
m_keys.push_back(key);
}
}
void KeyboardShortcuts::addMissingKeysForCommands()
{
std::set<std::string> commandsAlreadyAdded;
for (const KeyPtr& key : m_keys) {
if (key->type() != KeyType::Command)
continue;
if (key->params().empty())
commandsAlreadyAdded.insert(key->command()->id());
}
return keys;
std::vector<std::string> ids;
Commands* commands = Commands::instance();
commands->getAllIds(ids);
for (const std::string& id : ids) {
Command* command = commands->byId(id.c_str());
// Don't add commands that need params (they will be added to
// the list using the list of keyboard shortcuts from gui.xml).
if (command->needsParams())
continue;
auto it = commandsAlreadyAdded.find(command->id());
if (it != commandsAlreadyAdded.end())
continue;
// Create the new Key element in KeyboardShortcuts for this
// command without params.
this->command(command->id().c_str());
}
}
std::string key_tooltip(const char* str, const app::Key* key)

View File

@ -9,7 +9,6 @@
#pragma once
#include "app/ui/key.h"
#include "base/disable_copying.h"
#include "obs/signal.h"
class TiXmlElement;
@ -22,15 +21,21 @@ namespace app {
typedef Keys::const_iterator const_iterator;
static KeyboardShortcuts* instance();
~KeyboardShortcuts();
const Keys& keys() const { return m_keys; }
KeyboardShortcuts();
KeyboardShortcuts(const KeyboardShortcuts&) = delete;
KeyboardShortcuts& operator=(const KeyboardShortcuts&) = delete;
~KeyboardShortcuts();
iterator begin() { return m_keys.begin(); }
iterator end() { return m_keys.end(); }
const_iterator begin() const { return m_keys.begin(); }
const_iterator end() const { return m_keys.end(); }
// const Keys& keys() const { return m_keys; }
void setKeys(const KeyboardShortcuts& keys,
const bool cloneKeys);
void clear();
void importFile(TiXmlElement* rootElement, KeySource source);
void importFile(const std::string& filename, KeySource source);
@ -55,21 +60,21 @@ namespace app {
WheelAction getWheelActionFromMouseMessage(const KeyContext context,
const ui::Message* msg);
bool hasMouseWheelCustomization() const;
Keys getDefaultMouseWheelTable(const bool zoomWithWheel) const;
void clearMouseWheelKeys();
void addMissingMouseWheelKeys();
void setDefaultMouseWheelKeys(const bool zoomWithWheel);
// Generated when the tooltips are modified by the user.
void addMissingKeysForCommands();
// Generated when the keyboard shortcuts are modified by the user.
// Useful to regenerate tooltips with shortcuts.
obs::signal<void()> UserChange;
private:
KeyboardShortcuts();
void exportKeys(TiXmlElement& parent, KeyType type);
void exportAccel(TiXmlElement& parent, const Key* key, const ui::Accelerator& accel, bool removed);
Keys m_keys;
DISABLE_COPYING(KeyboardShortcuts);
};
std::string key_tooltip(const char* str, const Key* key);

View File

@ -11,6 +11,7 @@
#include "app/ui/select_accelerator.h"
#include "app/ui/key.h"
#include "app/ui/keyboard_shortcuts.h"
#include "base/bind.h"
#include "obs/signal.h"
#include "ui/entry.h"
@ -87,7 +88,7 @@ protected:
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel,
const KeyContext keyContext,
const Keys& currentKeys)
const KeyboardShortcuts& currentKeys)
: m_keyField(new KeyField(accel))
, m_keyContext(keyContext)
, m_currentKeys(currentKeys)

View File

@ -8,19 +8,20 @@
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
#pragma once
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/key_context.h"
#include "ui/accelerator.h"
#include "ui/tooltips.h"
#include "select_accelerator.xml.h"
namespace app {
class KeyboardShortcuts;
class SelectAccelerator : public app::gen::SelectAccelerator {
public:
SelectAccelerator(const ui::Accelerator& accelerator,
const KeyContext keyContext,
const Keys& currentKeys);
const KeyboardShortcuts& currentKeys);
bool isOK() const { return m_ok; }
bool isModified() const { return m_modified; }
@ -40,7 +41,7 @@ namespace app {
ui::TooltipManager m_tooltipManager;
KeyField* m_keyField;
KeyContext m_keyContext;
const Keys& m_currentKeys;
const KeyboardShortcuts& m_currentKeys;
ui::Accelerator m_origAccel;
ui::Accelerator m_accel;
bool m_ok;