mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +02:00
Apply shortcuts changes to actions.
This commit is contained in:
parent
a93e01b896
commit
86096db02d
3 changed files with 143 additions and 53 deletions
|
@ -179,19 +179,30 @@ public:
|
|||
[[nodiscard]] base::flat_map<QKeySequence, Command> keysDefaults() const;
|
||||
[[nodiscard]] base::flat_map<QKeySequence, Command> keysCurrents() const;
|
||||
|
||||
void change(
|
||||
QKeySequence was,
|
||||
QKeySequence now,
|
||||
Command command,
|
||||
std::optional<Command> restore);
|
||||
|
||||
private:
|
||||
void fillDefaults();
|
||||
void writeDefaultFile();
|
||||
bool readCustomFile();
|
||||
|
||||
void set(const QString &keys, Command command, bool replace = false);
|
||||
void set(const QKeySequence &result, Command command, bool replace);
|
||||
void remove(const QString &keys);
|
||||
void remove(const QKeySequence &keys);
|
||||
void unregister(base::unique_qptr<QAction> shortcut);
|
||||
|
||||
void pruneListened();
|
||||
|
||||
QStringList _errors;
|
||||
|
||||
base::flat_map<QKeySequence, base::unique_qptr<QAction>> _shortcuts;
|
||||
base::flat_multi_map<not_null<QObject*>, Command> _commandByObject;
|
||||
std::vector<QPointer<QWidget>> _listened;
|
||||
|
||||
base::flat_map<QKeySequence, Command> _defaults;
|
||||
|
||||
|
@ -299,6 +310,23 @@ base::flat_map<QKeySequence, Command> Manager::keysCurrents() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Manager::change(
|
||||
QKeySequence was,
|
||||
QKeySequence now,
|
||||
Command command,
|
||||
std::optional<Command> restore) {
|
||||
if (!was.isEmpty()) {
|
||||
remove(was);
|
||||
}
|
||||
if (!now.isEmpty()) {
|
||||
set(now, command, true);
|
||||
}
|
||||
if (restore) {
|
||||
Assert(!was.isEmpty());
|
||||
set(was, *restore, true);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Command> Manager::lookup(not_null<QObject*> object) const {
|
||||
auto result = std::vector<Command>();
|
||||
auto i = _commandByObject.findFirst(object);
|
||||
|
@ -322,11 +350,23 @@ void Manager::toggleSupport(bool toggled) {
|
|||
}
|
||||
|
||||
void Manager::listen(not_null<QWidget*> widget) {
|
||||
pruneListened();
|
||||
_listened.push_back(widget.get());
|
||||
for (const auto &[keys, shortcut] : _shortcuts) {
|
||||
widget->addAction(shortcut.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::pruneListened() {
|
||||
for (auto i = begin(_listened); i != end(_listened);) {
|
||||
if (i->data()) {
|
||||
++i;
|
||||
} else {
|
||||
i = _listened.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Manager::readCustomFile() {
|
||||
// read custom shortcuts from file if it exists or write an empty custom shortcuts file
|
||||
QFile file(CustomFilePath());
|
||||
|
@ -527,8 +567,15 @@ void Manager::set(const QString &keys, Command command, bool replace) {
|
|||
_errors.push_back(u"Could not derive key sequence '%1'!"_q.arg(keys));
|
||||
return;
|
||||
}
|
||||
set(result, command, replace);
|
||||
}
|
||||
|
||||
void Manager::set(
|
||||
const QKeySequence &keys,
|
||||
Command command,
|
||||
bool replace) {
|
||||
auto shortcut = base::make_unique_q<QAction>();
|
||||
shortcut->setShortcut(result);
|
||||
shortcut->setShortcut(keys);
|
||||
shortcut->setShortcutContext(Qt::ApplicationShortcut);
|
||||
if (!AutoRepeatCommands.contains(command)) {
|
||||
shortcut->setAutoRepeat(false);
|
||||
|
@ -539,20 +586,26 @@ void Manager::set(const QString &keys, Command command, bool replace) {
|
|||
shortcut->setEnabled(false);
|
||||
}
|
||||
auto object = shortcut.get();
|
||||
auto i = _shortcuts.find(result);
|
||||
auto i = _shortcuts.find(keys);
|
||||
if (i == end(_shortcuts)) {
|
||||
i = _shortcuts.emplace(result, std::move(shortcut)).first;
|
||||
i = _shortcuts.emplace(keys, std::move(shortcut)).first;
|
||||
} else if (replace) {
|
||||
unregister(std::exchange(i->second, std::move(shortcut)));
|
||||
} else {
|
||||
object = i->second.get();
|
||||
}
|
||||
_commandByObject.emplace(object, command);
|
||||
if (!shortcut && isMediaShortcut) {
|
||||
_mediaShortcuts.emplace(i->second.get());
|
||||
}
|
||||
if (!shortcut && isSupportShortcut) {
|
||||
_supportShortcuts.emplace(i->second.get());
|
||||
if (!shortcut) { // Added the new one.
|
||||
if (isMediaShortcut) {
|
||||
_mediaShortcuts.emplace(i->second.get());
|
||||
}
|
||||
if (isSupportShortcut) {
|
||||
_supportShortcuts.emplace(i->second.get());
|
||||
}
|
||||
pruneListened();
|
||||
for (const auto &widget : _listened) {
|
||||
widget->addAction(i->second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -566,7 +619,11 @@ void Manager::remove(const QString &keys) {
|
|||
_errors.push_back(u"Could not derive key sequence '%1'!"_q.arg(keys));
|
||||
return;
|
||||
}
|
||||
const auto i = _shortcuts.find(result);
|
||||
remove(result);
|
||||
}
|
||||
|
||||
void Manager::remove(const QKeySequence &keys) {
|
||||
const auto i = _shortcuts.find(keys);
|
||||
if (i != end(_shortcuts)) {
|
||||
unregister(std::move(i->second));
|
||||
_shortcuts.erase(i);
|
||||
|
@ -671,6 +728,14 @@ base::flat_map<QKeySequence, Command> KeysCurrents() {
|
|||
return Data.keysCurrents();
|
||||
}
|
||||
|
||||
void Change(
|
||||
QKeySequence was,
|
||||
QKeySequence now,
|
||||
Command command,
|
||||
std::optional<Command> restore) {
|
||||
Data.change(was, now, command, restore);
|
||||
}
|
||||
|
||||
bool AllowWithoutModifiers(int key) {
|
||||
const auto service = {
|
||||
Qt::Key_Escape,
|
||||
|
|
|
@ -144,6 +144,13 @@ void Unpause();
|
|||
|
||||
[[nodiscard]] base::flat_map<QKeySequence, Command> KeysDefaults();
|
||||
[[nodiscard]] base::flat_map<QKeySequence, Command> KeysCurrents();
|
||||
|
||||
void Change(
|
||||
QKeySequence was,
|
||||
QKeySequence now,
|
||||
Command command,
|
||||
std::optional<Command> restore = {});
|
||||
|
||||
[[nodiscard]] bool AllowWithoutModifiers(int key);
|
||||
|
||||
} // namespace Shortcuts
|
||||
|
|
|
@ -227,10 +227,10 @@ struct Labeled {
|
|||
TextWithEntities{ key.toString() },
|
||||
EntityType::StrikeOut)
|
||||
: TextWithEntities{ key.toString() });
|
||||
keys->setTextColorOverride(removed
|
||||
? st::attentionButtonFg->c
|
||||
: (recording == raw)
|
||||
keys->setTextColorOverride((recording == raw)
|
||||
? st::boxTextFgGood->c
|
||||
: removed
|
||||
? st::attentionButtonFg->c
|
||||
: std::optional<QColor>());
|
||||
keys->resizeToNaturalWidth(available);
|
||||
keys->moveToRight(
|
||||
|
@ -259,56 +259,71 @@ struct Labeled {
|
|||
return;
|
||||
}
|
||||
state->recording = nullptr;
|
||||
if (result) {
|
||||
auto was = button->key.current();
|
||||
const auto now = *result;
|
||||
for (auto &entry : state->entries) {
|
||||
const auto i = ranges::find(
|
||||
entry.buttons,
|
||||
button,
|
||||
&std::unique_ptr<Button>::get);
|
||||
if (i != end(entry.buttons)) {
|
||||
const auto index = i - begin(entry.buttons);
|
||||
if (now.isEmpty()) {
|
||||
entry.now.erase(begin(entry.now) + index);
|
||||
} else {
|
||||
const auto i = ranges::find(entry.now, now);
|
||||
if (i == end(entry.now)) {
|
||||
entry.now[index] = now;
|
||||
} else if (i != begin(entry.now) + index) {
|
||||
std::swap(entry.now[index], *i);
|
||||
entry.now.erase(i);
|
||||
}
|
||||
}
|
||||
fill(entry);
|
||||
checkModified();
|
||||
} else if (now != was) {
|
||||
const auto i = now.isEmpty()
|
||||
? end(entry.now)
|
||||
: ranges::find(entry.now, now);
|
||||
if (i != end(entry.now)) {
|
||||
entry.buttons[i - begin(entry.now)]->removed = true;
|
||||
}
|
||||
const auto j = was.isEmpty()
|
||||
? end(entry.now)
|
||||
: ranges::find(entry.now, was);
|
||||
if (j != end(entry.now)) {
|
||||
entry.buttons[j - begin(entry.now)]->removed = false;
|
||||
was = QKeySequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
InvokeQueued(content, [=] {
|
||||
InvokeQueued(content, [=] {
|
||||
// Let all the shortcut events propagate first.
|
||||
S::Unpause();
|
||||
});
|
||||
});
|
||||
auto was = button->key.current();
|
||||
const auto now = result.value_or(was);
|
||||
if (now == was) {
|
||||
if (!result || !button->removed.current()) {
|
||||
return;
|
||||
}
|
||||
was = QKeySequence();
|
||||
}
|
||||
|
||||
auto changed = false;
|
||||
const auto command = button->command;
|
||||
for (auto &entry : state->entries) {
|
||||
const auto i = ranges::find(
|
||||
entry.buttons,
|
||||
button,
|
||||
&std::unique_ptr<Button>::get);
|
||||
if (i != end(entry.buttons)) {
|
||||
const auto index = i - begin(entry.buttons);
|
||||
if (now.isEmpty()) {
|
||||
entry.now.erase(begin(entry.now) + index);
|
||||
} else {
|
||||
const auto i = ranges::find(entry.now, now);
|
||||
if (i == end(entry.now)) {
|
||||
entry.now[index] = now;
|
||||
} else if (i != begin(entry.now) + index) {
|
||||
std::swap(entry.now[index], *i);
|
||||
entry.now.erase(i);
|
||||
}
|
||||
}
|
||||
fill(entry);
|
||||
checkModified();
|
||||
} else if (now != was) {
|
||||
const auto i = now.isEmpty()
|
||||
? end(entry.now)
|
||||
: ranges::find(entry.now, now);
|
||||
if (i != end(entry.now)) {
|
||||
entry.buttons[i - begin(entry.now)]->removed = true;
|
||||
}
|
||||
const auto j = was.isEmpty()
|
||||
? end(entry.now)
|
||||
: ranges::find(entry.now, was);
|
||||
if (j != end(entry.now)) {
|
||||
entry.buttons[j - begin(entry.now)]->removed = false;
|
||||
S::Change(was, now, command, entry.command);
|
||||
was = QKeySequence();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
S::Change(was, now, command);
|
||||
}
|
||||
};
|
||||
base::install_event_filter(content, qApp, [=](not_null<QEvent*> e) {
|
||||
const auto type = e->type();
|
||||
if (type == QEvent::ShortcutOverride && state->recording.current()) {
|
||||
if (!content->window()->isActiveWindow()) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
const auto key = static_cast<QKeyEvent*>(e.get());
|
||||
const auto m = key->modifiers();
|
||||
const auto k = key->key();
|
||||
|
@ -325,7 +340,10 @@ struct Labeled {
|
|||
}
|
||||
stopRecording(clear ? QKeySequence() : QKeySequence(k | m));
|
||||
return base::EventFilterResult::Cancel;
|
||||
} else if (type == QEvent::KeyPress) {
|
||||
} else if (type == QEvent::KeyPress && state->recording.current()) {
|
||||
if (!content->window()->isActiveWindow()) {
|
||||
return base::EventFilterResult::Continue;
|
||||
}
|
||||
if (static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape) {
|
||||
stopRecording();
|
||||
return base::EventFilterResult::Cancel;
|
||||
|
|
Loading…
Add table
Reference in a new issue