mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Improve editing of hotkeys (#4628)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
fb02d59b48
commit
c7b22939d5
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
- Minor: Add an icon showing when streamer mode is enabled (#4410)
|
- Minor: Add an icon showing when streamer mode is enabled (#4410)
|
||||||
- Minor: Added `/shoutout <username>` commands to shoutout specified user. (#4638)
|
- Minor: Added `/shoutout <username>` commands to shoutout specified user. (#4638)
|
||||||
|
- Minor: Improved editing hotkeys. (#4628)
|
||||||
- Dev: Added command to set Qt's logging filter/rules at runtime (`/c2-set-logging-rules`). (#4637)
|
- Dev: Added command to set Qt's logging filter/rules at runtime (`/c2-set-logging-rules`). (#4637)
|
||||||
- Dev: Added the ability to see & load custom themes from the Themes directory. No stable promises are made of this feature, changes might be made that breaks custom themes without notice. (#4570)
|
- Dev: Added the ability to see & load custom themes from the Themes directory. No stable promises are made of this feature, changes might be made that breaks custom themes without notice. (#4570)
|
||||||
- Dev: Added test cases for emote and tab completion. (#4644)
|
- Dev: Added test cases for emote and tab completion. (#4644)
|
||||||
|
|
|
@ -5,6 +5,20 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
inline const std::vector<std::pair<QString, std::vector<QString>>>
|
||||||
|
HOTKEY_ARG_ON_OFF_TOGGLE = {
|
||||||
|
{"Toggle", {}},
|
||||||
|
{"Set to on", {"on"}},
|
||||||
|
{"Set to off", {"off"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const std::vector<std::pair<QString, std::vector<QString>>>
|
||||||
|
HOTKEY_ARG_WITH_OR_WITHOUT_SELECTION = {
|
||||||
|
{"No", {"withoutSelection"}},
|
||||||
|
{"Yes", {"withSelection"}},
|
||||||
|
};
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
@ -13,6 +27,9 @@ struct ActionDefinition {
|
||||||
// displayName is the value that would be shown to a user when they edit or create a hotkey for an action
|
// displayName is the value that would be shown to a user when they edit or create a hotkey for an action
|
||||||
QString displayName;
|
QString displayName;
|
||||||
|
|
||||||
|
// argumentDescription is a description of the arguments in a format of
|
||||||
|
// "<required arg: description of possible values> [optional arg: possible
|
||||||
|
// values]"
|
||||||
QString argumentDescription = "";
|
QString argumentDescription = "";
|
||||||
|
|
||||||
// minCountArguments is the minimum amount of arguments the action accepts
|
// minCountArguments is the minimum amount of arguments the action accepts
|
||||||
|
@ -21,6 +38,20 @@ struct ActionDefinition {
|
||||||
|
|
||||||
// maxCountArguments is the maximum amount of arguments the action accepts
|
// maxCountArguments is the maximum amount of arguments the action accepts
|
||||||
uint8_t maxCountArguments = minCountArguments;
|
uint8_t maxCountArguments = minCountArguments;
|
||||||
|
|
||||||
|
// possibleArguments is empty or contains all possible argument values,
|
||||||
|
// it is an ordered mapping from option name (what the user sees) to
|
||||||
|
// arguments (what the action code will see).
|
||||||
|
// As std::map<K, V> does not guarantee order this is a std::vector<...>
|
||||||
|
std::vector<std::pair<QString, std::vector<QString>>> possibleArguments =
|
||||||
|
{};
|
||||||
|
|
||||||
|
// When possibleArguments are present this should be a string like
|
||||||
|
// "Direction:" which will be shown before the values from
|
||||||
|
// possibleArguments in the UI. Otherwise, it should be empty.
|
||||||
|
QString argumentsPrompt = "";
|
||||||
|
// A more detailed description of what argumentsPrompt means
|
||||||
|
QString argumentsPromptHover = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
using ActionDefinitionMap = std::map<QString, ActionDefinition>;
|
using ActionDefinitionMap = std::map<QString, ActionDefinition>;
|
||||||
|
@ -39,9 +70,15 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
}},
|
}},
|
||||||
{"scrollPage",
|
{"scrollPage",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Scroll",
|
.displayName = "Scroll",
|
||||||
"<up or down>",
|
.argumentDescription = "<direction: up or down>",
|
||||||
1,
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"Up", {"up"}},
|
||||||
|
{"Down", {"down"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Direction:",
|
||||||
}},
|
}},
|
||||||
{"search", ActionDefinition{"Focus search box"}},
|
{"search", ActionDefinition{"Focus search box"}},
|
||||||
{"execModeratorAction",
|
{"execModeratorAction",
|
||||||
|
@ -57,9 +94,19 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
{"delete", ActionDefinition{"Close"}},
|
{"delete", ActionDefinition{"Close"}},
|
||||||
{"focus",
|
{"focus",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Focus neighbouring split",
|
.displayName = "Focus neighbouring split",
|
||||||
"<up, down, left, or right>",
|
.argumentDescription = "<direction: up, down, left or right>",
|
||||||
1,
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"Up", {"up"}},
|
||||||
|
{"Down", {"down"}},
|
||||||
|
{"Left", {"left"}},
|
||||||
|
{"Right", {"right"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Direction:",
|
||||||
|
.argumentsPromptHover =
|
||||||
|
"Which direction to look for a split to focus?",
|
||||||
}},
|
}},
|
||||||
{"openInBrowser", ActionDefinition{"Open channel in browser"}},
|
{"openInBrowser", ActionDefinition{"Open channel in browser"}},
|
||||||
{"openInCustomPlayer",
|
{"openInCustomPlayer",
|
||||||
|
@ -71,10 +118,18 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
{"reconnect", ActionDefinition{"Reconnect to chat"}},
|
{"reconnect", ActionDefinition{"Reconnect to chat"}},
|
||||||
{"reloadEmotes",
|
{"reloadEmotes",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Reload emotes",
|
.displayName = "Reload emotes",
|
||||||
"[channel or subscriber]",
|
.argumentDescription =
|
||||||
0,
|
"[type: channel or subscriber; default: all emotes]",
|
||||||
1,
|
.minCountArguments = 0,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"All emotes", {}},
|
||||||
|
{"Channel emotes only", {"channel"}},
|
||||||
|
{"Subscriber emotes only", {"subscriber"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Emote type:",
|
||||||
|
.argumentsPromptHover = "Which emotes should Chatterino reload",
|
||||||
}},
|
}},
|
||||||
{"runCommand",
|
{"runCommand",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
|
@ -84,25 +139,41 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
}},
|
}},
|
||||||
{"scrollPage",
|
{"scrollPage",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Scroll",
|
.displayName = "Scroll",
|
||||||
"<up or down>",
|
.argumentDescription = "<up or down>",
|
||||||
1,
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"Up", {"up"}},
|
||||||
|
{"Down", {"down"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Direction:",
|
||||||
|
.argumentsPromptHover =
|
||||||
|
"Which direction do you want to see more messages",
|
||||||
}},
|
}},
|
||||||
{"scrollToBottom", ActionDefinition{"Scroll to the bottom"}},
|
{"scrollToBottom", ActionDefinition{"Scroll to the bottom"}},
|
||||||
{"scrollToTop", ActionDefinition{"Scroll to the top"}},
|
{"scrollToTop", ActionDefinition{"Scroll to the top"}},
|
||||||
{"setChannelNotification",
|
{"setChannelNotification",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Set channel live notification",
|
.displayName = "Set channel live notification",
|
||||||
"[on or off. default: toggle]",
|
.argumentDescription = "[on or off. default: toggle]",
|
||||||
0,
|
.minCountArguments = 0,
|
||||||
1,
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments = HOTKEY_ARG_ON_OFF_TOGGLE,
|
||||||
|
.argumentsPrompt = "New value:",
|
||||||
|
.argumentsPromptHover = "Should the channel live notification be "
|
||||||
|
"enabled, disabled or toggled",
|
||||||
}},
|
}},
|
||||||
{"setModerationMode",
|
{"setModerationMode",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Set moderation mode",
|
.displayName = "Set moderation mode",
|
||||||
"[on or off. default: toggle]",
|
.argumentDescription = "[on or off. default: toggle]",
|
||||||
0,
|
.minCountArguments = 0,
|
||||||
1,
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments = HOTKEY_ARG_ON_OFF_TOGGLE,
|
||||||
|
.argumentsPrompt = "New value:",
|
||||||
|
.argumentsPromptHover =
|
||||||
|
"Should the moderation mode be enabled, disabled or toggled",
|
||||||
}},
|
}},
|
||||||
{"showSearch", ActionDefinition{"Search current channel"}},
|
{"showSearch", ActionDefinition{"Search current channel"}},
|
||||||
{"showGlobalSearch", ActionDefinition{"Search all channels"}},
|
{"showGlobalSearch", ActionDefinition{"Search all channels"}},
|
||||||
|
@ -114,21 +185,38 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
{"clear", ActionDefinition{"Clear message"}},
|
{"clear", ActionDefinition{"Clear message"}},
|
||||||
{"copy",
|
{"copy",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Copy",
|
.displayName = "Copy",
|
||||||
"<source of text: split, splitInput or auto>",
|
.argumentDescription =
|
||||||
1,
|
"<source of text: auto, split or splitInput>",
|
||||||
|
.minCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"Automatic", {"auto"}},
|
||||||
|
{"Split", {"split"}},
|
||||||
|
{"Split Input", {"splitInput"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Source of text:",
|
||||||
}},
|
}},
|
||||||
{"cursorToStart",
|
{"cursorToStart",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"To start of message",
|
.displayName = "To start of message",
|
||||||
"<withSelection or withoutSelection>",
|
.argumentDescription =
|
||||||
1,
|
"<selection mode: withSelection or withoutSelection>",
|
||||||
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments = HOTKEY_ARG_WITH_OR_WITHOUT_SELECTION,
|
||||||
|
.argumentsPrompt = "Select text from cursor to start:",
|
||||||
|
// XXX: write a hover for this that doesn't suck
|
||||||
}},
|
}},
|
||||||
{"cursorToEnd",
|
{"cursorToEnd",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"To end of message",
|
.displayName = "To end of message",
|
||||||
"<withSelection or withoutSelection>",
|
.argumentDescription =
|
||||||
1,
|
"<selection mode: withSelection or withoutSelection>",
|
||||||
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments = HOTKEY_ARG_WITH_OR_WITHOUT_SELECTION,
|
||||||
|
.argumentsPrompt = "Select text from cursor to end:",
|
||||||
|
// XXX: write a hover for this that doesn't suck
|
||||||
}},
|
}},
|
||||||
{"nextMessage", ActionDefinition{"Choose next sent message"}},
|
{"nextMessage", ActionDefinition{"Choose next sent message"}},
|
||||||
{"openEmotesPopup", ActionDefinition{"Open emotes list"}},
|
{"openEmotesPopup", ActionDefinition{"Open emotes list"}},
|
||||||
|
@ -140,10 +228,16 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
{"selectWord", ActionDefinition{"Select word"}},
|
{"selectWord", ActionDefinition{"Select word"}},
|
||||||
{"sendMessage",
|
{"sendMessage",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Send message",
|
.displayName = "Send message",
|
||||||
"[keepInput to not clear the text after sending]",
|
.argumentDescription =
|
||||||
0,
|
"[keepInput to not clear the text after sending]",
|
||||||
1,
|
.minCountArguments = 0,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"Default behavior", {}},
|
||||||
|
{"Keep message in input after sending it", {"keepInput"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Behavior:",
|
||||||
}},
|
}},
|
||||||
{"undo", ActionDefinition{"Undo"}},
|
{"undo", ActionDefinition{"Undo"}},
|
||||||
|
|
||||||
|
@ -163,7 +257,7 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
{"moveTab",
|
{"moveTab",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Move tab",
|
"Move tab",
|
||||||
"<next, previous, or new index of tab>",
|
"<where to move the tab: next, previous, or new index of tab>",
|
||||||
1,
|
1,
|
||||||
}},
|
}},
|
||||||
{"newSplit", ActionDefinition{"Create a new split"}},
|
{"newSplit", ActionDefinition{"Create a new split"}},
|
||||||
|
@ -172,40 +266,73 @@ inline const std::map<HotkeyCategory, ActionDefinitionMap> actionNames{
|
||||||
{"openTab",
|
{"openTab",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Select tab",
|
"Select tab",
|
||||||
"<last, next, previous, or index of tab to select>",
|
"<which tab to select: last, next, previous, or index>",
|
||||||
1,
|
1,
|
||||||
}},
|
}},
|
||||||
{"openQuickSwitcher", ActionDefinition{"Open the quick switcher"}},
|
{"openQuickSwitcher", ActionDefinition{"Open the quick switcher"}},
|
||||||
{"popup",
|
{"popup",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"New popup",
|
.displayName = "New popup",
|
||||||
"<split or window>",
|
.argumentDescription = "<split or window>",
|
||||||
1,
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments{
|
||||||
|
{"Focused Split", {"split"}},
|
||||||
|
{"Entire Tab", {"window"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Include:",
|
||||||
|
.argumentsPromptHover =
|
||||||
|
"What should be included in the new popup",
|
||||||
}},
|
}},
|
||||||
{"quit", ActionDefinition{"Quit Chatterino"}},
|
{"quit", ActionDefinition{"Quit Chatterino"}},
|
||||||
{"removeTab", ActionDefinition{"Remove current tab"}},
|
{"removeTab", ActionDefinition{"Remove current tab"}},
|
||||||
{"reopenSplit", ActionDefinition{"Reopen closed split"}},
|
{"reopenSplit", ActionDefinition{"Reopen closed split"}},
|
||||||
{"setStreamerMode",
|
{"setStreamerMode",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Set streamer mode",
|
.displayName = "Set streamer mode",
|
||||||
"[on, off, toggle, or auto. default: toggle]",
|
.argumentDescription =
|
||||||
0,
|
"[on, off, toggle, or auto. default: toggle]",
|
||||||
1,
|
.minCountArguments = 0,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments =
|
||||||
|
{
|
||||||
|
{"Toggle on/off", {}},
|
||||||
|
{"Set to on", {"on"}},
|
||||||
|
{"Set to off", {"off"}},
|
||||||
|
{"Set to automatic", {"auto"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "New value:",
|
||||||
|
.argumentsPromptHover =
|
||||||
|
"Should streamer mode be enabled, disabled, toggled (on/off) "
|
||||||
|
"or set to auto",
|
||||||
}},
|
}},
|
||||||
{"toggleLocalR9K", ActionDefinition{"Toggle local R9K"}},
|
{"toggleLocalR9K", ActionDefinition{"Toggle local R9K"}},
|
||||||
{"zoom",
|
{"zoom",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Zoom in/out",
|
.displayName = "Zoom in/out",
|
||||||
"<in, out, or reset>",
|
.argumentDescription = "Argument:",
|
||||||
1,
|
.minCountArguments = 1,
|
||||||
|
.maxCountArguments = 1,
|
||||||
|
.possibleArguments =
|
||||||
|
{
|
||||||
|
{"Zoom in", {"in"}},
|
||||||
|
{"Zoom out", {"out"}},
|
||||||
|
{"Reset zoom", {"reset"}},
|
||||||
|
},
|
||||||
|
.argumentsPrompt = "Option:",
|
||||||
}},
|
}},
|
||||||
{"setTabVisibility",
|
{"setTabVisibility",
|
||||||
ActionDefinition{
|
ActionDefinition{
|
||||||
"Set tab visibility",
|
.displayName = "Set tab visibility",
|
||||||
"[on, off, or toggle. default: toggle]",
|
.argumentDescription = "[on, off, or toggle. default: toggle]",
|
||||||
0,
|
.minCountArguments = 0,
|
||||||
1,
|
.maxCountArguments = 1,
|
||||||
}}}},
|
.possibleArguments = HOTKEY_ARG_ON_OFF_TOGGLE,
|
||||||
|
.argumentsPrompt = "New value:",
|
||||||
|
.argumentsPromptHover =
|
||||||
|
"Should the tabs be enabled, disabled or toggled.",
|
||||||
|
}},
|
||||||
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "controllers/hotkeys/HotkeyHelpers.hpp"
|
#include "controllers/hotkeys/HotkeyHelpers.hpp"
|
||||||
|
|
||||||
|
#include "controllers/hotkeys/ActionNames.hpp"
|
||||||
|
#include "controllers/hotkeys/HotkeyCategory.hpp"
|
||||||
|
|
||||||
|
#include <boost/optional/optional.hpp>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
@ -27,4 +31,20 @@ std::vector<QString> parseHotkeyArguments(QString argumentString)
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::optional<ActionDefinition> findHotkeyActionDefinition(
|
||||||
|
HotkeyCategory category, const QString &action)
|
||||||
|
{
|
||||||
|
auto allActions = actionNames.find(category);
|
||||||
|
if (allActions != actionNames.end())
|
||||||
|
{
|
||||||
|
const auto &actionsMap = allActions->second;
|
||||||
|
auto definition = actionsMap.find(action);
|
||||||
|
if (definition != actionsMap.end())
|
||||||
|
{
|
||||||
|
return {definition->second};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "controllers/hotkeys/ActionNames.hpp"
|
||||||
|
|
||||||
|
#include <boost/optional/optional.hpp>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -7,5 +10,7 @@
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
std::vector<QString> parseHotkeyArguments(QString argumentString);
|
std::vector<QString> parseHotkeyArguments(QString argumentString);
|
||||||
|
boost::optional<ActionDefinition> findHotkeyActionDefinition(
|
||||||
|
HotkeyCategory category, const QString &action);
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -17,6 +17,14 @@ EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr<Hotkey> hotkey,
|
||||||
, data_(hotkey)
|
, data_(hotkey)
|
||||||
{
|
{
|
||||||
this->ui_->setupUi(this);
|
this->ui_->setupUi(this);
|
||||||
|
this->setStyleSheet(R"(QToolTip {
|
||||||
|
padding: 2px;
|
||||||
|
background-color: #333333;
|
||||||
|
border: 1px solid #545454;
|
||||||
|
color: white;
|
||||||
|
})");
|
||||||
|
this->ui_->easyArgsPicker->setVisible(false);
|
||||||
|
this->ui_->easyArgsLabel->setVisible(false);
|
||||||
// dynamically add category names to the category picker
|
// dynamically add category names to the category picker
|
||||||
for (const auto &[_, hotkeyCategory] : getApp()->hotkeys->categories())
|
for (const auto &[_, hotkeyCategory] : getApp()->hotkeys->categories())
|
||||||
{
|
{
|
||||||
|
@ -28,34 +36,7 @@ EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr<Hotkey> hotkey,
|
||||||
|
|
||||||
if (hotkey)
|
if (hotkey)
|
||||||
{
|
{
|
||||||
if (!hotkey->validAction())
|
this->setFromHotkey(hotkey);
|
||||||
{
|
|
||||||
this->showEditError("Invalid action, make sure you select the "
|
|
||||||
"correct action before saving.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// editing a hotkey
|
|
||||||
|
|
||||||
// update pickers/input boxes to values from Hotkey object
|
|
||||||
this->ui_->categoryPicker->setCurrentIndex(size_t(hotkey->category()));
|
|
||||||
this->ui_->keyComboEdit->setKeySequence(
|
|
||||||
QKeySequence::fromString(hotkey->keySequence().toString()));
|
|
||||||
this->ui_->nameEdit->setText(hotkey->name());
|
|
||||||
// update arguments
|
|
||||||
QString argsText;
|
|
||||||
bool first = true;
|
|
||||||
for (const auto &arg : hotkey->arguments())
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
{
|
|
||||||
argsText += '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
argsText += arg;
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
this->ui_->argumentsEdit->setPlainText(argsText);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -66,6 +47,96 @@ EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr<Hotkey> hotkey,
|
||||||
this->ui_->argumentsEdit->setPlainText("");
|
this->ui_->argumentsEdit->setPlainText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void EditHotkeyDialog::setFromHotkey(std::shared_ptr<Hotkey> hotkey)
|
||||||
|
{
|
||||||
|
if (!hotkey->validAction())
|
||||||
|
{
|
||||||
|
this->showEditError("Invalid action, make sure you select the "
|
||||||
|
"correct action before saving.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// editing a hotkey
|
||||||
|
|
||||||
|
// update pickers/input boxes to values from Hotkey object
|
||||||
|
this->ui_->categoryPicker->setCurrentIndex(size_t(hotkey->category()));
|
||||||
|
this->ui_->keyComboEdit->setKeySequence(
|
||||||
|
QKeySequence::fromString(hotkey->keySequence().toString()));
|
||||||
|
this->ui_->nameEdit->setText(hotkey->name());
|
||||||
|
|
||||||
|
auto def = findHotkeyActionDefinition(hotkey->category(), hotkey->action());
|
||||||
|
if (def.has_value() && !def->possibleArguments.empty())
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoHotkeys) << "Enabled easy picker and arg edit "
|
||||||
|
"because we have arguments from hotkey";
|
||||||
|
this->ui_->easyArgsLabel->setVisible(true);
|
||||||
|
this->ui_->easyArgsPicker->setVisible(true);
|
||||||
|
|
||||||
|
this->ui_->argumentsEdit->setVisible(false);
|
||||||
|
this->ui_->argumentsLabel->setVisible(false);
|
||||||
|
this->ui_->argumentsDescription->setVisible(false);
|
||||||
|
|
||||||
|
this->ui_->easyArgsPicker->clear();
|
||||||
|
this->ui_->easyArgsLabel->setText(def->argumentsPrompt);
|
||||||
|
this->ui_->easyArgsLabel->setToolTip(def->argumentsPromptHover);
|
||||||
|
int matchIdx = -1;
|
||||||
|
for (int i = 0; i < def->possibleArguments.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &[displayText, argData] = def->possibleArguments.at(i);
|
||||||
|
this->ui_->easyArgsPicker->addItem(displayText);
|
||||||
|
|
||||||
|
// check if matches
|
||||||
|
if (argData.size() != hotkey->arguments().size())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool matches = true;
|
||||||
|
for (int j = 0; j < argData.size(); j++)
|
||||||
|
{
|
||||||
|
if (argData.at(j) != hotkey->arguments().at(j))
|
||||||
|
{
|
||||||
|
matches = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches)
|
||||||
|
{
|
||||||
|
matchIdx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matchIdx != -1)
|
||||||
|
{
|
||||||
|
this->ui_->easyArgsPicker->setCurrentIndex(matchIdx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(chatterinoHotkeys)
|
||||||
|
<< "Did not match hotkey arguments for " << hotkey->toString()
|
||||||
|
<< "using text edit instead of easy picker";
|
||||||
|
this->showEditError("Arguments do not match what's expected. The "
|
||||||
|
"argument picker is not available.");
|
||||||
|
this->ui_->easyArgsLabel->setVisible(false);
|
||||||
|
this->ui_->easyArgsPicker->setVisible(false);
|
||||||
|
|
||||||
|
this->ui_->argumentsEdit->setVisible(true);
|
||||||
|
this->ui_->argumentsLabel->setVisible(true);
|
||||||
|
this->ui_->argumentsDescription->setVisible(true);
|
||||||
|
}
|
||||||
|
// update arguments
|
||||||
|
QString argsText;
|
||||||
|
bool first = true;
|
||||||
|
for (const auto &arg : hotkey->arguments())
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
argsText += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
argsText += arg;
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
this->ui_->argumentsEdit->setPlainText(argsText);
|
||||||
|
}
|
||||||
|
|
||||||
EditHotkeyDialog::~EditHotkeyDialog()
|
EditHotkeyDialog::~EditHotkeyDialog()
|
||||||
{
|
{
|
||||||
|
@ -151,6 +222,14 @@ void EditHotkeyDialog::afterEdit()
|
||||||
action = actionTemp.toString();
|
action = actionTemp.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto def = findHotkeyActionDefinition(*category, action);
|
||||||
|
if (def.has_value() && this->ui_->easyArgsPicker->isVisible())
|
||||||
|
{
|
||||||
|
arguments =
|
||||||
|
def->possibleArguments.at(this->ui_->easyArgsPicker->currentIndex())
|
||||||
|
.second;
|
||||||
|
}
|
||||||
|
|
||||||
auto hotkey = std::make_shared<Hotkey>(
|
auto hotkey = std::make_shared<Hotkey>(
|
||||||
*category, this->ui_->keyComboEdit->keySequence(), action, arguments,
|
*category, this->ui_->keyComboEdit->keySequence(), action, arguments,
|
||||||
nameText);
|
nameText);
|
||||||
|
@ -263,44 +342,69 @@ void EditHotkeyDialog::updateArgumentsInput()
|
||||||
}
|
}
|
||||||
const ActionDefinition &def = definition->second;
|
const ActionDefinition &def = definition->second;
|
||||||
|
|
||||||
if (def.maxCountArguments != 0)
|
if (def.maxCountArguments == 0)
|
||||||
{
|
|
||||||
QString text =
|
|
||||||
"Arguments wrapped in <> are required.\nArguments wrapped in "
|
|
||||||
"[] "
|
|
||||||
"are optional.\nArguments are separated by a newline.";
|
|
||||||
if (!def.argumentDescription.isEmpty())
|
|
||||||
{
|
|
||||||
this->ui_->argumentsDescription->setVisible(true);
|
|
||||||
this->ui_->argumentsDescription->setText(
|
|
||||||
def.argumentDescription);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->ui_->argumentsDescription->setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
text = QString("Arguments wrapped in <> are required.");
|
|
||||||
if (def.maxCountArguments != def.minCountArguments)
|
|
||||||
{
|
|
||||||
text += QString("\nArguments wrapped in [] are optional.");
|
|
||||||
}
|
|
||||||
|
|
||||||
text += "\nArguments are separated by a newline.";
|
|
||||||
|
|
||||||
this->ui_->argumentsEdit->setEnabled(true);
|
|
||||||
this->ui_->argumentsEdit->setPlaceholderText(text);
|
|
||||||
|
|
||||||
this->ui_->argumentsLabel->setVisible(true);
|
|
||||||
this->ui_->argumentsDescription->setVisible(true);
|
|
||||||
this->ui_->argumentsEdit->setVisible(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
qCDebug(chatterinoHotkeys) << "Disabled easy picker and arg edit "
|
||||||
|
"because we don't have any arguments";
|
||||||
this->ui_->argumentsLabel->setVisible(false);
|
this->ui_->argumentsLabel->setVisible(false);
|
||||||
this->ui_->argumentsDescription->setVisible(false);
|
this->ui_->argumentsDescription->setVisible(false);
|
||||||
this->ui_->argumentsEdit->setVisible(false);
|
this->ui_->argumentsEdit->setVisible(false);
|
||||||
|
|
||||||
|
this->ui_->easyArgsLabel->setVisible(false);
|
||||||
|
this->ui_->easyArgsPicker->setVisible(false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (!def.argumentDescription.isEmpty())
|
||||||
|
{
|
||||||
|
this->ui_->argumentsDescription->setVisible(true);
|
||||||
|
this->ui_->argumentsDescription->setText(def.argumentDescription);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->ui_->argumentsDescription->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString text = "Arguments wrapped in <> are required.";
|
||||||
|
if (def.maxCountArguments != def.minCountArguments)
|
||||||
|
{
|
||||||
|
text += QString("\nArguments wrapped in [] are optional.");
|
||||||
|
}
|
||||||
|
|
||||||
|
text += "\nArguments are separated by a newline.";
|
||||||
|
|
||||||
|
this->ui_->argumentsEdit->setEnabled(true);
|
||||||
|
this->ui_->argumentsEdit->setPlaceholderText(text);
|
||||||
|
|
||||||
|
this->ui_->argumentsLabel->setVisible(true);
|
||||||
|
this->ui_->argumentsDescription->setVisible(true);
|
||||||
|
this->ui_->argumentsEdit->setVisible(true);
|
||||||
|
|
||||||
|
// update easy picker
|
||||||
|
if (def.possibleArguments.empty())
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoHotkeys)
|
||||||
|
<< "Disabled easy picker because we have possible arguments";
|
||||||
|
this->ui_->easyArgsPicker->setVisible(false);
|
||||||
|
this->ui_->easyArgsLabel->setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qCDebug(chatterinoHotkeys)
|
||||||
|
<< "Enabled easy picker because we have possible arguments";
|
||||||
|
this->ui_->easyArgsPicker->setVisible(true);
|
||||||
|
this->ui_->easyArgsLabel->setVisible(true);
|
||||||
|
|
||||||
|
this->ui_->argumentsLabel->setVisible(false);
|
||||||
|
this->ui_->argumentsEdit->setVisible(false);
|
||||||
|
this->ui_->argumentsDescription->setVisible(false);
|
||||||
|
|
||||||
|
this->ui_->easyArgsPicker->clear();
|
||||||
|
for (const auto &[displayText, _] : def.possibleArguments)
|
||||||
|
{
|
||||||
|
this->ui_->easyArgsPicker->addItem(displayText);
|
||||||
|
}
|
||||||
|
this->ui_->easyArgsPicker->setCurrentIndex(0);
|
||||||
|
this->ui_->easyArgsLabel->setText(def.argumentsPrompt);
|
||||||
|
this->ui_->easyArgsLabel->setToolTip(def.argumentsPromptHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ protected slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void showEditError(QString errorText);
|
void showEditError(QString errorText);
|
||||||
|
void setFromHotkey(std::shared_ptr<Hotkey> hotkey);
|
||||||
|
|
||||||
Ui::EditHotkeyDialog *ui_;
|
Ui::EditHotkeyDialog *ui_;
|
||||||
std::shared_ptr<Hotkey> data_;
|
std::shared_ptr<Hotkey> data_;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>300</height>
|
<height>400</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -42,6 +42,9 @@ see this message :)</string>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="nameLabel">
|
<widget class="QLabel" name="nameLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Set a name for the hotkey so you will be able to identify it later</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Name:</string>
|
<string>Name:</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -76,6 +79,9 @@ see this message :)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="categoryPicker"/>
|
||||||
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="actionLabel">
|
<widget class="QLabel" name="actionLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -95,6 +101,9 @@ see this message :)</string>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="keyComboLabel">
|
<widget class="QLabel" name="keyComboLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Pressing this keybinding will invoke the hotkey</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Keybinding:</string>
|
<string>Keybinding:</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -107,6 +116,16 @@ see this message :)</string>
|
||||||
<widget class="QKeySequenceEdit" name="keyComboEdit"/>
|
<widget class="QKeySequenceEdit" name="keyComboEdit"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="easyArgsLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>You are not supposed to see this, please report this!</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Argument:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="argumentsLabel">
|
<widget class="QLabel" name="argumentsLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Arguments:</string>
|
<string>Arguments:</string>
|
||||||
|
@ -116,7 +135,7 @@ see this message :)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QLabel" name="argumentsDescription">
|
<widget class="QLabel" name="argumentsDescription">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>You should never see this message :)</string>
|
<string>You should never see this message :)</string>
|
||||||
|
@ -126,7 +145,7 @@ see this message :)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QPlainTextEdit" name="argumentsEdit">
|
<widget class="QPlainTextEdit" name="argumentsEdit">
|
||||||
<property name="plainText">
|
<property name="plainText">
|
||||||
<string/>
|
<string/>
|
||||||
|
@ -136,8 +155,18 @@ see this message :)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QComboBox" name="categoryPicker"/>
|
<widget class="QComboBox" name="easyArgsPicker">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="currentText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
@ -169,8 +198,8 @@ see this message :)</string>
|
||||||
<slot>afterEdit()</slot>
|
<slot>afterEdit()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>257</x>
|
<x>263</x>
|
||||||
<y>290</y>
|
<y>352</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
|
@ -185,8 +214,8 @@ see this message :)</string>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>325</x>
|
<x>331</x>
|
||||||
<y>290</y>
|
<y>352</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
|
@ -201,8 +230,8 @@ see this message :)</string>
|
||||||
<slot>updatePossibleActions()</slot>
|
<slot>updatePossibleActions()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>246</x>
|
<x>172</x>
|
||||||
<y>85</y>
|
<y>118</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>75</x>
|
<x>75</x>
|
||||||
|
@ -217,8 +246,8 @@ see this message :)</string>
|
||||||
<slot>updateArgumentsInput()</slot>
|
<slot>updateArgumentsInput()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>148</x>
|
<x>172</x>
|
||||||
<y>119</y>
|
<y>156</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>74</x>
|
<x>74</x>
|
||||||
|
|
Loading…
Reference in a new issue