From 49069beed70943198ca16ebf300b668e7f395c6b Mon Sep 17 00:00:00 2001 From: fourtf Date: Fri, 27 Apr 2018 01:11:09 +0200 Subject: [PATCH] reworked commands settings page --- chatterino.pro | 6 +- src/providers/twitch/twitchmessagebuilder.cpp | 2 +- src/singletons/settingsmanager.hpp | 4 +- src/util/standarditemhelper.hpp | 6 +- src/widgets/helper/comboboxitemdelegate.cpp | 57 ++++++++++++ src/widgets/helper/comboboxitemdelegate.hpp | 26 ++++++ src/widgets/helper/notebooktab.cpp | 24 +++--- src/widgets/settingspages/appearancepage.cpp | 2 +- src/widgets/settingspages/commandpage.cpp | 86 +++++++++++++++++-- .../settingspages/highlightingpage.cpp | 37 ++++---- src/widgets/settingspages/ignoreuserspage.cpp | 21 +++-- 11 files changed, 221 insertions(+), 50 deletions(-) create mode 100644 src/widgets/helper/comboboxitemdelegate.cpp create mode 100644 src/widgets/helper/comboboxitemdelegate.hpp diff --git a/chatterino.pro b/chatterino.pro index a59d2e0b8..3f665720e 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -183,7 +183,8 @@ SOURCES += \ src/singletons/updatemanager.cpp \ src/widgets/lastruncrashdialog.cpp \ src/widgets/attachedwindow.cpp \ - src/widgets/settingspages/externaltoolspage.cpp + src/widgets/settingspages/externaltoolspage.cpp \ + src/widgets/helper/comboboxitemdelegate.cpp HEADERS += \ src/precompiled_header.hpp \ @@ -312,7 +313,8 @@ HEADERS += \ src/widgets/settingspages/externaltoolspage.hpp \ src/util/removescrollareabackground.hpp \ src/util/assertinguithread.h \ - src/util/standarditemhelper.hpp + src/util/standarditemhelper.hpp \ + src/widgets/helper/comboboxitemdelegate.hpp RESOURCES += \ resources/resources.qrc diff --git a/src/providers/twitch/twitchmessagebuilder.cpp b/src/providers/twitch/twitchmessagebuilder.cpp index 8e6e5a330..3c177650d 100644 --- a/src/providers/twitch/twitchmessagebuilder.cpp +++ b/src/providers/twitch/twitchmessagebuilder.cpp @@ -103,7 +103,7 @@ MessagePtr TwitchMessageBuilder::build() this->appendUsername(); // highlights - if (settings.enableHighlights && !isPastMsg) { + if (/*settings.enableHighlights &&*/ !isPastMsg) { this->parseHighlights(); } diff --git a/src/singletons/settingsmanager.hpp b/src/singletons/settingsmanager.hpp index 7f59d8fee..10c7a8bf2 100644 --- a/src/singletons/settingsmanager.hpp +++ b/src/singletons/settingsmanager.hpp @@ -38,7 +38,7 @@ public: BoolSetting showMessageLength = {"/appearance/messages/showMessageLength", false}; BoolSetting seperateMessages = {"/appearance/messages/separateMessages", false}; BoolSetting windowTopMost = {"/appearance/windowAlwaysOnTop", false}; - BoolSetting hideTabX = {"/appearance/hideTabX", false}; + BoolSetting showTabCloseButton = {"/appearance/showTabCloseButton", true}; BoolSetting hidePreferencesButton = {"/appearance/hidePreferencesButton", false}; BoolSetting hideUserButton = {"/appearance/hideUserButton", false}; BoolSetting enableSmoothScrolling = {"/appearance/smoothScrolling", true}; @@ -92,7 +92,7 @@ public: QStringSetting timeoutAction = {"/moderation/timeoutAction", "Disable"}; /// Highlighting - BoolSetting enableHighlights = {"/highlighting/enabled", true}; + // BoolSetting enableHighlights = {"/highlighting/enabled", true}; BoolSetting enableHighlightsSelf = {"/highlighting/nameIsHighlightKeyword", true}; BoolSetting enableHighlightSound = {"/highlighting/enableSound", true}; BoolSetting enableHighlightTaskbar = {"/highlighting/enableTaskbarFlashing", true}; diff --git a/src/util/standarditemhelper.hpp b/src/util/standarditemhelper.hpp index 73eb4ea2b..dd315609a 100644 --- a/src/util/standarditemhelper.hpp +++ b/src/util/standarditemhelper.hpp @@ -5,7 +5,7 @@ namespace chatterino { namespace util { -QStandardItem *boolItem(bool value, bool userCheckable = true, bool selectable = true) +static QStandardItem *boolItem(bool value, bool userCheckable = true, bool selectable = true) { auto *item = new QStandardItem(); item->setFlags((Qt::ItemFlags)(Qt::ItemIsEnabled | (selectable ? Qt::ItemIsSelectable : 0) | @@ -14,7 +14,7 @@ QStandardItem *boolItem(bool value, bool userCheckable = true, bool selectable = return item; } -QStandardItem *stringItem(const QString &value, bool editable = true, bool selectable = true) +static QStandardItem *stringItem(const QString &value, bool editable = true, bool selectable = true) { auto *item = new QStandardItem(value); item->setFlags((Qt::ItemFlags)(Qt::ItemIsEnabled | (selectable ? Qt::ItemIsSelectable : 0) | @@ -22,7 +22,7 @@ QStandardItem *stringItem(const QString &value, bool editable = true, bool selec return item; } -QStandardItem *emptyItem() +static QStandardItem *emptyItem() { auto *item = new QStandardItem(); item->setFlags((Qt::ItemFlags)0); diff --git a/src/widgets/helper/comboboxitemdelegate.cpp b/src/widgets/helper/comboboxitemdelegate.cpp new file mode 100644 index 000000000..0911066b1 --- /dev/null +++ b/src/widgets/helper/comboboxitemdelegate.cpp @@ -0,0 +1,57 @@ +#include "comboboxitemdelegate.hpp" + +#include + +namespace chatterino { +namespace widgets { + +ComboBoxItemDelegate::ComboBoxItemDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ +} + +ComboBoxItemDelegate::~ComboBoxItemDelegate() +{ +} + +QWidget *ComboBoxItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QVariant data = index.data(Qt::UserRole + 1); + + if (data.type() != QVariant::StringList) { + return QStyledItemDelegate::createEditor(parent, option, index); + } + + QComboBox *combo = new QComboBox(parent); + combo->addItems(data.toStringList()); + return combo; +} + +void ComboBoxItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + if (QComboBox *cb = qobject_cast(editor)) { + // get the index of the text in the combobox that matches the current value of the itenm + QString currentText = index.data(Qt::EditRole).toString(); + int cbIndex = cb->findText(currentText); + + // if it is valid, adjust the combobox + if (cbIndex >= 0) { + cb->setCurrentIndex(cbIndex); + } + } else { + QStyledItemDelegate::setEditorData(editor, index); + } +} + +void ComboBoxItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + if (QComboBox *cb = qobject_cast(editor)) + // save the current text of the combo box as the current value of the item + model->setData(index, cb->currentText(), Qt::EditRole); + else + QStyledItemDelegate::setModelData(editor, model, index); +} +} // namespace widgets +} // namespace chatterino diff --git a/src/widgets/helper/comboboxitemdelegate.hpp b/src/widgets/helper/comboboxitemdelegate.hpp new file mode 100644 index 000000000..618948d2f --- /dev/null +++ b/src/widgets/helper/comboboxitemdelegate.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace chatterino { +namespace widgets { + +// stolen from https://wiki.qt.io/Combo_Boxes_in_Item_Views + +class ComboBoxItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + ComboBoxItemDelegate(QObject *parent = 0); + ~ComboBoxItemDelegate(); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; + virtual void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; +}; + +} // namespace widgets +} // namespace chatterino diff --git a/src/widgets/helper/notebooktab.cpp b/src/widgets/helper/notebooktab.cpp index e65a9f388..2f48e17fd 100644 --- a/src/widgets/helper/notebooktab.cpp +++ b/src/widgets/helper/notebooktab.cpp @@ -27,7 +27,7 @@ NotebookTab2::NotebookTab2(Notebook2 *_notebook) this->positionChangedAnimation.setEasingCurve(QEasingCurve(QEasingCurve::InCubic)); - singletons::SettingManager::getInstance().hideTabX.connect( + singletons::SettingManager::getInstance().showTabCloseButton.connect( boost::bind(&NotebookTab2::hideTabXChanged, this, _1), this->managedConnections); this->setMouseTracking(true); @@ -82,7 +82,7 @@ void NotebookTab2::updateSize() int width; QFontMetrics metrics(this->font()); - if (singletons::SettingManager::getInstance().hideTabX) { + if (!singletons::SettingManager::getInstance().showTabCloseButton) { width = (int)((metrics.width(this->title) + 16 /*+ 16*/) * scale); } else { width = (int)((metrics.width(this->title) + 8 + 24 /*+ 16*/) * scale); @@ -248,7 +248,7 @@ void NotebookTab2::paintEvent(QPaintEvent *) painter.setPen(colors.text); // set area for text - int rectW = (settingManager.hideTabX ? 0 : static_cast(16) * scale); + int rectW = (!settingManager.showTabCloseButton ? 0 : static_cast(16) * scale); QRect rect(0, 0, this->width() - rectW, height); // draw text @@ -269,7 +269,7 @@ void NotebookTab2::paintEvent(QPaintEvent *) } // draw close x - if (!settingManager.hideTabX && (mouseOver || selected)) { + if (settingManager.showTabCloseButton && (mouseOver || selected)) { QRect xRect = this->getXRect(); if (!xRect.isNull()) { if (mouseOverX) { @@ -315,7 +315,7 @@ void NotebookTab2::mouseReleaseEvent(QMouseEvent *event) this->notebook->removePage(this->page); } } else { - if (!singletons::SettingManager::getInstance().hideTabX && this->mouseDownX && + if (singletons::SettingManager::getInstance().showTabCloseButton && this->mouseDownX && this->getXRect().contains(event->pos())) { this->mouseDownX = false; @@ -350,7 +350,7 @@ void NotebookTab2::dragEnterEvent(QDragEnterEvent *) void NotebookTab2::mouseMoveEvent(QMouseEvent *event) { - if (!singletons::SettingManager::getInstance().hideTabX && + if (singletons::SettingManager::getInstance().showTabCloseButton && this->notebook->getAllowUserTabManagement()) // { bool overX = this->getXRect().contains(event->pos()); @@ -401,7 +401,7 @@ NotebookTab::NotebookTab(Notebook *_notebook) this->positionChangedAnimation.setEasingCurve(QEasingCurve(QEasingCurve::InCubic)); - singletons::SettingManager::getInstance().hideTabX.connect( + singletons::SettingManager::getInstance().showTabCloseButton.connect( boost::bind(&NotebookTab::hideTabXChanged, this, _1), this->managedConnections); this->setMouseTracking(true); @@ -453,7 +453,7 @@ void NotebookTab::updateSize() int width; - if (singletons::SettingManager::getInstance().hideTabX) { + if (!singletons::SettingManager::getInstance().showTabCloseButton) { width = (int)((fontMetrics().width(this->title) + 16 /*+ 16*/) * scale); } else { width = (int)((fontMetrics().width(this->title) + 8 + 24 /*+ 16*/) * scale); @@ -619,7 +619,7 @@ void NotebookTab::paintEvent(QPaintEvent *) painter.setPen(colors.text); // set area for text - int rectW = (settingManager.hideTabX ? 0 : static_cast(16) * scale); + int rectW = (!settingManager.showTabCloseButton ? 0 : static_cast(16) * scale); QRect rect(0, 0, this->width() - rectW, height); // draw text @@ -640,7 +640,7 @@ void NotebookTab::paintEvent(QPaintEvent *) } // draw close x - if (!settingManager.hideTabX && (mouseOver || selected)) { + if (settingManager.showTabCloseButton && (mouseOver || selected)) { QRect xRect = this->getXRect(); if (mouseOverX) { painter.fillRect(xRect, QColor(0, 0, 0, 64)); @@ -682,7 +682,7 @@ void NotebookTab::mouseReleaseEvent(QMouseEvent *event) this->notebook->removePage(this->page); } } else { - if (!singletons::SettingManager::getInstance().hideTabX && this->mouseDownX && + if (singletons::SettingManager::getInstance().showTabCloseButton && this->mouseDownX && this->getXRect().contains(event->pos())) { this->mouseDownX = false; @@ -715,7 +715,7 @@ void NotebookTab::dragEnterEvent(QDragEnterEvent *) void NotebookTab::mouseMoveEvent(QMouseEvent *event) { - if (!singletons::SettingManager::getInstance().hideTabX) { + if (singletons::SettingManager::getInstance().showTabCloseButton) { bool overX = this->getXRect().contains(event->pos()); if (overX != this->mouseOverX) { diff --git a/src/widgets/settingspages/appearancepage.cpp b/src/widgets/settingspages/appearancepage.cpp index e7cd3c163..aeaa50495 100644 --- a/src/widgets/settingspages/appearancepage.cpp +++ b/src/widgets/settingspages/appearancepage.cpp @@ -53,7 +53,7 @@ AppearancePage::AppearancePage() form->addRow("Theme color:", this->createThemeColorChanger()); form->addRow("Font:", this->createFontChanger()); - form->addRow("Tabs:", this->createCheckBox(TAB_X, settings.hideTabX)); + form->addRow("Tabs:", this->createCheckBox(TAB_X, settings.showTabCloseButton)); #ifndef USEWINSDK form->addRow("", this->createCheckBox(TAB_PREF, settings.hidePreferencesButton)); form->addRow("", this->createCheckBox(TAB_USER, settings.hideUserButton)); diff --git a/src/widgets/settingspages/commandpage.cpp b/src/widgets/settingspages/commandpage.cpp index ff18bd4b6..b38e70a45 100644 --- a/src/widgets/settingspages/commandpage.cpp +++ b/src/widgets/settingspages/commandpage.cpp @@ -1,17 +1,20 @@ #include "commandpage.hpp" #include +#include +#include +#include #include #include "singletons/commandmanager.hpp" #include "util/layoutcreator.hpp" +#include "util/standarditemhelper.hpp" +//#include "widgets/helper/comboboxitemdelegate.hpp" // clang-format off -#define TEXT "One command per line.\n"\ - "\"/cmd example command\" will print \"example command\" when you type /cmd in chat.\n"\ - "{1} will be replaced with the first word you type after then command, {2} with the second and so on.\n"\ - "{1+} will be replaced with first word and everything after, {2+} with everything after the second word and so on\n"\ - "Duplicate commands will be ignored." +#define TEXT "{1} => first word, {2} => second word, ...\n"\ + "{1+} => first word and after, {2+} => second word and after, ...\n"\ + "{{1} => {1}" // clang-format on namespace chatterino { @@ -21,12 +24,81 @@ namespace settingspages { CommandPage::CommandPage() : SettingsPage("Commands", ":/images/commands.svg") { + auto &settings = singletons::SettingManager::getInstance(); + util::LayoutCreator layoutCreator(this); auto layout = layoutCreator.emplace().withoutMargin(); - layout.emplace(TEXT)->setWordWrap(true); + QTableView *view = *layout.emplace(); + QStandardItemModel *model = new QStandardItemModel(0, 2, view); - layout.append(this->getCommandsTextEdit()); + view->setModel(model); + model->setHeaderData(0, Qt::Horizontal, "Trigger"); + model->setHeaderData(1, Qt::Horizontal, "Command"); + view->setSelectionMode(QAbstractItemView::ExtendedSelection); + view->setSelectionBehavior(QAbstractItemView::SelectRows); + view->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + + for (const QString &string : singletons::CommandManager::getInstance().getCommands()) { + int index = string.indexOf(' '); + if (index == -1) { + model->appendRow({util::stringItem(string), util::stringItem("")}); + } else { + model->appendRow( + {util::stringItem(string.mid(0, index)), util::stringItem(string.mid(index + 1))}); + } + } + + QObject::connect( + model, &QStandardItemModel::dataChanged, + [model](const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector &roles) { + QStringList list; + + for (int i = 0; i < model->rowCount(); i++) { + QString command = model->item(i, 0)->data(Qt::EditRole).toString(); + // int index = command.indexOf(' '); + // if (index != -1) { + // command = command.mid(index); + // } + + list.append(command + " " + model->item(i, 1)->data(Qt::EditRole).toString()); + } + + singletons::CommandManager::getInstance().setCommands(list); + }); + + auto buttons = layout.emplace().withoutMargin(); + { + auto add = buttons.emplace("Add"); + QObject::connect(*add, &QPushButton::clicked, [model, view] { + model->appendRow({util::stringItem("/command"), util::stringItem("")}); + view->scrollToBottom(); + }); + + auto remove = buttons.emplace("Remove"); + QObject::connect(*remove, &QPushButton::clicked, [view, model] { + std::vector indices; + + for (const QModelIndex &index : view->selectionModel()->selectedRows(0)) { + indices.push_back(index.row()); + } + + std::sort(indices.begin(), indices.end()); + + for (int i = indices.size() - 1; i >= 0; i--) { + model->removeRow(indices[i]); + } + }); + buttons->addStretch(1); + } + + layout.append(this->createCheckBox("Also match the trigger at the end of the message", + settings.allowCommandsAtEnd)); + + QLabel *text = *layout.emplace(TEXT); + text->setWordWrap(true); + text->setStyleSheet("color: #bbb"); // ---- end of layout this->commandsEditTimer.setSingleShot(true); diff --git a/src/widgets/settingspages/highlightingpage.cpp b/src/widgets/settingspages/highlightingpage.cpp index fd4ea856c..f2d0e6376 100644 --- a/src/widgets/settingspages/highlightingpage.cpp +++ b/src/widgets/settingspages/highlightingpage.cpp @@ -32,7 +32,7 @@ HighlightingPage::HighlightingPage() auto layout = layoutCreator.emplace().withoutMargin(); { // GENERAL - layout.append(this->createCheckBox(ENABLE_HIGHLIGHTS, settings.enableHighlights)); + // layout.append(this->createCheckBox(ENABLE_HIGHLIGHTS, settings.enableHighlights)); // TABS auto tabs = layout.emplace(); @@ -77,7 +77,7 @@ HighlightingPage::HighlightingPage() view->setColumnWidth(0, 250); }); - auto buttons = highlights.emplace(); + auto buttons = highlights.emplace().withoutMargin(); QObject::connect(model, &QStandardItemModel::dataChanged, [model](const QModelIndex &topLeft, const QModelIndex &bottomRight, @@ -126,28 +126,31 @@ HighlightingPage::HighlightingPage() model->removeRow(indices[i]); } }); + buttons->addStretch(1); view->hideColumn(3); } + // DISABLED USERS - auto disabledUsers = tabs.appendTab(new QVBoxLayout, "Disabled Users"); - { - auto text = disabledUsers.emplace().getElement(); + // auto disabledUsers = tabs.appendTab(new QVBoxLayout, "Disabled Users"); + // { + // auto text = disabledUsers.emplace().getElement(); - QObject::connect(text, &QTextEdit::textChanged, this, - [this] { this->disabledUsersChangedTimer.start(200); }); + // QObject::connect(text, &QTextEdit::textChanged, this, + // [this] { this->disabledUsersChangedTimer.start(200); }); - QObject::connect( - &this->disabledUsersChangedTimer, &QTimer::timeout, this, [text, &settings]() { - QStringList list = text->toPlainText().split("\n", QString::SkipEmptyParts); - list.removeDuplicates(); - settings.highlightUserBlacklist = list.join("\n") + "\n"; - }); + // QObject::connect( + // &this->disabledUsersChangedTimer, &QTimer::timeout, this, [text, &settings]() + // { + // QStringList list = text->toPlainText().split("\n", + // QString::SkipEmptyParts); list.removeDuplicates(); + // settings.highlightUserBlacklist = list.join("\n") + "\n"; + // }); - settings.highlightUserBlacklist.connect([=](const QString &str, auto) { - text->setPlainText(str); // - }); - } + // settings.highlightUserBlacklist.connect([=](const QString &str, auto) { + // text->setPlainText(str); // + // }); + // } } // MISC diff --git a/src/widgets/settingspages/ignoreuserspage.cpp b/src/widgets/settingspages/ignoreuserspage.cpp index 1c81d4a5c..60a86760b 100644 --- a/src/widgets/settingspages/ignoreuserspage.cpp +++ b/src/widgets/settingspages/ignoreuserspage.cpp @@ -25,19 +25,24 @@ IgnoreUsersPage::IgnoreUsersPage() util::LayoutCreator layoutCreator(this); auto layout = layoutCreator.setLayoutType(); - auto group = layout.emplace("Ignored users").setLayoutType(); + // auto group = layout.emplace("Ignored users").setLayoutType(); + auto tabs = layout.emplace(); + tabs->setStyleSheet("color: #000"); + + // users + auto users = tabs.appendTab(new QVBoxLayout, "Users"); { - group.append( + users.append( this->createCheckBox("Enable twitch ignored users", settings.enableTwitchIgnoredUsers)); - auto anyways = group.emplace().withoutMargin(); + auto anyways = users.emplace().withoutMargin(); { anyways.emplace("Show anyways if:"); anyways.emplace(); anyways->addStretch(1); } - auto addremove = group.emplace().withoutMargin(); + auto addremove = users.emplace().withoutMargin(); { auto add = addremove.emplace("Ignore user"); auto remove = addremove.emplace("Unignore User"); @@ -46,10 +51,16 @@ IgnoreUsersPage::IgnoreUsersPage() addremove->addStretch(1); } - auto userList = group.emplace(); + auto userList = users.emplace(); UNUSED(userList); // TODO: Fill this list in with ignored users } + // messages + auto messages = tabs.appendTab(new QVBoxLayout, "Messages"); + { + messages.emplace("wip"); + } + auto label = layout.emplace(INFO); label->setWordWrap(true); label->setStyleSheet("color: #BBB");