mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-01 01:20:25 +00:00
parent
721e401052
commit
e4c2995326
@ -1282,6 +1282,7 @@ download_themes = Download Themes
|
|||||||
open_theme_folder = Open &Folder
|
open_theme_folder = Open &Folder
|
||||||
language_extensions = Languages
|
language_extensions = Languages
|
||||||
theme_extensions = Themes
|
theme_extensions = Themes
|
||||||
|
keys_extensions = Keyboard Shortcuts
|
||||||
script_extensions = Scripts
|
script_extensions = Scripts
|
||||||
palette_extensions = Palettes
|
palette_extensions = Palettes
|
||||||
dithering_matrix_extensions = Dithering Matrices
|
dithering_matrix_extensions = Dithering Matrices
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -16,6 +16,7 @@
|
|||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/console.h"
|
#include "app/console.h"
|
||||||
|
#include "app/extensions.h"
|
||||||
#include "app/gui_xml.h"
|
#include "app/gui_xml.h"
|
||||||
#include "app/i18n/strings.h"
|
#include "app/i18n/strings.h"
|
||||||
#include "app/recent_files.h"
|
#include "app/recent_files.h"
|
||||||
@ -417,10 +418,22 @@ void AppMenus::reload()
|
|||||||
.FirstChild("gui")
|
.FirstChild("gui")
|
||||||
.FirstChild("keyboard").ToElement();
|
.FirstChild("keyboard").ToElement();
|
||||||
|
|
||||||
|
// From a fresh start, load the default keys
|
||||||
KeyboardShortcuts::instance()->clear();
|
KeyboardShortcuts::instance()->clear();
|
||||||
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
|
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
|
||||||
|
|
||||||
// Load user settings
|
// Load extension-defined keys
|
||||||
|
for (const Extension* ext : App::instance()->extensions()) {
|
||||||
|
if (ext->isEnabled() &&
|
||||||
|
ext->hasKeys()) {
|
||||||
|
for (const auto& kv : ext->keys()) {
|
||||||
|
KeyboardShortcuts::instance()->importFile(
|
||||||
|
kv.second, KeySource::ExtensionDefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load user-defined keys
|
||||||
{
|
{
|
||||||
ResourceFinder rf;
|
ResourceFinder rf;
|
||||||
rf.includeUserDir("user.aseprite-keys");
|
rf.includeUserDir("user.aseprite-keys");
|
||||||
|
@ -58,7 +58,7 @@ using namespace ui;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef std::map<AppMenuItem*, KeyPtr> MenuKeys;
|
using MenuKeys = std::map<AppMenuItem*, KeyPtr>;
|
||||||
|
|
||||||
class HeaderSplitter : public Splitter {
|
class HeaderSplitter : public Splitter {
|
||||||
public:
|
public:
|
||||||
@ -195,7 +195,7 @@ private:
|
|||||||
window.openWindowInForeground();
|
window.openWindowInForeground();
|
||||||
|
|
||||||
if (window.isModified()) {
|
if (window.isModified()) {
|
||||||
m_key->disableAccel(origAccel);
|
m_key->disableAccel(origAccel, KeySource::UserDefined);
|
||||||
if (!window.accel().isEmpty())
|
if (!window.accel().isEmpty())
|
||||||
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ private:
|
|||||||
accel.toString())) != 1)
|
accel.toString())) != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_key->disableAccel(accel);
|
m_key->disableAccel(accel, KeySource::UserDefined);
|
||||||
window()->layout();
|
window()->layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1277,6 +1277,10 @@ private:
|
|||||||
if (extensionsList()->getItemsCount() > 0)
|
if (extensionsList()->getItemsCount() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
loadExtensionsByCategory(
|
||||||
|
Extension::Category::Keys,
|
||||||
|
Strings::options_keys_extensions());
|
||||||
|
|
||||||
loadExtensionsByCategory(
|
loadExtensionsByCategory(
|
||||||
Extension::Category::Languages,
|
Extension::Category::Languages,
|
||||||
Strings::options_language_extensions());
|
Strings::options_language_extensions());
|
||||||
|
@ -257,6 +257,12 @@ void Extension::executeExitActions()
|
|||||||
#endif // ENABLE_SCRIPTING
|
#endif // ENABLE_SCRIPTING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Extension::addKeys(const std::string& id, const std::string& path)
|
||||||
|
{
|
||||||
|
m_keys[id] = path;
|
||||||
|
updateCategory(Category::Keys);
|
||||||
|
}
|
||||||
|
|
||||||
void Extension::addLanguage(const std::string& id, const std::string& path)
|
void Extension::addLanguage(const std::string& id, const std::string& path)
|
||||||
{
|
{
|
||||||
m_languages[id] = path;
|
m_languages[id] = path;
|
||||||
@ -456,8 +462,10 @@ bool Extension::isDefaultTheme() const
|
|||||||
|
|
||||||
void Extension::updateCategory(const Category newCategory)
|
void Extension::updateCategory(const Category newCategory)
|
||||||
{
|
{
|
||||||
if (m_category == Category::None)
|
if (m_category == Category::None ||
|
||||||
|
m_category == Category::Keys) {
|
||||||
m_category = newCategory;
|
m_category = newCategory;
|
||||||
|
}
|
||||||
else if (m_category != newCategory)
|
else if (m_category != newCategory)
|
||||||
m_category = Category::Multiple;
|
m_category = Category::Multiple;
|
||||||
}
|
}
|
||||||
@ -1016,6 +1024,24 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
|
|
||||||
auto contributes = json["contributes"];
|
auto contributes = json["contributes"];
|
||||||
if (contributes.is_object()) {
|
if (contributes.is_object()) {
|
||||||
|
// Keys
|
||||||
|
auto keys = contributes["keys"];
|
||||||
|
if (keys.is_array()) {
|
||||||
|
for (const auto& key : keys.array_items()) {
|
||||||
|
std::string keyId = key["id"].string_value();
|
||||||
|
std::string keyPath = key["path"].string_value();
|
||||||
|
|
||||||
|
// The path must be always relative to the extension
|
||||||
|
keyPath = base::join_path(path, keyPath);
|
||||||
|
|
||||||
|
LOG("EXT: New keyboard shortcuts '%s' in '%s'\n",
|
||||||
|
keyId.c_str(),
|
||||||
|
keyPath.c_str());
|
||||||
|
|
||||||
|
extension->addKeys(keyId, keyPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
auto languages = contributes["languages"];
|
auto languages = contributes["languages"];
|
||||||
if (languages.is_array()) {
|
if (languages.is_array()) {
|
||||||
@ -1130,6 +1156,7 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
|
|
||||||
void Extensions::generateExtensionSignals(Extension* extension)
|
void Extensions::generateExtensionSignals(Extension* extension)
|
||||||
{
|
{
|
||||||
|
if (extension->hasKeys()) KeysChange(extension);
|
||||||
if (extension->hasLanguages()) LanguagesChange(extension);
|
if (extension->hasLanguages()) LanguagesChange(extension);
|
||||||
if (extension->hasThemes()) ThemesChange(extension);
|
if (extension->hasThemes()) ThemesChange(extension);
|
||||||
if (extension->hasPalettes()) PalettesChange(extension);
|
if (extension->hasPalettes()) PalettesChange(extension);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A.
|
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -36,6 +36,7 @@ namespace app {
|
|||||||
public:
|
public:
|
||||||
enum class Category {
|
enum class Category {
|
||||||
None,
|
None,
|
||||||
|
Keys,
|
||||||
Languages,
|
Languages,
|
||||||
Themes,
|
Themes,
|
||||||
Scripts,
|
Scripts,
|
||||||
@ -78,10 +79,12 @@ namespace app {
|
|||||||
const std::string& displayName() const { return m_displayName; }
|
const std::string& displayName() const { return m_displayName; }
|
||||||
const Category category() const { return m_category; }
|
const Category category() const { return m_category; }
|
||||||
|
|
||||||
|
const ExtensionItems& keys() const { return m_keys; }
|
||||||
const ExtensionItems& languages() const { return m_languages; }
|
const ExtensionItems& languages() const { return m_languages; }
|
||||||
const ExtensionItems& themes() const { return m_themes; }
|
const ExtensionItems& themes() const { return m_themes; }
|
||||||
const ExtensionItems& palettes() const { return m_palettes; }
|
const ExtensionItems& palettes() const { return m_palettes; }
|
||||||
|
|
||||||
|
void addKeys(const std::string& id, const std::string& path);
|
||||||
void addLanguage(const std::string& id, const std::string& path);
|
void addLanguage(const std::string& id, const std::string& path);
|
||||||
void addTheme(const std::string& id, const std::string& path);
|
void addTheme(const std::string& id, const std::string& path);
|
||||||
void addPalette(const std::string& id, const std::string& path);
|
void addPalette(const std::string& id, const std::string& path);
|
||||||
@ -98,6 +101,7 @@ namespace app {
|
|||||||
bool canBeDisabled() const;
|
bool canBeDisabled() const;
|
||||||
bool canBeUninstalled() const;
|
bool canBeUninstalled() const;
|
||||||
|
|
||||||
|
bool hasKeys() const { return !m_keys.empty(); }
|
||||||
bool hasLanguages() const { return !m_languages.empty(); }
|
bool hasLanguages() const { return !m_languages.empty(); }
|
||||||
bool hasThemes() const { return !m_themes.empty(); }
|
bool hasThemes() const { return !m_themes.empty(); }
|
||||||
bool hasPalettes() const { return !m_palettes.empty(); }
|
bool hasPalettes() const { return !m_palettes.empty(); }
|
||||||
@ -119,6 +123,7 @@ namespace app {
|
|||||||
void exitScripts();
|
void exitScripts();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ExtensionItems m_keys;
|
||||||
ExtensionItems m_languages;
|
ExtensionItems m_languages;
|
||||||
ExtensionItems m_themes;
|
ExtensionItems m_themes;
|
||||||
ExtensionItems m_palettes;
|
ExtensionItems m_palettes;
|
||||||
@ -180,6 +185,7 @@ namespace app {
|
|||||||
std::vector<Extension::DitheringMatrixInfo> ditheringMatrices();
|
std::vector<Extension::DitheringMatrixInfo> ditheringMatrices();
|
||||||
|
|
||||||
obs::signal<void(Extension*)> NewExtension;
|
obs::signal<void(Extension*)> NewExtension;
|
||||||
|
obs::signal<void(Extension*)> KeysChange;
|
||||||
obs::signal<void(Extension*)> LanguagesChange;
|
obs::signal<void(Extension*)> LanguagesChange;
|
||||||
obs::signal<void(Extension*)> ThemesChange;
|
obs::signal<void(Extension*)> ThemesChange;
|
||||||
obs::signal<void(Extension*)> PalettesChange;
|
obs::signal<void(Extension*)> PalettesChange;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -15,6 +15,7 @@
|
|||||||
#include "ui/accelerator.h"
|
#include "ui/accelerator.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@ -31,6 +32,7 @@ namespace app {
|
|||||||
|
|
||||||
enum class KeySource {
|
enum class KeySource {
|
||||||
Original,
|
Original,
|
||||||
|
ExtensionDefined,
|
||||||
UserDefined
|
UserDefined
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,20 +100,20 @@ namespace app {
|
|||||||
return KeyAction(int(a) & int(b));
|
return KeyAction(int(a) & int(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using KeySourceAccelList = std::vector<std::pair<KeySource, ui::Accelerator>>;
|
||||||
|
|
||||||
class Key {
|
class Key {
|
||||||
public:
|
public:
|
||||||
|
Key(const Key& key);
|
||||||
Key(Command* command, const Params& params, KeyContext keyContext);
|
Key(Command* command, const Params& params, KeyContext keyContext);
|
||||||
Key(KeyType type, tools::Tool* tool);
|
Key(KeyType type, tools::Tool* tool);
|
||||||
explicit Key(KeyAction action);
|
explicit Key(KeyAction action);
|
||||||
explicit Key(WheelAction action);
|
explicit Key(WheelAction action);
|
||||||
|
|
||||||
KeyType type() const { return m_type; }
|
KeyType type() const { return m_type; }
|
||||||
const ui::Accelerators& accels() const {
|
const ui::Accelerators& accels() const;
|
||||||
return (m_useUsers ? m_users: m_accels);
|
const KeySourceAccelList addsKeys() const { return m_adds; }
|
||||||
}
|
const KeySourceAccelList delsKeys() const { return m_dels; }
|
||||||
const ui::Accelerators& origAccels() const { return m_accels; }
|
|
||||||
const ui::Accelerators& userAccels() const { return m_users; }
|
|
||||||
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
|
|
||||||
|
|
||||||
void add(const ui::Accelerator& accel,
|
void add(const ui::Accelerator& accel,
|
||||||
const KeySource source,
|
const KeySource source,
|
||||||
@ -122,9 +124,15 @@ namespace app {
|
|||||||
bool isLooselyPressed() const;
|
bool isLooselyPressed() const;
|
||||||
|
|
||||||
bool hasAccel(const ui::Accelerator& accel) const;
|
bool hasAccel(const ui::Accelerator& accel) const;
|
||||||
void disableAccel(const ui::Accelerator& accel);
|
bool hasUserDefinedAccels() const;
|
||||||
|
|
||||||
// Resets user accelerators to the original ones.
|
// The KeySource indicates from where the key was disabled
|
||||||
|
// (e.g. if it was removed from an extension-defined file, or from
|
||||||
|
// user-defined).
|
||||||
|
void disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source);
|
||||||
|
|
||||||
|
// Resets user accelerators to the original & extension-defined ones.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void copyOriginalToUser();
|
void copyOriginalToUser();
|
||||||
@ -144,10 +152,11 @@ namespace app {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
KeyType m_type;
|
KeyType m_type;
|
||||||
ui::Accelerators m_accels; // Default accelerators (from gui.xml)
|
KeySourceAccelList m_adds;
|
||||||
ui::Accelerators m_users; // User-defined accelerators
|
KeySourceAccelList m_dels;
|
||||||
ui::Accelerators m_userRemoved; // Default accelerators removed by user
|
// Final list of accelerators after processing the
|
||||||
bool m_useUsers;
|
// addition/deletion of extension-defined & user-defined keys.
|
||||||
|
mutable std::unique_ptr<ui::Accelerators> m_accels;
|
||||||
KeyContext m_keycontext;
|
KeyContext m_keycontext;
|
||||||
|
|
||||||
// for KeyType::Command
|
// for KeyType::Command
|
||||||
@ -161,8 +170,8 @@ namespace app {
|
|||||||
WheelAction m_wheelAction;
|
WheelAction m_wheelAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<Key> KeyPtr;
|
using KeyPtr = std::shared_ptr<Key> ;
|
||||||
typedef std::vector<KeyPtr> Keys;
|
using Keys = std::vector<KeyPtr>;
|
||||||
|
|
||||||
std::string convertKeyContextToString(KeyContext keyContext);
|
std::string convertKeyContextToString(KeyContext keyContext);
|
||||||
std::string convertKeyContextToUserFriendlyString(KeyContext keyContext);
|
std::string convertKeyContextToUserFriendlyString(KeyContext keyContext);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -124,6 +124,32 @@ namespace {
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void erase_accel(app::KeySourceAccelList& kvs,
|
||||||
|
const app::KeySource source,
|
||||||
|
const ui::Accelerator& accel) {
|
||||||
|
for (auto it=kvs.begin(); it!=kvs.end(); ) {
|
||||||
|
auto& kv = *it;
|
||||||
|
if (kv.first == source &&
|
||||||
|
kv.second == accel) {
|
||||||
|
it = kvs.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase_accels(app::KeySourceAccelList& kvs,
|
||||||
|
const app::KeySource source) {
|
||||||
|
for (auto it=kvs.begin(); it!=kvs.end(); ) {
|
||||||
|
auto& kv = *it;
|
||||||
|
if (kv.first == source) {
|
||||||
|
it = kvs.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
@ -171,9 +197,33 @@ using namespace ui;
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Key
|
// Key
|
||||||
|
|
||||||
|
Key::Key(const Key& k)
|
||||||
|
: m_type(k.m_type)
|
||||||
|
, m_adds(k.m_adds)
|
||||||
|
, m_dels(k.m_dels)
|
||||||
|
, m_keycontext(k.m_keycontext)
|
||||||
|
{
|
||||||
|
switch (m_type) {
|
||||||
|
case KeyType::Command:
|
||||||
|
m_command = k.m_command;
|
||||||
|
m_params = k.m_params;
|
||||||
|
break;
|
||||||
|
case KeyType::Tool:
|
||||||
|
case KeyType::Quicktool:
|
||||||
|
m_tool = k.m_tool;
|
||||||
|
break;
|
||||||
|
case KeyType::Action:
|
||||||
|
m_action = k.m_action;
|
||||||
|
break;
|
||||||
|
case KeyType::WheelAction:
|
||||||
|
m_action = k.m_action;
|
||||||
|
m_wheelAction = k.m_wheelAction;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Key::Key(Command* command, const Params& params, KeyContext keyContext)
|
Key::Key(Command* command, const Params& params, KeyContext keyContext)
|
||||||
: m_type(KeyType::Command)
|
: m_type(KeyType::Command)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(keyContext)
|
, m_keycontext(keyContext)
|
||||||
, m_command(command)
|
, m_command(command)
|
||||||
, m_params(params)
|
, m_params(params)
|
||||||
@ -182,7 +232,6 @@ Key::Key(Command* command, const Params& params, KeyContext keyContext)
|
|||||||
|
|
||||||
Key::Key(KeyType type, tools::Tool* tool)
|
Key::Key(KeyType type, tools::Tool* tool)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(KeyContext::Any)
|
, m_keycontext(KeyContext::Any)
|
||||||
, m_tool(tool)
|
, m_tool(tool)
|
||||||
{
|
{
|
||||||
@ -190,7 +239,6 @@ Key::Key(KeyType type, tools::Tool* tool)
|
|||||||
|
|
||||||
Key::Key(KeyAction action)
|
Key::Key(KeyAction action)
|
||||||
: m_type(KeyType::Action)
|
: m_type(KeyType::Action)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(KeyContext::Any)
|
, m_keycontext(KeyContext::Any)
|
||||||
, m_action(action)
|
, m_action(action)
|
||||||
{
|
{
|
||||||
@ -239,35 +287,63 @@ Key::Key(KeyAction action)
|
|||||||
|
|
||||||
Key::Key(WheelAction wheelAction)
|
Key::Key(WheelAction wheelAction)
|
||||||
: m_type(KeyType::WheelAction)
|
: m_type(KeyType::WheelAction)
|
||||||
, m_useUsers(false)
|
|
||||||
, m_keycontext(KeyContext::MouseWheel)
|
, m_keycontext(KeyContext::MouseWheel)
|
||||||
, m_action(KeyAction::None)
|
, m_action(KeyAction::None)
|
||||||
, m_wheelAction(wheelAction)
|
, m_wheelAction(wheelAction)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ui::Accelerators& Key::accels() const
|
||||||
|
{
|
||||||
|
if (!m_accels) {
|
||||||
|
m_accels = std::make_unique<ui::Accelerators>();
|
||||||
|
|
||||||
|
// Add default keys
|
||||||
|
for (const auto& kv : m_adds) {
|
||||||
|
if (kv.first == KeySource::Original)
|
||||||
|
m_accels->add(kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete/add extension-defined keys
|
||||||
|
for (const auto& kv : m_dels) {
|
||||||
|
if (kv.first == KeySource::ExtensionDefined)
|
||||||
|
m_accels->remove(kv.second);
|
||||||
|
else {
|
||||||
|
ASSERT(kv.first != KeySource::Original);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& kv : m_adds) {
|
||||||
|
if (kv.first == KeySource::ExtensionDefined)
|
||||||
|
m_accels->add(kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete/add user-defined keys
|
||||||
|
for (const auto& kv : m_dels) {
|
||||||
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
m_accels->remove(kv.second);
|
||||||
|
}
|
||||||
|
for (const auto& kv : m_adds) {
|
||||||
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
m_accels->add(kv.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *m_accels;
|
||||||
|
}
|
||||||
|
|
||||||
void Key::add(const ui::Accelerator& accel,
|
void Key::add(const ui::Accelerator& accel,
|
||||||
const KeySource source,
|
const KeySource source,
|
||||||
KeyboardShortcuts& globalKeys)
|
KeyboardShortcuts& globalKeys)
|
||||||
{
|
{
|
||||||
Accelerators* accels = &m_accels;
|
m_adds.emplace_back(source, accel);
|
||||||
|
m_accels.reset();
|
||||||
if (source == KeySource::UserDefined) {
|
|
||||||
if (!m_useUsers) {
|
|
||||||
m_useUsers = true;
|
|
||||||
m_users = m_accels;
|
|
||||||
}
|
|
||||||
accels = &m_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the accelerator from other commands
|
// Remove the accelerator from other commands
|
||||||
if (source == KeySource::UserDefined) {
|
if (source == KeySource::ExtensionDefined ||
|
||||||
globalKeys.disableAccel(accel, m_keycontext, this);
|
source == KeySource::UserDefined) {
|
||||||
m_userRemoved.remove(accel);
|
erase_accel(m_dels, source, accel);
|
||||||
}
|
|
||||||
|
|
||||||
// Add the accelerator
|
globalKeys.disableAccel(accel, source, m_keycontext, this);
|
||||||
accels->add(accel);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ui::Accelerator* Key::isPressed(const Message* msg,
|
const ui::Accelerator* Key::isPressed(const Message* msg,
|
||||||
@ -322,31 +398,47 @@ bool Key::hasAccel(const ui::Accelerator& accel) const
|
|||||||
return accels().has(accel);
|
return accels().has(accel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key::disableAccel(const ui::Accelerator& accel)
|
bool Key::hasUserDefinedAccels() const
|
||||||
{
|
{
|
||||||
if (!m_useUsers) {
|
for (const auto& kv : m_adds) {
|
||||||
m_useUsers = true;
|
if (kv.first == KeySource::UserDefined)
|
||||||
m_users = m_accels;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_users.remove(accel);
|
void Key::disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source)
|
||||||
|
{
|
||||||
|
// It doesn't make sense that the default keyboard shortcuts file
|
||||||
|
// (gui.xml) removes some accelerator.
|
||||||
|
ASSERT(source != KeySource::Original);
|
||||||
|
|
||||||
if (m_accels.has(accel))
|
erase_accel(m_adds, source, accel);
|
||||||
m_userRemoved.add(accel);
|
erase_accel(m_dels, source, accel);
|
||||||
|
|
||||||
|
m_dels.emplace_back(source, accel);
|
||||||
|
m_accels.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key::reset()
|
void Key::reset()
|
||||||
{
|
{
|
||||||
m_users.clear();
|
erase_accels(m_adds, KeySource::UserDefined);
|
||||||
m_userRemoved.clear();
|
erase_accels(m_dels, KeySource::UserDefined);
|
||||||
m_useUsers = false;
|
m_accels.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Key::copyOriginalToUser()
|
void Key::copyOriginalToUser()
|
||||||
{
|
{
|
||||||
m_users = m_accels;
|
// Erase all user-defined keys
|
||||||
m_userRemoved.clear();
|
erase_accels(m_adds, KeySource::UserDefined);
|
||||||
m_useUsers = true;
|
erase_accels(m_dels, KeySource::UserDefined);
|
||||||
|
|
||||||
|
// Then copy all original & extension-defined keys as user-defined
|
||||||
|
auto copy = m_adds;
|
||||||
|
for (const auto& kv : copy)
|
||||||
|
m_adds.emplace_back(KeySource::UserDefined, kv.second);
|
||||||
|
m_accels.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Key::triggerString() const
|
std::string Key::triggerString() const
|
||||||
@ -465,7 +557,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,7 +586,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,7 +614,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,7 +642,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -578,7 +670,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
|||||||
if (!removed)
|
if (!removed)
|
||||||
key->add(accel, source, *this);
|
key->add(accel, source, *this);
|
||||||
else
|
else
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -633,11 +725,13 @@ void KeyboardShortcuts::exportKeys(TiXmlElement& parent, KeyType type)
|
|||||||
if (key->type() != type)
|
if (key->type() != type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (const ui::Accelerator& accel : key->userRemovedAccels())
|
for (const auto& kv : key->delsKeys())
|
||||||
exportAccel(parent, key.get(), accel, true);
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
exportAccel(parent, key.get(), kv.second, true);
|
||||||
|
|
||||||
for (const ui::Accelerator& accel : key->userAccels())
|
for (const auto& kv : key->addsKeys())
|
||||||
exportAccel(parent, key.get(), accel, false);
|
if (kv.first == KeySource::UserDefined)
|
||||||
|
exportAccel(parent, key.get(), kv.second, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,17 +867,19 @@ KeyPtr KeyboardShortcuts::wheelAction(WheelAction wheelAction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source,
|
||||||
const KeyContext keyContext,
|
const KeyContext keyContext,
|
||||||
const Key* newKey)
|
const Key* newKey)
|
||||||
{
|
{
|
||||||
for (KeyPtr& key : m_keys) {
|
for (KeyPtr& key : m_keys) {
|
||||||
if (key->keycontext() == keyContext &&
|
if (key.get() != newKey &&
|
||||||
|
key->keycontext() == keyContext &&
|
||||||
key->hasAccel(accel) &&
|
key->hasAccel(accel) &&
|
||||||
// Tools can contain the same keyboard shortcut
|
// Tools can contain the same keyboard shortcut
|
||||||
(key->type() != KeyType::Tool ||
|
(key->type() != KeyType::Tool ||
|
||||||
newKey == nullptr ||
|
newKey == nullptr ||
|
||||||
newKey->type() != KeyType::Tool)) {
|
newKey->type() != KeyType::Tool)) {
|
||||||
key->disableAccel(accel);
|
key->disableAccel(accel, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -885,7 +981,7 @@ bool KeyboardShortcuts::hasMouseWheelCustomization() const
|
|||||||
{
|
{
|
||||||
for (const KeyPtr& key : m_keys) {
|
for (const KeyPtr& key : m_keys) {
|
||||||
if (key->type() == KeyType::WheelAction &&
|
if (key->type() == KeyType::WheelAction &&
|
||||||
!key->userAccels().empty())
|
key->hasUserDefinedAccels())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2022 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -50,6 +51,7 @@ namespace app {
|
|||||||
KeyPtr wheelAction(WheelAction action);
|
KeyPtr wheelAction(WheelAction action);
|
||||||
|
|
||||||
void disableAccel(const ui::Accelerator& accel,
|
void disableAccel(const ui::Accelerator& accel,
|
||||||
|
const KeySource source,
|
||||||
const KeyContext keyContext,
|
const KeyContext keyContext,
|
||||||
const Key* newKey);
|
const Key* newKey);
|
||||||
|
|
||||||
|
@ -24,9 +24,11 @@ MainMenuBar::MainMenuBar()
|
|||||||
{
|
{
|
||||||
Extensions& extensions = App::instance()->extensions();
|
Extensions& extensions = App::instance()->extensions();
|
||||||
|
|
||||||
m_extScripts =
|
// Reload the main menu if there are changes in keyboard shortcuts
|
||||||
extensions.ScriptsChange.connect(
|
// or scripts when extensions are installed/uninstalled or
|
||||||
[this]{ reload(); });
|
// enabled/disabled.
|
||||||
|
m_extKeys = extensions.KeysChange.connect( [this]{ reload(); });
|
||||||
|
m_extScripts = extensions.ScriptsChange.connect( [this]{ reload(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenuBar::reload()
|
void MainMenuBar::reload()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A
|
// Copyright (C) 2020-2022 Igara Studio S.A
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2015 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -21,6 +21,7 @@ namespace app {
|
|||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
obs::scoped_connection m_extKeys;
|
||||||
obs::scoped_connection m_extScripts;
|
obs::scoped_connection m_extScripts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user