mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Feature: execute commands on chat messages using the context menu (#3738)
This commit is contained in:
parent
7d9c3c65da
commit
4239666934
8 changed files with 103 additions and 9 deletions
|
@ -15,6 +15,7 @@
|
||||||
- Minor: Prevent user from entering incorrect characters in Live Notifications channels list. (#3715, #3730)
|
- Minor: Prevent user from entering incorrect characters in Live Notifications channels list. (#3715, #3730)
|
||||||
- Minor: Fixed automod caught message notice appearing twice for mods. (#3717)
|
- Minor: Fixed automod caught message notice appearing twice for mods. (#3717)
|
||||||
- Minor: Added `/requests` command. Usage: `/requests [channel]`. Opens the channel points requests queue for the provided channel or the current channel if no input is provided. (#3746)
|
- Minor: Added `/requests` command. Usage: `/requests [channel]`. Opens the channel points requests queue for the provided channel or the current channel if no input is provided. (#3746)
|
||||||
|
- Minor: Added ability to execute commands on chat messages using the message context menu. (#3738)
|
||||||
- Bugfix: Fixed live notifications for usernames containing uppercase characters. (#3646)
|
- Bugfix: Fixed live notifications for usernames containing uppercase characters. (#3646)
|
||||||
- Bugfix: Fixed live notifications not getting updated for closed streams going offline. (#3678)
|
- Bugfix: Fixed live notifications not getting updated for closed streams going offline. (#3678)
|
||||||
- Bugfix: Fixed certain settings dialogs appearing behind the main window, when `Always on top` was used. (#3679)
|
- Bugfix: Fixed certain settings dialogs appearing behind the main window, when `Always on top` was used. (#3679)
|
||||||
|
|
|
@ -15,11 +15,14 @@ Command::Command(const QString &_text)
|
||||||
|
|
||||||
this->name = _text.mid(0, index).trimmed();
|
this->name = _text.mid(0, index).trimmed();
|
||||||
this->func = _text.mid(index + 1).trimmed();
|
this->func = _text.mid(index + 1).trimmed();
|
||||||
|
this->showInMsgContextMenu = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::Command(const QString &_name, const QString &_func)
|
Command::Command(const QString &_name, const QString &_func,
|
||||||
|
bool _showInMsgContextMenu)
|
||||||
: name(_name.trimmed())
|
: name(_name.trimmed())
|
||||||
, func(_func.trimmed())
|
, func(_func.trimmed())
|
||||||
|
, showInMsgContextMenu(_showInMsgContextMenu)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,12 @@ namespace chatterino {
|
||||||
struct Command {
|
struct Command {
|
||||||
QString name;
|
QString name;
|
||||||
QString func;
|
QString func;
|
||||||
|
bool showInMsgContextMenu;
|
||||||
|
|
||||||
Command() = default;
|
Command() = default;
|
||||||
explicit Command(const QString &text);
|
explicit Command(const QString &text);
|
||||||
Command(const QString &name, const QString &func);
|
Command(const QString &name, const QString &func,
|
||||||
|
bool showInMsgContextMenu = false);
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
};
|
};
|
||||||
|
@ -31,6 +33,8 @@ struct Serialize<chatterino::Command> {
|
||||||
|
|
||||||
chatterino::rj::set(ret, "name", value.name, a);
|
chatterino::rj::set(ret, "name", value.name, a);
|
||||||
chatterino::rj::set(ret, "func", value.func, a);
|
chatterino::rj::set(ret, "func", value.func, a);
|
||||||
|
chatterino::rj::set(ret, "showInMsgContextMenu",
|
||||||
|
value.showInMsgContextMenu, a);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +63,15 @@ struct Deserialize<chatterino::Command> {
|
||||||
PAJLADA_REPORT_ERROR(error);
|
PAJLADA_REPORT_ERROR(error);
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
if (!chatterino::rj::getSafe(value, "showInMsgContextMenu",
|
||||||
|
command.showInMsgContextMenu))
|
||||||
|
{
|
||||||
|
command.showInMsgContextMenu = false;
|
||||||
|
|
||||||
|
PAJLADA_REPORT_ERROR(error);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace chatterino {
|
||||||
|
|
||||||
// commandmodel
|
// commandmodel
|
||||||
CommandModel::CommandModel(QObject *parent)
|
CommandModel::CommandModel(QObject *parent)
|
||||||
: SignalVectorModel<Command>(2, parent)
|
: SignalVectorModel<Command>(Column::COUNT, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,16 +14,21 @@ CommandModel::CommandModel(QObject *parent)
|
||||||
Command CommandModel::getItemFromRow(std::vector<QStandardItem *> &row,
|
Command CommandModel::getItemFromRow(std::vector<QStandardItem *> &row,
|
||||||
const Command &original)
|
const Command &original)
|
||||||
{
|
{
|
||||||
return Command(row[0]->data(Qt::EditRole).toString(),
|
return Command(row[Column::Trigger]->data(Qt::EditRole).toString(),
|
||||||
row[1]->data(Qt::EditRole).toString());
|
row[Column::CommandFunc]->data(Qt::EditRole).toString(),
|
||||||
|
row[Column::ShowInMessageContextMenu]
|
||||||
|
->data(Qt::CheckStateRole)
|
||||||
|
.toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
// turns a row in the model into a vector item
|
// turns a row in the model into a vector item
|
||||||
void CommandModel::getRowFromItem(const Command &item,
|
void CommandModel::getRowFromItem(const Command &item,
|
||||||
std::vector<QStandardItem *> &row)
|
std::vector<QStandardItem *> &row)
|
||||||
{
|
{
|
||||||
setStringItem(row[0], item.name);
|
setStringItem(row[Column::Trigger], item.name);
|
||||||
setStringItem(row[1], item.func);
|
setStringItem(row[Column::CommandFunc], item.func);
|
||||||
|
setBoolItem(row[Column::ShowInMessageContextMenu],
|
||||||
|
item.showInMsgContextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -13,6 +13,13 @@ class CommandModel : public SignalVectorModel<Command>
|
||||||
{
|
{
|
||||||
explicit CommandModel(QObject *parent);
|
explicit CommandModel(QObject *parent);
|
||||||
|
|
||||||
|
enum Column {
|
||||||
|
Trigger = 0,
|
||||||
|
CommandFunc = 1,
|
||||||
|
ShowInMessageContextMenu = 2,
|
||||||
|
COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// turn a vector item into a model row
|
// turn a vector item into a model row
|
||||||
virtual Command getItemFromRow(std::vector<QStandardItem *> &row,
|
virtual Command getItemFromRow(std::vector<QStandardItem *> &row,
|
||||||
|
|
|
@ -1885,6 +1885,10 @@ void ChannelView::addContextMenuItems(
|
||||||
// Add hidden options (e.g. copy message ID) if the user held down Shift
|
// Add hidden options (e.g. copy message ID) if the user held down Shift
|
||||||
this->addHiddenContextMenuItems(hoveredElement, layout, event, *menu);
|
this->addHiddenContextMenuItems(hoveredElement, layout, event, *menu);
|
||||||
|
|
||||||
|
// Add executable command options
|
||||||
|
this->addCommandExecutionContextMenuItems(hoveredElement, layout, event,
|
||||||
|
*menu);
|
||||||
|
|
||||||
menu->popup(QCursor::pos());
|
menu->popup(QCursor::pos());
|
||||||
menu->raise();
|
menu->raise();
|
||||||
}
|
}
|
||||||
|
@ -2081,6 +2085,62 @@ void ChannelView::addHiddenContextMenuItems(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChannelView::addCommandExecutionContextMenuItems(
|
||||||
|
const MessageLayoutElement * /*hoveredElement*/, MessageLayoutPtr layout,
|
||||||
|
QMouseEvent * /*event*/, QMenu &menu)
|
||||||
|
{
|
||||||
|
/* Get commands to be displayed in context menu;
|
||||||
|
* only those that had the showInMsgContextMenu check box marked in the Commands page */
|
||||||
|
std::vector<Command> cmds;
|
||||||
|
for (auto &cmd : getApp()->commands->items)
|
||||||
|
{
|
||||||
|
if (cmd.showInMsgContextMenu)
|
||||||
|
{
|
||||||
|
cmds.push_back(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmds.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
auto executeAction = menu.addAction("Execute command");
|
||||||
|
auto cmdMenu = new QMenu;
|
||||||
|
executeAction->setMenu(cmdMenu);
|
||||||
|
|
||||||
|
for (auto &cmd : cmds)
|
||||||
|
{
|
||||||
|
QString inputText = this->selection_.isEmpty()
|
||||||
|
? layout->getMessage()->messageText
|
||||||
|
: this->getSelectedText();
|
||||||
|
|
||||||
|
inputText.push_front(cmd.name + " ");
|
||||||
|
|
||||||
|
cmdMenu->addAction(cmd.name, [this, inputText] {
|
||||||
|
ChannelPtr channel;
|
||||||
|
|
||||||
|
/* Search popups and user message history's underlyingChannels aren't of type TwitchChannel, but
|
||||||
|
* we would still like to execute commands from them. Use their source channel instead if applicable. */
|
||||||
|
if (this->hasSourceChannel())
|
||||||
|
{
|
||||||
|
channel = this->sourceChannel();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
channel = this->underlyingChannel_;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString value =
|
||||||
|
getApp()->commands->execCommand(inputText, channel, false);
|
||||||
|
|
||||||
|
channel->sendMessage(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChannelView::mouseDoubleClickEvent(QMouseEvent *event)
|
void ChannelView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() != Qt::LeftButton)
|
if (event->button() != Qt::LeftButton)
|
||||||
|
|
|
@ -184,6 +184,10 @@ private:
|
||||||
void addHiddenContextMenuItems(const MessageLayoutElement *hoveredElement,
|
void addHiddenContextMenuItems(const MessageLayoutElement *hoveredElement,
|
||||||
MessageLayoutPtr layout, QMouseEvent *event,
|
MessageLayoutPtr layout, QMouseEvent *event,
|
||||||
QMenu &menu);
|
QMenu &menu);
|
||||||
|
void addCommandExecutionContextMenuItems(
|
||||||
|
const MessageLayoutElement *hoveredElement, MessageLayoutPtr layout,
|
||||||
|
QMouseEvent *event, QMenu &menu);
|
||||||
|
|
||||||
int getLayoutWidth() const;
|
int getLayoutWidth() const;
|
||||||
void updatePauses();
|
void updatePauses();
|
||||||
void unpaused();
|
void unpaused();
|
||||||
|
|
|
@ -44,8 +44,9 @@ CommandPage::CommandPage()
|
||||||
layout.emplace<EditableModelView>(app->commands->createModel(nullptr))
|
layout.emplace<EditableModelView>(app->commands->createModel(nullptr))
|
||||||
.getElement();
|
.getElement();
|
||||||
|
|
||||||
view->setTitles({"Trigger", "Command"});
|
view->setTitles({"Trigger", "Command", "Show In\nMessage Menu"});
|
||||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||||
|
1, QHeaderView::Stretch);
|
||||||
view->addButtonPressed.connect([] {
|
view->addButtonPressed.connect([] {
|
||||||
getApp()->commands->items.append(
|
getApp()->commands->items.append(
|
||||||
Command{"/command", "I made a new command HeyGuys"});
|
Command{"/command", "I made a new command HeyGuys"});
|
||||||
|
|
Loading…
Reference in a new issue