mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Merge branch 'master' of https://github.com/fourtf/chatterino2
This commit is contained in:
commit
ef4c7dbe60
|
@ -223,7 +223,8 @@ SOURCES += \
|
||||||
src/singletons/Resources.cpp \
|
src/singletons/Resources.cpp \
|
||||||
src/singletons/Settings.cpp \
|
src/singletons/Settings.cpp \
|
||||||
src/singletons/Updates.cpp \
|
src/singletons/Updates.cpp \
|
||||||
src/singletons/Theme.cpp
|
src/singletons/Theme.cpp \
|
||||||
|
src/controllers/moderationactions/ModerationActionModel.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/Application.hpp \
|
src/Application.hpp \
|
||||||
|
@ -393,7 +394,8 @@ HEADERS += \
|
||||||
src/singletons/Theme.hpp \
|
src/singletons/Theme.hpp \
|
||||||
src/common/SimpleSignalVector.hpp \
|
src/common/SimpleSignalVector.hpp \
|
||||||
src/common/SignalVector.hpp \
|
src/common/SignalVector.hpp \
|
||||||
src/common/Singleton.hpp
|
src/common/Singleton.hpp \
|
||||||
|
src/controllers/moderationactions/ModerationActionModel.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources/resources.qrc \
|
resources/resources.qrc \
|
||||||
|
|
|
@ -1,23 +1,7 @@
|
||||||
#tabWidget {
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
font-size: <font-size>px;
|
font-size: <font-size>px;
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsDialogTab:hover {
|
|
||||||
border: 1px solid grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
QLabel, QCheckBox, QGroupBox, SettingsDialogTab {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
QGroupBox {
|
|
||||||
background-color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator {
|
||||||
width: <checkbox-size>px;
|
width: <checkbox-size>px;
|
||||||
height: <checkbox-size>px;
|
height: <checkbox-size>px;
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
TwitchWatching,
|
TwitchWatching,
|
||||||
TwitchMentions,
|
TwitchMentions,
|
||||||
TwitchEnd,
|
TwitchEnd,
|
||||||
|
Misc
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Channel(const QString &_name, Type type);
|
explicit Channel(const QString &_name, Type type);
|
||||||
|
|
|
@ -50,6 +50,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isSorted() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<TVectorItem> vector;
|
std::vector<TVectorItem> vector;
|
||||||
QTimer itemsChangedTimer;
|
QTimer itemsChangedTimer;
|
||||||
|
@ -60,9 +62,10 @@ class BaseSignalVector : public ReadOnlySignalVector<TVectorItem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// returns the actual index of the inserted item
|
// returns the actual index of the inserted item
|
||||||
virtual int insertItem(const TVectorItem &item, int proposedIndex = -1, void *caller = 0) = 0;
|
virtual int insertItem(const TVectorItem &item, int proposedIndex = -1,
|
||||||
|
void *caller = nullptr) = 0;
|
||||||
|
|
||||||
void removeItem(int index, void *caller = 0)
|
void removeItem(int index, void *caller = nullptr)
|
||||||
{
|
{
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
assert(index >= 0 && index < this->vector.size());
|
assert(index >= 0 && index < this->vector.size());
|
||||||
|
@ -75,7 +78,7 @@ public:
|
||||||
this->invokeDelayedItemsChanged();
|
this->invokeDelayedItemsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
int appendItem(const TVectorItem &item, void *caller = 0)
|
int appendItem(const TVectorItem &item, void *caller = nullptr)
|
||||||
{
|
{
|
||||||
return this->insertItem(item, -1, caller);
|
return this->insertItem(item, -1, caller);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +88,7 @@ template <typename TVectorItem>
|
||||||
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
|
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = 0) override
|
virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = nullptr) override
|
||||||
{
|
{
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
|
@ -101,6 +104,11 @@ public:
|
||||||
this->invokeDelayedItemsChanged();
|
this->invokeDelayedItemsChanged();
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isSorted() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TVectorItem, typename Compare>
|
template <typename TVectorItem, typename Compare>
|
||||||
|
@ -120,6 +128,11 @@ public:
|
||||||
this->invokeDelayedItemsChanged();
|
this->invokeDelayedItemsChanged();
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isSorted() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -171,8 +171,8 @@ QString CommandController::execCommand(const QString &text, ChannelPtr channel,
|
||||||
auto target = words.at(1);
|
auto target = words.at(1);
|
||||||
|
|
||||||
if (user->isAnon()) {
|
if (user->isAnon()) {
|
||||||
channel->addMessage(Message::createSystemMessage(
|
channel->addMessage(
|
||||||
"You must be logged in to ignore someone"));
|
Message::createSystemMessage("You must be logged in to ignore someone"));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,8 +188,8 @@ QString CommandController::execCommand(const QString &text, ChannelPtr channel,
|
||||||
auto target = words.at(1);
|
auto target = words.at(1);
|
||||||
|
|
||||||
if (user->isAnon()) {
|
if (user->isAnon()) {
|
||||||
channel->addMessage(Message::createSystemMessage(
|
channel->addMessage(
|
||||||
"You must be logged in to ignore someone"));
|
Message::createSystemMessage("You must be logged in to ignore someone"));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isImage_;
|
bool isImage_;
|
||||||
Image *image_;
|
Image *image_ = nullptr;
|
||||||
QString line1_;
|
QString line1_;
|
||||||
QString line2_;
|
QString line2_;
|
||||||
QString action_;
|
QString action_;
|
||||||
|
|
27
src/controllers/moderationactions/ModerationActionModel.cpp
Normal file
27
src/controllers/moderationactions/ModerationActionModel.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "ModerationActionModel.hpp"
|
||||||
|
|
||||||
|
#include "util/StandardItemHelper.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
// commandmodel
|
||||||
|
ModerationActionModel ::ModerationActionModel(QObject *parent)
|
||||||
|
: SignalVectorModel<ModerationAction>(1, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn a vector item into a model row
|
||||||
|
ModerationAction ModerationActionModel::getItemFromRow(std::vector<QStandardItem *> &row,
|
||||||
|
const ModerationAction &original)
|
||||||
|
{
|
||||||
|
return ModerationAction(row[0]->data(Qt::DisplayRole).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// turns a row in the model into a vector item
|
||||||
|
void ModerationActionModel::getRowFromItem(const ModerationAction &item,
|
||||||
|
std::vector<QStandardItem *> &row)
|
||||||
|
{
|
||||||
|
setStringItem(row[0], item.getAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
31
src/controllers/moderationactions/ModerationActionModel.hpp
Normal file
31
src/controllers/moderationactions/ModerationActionModel.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "common/SignalVectorModel.hpp"
|
||||||
|
#include "controllers/moderationactions/ModerationAction.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
class ModerationActions;
|
||||||
|
|
||||||
|
class ModerationActionModel : public SignalVectorModel<ModerationAction>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ModerationActionModel(QObject *parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// turn a vector item into a model row
|
||||||
|
virtual ModerationAction getItemFromRow(std::vector<QStandardItem *> &row,
|
||||||
|
const ModerationAction &original) override;
|
||||||
|
|
||||||
|
// turns a row in the model into a vector item
|
||||||
|
virtual void getRowFromItem(const ModerationAction &item,
|
||||||
|
std::vector<QStandardItem *> &row) override;
|
||||||
|
|
||||||
|
friend class HighlightController;
|
||||||
|
|
||||||
|
friend class ModerationActions;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
|
@ -1,6 +1,7 @@
|
||||||
#include "ModerationActions.hpp"
|
#include "ModerationActions.hpp"
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
|
#include "controllers/moderationactions/ModerationActionModel.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
@ -25,4 +26,12 @@ void ModerationActions::initialize()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModerationActionModel *ModerationActions::createModel(QObject *parent)
|
||||||
|
{
|
||||||
|
ModerationActionModel *model = new ModerationActionModel(parent);
|
||||||
|
model->init(&this->items);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/ChatterinoSetting.hpp"
|
||||||
#include "common/SignalVector.hpp"
|
#include "common/SignalVector.hpp"
|
||||||
#include "controllers/moderationactions/ModerationAction.hpp"
|
#include "controllers/moderationactions/ModerationAction.hpp"
|
||||||
#include "common/ChatterinoSetting.hpp"
|
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
|
class ModerationActionModel;
|
||||||
|
|
||||||
class ModerationActions
|
class ModerationActions
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +17,8 @@ public:
|
||||||
|
|
||||||
UnsortedSignalVector<ModerationAction> items;
|
UnsortedSignalVector<ModerationAction> items;
|
||||||
|
|
||||||
|
ModerationActionModel *createModel(QObject *parent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ChatterinoSetting<std::vector<ModerationAction>> setting = {"/moderation/actions"};
|
ChatterinoSetting<std::vector<ModerationAction>> setting = {"/moderation/actions"};
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
|
@ -47,8 +47,8 @@ QString MessageBuilder::matchLink(const QString &string)
|
||||||
{
|
{
|
||||||
LinkParser linkParser(string);
|
LinkParser linkParser(string);
|
||||||
|
|
||||||
static QRegularExpression httpRegex("\\bhttps?://");
|
static QRegularExpression httpRegex("\\bhttps?://", QRegularExpression::CaseInsensitiveOption);
|
||||||
static QRegularExpression ftpRegex("\\bftps?://");
|
static QRegularExpression ftpRegex("\\bftps?://", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
|
||||||
if (!linkParser.hasMatch()) {
|
if (!linkParser.hasMatch()) {
|
||||||
return QString();
|
return QString();
|
||||||
|
|
|
@ -247,7 +247,7 @@ void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
|
||||||
MessageElement::Flags _flags)
|
MessageElement::Flags _flags)
|
||||||
{
|
{
|
||||||
if (_flags & MessageElement::ModeratorTools) {
|
if (_flags & MessageElement::ModeratorTools) {
|
||||||
QSize size((int)(container.getScale() * 16), (int)(container.getScale() * 16));
|
QSize size(int(container.getScale() * 16), int(container.getScale() * 16));
|
||||||
|
|
||||||
for (const ModerationAction &m : getApp()->moderationActions->items.getVector()) {
|
for (const ModerationAction &m : getApp()->moderationActions->items.getVector()) {
|
||||||
if (m.isImage()) {
|
if (m.isImage()) {
|
||||||
|
|
|
@ -37,11 +37,11 @@ void BTTVEmotes::loadGlobalEmotes()
|
||||||
|
|
||||||
EmoteData emoteData;
|
EmoteData emoteData;
|
||||||
emoteData.image1x = new Image(getEmoteLink(urlTemplate, id, "1x"), 1, code,
|
emoteData.image1x = new Image(getEmoteLink(urlTemplate, id, "1x"), 1, code,
|
||||||
code + "<br />Global BTTV Emote");
|
code + "<br />Global BTTV Emote");
|
||||||
emoteData.image2x = new Image(getEmoteLink(urlTemplate, id, "2x"), 0.5,
|
emoteData.image2x = new Image(getEmoteLink(urlTemplate, id, "2x"), 0.5, code,
|
||||||
code, code + "<br />Global BTTV Emote");
|
code + "<br />Global BTTV Emote");
|
||||||
emoteData.image3x = new Image(getEmoteLink(urlTemplate, id, "3x"), 0.25,
|
emoteData.image3x = new Image(getEmoteLink(urlTemplate, id, "3x"), 0.25, code,
|
||||||
code, code + "<br />Global BTTV Emote");
|
code + "<br />Global BTTV Emote");
|
||||||
emoteData.pageLink = "https://manage.betterttv.net/emotes/" + id;
|
emoteData.pageLink = "https://manage.betterttv.net/emotes/" + id;
|
||||||
|
|
||||||
this->globalEmotes.insert(code, emoteData);
|
this->globalEmotes.insert(code, emoteData);
|
||||||
|
@ -89,19 +89,16 @@ void BTTVEmotes::loadChannelEmotes(const QString &channelName, std::weak_ptr<Emo
|
||||||
EmoteData emoteData;
|
EmoteData emoteData;
|
||||||
QString link = linkTemplate;
|
QString link = linkTemplate;
|
||||||
link.detach();
|
link.detach();
|
||||||
emoteData.image1x =
|
emoteData.image1x = new Image(link.replace("{{id}}", id).replace("{{image}}", "1x"),
|
||||||
new Image(link.replace("{{id}}", id).replace("{{image}}", "1x"), 1,
|
1, code, code + "<br />Channel BTTV Emote");
|
||||||
code, code + "<br />Channel BTTV Emote");
|
|
||||||
link = linkTemplate;
|
link = linkTemplate;
|
||||||
link.detach();
|
link.detach();
|
||||||
emoteData.image2x =
|
emoteData.image2x = new Image(link.replace("{{id}}", id).replace("{{image}}", "2x"),
|
||||||
new Image(link.replace("{{id}}", id).replace("{{image}}", "2x"),
|
0.5, code, code + "<br />Channel BTTV Emote");
|
||||||
0.5, code, code + "<br />Channel BTTV Emote");
|
|
||||||
link = linkTemplate;
|
link = linkTemplate;
|
||||||
link.detach();
|
link.detach();
|
||||||
emoteData.image3x =
|
emoteData.image3x = new Image(link.replace("{{id}}", id).replace("{{image}}", "3x"),
|
||||||
new Image(link.replace("{{id}}", id).replace("{{image}}", "3x"),
|
0.25, code, code + "<br />Channel BTTV Emote");
|
||||||
0.25, code, code + "<br />Channel BTTV Emote");
|
|
||||||
emoteData.pageLink = "https://manage.betterttv.net/emotes/" + id;
|
emoteData.pageLink = "https://manage.betterttv.net/emotes/" + id;
|
||||||
|
|
||||||
return emoteData;
|
return emoteData;
|
||||||
|
|
|
@ -260,8 +260,8 @@ void Emojis::loadEmojiSet()
|
||||||
urlPrefix = it->second;
|
urlPrefix = it->second;
|
||||||
}
|
}
|
||||||
QString url = urlPrefix + code + ".png";
|
QString url = urlPrefix + code + ".png";
|
||||||
emoji->emoteData.image1x = new Image(
|
emoji->emoteData.image1x =
|
||||||
url, 0.35, emoji->value, ":" + emoji->shortCodes[0] + ":<br/>Emoji");
|
new Image(url, 0.35, emoji->value, ":" + emoji->shortCodes[0] + ":<br/>Emoji");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,8 +253,7 @@ void IrcMessageHandler::handleUserNoticeMessage(Communi::IrcMessage *message, Tw
|
||||||
auto it = tags.find("system-msg");
|
auto it = tags.find("system-msg");
|
||||||
|
|
||||||
if (it != tags.end()) {
|
if (it != tags.end()) {
|
||||||
auto newMessage =
|
auto newMessage = Message::createSystemMessage(parseTagString(it.value().toString()));
|
||||||
Message::createSystemMessage(parseTagString(it.value().toString()));
|
|
||||||
|
|
||||||
newMessage->flags |= Message::Subscription;
|
newMessage->flags |= Message::Subscription;
|
||||||
|
|
||||||
|
@ -322,12 +321,22 @@ void IrcMessageHandler::handleNoticeMessage(Communi::IrcNoticeMessage *message)
|
||||||
void IrcMessageHandler::handleWriteConnectionNoticeMessage(Communi::IrcNoticeMessage *message)
|
void IrcMessageHandler::handleWriteConnectionNoticeMessage(Communi::IrcNoticeMessage *message)
|
||||||
{
|
{
|
||||||
static std::unordered_set<std::string> readConnectionOnlyIDs{
|
static std::unordered_set<std::string> readConnectionOnlyIDs{
|
||||||
"host_on", "host_off", "host_target_went_offline", "emote_only_on", "emote_only_off",
|
"host_on",
|
||||||
"slow_on", "slow_off", "subs_on", "subs_off", "r9k_on", "r9k_off",
|
"host_off",
|
||||||
|
"host_target_went_offline",
|
||||||
|
"emote_only_on",
|
||||||
|
"emote_only_off",
|
||||||
|
"slow_on",
|
||||||
|
"slow_off",
|
||||||
|
"subs_on",
|
||||||
|
"subs_off",
|
||||||
|
"r9k_on",
|
||||||
|
"r9k_off",
|
||||||
|
|
||||||
// Display for user who times someone out. This implies you're a moderator, at which point
|
// Display for user who times someone out. This implies you're a moderator, at which point
|
||||||
// you will be connected to PubSub and receive a better message from there
|
// you will be connected to PubSub and receive a better message from there
|
||||||
"timeout_success", "ban_success",
|
"timeout_success",
|
||||||
|
"ban_success",
|
||||||
};
|
};
|
||||||
|
|
||||||
QVariant v = message->tag("msg-id");
|
QVariant v = message->tag("msg-id");
|
||||||
|
|
|
@ -194,8 +194,7 @@ void TwitchServer::onMessageSendRequested(TwitchChannel *channel, const QString
|
||||||
// check if you are sending messages too fast
|
// check if you are sending messages too fast
|
||||||
if (!lastMessage.empty() && lastMessage.back() + minMessageOffset > now) {
|
if (!lastMessage.empty() && lastMessage.back() + minMessageOffset > now) {
|
||||||
if (this->lastErrorTimeSpeed_ + 30s < now) {
|
if (this->lastErrorTimeSpeed_ + 30s < now) {
|
||||||
auto errorMessage =
|
auto errorMessage = Message::createSystemMessage("sending messages too fast");
|
||||||
Message::createSystemMessage("sending messages too fast");
|
|
||||||
|
|
||||||
channel->addMessage(errorMessage);
|
channel->addMessage(errorMessage);
|
||||||
|
|
||||||
|
@ -212,8 +211,7 @@ void TwitchServer::onMessageSendRequested(TwitchChannel *channel, const QString
|
||||||
// check if you are sending too many messages
|
// check if you are sending too many messages
|
||||||
if (lastMessage.size() >= maxMessageCount) {
|
if (lastMessage.size() >= maxMessageCount) {
|
||||||
if (this->lastErrorTimeAmount_ + 30s < now) {
|
if (this->lastErrorTimeAmount_ + 30s < now) {
|
||||||
auto errorMessage =
|
auto errorMessage = Message::createSystemMessage("sending too many messages");
|
||||||
Message::createSystemMessage("sending too many messages");
|
|
||||||
|
|
||||||
channel->addMessage(errorMessage);
|
channel->addMessage(errorMessage);
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,6 @@ void Paths::initSubDirectories()
|
||||||
|
|
||||||
// create settings subdirectories and validate that they are created properly
|
// create settings subdirectories and validate that they are created properly
|
||||||
auto makePath = [&](const std::string &name) -> QString {
|
auto makePath = [&](const std::string &name) -> QString {
|
||||||
|
|
||||||
auto path = combinePath(this->rootAppDataDirectory, QString::fromStdString(name));
|
auto path = combinePath(this->rootAppDataDirectory, QString::fromStdString(name));
|
||||||
|
|
||||||
if (!QDir().mkpath(path)) {
|
if (!QDir().mkpath(path)) {
|
||||||
|
|
|
@ -434,6 +434,8 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message, long *r
|
||||||
default:
|
default:
|
||||||
return QWidget::nativeEvent(eventType, message, result);
|
return QWidget::nativeEvent(eventType, message, result);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
return QWidget::nativeEvent(eventType, message, result);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +455,12 @@ void BaseWindow::paintEvent(QPaintEvent *)
|
||||||
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
|
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->drawCustomWindowFrame(painter);
|
// this->drawCustomWindowFrame(painter);
|
||||||
|
// QPainter painter(this);
|
||||||
|
|
||||||
|
QColor bg = this->overrideBackgroundColor_.value_or(this->themeManager->window.background);
|
||||||
|
|
||||||
|
painter.fillRect(QRect(0, 1, this->width() - 0, this->height() - 0), bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseWindow::updateScale()
|
void BaseWindow::updateScale()
|
||||||
|
@ -492,14 +499,16 @@ void BaseWindow::calcButtonsSizes()
|
||||||
|
|
||||||
void BaseWindow::drawCustomWindowFrame(QPainter &painter)
|
void BaseWindow::drawCustomWindowFrame(QPainter &painter)
|
||||||
{
|
{
|
||||||
#ifdef USEWINSDK
|
//#ifdef USEWINSDK
|
||||||
if (this->hasCustomWindowFrame()) {
|
// if (this->hasCustomWindowFrame()) {
|
||||||
QPainter painter(this);
|
// QPainter painter(this);
|
||||||
|
|
||||||
painter.fillRect(QRect(0, 1, this->width() - 0, this->height() - 0),
|
// QColor bg =
|
||||||
this->themeManager->window.background);
|
// this->overrideBackgroundColor_.value_or(this->themeManager->window.background);
|
||||||
}
|
|
||||||
#endif
|
// painter.fillRect(QRect(0, 1, this->width() - 0, this->height() - 0), bg);
|
||||||
|
// }
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseWindow::handleDPICHANGED(MSG *msg)
|
bool BaseWindow::handleDPICHANGED(MSG *msg)
|
||||||
|
|
|
@ -70,6 +70,8 @@ protected:
|
||||||
|
|
||||||
void updateScale();
|
void updateScale();
|
||||||
|
|
||||||
|
boost::optional<QColor> overrideBackgroundColor_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void moveIntoDesktopRect(QWidget *parent);
|
void moveIntoDesktopRect(QWidget *parent);
|
||||||
|
|
|
@ -76,8 +76,7 @@ void TooltipWidget::updateFont()
|
||||||
{
|
{
|
||||||
auto app = getApp();
|
auto app = getApp();
|
||||||
|
|
||||||
this->setFont(
|
this->setFont(app->fonts->getFont(Fonts::Type::ChatMediumSmall, this->getScale()));
|
||||||
app->fonts->getFont(Fonts::Type::ChatMediumSmall, this->getScale()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TooltipWidget::setText(QString text)
|
void TooltipWidget::setText(QString text)
|
||||||
|
|
|
@ -32,6 +32,8 @@ SettingsDialog::SettingsDialog()
|
||||||
this->addTabs();
|
this->addTabs();
|
||||||
|
|
||||||
this->scaleChangedEvent(this->getScale());
|
this->scaleChangedEvent(this->getScale());
|
||||||
|
|
||||||
|
this->overrideBackgroundColor_ = QColor("#282828");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::initUi()
|
void SettingsDialog::initUi()
|
||||||
|
@ -149,8 +151,6 @@ void SettingsDialog::showDialog(PreferredTab preferredTab)
|
||||||
|
|
||||||
void SettingsDialog::refresh()
|
void SettingsDialog::refresh()
|
||||||
{
|
{
|
||||||
// this->ui.accountSwitchWidget->refresh();
|
|
||||||
|
|
||||||
getApp()->settings->saveSnapshot();
|
getApp()->settings->saveSnapshot();
|
||||||
|
|
||||||
for (auto *tab : this->tabs) {
|
for (auto *tab : this->tabs) {
|
||||||
|
@ -163,16 +163,16 @@ void SettingsDialog::scaleChangedEvent(float newDpi)
|
||||||
QFile file(":/qss/settings.qss");
|
QFile file(":/qss/settings.qss");
|
||||||
file.open(QFile::ReadOnly);
|
file.open(QFile::ReadOnly);
|
||||||
QString styleSheet = QLatin1String(file.readAll());
|
QString styleSheet = QLatin1String(file.readAll());
|
||||||
styleSheet.replace("<font-size>", QString::number((int)(14 * newDpi)));
|
styleSheet.replace("<font-size>", QString::number(int(14 * newDpi)));
|
||||||
styleSheet.replace("<checkbox-size>", QString::number((int)(14 * newDpi)));
|
styleSheet.replace("<checkbox-size>", QString::number(int(14 * newDpi)));
|
||||||
|
|
||||||
for (SettingsDialogTab *tab : this->tabs) {
|
for (SettingsDialogTab *tab : this->tabs) {
|
||||||
tab->setFixedHeight((int)(30 * newDpi));
|
tab->setFixedHeight(int(30 * newDpi));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setStyleSheet(styleSheet);
|
this->setStyleSheet(styleSheet);
|
||||||
|
|
||||||
this->ui_.tabContainerContainer->setFixedWidth((int)(200 * newDpi));
|
this->ui_.tabContainerContainer->setFixedWidth(int(200 * newDpi));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::themeRefreshEvent()
|
void SettingsDialog::themeRefreshEvent()
|
||||||
|
@ -180,32 +180,10 @@ void SettingsDialog::themeRefreshEvent()
|
||||||
BaseWindow::themeRefreshEvent();
|
BaseWindow::themeRefreshEvent();
|
||||||
|
|
||||||
QPalette palette;
|
QPalette palette;
|
||||||
palette.setColor(QPalette::Background, QColor("#444"));
|
palette.setColor(QPalette::Background, QColor("#f44"));
|
||||||
this->setPalette(palette);
|
this->setPalette(palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void SettingsDialog::setChildrensFont(QLayout *object, QFont &font, int indent)
|
|
||||||
//{
|
|
||||||
// // for (QWidget *widget : this->widgets) {
|
|
||||||
// // widget->setFont(font);
|
|
||||||
// // }
|
|
||||||
// // for (int i = 0; i < object->count(); i++) {
|
|
||||||
// // if (object->itemAt(i)->layout()) {
|
|
||||||
// // setChildrensFont(object->layout()->itemAt(i)->layout(), font, indent + 2);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // if (object->itemAt(i)->widget()) {
|
|
||||||
// // object->itemAt(i)->widget()->setFont(font);
|
|
||||||
|
|
||||||
// // if (object->itemAt(i)->widget()->layout() &&
|
|
||||||
// // !object->itemAt(i)->widget()->layout()->isEmpty()) {
|
|
||||||
// // setChildrensFont(object->itemAt(i)->widget()->layout(), font, indent +
|
|
||||||
// 2);
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
//}
|
|
||||||
|
|
||||||
///// Widget creation helpers
|
///// Widget creation helpers
|
||||||
void SettingsDialog::okButtonClicked()
|
void SettingsDialog::okButtonClicked()
|
||||||
{
|
{
|
||||||
|
|
|
@ -364,9 +364,11 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
||||||
}
|
}
|
||||||
a->setBorderColor(color1);
|
a->setBorderColor(color1);
|
||||||
|
|
||||||
QObject::connect(a.getElement(), &RippleEffectLabel2::clicked, [
|
QObject::connect(
|
||||||
this, timeout = std::get<1>(item)
|
a.getElement(), &RippleEffectLabel2::clicked,
|
||||||
] { this->buttonClicked.invoke(std::make_pair(Action::Timeout, timeout)); });
|
[this, timeout = std::get<1>(item)] {
|
||||||
|
this->buttonClicked.invoke(std::make_pair(Action::Timeout, timeout));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -375,16 +377,21 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
||||||
|
|
||||||
addTimeouts("sec", {{"1", 1}});
|
addTimeouts("sec", {{"1", 1}});
|
||||||
addTimeouts("min", {
|
addTimeouts("min", {
|
||||||
{"1", 1 * 60}, {"5", 5 * 60}, {"10", 10 * 60},
|
{"1", 1 * 60},
|
||||||
|
{"5", 5 * 60},
|
||||||
|
{"10", 10 * 60},
|
||||||
});
|
});
|
||||||
addTimeouts("hour", {
|
addTimeouts("hour", {
|
||||||
{"1", 1 * 60 * 60}, {"4", 4 * 60 * 60},
|
{"1", 1 * 60 * 60},
|
||||||
|
{"4", 4 * 60 * 60},
|
||||||
});
|
});
|
||||||
addTimeouts("days", {
|
addTimeouts("days", {
|
||||||
{"1", 1 * 60 * 60 * 24}, {"3", 3 * 60 * 60 * 24},
|
{"1", 1 * 60 * 60 * 24},
|
||||||
|
{"3", 3 * 60 * 60 * 24},
|
||||||
});
|
});
|
||||||
addTimeouts("weeks", {
|
addTimeouts("weeks", {
|
||||||
{"1", 1 * 60 * 60 * 24 * 7}, {"2", 2 * 60 * 60 * 24 * 7},
|
{"1", 1 * 60 * 60 * 24 * 7},
|
||||||
|
{"2", 2 * 60 * 60 * 24 * 7},
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton(Ban, "ban", getApp()->resources->buttons.ban);
|
addButton(Ban, "ban", getApp()->resources->buttons.ban);
|
||||||
|
|
|
@ -238,8 +238,8 @@ void NotebookTab::paintEvent(QPaintEvent *)
|
||||||
// || SettingsDialog::getHandle() == QApplication::activeWindow();
|
// || SettingsDialog::getHandle() == QApplication::activeWindow();
|
||||||
|
|
||||||
QBrush tabBackground = /*this->mouseOver_ ? colors.backgrounds.hover
|
QBrush tabBackground = /*this->mouseOver_ ? colors.backgrounds.hover
|
||||||
:*/ (windowFocused ? colors.backgrounds.regular
|
:*/
|
||||||
: colors.backgrounds.unfocused);
|
(windowFocused ? colors.backgrounds.regular : colors.backgrounds.unfocused);
|
||||||
|
|
||||||
// painter.fillRect(rect(), this->mouseOver_ ? regular.backgrounds.hover
|
// painter.fillRect(rect(), this->mouseOver_ ? regular.backgrounds.hover
|
||||||
// : (windowFocused ? regular.backgrounds.regular
|
// : (windowFocused ? regular.backgrounds.regular
|
||||||
|
|
|
@ -93,8 +93,7 @@ void ResizingTextEdit::keyPressEvent(QKeyEvent *event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *completionModel =
|
auto *completionModel = static_cast<CompletionModel *>(this->completer->model());
|
||||||
static_cast<CompletionModel *>(this->completer->model());
|
|
||||||
|
|
||||||
if (!this->completionInProgress) {
|
if (!this->completionInProgress) {
|
||||||
// First type pressing tab after modifying a message, we refresh our completion model
|
// First type pressing tab after modifying a message, we refresh our completion model
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "singletons/WindowManager.hpp"
|
#include "singletons/WindowManager.hpp"
|
||||||
#include "util/LayoutCreator.hpp"
|
#include "util/LayoutCreator.hpp"
|
||||||
#include "util/RemoveScrollAreaBackground.hpp"
|
#include "util/RemoveScrollAreaBackground.hpp"
|
||||||
|
#include "widgets/helper/Line.hpp"
|
||||||
|
|
||||||
#include <QFontDialog>
|
#include <QFontDialog>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
@ -23,8 +24,6 @@
|
||||||
#define SCROLL_SMOOTH "Enable smooth scrolling"
|
#define SCROLL_SMOOTH "Enable smooth scrolling"
|
||||||
#define SCROLL_NEWMSG "Enable smooth scrolling for new messages"
|
#define SCROLL_NEWMSG "Enable smooth scrolling for new messages"
|
||||||
|
|
||||||
#define LAST_MSG "Mark the last message you read (dotted line)"
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define TIMESTAMP_FORMATS "hh:mm a", "h:mm a", "hh:mm:ss a", "h:mm:ss a", "HH:mm", "H:mm", "HH:mm:ss", "H:mm:ss"
|
#define TIMESTAMP_FORMATS "hh:mm a", "h:mm a", "hh:mm:ss a", "h:mm:ss a", "HH:mm", "H:mm", "HH:mm:ss", "H:mm:ss"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -34,178 +33,206 @@ namespace chatterino {
|
||||||
AppearancePage::AppearancePage()
|
AppearancePage::AppearancePage()
|
||||||
: SettingsPage("Look", ":/images/theme.svg")
|
: SettingsPage("Look", ":/images/theme.svg")
|
||||||
{
|
{
|
||||||
auto app = getApp();
|
|
||||||
LayoutCreator<AppearancePage> layoutCreator(this);
|
LayoutCreator<AppearancePage> layoutCreator(this);
|
||||||
|
|
||||||
auto scroll = layoutCreator.emplace<QScrollArea>();
|
auto xd = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||||
|
|
||||||
|
// settings
|
||||||
|
auto scroll = xd.emplace<QScrollArea>();
|
||||||
auto widget = scroll.emplaceScrollAreaWidget();
|
auto widget = scroll.emplaceScrollAreaWidget();
|
||||||
removeScrollAreaBackground(scroll.getElement(), widget.getElement());
|
removeScrollAreaBackground(scroll.getElement(), widget.getElement());
|
||||||
|
|
||||||
auto layout = widget.setLayoutType<QVBoxLayout>();
|
auto &layout = *widget.setLayoutType<QVBoxLayout>().withoutMargin();
|
||||||
|
|
||||||
auto application =
|
this->addApplicationGroup(layout);
|
||||||
layout.emplace<QGroupBox>("Application").emplace<QVBoxLayout>().withoutMargin();
|
this->addMessagesGroup(layout);
|
||||||
{
|
this->addEmotesGroup(layout);
|
||||||
auto form = application.emplace<QFormLayout>();
|
|
||||||
|
|
||||||
auto *theme = this->createComboBox({THEME_ITEMS}, app->themes->themeName);
|
// preview
|
||||||
QObject::connect(theme, &QComboBox::currentTextChanged,
|
xd.emplace<Line>(false);
|
||||||
[](const QString &) { getApp()->windows->forceLayoutChannelViews(); });
|
|
||||||
|
|
||||||
form->addRow("Theme:", theme);
|
auto channelView = xd.emplace<ChannelView>();
|
||||||
// form->addRow("Theme color:", this->createThemeColorChanger());
|
auto channel = this->createPreviewChannel();
|
||||||
form->addRow("UI Scaling:", this->createUiScaleSlider());
|
channelView->setChannel(channel);
|
||||||
form->addRow("Font:", this->createFontChanger());
|
channelView->setScaleIndependantHeight(64);
|
||||||
|
|
||||||
form->addRow("Tabs:", this->createCheckBox(TAB_X, app->settings->showTabCloseButton));
|
layout.addStretch(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppearancePage::addApplicationGroup(QVBoxLayout &layout)
|
||||||
|
{
|
||||||
|
auto box = LayoutCreator<QVBoxLayout>(&layout)
|
||||||
|
.emplace<QGroupBox>("Application")
|
||||||
|
.emplace<QVBoxLayout>()
|
||||||
|
.withoutMargin();
|
||||||
|
|
||||||
|
auto form = box.emplace<QFormLayout>();
|
||||||
|
|
||||||
|
// theme
|
||||||
|
auto *theme = this->createComboBox({THEME_ITEMS}, getApp()->themes->themeName);
|
||||||
|
QObject::connect(theme, &QComboBox::currentTextChanged,
|
||||||
|
[](const QString &) { getApp()->windows->forceLayoutChannelViews(); });
|
||||||
|
|
||||||
|
form->addRow("Theme:", theme);
|
||||||
|
|
||||||
|
// ui scale
|
||||||
|
form->addRow("UI Scaling:", this->createUiScaleSlider());
|
||||||
|
|
||||||
|
// font
|
||||||
|
form->addRow("Font:", this->createFontChanger());
|
||||||
|
|
||||||
|
// tab x
|
||||||
|
form->addRow("Tabs:", this->createCheckBox(TAB_X, getSettings()->showTabCloseButton));
|
||||||
|
|
||||||
|
// show buttons
|
||||||
#ifndef USEWINSDK
|
#ifndef USEWINSDK
|
||||||
form->addRow("", this->createCheckBox(TAB_PREF, app->settings->hidePreferencesButton));
|
form->addRow("", this->createCheckBox(TAB_PREF, app->settings->hidePreferencesButton));
|
||||||
form->addRow("", this->createCheckBox(TAB_USER, app->settings->hideUserButton));
|
form->addRow("", this->createCheckBox(TAB_USER, app->settings->hideUserButton));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
form->addRow("Scrolling:",
|
// scrolling
|
||||||
this->createCheckBox(SCROLL_SMOOTH, app->settings->enableSmoothScrolling));
|
form->addRow("Scrolling:",
|
||||||
form->addRow("", this->createCheckBox(SCROLL_NEWMSG,
|
this->createCheckBox(SCROLL_SMOOTH, getSettings()->enableSmoothScrolling));
|
||||||
app->settings->enableSmoothScrollingNewMessages));
|
form->addRow(
|
||||||
}
|
"", this->createCheckBox(SCROLL_NEWMSG, getSettings()->enableSmoothScrollingNewMessages));
|
||||||
|
}
|
||||||
|
|
||||||
auto messages = layout.emplace<QGroupBox>("Messages").emplace<QVBoxLayout>();
|
void AppearancePage::addMessagesGroup(QVBoxLayout &layout)
|
||||||
|
{
|
||||||
|
auto box =
|
||||||
|
LayoutCreator<QVBoxLayout>(&layout).emplace<QGroupBox>("Messages").emplace<QVBoxLayout>();
|
||||||
|
|
||||||
|
// timestamps
|
||||||
|
box.append(this->createCheckBox("Show timestamps", getSettings()->showTimestamps));
|
||||||
|
auto tbox = box.emplace<QHBoxLayout>().withoutMargin();
|
||||||
{
|
{
|
||||||
messages.append(this->createCheckBox("Show timestamp", app->settings->showTimestamps));
|
tbox.emplace<QLabel>("Timestamp format (a = am/pm):");
|
||||||
auto tbox = messages.emplace<QHBoxLayout>().withoutMargin();
|
tbox.append(this->createComboBox({TIMESTAMP_FORMATS}, getSettings()->timestampFormat));
|
||||||
{
|
tbox->addStretch(1);
|
||||||
tbox.emplace<QLabel>("timestamp format (a = am/pm):");
|
|
||||||
tbox.append(this->createComboBox({TIMESTAMP_FORMATS}, app->settings->timestampFormat));
|
|
||||||
tbox->addStretch(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
messages.append(this->createCheckBox("Show badges", app->settings->showBadges));
|
|
||||||
|
|
||||||
{
|
|
||||||
auto *combo = new QComboBox(this);
|
|
||||||
combo->addItems({"Never", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
|
|
||||||
"13", "14", "15"});
|
|
||||||
const auto currentIndex = []() -> int {
|
|
||||||
auto val = getApp()->settings->collpseMessagesMinLines.getValue();
|
|
||||||
if (val > 0) {
|
|
||||||
--val;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}();
|
|
||||||
combo->setCurrentIndex(currentIndex);
|
|
||||||
|
|
||||||
QObject::connect(combo, &QComboBox::currentTextChanged, [](const QString &str) {
|
|
||||||
getApp()->settings->collpseMessagesMinLines = str.toInt();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto hbox = messages.emplace<QHBoxLayout>().withoutMargin();
|
|
||||||
hbox.emplace<QLabel>("Collapse messages longer than");
|
|
||||||
hbox.append(combo);
|
|
||||||
hbox.emplace<QLabel>("lines");
|
|
||||||
}
|
|
||||||
|
|
||||||
messages.append(this->createCheckBox("Separate messages", app->settings->separateMessages));
|
|
||||||
messages.append(this->createCheckBox("Alternate message background color",
|
|
||||||
app->settings->alternateMessageBackground));
|
|
||||||
messages.append(this->createCheckBox("Show message length while typing",
|
|
||||||
app->settings->showMessageLength));
|
|
||||||
|
|
||||||
messages.append(this->createCheckBox(LAST_MSG, app->settings->showLastMessageIndicator));
|
|
||||||
{
|
|
||||||
auto *combo = new QComboBox(this);
|
|
||||||
combo->addItems({"Dotted", "Solid"});
|
|
||||||
|
|
||||||
const auto currentIndex = []() -> int {
|
|
||||||
switch (getApp()->settings->lastMessagePattern.getValue()) {
|
|
||||||
case Qt::SolidLine: {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
case Qt::VerPattern: {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
combo->setCurrentIndex(currentIndex);
|
|
||||||
|
|
||||||
QObject::connect(combo,
|
|
||||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
||||||
[](int index) {
|
|
||||||
Qt::BrushStyle brush;
|
|
||||||
switch (index) {
|
|
||||||
case 1:
|
|
||||||
brush = Qt::SolidPattern;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case 0:
|
|
||||||
brush = Qt::VerPattern;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
getApp()->settings->lastMessagePattern = brush;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto hbox = messages.emplace<QHBoxLayout>().withoutMargin();
|
|
||||||
hbox.emplace<QLabel>("Last message indicator pattern");
|
|
||||||
hbox.append(combo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto emotes = layout.emplace<QGroupBox>("Emotes").setLayoutType<QVBoxLayout>();
|
// badges
|
||||||
|
box.append(this->createCheckBox("Show badges", getSettings()->showBadges));
|
||||||
|
|
||||||
|
// collapsing
|
||||||
{
|
{
|
||||||
/*
|
auto *combo = new QComboBox(this);
|
||||||
emotes.append(
|
combo->addItems(
|
||||||
this->createCheckBox("Enable Twitch emotes", app->settings->enableTwitchEmotes));
|
{"Never", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"});
|
||||||
emotes.append(this->createCheckBox("Enable BetterTTV emotes for Twitch",
|
|
||||||
app->settings->enableBttvEmotes));
|
|
||||||
emotes.append(this->createCheckBox("Enable FrankerFaceZ emotes for Twitch",
|
|
||||||
app->settings->enableFfzEmotes));
|
|
||||||
emotes.append(this->createCheckBox("Enable emojis", app->settings->enableEmojis));
|
|
||||||
*/
|
|
||||||
emotes.append(
|
|
||||||
this->createCheckBox("Enable animations", app->settings->enableGifAnimations));
|
|
||||||
|
|
||||||
auto scaleBox = emotes.emplace<QHBoxLayout>();
|
const auto currentIndex = []() -> int {
|
||||||
{
|
auto val = getSettings()->collpseMessagesMinLines.getValue();
|
||||||
scaleBox.emplace<QLabel>("Emote scale:");
|
if (val > 0) {
|
||||||
|
--val;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}();
|
||||||
|
combo->setCurrentIndex(currentIndex);
|
||||||
|
|
||||||
auto emoteScale = scaleBox.emplace<QSlider>(Qt::Horizontal);
|
QObject::connect(combo, &QComboBox::currentTextChanged, [](const QString &str) {
|
||||||
emoteScale->setMinimum(5);
|
getSettings()->collpseMessagesMinLines = str.toInt();
|
||||||
emoteScale->setMaximum(50);
|
});
|
||||||
|
|
||||||
auto scaleLabel = scaleBox.emplace<QLabel>("1.0");
|
auto hbox = box.emplace<QHBoxLayout>().withoutMargin();
|
||||||
scaleLabel->setFixedWidth(100);
|
hbox.emplace<QLabel>("Collapse messages longer than");
|
||||||
QObject::connect(emoteScale.getElement(), &QSlider::valueChanged,
|
hbox.append(combo);
|
||||||
[scaleLabel](int value) mutable {
|
hbox.emplace<QLabel>("lines");
|
||||||
float f = (float)value / 10.f;
|
|
||||||
scaleLabel->setText(QString::number(f));
|
|
||||||
|
|
||||||
getApp()->settings->emoteScale.setValue(f);
|
|
||||||
});
|
|
||||||
|
|
||||||
emoteScale->setValue(std::max<int>(
|
|
||||||
5, std::min<int>(50, (int)(app->settings->emoteScale.getValue() * 10.f))));
|
|
||||||
|
|
||||||
scaleLabel->setText(QString::number(app->settings->emoteScale.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto *combo = new QComboBox(this);
|
|
||||||
combo->addItems({"EmojiOne 2", "EmojiOne 3", "Twitter", "Facebook", "Apple", "Google",
|
|
||||||
"Messenger"});
|
|
||||||
|
|
||||||
combo->setCurrentText(getApp()->settings->emojiSet);
|
|
||||||
|
|
||||||
QObject::connect(combo, &QComboBox::currentTextChanged, [](const QString &str) {
|
|
||||||
getApp()->settings->emojiSet = str; //
|
|
||||||
});
|
|
||||||
|
|
||||||
auto hbox = emotes.emplace<QHBoxLayout>().withoutMargin();
|
|
||||||
hbox.emplace<QLabel>("Emoji set");
|
|
||||||
hbox.append(combo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layout->addStretch(1);
|
// seperate
|
||||||
|
box.append(this->createCheckBox("Separation lines", getSettings()->separateMessages));
|
||||||
|
|
||||||
|
// alternate
|
||||||
|
box.append(this->createCheckBox("Alternate background colors",
|
||||||
|
getSettings()->alternateMessageBackground));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppearancePage::addEmotesGroup(QVBoxLayout &layout)
|
||||||
|
{
|
||||||
|
auto box = LayoutCreator<QVBoxLayout>(&layout)
|
||||||
|
.emplace<QGroupBox>("Emotes")
|
||||||
|
.setLayoutType<QVBoxLayout>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
emotes.append(
|
||||||
|
this->createCheckBox("Enable Twitch emotes", app->settings->enableTwitchEmotes));
|
||||||
|
emotes.append(this->createCheckBox("Enable BetterTTV emotes for Twitch",
|
||||||
|
app->settings->enableBttvEmotes));
|
||||||
|
emotes.append(this->createCheckBox("Enable FrankerFaceZ emotes for Twitch",
|
||||||
|
app->settings->enableFfzEmotes));
|
||||||
|
emotes.append(this->createCheckBox("Enable emojis", app->settings->enableEmojis));
|
||||||
|
*/
|
||||||
|
box.append(this->createCheckBox("Animated emotes", getSettings()->enableGifAnimations));
|
||||||
|
|
||||||
|
auto scaleBox = box.emplace<QHBoxLayout>();
|
||||||
|
{
|
||||||
|
scaleBox.emplace<QLabel>("Size:");
|
||||||
|
|
||||||
|
auto emoteScale = scaleBox.emplace<QSlider>(Qt::Horizontal);
|
||||||
|
emoteScale->setMinimum(5);
|
||||||
|
emoteScale->setMaximum(50);
|
||||||
|
|
||||||
|
auto scaleLabel = scaleBox.emplace<QLabel>("1.0");
|
||||||
|
scaleLabel->setFixedWidth(100);
|
||||||
|
QObject::connect(emoteScale.getElement(), &QSlider::valueChanged,
|
||||||
|
[scaleLabel](int value) mutable {
|
||||||
|
float f = float(value) / 10.f;
|
||||||
|
scaleLabel->setText(QString::number(f));
|
||||||
|
|
||||||
|
getSettings()->emoteScale.setValue(f);
|
||||||
|
});
|
||||||
|
|
||||||
|
emoteScale->setValue(
|
||||||
|
std::max<int>(5, std::min<int>(50, int(getSettings()->emoteScale.getValue() * 10.f))));
|
||||||
|
|
||||||
|
scaleLabel->setText(QString::number(getSettings()->emoteScale.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *combo = new QComboBox(this);
|
||||||
|
combo->addItems(
|
||||||
|
{"EmojiOne 2", "EmojiOne 3", "Twitter", "Facebook", "Apple", "Google", "Messenger"});
|
||||||
|
|
||||||
|
combo->setCurrentText(getSettings()->emojiSet);
|
||||||
|
|
||||||
|
QObject::connect(combo, &QComboBox::currentTextChanged, [](const QString &str) {
|
||||||
|
getSettings()->emojiSet = str; //
|
||||||
|
});
|
||||||
|
|
||||||
|
auto hbox = box.emplace<QHBoxLayout>().withoutMargin();
|
||||||
|
hbox.emplace<QLabel>("Emoji set:");
|
||||||
|
hbox.append(combo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelPtr AppearancePage::createPreviewChannel()
|
||||||
|
{
|
||||||
|
auto channel = ChannelPtr(new Channel("preview", Channel::Misc));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto message = MessagePtr(new Message());
|
||||||
|
message->addElement(new ImageElement(getApp()->resources->badgeModerator,
|
||||||
|
MessageElement::BadgeChannelAuthority));
|
||||||
|
message->addElement(new ImageElement(getApp()->resources->badgeSubscriber,
|
||||||
|
MessageElement::BadgeSubscription));
|
||||||
|
message->addElement(new TimestampElement());
|
||||||
|
message->addElement(new TextElement("username1:", MessageElement::Username,
|
||||||
|
QColor("#0094FF"), FontStyle::ChatMediumBold));
|
||||||
|
message->addElement(new TextElement("This is a preview message :)", MessageElement::Text));
|
||||||
|
channel->addMessage(message);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto message = MessagePtr(new Message());
|
||||||
|
message->addElement(new ImageElement(getApp()->resources->badgePremium,
|
||||||
|
MessageElement::BadgeChannelAuthority));
|
||||||
|
message->addElement(new TimestampElement());
|
||||||
|
message->addElement(new TextElement("username2:", MessageElement::Username,
|
||||||
|
QColor("#FF6A00"), FontStyle::ChatMediumBold));
|
||||||
|
message->addElement(new TextElement("This is another one :)", MessageElement::Text));
|
||||||
|
channel->addMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLayout *AppearancePage::createThemeColorChanger()
|
QLayout *AppearancePage::createThemeColorChanger()
|
||||||
|
@ -297,18 +324,15 @@ QLayout *AppearancePage::createUiScaleSlider()
|
||||||
|
|
||||||
slider->setMinimum(WindowManager::uiScaleMin);
|
slider->setMinimum(WindowManager::uiScaleMin);
|
||||||
slider->setMaximum(WindowManager::uiScaleMax);
|
slider->setMaximum(WindowManager::uiScaleMax);
|
||||||
slider->setValue(
|
slider->setValue(WindowManager::clampUiScale(getSettings()->uiScale.getValue()));
|
||||||
WindowManager::clampUiScale(getApp()->settings->uiScale.getValue()));
|
|
||||||
|
|
||||||
label->setMinimumWidth(100);
|
label->setMinimumWidth(100);
|
||||||
|
|
||||||
QObject::connect(slider, &QSlider::valueChanged,
|
QObject::connect(slider, &QSlider::valueChanged,
|
||||||
[](auto value) { getApp()->settings->uiScale.setValue(value); });
|
[](auto value) { getSettings()->uiScale.setValue(value); });
|
||||||
|
|
||||||
getApp()->settings->uiScale.connect(
|
getSettings()->uiScale.connect(
|
||||||
[label](auto, auto) {
|
[label](auto, auto) { label->setText(QString::number(WindowManager::getUiScaleValue())); },
|
||||||
label->setText(QString::number(WindowManager::getUiScaleValue()));
|
|
||||||
},
|
|
||||||
this->connections_);
|
this->connections_);
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Channel.hpp"
|
||||||
#include "widgets/settingspages/SettingsPage.hpp"
|
#include "widgets/settingspages/SettingsPage.hpp"
|
||||||
|
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <pajlada/signals/signalholder.hpp>
|
#include <pajlada/signals/signalholder.hpp>
|
||||||
|
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class AppearancePage : public SettingsPage
|
class AppearancePage : public SettingsPage
|
||||||
|
@ -12,10 +15,16 @@ class AppearancePage : public SettingsPage
|
||||||
public:
|
public:
|
||||||
AppearancePage();
|
AppearancePage();
|
||||||
|
|
||||||
|
void addApplicationGroup(QVBoxLayout &layout);
|
||||||
|
void addMessagesGroup(QVBoxLayout &layout);
|
||||||
|
void addEmotesGroup(QVBoxLayout &layout);
|
||||||
|
|
||||||
QLayout *createThemeColorChanger();
|
QLayout *createThemeColorChanger();
|
||||||
QLayout *createFontChanger();
|
QLayout *createFontChanger();
|
||||||
QLayout *createUiScaleSlider();
|
QLayout *createUiScaleSlider();
|
||||||
|
|
||||||
|
ChannelPtr createPreviewChannel();
|
||||||
|
|
||||||
std::vector<pajlada::Signals::ScopedConnection> connections_;
|
std::vector<pajlada::Signals::ScopedConnection> connections_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#endif
|
#endif
|
||||||
#define INPUT_EMPTY "Hide input box when empty"
|
#define INPUT_EMPTY "Hide input box when empty"
|
||||||
#define PAUSE_HOVERING "When hovering"
|
#define PAUSE_HOVERING "When hovering"
|
||||||
|
#define LAST_MSG "Mark the last message you read (dotted line)"
|
||||||
|
|
||||||
#define LIMIT_CHATTERS_FOR_SMALLER_STREAMERS "Only fetch chatters list for viewers under X viewers"
|
#define LIMIT_CHATTERS_FOR_SMALLER_STREAMERS "Only fetch chatters list for viewers under X viewers"
|
||||||
|
|
||||||
|
@ -38,6 +39,48 @@ BehaviourPage::BehaviourPage()
|
||||||
form->addRow(
|
form->addRow(
|
||||||
"", this->createCheckBox("Show which users parted the channel (up to 1000 chatters)",
|
"", this->createCheckBox("Show which users parted the channel (up to 1000 chatters)",
|
||||||
app->settings->showParts));
|
app->settings->showParts));
|
||||||
|
|
||||||
|
form->addRow("", this->createCheckBox("Show message length while typing",
|
||||||
|
getSettings()->showMessageLength));
|
||||||
|
form->addRow("", this->createCheckBox(LAST_MSG, getSettings()->showLastMessageIndicator));
|
||||||
|
{
|
||||||
|
auto *combo = new QComboBox(this);
|
||||||
|
combo->addItems({"Dotted", "Solid"});
|
||||||
|
|
||||||
|
const auto currentIndex = []() -> int {
|
||||||
|
switch (getApp()->settings->lastMessagePattern.getValue()) {
|
||||||
|
case Qt::SolidLine: {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
case Qt::VerPattern: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
combo->setCurrentIndex(currentIndex);
|
||||||
|
|
||||||
|
QObject::connect(combo,
|
||||||
|
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
[](int index) {
|
||||||
|
Qt::BrushStyle brush;
|
||||||
|
switch (index) {
|
||||||
|
case 1:
|
||||||
|
brush = Qt::SolidPattern;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
brush = Qt::VerPattern;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
getSettings()->lastMessagePattern = brush;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto hbox = form.emplace<QHBoxLayout>().withoutMargin();
|
||||||
|
hbox.emplace<QLabel>("Last message indicator pattern");
|
||||||
|
hbox.append(combo);
|
||||||
|
}
|
||||||
|
|
||||||
form->addRow("Pause chat:",
|
form->addRow("Pause chat:",
|
||||||
this->createCheckBox(PAUSE_HOVERING, app->settings->pauseChatHover));
|
this->createCheckBox(PAUSE_HOVERING, app->settings->pauseChatHover));
|
||||||
|
|
||||||
|
@ -76,7 +119,7 @@ QSlider *BehaviourPage::createMouseScrollSlider()
|
||||||
auto slider = new QSlider(Qt::Horizontal);
|
auto slider = new QSlider(Qt::Horizontal);
|
||||||
|
|
||||||
float currentValue = app->settings->mouseScrollMultiplier;
|
float currentValue = app->settings->mouseScrollMultiplier;
|
||||||
int sliderValue = ((currentValue - 0.1f) / 2.f) * 99.f;
|
int sliderValue = int(((currentValue - 0.1f) / 2.f) * 99.f);
|
||||||
slider->setValue(sliderValue);
|
slider->setValue(sliderValue);
|
||||||
|
|
||||||
QObject::connect(slider, &QSlider::valueChanged, [=](int newValue) {
|
QObject::connect(slider, &QSlider::valueChanged, [=](int newValue) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "ModerationPage.hpp"
|
#include "ModerationPage.hpp"
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
|
#include "controllers/moderationactions/ModerationActionModel.hpp"
|
||||||
|
#include "controllers/moderationactions/ModerationActions.hpp"
|
||||||
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
||||||
#include "controllers/taggedusers/TaggedUsersModel.hpp"
|
#include "controllers/taggedusers/TaggedUsersModel.hpp"
|
||||||
#include "singletons/Logging.hpp"
|
#include "singletons/Logging.hpp"
|
||||||
|
@ -8,6 +10,7 @@
|
||||||
#include "util/LayoutCreator.hpp"
|
#include "util/LayoutCreator.hpp"
|
||||||
#include "widgets/helper/EditableModelView.hpp"
|
#include "widgets/helper/EditableModelView.hpp"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
@ -82,7 +85,7 @@ ModerationPage::ModerationPage()
|
||||||
// Logs end
|
// Logs end
|
||||||
}
|
}
|
||||||
|
|
||||||
auto modMode = tabs.appendTab(new QVBoxLayout, "Moderation mode");
|
auto modMode = tabs.appendTab(new QVBoxLayout, "Moderation buttons");
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
auto label = modMode.emplace<QLabel>("Click the moderation mod button (<img width='18' height='18' src=':/images/moderatormode_disabled.png'>) in a channel that you moderate to enable moderator mode.<br>");
|
auto label = modMode.emplace<QLabel>("Click the moderation mod button (<img width='18' height='18' src=':/images/moderatormode_disabled.png'>) in a channel that you moderate to enable moderator mode.<br>");
|
||||||
|
@ -97,26 +100,17 @@ ModerationPage::ModerationPage()
|
||||||
// app->settings->timeoutAction));
|
// app->settings->timeoutAction));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// auto modButtons =
|
EditableModelView *view =
|
||||||
// modMode.emplace<QGroupBox>("Custom moderator buttons").setLayoutType<QVBoxLayout>();
|
modMode.emplace<EditableModelView>(app->moderationActions->createModel(nullptr))
|
||||||
// {
|
.getElement();
|
||||||
// auto label2 =
|
|
||||||
// modButtons.emplace<QLabel>("One action per line. {user} will be replaced with the
|
|
||||||
// "
|
|
||||||
// "username.<br>Example `/timeout {user} 120`<br>");
|
|
||||||
// label2->setWordWrap(true);
|
|
||||||
|
|
||||||
// auto text = modButtons.emplace<QTextEdit>().getElement();
|
view->setTitles({"Actions"});
|
||||||
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||||
|
view->getTableView()->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
|
|
||||||
// text->setPlainText(app->moderationActions->items);
|
view->addButtonPressed.connect([] {
|
||||||
|
getApp()->moderationActions->items.appendItem(ModerationAction("/timeout {user} 300"));
|
||||||
// QObject::connect(text, &QTextEdit::textChanged, this,
|
});
|
||||||
// [this] { this->itemsChangedTimer.start(200); });
|
|
||||||
|
|
||||||
// QObject::connect(&this->itemsChangedTimer, &QTimer::timeout, this, [text, app]() {
|
|
||||||
// app->windows->moderationActions = text->toPlainText();
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*auto taggedUsers = tabs.appendTab(new QVBoxLayout, "Tagged users");
|
/*auto taggedUsers = tabs.appendTab(new QVBoxLayout, "Tagged users");
|
||||||
{
|
{
|
||||||
|
|
|
@ -581,8 +581,7 @@ void SplitContainer::decodeNodeRecusively(QJsonObject &obj, Node *node)
|
||||||
auto _type = _obj.value("type");
|
auto _type = _obj.value("type");
|
||||||
if (_type == "split") {
|
if (_type == "split") {
|
||||||
auto *split = new Split(this);
|
auto *split = new Split(this);
|
||||||
split->setChannel(
|
split->setChannel(WindowManager::decodeChannel(_obj.value("data").toObject()));
|
||||||
WindowManager::decodeChannel(_obj.value("data").toObject()));
|
|
||||||
|
|
||||||
Node *_node = new Node();
|
Node *_node = new Node();
|
||||||
_node->parent = node;
|
_node->parent = node;
|
||||||
|
@ -605,8 +604,7 @@ void SplitContainer::decodeNodeRecusively(QJsonObject &obj, Node *node)
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
if (node->getChildren().size() < 2) {
|
if (node->getChildren().size() < 2) {
|
||||||
auto *split = new Split(this);
|
auto *split = new Split(this);
|
||||||
split->setChannel(
|
split->setChannel(WindowManager::decodeChannel(obj.value("data").toObject()));
|
||||||
WindowManager::decodeChannel(obj.value("data").toObject()));
|
|
||||||
|
|
||||||
this->insertSplit(split, direction, node);
|
this->insertSplit(split, direction, node);
|
||||||
}
|
}
|
||||||
|
|
7
tools/clang-format-all.sh
Executable file
7
tools/clang-format-all.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
read -p "Are you sure you want to run clang-format on all files in src/? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
find src/ -iname "*.hpp" -o -iname "*.cpp" -exec clang-format -i {} \;
|
||||||
|
fi
|
Loading…
Reference in a new issue