Merge branch 'master' into apa-notification-on-live
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "Application.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "providers/twitch/TwitchAccount.hpp"
|
||||
#include "providers/twitch/TwitchCommon.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#ifdef USEWINSDK
|
||||
#include "util/WindowsHelper.hpp"
|
||||
# include "util/WindowsHelper.hpp"
|
||||
|
||||
#include "Windows.h"
|
||||
# include "Windows.h"
|
||||
// don't even think about reordering these
|
||||
#include "Psapi.h"
|
||||
#pragma comment(lib, "Dwmapi.lib")
|
||||
# include "Psapi.h"
|
||||
# pragma comment(lib, "Dwmapi.lib")
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Split;
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
|
||||
class AttachedWindow : public QWidget
|
||||
{
|
||||
AttachedWindow(void *_target, int _yOffset);
|
||||
|
||||
+39
-36
@@ -4,12 +4,13 @@
|
||||
#include "boost/algorithm/algorithm.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/PostToThread.hpp"
|
||||
#include "util/WindowsHelper.hpp"
|
||||
#include "widgets/Label.hpp"
|
||||
#include "widgets/TooltipWidget.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
@@ -19,20 +20,20 @@
|
||||
#include <functional>
|
||||
|
||||
#ifdef USEWINSDK
|
||||
#include <ObjIdl.h>
|
||||
#include <VersionHelpers.h>
|
||||
#include <Windows.h>
|
||||
#include <dwmapi.h>
|
||||
#include <gdiplus.h>
|
||||
#include <windowsx.h>
|
||||
# include <ObjIdl.h>
|
||||
# include <VersionHelpers.h>
|
||||
# include <Windows.h>
|
||||
# include <dwmapi.h>
|
||||
# include <gdiplus.h>
|
||||
# include <windowsx.h>
|
||||
|
||||
//#include <ShellScalingApi.h>
|
||||
#pragma comment(lib, "Dwmapi.lib")
|
||||
# pragma comment(lib, "Dwmapi.lib")
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
# include <QHBoxLayout>
|
||||
# include <QVBoxLayout>
|
||||
|
||||
#define WM_DPICHANGED 0x02E0
|
||||
# define WM_DPICHANGED 0x02E0
|
||||
#endif
|
||||
|
||||
#include "widgets/helper/TitlebarButton.hpp"
|
||||
@@ -55,13 +56,13 @@ BaseWindow::BaseWindow(QWidget *parent, Flags _flags)
|
||||
this->init();
|
||||
|
||||
this->connections_.managedConnect(
|
||||
getApp()->settings->uiScale.getValueChangedSignal(),
|
||||
getSettings()->uiScale.getValueChangedSignal(),
|
||||
[this](auto, auto) { postToThread([this] { this->updateScale(); }); });
|
||||
|
||||
this->updateScale();
|
||||
|
||||
createWindowShortcut(this, "CTRL+0",
|
||||
[] { getApp()->settings->uiScale.setValue(0); });
|
||||
[] { getSettings()->uiScale.setValue(0); });
|
||||
|
||||
// QTimer::this->scaleChangedEvent(this->getScale());
|
||||
}
|
||||
@@ -104,19 +105,17 @@ void BaseWindow::init()
|
||||
QSizePolicy policy(QSizePolicy::Ignored,
|
||||
QSizePolicy::Preferred);
|
||||
policy.setHorizontalStretch(1);
|
||||
// title->setBaseSize(0, 0);
|
||||
// title->setScaledContents(true);
|
||||
title->setSizePolicy(policy);
|
||||
buttonLayout->addWidget(title);
|
||||
this->ui_.titleLabel = title;
|
||||
|
||||
// buttons
|
||||
TitleBarButton *_minButton = new TitleBarButton;
|
||||
_minButton->setButtonStyle(TitleBarButton::Minimize);
|
||||
_minButton->setButtonStyle(TitleBarButtonStyle::Minimize);
|
||||
TitleBarButton *_maxButton = new TitleBarButton;
|
||||
_maxButton->setButtonStyle(TitleBarButton::Maximize);
|
||||
_maxButton->setButtonStyle(TitleBarButtonStyle::Maximize);
|
||||
TitleBarButton *_exitButton = new TitleBarButton;
|
||||
_exitButton->setButtonStyle(TitleBarButton::Close);
|
||||
_exitButton->setButtonStyle(TitleBarButtonStyle::Close);
|
||||
|
||||
QObject::connect(_minButton, &TitleBarButton::clicked, this,
|
||||
[this] {
|
||||
@@ -164,7 +163,7 @@ void BaseWindow::init()
|
||||
// fourtf: don't ask me why we need to delay this
|
||||
if (!(this->flags_ & Flags::TopMost)) {
|
||||
QTimer::singleShot(1, this, [this] {
|
||||
getApp()->settings->windowTopMost.connect(
|
||||
getSettings()->windowTopMost.connect(
|
||||
[this](bool topMost, auto) {
|
||||
::SetWindowPos(HWND(this->winId()),
|
||||
topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,
|
||||
@@ -175,7 +174,7 @@ void BaseWindow::init()
|
||||
});
|
||||
}
|
||||
#else
|
||||
// if (getApp()->settings->windowTopMost.getValue()) {
|
||||
// if (getSettings()->windowTopMost.getValue()) {
|
||||
// this->setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||
// }
|
||||
#endif
|
||||
@@ -239,7 +238,7 @@ void BaseWindow::themeChangedEvent()
|
||||
this->ui_.titleLabel->setPalette(palette_title);
|
||||
}
|
||||
|
||||
for (RippleEffectButton *button : this->ui_.buttons) {
|
||||
for (Button *button : this->ui_.buttons) {
|
||||
button->setMouseEffectColor(this->theme->window.text);
|
||||
}
|
||||
} else {
|
||||
@@ -268,11 +267,11 @@ void BaseWindow::wheelEvent(QWheelEvent *event)
|
||||
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
if (event->delta() > 0) {
|
||||
getApp()->settings->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getApp()->settings->uiScale.getValue() + 1));
|
||||
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getSettings()->uiScale.getValue() + 1));
|
||||
} else {
|
||||
getApp()->settings->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getApp()->settings->uiScale.getValue() - 1));
|
||||
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getSettings()->uiScale.getValue() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,7 +316,7 @@ void BaseWindow::mousePressEvent(QMouseEvent *event)
|
||||
};
|
||||
|
||||
if (!recursiveCheckMouseTracking(widget)) {
|
||||
Log("Start moving");
|
||||
log("Start moving");
|
||||
this->moving = true;
|
||||
}
|
||||
}
|
||||
@@ -332,7 +331,7 @@ void BaseWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
#ifndef Q_OS_WIN
|
||||
if (this->flags_ & FramelessDraggable) {
|
||||
if (this->moving) {
|
||||
Log("Stop moving");
|
||||
log("Stop moving");
|
||||
this->moving = false;
|
||||
}
|
||||
}
|
||||
@@ -355,8 +354,8 @@ void BaseWindow::mouseMoveEvent(QMouseEvent *event)
|
||||
BaseWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
TitleBarButton *BaseWindow::addTitleBarButton(
|
||||
const TitleBarButton::Style &style, std::function<void()> onClicked)
|
||||
TitleBarButton *BaseWindow::addTitleBarButton(const TitleBarButtonStyle &style,
|
||||
std::function<void()> onClicked)
|
||||
{
|
||||
TitleBarButton *button = new TitleBarButton;
|
||||
button->setScaleIndependantSize(30, 30);
|
||||
@@ -371,15 +370,15 @@ TitleBarButton *BaseWindow::addTitleBarButton(
|
||||
return button;
|
||||
}
|
||||
|
||||
RippleEffectLabel *BaseWindow::addTitleBarLabel(std::function<void()> onClicked)
|
||||
EffectLabel *BaseWindow::addTitleBarLabel(std::function<void()> onClicked)
|
||||
{
|
||||
RippleEffectLabel *button = new RippleEffectLabel;
|
||||
EffectLabel *button = new EffectLabel;
|
||||
button->setScaleIndependantHeight(30);
|
||||
|
||||
this->ui_.buttons.push_back(button);
|
||||
this->ui_.titlebarBox->insertWidget(1, button);
|
||||
|
||||
QObject::connect(button, &RippleEffectLabel::clicked, this,
|
||||
QObject::connect(button, &EffectLabel::clicked, this,
|
||||
[onClicked] { onClicked(); });
|
||||
|
||||
return button;
|
||||
@@ -391,10 +390,10 @@ void BaseWindow::changeEvent(QEvent *)
|
||||
|
||||
#ifdef USEWINSDK
|
||||
if (this->ui_.maxButton) {
|
||||
this->ui_.maxButton->setButtonStyle(this->windowState() &
|
||||
Qt::WindowMaximized
|
||||
? TitleBarButton::Unmaximize
|
||||
: TitleBarButton::Maximize);
|
||||
this->ui_.maxButton->setButtonStyle(
|
||||
this->windowState() & Qt::WindowMaximized
|
||||
? TitleBarButtonStyle::Unmaximize
|
||||
: TitleBarButtonStyle::Maximize);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -461,7 +460,11 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||
long *result)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
# if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
||||
MSG *msg = *reinterpret_cast<MSG **>(message);
|
||||
# else
|
||||
MSG *msg = reinterpret_cast<MSG *>(message);
|
||||
# endif
|
||||
|
||||
bool returnValue = false;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "BaseWidget.hpp"
|
||||
#include "widgets/helper/TitlebarButton.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
@@ -12,9 +11,10 @@ typedef struct tagMSG MSG;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class RippleEffectButton;
|
||||
class RippleEffectLabel;
|
||||
class Button;
|
||||
class EffectLabel;
|
||||
class TitleBarButton;
|
||||
enum class TitleBarButtonStyle;
|
||||
|
||||
class BaseWindow : public BaseWidget
|
||||
{
|
||||
@@ -36,9 +36,9 @@ public:
|
||||
|
||||
QWidget *getLayoutContainer();
|
||||
bool hasCustomWindowFrame();
|
||||
TitleBarButton *addTitleBarButton(const TitleBarButton::Style &style,
|
||||
TitleBarButton *addTitleBarButton(const TitleBarButtonStyle &style,
|
||||
std::function<void()> onClicked);
|
||||
RippleEffectLabel *addTitleBarLabel(std::function<void()> onClicked);
|
||||
EffectLabel *addTitleBarLabel(std::function<void()> onClicked);
|
||||
|
||||
void setStayInScreenRect(bool value);
|
||||
bool getStayInScreenRect() const;
|
||||
@@ -109,11 +109,11 @@ private:
|
||||
TitleBarButton *maxButton = nullptr;
|
||||
TitleBarButton *exitButton = nullptr;
|
||||
QWidget *layoutBase = nullptr;
|
||||
std::vector<RippleEffectButton *> buttons;
|
||||
std::vector<Button *> buttons;
|
||||
} ui_;
|
||||
|
||||
pajlada::Signals::SignalHolder connections_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
};
|
||||
}; // namespace chatterino
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
+14
-15
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/InitUpdateButton.hpp"
|
||||
@@ -27,11 +28,11 @@ namespace chatterino {
|
||||
|
||||
Notebook::Notebook(QWidget *parent)
|
||||
: BaseWidget(parent)
|
||||
, addButton_(this)
|
||||
, addButton_(new NotebookButton(this))
|
||||
{
|
||||
this->addButton_.setIcon(NotebookButton::Icon::Plus);
|
||||
this->addButton_->setIcon(NotebookButton::Icon::Plus);
|
||||
|
||||
this->addButton_.setHidden(true);
|
||||
this->addButton_->setHidden(true);
|
||||
|
||||
auto *shortcut_next = new QShortcut(QKeySequence("Ctrl+Tab"), this);
|
||||
QObject::connect(shortcut_next, &QShortcut::activated,
|
||||
@@ -290,14 +291,14 @@ void Notebook::setShowAddButton(bool value)
|
||||
{
|
||||
this->showAddButton_ = value;
|
||||
|
||||
this->addButton_.setHidden(!value);
|
||||
this->addButton_->setHidden(!value);
|
||||
}
|
||||
|
||||
void Notebook::scaleChangedEvent(float scale)
|
||||
{
|
||||
float h = NOTEBOOK_TAB_HEIGHT * this->getScale();
|
||||
|
||||
this->addButton_.setFixedSize(h, h);
|
||||
this->addButton_->setFixedSize(h, h);
|
||||
|
||||
for (auto &i : this->items_) {
|
||||
i.tab->updateSize();
|
||||
@@ -353,7 +354,7 @@ void Notebook::performLayout(bool animated)
|
||||
}
|
||||
|
||||
if (this->showAddButton_) {
|
||||
this->addButton_.move(x, y);
|
||||
this->addButton_->move(x, y);
|
||||
}
|
||||
|
||||
if (this->lineY_ != y + tabHeight) {
|
||||
@@ -368,7 +369,7 @@ void Notebook::performLayout(bool animated)
|
||||
}
|
||||
|
||||
if (this->showAddButton_) {
|
||||
this->addButton_.raise();
|
||||
this->addButton_->raise();
|
||||
}
|
||||
|
||||
if (this->selectedPage_ != nullptr) {
|
||||
@@ -389,7 +390,7 @@ void Notebook::paintEvent(QPaintEvent *event)
|
||||
|
||||
NotebookButton *Notebook::getAddButton()
|
||||
{
|
||||
return &this->addButton_;
|
||||
return this->addButton_;
|
||||
}
|
||||
|
||||
NotebookButton *Notebook::addCustomButton()
|
||||
@@ -432,10 +433,9 @@ void SplitNotebook::addCustomButtons()
|
||||
// settings
|
||||
auto settingsBtn = this->addCustomButton();
|
||||
|
||||
settingsBtn->setVisible(
|
||||
!getApp()->settings->hidePreferencesButton.getValue());
|
||||
settingsBtn->setVisible(!getSettings()->hidePreferencesButton.getValue());
|
||||
|
||||
getApp()->settings->hidePreferencesButton.connect(
|
||||
getSettings()->hidePreferencesButton.connect(
|
||||
[settingsBtn](bool hide, auto) { settingsBtn->setVisible(!hide); },
|
||||
this->connections_);
|
||||
|
||||
@@ -446,8 +446,8 @@ void SplitNotebook::addCustomButtons()
|
||||
|
||||
// account
|
||||
auto userBtn = this->addCustomButton();
|
||||
userBtn->setVisible(!getApp()->settings->hideUserButton.getValue());
|
||||
getApp()->settings->hideUserButton.connect(
|
||||
userBtn->setVisible(!getSettings()->hideUserButton.getValue());
|
||||
getSettings()->hideUserButton.connect(
|
||||
[userBtn](bool hide, auto) { userBtn->setVisible(!hide); },
|
||||
this->connections_);
|
||||
|
||||
@@ -460,8 +460,7 @@ void SplitNotebook::addCustomButtons()
|
||||
// updates
|
||||
auto updateBtn = this->addCustomButton();
|
||||
|
||||
initUpdateButton(*updateBtn, this->updateDialogHandle_,
|
||||
this->signalHolder_);
|
||||
initUpdateButton(*updateBtn, this->signalHolder_);
|
||||
}
|
||||
|
||||
SplitContainer *SplitNotebook::addPage(bool select)
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
#include "pajlada/signals/signal.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/dialogs/UpdateDialog.hpp"
|
||||
#include "widgets/helper/NotebookButton.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
#include <QList>
|
||||
#include <QMessageBox>
|
||||
@@ -15,6 +11,10 @@
|
||||
namespace chatterino {
|
||||
|
||||
class Window;
|
||||
class UpdateDialog;
|
||||
class NotebookButton;
|
||||
class NotebookTab;
|
||||
class SplitContainer;
|
||||
|
||||
class Notebook : public BaseWidget
|
||||
{
|
||||
@@ -22,6 +22,7 @@ class Notebook : public BaseWidget
|
||||
|
||||
public:
|
||||
explicit Notebook(QWidget *parent);
|
||||
~Notebook() override = default;
|
||||
|
||||
NotebookTab *addPage(QWidget *page, QString title = QString(),
|
||||
bool select = false);
|
||||
@@ -74,7 +75,7 @@ private:
|
||||
QList<Item> items_;
|
||||
QWidget *selectedPage_ = nullptr;
|
||||
|
||||
NotebookButton addButton_;
|
||||
NotebookButton *addButton_;
|
||||
std::vector<NotebookButton *> customButtons_;
|
||||
|
||||
bool allowUserTabManagement_ = false;
|
||||
@@ -94,7 +95,7 @@ private:
|
||||
void addCustomButtons();
|
||||
|
||||
pajlada::Signals::SignalHolder signalHolder_;
|
||||
std::unique_ptr<UpdateDialog> updateDialogHandle_;
|
||||
std::shared_ptr<UpdateDialog> updateDialogHandle_;
|
||||
|
||||
std::vector<pajlada::Signals::ScopedConnection> connections_;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "widgets/Scrollbar.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
@@ -103,8 +104,7 @@ void Scrollbar::setSmallChange(qreal value)
|
||||
|
||||
void Scrollbar::setDesiredValue(qreal value, bool animated)
|
||||
{
|
||||
auto app = getApp();
|
||||
animated &= app->settings->enableSmoothScrolling.getValue();
|
||||
animated &= getSettings()->enableSmoothScrolling.getValue();
|
||||
value = std::max(this->minimum_,
|
||||
std::min(this->maximum_ - this->largeChange_, value));
|
||||
|
||||
@@ -221,8 +221,6 @@ void Scrollbar::printCurrentState(const QString &prefix) const
|
||||
|
||||
void Scrollbar::paintEvent(QPaintEvent *)
|
||||
{
|
||||
auto *app = getApp();
|
||||
|
||||
bool mouseOver = this->mouseOverIndex_ != -1;
|
||||
int xOffset = mouseOver ? 0 : width() - int(4 * this->getScale());
|
||||
|
||||
@@ -267,9 +265,11 @@ void Scrollbar::paintEvent(QPaintEvent *)
|
||||
QColor color = [&] {
|
||||
switch (highlight.getColor()) {
|
||||
case ScrollbarHighlight::Highlight:
|
||||
return app->themes->scrollbars.highlights.highlight;
|
||||
return getApp()
|
||||
->themes->scrollbars.highlights.highlight;
|
||||
case ScrollbarHighlight::Subscription:
|
||||
return app->themes->scrollbars.highlights.subscription;
|
||||
return getApp()
|
||||
->themes->scrollbars.highlights.subscription;
|
||||
}
|
||||
return QColor();
|
||||
}();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "messages/LimitedQueue.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/helper/ScrollbarHighlight.hpp"
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
#include "common/Channel.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
#ifdef USEWEBENGINE
|
||||
#include <QtWebEngineWidgets>
|
||||
# include <QtWebEngineWidgets>
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#ifdef USEWINSDK
|
||||
#include <Windows.h>
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
@@ -79,7 +79,7 @@ void TooltipWidget::updateFont()
|
||||
auto app = getApp();
|
||||
|
||||
this->setFont(
|
||||
app->fonts->getFont(Fonts::Type::ChatMediumSmall, this->getScale()));
|
||||
app->fonts->getFont(FontStyle::ChatMediumSmall, this->getScale()));
|
||||
}
|
||||
|
||||
void TooltipWidget::setText(QString text)
|
||||
|
||||
+42
-40
@@ -14,8 +14,11 @@
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
#include "widgets/dialogs/UpdateDialog.hpp"
|
||||
#include "widgets/dialogs/WelcomeDialog.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
#include "widgets/helper/TitlebarButton.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopServices>
|
||||
@@ -28,10 +31,10 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
Window::Window(Type type)
|
||||
Window::Window(WindowType type)
|
||||
: BaseWindow(nullptr, BaseWindow::EnableCustomFrame)
|
||||
, type_(type)
|
||||
, notebook_(this)
|
||||
, notebook_(new SplitNotebook(this))
|
||||
{
|
||||
this->addCustomTitlebarButtons();
|
||||
this->addDebugStuff();
|
||||
@@ -42,26 +45,26 @@ Window::Window(Type type)
|
||||
[this] { this->onAccountSelected(); });
|
||||
this->onAccountSelected();
|
||||
|
||||
if (type == Type::Main) {
|
||||
if (type == WindowType::Main) {
|
||||
this->resize(int(600 * this->getScale()), int(500 * this->getScale()));
|
||||
} else {
|
||||
this->resize(int(300 * this->getScale()), int(500 * this->getScale()));
|
||||
}
|
||||
}
|
||||
|
||||
Window::Type Window::getType()
|
||||
WindowType Window::getType()
|
||||
{
|
||||
return this->type_;
|
||||
}
|
||||
|
||||
SplitNotebook &Window::getNotebook()
|
||||
{
|
||||
return this->notebook_;
|
||||
return *this->notebook_;
|
||||
}
|
||||
|
||||
void Window::repaintVisibleChatWidgets(Channel *channel)
|
||||
{
|
||||
auto page = this->notebook_.getOrAddSelectedPage();
|
||||
auto page = this->notebook_->getOrAddSelectedPage();
|
||||
|
||||
for (const auto &split : page->getSplits()) {
|
||||
if (channel == nullptr || channel == split->getChannel().get()) {
|
||||
@@ -77,7 +80,7 @@ bool Window::event(QEvent *event)
|
||||
break;
|
||||
|
||||
case QEvent::WindowDeactivate: {
|
||||
auto page = this->notebook_.getOrAddSelectedPage();
|
||||
auto page = this->notebook_->getOrAddSelectedPage();
|
||||
|
||||
if (page != nullptr) {
|
||||
std::vector<Split *> splits = page->getSplits();
|
||||
@@ -102,8 +105,8 @@ bool Window::event(QEvent *event)
|
||||
void Window::showEvent(QShowEvent *event)
|
||||
{
|
||||
// Startup notification
|
||||
if (getApp()->settings->startUpNotification.getValue() < 1) {
|
||||
getApp()->settings->startUpNotification = 1;
|
||||
if (getSettings()->startUpNotification.getValue() < 1) {
|
||||
getSettings()->startUpNotification = 1;
|
||||
|
||||
auto box = new QMessageBox(
|
||||
QMessageBox::Information, "Chatterino 2 Beta",
|
||||
@@ -115,8 +118,8 @@ void Window::showEvent(QShowEvent *event)
|
||||
}
|
||||
|
||||
// Show changelog
|
||||
if (getApp()->settings->currentVersion.getValue() != "" &&
|
||||
getApp()->settings->currentVersion.getValue() != CHATTERINO_VERSION) {
|
||||
if (getSettings()->currentVersion.getValue() != "" &&
|
||||
getSettings()->currentVersion.getValue() != CHATTERINO_VERSION) {
|
||||
auto box = new QMessageBox(QMessageBox::Information,
|
||||
"Chatterino 2 Beta", "Show changelog?",
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
@@ -127,7 +130,7 @@ void Window::showEvent(QShowEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
getApp()->settings->currentVersion.setValue(CHATTERINO_VERSION);
|
||||
getSettings()->currentVersion.setValue(CHATTERINO_VERSION);
|
||||
|
||||
// --
|
||||
BaseWindow::showEvent(event);
|
||||
@@ -135,7 +138,7 @@ void Window::showEvent(QShowEvent *event)
|
||||
|
||||
void Window::closeEvent(QCloseEvent *)
|
||||
{
|
||||
if (this->type_ == Type::Main) {
|
||||
if (this->type_ == WindowType::Main) {
|
||||
auto app = getApp();
|
||||
app->windows->save();
|
||||
app->windows->closeAll();
|
||||
@@ -143,7 +146,7 @@ void Window::closeEvent(QCloseEvent *)
|
||||
|
||||
this->closed.invoke();
|
||||
|
||||
if (this->type_ == Type::Main) {
|
||||
if (this->type_ == WindowType::Main) {
|
||||
QApplication::exit();
|
||||
}
|
||||
}
|
||||
@@ -152,35 +155,34 @@ void Window::addLayout()
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(&this->notebook_);
|
||||
layout->addWidget(this->notebook_);
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
|
||||
// set margin
|
||||
layout->setMargin(0);
|
||||
|
||||
this->notebook_.setAllowUserTabManagement(true);
|
||||
this->notebook_.setShowAddButton(true);
|
||||
this->notebook_->setAllowUserTabManagement(true);
|
||||
this->notebook_->setShowAddButton(true);
|
||||
}
|
||||
|
||||
void Window::addCustomTitlebarButtons()
|
||||
{
|
||||
if (!this->hasCustomWindowFrame()) return;
|
||||
if (this->type_ != Type::Main) return;
|
||||
if (this->type_ != WindowType::Main) return;
|
||||
|
||||
// settings
|
||||
this->addTitleBarButton(TitleBarButton::Settings, [] {
|
||||
getApp()->windows->showSettingsDialog(); //
|
||||
});
|
||||
this->addTitleBarButton(TitleBarButtonStyle::Settings,
|
||||
[] { getApp()->windows->showSettingsDialog(); });
|
||||
|
||||
// updates
|
||||
auto update = this->addTitleBarButton(TitleBarButton::None, [] {});
|
||||
auto update = this->addTitleBarButton(TitleBarButtonStyle::None, [] {});
|
||||
|
||||
initUpdateButton(*update, this->updateDialogHandle_, this->signalHolder_);
|
||||
initUpdateButton(*update, this->signalHolder_);
|
||||
|
||||
// account
|
||||
this->userLabel_ = this->addTitleBarLabel([this] {
|
||||
getApp()->windows->showAccountSelectPopup(this->userLabel_->mapToGlobal(
|
||||
this->userLabel_->rect().bottomLeft())); //
|
||||
this->userLabel_->rect().bottomLeft()));
|
||||
});
|
||||
this->userLabel_->setMinimumWidth(20 * getScale());
|
||||
}
|
||||
@@ -252,35 +254,35 @@ void Window::addShortcuts()
|
||||
|
||||
// Switch tab
|
||||
createWindowShortcut(this, "CTRL+T", [this] {
|
||||
this->notebook_.getOrAddSelectedPage()->appendNewSplit(true);
|
||||
this->notebook_->getOrAddSelectedPage()->appendNewSplit(true);
|
||||
});
|
||||
|
||||
createWindowShortcut(this, "CTRL+1",
|
||||
[this] { this->notebook_.selectIndex(0); });
|
||||
[this] { this->notebook_->selectIndex(0); });
|
||||
createWindowShortcut(this, "CTRL+2",
|
||||
[this] { this->notebook_.selectIndex(1); });
|
||||
[this] { this->notebook_->selectIndex(1); });
|
||||
createWindowShortcut(this, "CTRL+3",
|
||||
[this] { this->notebook_.selectIndex(2); });
|
||||
[this] { this->notebook_->selectIndex(2); });
|
||||
createWindowShortcut(this, "CTRL+4",
|
||||
[this] { this->notebook_.selectIndex(3); });
|
||||
[this] { this->notebook_->selectIndex(3); });
|
||||
createWindowShortcut(this, "CTRL+5",
|
||||
[this] { this->notebook_.selectIndex(4); });
|
||||
[this] { this->notebook_->selectIndex(4); });
|
||||
createWindowShortcut(this, "CTRL+6",
|
||||
[this] { this->notebook_.selectIndex(5); });
|
||||
[this] { this->notebook_->selectIndex(5); });
|
||||
createWindowShortcut(this, "CTRL+7",
|
||||
[this] { this->notebook_.selectIndex(6); });
|
||||
[this] { this->notebook_->selectIndex(6); });
|
||||
createWindowShortcut(this, "CTRL+8",
|
||||
[this] { this->notebook_.selectIndex(7); });
|
||||
[this] { this->notebook_->selectIndex(7); });
|
||||
createWindowShortcut(this, "CTRL+9",
|
||||
[this] { this->notebook_.selectIndex(8); });
|
||||
[this] { this->notebook_->selectIndex(8); });
|
||||
|
||||
// Zoom in
|
||||
{
|
||||
auto s = new QShortcut(QKeySequence::ZoomIn, this);
|
||||
s->setContext(Qt::WindowShortcut);
|
||||
QObject::connect(s, &QShortcut::activated, this, [] {
|
||||
getApp()->settings->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getApp()->settings->uiScale.getValue() + 1));
|
||||
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getSettings()->uiScale.getValue() + 1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -289,18 +291,18 @@ void Window::addShortcuts()
|
||||
auto s = new QShortcut(QKeySequence::ZoomOut, this);
|
||||
s->setContext(Qt::WindowShortcut);
|
||||
QObject::connect(s, &QShortcut::activated, this, [] {
|
||||
getApp()->settings->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getApp()->settings->uiScale.getValue() - 1));
|
||||
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getSettings()->uiScale.getValue() - 1));
|
||||
});
|
||||
}
|
||||
|
||||
// New tab
|
||||
createWindowShortcut(this, "CTRL+SHIFT+T",
|
||||
[this] { this->notebook_.addPage(true); });
|
||||
[this] { this->notebook_->addPage(true); });
|
||||
|
||||
// Close tab
|
||||
createWindowShortcut(this, "CTRL+SHIFT+W",
|
||||
[this] { this->notebook_.removeCurrentPage(); });
|
||||
[this] { this->notebook_->removeCurrentPage(); });
|
||||
}
|
||||
|
||||
void Window::onAccountSelected()
|
||||
|
||||
+11
-15
@@ -1,13 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/Helpers.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/dialogs/UpdateDialog.hpp"
|
||||
|
||||
//#ifdef USEWINSDK
|
||||
//#include <platform/borderless/qwinwidget.h>
|
||||
//#endif
|
||||
|
||||
#include <pajlada/settings/setting.hpp>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
@@ -16,17 +9,20 @@
|
||||
namespace chatterino {
|
||||
|
||||
class Theme;
|
||||
class UpdateDialog;
|
||||
class SplitNotebook;
|
||||
class Channel;
|
||||
|
||||
enum class WindowType { Main, Popup, Attached };
|
||||
|
||||
class Window : public BaseWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Type { Main, Popup, Attached };
|
||||
explicit Window(WindowType type);
|
||||
|
||||
explicit Window(Window::Type type);
|
||||
|
||||
Type getType();
|
||||
WindowType getType();
|
||||
SplitNotebook &getNotebook();
|
||||
|
||||
void repaintVisibleChatWidgets(Channel *channel = nullptr);
|
||||
@@ -45,11 +41,11 @@ private:
|
||||
void addLayout();
|
||||
void onAccountSelected();
|
||||
|
||||
Type type_;
|
||||
WindowType type_;
|
||||
|
||||
SplitNotebook notebook_;
|
||||
RippleEffectLabel *userLabel_ = nullptr;
|
||||
std::unique_ptr<UpdateDialog> updateDialogHandle_;
|
||||
SplitNotebook *notebook_;
|
||||
EffectLabel *userLabel_ = nullptr;
|
||||
std::shared_ptr<UpdateDialog> updateDialogHandle_;
|
||||
|
||||
pajlada::Signals::SignalHolder signalHolder_;
|
||||
|
||||
|
||||
+110
-113
@@ -2,139 +2,143 @@
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "debug/Benchmark.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "messages/MessageBuilder.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "singletons/Emotes.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QShortcut>
|
||||
#include <QTabWidget>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
EmotePopup::EmotePopup()
|
||||
: BaseWindow(nullptr, BaseWindow::EnableCustomFrame)
|
||||
{
|
||||
this->viewEmotes_ = new ChannelView();
|
||||
this->viewEmojis_ = new ChannelView();
|
||||
|
||||
this->viewEmotes_->setOverrideFlags(MessageElementFlags{
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
this->viewEmojis_->setOverrideFlags(MessageElementFlags{
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
|
||||
this->viewEmotes_->setEnableScrollingToBottom(false);
|
||||
this->viewEmojis_->setEnableScrollingToBottom(false);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
|
||||
Notebook *notebook = new Notebook(this);
|
||||
layout->addWidget(notebook);
|
||||
layout->setMargin(0);
|
||||
|
||||
notebook->addPage(this->viewEmotes_, "Emotes");
|
||||
notebook->addPage(this->viewEmojis_, "Emojis");
|
||||
|
||||
this->loadEmojis();
|
||||
|
||||
this->viewEmotes_->linkClicked.connect(
|
||||
[this](const Link &link) { this->linkClicked.invoke(link); });
|
||||
this->viewEmojis_->linkClicked.connect(
|
||||
[this](const Link &link) { this->linkClicked.invoke(link); });
|
||||
}
|
||||
|
||||
void EmotePopup::loadChannel(ChannelPtr _channel)
|
||||
{
|
||||
this->setWindowTitle("Emotes from " + _channel->getName());
|
||||
|
||||
TwitchChannel *channel = dynamic_cast<TwitchChannel *>(_channel.get());
|
||||
|
||||
if (channel == nullptr) {
|
||||
return;
|
||||
namespace {
|
||||
auto makeTitleMessage(const QString &title)
|
||||
{
|
||||
MessageBuilder builder;
|
||||
builder.emplace<TextElement>(title, MessageElementFlag::Text);
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
return builder.release();
|
||||
}
|
||||
auto makeEmoteMessage(const EmoteMap &map)
|
||||
{
|
||||
MessageBuilder builder;
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
builder->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
ChannelPtr emoteChannel(new Channel("", Channel::Type::None));
|
||||
|
||||
auto addEmotes = [&](const EmoteMap &map, const QString &title,
|
||||
const QString &emoteDesc) {
|
||||
// TITLE
|
||||
MessageBuilder builder1;
|
||||
|
||||
builder1.emplace<TextElement>(title, MessageElementFlag::Text);
|
||||
|
||||
builder1->flags.set(MessageFlag::Centered);
|
||||
emoteChannel->addMessage(builder1.release());
|
||||
|
||||
// EMOTES
|
||||
MessageBuilder builder2;
|
||||
builder2->flags.set(MessageFlag::Centered);
|
||||
builder2->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
for (auto emote : map) {
|
||||
builder2
|
||||
for (const auto &emote : map) {
|
||||
builder
|
||||
.emplace<EmoteElement>(emote.second,
|
||||
MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.first.string));
|
||||
}
|
||||
|
||||
emoteChannel->addMessage(builder2.release());
|
||||
return builder.release();
|
||||
}
|
||||
void addEmoteSets(
|
||||
std::vector<std::shared_ptr<TwitchAccount::EmoteSet>> sets,
|
||||
Channel &globalChannel, Channel &subChannel)
|
||||
{
|
||||
for (const auto &set : sets) {
|
||||
auto &channel = set->key == "0" ? globalChannel : subChannel;
|
||||
|
||||
// TITLE
|
||||
auto text =
|
||||
set->key == "0" || set->text.isEmpty() ? "Twitch" : set->text;
|
||||
channel.addMessage(makeTitleMessage(text));
|
||||
|
||||
// EMOTES
|
||||
MessageBuilder builder;
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
builder->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
|
||||
for (const auto &emote : set->emotes) {
|
||||
builder
|
||||
.emplace<EmoteElement>(
|
||||
getApp()->emotes->twitch.getOrCreateEmote(emote.id,
|
||||
emote.name),
|
||||
MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.name.string));
|
||||
}
|
||||
|
||||
channel.addMessage(builder.release());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
EmotePopup::EmotePopup()
|
||||
: BaseWindow(nullptr, BaseWindow::EnableCustomFrame)
|
||||
{
|
||||
auto layout = new QVBoxLayout(this);
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
|
||||
auto notebook = new Notebook(this);
|
||||
layout->addWidget(notebook);
|
||||
layout->setMargin(0);
|
||||
|
||||
auto clicked = [this](const Link &link) { this->linkClicked.invoke(link); };
|
||||
|
||||
auto makeView = [&](QString tabTitle) {
|
||||
auto view = new ChannelView();
|
||||
|
||||
view->setOverrideFlags(MessageElementFlags{
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
view->setEnableScrollingToBottom(false);
|
||||
notebook->addPage(view, tabTitle);
|
||||
view->linkClicked.connect(clicked);
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
auto app = getApp();
|
||||
this->subEmotesView_ = makeView("Subs");
|
||||
this->channelEmotesView_ = makeView("Channel");
|
||||
this->globalEmotesView_ = makeView("Global");
|
||||
this->viewEmojis_ = makeView("Emojis");
|
||||
|
||||
// fourtf: the entire emote manager needs to be refactored so there's no
|
||||
// point in trying to fix this pile of garbage
|
||||
for (const auto &set :
|
||||
app->accounts->twitch.getCurrent()->accessEmotes()->emoteSets) {
|
||||
// TITLE
|
||||
MessageBuilder builder1;
|
||||
this->loadEmojis();
|
||||
}
|
||||
|
||||
QString setText;
|
||||
if (set->text.isEmpty()) {
|
||||
if (set->channelName.isEmpty()) {
|
||||
setText = "Twitch Account Emotes";
|
||||
} else {
|
||||
setText = "Twitch Account Emotes (" + set->channelName + ")";
|
||||
}
|
||||
} else {
|
||||
setText = set->text;
|
||||
}
|
||||
void EmotePopup::loadChannel(ChannelPtr _channel)
|
||||
{
|
||||
BenchmarkGuard guard("loadChannel");
|
||||
|
||||
builder1.emplace<TextElement>(setText, MessageElementFlag::Text);
|
||||
this->setWindowTitle("Emotes from " + _channel->getName());
|
||||
|
||||
builder1->flags.set(MessageFlag::Centered);
|
||||
emoteChannel->addMessage(builder1.release());
|
||||
auto twitchChannel = dynamic_cast<TwitchChannel *>(_channel.get());
|
||||
if (twitchChannel == nullptr) return;
|
||||
|
||||
// EMOTES
|
||||
MessageBuilder builder2;
|
||||
builder2->flags.set(MessageFlag::Centered);
|
||||
builder2->flags.set(MessageFlag::DisableCompactEmotes);
|
||||
auto addEmotes = [&](Channel &channel, const EmoteMap &map,
|
||||
const QString &title) {
|
||||
channel.addMessage(makeTitleMessage(title));
|
||||
channel.addMessage(makeEmoteMessage(map));
|
||||
};
|
||||
|
||||
for (const auto &emote : set->emotes) {
|
||||
builder2
|
||||
.emplace<EmoteElement>(
|
||||
app->emotes->twitch.getOrCreateEmote(emote.id, emote.name),
|
||||
MessageElementFlag::AlwaysShow)
|
||||
->setLink(Link(Link::InsertText, emote.name.string));
|
||||
}
|
||||
auto subChannel = std::make_shared<Channel>("", Channel::Type::None);
|
||||
auto globalChannel = std::make_shared<Channel>("", Channel::Type::None);
|
||||
auto channelChannel = std::make_shared<Channel>("", Channel::Type::None);
|
||||
|
||||
emoteChannel->addMessage(builder2.release());
|
||||
}
|
||||
// twitch
|
||||
addEmoteSets(
|
||||
getApp()->accounts->twitch.getCurrent()->accessEmotes()->emoteSets,
|
||||
*globalChannel, *subChannel);
|
||||
|
||||
addEmotes(*app->emotes->bttv.accessGlobalEmotes(),
|
||||
"BetterTTV Global Emotes", "BetterTTV Global Emote");
|
||||
addEmotes(*channel->accessBttvEmotes(), "BetterTTV Channel Emotes",
|
||||
"BetterTTV Channel Emote");
|
||||
// addEmotes(*app->emotes->ffz.accessGlobalEmotes(), "FrankerFaceZ Global
|
||||
// Emotes",
|
||||
// "FrankerFaceZ Global Emote");
|
||||
addEmotes(*channel->accessFfzEmotes(), "FrankerFaceZ Channel Emotes",
|
||||
"FrankerFaceZ Channel Emote");
|
||||
// global
|
||||
addEmotes(*globalChannel, *twitchChannel->globalBttv().emotes(),
|
||||
"BetterTTV");
|
||||
addEmotes(*globalChannel, *twitchChannel->globalFfz().emotes(),
|
||||
"FrankerFaceZ");
|
||||
|
||||
this->viewEmotes_->setChannel(emoteChannel);
|
||||
// channel
|
||||
addEmotes(*channelChannel, *twitchChannel->bttvEmotes(), "BetterTTV");
|
||||
addEmotes(*channelChannel, *twitchChannel->ffzEmotes(), "FrankerFaceZ");
|
||||
|
||||
this->globalEmotesView_->setChannel(globalChannel);
|
||||
this->subEmotesView_->setChannel(subChannel);
|
||||
this->channelEmotesView_->setChannel(channelChannel);
|
||||
}
|
||||
|
||||
void EmotePopup::loadEmojis()
|
||||
@@ -143,13 +147,6 @@ void EmotePopup::loadEmojis()
|
||||
|
||||
ChannelPtr emojiChannel(new Channel("", Channel::Type::None));
|
||||
|
||||
// title
|
||||
MessageBuilder builder1;
|
||||
|
||||
builder1.emplace<TextElement>("emojis", MessageElementFlag::Text);
|
||||
builder1->flags.set(MessageFlag::Centered);
|
||||
emojiChannel->addMessage(builder1.release());
|
||||
|
||||
// emojis
|
||||
MessageBuilder builder;
|
||||
builder->flags.set(MessageFlag::Centered);
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Link;
|
||||
class ChannelView;
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
|
||||
class EmotePopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
@@ -19,8 +22,10 @@ public:
|
||||
pajlada::Signals::Signal<Link> linkClicked;
|
||||
|
||||
private:
|
||||
ChannelView *viewEmotes_;
|
||||
ChannelView *viewEmojis_;
|
||||
ChannelView *globalEmotesView_{};
|
||||
ChannelView *channelEmotesView_{};
|
||||
ChannelView *subEmotesView_{};
|
||||
ChannelView *viewEmojis_{};
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "widgets/dialogs/LoginDialog.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "providers/twitch/PartialTwitchUser.hpp"
|
||||
|
||||
#ifdef USEWINSDK
|
||||
#include <Windows.h>
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <QClipboard>
|
||||
@@ -20,54 +21,54 @@ namespace chatterino {
|
||||
|
||||
namespace {
|
||||
|
||||
void LogInWithCredentials(const std::string &userID,
|
||||
const std::string &username,
|
||||
const std::string &clientID,
|
||||
const std::string &oauthToken)
|
||||
{
|
||||
QStringList errors;
|
||||
void LogInWithCredentials(const std::string &userID,
|
||||
const std::string &username,
|
||||
const std::string &clientID,
|
||||
const std::string &oauthToken)
|
||||
{
|
||||
QStringList errors;
|
||||
|
||||
if (userID.empty()) {
|
||||
errors.append("Missing user ID");
|
||||
if (userID.empty()) {
|
||||
errors.append("Missing user ID");
|
||||
}
|
||||
if (username.empty()) {
|
||||
errors.append("Missing username");
|
||||
}
|
||||
if (clientID.empty()) {
|
||||
errors.append("Missing Client ID");
|
||||
}
|
||||
if (oauthToken.empty()) {
|
||||
errors.append("Missing OAuth Token");
|
||||
}
|
||||
|
||||
if (errors.length() > 0) {
|
||||
QMessageBox messageBox;
|
||||
messageBox.setIcon(QMessageBox::Critical);
|
||||
messageBox.setText(errors.join("<br />"));
|
||||
messageBox.setStandardButtons(QMessageBox::Ok);
|
||||
messageBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
// QMessageBox messageBox;
|
||||
// messageBox.setIcon(QMessageBox::Information);
|
||||
// messageBox.setText("Successfully logged in with user <b>" +
|
||||
// qS(username) + "</b>!");
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/username", username);
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/userID", userID);
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/clientID", clientID);
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/oauthToken", oauthToken);
|
||||
|
||||
getApp()->accounts->twitch.reloadUsers();
|
||||
|
||||
// messageBox.exec();
|
||||
|
||||
getApp()->accounts->twitch.currentUsername = username;
|
||||
}
|
||||
if (username.empty()) {
|
||||
errors.append("Missing username");
|
||||
}
|
||||
if (clientID.empty()) {
|
||||
errors.append("Missing Client ID");
|
||||
}
|
||||
if (oauthToken.empty()) {
|
||||
errors.append("Missing OAuth Token");
|
||||
}
|
||||
|
||||
if (errors.length() > 0) {
|
||||
QMessageBox messageBox;
|
||||
messageBox.setIcon(QMessageBox::Critical);
|
||||
messageBox.setText(errors.join("<br />"));
|
||||
messageBox.setStandardButtons(QMessageBox::Ok);
|
||||
messageBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
// QMessageBox messageBox;
|
||||
// messageBox.setIcon(QMessageBox::Information);
|
||||
// messageBox.setText("Successfully logged in with user <b>" +
|
||||
// qS(username) + "</b>!");
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/username", username);
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/userID", userID);
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/clientID", clientID);
|
||||
pajlada::Settings::Setting<std::string>::set(
|
||||
"/accounts/uid" + userID + "/oauthToken", oauthToken);
|
||||
|
||||
getApp()->accounts->twitch.reloadUsers();
|
||||
|
||||
// messageBox.exec();
|
||||
|
||||
getApp()->accounts->twitch.currentUsername = username;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "LogsPopup.hpp"
|
||||
|
||||
#include "IrcMessage"
|
||||
#include "common/Channel.hpp"
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchMessageBuilder.hpp"
|
||||
@@ -14,6 +15,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
LogsPopup::LogsPopup()
|
||||
: channel_(Channel::getEmpty())
|
||||
{
|
||||
this->initLayout();
|
||||
this->resize(400, 600);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
@@ -8,6 +7,12 @@ namespace chatterino {
|
||||
class Channel;
|
||||
class ChannelView;
|
||||
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
|
||||
struct Message;
|
||||
using MessagePtr = std::shared_ptr<const Message>;
|
||||
|
||||
class LogsPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
@@ -17,7 +22,7 @@ public:
|
||||
|
||||
private:
|
||||
ChannelView *channelView_ = nullptr;
|
||||
ChannelPtr channel_ = Channel::getEmpty();
|
||||
ChannelPtr channel_;
|
||||
|
||||
QString userName_;
|
||||
int roomID_;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "NotificationPopup.hpp"
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ChannelView;
|
||||
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
|
||||
struct Message;
|
||||
using MessagePtr = std::shared_ptr<const Message>;
|
||||
|
||||
class NotificationPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -47,7 +47,7 @@ void QualityPopup::okButtonClicked()
|
||||
try {
|
||||
openStreamlink(channelURL, this->ui_.selector.currentText());
|
||||
} catch (const Exception &ex) {
|
||||
Log("Exception caught trying to open streamlink: {}", ex.what());
|
||||
log("Exception caught trying to open streamlink: {}", ex.what());
|
||||
}
|
||||
|
||||
this->close();
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "providers/twitch/TwitchServer.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class SelectChannelDialog : public BaseWindow
|
||||
class Notebook;
|
||||
|
||||
class SelectChannelDialog final : public BaseWindow
|
||||
{
|
||||
public:
|
||||
SelectChannelDialog(QWidget *parent = nullptr);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "widgets/helper/SettingsDialogTab.hpp"
|
||||
#include "widgets/settingspages/AboutPage.hpp"
|
||||
#include "widgets/settingspages/AccountsPage.hpp"
|
||||
#include "widgets/settingspages/AdvancedPage.hpp"
|
||||
#include "widgets/settingspages/BrowserExtensionPage.hpp"
|
||||
#include "widgets/settingspages/CommandPage.hpp"
|
||||
#include "widgets/settingspages/EmotesPage.hpp"
|
||||
@@ -105,6 +106,7 @@ void SettingsDialog::addTabs()
|
||||
// this->addTab(new SpecialChannelsPage);
|
||||
this->addTab(new BrowserExtensionPage);
|
||||
this->addTab(new ExternalToolsPage);
|
||||
this->addTab(new AdvancedPage);
|
||||
|
||||
this->ui_.tabContainer->addStretch(1);
|
||||
this->addTab(new AboutPage, Qt::AlignBottom);
|
||||
@@ -156,7 +158,7 @@ void SettingsDialog::showDialog(PreferredTab preferredTab)
|
||||
|
||||
void SettingsDialog::refresh()
|
||||
{
|
||||
getApp()->settings->saveSnapshot();
|
||||
getSettings()->saveSnapshot();
|
||||
|
||||
for (auto *tab : this->tabs_) {
|
||||
tab->getSettingsPage()->onShow();
|
||||
@@ -201,7 +203,7 @@ void SettingsDialog::onCancelClicked()
|
||||
tab->getSettingsPage()->cancel();
|
||||
}
|
||||
|
||||
getApp()->settings->restoreSnapshot();
|
||||
getSettings()->restoreSnapshot();
|
||||
|
||||
this->close();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "UserInfoPopup.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Channel.hpp"
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "controllers/highlights/HighlightController.hpp"
|
||||
@@ -11,8 +12,8 @@
|
||||
#include "util/PostToThread.hpp"
|
||||
#include "widgets/Label.hpp"
|
||||
#include "widgets/dialogs/LogsPopup.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/helper/Line.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDesktopServices>
|
||||
@@ -46,14 +47,13 @@ UserInfoPopup::UserInfoPopup()
|
||||
auto head = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
// avatar
|
||||
auto avatar = head.emplace<RippleEffectButton>(nullptr).assign(
|
||||
&this->ui_.avatarButton);
|
||||
auto avatar =
|
||||
head.emplace<Button>(nullptr).assign(&this->ui_.avatarButton);
|
||||
avatar->setScaleIndependantSize(100, 100);
|
||||
QObject::connect(avatar.getElement(), &RippleEffectButton::clicked,
|
||||
[this] {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl("https://twitch.tv/" + this->userName_));
|
||||
});
|
||||
QObject::connect(avatar.getElement(), &Button::clicked, [this] {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl("https://twitch.tv/" + this->userName_.toLower()));
|
||||
});
|
||||
|
||||
// items on the right
|
||||
auto vbox = head.emplace<QVBoxLayout>();
|
||||
@@ -82,33 +82,31 @@ UserInfoPopup::UserInfoPopup()
|
||||
user.emplace<QCheckBox>("Ignore").assign(&this->ui_.ignore);
|
||||
user.emplace<QCheckBox>("Ignore highlights")
|
||||
.assign(&this->ui_.ignoreHighlights);
|
||||
auto viewLogs = user.emplace<RippleEffectLabel2>(this);
|
||||
auto viewLogs = user.emplace<EffectLabel2>(this);
|
||||
viewLogs->getLabel().setText("Online logs");
|
||||
|
||||
auto mod = user.emplace<RippleEffectButton>(this);
|
||||
auto mod = user.emplace<Button>(this);
|
||||
mod->setPixmap(app->resources->buttons.mod);
|
||||
mod->setScaleIndependantSize(30, 30);
|
||||
auto unmod = user.emplace<RippleEffectButton>(this);
|
||||
auto unmod = user.emplace<Button>(this);
|
||||
unmod->setPixmap(app->resources->buttons.unmod);
|
||||
unmod->setScaleIndependantSize(30, 30);
|
||||
|
||||
user->addStretch(1);
|
||||
|
||||
QObject::connect(viewLogs.getElement(), &RippleEffectButton::clicked,
|
||||
[this] {
|
||||
auto logs = new LogsPopup();
|
||||
logs->setInfo(this->channel_, this->userName_);
|
||||
logs->setAttribute(Qt::WA_DeleteOnClose);
|
||||
logs->show();
|
||||
});
|
||||
QObject::connect(viewLogs.getElement(), &Button::clicked, [this] {
|
||||
auto logs = new LogsPopup();
|
||||
logs->setInfo(this->channel_, this->userName_);
|
||||
logs->setAttribute(Qt::WA_DeleteOnClose);
|
||||
logs->show();
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
mod.getElement(), &RippleEffectButton::clicked,
|
||||
[this] { this->channel_->sendMessage("/mod " + this->userName_); });
|
||||
QObject::connect(
|
||||
unmod.getElement(), &RippleEffectButton::clicked, [this] {
|
||||
this->channel_->sendMessage("/unmod " + this->userName_);
|
||||
});
|
||||
QObject::connect(mod.getElement(), &Button::clicked, [this] {
|
||||
this->channel_->sendMessage("/mod " + this->userName_);
|
||||
});
|
||||
QObject::connect(unmod.getElement(), &Button::clicked, [this] {
|
||||
this->channel_->sendMessage("/unmod " + this->userName_);
|
||||
});
|
||||
|
||||
// userstate
|
||||
this->userStateChanged_.connect([this, mod, unmod]() mutable {
|
||||
@@ -429,14 +427,13 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
||||
auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
|
||||
hbox->setSpacing(0);
|
||||
{
|
||||
auto button = hbox.emplace<RippleEffectButton>(nullptr);
|
||||
auto button = hbox.emplace<Button>(nullptr);
|
||||
button->setPixmap(pixmap);
|
||||
button->setScaleIndependantSize(buttonHeight, buttonHeight);
|
||||
button->setBorderColor(QColor(255, 255, 255, 127));
|
||||
|
||||
QObject::connect(
|
||||
button.getElement(), &RippleEffectButton::clicked,
|
||||
[this, action] {
|
||||
button.getElement(), &Button::clicked, [this, action] {
|
||||
this->buttonClicked.invoke(std::make_pair(action, -1));
|
||||
});
|
||||
}
|
||||
@@ -458,7 +455,7 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
||||
hbox->setSpacing(0);
|
||||
|
||||
for (const auto &item : items) {
|
||||
auto a = hbox.emplace<RippleEffectLabel2>();
|
||||
auto a = hbox.emplace<EffectLabel2>();
|
||||
a->getLabel().setText(std::get<0>(item));
|
||||
|
||||
if (std::get<0>(item).length() > 1) {
|
||||
@@ -468,7 +465,7 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
|
||||
}
|
||||
a->setBorderColor(color1);
|
||||
|
||||
QObject::connect(a.getElement(), &RippleEffectLabel2::clicked,
|
||||
QObject::connect(a.getElement(), &EffectLabel2::clicked,
|
||||
[this, timeout = std::get<1>(item)] {
|
||||
this->buttonClicked.invoke(std::make_pair(
|
||||
Action::Timeout, timeout));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
@@ -9,6 +8,8 @@ class QCheckBox;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
class Label;
|
||||
|
||||
class UserInfoPopup final : public BaseWindow
|
||||
@@ -40,7 +41,7 @@ private:
|
||||
std::shared_ptr<bool> hack_;
|
||||
|
||||
struct {
|
||||
RippleEffectButton *avatarButton = nullptr;
|
||||
Button *avatarButton = nullptr;
|
||||
// RippleEffectLabel2 *viewLogs = nullptr;
|
||||
|
||||
Label *nameLabel = nullptr;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "RippleEffectButton.hpp"
|
||||
#include "Button.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
@@ -10,11 +10,11 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
RippleEffectButton::RippleEffectButton(BaseWidget *parent)
|
||||
Button::Button(BaseWidget *parent)
|
||||
: BaseWidget(parent)
|
||||
{
|
||||
connect(&effectTimer_, &QTimer::timeout, this,
|
||||
&RippleEffectButton::onMouseEffectTimeout);
|
||||
&Button::onMouseEffectTimeout);
|
||||
|
||||
this->effectTimer_.setInterval(20);
|
||||
this->effectTimer_.start();
|
||||
@@ -22,64 +22,64 @@ RippleEffectButton::RippleEffectButton(BaseWidget *parent)
|
||||
this->setMouseTracking(true);
|
||||
}
|
||||
|
||||
void RippleEffectButton::setMouseEffectColor(boost::optional<QColor> color)
|
||||
void Button::setMouseEffectColor(boost::optional<QColor> color)
|
||||
{
|
||||
this->mouseEffectColor_ = color;
|
||||
}
|
||||
|
||||
void RippleEffectButton::setPixmap(const QPixmap &_pixmap)
|
||||
void Button::setPixmap(const QPixmap &_pixmap)
|
||||
{
|
||||
this->pixmap_ = _pixmap;
|
||||
this->update();
|
||||
}
|
||||
|
||||
const QPixmap &RippleEffectButton::getPixmap() const
|
||||
const QPixmap &Button::getPixmap() const
|
||||
{
|
||||
return this->pixmap_;
|
||||
}
|
||||
|
||||
void RippleEffectButton::setDim(bool value)
|
||||
void Button::setDim(bool value)
|
||||
{
|
||||
this->dimPixmap_ = value;
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
bool RippleEffectButton::getDim() const
|
||||
bool Button::getDim() const
|
||||
{
|
||||
return this->dimPixmap_;
|
||||
}
|
||||
|
||||
void RippleEffectButton::setEnable(bool value)
|
||||
void Button::setEnable(bool value)
|
||||
{
|
||||
this->enabled_ = value;
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
bool RippleEffectButton::getEnable() const
|
||||
bool Button::getEnable() const
|
||||
{
|
||||
return this->enabled_;
|
||||
}
|
||||
|
||||
qreal RippleEffectButton::getCurrentDimAmount() const
|
||||
qreal Button::getCurrentDimAmount() const
|
||||
{
|
||||
return this->dimPixmap_ && !this->mouseOver_ ? 0.7 : 1;
|
||||
}
|
||||
|
||||
void RippleEffectButton::setBorderColor(const QColor &color)
|
||||
void Button::setBorderColor(const QColor &color)
|
||||
{
|
||||
this->borderColor_ = color;
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
const QColor &RippleEffectButton::getBorderColor() const
|
||||
const QColor &Button::getBorderColor() const
|
||||
{
|
||||
return this->borderColor_;
|
||||
}
|
||||
|
||||
void RippleEffectButton::setMenu(std::unique_ptr<QMenu> menu)
|
||||
void Button::setMenu(std::unique_ptr<QMenu> menu)
|
||||
{
|
||||
this->menu_ = std::move(menu);
|
||||
|
||||
@@ -93,7 +93,7 @@ void RippleEffectButton::setMenu(std::unique_ptr<QMenu> menu)
|
||||
}));
|
||||
}
|
||||
|
||||
void RippleEffectButton::paintEvent(QPaintEvent *)
|
||||
void Button::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
@@ -126,7 +126,7 @@ void RippleEffectButton::paintEvent(QPaintEvent *)
|
||||
}
|
||||
}
|
||||
|
||||
void RippleEffectButton::fancyPaint(QPainter &painter)
|
||||
void Button::fancyPaint(QPainter &painter)
|
||||
{
|
||||
if (!this->enabled_) {
|
||||
return;
|
||||
@@ -169,17 +169,17 @@ void RippleEffectButton::fancyPaint(QPainter &painter)
|
||||
}
|
||||
}
|
||||
|
||||
void RippleEffectButton::enterEvent(QEvent *)
|
||||
void Button::enterEvent(QEvent *)
|
||||
{
|
||||
this->mouseOver_ = true;
|
||||
}
|
||||
|
||||
void RippleEffectButton::leaveEvent(QEvent *)
|
||||
void Button::leaveEvent(QEvent *)
|
||||
{
|
||||
this->mouseOver_ = false;
|
||||
}
|
||||
|
||||
void RippleEffectButton::mousePressEvent(QMouseEvent *event)
|
||||
void Button::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (!this->enabled_) {
|
||||
return;
|
||||
@@ -197,10 +197,12 @@ void RippleEffectButton::mousePressEvent(QMouseEvent *event)
|
||||
|
||||
if (this->menu_ && !this->menuVisible_) {
|
||||
QTimer::singleShot(80, this, [this] { this->showMenu(); });
|
||||
this->mouseDown_ = false;
|
||||
this->mouseOver_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RippleEffectButton::mouseReleaseEvent(QMouseEvent *event)
|
||||
void Button::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (!this->enabled_) {
|
||||
return;
|
||||
@@ -217,7 +219,7 @@ void RippleEffectButton::mouseReleaseEvent(QMouseEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void RippleEffectButton::mouseMoveEvent(QMouseEvent *event)
|
||||
void Button::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (!this->enabled_) {
|
||||
return;
|
||||
@@ -228,7 +230,7 @@ void RippleEffectButton::mouseMoveEvent(QMouseEvent *event)
|
||||
this->update();
|
||||
}
|
||||
|
||||
void RippleEffectButton::onMouseEffectTimeout()
|
||||
void Button::onMouseEffectTimeout()
|
||||
{
|
||||
bool performUpdate = false;
|
||||
|
||||
@@ -272,7 +274,7 @@ void RippleEffectButton::onMouseEffectTimeout()
|
||||
}
|
||||
}
|
||||
|
||||
void RippleEffectButton::showMenu()
|
||||
void Button::showMenu()
|
||||
{
|
||||
if (!this->menu_) return;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class RippleEffectButton : public BaseWidget
|
||||
class Button : public BaseWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -28,7 +28,7 @@ class RippleEffectButton : public BaseWidget
|
||||
};
|
||||
|
||||
public:
|
||||
RippleEffectButton(BaseWidget *parent);
|
||||
Button(BaseWidget *parent = nullptr);
|
||||
|
||||
void setMouseEffectColor(boost::optional<QColor> color);
|
||||
void setPixmap(const QPixmap &pixmap_);
|
||||
+184
-202
@@ -1,19 +1,25 @@
|
||||
#include "ChannelView.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "debug/Benchmark.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
#include "messages/LimitedQueueSnapshot.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "messages/MessageElement.hpp"
|
||||
#include "messages/layouts/MessageLayout.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "messages/layouts/MessageLayoutElement.hpp"
|
||||
#include "providers/twitch/TwitchServer.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/DistanceBetweenPoints.hpp"
|
||||
#include "widgets/Scrollbar.hpp"
|
||||
#include "widgets/TooltipWidget.hpp"
|
||||
#include "widgets/dialogs/UserInfoPopup.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
#include <QClipboard>
|
||||
@@ -34,132 +40,73 @@
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
void addEmoteContextMenuItems(const Emote &emote,
|
||||
MessageElementFlags creatorFlags, QMenu &menu)
|
||||
{
|
||||
auto openAction = menu.addAction("Open");
|
||||
auto openMenu = new QMenu;
|
||||
openAction->setMenu(openMenu);
|
||||
void addEmoteContextMenuItems(const Emote &emote,
|
||||
MessageElementFlags creatorFlags, QMenu &menu)
|
||||
{
|
||||
auto openAction = menu.addAction("Open");
|
||||
auto openMenu = new QMenu;
|
||||
openAction->setMenu(openMenu);
|
||||
|
||||
auto copyAction = menu.addAction("Copy");
|
||||
auto copyMenu = new QMenu;
|
||||
copyAction->setMenu(copyMenu);
|
||||
auto copyAction = menu.addAction("Copy");
|
||||
auto copyMenu = new QMenu;
|
||||
copyAction->setMenu(copyMenu);
|
||||
|
||||
// see if the QMenu actually gets destroyed
|
||||
QObject::connect(openMenu, &QMenu::destroyed, [] {
|
||||
QMessageBox(QMessageBox::Information, "xD", "the menu got deleted")
|
||||
.exec();
|
||||
});
|
||||
// see if the QMenu actually gets destroyed
|
||||
QObject::connect(openMenu, &QMenu::destroyed, [] {
|
||||
QMessageBox(QMessageBox::Information, "xD", "the menu got deleted")
|
||||
.exec();
|
||||
});
|
||||
|
||||
// Add copy and open links for 1x, 2x, 3x
|
||||
auto addImageLink = [&](const ImagePtr &image, char scale) {
|
||||
if (!image->isEmpty()) {
|
||||
copyMenu->addAction(
|
||||
QString(scale) + "x link", [url = image->url()] {
|
||||
QApplication::clipboard()->setText(url.string);
|
||||
});
|
||||
openMenu->addAction(
|
||||
QString(scale) + "x link", [url = image->url()] {
|
||||
QDesktopServices::openUrl(QUrl(url.string));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
addImageLink(emote.images.getImage1(), '1');
|
||||
addImageLink(emote.images.getImage2(), '2');
|
||||
addImageLink(emote.images.getImage3(), '3');
|
||||
|
||||
// Copy and open emote page link
|
||||
auto addPageLink = [&](const QString &name) {
|
||||
copyMenu->addSeparator();
|
||||
openMenu->addSeparator();
|
||||
|
||||
// Add copy and open links for 1x, 2x, 3x
|
||||
auto addImageLink = [&](const ImagePtr &image, char scale) {
|
||||
if (!image->empty()) {
|
||||
copyMenu->addAction(
|
||||
QString(scale) + "x link", [url = image->url()] {
|
||||
QApplication::clipboard()->setText(url.string);
|
||||
"Copy " + name + " emote link", [url = emote.homePage] {
|
||||
QApplication::clipboard()->setText(url.string); //
|
||||
});
|
||||
openMenu->addAction(QString(scale) + "x link",
|
||||
[url = image->url()] {
|
||||
QDesktopServices::openUrl(QUrl(url.string));
|
||||
});
|
||||
openMenu->addAction(
|
||||
"Open " + name + " emote link", [url = emote.homePage] {
|
||||
QDesktopServices::openUrl(QUrl(url.string)); //
|
||||
});
|
||||
};
|
||||
|
||||
if (creatorFlags.has(MessageElementFlag::BttvEmote)) {
|
||||
addPageLink("BTTV");
|
||||
} else if (creatorFlags.has(MessageElementFlag::FfzEmote)) {
|
||||
addPageLink("FFZ");
|
||||
}
|
||||
};
|
||||
|
||||
addImageLink(emote.images.getImage1(), '1');
|
||||
addImageLink(emote.images.getImage2(), '2');
|
||||
addImageLink(emote.images.getImage3(), '3');
|
||||
|
||||
// Copy and open emote page link
|
||||
auto addPageLink = [&](const QString &name) {
|
||||
copyMenu->addSeparator();
|
||||
openMenu->addSeparator();
|
||||
|
||||
copyMenu->addAction(
|
||||
"Copy " + name + " emote link", [url = emote.homePage] {
|
||||
QApplication::clipboard()->setText(url.string); //
|
||||
});
|
||||
openMenu->addAction("Open " + name + " emote link",
|
||||
[url = emote.homePage] {
|
||||
QDesktopServices::openUrl(QUrl(url.string)); //
|
||||
});
|
||||
};
|
||||
|
||||
if (creatorFlags.has(MessageElementFlag::BttvEmote)) {
|
||||
addPageLink("BTTV");
|
||||
} else if (creatorFlags.has(MessageElementFlag::FfzEmote)) {
|
||||
addPageLink("FFZ");
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ChannelView::ChannelView(BaseWidget *parent)
|
||||
: BaseWidget(parent)
|
||||
, scrollBar_(this)
|
||||
, scrollBar_(new Scrollbar(this))
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
this->setMouseTracking(true);
|
||||
|
||||
this->connections_.push_back(app->windows->wordFlagsChanged.connect([this] {
|
||||
this->layoutMessages();
|
||||
this->update();
|
||||
}));
|
||||
|
||||
this->scrollBar_.getCurrentValueChanged().connect([this] {
|
||||
// Whenever the scrollbar value has been changed, re-render the
|
||||
// ChatWidgetView
|
||||
this->actuallyLayoutMessages(true);
|
||||
|
||||
// if (!this->isPaused()) {
|
||||
this->goToBottom_->setVisible(this->enableScrollingToBottom_ &&
|
||||
this->scrollBar_.isVisible() &&
|
||||
!this->scrollBar_.isAtBottom());
|
||||
// }
|
||||
|
||||
this->queueUpdate();
|
||||
});
|
||||
|
||||
this->scrollBar_.getDesiredValueChanged().connect([this] {
|
||||
this->pausedByScrollingUp_ = !this->scrollBar_.isAtBottom();
|
||||
});
|
||||
|
||||
this->connections_.push_back(app->windows->repaintGifs.connect([&] {
|
||||
this->queueUpdate(); //
|
||||
}));
|
||||
|
||||
this->connections_.push_back(
|
||||
app->windows->layout.connect([&](Channel *channel) {
|
||||
if (channel == nullptr || this->channel_.get() == channel) {
|
||||
this->layoutMessages();
|
||||
}
|
||||
}));
|
||||
|
||||
this->goToBottom_ = new RippleEffectLabel(this, 0);
|
||||
this->goToBottom_->setStyleSheet(
|
||||
"background-color: rgba(0,0,0,0.66); color: #FFF;");
|
||||
this->goToBottom_->getLabel().setText("More messages below");
|
||||
this->goToBottom_->setVisible(false);
|
||||
|
||||
this->connections_.emplace_back(app->fonts->fontChanged.connect([this] {
|
||||
this->layoutMessages(); //
|
||||
}));
|
||||
|
||||
QObject::connect(this->goToBottom_, &RippleEffectLabel::clicked, this, [=] {
|
||||
QTimer::singleShot(180, [=] {
|
||||
this->scrollBar_.scrollToBottom(
|
||||
app->settings->enableSmoothScrollingNewMessages.getValue());
|
||||
});
|
||||
});
|
||||
|
||||
// this->updateTimer.setInterval(1000 / 60);
|
||||
// this->updateTimer.setSingleShot(true);
|
||||
// connect(&this->updateTimer, &QTimer::timeout, this, [this] {
|
||||
// if (this->updateQueued) {
|
||||
// this->updateQueued = false;
|
||||
// this->repaint();
|
||||
// this->updateTimer.start();
|
||||
// }
|
||||
// });
|
||||
this->initializeLayout();
|
||||
this->initializeScrollbar();
|
||||
this->initializeSignals();
|
||||
|
||||
this->pauseTimeout_.setSingleShot(true);
|
||||
QObject::connect(&this->pauseTimeout_, &QTimer::timeout, [this] {
|
||||
@@ -168,31 +115,67 @@ ChannelView::ChannelView(BaseWidget *parent)
|
||||
this->layoutMessages();
|
||||
});
|
||||
|
||||
app->settings->showLastMessageIndicator.connect(
|
||||
[this](auto, auto) {
|
||||
this->update(); //
|
||||
},
|
||||
this->connections_);
|
||||
|
||||
this->layoutCooldown_ = new QTimer(this);
|
||||
this->layoutCooldown_->setSingleShot(true);
|
||||
this->layoutCooldown_->setInterval(66);
|
||||
|
||||
QObject::connect(this->layoutCooldown_, &QTimer::timeout, [this] {
|
||||
if (this->layoutQueued_) {
|
||||
this->layoutMessages();
|
||||
this->layoutQueued_ = false;
|
||||
}
|
||||
});
|
||||
|
||||
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+C"), this);
|
||||
auto shortcut = new QShortcut(QKeySequence("Ctrl+C"), this);
|
||||
QObject::connect(shortcut, &QShortcut::activated, [this] {
|
||||
QGuiApplication::clipboard()->setText(this->getSelectedText());
|
||||
});
|
||||
}
|
||||
|
||||
ChannelView::~ChannelView()
|
||||
void ChannelView::initializeLayout()
|
||||
{
|
||||
this->goToBottom_ = new EffectLabel(this, 0);
|
||||
this->goToBottom_->setStyleSheet(
|
||||
"background-color: rgba(0,0,0,0.66); color: #FFF;");
|
||||
this->goToBottom_->getLabel().setText("More messages below");
|
||||
this->goToBottom_->setVisible(false);
|
||||
|
||||
QObject::connect(this->goToBottom_, &EffectLabel::clicked, this, [=] {
|
||||
QTimer::singleShot(180, [=] {
|
||||
this->scrollBar_->scrollToBottom(
|
||||
getSettings()->enableSmoothScrollingNewMessages.getValue());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelView::initializeScrollbar()
|
||||
{
|
||||
this->scrollBar_->getCurrentValueChanged().connect([this] {
|
||||
this->actuallyLayoutMessages(true);
|
||||
|
||||
this->goToBottom_->setVisible(this->enableScrollingToBottom_ &&
|
||||
this->scrollBar_->isVisible() &&
|
||||
!this->scrollBar_->isAtBottom());
|
||||
|
||||
this->queueUpdate();
|
||||
});
|
||||
|
||||
this->scrollBar_->getDesiredValueChanged().connect([this] {
|
||||
this->pausedByScrollingUp_ = !this->scrollBar_->isAtBottom();
|
||||
});
|
||||
}
|
||||
|
||||
void ChannelView::initializeSignals()
|
||||
{
|
||||
this->connections_.push_back(
|
||||
getApp()->windows->wordFlagsChanged.connect([this] {
|
||||
this->layoutMessages();
|
||||
this->update();
|
||||
}));
|
||||
|
||||
getSettings()->showLastMessageIndicator.connect(
|
||||
[this](auto, auto) { this->update(); }, this->connections_);
|
||||
|
||||
connections_.push_back(
|
||||
getApp()->windows->repaintGifs.connect([&] { this->queueUpdate(); }));
|
||||
|
||||
connections_.push_back(
|
||||
getApp()->windows->layout.connect([&](Channel *channel) {
|
||||
if (channel == nullptr || this->channel_.get() == channel)
|
||||
this->layoutMessages();
|
||||
}));
|
||||
|
||||
connections_.push_back(getApp()->fonts->fontChanged.connect(
|
||||
[this] { this->layoutMessages(); }));
|
||||
}
|
||||
|
||||
void ChannelView::themeChangedEvent()
|
||||
@@ -228,14 +211,12 @@ void ChannelView::layoutMessages()
|
||||
|
||||
void ChannelView::actuallyLayoutMessages(bool causedByScrollbar)
|
||||
{
|
||||
// BenchmarkGuard benchmark("layout messages");
|
||||
|
||||
auto app = getApp();
|
||||
// BenchmarkGuard benchmark("layout");
|
||||
|
||||
auto messagesSnapshot = this->getMessagesSnapshot();
|
||||
|
||||
if (messagesSnapshot.getLength() == 0) {
|
||||
this->scrollBar_.setVisible(false);
|
||||
this->scrollBar_->setVisible(false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -248,9 +229,9 @@ void ChannelView::actuallyLayoutMessages(bool causedByScrollbar)
|
||||
// The scrollbar was not visible
|
||||
// The scrollbar was visible and at the bottom
|
||||
this->showingLatestMessages_ =
|
||||
this->scrollBar_.isAtBottom() || !this->scrollBar_.isVisible();
|
||||
this->scrollBar_->isAtBottom() || !this->scrollBar_->isVisible();
|
||||
|
||||
size_t start = size_t(this->scrollBar_.getCurrentValue());
|
||||
size_t start = size_t(this->scrollBar_->getCurrentValue());
|
||||
int layoutWidth = this->getLayoutWidth();
|
||||
|
||||
MessageElementFlags flags = this->getFlags();
|
||||
@@ -258,7 +239,7 @@ void ChannelView::actuallyLayoutMessages(bool causedByScrollbar)
|
||||
// layout the visible messages in the view
|
||||
if (messagesSnapshot.getLength() > start) {
|
||||
int y = int(-(messagesSnapshot[start]->getHeight() *
|
||||
(fmod(this->scrollBar_.getCurrentValue(), 1))));
|
||||
(fmod(this->scrollBar_->getCurrentValue(), 1))));
|
||||
|
||||
for (size_t i = start; i < messagesSnapshot.getLength(); ++i) {
|
||||
auto message = messagesSnapshot[i];
|
||||
@@ -285,8 +266,9 @@ void ChannelView::actuallyLayoutMessages(bool causedByScrollbar)
|
||||
h -= message->getHeight();
|
||||
|
||||
if (h < 0) {
|
||||
this->scrollBar_.setLargeChange((messagesSnapshot.getLength() - i) +
|
||||
qreal(h) / message->getHeight());
|
||||
this->scrollBar_->setLargeChange(
|
||||
(messagesSnapshot.getLength() - i) +
|
||||
qreal(h) / message->getHeight());
|
||||
// this->scrollBar.setDesiredValue(this->scrollBar.getDesiredValue());
|
||||
|
||||
showScrollbar = true;
|
||||
@@ -294,22 +276,22 @@ void ChannelView::actuallyLayoutMessages(bool causedByScrollbar)
|
||||
}
|
||||
}
|
||||
|
||||
this->scrollBar_.setVisible(showScrollbar);
|
||||
this->scrollBar_->setVisible(showScrollbar);
|
||||
|
||||
if (!showScrollbar && !causedByScrollbar) {
|
||||
this->scrollBar_.setDesiredValue(0);
|
||||
this->scrollBar_->setDesiredValue(0);
|
||||
}
|
||||
|
||||
this->scrollBar_.setMaximum(messagesSnapshot.getLength());
|
||||
this->scrollBar_->setMaximum(messagesSnapshot.getLength());
|
||||
|
||||
// If we were showing the latest messages and the scrollbar now wants to be
|
||||
// rendered, scroll to bottom
|
||||
if (this->enableScrollingToBottom_ && this->showingLatestMessages_ &&
|
||||
showScrollbar) {
|
||||
if (!this->isPaused()) {
|
||||
this->scrollBar_.scrollToBottom(
|
||||
this->scrollBar_->scrollToBottom(
|
||||
// this->messageWasAdded &&
|
||||
app->settings->enableSmoothScrollingNewMessages.getValue());
|
||||
getSettings()->enableSmoothScrollingNewMessages.getValue());
|
||||
}
|
||||
this->messageWasAdded_ = false;
|
||||
}
|
||||
@@ -332,7 +314,7 @@ void ChannelView::clearMessages()
|
||||
|
||||
Scrollbar &ChannelView::getScrollBar()
|
||||
{
|
||||
return this->scrollBar_;
|
||||
return *this->scrollBar_;
|
||||
}
|
||||
|
||||
QString ChannelView::getSelectedText()
|
||||
@@ -401,7 +383,7 @@ const boost::optional<MessageElementFlags> &ChannelView::getOverrideFlags()
|
||||
|
||||
LimitedQueueSnapshot<MessageLayoutPtr> ChannelView::getMessagesSnapshot()
|
||||
{
|
||||
if (!this->isPaused() /*|| this->scrollBar_.isVisible()*/) {
|
||||
if (!this->isPaused() /*|| this->scrollBar_->isVisible()*/) {
|
||||
this->snapshot_ = this->messages.getSnapshot();
|
||||
}
|
||||
|
||||
@@ -436,10 +418,10 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||
if (this->messages.pushBack(MessageLayoutPtr(messageRef),
|
||||
deleted)) {
|
||||
// if (!this->isPaused()) {
|
||||
if (this->scrollBar_.isAtBottom()) {
|
||||
this->scrollBar_.scrollToBottom();
|
||||
if (this->scrollBar_->isAtBottom()) {
|
||||
this->scrollBar_->scrollToBottom();
|
||||
} else {
|
||||
this->scrollBar_.offset(-1);
|
||||
this->scrollBar_->offset(-1);
|
||||
}
|
||||
// }
|
||||
}
|
||||
@@ -454,7 +436,7 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||
}
|
||||
}
|
||||
|
||||
this->scrollBar_.addHighlight(message->getScrollBarHighlight());
|
||||
this->scrollBar_->addHighlight(message->getScrollBarHighlight());
|
||||
|
||||
this->messageWasAdded_ = true;
|
||||
this->layoutMessages();
|
||||
@@ -472,10 +454,10 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||
|
||||
if (!this->isPaused()) {
|
||||
if (this->messages.pushFront(messageRefs).size() > 0) {
|
||||
if (this->scrollBar_.isAtBottom()) {
|
||||
this->scrollBar_.scrollToBottom();
|
||||
if (this->scrollBar_->isAtBottom()) {
|
||||
this->scrollBar_->scrollToBottom();
|
||||
} else {
|
||||
this->scrollBar_.offset(qreal(messages.size()));
|
||||
this->scrollBar_->offset(qreal(messages.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,7 +469,7 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||
messages.at(i)->getScrollBarHighlight());
|
||||
}
|
||||
|
||||
this->scrollBar_.addHighlightsAtStart(highlights);
|
||||
this->scrollBar_->addHighlightsAtStart(highlights);
|
||||
|
||||
this->messageWasAdded_ = true;
|
||||
this->layoutMessages();
|
||||
@@ -515,7 +497,7 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||
MessageLayoutPtr newItem(new MessageLayout(replacement));
|
||||
auto snapshot = this->messages.getSnapshot();
|
||||
if (index >= snapshot.getLength()) {
|
||||
Log("Tried to replace out of bounds message. Index: {}. "
|
||||
log("Tried to replace out of bounds message. Index: {}. "
|
||||
"Length: {}",
|
||||
index, snapshot.getLength());
|
||||
return;
|
||||
@@ -526,7 +508,7 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||
newItem->flags.set(MessageLayoutFlag::AlternateBackground);
|
||||
}
|
||||
|
||||
this->scrollBar_.replaceHighlight(
|
||||
this->scrollBar_->replaceHighlight(
|
||||
index, replacement->getScrollBarHighlight());
|
||||
|
||||
this->messages.replaceItem(message, newItem);
|
||||
@@ -594,12 +576,12 @@ void ChannelView::updateLastReadMessage()
|
||||
|
||||
void ChannelView::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
this->scrollBar_.setGeometry(this->width() - this->scrollBar_.width(), 0,
|
||||
this->scrollBar_.width(), this->height());
|
||||
this->scrollBar_->setGeometry(this->width() - this->scrollBar_->width(), 0,
|
||||
this->scrollBar_->width(), this->height());
|
||||
|
||||
this->goToBottom_->setGeometry(0, this->height() - 32, this->width(), 32);
|
||||
|
||||
this->scrollBar_.raise();
|
||||
this->scrollBar_->raise();
|
||||
|
||||
this->layoutMessages();
|
||||
|
||||
@@ -656,15 +638,15 @@ bool ChannelView::isPaused()
|
||||
void ChannelView::updatePauseStatus()
|
||||
{
|
||||
if (this->isPaused()) {
|
||||
this->scrollBar_.pauseHighlights();
|
||||
this->scrollBar_->pauseHighlights();
|
||||
} else {
|
||||
this->scrollBar_.unpauseHighlights();
|
||||
this->scrollBar_->unpauseHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelView::paintEvent(QPaintEvent * /*event*/)
|
||||
{
|
||||
// BenchmarkGuard benchmark("paint event");
|
||||
// BenchmarkGuard benchmark("paint");
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
@@ -678,18 +660,16 @@ void ChannelView::paintEvent(QPaintEvent * /*event*/)
|
||||
// such as the grey overlay when a message is disabled
|
||||
void ChannelView::drawMessages(QPainter &painter)
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
auto messagesSnapshot = this->getMessagesSnapshot();
|
||||
|
||||
size_t start = size_t(this->scrollBar_.getCurrentValue());
|
||||
size_t start = size_t(this->scrollBar_->getCurrentValue());
|
||||
|
||||
if (start >= messagesSnapshot.getLength()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int y = int(-(messagesSnapshot[start].get()->getHeight() *
|
||||
(fmod(this->scrollBar_.getCurrentValue(), 1))));
|
||||
(fmod(this->scrollBar_->getCurrentValue(), 1))));
|
||||
|
||||
MessageLayout *end = nullptr;
|
||||
bool windowFocused = this->window() == QApplication::activeWindow();
|
||||
@@ -698,7 +678,7 @@ void ChannelView::drawMessages(QPainter &painter)
|
||||
MessageLayout *layout = messagesSnapshot[i].get();
|
||||
|
||||
bool isLastMessage = false;
|
||||
if (app->settings->showLastMessageIndicator) {
|
||||
if (getSettings()->showLastMessageIndicator) {
|
||||
isLastMessage = this->lastReadMessage_.get() == layout;
|
||||
}
|
||||
|
||||
@@ -760,12 +740,10 @@ void ChannelView::wheelEvent(QWheelEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->scrollBar_.isVisible()) {
|
||||
auto app = getApp();
|
||||
if (this->scrollBar_->isVisible()) {
|
||||
float mouseMultiplier = getSettings()->mouseScrollMultiplier;
|
||||
|
||||
float mouseMultiplier = app->settings->mouseScrollMultiplier;
|
||||
|
||||
qreal desired = this->scrollBar_.getDesiredValue();
|
||||
qreal desired = this->scrollBar_->getDesiredValue();
|
||||
qreal delta = event->delta() * qreal(1.5) * mouseMultiplier;
|
||||
|
||||
auto snapshot = this->getMessagesSnapshot();
|
||||
@@ -823,7 +801,7 @@ void ChannelView::wheelEvent(QWheelEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
this->scrollBar_.setDesiredValue(desired, true);
|
||||
this->scrollBar_->setDesiredValue(desired, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,9 +826,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
if (app->settings->pauseChatHover.getValue()) {
|
||||
if (getSettings()->pauseChatHover.getValue()) {
|
||||
this->pause(CHAT_HOVER_PAUSE_DURATION);
|
||||
}
|
||||
|
||||
@@ -915,8 +891,6 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
|
||||
void ChannelView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
this->mouseDown.invoke(event);
|
||||
|
||||
std::shared_ptr<MessageLayout> layout;
|
||||
@@ -953,7 +927,7 @@ void ChannelView::mousePressEvent(QMouseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->settings->linksDoubleClickOnly.getValue()) {
|
||||
if (getSettings()->linksDoubleClickOnly.getValue()) {
|
||||
this->pause(200);
|
||||
}
|
||||
|
||||
@@ -1058,19 +1032,28 @@ void ChannelView::handleMouseClick(QMouseEvent *event,
|
||||
}
|
||||
|
||||
auto &link = hoveredElement->getLink();
|
||||
if (!getApp()->settings->linksDoubleClickOnly) {
|
||||
if (!getSettings()->linksDoubleClickOnly) {
|
||||
this->handleLinkClick(event, link, layout);
|
||||
}
|
||||
|
||||
// Invoke to signal from EmotePopup.
|
||||
if (link.type == Link::InsertText) {
|
||||
this->linkClicked.invoke(link);
|
||||
}
|
||||
} break;
|
||||
case Qt::RightButton: {
|
||||
|
||||
auto insertText = [=](QString text) {
|
||||
if (auto split = dynamic_cast<Split *>(this->parentWidget())) {
|
||||
split->insertTextToInput(text);
|
||||
}
|
||||
};
|
||||
|
||||
auto &link = hoveredElement->getLink();
|
||||
if (link.type == Link::UserInfo) {
|
||||
Split *split = dynamic_cast<Split *>(this->parentWidget());
|
||||
if (split != nullptr) {
|
||||
split->insertTextToInput("@" + link.value + ", ");
|
||||
}
|
||||
insertText("@" + link.value + ", ");
|
||||
} else if (link.type == Link::UserWhisper) {
|
||||
insertText("/w " + link.value + " ");
|
||||
} else {
|
||||
this->addContextMenuItems(hoveredElement, layout);
|
||||
}
|
||||
@@ -1123,17 +1106,18 @@ void ChannelView::addContextMenuItems(
|
||||
|
||||
menu->addAction("Copy message", [layout] {
|
||||
QString copyString;
|
||||
layout->addSelectionText(copyString);
|
||||
layout->addSelectionText(copyString, 0, INT_MAX,
|
||||
CopyMode::OnlyTextAndEmotes);
|
||||
|
||||
QGuiApplication::clipboard()->setText(copyString);
|
||||
});
|
||||
|
||||
// menu->addAction("Quote message", [layout] {
|
||||
// QString copyString;
|
||||
// layout->addSelectionText(copyString);
|
||||
menu->addAction("Copy full message", [layout] {
|
||||
QString copyString;
|
||||
layout->addSelectionText(copyString);
|
||||
|
||||
// // insert into input
|
||||
// });
|
||||
QGuiApplication::clipboard()->setText(copyString);
|
||||
});
|
||||
|
||||
menu->popup(QCursor::pos());
|
||||
menu->raise();
|
||||
@@ -1143,9 +1127,7 @@ void ChannelView::addContextMenuItems(
|
||||
|
||||
void ChannelView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
if (app->settings->linksDoubleClickOnly) {
|
||||
if (getSettings()->linksDoubleClickOnly) {
|
||||
std::shared_ptr<MessageLayout> layout;
|
||||
QPoint relativePos;
|
||||
int messageIndex;
|
||||
@@ -1188,6 +1170,7 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
||||
}
|
||||
|
||||
switch (link.type) {
|
||||
case Link::UserWhisper:
|
||||
case Link::UserInfo: {
|
||||
auto user = link.value;
|
||||
|
||||
@@ -1200,19 +1183,18 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
||||
userPopup->show();
|
||||
|
||||
qDebug() << "Clicked " << user << "s message";
|
||||
break;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case Link::Url: {
|
||||
QDesktopServices::openUrl(QUrl(link.value));
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Link::UserAction: {
|
||||
QString value = link.value;
|
||||
value.replace("{user}", layout->getMessage()->loginName);
|
||||
this->channel_->sendMessage(value);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:;
|
||||
}
|
||||
@@ -1224,14 +1206,14 @@ bool ChannelView::tryGetMessageAt(QPoint p,
|
||||
{
|
||||
auto messagesSnapshot = this->getMessagesSnapshot();
|
||||
|
||||
size_t start = this->scrollBar_.getCurrentValue();
|
||||
size_t start = this->scrollBar_->getCurrentValue();
|
||||
|
||||
if (start >= messagesSnapshot.getLength()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int y = -(messagesSnapshot[start]->getHeight() *
|
||||
(fmod(this->scrollBar_.getCurrentValue(), 1)));
|
||||
(fmod(this->scrollBar_->getCurrentValue(), 1)));
|
||||
|
||||
for (size_t i = start; i < messagesSnapshot.getLength(); ++i) {
|
||||
auto message = messagesSnapshot[i];
|
||||
@@ -1251,7 +1233,7 @@ bool ChannelView::tryGetMessageAt(QPoint p,
|
||||
|
||||
int ChannelView::getLayoutWidth() const
|
||||
{
|
||||
if (this->scrollBar_.isVisible())
|
||||
if (this->scrollBar_->isVisible())
|
||||
return int(this->width() - 8 * this->getScale());
|
||||
|
||||
return this->width();
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/Image.hpp"
|
||||
#include "common/FlagsEnum.hpp"
|
||||
#include "messages/LimitedQueue.hpp"
|
||||
#include "messages/LimitedQueueSnapshot.hpp"
|
||||
#include "messages/MessageElement.hpp"
|
||||
#include "messages/Selection.hpp"
|
||||
#include "messages/layouts/MessageLayout.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/Scrollbar.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
|
||||
#include <QPaintEvent>
|
||||
#include <QScroller>
|
||||
@@ -20,14 +16,28 @@
|
||||
#include <unordered_set>
|
||||
|
||||
namespace chatterino {
|
||||
enum class HighlightState;
|
||||
|
||||
class ChannelView : public BaseWidget
|
||||
class Channel;
|
||||
using ChannelPtr = std::shared_ptr<Channel>;
|
||||
|
||||
class MessageLayout;
|
||||
using MessageLayoutPtr = std::shared_ptr<MessageLayout>;
|
||||
|
||||
enum class MessageElementFlag;
|
||||
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
|
||||
|
||||
class Scrollbar;
|
||||
class EffectLabel;
|
||||
struct Link;
|
||||
class MessageLayoutElement;
|
||||
|
||||
class ChannelView final : public BaseWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ChannelView(BaseWidget *parent = nullptr);
|
||||
virtual ~ChannelView() override;
|
||||
|
||||
void queueUpdate();
|
||||
Scrollbar &getScrollBar();
|
||||
@@ -77,6 +87,14 @@ protected:
|
||||
QPoint &relativePos, int &index);
|
||||
|
||||
private:
|
||||
void initializeLayout();
|
||||
void initializeScrollbar();
|
||||
void initializeSignals();
|
||||
|
||||
// void messageAppended(MessagePtr &message);
|
||||
// void messageAddedAtStart(std::vector<MessagePtr> &messages);
|
||||
// void messageRemoveFromStart(MessagePtr &message);
|
||||
|
||||
void updatePauseStatus();
|
||||
void detachChannel();
|
||||
void actuallyLayoutMessages(bool causedByScollbar = false);
|
||||
@@ -114,8 +132,8 @@ private:
|
||||
|
||||
ChannelPtr channel_;
|
||||
|
||||
Scrollbar scrollBar_;
|
||||
RippleEffectLabel *goToBottom_;
|
||||
Scrollbar *scrollBar_;
|
||||
EffectLabel *goToBottom_;
|
||||
|
||||
// This variable can be used to decide whether or not we should render the
|
||||
// "Show latest messages" button
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "widgets/splits/SplitHeader.hpp"
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
RippleEffectLabel::RippleEffectLabel(BaseWidget *parent, int spacing)
|
||||
: RippleEffectButton(parent)
|
||||
EffectLabel::EffectLabel(BaseWidget *parent, int spacing)
|
||||
: Button(parent)
|
||||
, label_(this)
|
||||
{
|
||||
setLayout(&this->hbox_);
|
||||
@@ -21,8 +21,8 @@ RippleEffectLabel::RippleEffectLabel(BaseWidget *parent, int spacing)
|
||||
this->hbox_.addSpacing(spacing);
|
||||
}
|
||||
|
||||
RippleEffectLabel2::RippleEffectLabel2(BaseWidget *parent, int padding)
|
||||
: RippleEffectButton(parent)
|
||||
EffectLabel2::EffectLabel2(BaseWidget *parent, int padding)
|
||||
: Button(parent)
|
||||
, label_(this)
|
||||
{
|
||||
auto *hbox = new QHBoxLayout(this);
|
||||
@@ -37,7 +37,7 @@ RippleEffectLabel2::RippleEffectLabel2(BaseWidget *parent, int padding)
|
||||
// hbox.addSpacing(spacing);
|
||||
}
|
||||
|
||||
Label &RippleEffectLabel2::getLabel()
|
||||
Label &EffectLabel2::getLabel()
|
||||
{
|
||||
return this->label_;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/Label.hpp"
|
||||
#include "widgets/helper/RippleEffectButton.hpp"
|
||||
#include "widgets/helper/Button.hpp"
|
||||
#include "widgets/helper/SignalLabel.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
@@ -12,10 +12,10 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class RippleEffectLabel : public RippleEffectButton
|
||||
class EffectLabel : public Button
|
||||
{
|
||||
public:
|
||||
explicit RippleEffectLabel(BaseWidget *parent = nullptr, int spacing = 6);
|
||||
explicit EffectLabel(BaseWidget *parent = nullptr, int spacing = 6);
|
||||
|
||||
SignalLabel &getLabel()
|
||||
{
|
||||
@@ -27,10 +27,10 @@ private:
|
||||
SignalLabel label_;
|
||||
};
|
||||
|
||||
class RippleEffectLabel2 : public RippleEffectButton
|
||||
class EffectLabel2 : public Button
|
||||
{
|
||||
public:
|
||||
explicit RippleEffectLabel2(BaseWidget *parent = nullptr, int padding = 6);
|
||||
explicit EffectLabel2(BaseWidget *parent = nullptr, int padding = 6);
|
||||
|
||||
Label &getLabel();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "widgets/helper/NotebookButton.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/helper/RippleEffectButton.hpp"
|
||||
#include "widgets/helper/Button.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
#include <QMouseEvent>
|
||||
@@ -14,7 +15,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
NotebookButton::NotebookButton(Notebook *parent)
|
||||
: RippleEffectButton(parent)
|
||||
: Button(parent)
|
||||
, parent_(parent)
|
||||
{
|
||||
this->setAcceptDrops(true);
|
||||
@@ -122,7 +123,7 @@ void NotebookButton::paintEvent(QPaintEvent *event)
|
||||
default:;
|
||||
}
|
||||
|
||||
RippleEffectButton::paintEvent(event);
|
||||
Button::paintEvent(event);
|
||||
}
|
||||
|
||||
void NotebookButton::mouseReleaseEvent(QMouseEvent *event)
|
||||
@@ -135,7 +136,7 @@ void NotebookButton::mouseReleaseEvent(QMouseEvent *event)
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
RippleEffectButton::mouseReleaseEvent(event);
|
||||
Button::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void NotebookButton::dragEnterEvent(QDragEnterEvent *event)
|
||||
@@ -149,7 +150,7 @@ void NotebookButton::dragEnterEvent(QDragEnterEvent *event)
|
||||
auto e = new QMouseEvent(QMouseEvent::MouseButtonPress,
|
||||
QPointF(this->width() / 2, this->height() / 2),
|
||||
Qt::LeftButton, Qt::LeftButton, 0);
|
||||
RippleEffectButton::mousePressEvent(e);
|
||||
Button::mousePressEvent(e);
|
||||
delete e;
|
||||
}
|
||||
|
||||
@@ -161,7 +162,7 @@ void NotebookButton::dragLeaveEvent(QDragLeaveEvent *)
|
||||
auto e = new QMouseEvent(QMouseEvent::MouseButtonRelease,
|
||||
QPointF(this->width() / 2, this->height() / 2),
|
||||
Qt::LeftButton, Qt::LeftButton, 0);
|
||||
RippleEffectButton::mouseReleaseEvent(e);
|
||||
Button::mouseReleaseEvent(e);
|
||||
delete e;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "RippleEffectButton.hpp"
|
||||
#include "Button.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace chatterino {
|
||||
|
||||
class Notebook;
|
||||
|
||||
class NotebookButton : public RippleEffectButton
|
||||
class NotebookButton : public Button
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Application.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "singletons/Fonts.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "util/Clamp.hpp"
|
||||
@@ -10,6 +11,7 @@
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
#include "widgets/dialogs/TextInputDialog.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
@@ -21,7 +23,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
NotebookTab::NotebookTab(Notebook *notebook)
|
||||
: RippleEffectButton(notebook)
|
||||
: Button(notebook)
|
||||
, positionChangedAnimation_(this, "pos")
|
||||
, notebook_(notebook)
|
||||
, menu_(this)
|
||||
@@ -33,7 +35,7 @@ NotebookTab::NotebookTab(Notebook *notebook)
|
||||
this->positionChangedAnimation_.setEasingCurve(
|
||||
QEasingCurve(QEasingCurve::InCubic));
|
||||
|
||||
app->settings->showTabCloseButton.connect(
|
||||
getSettings()->showTabCloseButton.connect(
|
||||
boost::bind(&NotebookTab::hideTabXChanged, this, _1),
|
||||
this->managedConnections_);
|
||||
|
||||
@@ -286,7 +288,7 @@ void NotebookTab::paintEvent(QPaintEvent *)
|
||||
painter.setPen(colors.text);
|
||||
|
||||
// set area for text
|
||||
int rectW = (!app->settings->showTabCloseButton ? 0 : int(16 * scale));
|
||||
int rectW = (!getSettings()->showTabCloseButton ? 0 : int(16 * scale));
|
||||
QRect rect(0, 0, this->width() - rectW, height);
|
||||
|
||||
// draw text
|
||||
@@ -341,7 +343,7 @@ void NotebookTab::paintEvent(QPaintEvent *)
|
||||
|
||||
bool NotebookTab::hasXButton()
|
||||
{
|
||||
return getApp()->settings->showTabCloseButton &&
|
||||
return getSettings()->showTabCloseButton &&
|
||||
this->notebook_->getAllowUserTabManagement();
|
||||
}
|
||||
|
||||
@@ -406,7 +408,7 @@ void NotebookTab::enterEvent(QEvent *event)
|
||||
|
||||
this->update();
|
||||
|
||||
RippleEffectButton::enterEvent(event);
|
||||
Button::enterEvent(event);
|
||||
}
|
||||
|
||||
void NotebookTab::leaveEvent(QEvent *event)
|
||||
@@ -416,7 +418,7 @@ void NotebookTab::leaveEvent(QEvent *event)
|
||||
|
||||
this->update();
|
||||
|
||||
RippleEffectButton::leaveEvent(event);
|
||||
Button::leaveEvent(event);
|
||||
}
|
||||
|
||||
void NotebookTab::dragEnterEvent(QDragEnterEvent *event)
|
||||
@@ -434,7 +436,7 @@ void NotebookTab::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
if (app->settings->showTabCloseButton &&
|
||||
if (getSettings()->showTabCloseButton &&
|
||||
this->notebook_->getAllowUserTabManagement()) //
|
||||
{
|
||||
bool overX = this->getXRect().contains(event->pos());
|
||||
@@ -461,7 +463,7 @@ void NotebookTab::mouseMoveEvent(QMouseEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
RippleEffectButton::mouseMoveEvent(event);
|
||||
Button::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
QRect NotebookTab::getXRect()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common/Common.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/helper/RippleEffectButton.hpp"
|
||||
#include "widgets/helper/Button.hpp"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QPropertyAnimation>
|
||||
@@ -17,7 +17,7 @@ namespace chatterino {
|
||||
class Notebook;
|
||||
class SplitContainer;
|
||||
|
||||
class NotebookTab : public RippleEffectButton
|
||||
class NotebookTab : public Button
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ void ResizingTextEdit::keyPressEvent(QKeyEvent *event)
|
||||
// First type pressing tab after modifying a message, we refresh our
|
||||
// completion model
|
||||
this->completer_->setModel(completionModel);
|
||||
completionModel->refresh();
|
||||
completionModel->refresh(currentCompletionPrefix);
|
||||
this->completionInProgress_ = true;
|
||||
this->completer_->setCompletionPrefix(currentCompletionPrefix);
|
||||
this->completer_->complete();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ScrollbarHighlight
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/Channel.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "messages/LimitedQueueSnapshot.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <memory>
|
||||
@@ -13,6 +12,9 @@ namespace chatterino {
|
||||
class Channel;
|
||||
class ChannelView;
|
||||
|
||||
struct Message;
|
||||
using MessagePtr = std::shared_ptr<const Message>;
|
||||
|
||||
class SearchPopup : public BaseWindow
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
namespace chatterino {
|
||||
|
||||
TitleBarButton::TitleBarButton()
|
||||
: RippleEffectButton(nullptr)
|
||||
: Button(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TitleBarButton::Style TitleBarButton::getButtonStyle() const
|
||||
TitleBarButtonStyle TitleBarButton::getButtonStyle() const
|
||||
{
|
||||
return this->style_;
|
||||
}
|
||||
|
||||
void TitleBarButton::setButtonStyle(Style _style)
|
||||
void TitleBarButton::setButtonStyle(TitleBarButtonStyle _style)
|
||||
{
|
||||
this->style_ = _style;
|
||||
this->update();
|
||||
@@ -35,16 +35,16 @@ void TitleBarButton::paintEvent(QPaintEvent *event)
|
||||
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
switch (this->style_) {
|
||||
case Minimize: {
|
||||
case TitleBarButtonStyle::Minimize: {
|
||||
painter.fillRect(centerX - xD / 2, xD * 3 / 2, xD, 1, color);
|
||||
break;
|
||||
}
|
||||
case Maximize: {
|
||||
case TitleBarButtonStyle::Maximize: {
|
||||
painter.setPen(color);
|
||||
painter.drawRect(centerX - xD / 2, xD, xD - 1, xD - 1);
|
||||
break;
|
||||
}
|
||||
case Unmaximize: {
|
||||
case TitleBarButtonStyle::Unmaximize: {
|
||||
int xD2 = xD * 1 / 5;
|
||||
int xD3 = xD * 4 / 5;
|
||||
|
||||
@@ -54,7 +54,7 @@ void TitleBarButton::paintEvent(QPaintEvent *event)
|
||||
painter.drawRect(centerX - xD / 2, xD + xD2, xD3, xD3);
|
||||
break;
|
||||
}
|
||||
case Close: {
|
||||
case TitleBarButtonStyle::Close: {
|
||||
QRect rect(centerX - xD / 2, xD, xD - 1, xD - 1);
|
||||
painter.setPen(QPen(color, 1));
|
||||
|
||||
@@ -62,7 +62,7 @@ void TitleBarButton::paintEvent(QPaintEvent *event)
|
||||
painter.drawLine(rect.topRight(), rect.bottomLeft());
|
||||
break;
|
||||
}
|
||||
case User: {
|
||||
case TitleBarButtonStyle::User: {
|
||||
color = "#999";
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
@@ -88,7 +88,7 @@ void TitleBarButton::paintEvent(QPaintEvent *event)
|
||||
|
||||
break;
|
||||
}
|
||||
case Settings: {
|
||||
case TitleBarButtonStyle::Settings: {
|
||||
color = "#999";
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
@@ -119,7 +119,7 @@ void TitleBarButton::paintEvent(QPaintEvent *event)
|
||||
default:;
|
||||
}
|
||||
|
||||
RippleEffectButton::paintEvent(event);
|
||||
Button::paintEvent(event);
|
||||
// this->fancyPaint(painter);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/helper/RippleEffectButton.hpp"
|
||||
#include "widgets/helper/Button.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class TitleBarButton : public RippleEffectButton
|
||||
enum class TitleBarButtonStyle {
|
||||
None = 0,
|
||||
Minimize = 1,
|
||||
Maximize = 2,
|
||||
Unmaximize = 4,
|
||||
Close = 8,
|
||||
User = 16,
|
||||
Settings = 32
|
||||
};
|
||||
|
||||
class TitleBarButton : public Button
|
||||
{
|
||||
public:
|
||||
enum Style {
|
||||
None = 0,
|
||||
Minimize = 1,
|
||||
Maximize = 2,
|
||||
Unmaximize = 4,
|
||||
Close = 8,
|
||||
User = 16,
|
||||
Settings = 32
|
||||
};
|
||||
|
||||
TitleBarButton();
|
||||
|
||||
Style getButtonStyle() const;
|
||||
void setButtonStyle(Style style_);
|
||||
TitleBarButtonStyle getButtonStyle() const;
|
||||
void setButtonStyle(TitleBarButtonStyle style_);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
private:
|
||||
Style style_;
|
||||
TitleBarButtonStyle style_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
AboutPage::AboutPage()
|
||||
: SettingsPage("About", ":/images/about.svg")
|
||||
: SettingsPage("About", ":/settings/about.svg")
|
||||
{
|
||||
LayoutCreator<AboutPage> layoutCreator(this);
|
||||
|
||||
@@ -111,7 +111,8 @@ AboutPage::AboutPage()
|
||||
l.emplace<QLabel>("Apple emojis provided by <a href=\"https://apple.com\">Apple</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Google emojis provided by <a href=\"https://google.com\">Google</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Messenger emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Emoji datasource provided by <a href=\"https://www.iamcal.com/\">Cal Henderson</a>")->setOpenExternalLinks(true);
|
||||
l.emplace<QLabel>("Emoji datasource provided by <a href=\"https://www.iamcal.com/\">Cal Henderson</a>"
|
||||
"(<a href=\"https://github.com/iamcal/emoji-data/blob/master/LICENSE\">show license</a>)")->setOpenExternalLinks(true);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ AboutPage::AboutPage()
|
||||
QStringList contributorParts = line.split("|");
|
||||
|
||||
if (contributorParts.size() != 4) {
|
||||
Log("Missing parts in line '{}'", line);
|
||||
log("Missing parts in line '{}'", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -179,6 +180,18 @@ AboutPage::AboutPage()
|
||||
}
|
||||
}
|
||||
|
||||
auto buildInfo = QStringList();
|
||||
buildInfo += "Qt " QT_VERSION_STR;
|
||||
#ifdef USEWINSDK
|
||||
buildInfo += "Windows SDK";
|
||||
#endif
|
||||
#ifdef _MSC_FULL_VER
|
||||
buildInfo += "MSVC " + QString::number(_MSC_FULL_VER, 10);
|
||||
#endif
|
||||
|
||||
auto buildText = QString("Built with " + buildInfo.join(", "));
|
||||
layout.emplace<QLabel>(buildText);
|
||||
|
||||
layout->addStretch(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
AccountsPage::AccountsPage()
|
||||
: SettingsPage("Accounts", ":/images/accounts.svg")
|
||||
: SettingsPage("Accounts", ":/settings/accounts.svg")
|
||||
{
|
||||
auto *app = getApp();
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "AdvancedPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/taggedusers/TaggedUsersController.hpp"
|
||||
#include "controllers/taggedusers/TaggedUsersModel.hpp"
|
||||
#include "singletons/Logging.hpp"
|
||||
#include "singletons/Paths.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFormLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QPushButton>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
AdvancedPage::AdvancedPage()
|
||||
: SettingsPage("Advanced", "")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<AdvancedPage> layoutCreator(this);
|
||||
|
||||
auto tabs = layoutCreator.emplace<QTabWidget>();
|
||||
|
||||
{
|
||||
auto layout = tabs.appendTab(new QVBoxLayout, "Cache");
|
||||
auto folderLabel = layout.emplace<QLabel>();
|
||||
|
||||
folderLabel->setTextFormat(Qt::RichText);
|
||||
folderLabel->setTextInteractionFlags(Qt::TextBrowserInteraction |
|
||||
Qt::LinksAccessibleByKeyboard |
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
folderLabel->setOpenExternalLinks(true);
|
||||
|
||||
getSettings()->cachePath.connect([folderLabel](const auto &,
|
||||
auto) mutable {
|
||||
QString newPath = getPaths()->cacheDirectory();
|
||||
|
||||
QString pathShortened = "Cache saved at <a href=\"file:///" +
|
||||
newPath +
|
||||
"\"><span style=\"color: white;\">" +
|
||||
shortenString(newPath, 50) + "</span></a>";
|
||||
|
||||
folderLabel->setText(pathShortened);
|
||||
folderLabel->setToolTip(newPath);
|
||||
});
|
||||
|
||||
layout->addStretch(1);
|
||||
|
||||
auto selectDir = layout.emplace<QPushButton>("Set custom cache folder");
|
||||
|
||||
QObject::connect(
|
||||
selectDir.getElement(), &QPushButton::clicked, this, [this] {
|
||||
auto dirName = QFileDialog::getExistingDirectory(this);
|
||||
|
||||
getSettings()->cachePath = dirName;
|
||||
});
|
||||
|
||||
auto resetDir =
|
||||
layout.emplace<QPushButton>("Reset custom cache folder");
|
||||
QObject::connect(resetDir.getElement(), &QPushButton::clicked, this,
|
||||
[]() mutable {
|
||||
getSettings()->cachePath = ""; //
|
||||
});
|
||||
|
||||
// Logs end
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/settingspages/SettingsPage.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class AdvancedPage : public SettingsPage
|
||||
{
|
||||
public:
|
||||
AdvancedPage();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
CommandPage::CommandPage()
|
||||
: SettingsPage("Commands", ":/images/commands.svg")
|
||||
: SettingsPage("Commands", ":/settings/commands.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
@@ -47,7 +47,7 @@ CommandPage::CommandPage()
|
||||
|
||||
layout.append(
|
||||
this->createCheckBox("Also match the trigger at the end of the message",
|
||||
app->settings->allowCommandsAtEnd));
|
||||
getSettings()->allowCommandsAtEnd));
|
||||
|
||||
QLabel *text = layout.emplace<QLabel>(TEXT).getElement();
|
||||
text->setWordWrap(true);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
EmotesPage::EmotesPage()
|
||||
: SettingsPage("Emotes", ":/images/emote.svg")
|
||||
: SettingsPage("Emotes", ":/settings/emote.svg")
|
||||
{
|
||||
// SettingManager &settings = SettingManager::getInstance();
|
||||
// LayoutCreator<EmotesPage> layoutCreator(this);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "ExternalToolsPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
|
||||
#include <QGroupBox>
|
||||
@@ -10,16 +11,6 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
namespace {
|
||||
|
||||
QString CreateLink(const QString &url, const QString &name)
|
||||
{
|
||||
return QString("<a href=\"" + url + "\"><span style=\"color: white;\">" +
|
||||
name + "</span></a>");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ExternalToolsPage::ExternalToolsPage()
|
||||
: SettingsPage("External tools", "")
|
||||
{
|
||||
@@ -41,8 +32,8 @@ ExternalToolsPage::ExternalToolsPage()
|
||||
description->setStyleSheet("color: #bbb");
|
||||
|
||||
auto links = new QLabel(
|
||||
CreateLink("https://streamlink.github.io/", "Website") + " " +
|
||||
CreateLink(
|
||||
createNamedLink("https://streamlink.github.io/", "Website") + " " +
|
||||
createNamedLink(
|
||||
"https://github.com/streamlink/streamlink/releases/latest",
|
||||
"Download"));
|
||||
links->setTextFormat(Qt::RichText);
|
||||
@@ -57,22 +48,22 @@ ExternalToolsPage::ExternalToolsPage()
|
||||
auto customPathCb =
|
||||
this->createCheckBox("Use custom path (Enable if using "
|
||||
"non-standard streamlink installation path)",
|
||||
app->settings->streamlinkUseCustomPath);
|
||||
getSettings()->streamlinkUseCustomPath);
|
||||
groupLayout->setWidget(2, QFormLayout::SpanningRole, customPathCb);
|
||||
|
||||
auto customPath = this->createLineEdit(app->settings->streamlinkPath);
|
||||
auto customPath = this->createLineEdit(getSettings()->streamlinkPath);
|
||||
customPath->setPlaceholderText(
|
||||
"Path to folder where Streamlink executable can be found");
|
||||
groupLayout->addRow("Custom streamlink path:", customPath);
|
||||
groupLayout->addRow(
|
||||
"Preferred quality:",
|
||||
this->createComboBox({STREAMLINK_QUALITY},
|
||||
app->settings->preferredQuality));
|
||||
getSettings()->preferredQuality));
|
||||
groupLayout->addRow(
|
||||
"Additional options:",
|
||||
this->createLineEdit(app->settings->streamlinkOpts));
|
||||
this->createLineEdit(getSettings()->streamlinkOpts));
|
||||
|
||||
app->settings->streamlinkUseCustomPath.connect(
|
||||
getSettings()->streamlinkUseCustomPath.connect(
|
||||
[=](const auto &value, auto) {
|
||||
customPath->setEnabled(value); //
|
||||
},
|
||||
|
||||
@@ -18,9 +18,8 @@
|
||||
namespace chatterino {
|
||||
|
||||
FeelPage::FeelPage()
|
||||
: SettingsPage("Feel", ":/images/behave.svg")
|
||||
: SettingsPage("Feel", ":/settings/behave.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<FeelPage> layoutCreator(this);
|
||||
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
@@ -37,20 +36,20 @@ FeelPage::FeelPage()
|
||||
form->addRow(
|
||||
"", this->createCheckBox(
|
||||
"Show which users joined the channel (up to 1000 chatters)",
|
||||
app->settings->showJoins));
|
||||
getSettings()->showJoins));
|
||||
form->addRow(
|
||||
"", this->createCheckBox(
|
||||
"Show which users parted the channel (up to 1000 chatters)",
|
||||
app->settings->showParts));
|
||||
getSettings()->showParts));
|
||||
|
||||
form->addRow("Pause chat:",
|
||||
this->createCheckBox(PAUSE_HOVERING,
|
||||
app->settings->pauseChatHover));
|
||||
getSettings()->pauseChatHover));
|
||||
|
||||
form->addRow("Mouse scroll speed:", this->createMouseScrollSlider());
|
||||
form->addRow("Links:",
|
||||
this->createCheckBox("Open links only on double click",
|
||||
app->settings->linksDoubleClickOnly));
|
||||
getSettings()->linksDoubleClickOnly));
|
||||
}
|
||||
|
||||
layout->addSpacing(16);
|
||||
@@ -61,11 +60,11 @@ FeelPage::FeelPage()
|
||||
groupLayout->addRow(
|
||||
LIMIT_CHATTERS_FOR_SMALLER_STREAMERS,
|
||||
this->createCheckBox(
|
||||
"", app->settings->onlyFetchChattersForSmallerStreamers));
|
||||
"", getSettings()->onlyFetchChattersForSmallerStreamers));
|
||||
|
||||
groupLayout->addRow(
|
||||
"What viewer count counts as a \"smaller streamer\"",
|
||||
this->createSpinBox(app->settings->smallStreamerLimit, 10, 50000));
|
||||
this->createSpinBox(getSettings()->smallStreamerLimit, 10, 50000));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -73,7 +72,7 @@ FeelPage::FeelPage()
|
||||
auto groupLayout = group.setLayoutType<QVBoxLayout>();
|
||||
|
||||
groupLayout.append(this->createCheckBox("Show whispers inline",
|
||||
app->settings->inlineWhispers));
|
||||
getSettings()->inlineWhispers));
|
||||
}
|
||||
|
||||
layout->addStretch(1);
|
||||
@@ -81,17 +80,16 @@ FeelPage::FeelPage()
|
||||
|
||||
QSlider *FeelPage::createMouseScrollSlider()
|
||||
{
|
||||
auto app = getApp();
|
||||
auto slider = new QSlider(Qt::Horizontal);
|
||||
|
||||
float currentValue = app->settings->mouseScrollMultiplier;
|
||||
float currentValue = getSettings()->mouseScrollMultiplier;
|
||||
int sliderValue = int(((currentValue - 0.1f) / 2.f) * 99.f);
|
||||
slider->setValue(sliderValue);
|
||||
|
||||
QObject::connect(slider, &QSlider::valueChanged, [=](int newValue) {
|
||||
float mul = static_cast<float>(newValue) / 99.f;
|
||||
float newSliderValue = (mul * 2.1f) + 0.1f;
|
||||
app->settings->mouseScrollMultiplier = newSliderValue;
|
||||
getSettings()->mouseScrollMultiplier = newSliderValue;
|
||||
});
|
||||
|
||||
return slider;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
HighlightingPage::HighlightingPage()
|
||||
: SettingsPage("Highlights", ":/images/notifications.svg")
|
||||
: SettingsPage("Highlights", ":/settings/notifications.svg")
|
||||
{
|
||||
auto app = getApp();
|
||||
LayoutCreator<HighlightingPage> layoutCreator(this);
|
||||
@@ -39,7 +39,7 @@ HighlightingPage::HighlightingPage()
|
||||
{
|
||||
// GENERAL
|
||||
// layout.append(this->createCheckBox(ENABLE_HIGHLIGHTS,
|
||||
// app->settings->enableHighlights));
|
||||
// getSettings()->enableHighlights));
|
||||
|
||||
// TABS
|
||||
auto tabs = layout.emplace<QTabWidget>();
|
||||
@@ -135,7 +135,7 @@ HighlightingPage::HighlightingPage()
|
||||
auto customSound = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
customSound.append(this->createCheckBox(
|
||||
"Custom sound", app->settings->customHighlightSound));
|
||||
"Custom sound", getSettings()->customHighlightSound));
|
||||
auto selectFile =
|
||||
customSound.emplace<QPushButton>("Select custom sound file");
|
||||
QObject::connect(selectFile.getElement(), &QPushButton::clicked,
|
||||
@@ -143,12 +143,12 @@ HighlightingPage::HighlightingPage()
|
||||
auto fileName = QFileDialog::getOpenFileName(
|
||||
this, tr("Open Sound"), "",
|
||||
tr("Audio Files (*.mp3 *.wav)"));
|
||||
app->settings->pathHighlightSound = fileName;
|
||||
getSettings()->pathHighlightSound = fileName;
|
||||
});
|
||||
}
|
||||
|
||||
layout.append(createCheckBox(ALWAYS_PLAY,
|
||||
app->settings->highlightAlwaysPlaySound));
|
||||
getSettings()->highlightAlwaysPlaySound));
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "controllers/accounts/AccountController.hpp"
|
||||
#include "controllers/ignores/IgnoreController.hpp"
|
||||
#include "controllers/ignores/IgnoreModel.hpp"
|
||||
#include "providers/twitch/TwitchAccount.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
@@ -68,9 +69,8 @@ void addPhrasesTab(LayoutCreator<QVBoxLayout> layout)
|
||||
void addUsersTab(IgnoresPage &page, LayoutCreator<QVBoxLayout> users,
|
||||
QStringListModel &userModel)
|
||||
{
|
||||
users.append(
|
||||
page.createCheckBox("Enable twitch ignored users",
|
||||
getApp()->settings->enableTwitchIgnoredUsers));
|
||||
users.append(page.createCheckBox("Enable twitch ignored users",
|
||||
getSettings()->enableTwitchIgnoredUsers));
|
||||
|
||||
auto anyways = users.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
// LayoutCreator<LogsPage> layoutCreator(this);
|
||||
// auto layout = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
|
||||
|
||||
// auto logPath = app->paths->logsFolderPath;
|
||||
// auto logPath = getPaths()->logsFolderPath;
|
||||
|
||||
// auto created = layout.emplace<QLabel>();
|
||||
// created->setText("Logs are saved to " + CreateLink(logPath, true));
|
||||
@@ -43,7 +43,7 @@
|
||||
// Qt::LinksAccessibleByKeyboard);
|
||||
// created->setOpenExternalLinks(true);
|
||||
// layout.append(this->createCheckBox("Enable logging",
|
||||
// app->settings->enableLogging));
|
||||
// getSettings()->enableLogging));
|
||||
|
||||
// layout->addStretch(1);
|
||||
//}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#include "LookPage.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "messages/Image.hpp"
|
||||
#include "messages/MessageBuilder.hpp"
|
||||
#include "singletons/Resources.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/RemoveScrollAreaBackground.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/Line.hpp"
|
||||
|
||||
#include <QFontDialog>
|
||||
@@ -27,9 +31,9 @@
|
||||
// clang-format on
|
||||
|
||||
#ifdef USEWINSDK
|
||||
#define WINDOW_TOPMOST "Window always on top"
|
||||
# define WINDOW_TOPMOST "Window always on top"
|
||||
#else
|
||||
#define WINDOW_TOPMOST "Window always on top (requires restart)"
|
||||
# define WINDOW_TOPMOST "Window always on top (requires restart)"
|
||||
#endif
|
||||
#define INPUT_EMPTY "Show input box when empty"
|
||||
#define LAST_MSG "Mark the last message you read"
|
||||
@@ -37,7 +41,7 @@
|
||||
namespace chatterino {
|
||||
|
||||
LookPage::LookPage()
|
||||
: SettingsPage("Look", ":/images/theme.svg")
|
||||
: SettingsPage("Look", ":/settings/theme.svg")
|
||||
{
|
||||
this->initializeUi();
|
||||
}
|
||||
@@ -204,16 +208,19 @@ void LookPage::addEmoteTab(LayoutCreator<QVBoxLayout> layout)
|
||||
/*
|
||||
emotes.append(
|
||||
this->createCheckBox("Enable Twitch emotes",
|
||||
app->settings->enableTwitchEmotes));
|
||||
getSettings()->enableTwitchEmotes));
|
||||
emotes.append(this->createCheckBox("Enable BetterTTV emotes for Twitch",
|
||||
app->settings->enableBttvEmotes));
|
||||
getSettings()->enableBttvEmotes));
|
||||
emotes.append(this->createCheckBox("Enable FrankerFaceZ emotes for Twitch",
|
||||
app->settings->enableFfzEmotes));
|
||||
getSettings()->enableFfzEmotes));
|
||||
emotes.append(this->createCheckBox("Enable emojis",
|
||||
app->settings->enableEmojis));
|
||||
getSettings()->enableEmojis));
|
||||
*/
|
||||
layout.append(
|
||||
this->createCheckBox("Animations", getSettings()->enableGifAnimations));
|
||||
layout.append(
|
||||
this->createCheckBox("Animations only when chatterino has focus",
|
||||
getSettings()->enableAnimationsWhenFocused));
|
||||
|
||||
auto scaleBox = layout.emplace<QHBoxLayout>().withoutMargin();
|
||||
{
|
||||
@@ -281,7 +288,7 @@ void LookPage::addLastReadMessageIndicatorPatternSelector(
|
||||
combo->addItems({"Dotted line", "Solid line"});
|
||||
|
||||
const auto currentIndex = []() -> int {
|
||||
switch (getApp()->settings->lastMessagePattern.getValue()) {
|
||||
switch (getSettings()->lastMessagePattern.getValue()) {
|
||||
case Qt::SolidLine:
|
||||
return 1;
|
||||
case Qt::VerPattern:
|
||||
@@ -322,11 +329,11 @@ ChannelPtr LookPage::createPreviewChannel()
|
||||
{
|
||||
MessageBuilder builder;
|
||||
builder.emplace<TimestampElement>(QTime(8, 13, 42));
|
||||
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.moderator), MessageElementFlag::BadgeChannelAuthority);
|
||||
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.subscriber), MessageElementFlag::BadgeSubscription);
|
||||
builder.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->twitch.moderator), MessageElementFlag::BadgeChannelAuthority);
|
||||
builder.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->twitch.subscriber, 0.25), MessageElementFlag::BadgeSubscription);
|
||||
builder.emplace<TextElement>("username1:", MessageElementFlag::Username, QColor("#0094FF"), FontStyle::ChatMediumBold);
|
||||
builder.emplace<TextElement>("This is a preview message", MessageElementFlag::Text);
|
||||
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->pajaDank), MessageElementFlag::AlwaysShow);
|
||||
builder.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->pajaDank, 0.25), MessageElementFlag::AlwaysShow);
|
||||
builder.emplace<TextElement>("@fourtf", MessageElementFlag::BoldUsername, MessageColor::Text, FontStyle::ChatMediumBold);
|
||||
builder.emplace<TextElement>("@fourtf", MessageElementFlag::NonBoldUsername);
|
||||
channel->addMessage(builder.release());
|
||||
@@ -334,7 +341,7 @@ ChannelPtr LookPage::createPreviewChannel()
|
||||
{
|
||||
MessageBuilder message;
|
||||
message.emplace<TimestampElement>(QTime(8, 15, 21));
|
||||
message.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.broadcaster), MessageElementFlag::BadgeChannelAuthority);
|
||||
message.emplace<ImageElement>(Image::fromPixmap(getApp()->resources->twitch.broadcaster), MessageElementFlag::BadgeChannelAuthority);
|
||||
message.emplace<TextElement>("username2:", MessageElementFlag::Username, QColor("#FF6A00"), FontStyle::ChatMediumBold);
|
||||
message.emplace<TextElement>("This is another one", MessageElementFlag::Text);
|
||||
// message.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->ppHop), MessageElementFlag::BttvEmote);
|
||||
@@ -416,7 +423,7 @@ QLayout *LookPage::createFontChanger()
|
||||
button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Policy::Fixed);
|
||||
|
||||
QObject::connect(button, &QPushButton::clicked, [=]() {
|
||||
QFontDialog dialog(app->fonts->getFont(Fonts::ChatMedium, 1.));
|
||||
QFontDialog dialog(app->fonts->getFont(FontStyle::ChatMedium, 1.));
|
||||
|
||||
dialog.setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "controllers/taggedusers/TaggedUsersModel.hpp"
|
||||
#include "singletons/Logging.hpp"
|
||||
#include "singletons/Paths.hpp"
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/helper/EditableModelView.hpp"
|
||||
|
||||
@@ -25,18 +26,6 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
inline QString CreateLink(const QString &url, bool file = false)
|
||||
{
|
||||
if (file) {
|
||||
return QString("<a href=\"file:///" + url +
|
||||
"\"><span style=\"color: white;\">" + url +
|
||||
"</span></a>");
|
||||
}
|
||||
|
||||
return QString("<a href=\"" + url + "\"><span style=\"color: white;\">" +
|
||||
url + "</span></a>");
|
||||
}
|
||||
|
||||
qint64 dirSize(QString dirPath)
|
||||
{
|
||||
qint64 size = 0;
|
||||
@@ -69,12 +58,11 @@ QString formatSize(qint64 size)
|
||||
|
||||
QString fetchLogDirectorySize()
|
||||
{
|
||||
auto app = getApp();
|
||||
QString logPathDirectory;
|
||||
if (app->settings->logPath == "") {
|
||||
logPathDirectory = app->paths->messageLogDirectory;
|
||||
if (getSettings()->logPath == "") {
|
||||
logPathDirectory = getPaths()->messageLogDirectory;
|
||||
} else {
|
||||
logPathDirectory = app->settings->logPath;
|
||||
logPathDirectory = getSettings()->logPath;
|
||||
}
|
||||
qint64 logsSize = dirSize(logPathDirectory);
|
||||
QString logsSizeLabel = "Your logs currently take up ";
|
||||
@@ -101,30 +89,20 @@ ModerationPage::ModerationPage()
|
||||
QtConcurrent::run([] { return fetchLogDirectorySize(); }));
|
||||
|
||||
// Logs (copied from LoggingMananger)
|
||||
app->settings->logPath.connect(
|
||||
getSettings()->logPath.connect(
|
||||
[app, logsPathLabel](const QString &logPath, auto) mutable {
|
||||
QString pathOriginal;
|
||||
|
||||
if (logPath == "") {
|
||||
pathOriginal = app->paths->messageLogDirectory;
|
||||
pathOriginal = getPaths()->messageLogDirectory;
|
||||
} else {
|
||||
pathOriginal = logPath;
|
||||
}
|
||||
|
||||
QString pathShortened;
|
||||
|
||||
if (pathOriginal.size() > 50) {
|
||||
pathShortened = pathOriginal;
|
||||
pathShortened.resize(50);
|
||||
pathShortened += "...";
|
||||
} else {
|
||||
pathShortened = pathOriginal;
|
||||
}
|
||||
|
||||
pathShortened = "Logs saved at <a href=\"file:///" +
|
||||
pathOriginal +
|
||||
"\"><span style=\"color: white;\">" +
|
||||
pathShortened + "</span></a>";
|
||||
QString pathShortened =
|
||||
"Logs saved at <a href=\"file:///" + pathOriginal +
|
||||
"\"><span style=\"color: white;\">" +
|
||||
shortenString(pathOriginal, 50) + "</span></a>";
|
||||
|
||||
logsPathLabel->setText(pathShortened);
|
||||
logsPathLabel->setToolTip(pathOriginal);
|
||||
@@ -136,7 +114,7 @@ ModerationPage::ModerationPage()
|
||||
Qt::LinksAccessibleByKeyboard);
|
||||
logsPathLabel->setOpenExternalLinks(true);
|
||||
logs.append(this->createCheckBox("Enable logging",
|
||||
app->settings->enableLogging));
|
||||
getSettings()->enableLogging));
|
||||
|
||||
logs->addStretch(1);
|
||||
auto selectDir = logs.emplace<QPushButton>("Set custom logpath");
|
||||
@@ -145,10 +123,9 @@ ModerationPage::ModerationPage()
|
||||
QObject::connect(
|
||||
selectDir.getElement(), &QPushButton::clicked, this,
|
||||
[this, logsPathSizeLabel]() mutable {
|
||||
auto app = getApp();
|
||||
auto dirName = QFileDialog::getExistingDirectory(this);
|
||||
|
||||
app->settings->logPath = dirName;
|
||||
getSettings()->logPath = dirName;
|
||||
|
||||
// Refresh: Show how big (size-wise) the logs are
|
||||
logsPathSizeLabel->setText(
|
||||
@@ -159,8 +136,7 @@ ModerationPage::ModerationPage()
|
||||
auto resetDir = logs.emplace<QPushButton>("Reset logpath");
|
||||
QObject::connect(resetDir.getElement(), &QPushButton::clicked, this,
|
||||
[logsPathSizeLabel]() mutable {
|
||||
auto app = getApp();
|
||||
app->settings->logPath = "";
|
||||
getSettings()->logPath = "";
|
||||
|
||||
// Refresh: Show how big (size-wise) the logs are
|
||||
logsPathSizeLabel->setText(QtConcurrent::run(
|
||||
@@ -183,7 +159,7 @@ ModerationPage::ModerationPage()
|
||||
// form->addRow("Action on timed out messages
|
||||
// (unimplemented):",
|
||||
// this->createComboBox({"Disable", "Hide"},
|
||||
// app->settings->timeoutAction));
|
||||
// getSettings()->timeoutAction));
|
||||
// }
|
||||
|
||||
EditableModelView *view =
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace chatterino {
|
||||
SpecialChannelsPage::SpecialChannelsPage()
|
||||
: SettingsPage("Special channels", "")
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
LayoutCreator<SpecialChannelsPage> layoutCreator(this);
|
||||
auto layout = layoutCreator.setLayoutType<QVBoxLayout>();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Common.hpp"
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "providers/twitch/EmoteValue.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchMessageBuilder.hpp"
|
||||
@@ -11,15 +11,20 @@
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/StreamLink.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/Window.hpp"
|
||||
#include "widgets/dialogs/QualityPopup.hpp"
|
||||
#include "widgets/dialogs/SelectChannelDialog.hpp"
|
||||
#include "widgets/dialogs/TextInputDialog.hpp"
|
||||
#include "widgets/dialogs/UserInfoPopup.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/DebugPopup.hpp"
|
||||
#include "widgets/helper/ResizingTextEdit.hpp"
|
||||
#include "widgets/helper/SearchPopup.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
#include "widgets/splits/SplitHeader.hpp"
|
||||
#include "widgets/splits/SplitInput.hpp"
|
||||
#include "widgets/splits/SplitOverlay.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
@@ -37,7 +42,6 @@
|
||||
#include <random>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
pajlada::Signals::Signal<Qt::KeyboardModifiers> Split::modifierStatusChanged;
|
||||
Qt::KeyboardModifiers Split::modifierStatus = Qt::NoModifier;
|
||||
|
||||
@@ -51,32 +55,30 @@ Split::Split(QWidget *parent)
|
||||
: BaseWidget(parent)
|
||||
, container_(nullptr)
|
||||
, channel_(Channel::getEmpty())
|
||||
, vbox_(this)
|
||||
, header_(this)
|
||||
, view_(this)
|
||||
, input_(this)
|
||||
, vbox_(new QVBoxLayout(this))
|
||||
, header_(new SplitHeader(this))
|
||||
, view_(new ChannelView(this))
|
||||
, input_(new SplitInput(this))
|
||||
, overlay_(new SplitOverlay(this))
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
this->setMouseTracking(true);
|
||||
|
||||
this->vbox_.setSpacing(0);
|
||||
this->vbox_.setMargin(1);
|
||||
this->vbox_->setSpacing(0);
|
||||
this->vbox_->setMargin(1);
|
||||
|
||||
this->vbox_.addWidget(&this->header_);
|
||||
this->vbox_.addWidget(&this->view_, 1);
|
||||
this->vbox_.addWidget(&this->input_);
|
||||
this->vbox_->addWidget(this->header_);
|
||||
this->vbox_->addWidget(this->view_, 1);
|
||||
this->vbox_->addWidget(this->input_);
|
||||
|
||||
// Initialize chat widget-wide hotkeys
|
||||
// CTRL+W: Close Split
|
||||
createShortcut(this, "CTRL+W", &Split::doCloseSplit);
|
||||
createShortcut(this, "CTRL+W", &Split::deleteFromContainer);
|
||||
|
||||
// CTRL+R: Change Channel
|
||||
createShortcut(this, "CTRL+R", &Split::doChangeChannel);
|
||||
createShortcut(this, "CTRL+R", &Split::changeChannel);
|
||||
|
||||
// CTRL+F: Search
|
||||
createShortcut(this, "CTRL+F", &Split::showSearchPopup);
|
||||
createShortcut(this, "CTRL+F", &Split::showSearch);
|
||||
|
||||
// F12
|
||||
createShortcut(this, "F10", [] {
|
||||
@@ -91,41 +93,41 @@ Split::Split(QWidget *parent)
|
||||
// CreateShortcut(this, "ALT+SHIFT+UP", &Split::doIncFlexY);
|
||||
// CreateShortcut(this, "ALT+SHIFT+DOWN", &Split::doDecFlexY);
|
||||
|
||||
this->input_.ui_.textEdit->installEventFilter(parent);
|
||||
this->input_->ui_.textEdit->installEventFilter(parent);
|
||||
|
||||
this->view_.mouseDown.connect([this](QMouseEvent *) {
|
||||
this->view_->mouseDown.connect([this](QMouseEvent *) {
|
||||
//
|
||||
this->giveFocus(Qt::MouseFocusReason);
|
||||
});
|
||||
this->view_.selectionChanged.connect([this]() {
|
||||
if (view_.hasSelection()) {
|
||||
this->input_.clearSelection();
|
||||
this->view_->selectionChanged.connect([this]() {
|
||||
if (view_->hasSelection()) {
|
||||
this->input_->clearSelection();
|
||||
}
|
||||
});
|
||||
|
||||
this->input_.textChanged.connect([=](const QString &newText) {
|
||||
if (app->settings->showEmptyInput) {
|
||||
this->input_->textChanged.connect([=](const QString &newText) {
|
||||
if (getSettings()->showEmptyInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newText.length() == 0) {
|
||||
this->input_.hide();
|
||||
} else if (this->input_.isHidden()) {
|
||||
this->input_.show();
|
||||
this->input_->hide();
|
||||
} else if (this->input_->isHidden()) {
|
||||
this->input_->show();
|
||||
}
|
||||
});
|
||||
|
||||
app->settings->showEmptyInput.connect(
|
||||
getSettings()->showEmptyInput.connect(
|
||||
[this](const bool &showEmptyInput, auto) {
|
||||
if (!showEmptyInput && this->input_.getInputText().length() == 0) {
|
||||
this->input_.hide();
|
||||
if (!showEmptyInput && this->input_->getInputText().length() == 0) {
|
||||
this->input_->hide();
|
||||
} else {
|
||||
this->input_.show();
|
||||
this->input_->show();
|
||||
}
|
||||
},
|
||||
this->managedConnections_);
|
||||
|
||||
this->header_.updateModerationModeIcon();
|
||||
this->header_->updateModerationModeIcon();
|
||||
this->overlay_->hide();
|
||||
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
@@ -141,9 +143,9 @@ Split::Split(QWidget *parent)
|
||||
}
|
||||
});
|
||||
|
||||
this->input_.ui_.textEdit->focused.connect(
|
||||
this->input_->ui_.textEdit->focused.connect(
|
||||
[this] { this->focused.invoke(); });
|
||||
this->input_.ui_.textEdit->focusLost.connect(
|
||||
this->input_->ui_.textEdit->focusLost.connect(
|
||||
[this] { this->focusLost.invoke(); });
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ Split::~Split()
|
||||
|
||||
ChannelView &Split::getChannelView()
|
||||
{
|
||||
return this->view_;
|
||||
return *this->view_;
|
||||
}
|
||||
|
||||
SplitContainer *Split::getContainer()
|
||||
@@ -189,7 +191,7 @@ void Split::setChannel(IndirectChannel newChannel)
|
||||
{
|
||||
this->channel_ = newChannel;
|
||||
|
||||
this->view_.setChannel(newChannel.get());
|
||||
this->view_->setChannel(newChannel.get());
|
||||
|
||||
this->usermodeChangedConnection_.disconnect();
|
||||
this->roomModeChangedConnection_.disconnect();
|
||||
@@ -199,12 +201,12 @@ void Split::setChannel(IndirectChannel newChannel)
|
||||
|
||||
if (tc != nullptr) {
|
||||
this->usermodeChangedConnection_ = tc->userStateChanged.connect([this] {
|
||||
this->header_.updateModerationModeIcon();
|
||||
this->header_.updateRoomModes();
|
||||
this->header_->updateModerationModeIcon();
|
||||
this->header_->updateRoomModes();
|
||||
});
|
||||
|
||||
this->roomModeChangedConnection_ = tc->roomModesChanged.connect(
|
||||
[this] { this->header_.updateRoomModes(); });
|
||||
[this] { this->header_->updateRoomModes(); });
|
||||
}
|
||||
|
||||
this->indirectChannelChangedConnection_ =
|
||||
@@ -212,9 +214,9 @@ void Split::setChannel(IndirectChannel newChannel)
|
||||
QTimer::singleShot(0, [this] { this->setChannel(this->channel_); });
|
||||
});
|
||||
|
||||
this->header_.updateModerationModeIcon();
|
||||
this->header_.updateChannelText();
|
||||
this->header_.updateRoomModes();
|
||||
this->header_->updateModerationModeIcon();
|
||||
this->header_->updateChannelText();
|
||||
this->header_->updateRoomModes();
|
||||
|
||||
this->channelChanged.invoke();
|
||||
}
|
||||
@@ -223,8 +225,8 @@ void Split::setModerationMode(bool value)
|
||||
{
|
||||
if (value != this->moderationMode_) {
|
||||
this->moderationMode_ = value;
|
||||
this->header_.updateModerationModeIcon();
|
||||
this->view_.layoutMessages();
|
||||
this->header_->updateModerationModeIcon();
|
||||
this->view_->layoutMessages();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +237,7 @@ bool Split::getModerationMode() const
|
||||
|
||||
void Split::insertTextToInput(const QString &text)
|
||||
{
|
||||
this->input_.insertText(text);
|
||||
this->input_->insertText(text);
|
||||
}
|
||||
|
||||
void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
||||
@@ -269,27 +271,27 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
||||
|
||||
void Split::layoutMessages()
|
||||
{
|
||||
this->view_.layoutMessages();
|
||||
this->view_->layoutMessages();
|
||||
}
|
||||
|
||||
void Split::updateGifEmotes()
|
||||
{
|
||||
this->view_.queueUpdate();
|
||||
this->view_->queueUpdate();
|
||||
}
|
||||
|
||||
void Split::updateLastReadMessage()
|
||||
{
|
||||
this->view_.updateLastReadMessage();
|
||||
this->view_->updateLastReadMessage();
|
||||
}
|
||||
|
||||
void Split::giveFocus(Qt::FocusReason reason)
|
||||
{
|
||||
this->input_.ui_.textEdit->setFocus(reason);
|
||||
this->input_->ui_.textEdit->setFocus(reason);
|
||||
}
|
||||
|
||||
bool Split::hasFocus() const
|
||||
{
|
||||
return this->input_.ui_.textEdit->hasFocus();
|
||||
return this->input_->ui_.textEdit->hasFocus();
|
||||
}
|
||||
|
||||
void Split::paintEvent(QPaintEvent *)
|
||||
@@ -307,13 +309,13 @@ void Split::mouseMoveEvent(QMouseEvent *event)
|
||||
|
||||
void Split::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
this->view_.unsetCursor();
|
||||
this->view_->unsetCursor();
|
||||
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||
}
|
||||
|
||||
void Split::keyReleaseEvent(QKeyEvent *event)
|
||||
{
|
||||
this->view_.unsetCursor();
|
||||
this->view_->unsetCursor();
|
||||
this->handleModifiers(QGuiApplication::queryKeyboardModifiers());
|
||||
}
|
||||
|
||||
@@ -362,21 +364,21 @@ void Split::handleModifiers(Qt::KeyboardModifiers modifiers)
|
||||
}
|
||||
|
||||
/// Slots
|
||||
void Split::doAddSplit()
|
||||
void Split::addSibling()
|
||||
{
|
||||
if (this->container_) {
|
||||
this->container_->appendNewSplit(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Split::doCloseSplit()
|
||||
void Split::deleteFromContainer()
|
||||
{
|
||||
if (this->container_) {
|
||||
this->container_->deleteSplit(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Split::doChangeChannel()
|
||||
void Split::changeChannel()
|
||||
{
|
||||
this->showChangeChannelPopup("Change channel", false, [](bool) {});
|
||||
|
||||
@@ -388,10 +390,10 @@ void Split::doChangeChannel()
|
||||
}
|
||||
}
|
||||
|
||||
void Split::doPopup()
|
||||
void Split::popup()
|
||||
{
|
||||
auto app = getApp();
|
||||
Window &window = app->windows->createWindow(Window::Type::Popup);
|
||||
Window &window = app->windows->createWindow(WindowType::Popup);
|
||||
|
||||
Split *split = new Split(static_cast<SplitContainer *>(
|
||||
window.getNotebook().getOrAddSelectedPage()));
|
||||
@@ -402,9 +404,9 @@ void Split::doPopup()
|
||||
window.show();
|
||||
}
|
||||
|
||||
void Split::doClearChat()
|
||||
void Split::clear()
|
||||
{
|
||||
this->view_.clearMessages();
|
||||
this->view_->clearMessages();
|
||||
}
|
||||
|
||||
void Split::openInBrowser()
|
||||
@@ -417,7 +419,7 @@ void Split::openInBrowser()
|
||||
}
|
||||
}
|
||||
|
||||
void Split::openInPopupPlayer()
|
||||
void Split::openBrowserPlayer()
|
||||
{
|
||||
ChannelPtr channel = this->getChannel();
|
||||
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) {
|
||||
@@ -431,7 +433,7 @@ void Split::openInStreamlink()
|
||||
try {
|
||||
openStreamlinkForChannel(this->getChannel()->getName());
|
||||
} catch (const Exception &ex) {
|
||||
Log("Error in doOpenStreamlink: {}", ex.what());
|
||||
log("Error in doOpenStreamlink: {}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,8 +446,8 @@ void Split::showViewerList()
|
||||
QDockWidget::DockWidgetFloatable);
|
||||
viewerDock->resize(
|
||||
0.5 * this->width(),
|
||||
this->height() - this->header_.height() - this->input_.height());
|
||||
viewerDock->move(0, this->header_.height());
|
||||
this->height() - this->header_->height() - this->input_->height());
|
||||
viewerDock->move(0, this->header_->height());
|
||||
|
||||
auto multiWidget = new QWidget(viewerDock);
|
||||
auto dockVbox = new QVBoxLayout(viewerDock);
|
||||
@@ -545,10 +547,10 @@ void Split::showUserInfoPopup(const UserName &user)
|
||||
|
||||
void Split::copyToClipboard()
|
||||
{
|
||||
QApplication::clipboard()->setText(this->view_.getSelectedText());
|
||||
QApplication::clipboard()->setText(this->view_->getSelectedText());
|
||||
}
|
||||
|
||||
void Split::showSearchPopup()
|
||||
void Split::showSearch()
|
||||
{
|
||||
SearchPopup *popup = new SearchPopup();
|
||||
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Aliases.hpp"
|
||||
#include "common/Channel.hpp"
|
||||
#include "common/NullablePtr.hpp"
|
||||
#include "common/SerializeCustom.hpp"
|
||||
#include "messages/LimitedQueueSnapshot.hpp"
|
||||
#include "messages/MessageElement.hpp"
|
||||
#include "messages/layouts/MessageLayout.hpp"
|
||||
#include "messages/layouts/MessageLayoutElement.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
#include "widgets/splits/SplitHeader.hpp"
|
||||
#include "widgets/splits/SplitInput.hpp"
|
||||
|
||||
#include <QFont>
|
||||
#include <QShortcut>
|
||||
@@ -20,6 +12,9 @@
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class ChannelView;
|
||||
class SplitHeader;
|
||||
class SplitInput;
|
||||
class SplitContainer;
|
||||
class SplitOverlay;
|
||||
class SelectChannelDialog;
|
||||
@@ -103,10 +98,10 @@ private:
|
||||
SplitContainer *container_;
|
||||
IndirectChannel channel_;
|
||||
|
||||
QVBoxLayout vbox_;
|
||||
SplitHeader header_;
|
||||
ChannelView view_;
|
||||
SplitInput input_;
|
||||
QVBoxLayout *vbox_;
|
||||
SplitHeader *header_;
|
||||
ChannelView *view_;
|
||||
SplitInput *input_;
|
||||
SplitOverlay *overlay_;
|
||||
|
||||
NullablePtr<SelectChannelDialog> selectChannelDialog_;
|
||||
@@ -125,39 +120,16 @@ private:
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
|
||||
public slots:
|
||||
// Add new split to the notebook page that this chat widget is in
|
||||
// This is only activated from the menu now. Hotkey is handled in Notebook
|
||||
void doAddSplit();
|
||||
|
||||
// Close current split (chat widget)
|
||||
void doCloseSplit();
|
||||
|
||||
// Show a dialog for changing the current splits/chat widgets channel
|
||||
void doChangeChannel();
|
||||
|
||||
// Open popup copy of this chat widget
|
||||
// XXX: maybe make current chatwidget a popup instead?
|
||||
void doPopup();
|
||||
|
||||
// Clear chat from all messages
|
||||
void doClearChat();
|
||||
|
||||
// Open link to twitch channel in default browser
|
||||
void addSibling();
|
||||
void deleteFromContainer();
|
||||
void changeChannel();
|
||||
void popup();
|
||||
void clear();
|
||||
void openInBrowser();
|
||||
|
||||
// Open popup player of twitch channel in default browser
|
||||
void openInPopupPlayer();
|
||||
|
||||
// Open twitch channel stream through streamlink
|
||||
void openBrowserPlayer();
|
||||
void openInStreamlink();
|
||||
|
||||
// Copy text from chat
|
||||
void copyToClipboard();
|
||||
|
||||
// Open a search popup
|
||||
void showSearchPopup();
|
||||
|
||||
// Open viewer list of the channel
|
||||
void showSearch();
|
||||
void showViewerList();
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "util/Helpers.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
@@ -40,12 +41,12 @@ SplitContainer::SplitContainer(Notebook *parent)
|
||||
this->layout();
|
||||
|
||||
if (modifiers == showResizeHandlesModifiers) {
|
||||
for (std::unique_ptr<ResizeHandle> &handle : this->resizeHandles_) {
|
||||
for (auto &handle : this->resizeHandles_) {
|
||||
handle->show();
|
||||
handle->raise();
|
||||
}
|
||||
} else {
|
||||
for (std::unique_ptr<ResizeHandle> &handle : this->resizeHandles_) {
|
||||
for (auto &handle : this->resizeHandles_) {
|
||||
handle->hide();
|
||||
}
|
||||
}
|
||||
@@ -89,7 +90,7 @@ void SplitContainer::hideResizeHandles()
|
||||
{
|
||||
this->overlay_.hide();
|
||||
|
||||
for (std::unique_ptr<ResizeHandle> &handle : this->resizeHandles_) {
|
||||
for (auto &handle : this->resizeHandles_) {
|
||||
handle->hide();
|
||||
}
|
||||
}
|
||||
@@ -311,7 +312,7 @@ void SplitContainer::focusSplitRecursive(Node *node, Direction direction)
|
||||
|
||||
void SplitContainer::layout()
|
||||
{
|
||||
this->baseNode_.geometry_ = this->rect();
|
||||
this->baseNode_.geometry_ = this->rect().adjusted(-1, -1, 0, 0);
|
||||
|
||||
std::vector<DropRect> _dropRects;
|
||||
std::vector<ResizeRect> _resizeRects;
|
||||
@@ -326,25 +327,30 @@ void SplitContainer::layout()
|
||||
|
||||
Node *node = this->baseNode_.findNodeContainingSplit(split);
|
||||
|
||||
// left
|
||||
_dropRects.push_back(
|
||||
DropRect(QRect(g.left(), g.top(), g.width() / 3, g.height()),
|
||||
Position(node, Direction::Left)));
|
||||
_dropRects.push_back(DropRect(QRect(g.left() + g.width() / 3 * 2,
|
||||
g.top(), g.width() / 3, g.height()),
|
||||
// right
|
||||
_dropRects.push_back(DropRect(QRect(g.right() - g.width() / 3, g.top(),
|
||||
g.width() / 3, g.height()),
|
||||
Position(node, Direction::Right)));
|
||||
|
||||
// top
|
||||
_dropRects.push_back(
|
||||
DropRect(QRect(g.left(), g.top(), g.width(), g.height() / 2),
|
||||
Position(node, Direction::Above)));
|
||||
_dropRects.push_back(DropRect(QRect(g.left(), g.top() + g.height() / 2,
|
||||
g.width(), g.height() / 2),
|
||||
Position(node, Direction::Below)));
|
||||
// bottom
|
||||
_dropRects.push_back(
|
||||
DropRect(QRect(g.left(), g.bottom() - g.height() / 2, g.width(),
|
||||
g.height() / 2),
|
||||
Position(node, Direction::Below)));
|
||||
}
|
||||
|
||||
if (this->splits_.empty()) {
|
||||
QRect g = this->rect();
|
||||
_dropRects.push_back(
|
||||
DropRect(QRect(g.left(), g.top(), g.width(), g.height()),
|
||||
DropRect(QRect(g.left(), g.top(), g.width() - 1, g.height() - 1),
|
||||
Position(nullptr, Direction::Below)));
|
||||
}
|
||||
|
||||
@@ -899,7 +905,7 @@ void SplitContainer::Node::layout(bool addSpacing, float _scale,
|
||||
case Node::_Split: {
|
||||
QRect rect = this->geometry_.toRect();
|
||||
this->split_->setGeometry(
|
||||
rect.marginsRemoved(QMargins(1, 1, 1, 1)));
|
||||
rect.marginsRemoved(QMargins(1, 1, 0, 0)));
|
||||
} break;
|
||||
case Node::VerticalContainer:
|
||||
case Node::HorizontalContainer: {
|
||||
@@ -963,10 +969,10 @@ void SplitContainer::Node::layout(bool addSpacing, float _scale,
|
||||
}
|
||||
|
||||
// iterate children
|
||||
qreal pos = isVertical ? childRect.top() : childRect.left();
|
||||
auto pos = int(isVertical ? childRect.top() : childRect.left());
|
||||
for (std::unique_ptr<Node> &child : this->children_) {
|
||||
// set rect
|
||||
QRectF rect = childRect;
|
||||
QRect rect = childRect.toRect();
|
||||
if (isVertical) {
|
||||
rect.setTop(pos);
|
||||
rect.setHeight(
|
||||
@@ -982,6 +988,11 @@ void SplitContainer::Node::layout(bool addSpacing, float _scale,
|
||||
sizeMultiplier);
|
||||
}
|
||||
|
||||
if (child == this->children_.back()) {
|
||||
rect.setRight(childRect.right() - 1);
|
||||
rect.setBottom(childRect.bottom() - 1);
|
||||
}
|
||||
|
||||
child->geometry_ = rect;
|
||||
child->layout(addSpacing, _scale, dropRects, resizeRects);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
#include <QDragEnterEvent>
|
||||
#include <QHBoxLayout>
|
||||
@@ -13,21 +11,24 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
#include <vector>
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Split;
|
||||
class NotebookTab;
|
||||
class Notebook;
|
||||
|
||||
//
|
||||
// Note: This class is a spaghetti container. There is a lot of spaghetti code
|
||||
// inside but it doesn't expose any of it publicly.
|
||||
//
|
||||
|
||||
class SplitContainer : public BaseWidget, pajlada::Signals::SignalHolder
|
||||
class SplitContainer final : public BaseWidget, pajlada::Signals::SignalHolder
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
+213
-265
@@ -6,136 +6,186 @@
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchServer.hpp"
|
||||
#include "singletons/Resources.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "util/LayoutHelper.hpp"
|
||||
#include "widgets/Label.hpp"
|
||||
#include "widgets/TooltipWidget.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDesktopWidget>
|
||||
#include <QDrag>
|
||||
#include <QHBoxLayout>
|
||||
#include <QInputDialog>
|
||||
#include <QMenu>
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
#ifdef USEWEBENGINE
|
||||
#include "widgets/StreamView.hpp"
|
||||
# include "widgets/StreamView.hpp"
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
auto formatRoomMode(TwitchChannel &channel) -> QString
|
||||
{
|
||||
QString text;
|
||||
|
||||
{
|
||||
auto modes = channel.accessRoomModes();
|
||||
|
||||
if (modes->r9k) text += "r9k, ";
|
||||
if (modes->slowMode)
|
||||
text +=
|
||||
QString("slow(%1), ").arg(QString::number(modes->slowMode));
|
||||
if (modes->emoteOnly) text += "emote, ";
|
||||
if (modes->submode) text += "sub, ";
|
||||
}
|
||||
|
||||
if (text.length() > 2) {
|
||||
text = text.mid(0, text.size() - 2);
|
||||
}
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
static QRegularExpression commaReplacement("^(.+?, .+?,) (.+)$");
|
||||
|
||||
auto match = commaReplacement.match(text);
|
||||
if (match.hasMatch())
|
||||
text = match.captured(1) + '\n' + match.captured(2);
|
||||
}
|
||||
|
||||
if (text.isEmpty() && channel.hasModRights()) return "none";
|
||||
|
||||
return text;
|
||||
}
|
||||
auto formatTooltip(const TwitchChannel::StreamStatus &s)
|
||||
{
|
||||
return QStringList{"<style>.center { text-align: center; }</style>",
|
||||
"<p class=\"center\">",
|
||||
s.title,
|
||||
"<br><br>",
|
||||
s.game,
|
||||
"<br>",
|
||||
s.rerun ? "Vod-casting" : "Live",
|
||||
" for ",
|
||||
s.uptime,
|
||||
" with ",
|
||||
QString::number(s.viewerCount),
|
||||
" viewers",
|
||||
"</p>"}
|
||||
.join("");
|
||||
}
|
||||
auto formatTitle(const TwitchChannel::StreamStatus &s, Settings &settings)
|
||||
{
|
||||
auto title = QString();
|
||||
|
||||
// live
|
||||
if (s.rerun)
|
||||
title += " (rerun)";
|
||||
else if (s.streamType.isEmpty())
|
||||
title += " (" + s.streamType + ")";
|
||||
else
|
||||
title += " (live)";
|
||||
|
||||
// description
|
||||
if (settings.showViewerCount)
|
||||
title += " - " + QString::number(s.viewerCount);
|
||||
if (settings.showTitle) title += " - " + s.title;
|
||||
if (settings.showGame) title += " - " + s.game;
|
||||
if (settings.showUptime) title += " - " + s.uptime;
|
||||
|
||||
return title;
|
||||
}
|
||||
auto distance(QPoint a, QPoint b)
|
||||
{
|
||||
auto x = std::abs(a.x() - b.x());
|
||||
auto y = std::abs(a.y() - b.y());
|
||||
|
||||
return std::sqrt(x * x + y * y);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SplitHeader::SplitHeader(Split *_split)
|
||||
: BaseWidget(_split)
|
||||
, split_(_split)
|
||||
{
|
||||
this->split_->focused.connect([this]() { this->themeChangedEvent(); });
|
||||
this->split_->focusLost.connect([this]() { this->themeChangedEvent(); });
|
||||
|
||||
auto app = getApp();
|
||||
|
||||
LayoutCreator<SplitHeader> layoutCreator(this);
|
||||
auto layout = layoutCreator.emplace<QHBoxLayout>().withoutMargin();
|
||||
layout->setSpacing(0);
|
||||
{
|
||||
// channel name label
|
||||
auto title = layout.emplace<Label>().assign(&this->titleLabel);
|
||||
title->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Preferred);
|
||||
title->setCentered(true);
|
||||
title->setHasOffset(false);
|
||||
|
||||
// mode button
|
||||
auto mode = layout.emplace<RippleEffectLabel>(nullptr).assign(
|
||||
&this->modeButton_);
|
||||
|
||||
mode->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
mode->hide();
|
||||
|
||||
this->setupModeLabel(*mode);
|
||||
|
||||
mode->setMenu(this->createChatModeMenu());
|
||||
|
||||
// moderation mode
|
||||
auto moderator = layout.emplace<RippleEffectButton>(this).assign(
|
||||
&this->moderationButton_);
|
||||
|
||||
QObject::connect(
|
||||
moderator.getElement(), &RippleEffectButton::clicked, this,
|
||||
[this, moderator]() mutable {
|
||||
this->split_->setModerationMode(
|
||||
!this->split_->getModerationMode());
|
||||
|
||||
moderator->setDim(!this->split_->getModerationMode());
|
||||
});
|
||||
|
||||
this->updateModerationModeIcon();
|
||||
|
||||
// dropdown label
|
||||
auto dropdown = layout.emplace<RippleEffectButton>(this).assign(
|
||||
&this->dropdownButton_);
|
||||
dropdown->setMouseTracking(true);
|
||||
// dropdown->setPixmap(*app->resources->splitHeaderContext->getPixmap());
|
||||
// dropdown->setScaleIndependantSize(23, 23);
|
||||
dropdown->setMenu(this->createMainMenu());
|
||||
QObject::connect(dropdown.getElement(),
|
||||
&RippleEffectButton::leftMousePress, this, [this] {});
|
||||
}
|
||||
|
||||
// ---- misc
|
||||
this->layout()->setMargin(0);
|
||||
this->scaleChangedEvent(this->getScale());
|
||||
|
||||
this->updateChannelText();
|
||||
|
||||
this->initializeChannelSignals();
|
||||
|
||||
this->split_->channelChanged.connect([this]() {
|
||||
this->initializeChannelSignals(); //
|
||||
});
|
||||
|
||||
this->managedConnect(app->accounts->twitch.currentUserChanged,
|
||||
[this] { this->updateModerationModeIcon(); });
|
||||
this->initializeLayout();
|
||||
|
||||
this->setMouseTracking(true);
|
||||
this->updateChannelText();
|
||||
this->handleChannelChanged();
|
||||
this->updateModerationModeIcon();
|
||||
|
||||
// Update title on title-settings-change
|
||||
getSettings()->showViewerCount.connect(
|
||||
[this](const auto &, const auto &) { this->updateChannelText(); },
|
||||
this->managedConnections_);
|
||||
getSettings()->showTitle.connect(
|
||||
[this](const auto &, const auto &) { this->updateChannelText(); },
|
||||
this->managedConnections_);
|
||||
getSettings()->showGame.connect(
|
||||
[this](const auto &, const auto &) { this->updateChannelText(); },
|
||||
this->managedConnections_);
|
||||
getSettings()->showUptime.connect(
|
||||
[this](const auto &, const auto &) { this->updateChannelText(); },
|
||||
this->managedConnections_);
|
||||
this->split_->focused.connect([this]() { this->themeChangedEvent(); });
|
||||
this->split_->focusLost.connect([this]() { this->themeChangedEvent(); });
|
||||
this->split_->channelChanged.connect(
|
||||
[this]() { this->handleChannelChanged(); });
|
||||
|
||||
this->managedConnect(getApp()->accounts->twitch.currentUserChanged,
|
||||
[this] { this->updateModerationModeIcon(); });
|
||||
|
||||
auto _ = [this](const auto &, const auto &) { this->updateChannelText(); };
|
||||
getSettings()->showViewerCount.connect(_, this->managedConnections_);
|
||||
getSettings()->showTitle.connect(_, this->managedConnections_);
|
||||
getSettings()->showGame.connect(_, this->managedConnections_);
|
||||
getSettings()->showUptime.connect(_, this->managedConnections_);
|
||||
}
|
||||
|
||||
SplitHeader::~SplitHeader()
|
||||
void SplitHeader::initializeLayout()
|
||||
{
|
||||
this->onlineStatusChangedConnection_.disconnect();
|
||||
auto layout = makeLayout<QHBoxLayout>(
|
||||
{// title
|
||||
this->titleLabel = makeWidget<Label>([](auto w) {
|
||||
w->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Preferred);
|
||||
w->setCentered(true);
|
||||
w->setHasOffset(false);
|
||||
}),
|
||||
// mode
|
||||
this->modeButton_ = makeWidget<EffectLabel>([&](auto w) {
|
||||
w->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
w->hide();
|
||||
this->initializeModeSignals(*w);
|
||||
w->setMenu(this->createChatModeMenu());
|
||||
}),
|
||||
// moderator
|
||||
this->moderationButton_ = makeWidget<Button>([&](auto w) {
|
||||
QObject::connect(w, &Button::clicked, this, [this, w]() mutable {
|
||||
this->split_->setModerationMode(
|
||||
!this->split_->getModerationMode());
|
||||
|
||||
w->setDim(!this->split_->getModerationMode());
|
||||
});
|
||||
}),
|
||||
// dropdown
|
||||
this->dropdownButton_ = makeWidget<Button>(
|
||||
[&](auto w) { w->setMenu(this->createMainMenu()); })});
|
||||
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(0);
|
||||
this->setLayout(layout);
|
||||
}
|
||||
|
||||
std::unique_ptr<QMenu> SplitHeader::createMainMenu()
|
||||
{
|
||||
auto menu = std::make_unique<QMenu>();
|
||||
menu->addAction("New split", this->split_, &Split::doAddSplit,
|
||||
QKeySequence(tr("Ctrl+T")));
|
||||
menu->addAction("Close split", this->split_, &Split::doCloseSplit,
|
||||
QKeySequence(tr("Ctrl+W")));
|
||||
menu->addAction("Change channel", this->split_, &Split::doChangeChannel,
|
||||
QKeySequence(tr("Ctrl+R")));
|
||||
menu->addAction("New split", this->split_, &Split::addSibling,
|
||||
QKeySequence("Ctrl+T"));
|
||||
menu->addAction("Close split", this->split_, &Split::deleteFromContainer,
|
||||
QKeySequence("Ctrl+W"));
|
||||
menu->addAction("Change channel", this->split_, &Split::changeChannel,
|
||||
QKeySequence("Ctrl+R"));
|
||||
menu->addSeparator();
|
||||
menu->addAction("Viewer list", this->split_, &Split::showViewerList);
|
||||
menu->addAction("Search", this->split_, &Split::showSearchPopup,
|
||||
QKeySequence(tr("Ctrl+F")));
|
||||
menu->addAction("Search", this->split_, &Split::showSearch,
|
||||
QKeySequence("Ctrl+F"));
|
||||
menu->addSeparator();
|
||||
menu->addAction("Popup", this->split_, &Split::doPopup);
|
||||
menu->addAction("Popup", this->split_, &Split::popup);
|
||||
#ifdef USEWEBENGINE
|
||||
this->dropdownMenu.addAction("Start watching", this, [this] {
|
||||
ChannelPtr _channel = this->split->getChannel();
|
||||
@@ -152,7 +202,7 @@ std::unique_ptr<QMenu> SplitHeader::createMainMenu()
|
||||
menu->addAction("Open in browser", this->split_, &Split::openInBrowser);
|
||||
#ifndef USEWEBENGINE
|
||||
menu->addAction("Open player in browser", this->split_,
|
||||
&Split::openInPopupPlayer);
|
||||
&Split::openBrowserPlayer);
|
||||
#endif
|
||||
menu->addAction("Open streamlink", this->split_, &Split::openInStreamlink);
|
||||
|
||||
@@ -172,9 +222,8 @@ std::unique_ptr<QMenu> SplitHeader::createMainMenu()
|
||||
menu->addAction(action);
|
||||
|
||||
menu->addSeparator();
|
||||
menu->addAction("Reload channel emotes", this,
|
||||
SLOT(menuReloadChannelEmotes()));
|
||||
menu->addAction("Reconnect", this, SLOT(menuManualReconnect()));
|
||||
menu->addAction("Reload channel emotes", this, SLOT(reloadChannelEmotes()));
|
||||
menu->addAction("Reconnect", this, SLOT(reconnect()));
|
||||
// menu->addAction("Clear messages", this->split_, &Split::doClearChat);
|
||||
// menu->addSeparator();
|
||||
// menu->addAction("Show changelog", this, SLOT(menuShowChangelog()));
|
||||
@@ -218,16 +267,10 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||
setSub->setChecked(roomModes->submode);
|
||||
}));
|
||||
|
||||
auto toggle = [this](const QString &_command, QAction *action) mutable {
|
||||
QString command = _command;
|
||||
|
||||
if (!action->isChecked()) {
|
||||
command += "off";
|
||||
};
|
||||
auto toggle = [this](const QString &command, QAction *action) mutable {
|
||||
this->split_->getChannel().get()->sendMessage(
|
||||
command + (action->isChecked() ? "" : "off"));
|
||||
action->setChecked(!action->isChecked());
|
||||
|
||||
qDebug() << command;
|
||||
this->split_->getChannel().get()->sendMessage(command);
|
||||
};
|
||||
|
||||
QObject::connect(
|
||||
@@ -244,12 +287,12 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||
setSlow->setChecked(false);
|
||||
return;
|
||||
};
|
||||
bool ok;
|
||||
int slowSec = QInputDialog::getInt(this, "", "Seconds:", 10, 0, 500, 1,
|
||||
&ok, Qt::FramelessWindowHint);
|
||||
auto ok = bool();
|
||||
auto seconds = QInputDialog::getInt(this, "", "Seconds:", 10, 0, 500, 1,
|
||||
&ok, Qt::FramelessWindowHint);
|
||||
if (ok) {
|
||||
this->split_->getChannel().get()->sendMessage(
|
||||
QString("/slow %1").arg(slowSec));
|
||||
QString("/slow %1").arg(seconds));
|
||||
} else {
|
||||
setSlow->setChecked(false);
|
||||
}
|
||||
@@ -267,74 +310,37 @@ void SplitHeader::updateRoomModes()
|
||||
this->modeUpdateRequested_.invoke();
|
||||
}
|
||||
|
||||
void SplitHeader::setupModeLabel(RippleEffectLabel &label)
|
||||
void SplitHeader::initializeModeSignals(EffectLabel &label)
|
||||
{
|
||||
this->managedConnections_.push_back(
|
||||
this->modeUpdateRequested_.connect([this, &label] {
|
||||
auto twitchChannel =
|
||||
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get());
|
||||
|
||||
// return if the channel is not a twitch channel
|
||||
if (twitchChannel == nullptr) {
|
||||
label.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// set lable enabled
|
||||
this->modeUpdateRequested_.connect([this, &label] {
|
||||
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(
|
||||
this->split_->getChannel().get())) //
|
||||
{
|
||||
label.setEnable(twitchChannel->hasModRights());
|
||||
|
||||
// set the label text
|
||||
QString text;
|
||||
|
||||
{
|
||||
auto roomModes = twitchChannel->accessRoomModes();
|
||||
|
||||
if (roomModes->r9k) text += "r9k, ";
|
||||
if (roomModes->slowMode)
|
||||
text += QString("slow(%1), ")
|
||||
.arg(QString::number(roomModes->slowMode));
|
||||
if (roomModes->emoteOnly) text += "emote, ";
|
||||
if (roomModes->submode) text += "sub, ";
|
||||
}
|
||||
|
||||
if (text.length() > 2) {
|
||||
text = text.mid(0, text.size() - 2);
|
||||
}
|
||||
|
||||
if (text.isEmpty()) {
|
||||
if (twitchChannel->hasModRights()) {
|
||||
label.getLabel().setText("none");
|
||||
label.show();
|
||||
} else {
|
||||
label.hide();
|
||||
}
|
||||
} else {
|
||||
static QRegularExpression commaReplacement("^.+?, .+?,( ).+$");
|
||||
QRegularExpressionMatch match = commaReplacement.match(text);
|
||||
if (match.hasMatch()) {
|
||||
text = text.mid(0, match.capturedStart(1)) + '\n' +
|
||||
text.mid(match.capturedEnd(1));
|
||||
}
|
||||
auto text = formatRoomMode(*twitchChannel);
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
label.getLabel().setText(text);
|
||||
label.show();
|
||||
return;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
label.hide();
|
||||
});
|
||||
}
|
||||
|
||||
void SplitHeader::initializeChannelSignals()
|
||||
void SplitHeader::handleChannelChanged()
|
||||
{
|
||||
// Disconnect any previous signal first
|
||||
this->onlineStatusChangedConnection_.disconnect();
|
||||
this->channelConnections_.clear();
|
||||
|
||||
auto channel = this->split_->getChannel();
|
||||
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
|
||||
if (twitchChannel) {
|
||||
this->managedConnections_.emplace_back(
|
||||
twitchChannel->liveStatusChanged.connect([this]() {
|
||||
this->updateChannelText(); //
|
||||
}));
|
||||
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) {
|
||||
this->channelConnections_.emplace_back(
|
||||
twitchChannel->liveStatusChanged.connect(
|
||||
[this]() { this->updateChannelText(); }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,89 +351,47 @@ void SplitHeader::scaleChangedEvent(float scale)
|
||||
this->setFixedHeight(w);
|
||||
this->dropdownButton_->setFixedWidth(w);
|
||||
this->moderationButton_->setFixedWidth(w);
|
||||
// this->titleLabel->setFont(
|
||||
// FontManager::getInstance().getFont(FontStyle::Medium, scale));
|
||||
}
|
||||
|
||||
void SplitHeader::updateChannelText()
|
||||
{
|
||||
auto indirectChannel = this->split_->getIndirectChannel();
|
||||
auto channel = this->split_->getChannel();
|
||||
this->isLive_ = false;
|
||||
this->tooltipText_ = QString();
|
||||
|
||||
QString title = channel->getName();
|
||||
auto title = channel->getName();
|
||||
|
||||
if (indirectChannel.getType() == Channel::Type::TwitchWatching) {
|
||||
if (indirectChannel.getType() == Channel::Type::TwitchWatching)
|
||||
title = "watching: " + (title.isEmpty() ? "none" : title);
|
||||
}
|
||||
|
||||
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
|
||||
if (twitchChannel != nullptr) {
|
||||
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) {
|
||||
const auto streamStatus = twitchChannel->accessStreamStatus();
|
||||
|
||||
if (streamStatus->live) {
|
||||
this->isLive_ = true;
|
||||
this->tooltip_ = "<style>.center { text-align: center; }</style>"
|
||||
"<p class = \"center\">" +
|
||||
streamStatus->title + "<br><br>" +
|
||||
streamStatus->game + "<br>" +
|
||||
(streamStatus->rerun ? "Vod-casting" : "Live") +
|
||||
" for " + streamStatus->uptime + " with " +
|
||||
QString::number(streamStatus->viewerCount) +
|
||||
" viewers"
|
||||
"</p>";
|
||||
if (streamStatus->rerun) {
|
||||
title += " (rerun)";
|
||||
} else if (streamStatus->streamType.isEmpty()) {
|
||||
title += " (" + streamStatus->streamType + ")";
|
||||
} else {
|
||||
title += " (live)";
|
||||
}
|
||||
if (getSettings()->showViewerCount) {
|
||||
title += " - " + QString::number(streamStatus->viewerCount) +
|
||||
" viewers";
|
||||
}
|
||||
if (getSettings()->showTitle) {
|
||||
title += " - " + streamStatus->title;
|
||||
}
|
||||
if (getSettings()->showGame) {
|
||||
title += " - " + streamStatus->game;
|
||||
}
|
||||
if (getSettings()->showUptime) {
|
||||
title += " - uptime: " + streamStatus->uptime;
|
||||
}
|
||||
} else {
|
||||
this->tooltip_ = QString();
|
||||
this->tooltipText_ = formatTooltip(*streamStatus);
|
||||
title += formatTitle(*streamStatus, *getSettings());
|
||||
}
|
||||
}
|
||||
|
||||
if (title.isEmpty()) {
|
||||
title = "<empty>";
|
||||
}
|
||||
|
||||
this->isLive_ = false;
|
||||
this->titleLabel->setText(title);
|
||||
this->titleLabel->setText(title.isEmpty() ? "<empty>" : title);
|
||||
}
|
||||
|
||||
void SplitHeader::updateModerationModeIcon()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
this->moderationButton_->setPixmap(
|
||||
this->split_->getModerationMode()
|
||||
? app->resources->buttons.modModeEnabled
|
||||
: app->resources->buttons.modModeDisabled);
|
||||
|
||||
bool modButtonVisible = false;
|
||||
ChannelPtr channel = this->split_->getChannel();
|
||||
? getApp()->resources->buttons.modModeEnabled
|
||||
: getApp()->resources->buttons.modModeDisabled);
|
||||
|
||||
auto channel = this->split_->getChannel();
|
||||
auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
|
||||
if (twitchChannel != nullptr && twitchChannel->hasModRights()) {
|
||||
modButtonVisible = true;
|
||||
}
|
||||
|
||||
this->moderationButton_->setVisible(modButtonVisible);
|
||||
if (twitchChannel != nullptr && twitchChannel->hasModRights())
|
||||
this->moderationButton_->show();
|
||||
else
|
||||
this->moderationButton_->hide();
|
||||
}
|
||||
|
||||
void SplitHeader::paintEvent(QPaintEvent *)
|
||||
@@ -453,7 +417,7 @@ void SplitHeader::mousePressEvent(QMouseEvent *event)
|
||||
void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (this->dragging_ && event->button() == Qt::LeftButton) {
|
||||
QPoint pos = event->globalPos();
|
||||
auto pos = event->globalPos();
|
||||
|
||||
if (!showingHelpTooltip_) {
|
||||
this->showingHelpTooltip_ = true;
|
||||
@@ -465,18 +429,18 @@ void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
TooltipWidget *widget = new TooltipWidget();
|
||||
auto tooltip = new TooltipWidget();
|
||||
|
||||
widget->setText("Double click or press <Ctrl+R> to change the "
|
||||
"channel.\nClick and "
|
||||
"drag to move the split.");
|
||||
widget->setAttribute(Qt::WA_DeleteOnClose);
|
||||
widget->move(pos);
|
||||
widget->show();
|
||||
widget->raise();
|
||||
tooltip->setText("Double click or press <Ctrl+R> to change the "
|
||||
"channel.\nClick and "
|
||||
"drag to move the split.");
|
||||
tooltip->setAttribute(Qt::WA_DeleteOnClose);
|
||||
tooltip->move(pos);
|
||||
tooltip->show();
|
||||
tooltip->raise();
|
||||
|
||||
QTimer::singleShot(3000, widget, [this, widget] {
|
||||
widget->close();
|
||||
QTimer::singleShot(3000, tooltip, [this, tooltip] {
|
||||
tooltip->close();
|
||||
this->showingHelpTooltip_ = false;
|
||||
});
|
||||
});
|
||||
@@ -489,10 +453,7 @@ void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
|
||||
void SplitHeader::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (this->dragging_) {
|
||||
if (std::abs(this->dragStart_.x() - event->pos().x()) >
|
||||
int(12 * this->getScale()) ||
|
||||
std::abs(this->dragStart_.y() - event->pos().y()) >
|
||||
int(12 * this->getScale())) {
|
||||
if (distance(this->dragStart_, event->pos()) > 15 * this->getScale()) {
|
||||
this->split_->drag();
|
||||
this->dragging_ = false;
|
||||
}
|
||||
@@ -502,20 +463,20 @@ void SplitHeader::mouseMoveEvent(QMouseEvent *event)
|
||||
void SplitHeader::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
this->split_->doChangeChannel();
|
||||
this->split_->changeChannel();
|
||||
}
|
||||
this->doubleClicked_ = true;
|
||||
}
|
||||
|
||||
void SplitHeader::enterEvent(QEvent *event)
|
||||
{
|
||||
if (!this->tooltip_.isEmpty()) {
|
||||
auto tooltipWidget = TooltipWidget::getInstance();
|
||||
tooltipWidget->moveTo(
|
||||
this, this->mapToGlobal(this->rect().bottomLeft()), false);
|
||||
tooltipWidget->setText(this->tooltip_);
|
||||
tooltipWidget->show();
|
||||
tooltipWidget->raise();
|
||||
if (!this->tooltipText_.isEmpty()) {
|
||||
auto tooltip = TooltipWidget::getInstance();
|
||||
tooltip->moveTo(this, this->mapToGlobal(this->rect().bottomLeft()),
|
||||
false);
|
||||
tooltip->setText(this->tooltipText_);
|
||||
tooltip->show();
|
||||
tooltip->raise();
|
||||
}
|
||||
|
||||
BaseWidget::enterEvent(event);
|
||||
@@ -528,13 +489,9 @@ void SplitHeader::leaveEvent(QEvent *event)
|
||||
BaseWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void SplitHeader::rightButtonClicked()
|
||||
{
|
||||
}
|
||||
|
||||
void SplitHeader::themeChangedEvent()
|
||||
{
|
||||
QPalette palette;
|
||||
auto palette = QPalette();
|
||||
|
||||
if (this->split_->hasFocus()) {
|
||||
palette.setColor(QPalette::Foreground,
|
||||
@@ -542,41 +499,32 @@ void SplitHeader::themeChangedEvent()
|
||||
} else {
|
||||
palette.setColor(QPalette::Foreground, this->theme->splits.header.text);
|
||||
}
|
||||
this->titleLabel->setPalette(palette);
|
||||
|
||||
// --
|
||||
if (this->theme->isLightTheme()) {
|
||||
this->dropdownButton_->setPixmap(getApp()->resources->buttons.menuDark);
|
||||
} else {
|
||||
this->dropdownButton_->setPixmap(
|
||||
getApp()->resources->buttons.menuLight);
|
||||
}
|
||||
|
||||
this->titleLabel->setPalette(palette);
|
||||
}
|
||||
|
||||
void SplitHeader::menuMoveSplit()
|
||||
void SplitHeader::moveSplit()
|
||||
{
|
||||
}
|
||||
|
||||
void SplitHeader::menuReloadChannelEmotes()
|
||||
void SplitHeader::reloadChannelEmotes()
|
||||
{
|
||||
auto channel = this->split_->getChannel();
|
||||
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
||||
|
||||
if (twitchChannel) {
|
||||
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()))
|
||||
twitchChannel->refreshChannelEmotes();
|
||||
}
|
||||
}
|
||||
|
||||
void SplitHeader::menuManualReconnect()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
// fourtf: connection
|
||||
app->twitch.server->connect();
|
||||
}
|
||||
|
||||
void SplitHeader::menuShowChangelog()
|
||||
void SplitHeader::reconnect()
|
||||
{
|
||||
getApp()->twitch.server->connect();
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,37 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
#include "widgets/helper/SignalLabel.hpp"
|
||||
|
||||
#include <QAction>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QPaintEvent>
|
||||
#include <QPoint>
|
||||
#include <QWidget>
|
||||
#include <memory>
|
||||
#include <pajlada/settings/setting.hpp>
|
||||
#include <pajlada/signals/connection.hpp>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Split;
|
||||
class Button;
|
||||
class EffectLabel;
|
||||
class Label;
|
||||
class Split;
|
||||
|
||||
class SplitHeader : public BaseWidget, pajlada::Signals::SignalHolder
|
||||
class SplitHeader final : public BaseWidget, pajlada::Signals::SignalHolder
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SplitHeader(Split *_chatWidget);
|
||||
virtual ~SplitHeader() override;
|
||||
|
||||
// Update channel text from chat widget
|
||||
void updateChannelText();
|
||||
void updateModerationModeIcon();
|
||||
void updateRoomModes();
|
||||
@@ -49,41 +41,38 @@ protected:
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
void rightButtonClicked();
|
||||
void initializeChannelSignals();
|
||||
void setupModeLabel(RippleEffectLabel &label);
|
||||
void initializeLayout();
|
||||
void initializeModeSignals(EffectLabel &label);
|
||||
std::unique_ptr<QMenu> createMainMenu();
|
||||
std::unique_ptr<QMenu> createChatModeMenu();
|
||||
void handleChannelChanged();
|
||||
|
||||
Split *split_;
|
||||
Split *const split_{};
|
||||
QString tooltipText_{};
|
||||
bool isLive_{false};
|
||||
|
||||
QPoint dragStart_;
|
||||
bool dragging_ = false;
|
||||
bool doubleClicked_ = false;
|
||||
bool showingHelpTooltip_ = false;
|
||||
|
||||
pajlada::Signals::Connection onlineStatusChangedConnection_;
|
||||
|
||||
RippleEffectButton *dropdownButton_{};
|
||||
// Label *titleLabel{};
|
||||
// ui
|
||||
Button *dropdownButton_{};
|
||||
Label *titleLabel{};
|
||||
RippleEffectLabel *modeButton_{};
|
||||
RippleEffectButton *moderationButton_{};
|
||||
EffectLabel *modeButton_{};
|
||||
Button *moderationButton_{};
|
||||
|
||||
bool menuVisible_{};
|
||||
// states
|
||||
QPoint dragStart_{};
|
||||
bool dragging_{false};
|
||||
bool doubleClicked_{false};
|
||||
bool showingHelpTooltip_{false};
|
||||
bool menuVisible_{false};
|
||||
|
||||
// signals
|
||||
pajlada::Signals::NoArgSignal modeUpdateRequested_;
|
||||
|
||||
QString tooltip_;
|
||||
bool isLive_;
|
||||
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> channelConnections_;
|
||||
|
||||
public slots:
|
||||
void menuMoveSplit();
|
||||
void menuReloadChannelEmotes();
|
||||
void menuManualReconnect();
|
||||
void menuShowChangelog();
|
||||
void moveSplit();
|
||||
void reloadChannelEmotes();
|
||||
void reconnect();
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -2,14 +2,20 @@
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "controllers/commands/CommandController.hpp"
|
||||
#include "messages/Link.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchServer.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "util/LayoutCreator.hpp"
|
||||
#include "widgets/Notebook.hpp"
|
||||
#include "widgets/dialogs/EmotePopup.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/helper/ResizingTextEdit.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
#include "widgets/splits/SplitInput.hpp"
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QPainter>
|
||||
@@ -61,7 +67,7 @@ void SplitInput::initLayout()
|
||||
textEditLength->setAlignment(Qt::AlignRight);
|
||||
|
||||
box->addStretch(1);
|
||||
box.emplace<RippleEffectLabel>().assign(&this->ui_.emoteButton);
|
||||
box.emplace<EffectLabel>().assign(&this->ui_.emoteButton);
|
||||
}
|
||||
|
||||
this->ui_.emoteButton->getLabel().setTextFormat(Qt::RichText);
|
||||
@@ -70,42 +76,40 @@ void SplitInput::initLayout()
|
||||
|
||||
// set edit font
|
||||
this->ui_.textEdit->setFont(
|
||||
app->fonts->getFont(Fonts::Type::ChatMedium, this->getScale()));
|
||||
app->fonts->getFont(FontStyle::ChatMedium, this->getScale()));
|
||||
|
||||
this->managedConnections_.push_back(app->fonts->fontChanged.connect([=]() {
|
||||
this->ui_.textEdit->setFont(
|
||||
app->fonts->getFont(Fonts::Type::ChatMedium, this->getScale()));
|
||||
app->fonts->getFont(FontStyle::ChatMedium, this->getScale()));
|
||||
}));
|
||||
|
||||
// open emote popup
|
||||
QObject::connect(
|
||||
this->ui_.emoteButton, &RippleEffectLabel::clicked, [this] {
|
||||
if (!this->emotePopup_) {
|
||||
this->emotePopup_ = std::make_unique<EmotePopup>();
|
||||
this->emotePopup_->linkClicked.connect(
|
||||
[this](const Link &link) {
|
||||
if (link.type == Link::InsertText) {
|
||||
this->insertText(link.value + " ");
|
||||
}
|
||||
});
|
||||
}
|
||||
QObject::connect(this->ui_.emoteButton, &EffectLabel::clicked, [this] {
|
||||
if (!this->emotePopup_) {
|
||||
this->emotePopup_ = std::make_unique<EmotePopup>();
|
||||
this->emotePopup_->linkClicked.connect([this](const Link &link) {
|
||||
if (link.type == Link::InsertText) {
|
||||
this->insertText(link.value + " ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this->emotePopup_->resize(int(300 * this->emotePopup_->getScale()),
|
||||
int(500 * this->emotePopup_->getScale()));
|
||||
this->emotePopup_->loadChannel(this->split_->getChannel());
|
||||
this->emotePopup_->show();
|
||||
});
|
||||
this->emotePopup_->resize(int(300 * this->emotePopup_->getScale()),
|
||||
int(500 * this->emotePopup_->getScale()));
|
||||
this->emotePopup_->loadChannel(this->split_->getChannel());
|
||||
this->emotePopup_->show();
|
||||
});
|
||||
|
||||
// clear channelview selection when selecting in the input
|
||||
QObject::connect(this->ui_.textEdit, &QTextEdit::copyAvailable,
|
||||
[this](bool available) {
|
||||
if (available) {
|
||||
this->split_->view_.clearSelection();
|
||||
this->split_->view_->clearSelection();
|
||||
}
|
||||
});
|
||||
|
||||
// textEditLength visibility
|
||||
app->settings->showMessageLength.connect(
|
||||
getSettings()->showMessageLength.connect(
|
||||
[this](const bool &value, auto) {
|
||||
this->ui_.textEditLength->setHidden(!value);
|
||||
},
|
||||
@@ -172,8 +176,9 @@ void SplitInput::installKeyPressedEvent()
|
||||
sendMessage = sendMessage.replace('\n', ' ');
|
||||
|
||||
c->sendMessage(sendMessage);
|
||||
// don't add duplicate messages to message history
|
||||
if (this->prevMsg_.isEmpty() || !this->prevMsg_.endsWith(message))
|
||||
// don't add duplicate messages and empty message to message history
|
||||
if ((this->prevMsg_.isEmpty() || !this->prevMsg_.endsWith(message)) &&
|
||||
!message.trimmed().isEmpty())
|
||||
this->prevMsg_.append(message);
|
||||
|
||||
event->accept();
|
||||
@@ -275,7 +280,7 @@ void SplitInput::installKeyPressedEvent()
|
||||
}
|
||||
} else if (event->key() == Qt::Key_C &&
|
||||
event->modifiers() == Qt::ControlModifier) {
|
||||
if (this->split_->view_.hasSelection()) {
|
||||
if (this->split_->view_->hasSelection()) {
|
||||
this->split_->copyToClipboard();
|
||||
event->accept();
|
||||
}
|
||||
@@ -346,7 +351,7 @@ void SplitInput::paintEvent(QPaintEvent *)
|
||||
|
||||
if (this->theme->isLightTheme()) {
|
||||
int s = int(3 * this->getScale());
|
||||
QRect rect = this->rect().marginsRemoved(QMargins(s, s, s, s));
|
||||
QRect rect = this->rect().marginsRemoved(QMargins(s - 1, s - 1, s, s));
|
||||
|
||||
painter.fillRect(rect, this->theme->splits.input.background);
|
||||
|
||||
@@ -354,7 +359,7 @@ void SplitInput::paintEvent(QPaintEvent *)
|
||||
painter.drawRect(rect);
|
||||
} else {
|
||||
int s = int(1 * this->getScale());
|
||||
QRect rect = this->rect().marginsRemoved(QMargins(s, s, s, s));
|
||||
QRect rect = this->rect().marginsRemoved(QMargins(s - 1, s - 1, s, s));
|
||||
|
||||
painter.fillRect(rect, this->theme->splits.input.background);
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
#include "widgets/dialogs/EmotePopup.hpp"
|
||||
#include "widgets/helper/ResizingTextEdit.hpp"
|
||||
#include "widgets/helper/RippleEffectLabel.hpp"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
@@ -16,6 +13,9 @@
|
||||
namespace chatterino {
|
||||
|
||||
class Split;
|
||||
class EmotePopup;
|
||||
class EffectLabel;
|
||||
class ResizingTextEdit;
|
||||
|
||||
class SplitInput : public BaseWidget
|
||||
{
|
||||
@@ -45,12 +45,12 @@ private:
|
||||
void updateEmoteButton();
|
||||
|
||||
Split *const split_;
|
||||
std::unique_ptr<EmotePopup> emotePopup_;
|
||||
std::shared_ptr<EmotePopup> emotePopup_;
|
||||
|
||||
struct {
|
||||
ResizingTextEdit *textEdit;
|
||||
QLabel *textEditLength;
|
||||
RippleEffectLabel *emoteButton;
|
||||
EffectLabel *emoteButton;
|
||||
|
||||
QHBoxLayout *hbox;
|
||||
} ui_;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/Resources.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user