refined SplitHeader

This commit is contained in:
fourtf 2018-08-08 15:35:54 +02:00
parent 7a9af4ae84
commit d89b62692a
30 changed files with 422 additions and 464 deletions

View file

@ -186,8 +186,6 @@ SOURCES += \
src/widgets/helper/NotebookButton.cpp \ src/widgets/helper/NotebookButton.cpp \
src/widgets/helper/NotebookTab.cpp \ src/widgets/helper/NotebookTab.cpp \
src/widgets/helper/ResizingTextEdit.cpp \ src/widgets/helper/ResizingTextEdit.cpp \
src/widgets/helper/RippleEffectButton.cpp \
src/widgets/helper/RippleEffectLabel.cpp \
src/widgets/helper/ScrollbarHighlight.cpp \ src/widgets/helper/ScrollbarHighlight.cpp \
src/widgets/helper/SearchPopup.cpp \ src/widgets/helper/SearchPopup.cpp \
src/widgets/helper/SettingsDialogTab.cpp \ src/widgets/helper/SettingsDialogTab.cpp \
@ -250,7 +248,9 @@ SOURCES += \
src/RunGui.cpp \ src/RunGui.cpp \
src/BrowserExtension.cpp \ src/BrowserExtension.cpp \
src/util/FormatTime.cpp \ src/util/FormatTime.cpp \
src/util/FunctionEventFilter.cpp src/util/FunctionEventFilter.cpp \
src/widgets/helper/EffectLabel.cpp \
src/widgets/helper/Button.cpp
HEADERS += \ HEADERS += \
src/Application.hpp \ src/Application.hpp \
@ -374,8 +374,6 @@ HEADERS += \
src/widgets/helper/NotebookButton.hpp \ src/widgets/helper/NotebookButton.hpp \
src/widgets/helper/NotebookTab.hpp \ src/widgets/helper/NotebookTab.hpp \
src/widgets/helper/ResizingTextEdit.hpp \ src/widgets/helper/ResizingTextEdit.hpp \
src/widgets/helper/RippleEffectButton.hpp \
src/widgets/helper/RippleEffectLabel.hpp \
src/widgets/helper/ScrollbarHighlight.hpp \ src/widgets/helper/ScrollbarHighlight.hpp \
src/widgets/helper/SearchPopup.hpp \ src/widgets/helper/SearchPopup.hpp \
src/widgets/helper/SettingsDialogTab.hpp \ src/widgets/helper/SettingsDialogTab.hpp \
@ -448,7 +446,10 @@ HEADERS += \
src/RunGui.hpp \ src/RunGui.hpp \
src/BrowserExtension.hpp \ src/BrowserExtension.hpp \
src/util/FormatTime.hpp \ src/util/FormatTime.hpp \
src/util/FunctionEventFilter.hpp src/util/FunctionEventFilter.hpp \
src/widgets/helper/EffectLabel.hpp \
src/util/LayoutHelper.hpp \
src/widgets/helper/Button.hpp
RESOURCES += \ RESOURCES += \
resources/resources.qrc \ resources/resources.qrc \

View file

@ -82,6 +82,7 @@ MessageBuilder::MessageBuilder(TimeoutMessageTag, const QString &username,
} }
MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count) MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count)
: MessageBuilder()
{ {
this->emplace<TimestampElement>(); this->emplace<TimestampElement>();
this->message().flags.set(MessageFlag::System); this->message().flags.set(MessageFlag::System);
@ -127,6 +128,7 @@ MessageBuilder::MessageBuilder(const BanAction &action, uint32_t count)
} }
MessageBuilder::MessageBuilder(const UnbanAction &action) MessageBuilder::MessageBuilder(const UnbanAction &action)
: MessageBuilder()
{ {
this->emplace<TimestampElement>(); this->emplace<TimestampElement>();
this->message().flags.set(MessageFlag::System); this->message().flags.set(MessageFlag::System);

View file

@ -161,6 +161,6 @@ private:
std::unique_ptr<rapidjson::Document> snapshot_; std::unique_ptr<rapidjson::Document> snapshot_;
}; };
[[deprecated]] Settings *getSettings(); Settings *getSettings();
} // namespace chatterino } // namespace chatterino

View file

