mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
added new TupleTableModel for settingsdialog
This commit is contained in:
parent
1edcfe5219
commit
859f4aefcb
18 changed files with 574 additions and 236 deletions
|
@ -9,19 +9,18 @@ const ignoredPages = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const appName = "com.chatterino.chatterino";
|
const appName = "com.chatterino.chatterino";
|
||||||
|
|
||||||
/// Connect to port
|
|
||||||
|
|
||||||
let port = null;
|
let port = null;
|
||||||
|
|
||||||
|
|
||||||
|
/// Connect to port
|
||||||
function connectPort() {
|
function connectPort() {
|
||||||
port = chrome.runtime.connectNative("com.chatterino.chatterino");
|
port = chrome.runtime.connectNative("com.chatterino.chatterino");
|
||||||
console.log("port connected");
|
console.log("port connected");
|
||||||
|
|
||||||
port.onMessage.addListener(function(msg) {
|
port.onMessage.addListener(function (msg) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
});
|
});
|
||||||
port.onDisconnect.addListener(function() {
|
port.onDisconnect.addListener(function () {
|
||||||
console.log("port disconnected");
|
console.log("port disconnected");
|
||||||
|
|
||||||
port = null;
|
port = null;
|
||||||
|
@ -39,8 +38,8 @@ function getPort() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tab listeners
|
|
||||||
|
|
||||||
|
/// Tab listeners
|
||||||
chrome.tabs.onActivated.addListener((activeInfo) => {
|
chrome.tabs.onActivated.addListener((activeInfo) => {
|
||||||
chrome.tabs.get(activeInfo.tabId, (tab) => {
|
chrome.tabs.get(activeInfo.tabId, (tab) => {
|
||||||
if (!tab)
|
if (!tab)
|
||||||
|
@ -49,7 +48,7 @@ chrome.tabs.onActivated.addListener((activeInfo) => {
|
||||||
if (!tab.url)
|
if (!tab.url)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
matchUrl(tab.url);
|
matchUrl(tab.url, tab);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -57,32 +56,47 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||||
if (!tab.highlighted)
|
if (!tab.highlighted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
matchUrl(changeInfo.url);
|
matchUrl(changeInfo.url, tab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/// Misc
|
/// Misc
|
||||||
|
function matchUrl(url, tab) {
|
||||||
function matchUrl(url) {
|
|
||||||
if (!url)
|
if (!url)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const match = url.match(/^https?:\/\/(www\.)?twitch.tv\/([a-zA-Z0-9]+)\/?$/);
|
const match = url.match(/^https?:\/\/(www\.)?twitch.tv\/([a-zA-Z0-9]+)\/?$/);
|
||||||
|
|
||||||
if (match) {
|
let channelName;
|
||||||
const channelName = match[2];
|
|
||||||
|
|
||||||
if (!ignoredPages[channelName]) {
|
console.log(tab);
|
||||||
selectChannel(channelName);
|
|
||||||
|
if (match && (channelName = match[2], !ignoredPages[channelName])) {
|
||||||
|
console.log("channelName " + channelName);
|
||||||
|
console.log("winId " + tab.windowId);
|
||||||
|
|
||||||
|
chrome.windows.get(tab.windowId, {}, (window) => {
|
||||||
|
let yOffset = window.height - tab.height;
|
||||||
|
|
||||||
|
let port = getPort();
|
||||||
|
if (port) {
|
||||||
|
port.postMessage({
|
||||||
|
action: "select",
|
||||||
|
attach: true,
|
||||||
|
type: "twitch",
|
||||||
|
name: channelName,
|
||||||
|
winId: "" + tab.windowId,
|
||||||
|
yOffset: yOffset
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let port = getPort();
|
||||||
|
if (port) {
|
||||||
|
port.postMessage({
|
||||||
|
action: "detach",
|
||||||
|
winId: "" + tab.windowId
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectChannel(channelName) {
|
|
||||||
console.log("select" + channelName);
|
|
||||||
|
|
||||||
let port = getPort();
|
|
||||||
if (port) {
|
|
||||||
port.postMessage({action: "select", type: "twitch", name: channelName});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -181,7 +181,9 @@ SOURCES += \
|
||||||
src/singletons/helper/pubsubactions.cpp \
|
src/singletons/helper/pubsubactions.cpp \
|
||||||
src/widgets/selectchanneldialog.cpp \
|
src/widgets/selectchanneldialog.cpp \
|
||||||
src/singletons/updatemanager.cpp \
|
src/singletons/updatemanager.cpp \
|
||||||
src/widgets/lastruncrashdialog.cpp
|
src/widgets/lastruncrashdialog.cpp \
|
||||||
|
src/widgets/attachedwindow.cpp \
|
||||||
|
src/util/tupletablemodel.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/precompiled_header.hpp \
|
src/precompiled_header.hpp \
|
||||||
|
@ -305,7 +307,9 @@ HEADERS += \
|
||||||
src/singletons/helper/pubsubactions.hpp \
|
src/singletons/helper/pubsubactions.hpp \
|
||||||
src/widgets/selectchanneldialog.hpp \
|
src/widgets/selectchanneldialog.hpp \
|
||||||
src/singletons/updatemanager.hpp \
|
src/singletons/updatemanager.hpp \
|
||||||
src/widgets/lastruncrashdialog.hpp
|
src/widgets/lastruncrashdialog.hpp \
|
||||||
|
src/widgets/attachedwindow.hpp \
|
||||||
|
src/util/tupletablemodel.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources/resources.qrc
|
resources/resources.qrc
|
||||||
|
@ -359,10 +363,6 @@ win32-msvc* {
|
||||||
|
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
win32::exists(C:\fourtf) {
|
|
||||||
DEFINES += "OHHEYITSFOURTF"
|
|
||||||
}
|
|
||||||
|
|
||||||
linux {
|
linux {
|
||||||
QMAKE_LFLAGS += -lrt
|
QMAKE_LFLAGS += -lrt
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,14 @@ namespace messages {
|
||||||
|
|
||||||
struct HighlightPhrase {
|
struct HighlightPhrase {
|
||||||
QString key;
|
QString key;
|
||||||
bool sound;
|
|
||||||
bool alert;
|
bool alert;
|
||||||
|
bool sound;
|
||||||
|
bool regex;
|
||||||
|
|
||||||
bool operator==(const HighlightPhrase &rhs) const
|
bool operator==(const HighlightPhrase &other) const
|
||||||
{
|
{
|
||||||
return std::tie(this->key, this->sound, this->alert) ==
|
return std::tie(this->key, this->sound, this->alert, this->regex) ==
|
||||||
std::tie(rhs.key, rhs.sound, rhs.alert);
|
std::tie(other.key, other.sound, other.alert, other.regex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace messages
|
} // namespace messages
|
||||||
|
@ -35,6 +36,7 @@ struct Serialize<chatterino::messages::HighlightPhrase> {
|
||||||
AddMember(ret, "key", value.key, a);
|
AddMember(ret, "key", value.key, a);
|
||||||
AddMember(ret, "alert", value.alert, a);
|
AddMember(ret, "alert", value.alert, a);
|
||||||
AddMember(ret, "sound", value.sound, a);
|
AddMember(ret, "sound", value.sound, a);
|
||||||
|
AddMember(ret, "regex", value.regex, a);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +72,13 @@ struct Deserialize<chatterino::messages::HighlightPhrase> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value.HasMember("regex")) {
|
||||||
|
const rapidjson::Value ®ex = value["regex"];
|
||||||
|
if (regex.IsBool()) {
|
||||||
|
ret.regex = regex.GetBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -198,7 +198,7 @@ void MessageLayout::updateBuffer(QPixmap *buffer, int messageIndex, Selection &s
|
||||||
// draw message
|
// draw message
|
||||||
this->container.paintElements(painter);
|
this->container.paintElements(painter);
|
||||||
|
|
||||||
#ifdef OHHEYITSFOURTF
|
#ifdef FOURTF
|
||||||
// debug
|
// debug
|
||||||
painter.setPen(QColor(255, 0, 0));
|
painter.setPen(QColor(255, 0, 0));
|
||||||
painter.drawRect(buffer->rect().x(), buffer->rect().y(), buffer->rect().width() - 1,
|
painter.drawRect(buffer->rect().x(), buffer->rect().y(), buffer->rect().width() - 1,
|
||||||
|
|
|
@ -191,7 +191,7 @@ MessageLayoutElement *MessageLayoutContainer::getElementAt(QPoint point)
|
||||||
void MessageLayoutContainer::paintElements(QPainter &painter)
|
void MessageLayoutContainer::paintElements(QPainter &painter)
|
||||||
{
|
{
|
||||||
for (const std::unique_ptr<MessageLayoutElement> &element : this->elements) {
|
for (const std::unique_ptr<MessageLayoutElement> &element : this->elements) {
|
||||||
#ifdef OHHEYITSFOURTF
|
#ifdef FOURTF
|
||||||
painter.setPen(QColor(0, 255, 0));
|
painter.setPen(QColor(0, 255, 0));
|
||||||
painter.drawRect(element->getRect());
|
painter.drawRect(element->getRect());
|
||||||
#endif
|
#endif
|
||||||
|
@ -214,12 +214,14 @@ void MessageLayoutContainer::paintSelection(QPainter &painter, int messageIndex,
|
||||||
QColor selectionColor = themeManager.messages.selection;
|
QColor selectionColor = themeManager.messages.selection;
|
||||||
|
|
||||||
// don't draw anything
|
// don't draw anything
|
||||||
if (selection.selectionMin.messageIndex > messageIndex || selection.selectionMax.messageIndex < messageIndex) {
|
if (selection.selectionMin.messageIndex > messageIndex ||
|
||||||
|
selection.selectionMax.messageIndex < messageIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fully selected
|
// fully selected
|
||||||
if (selection.selectionMin.messageIndex < messageIndex && selection.selectionMax.messageIndex > messageIndex) {
|
if (selection.selectionMin.messageIndex < messageIndex &&
|
||||||
|
selection.selectionMax.messageIndex > messageIndex) {
|
||||||
for (Line &line : this->lines) {
|
for (Line &line : this->lines) {
|
||||||
QRect rect = line.rect;
|
QRect rect = line.rect;
|
||||||
|
|
||||||
|
@ -267,8 +269,8 @@ void MessageLayoutContainer::paintSelection(QPainter &painter, int messageIndex,
|
||||||
int c = this->elements[i]->getSelectionIndexCount();
|
int c = this->elements[i]->getSelectionIndexCount();
|
||||||
|
|
||||||
if (index + c > selection.selectionMax.charIndex) {
|
if (index + c > selection.selectionMax.charIndex) {
|
||||||
r = this->elements[i]->getXFromIndex(selection.selectionMax.charIndex -
|
r = this->elements[i]->getXFromIndex(
|
||||||
index);
|
selection.selectionMax.charIndex - index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index += c;
|
index += c;
|
||||||
|
|
|
@ -16,6 +16,10 @@ namespace ipc = boost::interprocess;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "singletons/windowmanager.hpp"
|
||||||
|
#include "widgets/attachedwindow.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -56,9 +60,14 @@ void NativeMessagingManager::registerHost()
|
||||||
root_obj.insert("path", QCoreApplication::applicationFilePath());
|
root_obj.insert("path", QCoreApplication::applicationFilePath());
|
||||||
root_obj.insert("type", "stdio");
|
root_obj.insert("type", "stdio");
|
||||||
|
|
||||||
|
// chrome
|
||||||
QJsonArray allowed_origins_arr = {"chrome-extension://aeicjepmjkgmbeohnchmpfjbpchogmjn/"};
|
QJsonArray allowed_origins_arr = {"chrome-extension://aeicjepmjkgmbeohnchmpfjbpchogmjn/"};
|
||||||
root_obj.insert("allowed_origins", allowed_origins_arr);
|
root_obj.insert("allowed_origins", allowed_origins_arr);
|
||||||
|
|
||||||
|
// firefox
|
||||||
|
QJsonArray allowed_extensions = {"585a153c7e1ac5463478f25f8f12220e9097e716@temporary-addon"};
|
||||||
|
root_obj.insert("allowed_extensions", allowed_extensions);
|
||||||
|
|
||||||
// save the manifest
|
// save the manifest
|
||||||
QString manifestPath =
|
QString manifestPath =
|
||||||
PathManager::getInstance().settingsFolderPath + "/native-messaging-manifest.json";
|
PathManager::getInstance().settingsFolderPath + "/native-messaging-manifest.json";
|
||||||
|
@ -70,13 +79,11 @@ void NativeMessagingManager::registerHost()
|
||||||
file.write(document.toJson());
|
file.write(document.toJson());
|
||||||
file.flush();
|
file.flush();
|
||||||
|
|
||||||
#ifdef XD
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// clang-format off
|
// clang-format off
|
||||||
QProcess::execute("REG ADD \"HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\com.chatterino.chatterino\" /ve /t REG_SZ /d \"" + manifestPath + "\" /f");
|
QProcess::execute("REG ADD \"HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\com.chatterino.chatterino\" /ve /t REG_SZ /d \"" + manifestPath + "\" /f");
|
||||||
// clang-format on
|
// clang-format on
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeMessagingManager::openGuiMessageQueue()
|
void NativeMessagingManager::openGuiMessageQueue()
|
||||||
|
@ -135,22 +142,45 @@ void NativeMessagingManager::ReceiverThread::handleMessage(const QJsonObject &ro
|
||||||
|
|
||||||
if (action == "select") {
|
if (action == "select") {
|
||||||
QString _type = root.value("type").toString();
|
QString _type = root.value("type").toString();
|
||||||
|
bool attach = root.value("attach").toBool();
|
||||||
QString name = root.value("name").toString();
|
QString name = root.value("name").toString();
|
||||||
|
QString winId = root.value("winId").toString();
|
||||||
|
int yOffset = root.value("yOffset").toInt(-1);
|
||||||
|
|
||||||
if (_type.isNull() || name.isNull()) {
|
if (_type.isNull() || name.isNull() || winId.isNull()) {
|
||||||
qDebug() << "NM type or name missing";
|
qDebug() << "NM type, name or winId missing";
|
||||||
|
attach = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_type == "twitch") {
|
if (_type == "twitch") {
|
||||||
util::postToThread([name] {
|
util::postToThread([name, attach, winId, yOffset] {
|
||||||
auto &ts = providers::twitch::TwitchServer::getInstance();
|
auto &ts = providers::twitch::TwitchServer::getInstance();
|
||||||
|
|
||||||
ts.watchingChannel.update(ts.getOrAddChannel(name));
|
ts.watchingChannel.update(ts.getOrAddChannel(name));
|
||||||
|
|
||||||
|
if (attach) {
|
||||||
|
auto *window =
|
||||||
|
widgets::AttachedWindow::get(::GetForegroundWindow(), winId, yOffset);
|
||||||
|
window->setChannel(ts.getOrAddChannel(name));
|
||||||
|
window->show();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "NM unknown channel type";
|
qDebug() << "NM unknown channel type";
|
||||||
}
|
}
|
||||||
|
} else if (action == "detach") {
|
||||||
|
QString winId = root.value("winId").toString();
|
||||||
|
|
||||||
|
if (winId.isNull()) {
|
||||||
|
qDebug() << "NM winId missing";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::postToThread([winId] { widgets::AttachedWindow::detach(winId); });
|
||||||
|
} else {
|
||||||
|
qDebug() << "NM unknown action " + action;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
src/util/tupletablemodel.cpp
Normal file
7
src/util/tupletablemodel.cpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include "tupletablemodel.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
} // namespace chatterino
|
211
src/util/tupletablemodel.hpp
Normal file
211
src/util/tupletablemodel.hpp
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
|
#include <pajlada/signals/signal.hpp>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <int I>
|
||||||
|
struct TupleConverter {
|
||||||
|
template <typename... Args>
|
||||||
|
static void tupleToVariants(const std::tuple<Args...> &t, std::vector<QVariant> &row)
|
||||||
|
{
|
||||||
|
row[I - 1] = QVariant(std::get<I - 1>(t));
|
||||||
|
TupleConverter<I - 1>::tupleToVariants<Args...>(t, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static void variantsToTuple(std::vector<QVariant> &row, std::tuple<Args...> &t)
|
||||||
|
{
|
||||||
|
std::get<I - 1>(t) = (decltype(std::get<I - 1>(t))) row[I - 1];
|
||||||
|
TupleConverter<I - 1>::variantsToTuple<Args...>(row, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct TupleConverter<0> {
|
||||||
|
template <typename... Args>
|
||||||
|
static void tupleToVariants(const std::tuple<Args...> &t, std::vector<QVariant> &row)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static void variantsToTuple(std::vector<QVariant> &row, std::tuple<Args...> &t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
class TupleTableModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
std::vector<std::vector<QVariant>> rows;
|
||||||
|
std::vector<QMap<int, QVariant>> titleData;
|
||||||
|
|
||||||
|
public:
|
||||||
|
pajlada::Signals::NoArgSignal itemsChanged;
|
||||||
|
|
||||||
|
TupleTableModel()
|
||||||
|
{
|
||||||
|
titleData.resize(sizeof...(Args));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRow(const std::tuple<Args...> &row)
|
||||||
|
{
|
||||||
|
this->beginInsertRows(QModelIndex(), this->rows.size(), this->rows.size());
|
||||||
|
std::vector<QVariant> variants;
|
||||||
|
variants.resize(sizeof...(Args));
|
||||||
|
TupleConverter<sizeof...(Args)>::tupleToVariants<Args...>(row, variants);
|
||||||
|
this->rows.push_back(variants);
|
||||||
|
this->endInsertRows();
|
||||||
|
this->itemsChanged.invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRow(Args... args)
|
||||||
|
{
|
||||||
|
this->beginInsertRows(QModelIndex(), this->rows.size(), this->rows.size());
|
||||||
|
std::vector<QVariant> variants;
|
||||||
|
variants.resize(sizeof...(Args));
|
||||||
|
TupleConverter<sizeof...(Args)>::tupleToVariants<Args...>(std::tuple<Args...>(args...),
|
||||||
|
variants);
|
||||||
|
this->rows.push_back(variants);
|
||||||
|
this->endInsertRows();
|
||||||
|
this->itemsChanged.invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<Args...> getRow(int index)
|
||||||
|
{
|
||||||
|
std::tuple<Args...> row;
|
||||||
|
TupleConverter<sizeof...(Args)>::variantsToTuple<Args...>(this->rows[index], row);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeRow(int index)
|
||||||
|
{
|
||||||
|
this->beginRemoveRows(QModelIndex(), index, index);
|
||||||
|
this->rows.erase(this->rows.begin() + index);
|
||||||
|
this->endRemoveRows();
|
||||||
|
this->itemsChanged.invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTitles(std::initializer_list<QString> titles)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const QString &title : titles) {
|
||||||
|
this->setHeaderData(i++, Qt::Horizontal, title, Qt::DisplayRole);
|
||||||
|
|
||||||
|
if (i >= sizeof...(Args))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getRowCount() const
|
||||||
|
{
|
||||||
|
return this->rows.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
|
{
|
||||||
|
return this->rows.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
|
{
|
||||||
|
return sizeof...(Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
|
||||||
|
{
|
||||||
|
QVariant data = this->rows[index.row()][index.column()];
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
if (data.type() == QVariant::Bool)
|
||||||
|
return QVariant();
|
||||||
|
else
|
||||||
|
return data;
|
||||||
|
} break;
|
||||||
|
case Qt::EditRole: {
|
||||||
|
return data;
|
||||||
|
} break;
|
||||||
|
case Qt::CheckStateRole: {
|
||||||
|
if (data.type() == QVariant::Bool)
|
||||||
|
return data;
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool setData(const QModelIndex &index, const QVariant &value,
|
||||||
|
int role = Qt::EditRole) override
|
||||||
|
{
|
||||||
|
QVariant data = this->rows[index.row()][index.column()];
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case (Qt::EditRole): {
|
||||||
|
this->rows[index.row()][index.column()] = value;
|
||||||
|
this->itemsChanged.invoke();
|
||||||
|
return true;
|
||||||
|
} break;
|
||||||
|
case (Qt::CheckStateRole): {
|
||||||
|
if (data.type() == QVariant::Bool) {
|
||||||
|
this->rows[index.row()][index.column()] = !data.toBool();
|
||||||
|
this->itemsChanged.invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation != Qt::Horizontal)
|
||||||
|
return QVariant();
|
||||||
|
if (section < 0 || section >= sizeof...(Args))
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
auto it = this->titleData[section].find(role);
|
||||||
|
return it == this->titleData[section].end() ? QVariant() : it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value,
|
||||||
|
int role)
|
||||||
|
{
|
||||||
|
if (orientation != Qt::Horizontal)
|
||||||
|
return false;
|
||||||
|
if (section < 0 || section >= sizeof...(Args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this->titleData[section][role] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Qt::ItemFlags flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QVariant data = this->rows[index.row()][index.column()];
|
||||||
|
|
||||||
|
if (data.type() == QVariant::Bool) {
|
||||||
|
return Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled |
|
||||||
|
Qt::ItemIsSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
} // namespace chatterino
|
112
src/widgets/attachedwindow.cpp
Normal file
112
src/widgets/attachedwindow.cpp
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#include "attachedwindow.hpp"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "widgets/split.hpp"
|
||||||
|
|
||||||
|
#include "Windows.h"
|
||||||
|
#pragma comment(lib, "Dwmapi.lib")
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace widgets {
|
||||||
|
|
||||||
|
AttachedWindow::AttachedWindow(void *_target, int _yOffset)
|
||||||
|
: target(_target)
|
||||||
|
, yOffset(_yOffset)
|
||||||
|
, QWidget(nullptr, Qt::FramelessWindowHint | Qt::Window)
|
||||||
|
{
|
||||||
|
QLayout *layout = new QVBoxLayout(this);
|
||||||
|
layout->setMargin(0);
|
||||||
|
this->setLayout(layout);
|
||||||
|
|
||||||
|
auto *split = new Split(singletons::ThemeManager::getInstance(), this);
|
||||||
|
this->ui.split = split;
|
||||||
|
split->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
|
||||||
|
layout->addWidget(split);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedWindow::~AttachedWindow()
|
||||||
|
{
|
||||||
|
for (auto it = items.begin(); it != items.end(); it++) {
|
||||||
|
if (it->window == this) {
|
||||||
|
items.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedWindow *AttachedWindow::get(void *target, const QString &winId, int yOffset)
|
||||||
|
{
|
||||||
|
for (Item &item : items) {
|
||||||
|
if (item.hwnd == target) {
|
||||||
|
return item.window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *window = new AttachedWindow(target, yOffset);
|
||||||
|
items.push_back(Item{target, window, winId});
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachedWindow::detach(const QString &winId)
|
||||||
|
{
|
||||||
|
for (Item &item : items) {
|
||||||
|
if (item.winId == winId) {
|
||||||
|
item.window->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachedWindow::setChannel(ChannelPtr channel)
|
||||||
|
{
|
||||||
|
this->ui.split->setChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachedWindow::showEvent(QShowEvent *)
|
||||||
|
{
|
||||||
|
attachToHwnd(this->target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachedWindow::attachToHwnd(void *_hwnd)
|
||||||
|
{
|
||||||
|
QTimer *timer = new QTimer(this);
|
||||||
|
timer->setInterval(1);
|
||||||
|
|
||||||
|
HWND hwnd = (HWND)this->winId();
|
||||||
|
HWND attached = (HWND)_hwnd;
|
||||||
|
QObject::connect(timer, &QTimer::timeout, [this, hwnd, attached, timer] {
|
||||||
|
::SetLastError(0);
|
||||||
|
RECT xD;
|
||||||
|
::GetWindowRect(attached, &xD);
|
||||||
|
|
||||||
|
if (::GetLastError() != 0) {
|
||||||
|
timer->stop();
|
||||||
|
timer->deleteLater();
|
||||||
|
this->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND next = ::GetNextWindow(attached, GW_HWNDPREV);
|
||||||
|
|
||||||
|
::SetWindowPos(hwnd, next ? next : HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||||
|
::MoveWindow(hwnd, xD.right - 360, xD.top + this->yOffset - 8, 360 - 8,
|
||||||
|
xD.bottom - xD.top - this->yOffset, false);
|
||||||
|
// ::MoveWindow(hwnd, xD.right - 360, xD.top + 82, 360 - 8, xD.bottom - xD.top - 82 -
|
||||||
|
// 8,
|
||||||
|
// false);
|
||||||
|
});
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void AttachedWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||||
|
//{
|
||||||
|
// MSG *msg = reinterpret_cast
|
||||||
|
|
||||||
|
// case WM_NCCALCSIZE: {
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
std::vector<AttachedWindow::Item> AttachedWindow::items;
|
||||||
|
|
||||||
|
} // namespace widgets
|
||||||
|
} // namespace chatterino
|
48
src/widgets/attachedwindow.hpp
Normal file
48
src/widgets/attachedwindow.hpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "channel.hpp"
|
||||||
|
#include "widgets/split.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace widgets {
|
||||||
|
|
||||||
|
class AttachedWindow : public QWidget
|
||||||
|
{
|
||||||
|
AttachedWindow(void *target, int asdf);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~AttachedWindow();
|
||||||
|
|
||||||
|
static AttachedWindow *get(void *target, const QString &winId, int yOffset);
|
||||||
|
static void detach(const QString &winId);
|
||||||
|
|
||||||
|
void setChannel(ChannelPtr channel);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void showEvent(QShowEvent *) override;
|
||||||
|
// virtual void nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||||
|
// override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *target;
|
||||||
|
int yOffset;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Split *split;
|
||||||
|
} ui;
|
||||||
|
|
||||||
|
void attachToHwnd(void *hwnd);
|
||||||
|
|
||||||
|
struct Item {
|
||||||
|
void *hwnd;
|
||||||
|
AttachedWindow *window;
|
||||||
|
QString winId;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<Item> items;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace widgets
|
||||||
|
} // namespace chatterino
|
|
@ -30,7 +30,7 @@ public:
|
||||||
QSize getScaleIndependantSize() const;
|
QSize getScaleIndependantSize() const;
|
||||||
int getScaleIndependantWidth() const;
|
int getScaleIndependantWidth() const;
|
||||||
int getScaleIndependantHeight() const;
|
int getScaleIndependantHeight() const;
|
||||||
void setScaleIndependantSize(int width, int height);
|
void setScaleIndependantSize(int width, int yOffset);
|
||||||
void setScaleIndependantSize(QSize);
|
void setScaleIndependantSize(QSize);
|
||||||
void setScaleIndependantWidth(int value);
|
void setScaleIndependantWidth(int value);
|
||||||
void setScaleIndependantHeight(int value);
|
void setScaleIndependantHeight(int value);
|
||||||
|
|
|
@ -98,7 +98,7 @@ ChannelView::ChannelView(BaseWidget *parent)
|
||||||
// this->resizeEvent(e);
|
// this->resizeEvent(e);
|
||||||
// delete e;
|
// delete e;
|
||||||
|
|
||||||
this->scrollBar.resize(this->scrollBar.width(), height() + 1);
|
this->scrollBar.resize(this->scrollBar.width(), this->height() + 1);
|
||||||
|
|
||||||
singletons::SettingManager::getInstance().showLastMessageIndicator.connect(
|
singletons::SettingManager::getInstance().showLastMessageIndicator.connect(
|
||||||
[this](auto, auto) { this->update(); }, this->managedConnections);
|
[this](auto, auto) { this->update(); }, this->managedConnections);
|
||||||
|
@ -198,14 +198,14 @@ void ChannelView::actuallyLayoutMessages()
|
||||||
|
|
||||||
y += message->getHeight();
|
y += message->getHeight();
|
||||||
|
|
||||||
if (y >= height()) {
|
if (y >= this->height()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// layout the messages at the bottom to determine the scrollbar thumb size
|
// layout the messages at the bottom to determine the scrollbar thumb size
|
||||||
int h = height() - 8;
|
int h = this->height() - 8;
|
||||||
|
|
||||||
for (int i = (int)messagesSnapshot.getLength() - 1; i >= 0; i--) {
|
for (int i = (int)messagesSnapshot.getLength() - 1; i >= 0; i--) {
|
||||||
auto *message = messagesSnapshot[i].get();
|
auto *message = messagesSnapshot[i].get();
|
||||||
|
@ -472,7 +472,7 @@ void ChannelView::updateLastReadMessage()
|
||||||
|
|
||||||
void ChannelView::resizeEvent(QResizeEvent *)
|
void ChannelView::resizeEvent(QResizeEvent *)
|
||||||
{
|
{
|
||||||
this->scrollBar.resize(this->scrollBar.width(), height());
|
this->scrollBar.resize(this->scrollBar.width(), this->height());
|
||||||
this->scrollBar.move(this->width() - this->scrollBar.width(), 0);
|
this->scrollBar.move(this->width() - this->scrollBar.width(), 0);
|
||||||
|
|
||||||
this->goToBottom->setGeometry(0, this->height() - 32, this->width(), 32);
|
this->goToBottom->setGeometry(0, this->height() - 32, this->width(), 32);
|
||||||
|
@ -559,7 +559,7 @@ void ChannelView::drawMessages(QPainter &painter)
|
||||||
y += layout->getHeight();
|
y += layout->getHeight();
|
||||||
|
|
||||||
end = layout;
|
end = layout;
|
||||||
if (y > height()) {
|
if (y > this->height()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
|
#include <QTableView>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
||||||
#include "debug/log.hpp"
|
#include "debug/log.hpp"
|
||||||
#include "singletons/settingsmanager.hpp"
|
#include "singletons/settingsmanager.hpp"
|
||||||
#include "util/layoutcreator.hpp"
|
#include "util/layoutcreator.hpp"
|
||||||
|
#include "util/tupletablemodel.hpp"
|
||||||
|
|
||||||
#define ENABLE_HIGHLIGHTS "Enable Highlighting"
|
#define ENABLE_HIGHLIGHTS "Enable Highlighting"
|
||||||
#define HIGHLIGHT_MSG "Highlight messages containing your name"
|
#define HIGHLIGHT_MSG "Highlight messages containing your name"
|
||||||
|
@ -54,15 +56,47 @@ HighlightingPage::HighlightingPage()
|
||||||
// HIGHLIGHTS
|
// HIGHLIGHTS
|
||||||
auto highlights = tabs.appendTab(new QVBoxLayout, "Highlights");
|
auto highlights = tabs.appendTab(new QVBoxLayout, "Highlights");
|
||||||
{
|
{
|
||||||
highlights.emplace<QListWidget>().assign(&this->highlightList);
|
QTableView *view = *highlights.emplace<QTableView>();
|
||||||
|
auto *model = new util::TupleTableModel<QString, bool, bool, bool>;
|
||||||
|
model->setTitles({"Pattern", "Flash taskbar", "Play sound", "Regex"});
|
||||||
|
|
||||||
|
// fourtf: could crash
|
||||||
|
for (const messages::HighlightPhrase &phrase :
|
||||||
|
settings.highlightProperties.getValue()) {
|
||||||
|
model->addRow(phrase.key, phrase.alert, phrase.sound, phrase.regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
view->setModel(model);
|
||||||
|
view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
view->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
view->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||||
|
view->resizeColumnsToContents();
|
||||||
|
view->setColumnWidth(0, 250);
|
||||||
|
|
||||||
auto buttons = highlights.emplace<QHBoxLayout>();
|
auto buttons = highlights.emplace<QHBoxLayout>();
|
||||||
|
|
||||||
buttons.emplace<QPushButton>("Add").assign(&this->highlightAdd);
|
model->itemsChanged.connect([model] {
|
||||||
buttons.emplace<QPushButton>("Edit").assign(&this->highlightEdit);
|
std::vector<messages::HighlightPhrase> phrases;
|
||||||
buttons.emplace<QPushButton>("Remove").assign(&this->highlightRemove);
|
for (int i = 0; i < model->getRowCount(); i++) {
|
||||||
|
auto t = model->getRow(i);
|
||||||
|
phrases.push_back(messages::HighlightPhrase{
|
||||||
|
std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
singletons::SettingManager::getInstance().highlightProperties.setValue(phrases);
|
||||||
|
});
|
||||||
|
|
||||||
this->addHighlightTabSignals();
|
auto add = buttons.emplace<QPushButton>("Add");
|
||||||
|
QObject::connect(*add, &QPushButton::clicked,
|
||||||
|
[model] { model->addRow("", true, false, false); });
|
||||||
|
auto remove = buttons.emplace<QPushButton>("Remove");
|
||||||
|
QObject::connect(*remove, &QPushButton::clicked, [view, model] {
|
||||||
|
if (view->selectionModel()->hasSelection()) {
|
||||||
|
model->removeRow(view->selectionModel()->selectedRows()[0].row());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
view->hideColumn(3);
|
||||||
}
|
}
|
||||||
// DISABLED USERS
|
// DISABLED USERS
|
||||||
auto disabledUsers = tabs.appendTab(new QVBoxLayout, "Disabled Users");
|
auto disabledUsers = tabs.appendTab(new QVBoxLayout, "Disabled Users");
|
||||||
|
@ -90,157 +124,6 @@ HighlightingPage::HighlightingPage()
|
||||||
this->disabledUsersChangedTimer.setSingleShot(true);
|
this->disabledUsersChangedTimer.setSingleShot(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// DISCLAIMER:
|
|
||||||
//
|
|
||||||
// If you are trying to learn from reading the chatterino code please ignore this segment.
|
|
||||||
//
|
|
||||||
void HighlightingPage::addHighlightTabSignals()
|
|
||||||
{
|
|
||||||
singletons::SettingManager &settings = singletons::SettingManager::getInstance();
|
|
||||||
|
|
||||||
auto addBtn = this->highlightAdd;
|
|
||||||
auto editBtn = this->highlightEdit;
|
|
||||||
auto delBtn = this->highlightRemove;
|
|
||||||
auto highlights = this->highlightList;
|
|
||||||
|
|
||||||
// Open "Add new highlight" dialog
|
|
||||||
QObject::connect(addBtn, &QPushButton::clicked, this, [highlights, this, &settings] {
|
|
||||||
auto show = new QWidget();
|
|
||||||
auto box = new QBoxLayout(QBoxLayout::TopToBottom);
|
|
||||||
|
|
||||||
auto edit = new QLineEdit();
|
|
||||||
auto add = new QPushButton("Add");
|
|
||||||
|
|
||||||
auto sound = new QCheckBox("Play sound");
|
|
||||||
auto task = new QCheckBox("Flash taskbar");
|
|
||||||
|
|
||||||
// Save highlight
|
|
||||||
QObject::connect(add, &QPushButton::clicked, this, [=, &settings] {
|
|
||||||
if (edit->text().length()) {
|
|
||||||
QString highlightKey = edit->text();
|
|
||||||
highlights->addItem(highlightKey);
|
|
||||||
|
|
||||||
auto properties = settings.highlightProperties.getValue();
|
|
||||||
|
|
||||||
messages::HighlightPhrase newHighlightProperty;
|
|
||||||
newHighlightProperty.key = highlightKey;
|
|
||||||
newHighlightProperty.sound = sound->isChecked();
|
|
||||||
newHighlightProperty.alert = task->isChecked();
|
|
||||||
|
|
||||||
properties.push_back(newHighlightProperty);
|
|
||||||
|
|
||||||
settings.highlightProperties = properties;
|
|
||||||
|
|
||||||
show->close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
box->addWidget(edit);
|
|
||||||
box->addWidget(add);
|
|
||||||
box->addWidget(sound);
|
|
||||||
box->addWidget(task);
|
|
||||||
show->setLayout(box);
|
|
||||||
show->show();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open "Edit selected highlight" dialog
|
|
||||||
QObject::connect(editBtn, &QPushButton::clicked, this, [highlights, this, &settings] {
|
|
||||||
if (highlights->selectedItems().isEmpty()) {
|
|
||||||
// No item selected
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QListWidgetItem *selectedHighlight = highlights->selectedItems().first();
|
|
||||||
QString highlightKey = selectedHighlight->text();
|
|
||||||
auto properties = settings.highlightProperties.getValue();
|
|
||||||
auto highlightIt = std::find_if(properties.begin(), properties.end(),
|
|
||||||
[highlightKey](const auto &highlight) {
|
|
||||||
return highlight.key == highlightKey; //
|
|
||||||
});
|
|
||||||
|
|
||||||
if (highlightIt == properties.end()) {
|
|
||||||
debug::Log("Unable to find highlight key {} in highlight properties. "
|
|
||||||
"This is weird",
|
|
||||||
highlightKey);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages::HighlightPhrase &selectedSetting = *highlightIt;
|
|
||||||
auto show = new QWidget();
|
|
||||||
auto box = new QBoxLayout(QBoxLayout::TopToBottom);
|
|
||||||
|
|
||||||
auto edit = new QLineEdit(highlightKey);
|
|
||||||
auto apply = new QPushButton("Apply");
|
|
||||||
|
|
||||||
auto sound = new QCheckBox("Play sound");
|
|
||||||
sound->setChecked(selectedSetting.sound);
|
|
||||||
auto task = new QCheckBox("Flash taskbar");
|
|
||||||
task->setChecked(selectedSetting.alert);
|
|
||||||
|
|
||||||
// Apply edited changes
|
|
||||||
QObject::connect(apply, &QPushButton::clicked, this, [=, &settings] {
|
|
||||||
QString newHighlightKey = edit->text();
|
|
||||||
|
|
||||||
if (newHighlightKey.length() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto properties = settings.highlightProperties.getValue();
|
|
||||||
auto highlightIt =
|
|
||||||
std::find_if(properties.begin(), properties.end(), [=](const auto &highlight) {
|
|
||||||
return highlight.key == highlightKey; //
|
|
||||||
});
|
|
||||||
|
|
||||||
if (highlightIt == properties.end()) {
|
|
||||||
debug::Log("Unable to find highlight key {} in highlight properties. "
|
|
||||||
"This is weird",
|
|
||||||
highlightKey);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto &highlightProperty = *highlightIt;
|
|
||||||
highlightProperty.key = newHighlightKey;
|
|
||||||
highlightProperty.sound = sound->isCheckable();
|
|
||||||
highlightProperty.alert = task->isCheckable();
|
|
||||||
|
|
||||||
settings.highlightProperties = properties;
|
|
||||||
|
|
||||||
selectedHighlight->setText(newHighlightKey);
|
|
||||||
selectedHighlight->setText(newHighlightKey);
|
|
||||||
|
|
||||||
show->close();
|
|
||||||
});
|
|
||||||
|
|
||||||
box->addWidget(edit);
|
|
||||||
box->addWidget(apply);
|
|
||||||
box->addWidget(sound);
|
|
||||||
box->addWidget(task);
|
|
||||||
show->setLayout(box);
|
|
||||||
show->show();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete selected highlight
|
|
||||||
QObject::connect(delBtn, &QPushButton::clicked, this, [highlights, &settings] {
|
|
||||||
if (highlights->selectedItems().isEmpty()) {
|
|
||||||
// No highlight selected
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QListWidgetItem *selectedHighlight = highlights->selectedItems().first();
|
|
||||||
QString highlightKey = selectedHighlight->text();
|
|
||||||
|
|
||||||
auto properties = settings.highlightProperties.getValue();
|
|
||||||
properties.erase(std::remove_if(properties.begin(), properties.end(),
|
|
||||||
[highlightKey](const auto &highlight) {
|
|
||||||
return highlight.key == highlightKey; //
|
|
||||||
}),
|
|
||||||
properties.end());
|
|
||||||
|
|
||||||
settings.highlightProperties = properties;
|
|
||||||
|
|
||||||
delete selectedHighlight;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace settingspages
|
} // namespace settingspages
|
||||||
} // namespace widgets
|
} // namespace widgets
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "widgets/settingspages/settingspage.hpp"
|
#include "widgets/settingspages/settingspage.hpp"
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
@ -17,14 +18,7 @@ public:
|
||||||
HighlightingPage();
|
HighlightingPage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QListWidget *highlightList;
|
|
||||||
QPushButton *highlightAdd;
|
|
||||||
QPushButton *highlightEdit;
|
|
||||||
QPushButton *highlightRemove;
|
|
||||||
|
|
||||||
QTimer disabledUsersChangedTimer;
|
QTimer disabledUsersChangedTimer;
|
||||||
|
|
||||||
void addHighlightTabSignals();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace settingspages
|
} // namespace settingspages
|
||||||
|
|
|
@ -37,16 +37,24 @@ namespace chatterino {
|
||||||
namespace widgets {
|
namespace widgets {
|
||||||
|
|
||||||
Split::Split(SplitContainer *parent)
|
Split::Split(SplitContainer *parent)
|
||||||
: BaseWidget(parent)
|
: Split((BaseWidget *)parent)
|
||||||
, parentPage(*parent)
|
{
|
||||||
|
this->container = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
Split::Split(BaseWidget *widget)
|
||||||
|
: Split(widget->themeManager, widget)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Split::Split(singletons::ThemeManager &manager, QWidget *parent)
|
||||||
|
: BaseWidget(manager, parent)
|
||||||
|
, container(nullptr)
|
||||||
, channel(Channel::getEmpty())
|
, channel(Channel::getEmpty())
|
||||||
, vbox(this)
|
, vbox(this)
|
||||||
, header(this)
|
, header(this)
|
||||||
, view(this)
|
, view(this)
|
||||||
, input(this)
|
, input(this)
|
||||||
, flexSizeX(1)
|
|
||||||
, flexSizeY(1)
|
|
||||||
, moderationMode(false)
|
|
||||||
{
|
{
|
||||||
this->setMouseTracking(true);
|
this->setMouseTracking(true);
|
||||||
|
|
||||||
|
@ -122,6 +130,11 @@ Split::~Split()
|
||||||
this->indirectChannelChangedConnection.disconnect();
|
this->indirectChannelChangedConnection.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Split::isInContainer() const
|
||||||
|
{
|
||||||
|
return this->container != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
IndirectChannel Split::getIndirectChannel()
|
IndirectChannel Split::getIndirectChannel()
|
||||||
{
|
{
|
||||||
return this->channel;
|
return this->channel;
|
||||||
|
@ -160,24 +173,26 @@ void Split::setChannel(IndirectChannel newChannel)
|
||||||
|
|
||||||
void Split::setFlexSizeX(double x)
|
void Split::setFlexSizeX(double x)
|
||||||
{
|
{
|
||||||
this->flexSizeX = x;
|
// this->flexSizeX = x;
|
||||||
this->parentPage.updateFlexValues();
|
// this->parentPage->updateFlexValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
double Split::getFlexSizeX()
|
double Split::getFlexSizeX()
|
||||||
{
|
{
|
||||||
return this->flexSizeX;
|
// return this->flexSizeX;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Split::setFlexSizeY(double y)
|
void Split::setFlexSizeY(double y)
|
||||||
{
|
{
|
||||||
this->flexSizeY = y;
|
// this->flexSizeY = y;
|
||||||
this->parentPage.updateFlexValues();
|
// this->parentPage.updateFlexValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
double Split::getFlexSizeY()
|
double Split::getFlexSizeY()
|
||||||
{
|
{
|
||||||
return this->flexSizeY;
|
// return this->flexSizeY;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Split::setModerationMode(bool value)
|
void Split::setModerationMode(bool value)
|
||||||
|
@ -206,7 +221,9 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
||||||
dialog->closed.connect([=] {
|
dialog->closed.connect([=] {
|
||||||
if (dialog->hasSeletedChannel()) {
|
if (dialog->hasSeletedChannel()) {
|
||||||
this->setChannel(dialog->getSelectedChannel());
|
this->setChannel(dialog->getSelectedChannel());
|
||||||
this->parentPage.refreshTitle();
|
if (this->isInContainer()) {
|
||||||
|
this->container->refreshTitle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(dialog->hasSeletedChannel());
|
callback(dialog->hasSeletedChannel());
|
||||||
|
@ -286,15 +303,17 @@ void Split::handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers)
|
||||||
/// Slots
|
/// Slots
|
||||||
void Split::doAddSplit()
|
void Split::doAddSplit()
|
||||||
{
|
{
|
||||||
SplitContainer *page = static_cast<SplitContainer *>(this->parentWidget());
|
if (this->container) {
|
||||||
page->addChat(true);
|
this->container->addChat(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Split::doCloseSplit()
|
void Split::doCloseSplit()
|
||||||
{
|
{
|
||||||
SplitContainer *page = static_cast<SplitContainer *>(this->parentWidget());
|
if (this->container) {
|
||||||
page->removeFromLayout(this);
|
this->container->removeFromLayout(this);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Split::doChangeChannel()
|
void Split::doChangeChannel()
|
||||||
|
|
|
@ -43,7 +43,9 @@ class Split : public BaseWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Split(SplitContainer *parent);
|
explicit Split(SplitContainer *parent);
|
||||||
|
explicit Split(BaseWidget *widget);
|
||||||
|
explicit Split(singletons::ThemeManager &manager, QWidget *parent);
|
||||||
~Split() override;
|
~Split() override;
|
||||||
|
|
||||||
pajlada::Signals::NoArgSignal channelChanged;
|
pajlada::Signals::NoArgSignal channelChanged;
|
||||||
|
@ -75,6 +77,8 @@ public:
|
||||||
|
|
||||||
void drag();
|
void drag();
|
||||||
|
|
||||||
|
bool isInContainer() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
void mouseMoveEvent(QMouseEvent *event) override;
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
@ -83,21 +87,22 @@ protected:
|
||||||
void keyReleaseEvent(QKeyEvent *event) override;
|
void keyReleaseEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SplitContainer &parentPage;
|
SplitContainer *container;
|
||||||
IndirectChannel channel;
|
IndirectChannel channel;
|
||||||
|
|
||||||
QVBoxLayout vbox;
|
QVBoxLayout vbox;
|
||||||
SplitHeader header;
|
SplitHeader header;
|
||||||
ChannelView view;
|
ChannelView view;
|
||||||
SplitInput input;
|
SplitInput input;
|
||||||
double flexSizeX;
|
double flexSizeX = 1;
|
||||||
double flexSizeY;
|
double flexSizeY = 1;
|
||||||
|
|
||||||
bool moderationMode;
|
bool moderationMode = false;
|
||||||
|
|
||||||
pajlada::Signals::Connection channelIDChangedConnection;
|
pajlada::Signals::Connection channelIDChangedConnection;
|
||||||
pajlada::Signals::Connection usermodeChangedConnection;
|
pajlada::Signals::Connection usermodeChangedConnection;
|
||||||
pajlada::Signals::Connection indirectChannelChangedConnection;
|
pajlada::Signals::Connection indirectChannelChangedConnection;
|
||||||
|
|
||||||
void doOpenAccountPopupWidget(AccountPopupWidget *widget, QString user);
|
void doOpenAccountPopupWidget(AccountPopupWidget *widget, QString user);
|
||||||
void channelNameUpdated(const QString &newChannelName);
|
void channelNameUpdated(const QString &newChannelName);
|
||||||
void handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers);
|
void handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers);
|
||||||
|
|
|
@ -11,10 +11,14 @@
|
||||||
#include "widgets/split.hpp"
|
#include "widgets/split.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QHeaderView>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include <QTableView>
|
||||||
|
#include "util/tupletablemodel.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace widgets {
|
namespace widgets {
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Window : public BaseWindow
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum WindowType { Main, Popup };
|
enum WindowType { Main, Popup, Attached };
|
||||||
|
|
||||||
explicit Window(singletons::ThemeManager &_themeManager, WindowType type);
|
explicit Window(singletons::ThemeManager &_themeManager, WindowType type);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue