2019-07-23 22:18:36 +02:00
|
|
|
#include "Button.hpp"
|
|
|
|
|
Sort and force grouping of includes (#4172)
This change enforces strict include grouping using IncludeCategories
In addition to adding this to the .clang-format file and applying it in the tests/src and src directories, I also did the following small changes:
In ChatterSet.hpp, I changed lrucache to a <>include
In Irc2.hpp, I change common/SignalVector.hpp to a "project-include"
In AttachedWindow.cpp, NativeMessaging.cpp, WindowsHelper.hpp, BaseWindow.cpp, and StreamerMode.cpp, I disabled clang-format for the windows-includes
In WindowDescriptors.hpp, I added the missing vector include. It was previously not needed because the include was handled by another file that was previously included first.
clang-format minimum version has been bumped, so Ubuntu version used in the check-formatting job has been bumped to 22.04 (which is the latest LTS)
2022-11-27 19:32:53 +01:00
|
|
|
#include "singletons/Theme.hpp"
|
|
|
|
#include "util/FunctionEventFilter.hpp"
|
|
|
|
|
2019-07-23 22:18:36 +02:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QPainter>
|
2023-01-07 11:41:39 +01:00
|
|
|
#include <QScreen>
|
2019-07-23 22:18:36 +02:00
|
|
|
|
2019-10-07 15:46:08 +02:00
|
|
|
namespace chatterino {
|
2020-09-26 15:40:43 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// returns a new resized image or the old one if the size didn't change
|
|
|
|
auto resizePixmap(const QPixmap ¤t, const QPixmap resized,
|
|
|
|
const QSize &size) -> QPixmap
|
|
|
|
{
|
|
|
|
if (resized.size() == size)
|
|
|
|
return resized;
|
|
|
|
else
|
|
|
|
return current.scaled(size, Qt::IgnoreAspectRatio,
|
|
|
|
Qt::SmoothTransformation);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
2019-07-23 22:18:36 +02:00
|
|
|
|
|
|
|
Button::Button(BaseWidget *parent)
|
|
|
|
: BaseWidget(parent)
|
|
|
|
{
|
|
|
|
connect(&effectTimer_, &QTimer::timeout, this,
|
|
|
|
&Button::onMouseEffectTimeout);
|
|
|
|
|
|
|
|
this->effectTimer_.setInterval(20);
|
|
|
|
this->effectTimer_.start();
|
|
|
|
|
|
|
|
this->setMouseTracking(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setMouseEffectColor(boost::optional<QColor> color)
|
|
|
|
{
|
2021-04-10 14:34:40 +02:00
|
|
|
this->mouseEffectColor_ = std::move(color);
|
2019-07-23 22:18:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setPixmap(const QPixmap &_pixmap)
|
|
|
|
{
|
|
|
|
this->pixmap_ = _pixmap;
|
2020-09-26 15:40:43 +02:00
|
|
|
this->resizedPixmap_ = {};
|
2019-07-23 22:18:36 +02:00
|
|
|
this->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
const QPixmap &Button::getPixmap() const
|
|
|
|
{
|
|
|
|
return this->pixmap_;
|
|
|
|
}
|
|
|
|
|
2019-09-01 13:06:56 +02:00
|
|
|
void Button::setDim(Dim value)
|
2019-07-23 22:18:36 +02:00
|
|
|
{
|
|
|
|
this->dimPixmap_ = value;
|
|
|
|
|
|
|
|
this->update();
|
|
|
|
}
|
|
|
|
|
2019-09-01 13:06:56 +02:00
|
|
|
Button::Dim Button::getDim() const
|
2019-07-23 22:18:36 +02:00
|
|
|
{
|
|
|
|
return this->dimPixmap_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setEnable(bool value)
|
|
|
|
{
|
|
|
|
this->enabled_ = value;
|
|
|
|
|
|
|
|
this->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Button::getEnable() const
|
|
|
|
{
|
|
|
|
return this->enabled_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setEnableMargin(bool value)
|
|
|
|
{
|
|
|
|
this->enableMargin_ = value;
|
|
|
|
|
|
|
|
this->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Button::getEnableMargin() const
|
|
|
|
{
|
|
|
|
return this->enableMargin_;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal Button::getCurrentDimAmount() const
|
|
|
|
{
|
2019-09-01 13:06:56 +02:00
|
|
|
if (this->dimPixmap_ == Dim::None || this->mouseOver_)
|
|
|
|
return 1;
|
|
|
|
else if (this->dimPixmap_ == Dim::Some)
|
|
|
|
return 0.7;
|
|
|
|
else
|
|
|
|
return 0.15;
|
2019-07-23 22:18:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setBorderColor(const QColor &color)
|
|
|
|
{
|
|
|
|
this->borderColor_ = color;
|
|
|
|
|
|
|
|
this->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
const QColor &Button::getBorderColor() const
|
|
|
|
{
|
|
|
|
return this->borderColor_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setMenu(std::unique_ptr<QMenu> menu)
|
|
|
|
{
|
2021-04-04 15:24:12 +02:00
|
|
|
if (this->menu_)
|
|
|
|
this->menu_.release()->deleteLater();
|
|
|
|
|
2019-07-23 22:18:36 +02:00
|
|
|
this->menu_ = std::move(menu);
|
|
|
|
|
|
|
|
this->menu_->installEventFilter(
|
|
|
|
new FunctionEventFilter(this, [this](QObject *, QEvent *event) {
|
|
|
|
if (event->type() == QEvent::Hide)
|
|
|
|
{
|
2020-11-08 12:02:19 +01:00
|
|
|
QTimer::singleShot(20, this, [this] {
|
|
|
|
this->menuVisible_ = false;
|
|
|
|
});
|
2019-07-23 22:18:36 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::paintEvent(QPaintEvent *)
|
|
|
|
{
|
|
|
|
QPainter painter(this);
|
|
|
|
|
|
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
|
|
|
|
|
|
|
if (!this->pixmap_.isNull())
|
|
|
|
{
|
2019-09-01 13:06:56 +02:00
|
|
|
painter.setOpacity(this->getCurrentDimAmount());
|
2019-07-23 22:18:36 +02:00
|
|
|
|
|
|
|
QRect rect = this->rect();
|
2019-09-01 13:06:56 +02:00
|
|
|
|
2020-09-26 15:40:43 +02:00
|
|
|
this->resizedPixmap_ =
|
|
|
|
resizePixmap(this->pixmap_, this->resizedPixmap_, rect.size());
|
|
|
|
|
2019-09-01 13:06:56 +02:00
|
|
|
int margin = this->height() < 22 * this->scale() ? 3 : 6;
|
|
|
|
|
|
|
|
int s = this->enableMargin_ ? int(margin * this->scale()) : 0;
|
2019-07-23 22:18:36 +02:00
|
|
|
|
|
|
|
rect.moveLeft(s);
|
|
|
|
rect.setRight(rect.right() - s - s);
|
|
|
|
rect.moveTop(s);
|
|
|
|
rect.setBottom(rect.bottom() - s - s);
|
|
|
|
|
2020-09-26 15:40:43 +02:00
|
|
|
painter.drawPixmap(rect, this->resizedPixmap_);
|
2019-07-23 22:18:36 +02:00
|
|
|
|
|
|
|
painter.setOpacity(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->fancyPaint(painter);
|
|
|
|
|
|
|
|
if (this->borderColor_.isValid())
|
|
|
|
{
|
|
|
|
painter.setRenderHint(QPainter::Antialiasing, false);
|
|
|
|
painter.setPen(this->borderColor_);
|
|
|
|
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::fancyPaint(QPainter &painter)
|
|
|
|
{
|
|
|
|
if (!this->enabled_)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
QColor c;
|
|
|
|
|
|
|
|
if (this->mouseEffectColor_)
|
|
|
|
{
|
|
|
|
c = this->mouseEffectColor_.get();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c = this->theme->isLightTheme() ? QColor(0, 0, 0)
|
|
|
|
: QColor(255, 255, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->hoverMultiplier_ > 0)
|
|
|
|
{
|
|
|
|
QRadialGradient gradient(QPointF(mousePos_), this->width() / 2);
|
|
|
|
|
|
|
|
gradient.setColorAt(0, QColor(c.red(), c.green(), c.blue(),
|
|
|
|
int(50 * this->hoverMultiplier_)));
|
|
|
|
gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(),
|
|
|
|
int(40 * this->hoverMultiplier_)));
|
|
|
|
|
|
|
|
painter.fillRect(this->rect(), gradient);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto effect : this->clickEffects_)
|
|
|
|
{
|
|
|
|
QRadialGradient gradient(effect.position.x(), effect.position.y(),
|
|
|
|
effect.progress * qreal(width()) * 2,
|
|
|
|
effect.position.x(), effect.position.y());
|
|
|
|
|
|
|
|
gradient.setColorAt(0, QColor(c.red(), c.green(), c.blue(),
|
|
|
|
int((1 - effect.progress) * 95)));
|
|
|
|
gradient.setColorAt(0.9999, QColor(c.red(), c.green(), c.blue(),
|
|
|
|
int((1 - effect.progress) * 95)));
|
|
|
|
gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(), int(0)));
|
|
|
|
|
|
|
|
painter.fillRect(this->rect(), gradient);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 18:13:29 +01:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
|
|
void Button::enterEvent(QEnterEvent * /*event*/)
|
|
|
|
#else
|
|
|
|
void Button::enterEvent(QEvent * /*event*/)
|
|
|
|
#endif
|
2019-07-23 22:18:36 +02:00
|
|
|
{
|
|
|
|
this->mouseOver_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::leaveEvent(QEvent *)
|
|
|
|
{
|
|
|
|
this->mouseOver_ = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::mousePressEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
if (!this->enabled_)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->button() != Qt::LeftButton)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->clickEffects_.push_back(ClickEffect(event->pos()));
|
|
|
|
|
|
|
|
this->mouseDown_ = true;
|
|
|
|
|
|
|
|
emit this->leftMousePress();
|
|
|
|
|
|
|
|
if (this->menu_ && !this->menuVisible_)
|
|
|
|
{
|
2020-11-08 12:02:19 +01:00
|
|
|
QTimer::singleShot(80, this, [this] {
|
|
|
|
this->showMenu();
|
|
|
|
});
|
2019-07-23 22:18:36 +02:00
|
|
|
this->mouseDown_ = false;
|
|
|
|
this->mouseOver_ = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::mouseReleaseEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
if (!this->enabled_)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (event->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
this->mouseDown_ = false;
|
|
|
|
|
|
|
|
if (this->rect().contains(event->pos()))
|
|
|
|
emit leftClicked();
|
|
|
|
}
|
|
|
|
|
|
|
|
emit clicked(event->button());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::mouseMoveEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
if (this->enabled_)
|
|
|
|
{
|
|
|
|
this->mousePos_ = event->pos();
|
|
|
|
|
|
|
|
this->update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::onMouseEffectTimeout()
|
|
|
|
{
|
|
|
|
bool performUpdate = false;
|
|
|
|
|
|
|
|
if (selected_)
|
|
|
|
{
|
|
|
|
if (this->hoverMultiplier_ != 0)
|
|
|
|
{
|
|
|
|
this->hoverMultiplier_ =
|
|
|
|
std::max(0.0, this->hoverMultiplier_ - 0.1);
|
|
|
|
performUpdate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mouseOver_)
|
|
|
|
{
|
|
|
|
if (this->hoverMultiplier_ != 1)
|
|
|
|
{
|
|
|
|
this->hoverMultiplier_ =
|
|
|
|
std::min(1.0, this->hoverMultiplier_ + 0.5);
|
|
|
|
performUpdate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (this->hoverMultiplier_ != 0)
|
|
|
|
{
|
|
|
|
this->hoverMultiplier_ =
|
|
|
|
std::max(0.0, this->hoverMultiplier_ - 0.3);
|
|
|
|
performUpdate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->clickEffects_.size() != 0)
|
|
|
|
{
|
|
|
|
performUpdate = true;
|
|
|
|
|
|
|
|
for (auto it = this->clickEffects_.begin();
|
|
|
|
it != this->clickEffects_.end();)
|
|
|
|
{
|
|
|
|
it->progress += mouseDown_ ? 0.02 : 0.07;
|
|
|
|
|
|
|
|
if (it->progress >= 1.0)
|
|
|
|
{
|
|
|
|
it = this->clickEffects_.erase(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (performUpdate)
|
|
|
|
{
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::showMenu()
|
|
|
|
{
|
|
|
|
if (!this->menu_)
|
|
|
|
return;
|
|
|
|
|
2023-05-02 20:50:13 +02:00
|
|
|
auto menuSizeHint = this->menu_->sizeHint();
|
|
|
|
auto point = this->mapToGlobal(
|
|
|
|
QPoint(this->width() - menuSizeHint.width(), this->height()));
|
2019-07-23 22:18:36 +02:00
|
|
|
|
2023-05-02 20:50:13 +02:00
|
|
|
auto *screen = QApplication::screenAt(point);
|
|
|
|
if (screen == nullptr)
|
|
|
|
{
|
|
|
|
screen = QApplication::primaryScreen();
|
|
|
|
}
|
|
|
|
auto bounds = screen->availableGeometry();
|
2019-07-23 22:18:36 +02:00
|
|
|
|
2023-05-02 20:50:13 +02:00
|
|
|
if (point.y() + menuSizeHint.height() > bounds.bottom())
|
|
|
|
{
|
|
|
|
// Menu doesn't fit going down, flip it to go up instead
|
|
|
|
point.setY(point.y() - menuSizeHint.height() - this->height());
|
|
|
|
}
|
2019-07-23 22:18:36 +02:00
|
|
|
|
2023-05-02 20:50:13 +02:00
|
|
|
this->menu_->popup(point);
|
2019-07-23 22:18:36 +02:00
|
|
|
this->menuVisible_ = true;
|
|
|
|
}
|
|
|
|
|
2019-10-07 15:46:08 +02:00
|
|
|
} // namespace chatterino
|