@ -1,18 +1,18 @@
#include "InitUpdateButton.hpp" #include "InitUpdateButton.hpp"
#include "widgets/dialogs/UpdateDialog.hpp" #include "widgets/dialogs/UpdateDialog.hpp"
#include "widgets/helper/RippleEffectButton.hpp" #include "widgets/helper/Button.hpp"
namespace chatterino { namespace chatterino {
void initUpdateButton(RippleEffectButton &button, void initUpdateButton(Button &button,
std::unique_ptr<UpdateDialog> &handle, std::unique_ptr<UpdateDialog> &handle,
pajlada::Signals::SignalHolder &signalHolder) pajlada::Signals::SignalHolder &signalHolder)
{ {
button.hide(); button.hide();
// show update prompt when clicking the button // show update prompt when clicking the button
QObject::connect(&button, &RippleEffectButton::clicked, [&button, &handle] { QObject::connect(&button, &Button::clicked, [&button, &handle] {
(void)(handle); (void)(handle);
auto dialog = new UpdateDialog(); auto dialog = new UpdateDialog();

View file

@ -10,10 +10,10 @@ class SignalHolder;
namespace chatterino { namespace chatterino {
class RippleEffectButton; class Button;
class UpdateDialog; class UpdateDialog;
void initUpdateButton(RippleEffectButton &button, void initUpdateButton(Button &button,
std::unique_ptr<UpdateDialog> &handle, std::unique_ptr<UpdateDialog> &handle,
pajlada::Signals::SignalHolder &signalHolder); pajlada::Signals::SignalHolder &signalHolder);

40
src/util/LayoutHelper.hpp Normal file
View file

@ -0,0 +1,40 @@
#pragma once
#include <QLayout>
#include <QWidget>
#include <boost/variant.hpp>
namespace chatterino {
using LayoutItem = boost::variant<QWidget *, QLayout *>;
template <typename T>
T *makeLayout(std::initializer_list<LayoutItem> items)
{
auto t = new T;
for (auto &item : items) {
switch (item.which()) {
case 0:
t->addItem(new QWidgetItem(boost::get<QWidget *>(item)));
break;
case 1:
t->addItem(boost::get<QLayout *>(item));
break;
}
}
return t;
}
template <typename T, typename With>
T *makeWidget(With with)
{
auto t = new T;
with(t);
return t;
}
} // namespace chatterino

View file

@ -9,7 +9,7 @@
#include "util/WindowsHelper.hpp" #include "util/WindowsHelper.hpp"
#include "widgets/Label.hpp" #include "widgets/Label.hpp"
#include "widgets/TooltipWidget.hpp" #include "widgets/TooltipWidget.hpp"
#include "widgets/helper/RippleEffectLabel.hpp" #include "widgets/helper/EffectLabel.hpp"
#include "widgets/helper/Shortcut.hpp" #include "widgets/helper/Shortcut.hpp"
#include <QApplication> #include <QApplication>
@ -239,7 +239,7 @@ void BaseWindow::themeChangedEvent()
this->ui_.titleLabel->setPalette(palette_title); this->ui_.titleLabel->setPalette(palette_title);
} }
for (RippleEffectButton *button : this->ui_.buttons) { for (Button *button : this->ui_.buttons) {
button->setMouseEffectColor(this->theme->window.text); button->setMouseEffectColor(this->theme->window.text);
} }
} else { } else {
@ -371,15 +371,15 @@ TitleBarButton *BaseWindow::addTitleBarButton(
return button; 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); button->setScaleIndependantHeight(30);
this->ui_.buttons.push_back(button); this->ui_.buttons.push_back(button);
this->ui_.titlebarBox->insertWidget(1, button); this->ui_.titlebarBox->insertWidget(1, button);
QObject::connect(button, &RippleEffectLabel::clicked, this, QObject::connect(button, &EffectLabel::clicked, this,
[onClicked] { onClicked(); }); [onClicked] { onClicked(); });
return button; return button;

View file

@ -12,8 +12,8 @@ typedef struct tagMSG MSG;
namespace chatterino { namespace chatterino {
class RippleEffectButton; class Button;
class RippleEffectLabel; class EffectLabel;
class TitleBarButton; class TitleBarButton;
class BaseWindow : public BaseWidget class BaseWindow : public BaseWidget
@ -38,7 +38,7 @@ public:
bool hasCustomWindowFrame(); bool hasCustomWindowFrame();
TitleBarButton *addTitleBarButton(const TitleBarButton::Style &style, TitleBarButton *addTitleBarButton(const TitleBarButton::Style &style,
std::function<void()> onClicked); std::function<void()> onClicked);
RippleEffectLabel *addTitleBarLabel(std::function<void()> onClicked); EffectLabel *addTitleBarLabel(std::function<void()> onClicked);
void setStayInScreenRect(bool value); void setStayInScreenRect(bool value);
bool getStayInScreenRect() const; bool getStayInScreenRect() const;
@ -109,7 +109,7 @@ private:
TitleBarButton *maxButton = nullptr; TitleBarButton *maxButton = nullptr;
TitleBarButton *exitButton = nullptr; TitleBarButton *exitButton = nullptr;
QWidget *layoutBase = nullptr; QWidget *layoutBase = nullptr;
std::vector<RippleEffectButton *> buttons; std::vector<Button *> buttons;
} ui_; } ui_;
pajlada::Signals::SignalHolder connections_; pajlada::Signals::SignalHolder connections_;

View file

@ -48,7 +48,7 @@ private:
Type type_; Type type_;
SplitNotebook notebook_; SplitNotebook notebook_;
RippleEffectLabel *userLabel_ = nullptr; EffectLabel *userLabel_ = nullptr;
std::unique_ptr<UpdateDialog> updateDialogHandle_; std::unique_ptr<UpdateDialog> updateDialogHandle_;
pajlada::Signals::SignalHolder signalHolder_; pajlada::Signals::SignalHolder signalHolder_;

View file

@ -11,8 +11,8 @@
#include "util/PostToThread.hpp" #include "util/PostToThread.hpp"
#include "widgets/Label.hpp" #include "widgets/Label.hpp"
#include "widgets/dialogs/LogsPopup.hpp" #include "widgets/dialogs/LogsPopup.hpp"
#include "widgets/helper/EffectLabel.hpp"
#include "widgets/helper/Line.hpp" #include "widgets/helper/Line.hpp"
#include "widgets/helper/RippleEffectLabel.hpp"
#include <QCheckBox> #include <QCheckBox>
#include <QDesktopServices> #include <QDesktopServices>
@ -46,14 +46,13 @@ UserInfoPopup::UserInfoPopup()
auto head = layout.emplace<QHBoxLayout>().withoutMargin(); auto head = layout.emplace<QHBoxLayout>().withoutMargin();
{ {
// avatar // avatar
auto avatar = head.emplace<RippleEffectButton>(nullptr).assign( auto avatar =
&this->ui_.avatarButton); head.emplace<Button>(nullptr).assign(&this->ui_.avatarButton);
avatar->setScaleIndependantSize(100, 100); avatar->setScaleIndependantSize(100, 100);
QObject::connect(avatar.getElement(), &RippleEffectButton::clicked, QObject::connect(avatar.getElement(), &Button::clicked, [this] {
[this] { QDesktopServices::openUrl(
QDesktopServices::openUrl( QUrl("https://twitch.tv/" + this->userName_));
QUrl("https://twitch.tv/" + this->userName_)); });
});
// items on the right // items on the right
auto vbox = head.emplace<QVBoxLayout>(); auto vbox = head.emplace<QVBoxLayout>();
@ -82,33 +81,31 @@ UserInfoPopup::UserInfoPopup()
user.emplace<QCheckBox>("Ignore").assign(&this->ui_.ignore); user.emplace<QCheckBox>("Ignore").assign(&this->ui_.ignore);
user.emplace<QCheckBox>("Ignore highlights") user.emplace<QCheckBox>("Ignore highlights")
.assign(&this->ui_.ignoreHighlights); .assign(&this->ui_.ignoreHighlights);
auto viewLogs = user.emplace<RippleEffectLabel2>(this); auto viewLogs = user.emplace<EffectLabel2>(this);
viewLogs->getLabel().setText("Online logs"); viewLogs->getLabel().setText("Online logs");
auto mod = user.emplace<RippleEffectButton>(this); auto mod = user.emplace<Button>(this);
mod->setPixmap(app->resources->buttons.mod); mod->setPixmap(app->resources->buttons.mod);
mod->setScaleIndependantSize(30, 30); mod->setScaleIndependantSize(30, 30);
auto unmod = user.emplace<RippleEffectButton>(this); auto unmod = user.emplace<Button>(this);
unmod->setPixmap(app->resources->buttons.unmod); unmod->setPixmap(app->resources->buttons.unmod);
unmod->setScaleIndependantSize(30, 30); unmod->setScaleIndependantSize(30, 30);
user->addStretch(1); user->addStretch(1);
QObject::connect(viewLogs.getElement(), &RippleEffectButton::clicked, QObject::connect(viewLogs.getElement(), &Button::clicked, [this] {
[this] { auto logs = new LogsPopup();
auto logs = new LogsPopup(); logs->setInfo(this->channel_, this->userName_);
logs->setInfo(this->channel_, this->userName_); logs->setAttribute(Qt::WA_DeleteOnClose);
logs->setAttribute(Qt::WA_DeleteOnClose); logs->show();
logs->show(); });
});
QObject::connect( QObject::connect(mod.getElement(), &Button::clicked, [this] {
mod.getElement(), &RippleEffectButton::clicked, this->channel_->sendMessage("/mod " + this->userName_);
[this] { this->channel_->sendMessage("/mod " + this->userName_); }); });
QObject::connect( QObject::connect(unmod.getElement(), &Button::clicked, [this] {
unmod.getElement(), &RippleEffectButton::clicked, [this] { this->channel_->sendMessage("/unmod " + this->userName_);
this->channel_->sendMessage("/unmod " + this->userName_); });
});
// userstate // userstate
this->userStateChanged_.connect([this, mod, unmod]() mutable { this->userStateChanged_.connect([this, mod, unmod]() mutable {
@ -429,14 +426,13 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin(); auto hbox = vbox.emplace<QHBoxLayout>().withoutMargin();
hbox->setSpacing(0); hbox->setSpacing(0);
{ {
auto button = hbox.emplace<RippleEffectButton>(nullptr); auto button = hbox.emplace<Button>(nullptr);
button->setPixmap(pixmap); button->setPixmap(pixmap);
button->setScaleIndependantSize(buttonHeight, buttonHeight); button->setScaleIndependantSize(buttonHeight, buttonHeight);
button->setBorderColor(QColor(255, 255, 255, 127)); button->setBorderColor(QColor(255, 255, 255, 127));
QObject::connect( QObject::connect(
button.getElement(), &RippleEffectButton::clicked, button.getElement(), &Button::clicked, [this, action] {
[this, action] {
this->buttonClicked.invoke(std::make_pair(action, -1)); this->buttonClicked.invoke(std::make_pair(action, -1));
}); });
} }
@ -458,7 +454,7 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
hbox->setSpacing(0); hbox->setSpacing(0);
for (const auto &item : items) { for (const auto &item : items) {
auto a = hbox.emplace<RippleEffectLabel2>(); auto a = hbox.emplace<EffectLabel2>();
a->getLabel().setText(std::get<0>(item)); a->getLabel().setText(std::get<0>(item));
if (std::get<0>(item).length() > 1) { if (std::get<0>(item).length() > 1) {
@ -468,7 +464,7 @@ UserInfoPopup::TimeoutWidget::TimeoutWidget()
} }
a->setBorderColor(color1); a->setBorderColor(color1);
QObject::connect(a.getElement(), &RippleEffectLabel2::clicked, QObject::connect(a.getElement(), &EffectLabel2::clicked,
[this, timeout = std::get<1>(item)] { [this, timeout = std::get<1>(item)] {
this->buttonClicked.invoke(std::make_pair( this->buttonClicked.invoke(std::make_pair(
Action::Timeout, timeout)); Action::Timeout, timeout));

View file

@ -40,7 +40,7 @@ private:
std::shared_ptr<bool> hack_; std::shared_ptr<bool> hack_;
struct { struct {
RippleEffectButton *avatarButton = nullptr; Button *avatarButton = nullptr;
// RippleEffectLabel2 *viewLogs = nullptr; // RippleEffectLabel2 *viewLogs = nullptr;
Label *nameLabel = nullptr; Label *nameLabel = nullptr;

View file

@ -1,4 +1,4 @@
#include "RippleEffectButton.hpp" #include "Button.hpp"
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
@ -10,11 +10,11 @@
namespace chatterino { namespace chatterino {
RippleEffectButton::RippleEffectButton(BaseWidget *parent) Button::Button(BaseWidget *parent)
: BaseWidget(parent) : BaseWidget(parent)
{ {
connect(&effectTimer_, &QTimer::timeout, this, connect(&effectTimer_, &QTimer::timeout, this,
&RippleEffectButton::onMouseEffectTimeout); &Button::onMouseEffectTimeout);
this->effectTimer_.setInterval(20); this->effectTimer_.setInterval(20);
this->effectTimer_.start(); this->effectTimer_.start();
@ -22,64 +22,64 @@ RippleEffectButton::RippleEffectButton(BaseWidget *parent)
this->setMouseTracking(true); this->setMouseTracking(true);
} }
void RippleEffectButton::setMouseEffectColor(boost::optional<QColor> color) void Button::setMouseEffectColor(boost::optional<QColor> color)
{ {
this->mouseEffectColor_ = color; this->mouseEffectColor_ = color;
} }
void RippleEffectButton::setPixmap(const QPixmap &_pixmap) void Button::setPixmap(const QPixmap &_pixmap)
{ {
this->pixmap_ = _pixmap; this->pixmap_ = _pixmap;
this->update(); this->update();
} }
const QPixmap &RippleEffectButton::getPixmap() const const QPixmap &Button::getPixmap() const
{ {
return this->pixmap_; return this->pixmap_;
} }
void RippleEffectButton::setDim(bool value) void Button::setDim(bool value)
{ {
this->dimPixmap_ = value; this->dimPixmap_ = value;
this->update(); this->update();
} }
bool RippleEffectButton::getDim() const bool Button::getDim() const
{ {
return this->dimPixmap_; return this->dimPixmap_;
} }
void RippleEffectButton::setEnable(bool value) void Button::setEnable(bool value)
{ {
this->enabled_ = value; this->enabled_ = value;
this->update(); this->update();
} }
bool RippleEffectButton::getEnable() const bool Button::getEnable() const
{ {
return this->enabled_; return this->enabled_;
} }
qreal RippleEffectButton::getCurrentDimAmount() const qreal Button::getCurrentDimAmount() const
{ {
return this->dimPixmap_ && !this->mouseOver_ ? 0.7 : 1; return this->dimPixmap_ && !this->mouseOver_ ? 0.7 : 1;
} }
void RippleEffectButton::setBorderColor(const QColor &color) void Button::setBorderColor(const QColor &color)
{ {
this->borderColor_ = color; this->borderColor_ = color;
this->update(); this->update();
} }
const QColor &RippleEffectButton::getBorderColor() const const QColor &Button::getBorderColor() const
{ {
return this->borderColor_; return this->borderColor_;
} }
void RippleEffectButton::setMenu(std::unique_ptr<QMenu> menu) void Button::setMenu(std::unique_ptr<QMenu> menu)
{ {
this->menu_ = std::move(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); QPainter painter(this);
@ -126,7 +126,7 @@ void RippleEffectButton::paintEvent(QPaintEvent *)
} }
} }
void RippleEffectButton::fancyPaint(QPainter &painter) void Button::fancyPaint(QPainter &painter)
{ {
if (!this->enabled_) { if (!this->enabled_) {
return; return;
@ -169,17 +169,17 @@ void RippleEffectButton::fancyPaint(QPainter &painter)
} }
} }
void RippleEffectButton::enterEvent(QEvent *) void Button::enterEvent(QEvent *)
{ {
this->mouseOver_ = true; this->mouseOver_ = true;
} }
void RippleEffectButton::leaveEvent(QEvent *) void Button::leaveEvent(QEvent *)
{ {
this->mouseOver_ = false; this->mouseOver_ = false;
} }
void RippleEffectButton::mousePressEvent(QMouseEvent *event) void Button::mousePressEvent(QMouseEvent *event)
{ {
if (!this->enabled_) { if (!this->enabled_) {
return; return;
@ -200,7 +200,7 @@ void RippleEffectButton::mousePressEvent(QMouseEvent *event)
} }
} }
void RippleEffectButton::mouseReleaseEvent(QMouseEvent *event) void Button::mouseReleaseEvent(QMouseEvent *event)
{ {
if (!this->enabled_) { if (!this->enabled_) {
return; return;
@ -217,7 +217,7 @@ void RippleEffectButton::mouseReleaseEvent(QMouseEvent *event)
} }
} }
void RippleEffectButton::mouseMoveEvent(QMouseEvent *event) void Button::mouseMoveEvent(QMouseEvent *event)
{ {
if (!this->enabled_) { if (!this->enabled_) {
return; return;
@ -228,7 +228,7 @@ void RippleEffectButton::mouseMoveEvent(QMouseEvent *event)
this->update(); this->update();
} }
void RippleEffectButton::onMouseEffectTimeout() void Button::onMouseEffectTimeout()
{ {
bool performUpdate = false; bool performUpdate = false;
@ -272,7 +272,7 @@ void RippleEffectButton::onMouseEffectTimeout()
} }
} }
void RippleEffectButton::showMenu() void Button::showMenu()
{ {
if (!this->menu_) return; if (!this->menu_) return;

View file

@ -13,7 +13,7 @@
namespace chatterino { namespace chatterino {
class RippleEffectButton : public BaseWidget class Button : public BaseWidget
{ {
Q_OBJECT Q_OBJECT
@ -28,7 +28,7 @@ class RippleEffectButton : public BaseWidget
}; };
public: public:
RippleEffectButton(BaseWidget *parent); Button(BaseWidget *parent = nullptr);
void setMouseEffectColor(boost::optional<QColor> color); void setMouseEffectColor(boost::optional<QColor> color);
void setPixmap(const QPixmap &pixmap_); void setPixmap(const QPixmap &pixmap_);

View file

@ -133,7 +133,7 @@ ChannelView::ChannelView(BaseWidget *parent)
} }
})); }));
this->goToBottom_ = new RippleEffectLabel(this, 0); this->goToBottom_ = new EffectLabel(this, 0);
this->goToBottom_->setStyleSheet( this->goToBottom_->setStyleSheet(
"background-color: rgba(0,0,0,0.66); color: #FFF;"); "background-color: rgba(0,0,0,0.66); color: #FFF;");
this->goToBottom_->getLabel().setText("More messages below"); this->goToBottom_->getLabel().setText("More messages below");
@ -143,7 +143,7 @@ ChannelView::ChannelView(BaseWidget *parent)
this->layoutMessages(); // this->layoutMessages(); //
})); }));
QObject::connect(this->goToBottom_, &RippleEffectLabel::clicked, this, [=] { QObject::connect(this->goToBottom_, &EffectLabel::clicked, this, [=] {
QTimer::singleShot(180, [=] { QTimer::singleShot(180, [=] {
this->scrollBar_.scrollToBottom( this->scrollBar_.scrollToBottom(
app->settings->enableSmoothScrollingNewMessages.getValue()); app->settings->enableSmoothScrollingNewMessages.getValue());

View file

@ -8,7 +8,7 @@
#include "messages/layouts/MessageLayout.hpp" #include "messages/layouts/MessageLayout.hpp"
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/Scrollbar.hpp" #include "widgets/Scrollbar.hpp"
#include "widgets/helper/RippleEffectLabel.hpp" #include "widgets/helper/EffectLabel.hpp"
#include <QPaintEvent> #include <QPaintEvent>
#include <QScroller> #include <QScroller>
@ -115,7 +115,7 @@ private:
ChannelPtr channel_; ChannelPtr channel_;
Scrollbar scrollBar_; Scrollbar scrollBar_;
RippleEffectLabel *goToBottom_; EffectLabel *goToBottom_;
// This variable can be used to decide whether or not we should render the // This variable can be used to decide whether or not we should render the
// "Show latest messages" button // "Show latest messages" button

View file

@ -1,4 +1,4 @@
#include "widgets/helper/RippleEffectLabel.hpp" #include "widgets/helper/EffectLabel.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "widgets/splits/SplitHeader.hpp" #include "widgets/splits/SplitHeader.hpp"
@ -7,8 +7,8 @@
namespace chatterino { namespace chatterino {
RippleEffectLabel::RippleEffectLabel(BaseWidget *parent, int spacing) EffectLabel::EffectLabel(BaseWidget *parent, int spacing)
: RippleEffectButton(parent) : Button(parent)
, label_(this) , label_(this)
{ {
setLayout(&this->hbox_); setLayout(&this->hbox_);
@ -21,8 +21,8 @@ RippleEffectLabel::RippleEffectLabel(BaseWidget *parent, int spacing)
this->hbox_.addSpacing(spacing); this->hbox_.addSpacing(spacing);
} }
RippleEffectLabel2::RippleEffectLabel2(BaseWidget *parent, int padding) EffectLabel2::EffectLabel2(BaseWidget *parent, int padding)
: RippleEffectButton(parent) : Button(parent)
, label_(this) , label_(this)
{ {
auto *hbox = new QHBoxLayout(this); auto *hbox = new QHBoxLayout(this);
@ -37,7 +37,7 @@ RippleEffectLabel2::RippleEffectLabel2(BaseWidget *parent, int padding)
// hbox.addSpacing(spacing); // hbox.addSpacing(spacing);
} }
Label &RippleEffectLabel2::getLabel() Label &EffectLabel2::getLabel()
{ {
return this->label_; return this->label_;
} }

View file

@ -2,7 +2,7 @@
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/Label.hpp" #include "widgets/Label.hpp"
#include "widgets/helper/RippleEffectButton.hpp" #include "widgets/helper/Button.hpp"
#include "widgets/helper/SignalLabel.hpp" #include "widgets/helper/SignalLabel.hpp"
#include <QHBoxLayout> #include <QHBoxLayout>
@ -12,10 +12,10 @@
namespace chatterino { namespace chatterino {
class RippleEffectLabel : public RippleEffectButton class EffectLabel : public Button
{ {
public: public:
explicit RippleEffectLabel(BaseWidget *parent = nullptr, int spacing = 6); explicit EffectLabel(BaseWidget *parent = nullptr, int spacing = 6);
SignalLabel &getLabel() SignalLabel &getLabel()
{ {
@ -27,10 +27,10 @@ private:
SignalLabel label_; SignalLabel label_;
}; };
class RippleEffectLabel2 : public RippleEffectButton class EffectLabel2 : public Button
{ {
public: public:
explicit RippleEffectLabel2(BaseWidget *parent = nullptr, int padding = 6); explicit EffectLabel2(BaseWidget *parent = nullptr, int padding = 6);
Label &getLabel(); Label &getLabel();

View file

@ -1,7 +1,7 @@
#include "widgets/helper/NotebookButton.hpp" #include "widgets/helper/NotebookButton.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "widgets/Notebook.hpp" #include "widgets/Notebook.hpp"
#include "widgets/helper/RippleEffectButton.hpp" #include "widgets/helper/Button.hpp"
#include "widgets/splits/SplitContainer.hpp" #include "widgets/splits/SplitContainer.hpp"
#include <QMouseEvent> #include <QMouseEvent>
@ -14,7 +14,7 @@
namespace chatterino { namespace chatterino {
NotebookButton::NotebookButton(Notebook *parent) NotebookButton::NotebookButton(Notebook *parent)
: RippleEffectButton(parent) : Button(parent)
, parent_(parent) , parent_(parent)
{ {
this->setAcceptDrops(true); this->setAcceptDrops(true);
@ -122,7 +122,7 @@ void NotebookButton::paintEvent(QPaintEvent *event)
default:; default:;
} }
RippleEffectButton::paintEvent(event); Button::paintEvent(event);
} }
void NotebookButton::mouseReleaseEvent(QMouseEvent *event) void NotebookButton::mouseReleaseEvent(QMouseEvent *event)
@ -135,7 +135,7 @@ void NotebookButton::mouseReleaseEvent(QMouseEvent *event)
emit clicked(); emit clicked();
} }
RippleEffectButton::mouseReleaseEvent(event); Button::mouseReleaseEvent(event);
} }
void NotebookButton::dragEnterEvent(QDragEnterEvent *event) void NotebookButton::dragEnterEvent(QDragEnterEvent *event)
@ -149,7 +149,7 @@ void NotebookButton::dragEnterEvent(QDragEnterEvent *event)
auto e = new QMouseEvent(QMouseEvent::MouseButtonPress, auto e = new QMouseEvent(QMouseEvent::MouseButtonPress,
QPointF(this->width() / 2, this->height() / 2), QPointF(this->width() / 2, this->height() / 2),
Qt::LeftButton, Qt::LeftButton, 0); Qt::LeftButton, Qt::LeftButton, 0);
RippleEffectButton::mousePressEvent(e); Button::mousePressEvent(e);
delete e; delete e;
} }
@ -161,7 +161,7 @@ void NotebookButton::dragLeaveEvent(QDragLeaveEvent *)
auto e = new QMouseEvent(QMouseEvent::MouseButtonRelease, auto e = new QMouseEvent(QMouseEvent::MouseButtonRelease,
QPointF(this->width() / 2, this->height() / 2), QPointF(this->width() / 2, this->height() / 2),
Qt::LeftButton, Qt::LeftButton, 0); Qt::LeftButton, Qt::LeftButton, 0);
RippleEffectButton::mouseReleaseEvent(e); Button::mouseReleaseEvent(e);
delete e; delete e;
} }

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "RippleEffectButton.hpp" #include "Button.hpp"
#include <QWidget> #include <QWidget>
@ -8,7 +8,7 @@ namespace chatterino {
class Notebook; class Notebook;
class NotebookButton : public RippleEffectButton class NotebookButton : public Button
{ {
Q_OBJECT Q_OBJECT

View file

@ -21,7 +21,7 @@
namespace chatterino { namespace chatterino {
NotebookTab::NotebookTab(Notebook *notebook) NotebookTab::NotebookTab(Notebook *notebook)
: RippleEffectButton(notebook) : Button(notebook)
, positionChangedAnimation_(this, "pos") , positionChangedAnimation_(this, "pos")
, notebook_(notebook) , notebook_(notebook)
, menu_(this) , menu_(this)
@ -404,7 +404,7 @@ void NotebookTab::enterEvent(QEvent *event)
this->update(); this->update();
RippleEffectButton::enterEvent(event); Button::enterEvent(event);
} }
void NotebookTab::leaveEvent(QEvent *event) void NotebookTab::leaveEvent(QEvent *event)
@ -414,7 +414,7 @@ void NotebookTab::leaveEvent(QEvent *event)
this->update(); this->update();
RippleEffectButton::leaveEvent(event); Button::leaveEvent(event);
} }
void NotebookTab::dragEnterEvent(QDragEnterEvent *event) void NotebookTab::dragEnterEvent(QDragEnterEvent *event)
@ -459,7 +459,7 @@ void NotebookTab::mouseMoveEvent(QMouseEvent *event)
} }
} }
RippleEffectButton::mouseMoveEvent(event); Button::mouseMoveEvent(event);
} }
QRect NotebookTab::getXRect() QRect NotebookTab::getXRect()

View file

@ -2,7 +2,7 @@
#include "common/Common.hpp" #include "common/Common.hpp"
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/helper/RippleEffectButton.hpp" #include "widgets/helper/Button.hpp"
#include <QMenu> #include <QMenu>
#include <QPropertyAnimation> #include <QPropertyAnimation>
@ -17,7 +17,7 @@ namespace chatterino {
class Notebook; class Notebook;
class SplitContainer; class SplitContainer;
class NotebookTab : public RippleEffectButton class NotebookTab : public Button
{ {
Q_OBJECT Q_OBJECT

View file

@ -5,7 +5,7 @@
namespace chatterino { namespace chatterino {
TitleBarButton::TitleBarButton() TitleBarButton::TitleBarButton()
: RippleEffectButton(nullptr) : Button(nullptr)
{ {
} }
@ -119,7 +119,7 @@ void TitleBarButton::paintEvent(QPaintEvent *event)
default:; default:;
} }
RippleEffectButton::paintEvent(event); Button::paintEvent(event);
// this->fancyPaint(painter); // this->fancyPaint(painter);
} }

View file

@ -1,10 +1,10 @@
#pragma once #pragma once
#include "widgets/helper/RippleEffectButton.hpp" #include "widgets/helper/Button.hpp"
namespace chatterino { namespace chatterino {
class TitleBarButton : public RippleEffectButton class TitleBarButton : public Button
{ {
public: public:
enum Style { enum Style {

View file

@ -323,10 +323,10 @@ ChannelPtr LookPage::createPreviewChannel()
MessageBuilder builder; MessageBuilder builder;
builder.emplace<TimestampElement>(QTime(8, 13, 42)); 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.moderator), MessageElementFlag::BadgeChannelAuthority);
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.subscriber), MessageElementFlag::BadgeSubscription); builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->twitch.subscriber, 0.25), MessageElementFlag::BadgeSubscription);
builder.emplace<TextElement>("username1:", MessageElementFlag::Username, QColor("#0094FF"), FontStyle::ChatMediumBold); builder.emplace<TextElement>("username1:", MessageElementFlag::Username, QColor("#0094FF"), FontStyle::ChatMediumBold);
builder.emplace<TextElement>("This is a preview message", MessageElementFlag::Text); builder.emplace<TextElement>("This is a preview message", MessageElementFlag::Text);
builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->pajaDank), MessageElementFlag::AlwaysShow); builder.emplace<ImageElement>(Image::fromNonOwningPixmap(&getApp()->resources->pajaDank, 0.25), MessageElementFlag::AlwaysShow);
builder.emplace<TextElement>("@fourtf", MessageElementFlag::BoldUsername, MessageColor::Text, FontStyle::ChatMediumBold); builder.emplace<TextElement>("@fourtf", MessageElementFlag::BoldUsername, MessageColor::Text, FontStyle::ChatMediumBold);
builder.emplace<TextElement>("@fourtf", MessageElementFlag::NonBoldUsername); builder.emplace<TextElement>("@fourtf", MessageElementFlag::NonBoldUsername);
channel->addMessage(builder.release()); channel->addMessage(builder.release());

View file

@ -57,8 +57,6 @@ Split::Split(QWidget *parent)
, input_(this) , input_(this)
, overlay_(new SplitOverlay(this)) , overlay_(new SplitOverlay(this))
{ {
auto app = getApp();
this->setMouseTracking(true); this->setMouseTracking(true);
this->vbox_.setSpacing(0); this->vbox_.setSpacing(0);
@ -70,13 +68,13 @@ Split::Split(QWidget *parent)
// Initialize chat widget-wide hotkeys // Initialize chat widget-wide hotkeys
// CTRL+W: Close Split // CTRL+W: Close Split
createShortcut(this, "CTRL+W", &Split::doCloseSplit); createShortcut(this, "CTRL+W", &Split::deleteFromContainer);
// CTRL+R: Change Channel // CTRL+R: Change Channel
createShortcut(this, "CTRL+R", &Split::doChangeChannel); createShortcut(this, "CTRL+R", &Split::changeChannel);
// CTRL+F: Search // CTRL+F: Search
createShortcut(this, "CTRL+F", &Split::showSearchPopup); createShortcut(this, "CTRL+F", &Split::showSearch);
// F12 // F12
createShortcut(this, "F10", [] { createShortcut(this, "F10", [] {
@ -104,7 +102,7 @@ Split::Split(QWidget *parent)
}); });
this->input_.textChanged.connect([=](const QString &newText) { this->input_.textChanged.connect([=](const QString &newText) {
if (app->settings->showEmptyInput) { if (getSettings()->showEmptyInput) {
return; return;
} }
@ -115,7 +113,7 @@ Split::Split(QWidget *parent)
} }
}); });
app->settings->showEmptyInput.connect( getSettings()->showEmptyInput.connect(
[this](const bool &showEmptyInput, auto) { [this](const bool &showEmptyInput, auto) {
if (!showEmptyInput && this->input_.getInputText().length() == 0) { if (!showEmptyInput && this->input_.getInputText().length() == 0) {
this->input_.hide(); this->input_.hide();
@ -362,21 +360,21 @@ void Split::handleModifiers(Qt::KeyboardModifiers modifiers)
} }
/// Slots /// Slots
void Split::doAddSplit() void Split::addSibling()
{ {
if (this->container_) { if (this->container_) {
this->container_->appendNewSplit(true); this->container_->appendNewSplit(true);
} }
} }
void Split::doCloseSplit() void Split::deleteFromContainer()
{ {
if (this->container_) { if (this->container_) {
this->container_->deleteSplit(this); this->container_->deleteSplit(this);
} }
} }
void Split::doChangeChannel() void Split::changeChannel()
{ {
this->showChangeChannelPopup("Change channel", false, [](bool) {}); this->showChangeChannelPopup("Change channel", false, [](bool) {});
@ -388,7 +386,7 @@ void Split::doChangeChannel()
} }
} }
void Split::doPopup() void Split::popup()
{ {
auto app = getApp(); auto app = getApp();
Window &window = app->windows->createWindow(Window::Type::Popup); Window &window = app->windows->createWindow(Window::Type::Popup);
@ -402,7 +400,7 @@ void Split::doPopup()
window.show(); window.show();
} }
void Split::doClearChat() void Split::clear()
{ {
this->view_.clearMessages(); this->view_.clearMessages();
} }
@ -417,7 +415,7 @@ void Split::openInBrowser()
} }
} }
void Split::openInPopupPlayer() void Split::openBrowserPlayer()
{ {
ChannelPtr channel = this->getChannel(); ChannelPtr channel = this->getChannel();
if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) { if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) {
@ -548,7 +546,7 @@ 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(); SearchPopup *popup = new SearchPopup();

View file

@ -9,7 +9,7 @@
#include "messages/layouts/MessageLayoutElement.hpp" #include "messages/layouts/MessageLayoutElement.hpp"
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/helper/ChannelView.hpp" #include "widgets/helper/ChannelView.hpp"
#include "widgets/helper/RippleEffectLabel.hpp" #include "widgets/helper/EffectLabel.hpp"
#include "widgets/splits/SplitHeader.hpp" #include "widgets/splits/SplitHeader.hpp"
#include "widgets/splits/SplitInput.hpp" #include "widgets/splits/SplitInput.hpp"
@ -125,39 +125,16 @@ private:
std::vector<pajlada::Signals::ScopedConnection> managedConnections_; std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
public slots: public slots:
// Add new split to the notebook page that this chat widget is in void addSibling();
// This is only activated from the menu now. Hotkey is handled in Notebook void deleteFromContainer();
void doAddSplit(); void changeChannel();
void popup();
// Close current split (chat widget) void clear();
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 openInBrowser(); void openInBrowser();
void openBrowserPlayer();
// Open popup player of twitch channel in default browser
void openInPopupPlayer();
// Open twitch channel stream through streamlink
void openInStreamlink(); void openInStreamlink();
// Copy text from chat
void copyToClipboard(); void copyToClipboard();
void showSearch();
// Open a search popup
void showSearchPopup();
// Open viewer list of the channel
void showViewerList(); void showViewerList();
}; };

View file

@ -7,6 +7,7 @@
#include "singletons/Resources.hpp" #include "singletons/Resources.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "util/LayoutCreator.hpp" #include "util/LayoutCreator.hpp"
#include "util/LayoutHelper.hpp"
#include "widgets/Label.hpp" #include "widgets/Label.hpp"
#include "widgets/TooltipWidget.hpp" #include "widgets/TooltipWidget.hpp"
#include "widgets/splits/Split.hpp" #include "widgets/splits/Split.hpp"
@ -19,122 +20,168 @@
#include <QMenu> #include <QMenu>
#include <QMimeData> #include <QMimeData>
#include <QPainter> #include <QPainter>
#include <cmath>
#ifdef USEWEBENGINE #ifdef USEWEBENGINE
#include "widgets/StreamView.hpp" #include "widgets/StreamView.hpp"
#endif #endif
namespace chatterino { namespace chatterino {
namespace {
auto formatRoomMode(TwitchChannel &channel)
{
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);
}
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) + " viewers";
if (settings.showTitle) title += " - " + s.title;
if (settings.showGame) title += " - " + s.game;
if (settings.showUptime) title += " - uptime: " + 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) SplitHeader::SplitHeader(Split *_split)
: BaseWidget(_split) : BaseWidget(_split)
, split_(_split) , split_(_split)
{ {
this->split_->focused.connect([this]() { this->themeChangedEvent(); }); this->initializeLayout();
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->setMouseTracking(true); this->setMouseTracking(true);
this->updateChannelText();
this->handleChannelChanged();
this->updateModerationModeIcon();
// Update title on title-settings-change this->split_->focused.connect([this]() { this->themeChangedEvent(); });
getSettings()->showViewerCount.connect( this->split_->focusLost.connect([this]() { this->themeChangedEvent(); });
[this](const auto &, const auto &) { this->updateChannelText(); }, this->split_->channelChanged.connect(
this->managedConnections_); [this]() { this->handleChannelChanged(); });
getSettings()->showTitle.connect(
[this](const auto &, const auto &) { this->updateChannelText(); }, this->managedConnect(getApp()->accounts->twitch.currentUserChanged,
this->managedConnections_); [this] { this->updateModerationModeIcon(); });
getSettings()->showGame.connect(
[this](const auto &, const auto &) { this->updateChannelText(); }, auto _ = [this](const auto &, const auto &) { this->updateChannelText(); };
this->managedConnections_); getSettings()->showViewerCount.connect(_, this->managedConnections_);
getSettings()->showUptime.connect( getSettings()->showTitle.connect(_, this->managedConnections_);
[this](const auto &, const auto &) { this->updateChannelText(); }, getSettings()->showGame.connect(_, this->managedConnections_);
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->setMouseTracking(true);
w->setMenu(this->createMainMenu());
QObject::connect(w, &Button::leftMousePress, this, [this] {});
})});
layout->setMargin(0);
layout->setSpacing(0);
this->setLayout(layout);
} }
std::unique_ptr<QMenu> SplitHeader::createMainMenu() std::unique_ptr<QMenu> SplitHeader::createMainMenu()
{ {
auto menu = std::make_unique<QMenu>(); auto menu = std::make_unique<QMenu>();
menu->addAction("New split", this->split_, &Split::doAddSplit, menu->addAction("New split", this->split_, &Split::addSibling,
QKeySequence(tr("Ctrl+T"))); QKeySequence("Ctrl+T"));
menu->addAction("Close split", this->split_, &Split::doCloseSplit, menu->addAction("Close split", this->split_, &Split::deleteFromContainer,
QKeySequence(tr("Ctrl+W"))); QKeySequence("Ctrl+W"));
menu->addAction("Change channel", this->split_, &Split::doChangeChannel, menu->addAction("Change channel", this->split_, &Split::changeChannel,
QKeySequence(tr("Ctrl+R"))); QKeySequence("Ctrl+R"));
menu->addSeparator(); menu->addSeparator();
menu->addAction("Viewer list", this->split_, &Split::showViewerList); menu->addAction("Viewer list", this->split_, &Split::showViewerList);
menu->addAction("Search", this->split_, &Split::showSearchPopup, menu->addAction("Search", this->split_, &Split::showSearch,
QKeySequence(tr("Ctrl+F"))); QKeySequence("Ctrl+F"));
menu->addSeparator(); menu->addSeparator();
menu->addAction("Popup", this->split_, &Split::doPopup); menu->addAction("Popup", this->split_, &Split::popup);
#ifdef USEWEBENGINE #ifdef USEWEBENGINE
this->dropdownMenu.addAction("Start watching", this, [this] { this->dropdownMenu.addAction("Start watching", this, [this] {
ChannelPtr _channel = this->split->getChannel(); ChannelPtr _channel = this->split->getChannel();
@ -151,13 +198,12 @@ std::unique_ptr<QMenu> SplitHeader::createMainMenu()
menu->addAction("Open in browser", this->split_, &Split::openInBrowser); menu->addAction("Open in browser", this->split_, &Split::openInBrowser);
#ifndef USEWEBENGINE #ifndef USEWEBENGINE
menu->addAction("Open player in browser", this->split_, menu->addAction("Open player in browser", this->split_,
&Split::openInPopupPlayer); &Split::openBrowserPlayer);
#endif #endif
menu->addAction("Open streamlink", this->split_, &Split::openInStreamlink); menu->addAction("Open streamlink", this->split_, &Split::openInStreamlink);
menu->addSeparator(); menu->addSeparator();
menu->addAction("Reload channel emotes", this, menu->addAction("Reload channel emotes", this, SLOT(reloadChannelEmotes()));
SLOT(menuReloadChannelEmotes())); menu->addAction("Reconnect", this, SLOT(reconnect()));
menu->addAction("Reconnect", this, SLOT(menuManualReconnect()));
// menu->addAction("Clear messages", this->split_, &Split::doClearChat); // menu->addAction("Clear messages", this->split_, &Split::doClearChat);
// menu->addSeparator(); // menu->addSeparator();
// menu->addAction("Show changelog", this, SLOT(menuShowChangelog())); // menu->addAction("Show changelog", this, SLOT(menuShowChangelog()));
@ -201,16 +247,10 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
setSub->setChecked(roomModes->submode); setSub->setChecked(roomModes->submode);
})); }));
auto toggle = [this](const QString &_command, QAction *action) mutable { auto toggle = [this](const QString &command, QAction *action) mutable {
QString command = _command; this->split_->getChannel().get()->sendMessage(
command + (action->isChecked() ? "" : "off"));
if (!action->isChecked()) {
command += "off";
};
action->setChecked(!action->isChecked()); action->setChecked(!action->isChecked());
qDebug() << command;
this->split_->getChannel().get()->sendMessage(command);
}; };
QObject::connect( QObject::connect(
@ -227,12 +267,12 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
setSlow->setChecked(false); setSlow->setChecked(false);
return; return;
}; };
bool ok; auto ok = bool();
int slowSec = QInputDialog::getInt(this, "", "Seconds:", 10, 0, 500, 1, auto seconds = QInputDialog::getInt(this, "", "Seconds:", 10, 0, 500, 1,
&ok, Qt::FramelessWindowHint); &ok, Qt::FramelessWindowHint);
if (ok) { if (ok) {
this->split_->getChannel().get()->sendMessage( this->split_->getChannel().get()->sendMessage(
QString("/slow %1").arg(slowSec)); QString("/slow %1").arg(seconds));
} else { } else {
setSlow->setChecked(false); setSlow->setChecked(false);
} }
@ -250,74 +290,47 @@ void SplitHeader::updateRoomModes()
this->modeUpdateRequested_.invoke(); this->modeUpdateRequested_.invoke();
} }
void SplitHeader::setupModeLabel(RippleEffectLabel &label) void SplitHeader::initializeModeSignals(EffectLabel &label)
{ {
this->managedConnections_.push_back( this->modeUpdateRequested_.connect([this, &label] {
this->modeUpdateRequested_.connect([this, &label] { auto twitchChannel =
auto twitchChannel = dynamic_cast<TwitchChannel *>(this->split_->getChannel().get());
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get());
// return if the channel is not a twitch channel // return if the channel is not a twitch channel
if (twitchChannel == nullptr) { if (twitchChannel == nullptr) {
label.hide(); label.hide();
return; return;
} }
// set lable enabled // set lable enabled
label.setEnable(twitchChannel->hasModRights()); label.setEnable(twitchChannel->hasModRights());
// set the label text // set the label text
QString text; auto text = formatRoomMode(*twitchChannel);
{ if (text.isEmpty()) {
auto roomModes = twitchChannel->accessRoomModes(); if (twitchChannel->hasModRights()) {
label.getLabel().setText("none");
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));
}
label.getLabel().setText(text);
label.show(); label.show();
} else {
label.hide();
} }
})); } else {
label.getLabel().setText(text);
label.show();
}
});
} }
void SplitHeader::initializeChannelSignals() void SplitHeader::handleChannelChanged()
{ {
// Disconnect any previous signal first this->channelConnections_.clear();
this->onlineStatusChangedConnection_.disconnect();
auto channel = this->split_->getChannel(); auto channel = this->split_->getChannel();
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()); if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) {
this->channelConnections_.emplace_back(
if (twitchChannel) { twitchChannel->liveStatusChanged.connect(
this->managedConnections_.emplace_back( [this]() { this->updateChannelText(); }));
twitchChannel->liveStatusChanged.connect([this]() {
this->updateChannelText(); //
}));
} }
} }
@ -328,89 +341,47 @@ void SplitHeader::scaleChangedEvent(float scale)
this->setFixedHeight(w); this->setFixedHeight(w);
this->dropdownButton_->setFixedWidth(w); this->dropdownButton_->setFixedWidth(w);
this->moderationButton_->setFixedWidth(w); this->moderationButton_->setFixedWidth(w);
// this->titleLabel->setFont(
// FontManager::getInstance().getFont(FontStyle::Medium, scale));
} }
void SplitHeader::updateChannelText() void SplitHeader::updateChannelText()
{ {
auto indirectChannel = this->split_->getIndirectChannel(); auto indirectChannel = this->split_->getIndirectChannel();
auto channel = this->split_->getChannel(); 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); title = "watching: " + (title.isEmpty() ? "none" : title);
}
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()); if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get())) {
if (twitchChannel != nullptr) {
const auto streamStatus = twitchChannel->accessStreamStatus(); const auto streamStatus = twitchChannel->accessStreamStatus();
if (streamStatus->live) { if (streamStatus->live) {
this->isLive_ = true; this->isLive_ = true;
this->tooltip_ = "<style>.center { text-align: center; }</style>" this->tooltipText_ = formatTooltip(*streamStatus);
"<p class = \"center\">" + title += formatTitle(*streamStatus, *getSettings());
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();
} }
} }
if (title.isEmpty()) { this->titleLabel->setText(title.isEmpty() ? "<empty>" : title);
title = "<empty>";
}
this->isLive_ = false;
this->titleLabel->setText(title);
} }
void SplitHeader::updateModerationModeIcon() void SplitHeader::updateModerationModeIcon()
{ {
auto app = getApp();
this->moderationButton_->setPixmap( this->moderationButton_->setPixmap(
this->split_->getModerationMode() this->split_->getModerationMode()
? app->resources->buttons.modModeEnabled ? getApp()->resources->buttons.modModeEnabled
: app->resources->buttons.modModeDisabled); : getApp()->resources->buttons.modModeDisabled);
bool modButtonVisible = false;
ChannelPtr channel = this->split_->getChannel();
auto channel = this->split_->getChannel();
auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()); auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel != nullptr && twitchChannel->hasModRights()) { if (twitchChannel != nullptr && twitchChannel->hasModRights())
modButtonVisible = true; this->moderationButton_->show();
} else
this->moderationButton_->hide();
this->moderationButton_->setVisible(modButtonVisible);
} }
void SplitHeader::paintEvent(QPaintEvent *) void SplitHeader::paintEvent(QPaintEvent *)
@ -436,7 +407,7 @@ void SplitHeader::mousePressEvent(QMouseEvent *event)
void SplitHeader::mouseReleaseEvent(QMouseEvent *event) void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
{ {
if (this->dragging_ && event->button() == Qt::LeftButton) { if (this->dragging_ && event->button() == Qt::LeftButton) {
QPoint pos = event->globalPos(); auto pos = event->globalPos();
if (!showingHelpTooltip_) { if (!showingHelpTooltip_) {
this->showingHelpTooltip_ = true; this->showingHelpTooltip_ = true;
@ -448,18 +419,18 @@ void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
return; return;
} }
TooltipWidget *widget = new TooltipWidget(); auto tooltip = new TooltipWidget();
widget->setText("Double click or press <Ctrl+R> to change the " tooltip->setText("Double click or press <Ctrl+R> to change the "
"channel.\nClick and " "channel.\nClick and "
"drag to move the split."); "drag to move the split.");
widget->setAttribute(Qt::WA_DeleteOnClose); tooltip->setAttribute(Qt::WA_DeleteOnClose);
widget->move(pos); tooltip->move(pos);
widget->show(); tooltip->show();
widget->raise(); tooltip->raise();
QTimer::singleShot(3000, widget, [this, widget] { QTimer::singleShot(3000, tooltip, [this, tooltip] {
widget->close(); tooltip->close();
this->showingHelpTooltip_ = false; this->showingHelpTooltip_ = false;
}); });
}); });
@ -472,10 +443,7 @@ void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
void SplitHeader::mouseMoveEvent(QMouseEvent *event) void SplitHeader::mouseMoveEvent(QMouseEvent *event)
{ {
if (this->dragging_) { if (this->dragging_) {
if (std::abs(this->dragStart_.x() - event->pos().x()) > if (distance(this->dragStart_, event->pos()) > 15 * this->getScale()) {
int(12 * this->getScale()) ||
std::abs(this->dragStart_.y() - event->pos().y()) >
int(12 * this->getScale())) {
this->split_->drag(); this->split_->drag();
this->dragging_ = false; this->dragging_ = false;
} }
@ -485,20 +453,20 @@ void SplitHeader::mouseMoveEvent(QMouseEvent *event)
void SplitHeader::mouseDoubleClickEvent(QMouseEvent *event) void SplitHeader::mouseDoubleClickEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
this->split_->doChangeChannel(); this->split_->changeChannel();
} }
this->doubleClicked_ = true; this->doubleClicked_ = true;
} }
void SplitHeader::enterEvent(QEvent *event) void SplitHeader::enterEvent(QEvent *event)
{ {
if (!this->tooltip_.isEmpty()) { if (!this->tooltipText_.isEmpty()) {
auto tooltipWidget = TooltipWidget::getInstance(); auto tooltip = TooltipWidget::getInstance();
tooltipWidget->moveTo( tooltip->moveTo(this, this->mapToGlobal(this->rect().bottomLeft()),
this, this->mapToGlobal(this->rect().bottomLeft()), false); false);
tooltipWidget->setText(this->tooltip_); tooltip->setText(this->tooltipText_);
tooltipWidget->show(); tooltip->show();
tooltipWidget->raise(); tooltip->raise();
} }
BaseWidget::enterEvent(event); BaseWidget::enterEvent(event);
@ -511,13 +479,9 @@ void SplitHeader::leaveEvent(QEvent *event)
BaseWidget::leaveEvent(event); BaseWidget::leaveEvent(event);
} }
void SplitHeader::rightButtonClicked()
{
}
void SplitHeader::themeChangedEvent() void SplitHeader::themeChangedEvent()
{ {
QPalette palette; auto palette = QPalette();
if (this->split_->hasFocus()) { if (this->split_->hasFocus()) {
palette.setColor(QPalette::Foreground, palette.setColor(QPalette::Foreground,
@ -525,41 +489,32 @@ void SplitHeader::themeChangedEvent()
} else { } else {
palette.setColor(QPalette::Foreground, this->theme->splits.header.text); palette.setColor(QPalette::Foreground, this->theme->splits.header.text);
} }
this->titleLabel->setPalette(palette);
// --
if (this->theme->isLightTheme()) { if (this->theme->isLightTheme()) {
this->dropdownButton_->setPixmap(getApp()->resources->buttons.menuDark); this->dropdownButton_->setPixmap(getApp()->resources->buttons.menuDark);
} else { } else {
this->dropdownButton_->setPixmap( this->dropdownButton_->setPixmap(
getApp()->resources->buttons.menuLight); 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(); auto channel = this->split_->getChannel();
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
if (twitchChannel) { if (auto twitchChannel = dynamic_cast<TwitchChannel *>(channel.get()))
twitchChannel->refreshChannelEmotes(); twitchChannel->refreshChannelEmotes();
}
} }
void SplitHeader::menuManualReconnect() void SplitHeader::reconnect()
{
auto app = getApp();
// fourtf: connection
app->twitch.server->connect();
}
void SplitHeader::menuShowChangelog()
{ {
getApp()->twitch.server->connect();
} }
} // namespace chatterino } // namespace chatterino

View file

@ -1,37 +1,29 @@
#pragma once #pragma once
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/helper/RippleEffectLabel.hpp"
#include "widgets/helper/SignalLabel.hpp"
#include <QAction>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu> #include <QMenu>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QPoint> #include <QPoint>
#include <QWidget> #include <memory>
#include <pajlada/settings/setting.hpp> #include <pajlada/settings/setting.hpp>
#include <pajlada/signals/connection.hpp> #include <pajlada/signals/connection.hpp>
#include <pajlada/signals/signalholder.hpp> #include <pajlada/signals/signalholder.hpp>
#include <vector> #include <vector>
namespace chatterino { namespace chatterino {
class Split; class Button;
class EffectLabel;
class Label; class Label;
class Split;
class SplitHeader : public BaseWidget, pajlada::Signals::SignalHolder class SplitHeader final : public BaseWidget, pajlada::Signals::SignalHolder
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit SplitHeader(Split *_chatWidget); explicit SplitHeader(Split *_chatWidget);
virtual ~SplitHeader() override;
// Update channel text from chat widget
void updateChannelText(); void updateChannelText();
void updateModerationModeIcon(); void updateModerationModeIcon();
void updateRoomModes(); void updateRoomModes();
@ -49,41 +41,38 @@ protected:
virtual void mouseDoubleClickEvent(QMouseEvent *event) override; virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
private: private:
void rightButtonClicked(); void initializeLayout();
void initializeChannelSignals(); void initializeModeSignals(EffectLabel &label);
void setupModeLabel(RippleEffectLabel &label);
std::unique_ptr<QMenu> createMainMenu(); std::unique_ptr<QMenu> createMainMenu();
std::unique_ptr<QMenu> createChatModeMenu(); std::unique_ptr<QMenu> createChatModeMenu();
void handleChannelChanged();
Split *split_; Split *const split_{};
QString tooltipText_{};
bool isLive_{false};
QPoint dragStart_; // ui
bool dragging_ = false; Button *dropdownButton_{};
bool doubleClicked_ = false;
bool showingHelpTooltip_ = false;
pajlada::Signals::Connection onlineStatusChangedConnection_;
RippleEffectButton *dropdownButton_{};
// Label *titleLabel{};
Label *titleLabel{}; Label *titleLabel{};
RippleEffectLabel *modeButton_{}; EffectLabel *modeButton_{};
RippleEffectButton *moderationButton_{}; Button *moderationButton_{};
bool menuVisible_{}; // states
QPoint dragStart_{};
bool dragging_{false};
bool doubleClicked_{false};
bool showingHelpTooltip_{false};
bool menuVisible_{false};
// signals
pajlada::Signals::NoArgSignal modeUpdateRequested_; pajlada::Signals::NoArgSignal modeUpdateRequested_;
QString tooltip_;
bool isLive_;
std::vector<pajlada::Signals::ScopedConnection> managedConnections_; std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
std::vector<pajlada::Signals::ScopedConnection> channelConnections_;
public slots: public slots:
void menuMoveSplit(); void moveSplit();
void menuReloadChannelEmotes(); void reloadChannelEmotes();
void menuManualReconnect(); void reconnect();
void menuShowChangelog();
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -61,7 +61,7 @@ void SplitInput::initLayout()
textEditLength->setAlignment(Qt::AlignRight); textEditLength->setAlignment(Qt::AlignRight);
box->addStretch(1); box->addStretch(1);
box.emplace<RippleEffectLabel>().assign(&this->ui_.emoteButton); box.emplace<EffectLabel>().assign(&this->ui_.emoteButton);
} }
this->ui_.emoteButton->getLabel().setTextFormat(Qt::RichText); this->ui_.emoteButton->getLabel().setTextFormat(Qt::RichText);
@ -79,7 +79,7 @@ void SplitInput::initLayout()
// open emote popup // open emote popup
QObject::connect( QObject::connect(
this->ui_.emoteButton, &RippleEffectLabel::clicked, [this] { this->ui_.emoteButton, &EffectLabel::clicked, [this] {
if (!this->emotePopup_) { if (!this->emotePopup_) {
this->emotePopup_ = std::make_unique<EmotePopup>(); this->emotePopup_ = std::make_unique<EmotePopup>();
this->emotePopup_->linkClicked.connect( this->emotePopup_->linkClicked.connect(

View file

@ -3,7 +3,7 @@
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "widgets/dialogs/EmotePopup.hpp" #include "widgets/dialogs/EmotePopup.hpp"
#include "widgets/helper/ResizingTextEdit.hpp" #include "widgets/helper/ResizingTextEdit.hpp"
#include "widgets/helper/RippleEffectLabel.hpp" #include "widgets/helper/EffectLabel.hpp"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
@ -50,7 +50,7 @@ private:
struct { struct {
ResizingTextEdit *textEdit; ResizingTextEdit *textEdit;
QLabel *textEditLength; QLabel *textEditLength;
RippleEffectLabel *emoteButton; EffectLabel *emoteButton;
QHBoxLayout *hbox; QHBoxLayout *hbox;
} ui_; } ui_;