refactor: buttons and friends (#6102)

This commit is contained in:
nerix
2025-05-25 11:17:06 +02:00
committed by GitHub
parent deed1061b5
commit 84c0b39fde
49 changed files with 1083 additions and 691 deletions
-468
View File
@@ -1,468 +0,0 @@
#include "widgets/helper/Button.hpp"
#include "singletons/Theme.hpp"
#include "util/FunctionEventFilter.hpp"
#include <QApplication>
#include <QDebug>
#include <QPainter>
#include <QScreen>
namespace {
QSizeF deviceIndependentSize(const QPixmap &pixmap)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
return QSizeF(pixmap.width(), pixmap.height()) / pixmap.devicePixelRatio();
#else
return pixmap.deviceIndependentSize();
#endif
}
/**
* Resizes a pixmap to a desired size.
* Does nothing if the target pixmap is already sized correctly.
*
* @param target The target pixmap.
* @param source The unscaled pixmap.
* @param size The desired device independent size.
* @param dpr The device pixel ratio of the target area. The size of the target in pixels will be `size * dpr`.
*/
void resizePixmap(QPixmap &target, const QPixmap &source, const QSize &size,
qreal dpr)
{
if (deviceIndependentSize(target) == size)
{
return;
}
QPixmap resized = source;
resized.setDevicePixelRatio(dpr);
target = resized.scaled(size * dpr, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
}
} // namespace
namespace chatterino {
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(std::optional<QColor> color)
{
this->mouseEffectColor_ = std::move(color);
}
void Button::setPixmap(const QPixmap &_pixmap)
{
// Avoid updates if the pixmap didn't change
if (_pixmap.cacheKey() == this->pixmap_.cacheKey())
{
return;
}
this->pixmap_ = _pixmap;
this->resizedPixmap_ = {};
this->update();
}
void Button::setSvgResource(const QString &resourcePath)
{
if (resourcePath == this->svgResourcePath)
{
// Same resource path as before - nothing changed
return;
}
if (this->svgRenderer)
{
this->svgRenderer->deleteLater();
}
this->svgRenderer = new QSvgRenderer(resourcePath, this);
this->svgRenderer->setAspectRatioMode(Qt::KeepAspectRatio);
this->svgResourcePath = resourcePath;
this->update();
}
const QPixmap &Button::getPixmap() const
{
return this->pixmap_;
}
void Button::setDim(Dim value)
{
this->dimPixmap_ = value;
this->update();
}
Button::Dim Button::getDim() const
{
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
{
if (this->dimPixmap_ == Dim::None || this->mouseOver_)
{
return 1;
}
else if (this->dimPixmap_ == Dim::Some)
{
return 0.7;
}
else
{
return 0.15;
}
}
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)
{
if (this->menu_)
{
this->menu_.release()->deleteLater();
}
this->menu_ = std::move(menu);
this->menu_->installEventFilter(
new FunctionEventFilter(this, [this](QObject *, QEvent *event) {
if (event->type() == QEvent::Hide)
{
QTimer::singleShot(20, this, [this] {
this->menuVisible_ = false;
});
}
return false;
}));
}
void Button::paintEvent(QPaintEvent *)
{
QPainter painter(this);
this->paintButton(painter);
}
void Button::paintButton(QPainter &painter)
{
painter.setRenderHint(QPainter::SmoothPixmapTransform);
if (this->svgRenderer != nullptr)
{
painter.setOpacity(this->getCurrentDimAmount());
auto rect = this->rect();
if (this->enableMargin_)
{
auto s = this->getMargin();
rect = {{s, s}, rect.size() - QSize{2 * s, 2 * s}};
}
this->svgRenderer->render(&painter, rect);
}
else if (!this->pixmap_.isNull())
{
painter.setOpacity(this->getCurrentDimAmount());
QRect rect = this->rect();
resizePixmap(this->resizedPixmap_, this->pixmap_, rect.size(),
this->devicePixelRatio());
if (this->enableMargin_)
{
auto s = this->getMargin();
rect.moveLeft(s);
rect.setRight(rect.right() - s - s);
rect.moveTop(s);
rect.setBottom(rect.bottom() - s - s);
}
painter.drawPixmap(rect, this->resizedPixmap_);
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_;
}
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_)
{
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(c.red(), c.green(), c.blue(),
int((1 - effect.progress) * 95)));
painter.drawEllipse(QPointF(effect.position),
effect.progress * qreal(width()) * 2,
effect.progress * qreal(width()) * 2);
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void Button::enterEvent(QEnterEvent * /*event*/)
#else
void Button::enterEvent(QEvent * /*event*/)
#endif
{
if (!this->mouseOver_)
{
this->mouseOver_ = true;
this->update();
}
}
void Button::leaveEvent(QEvent * /*event*/)
{
if (this->mouseOver_)
{
this->mouseOver_ = false;
this->update();
}
}
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;
this->leftMousePress();
if (this->menu_ && !this->menuVisible_)
{
QTimer::singleShot(80, this, [this] {
this->showMenu();
});
this->mouseDown_ = false;
this->mouseOver_ = false;
}
}
void Button::mouseReleaseEvent(QMouseEvent *event)
{
if (!this->enabled_)
{
return;
}
bool isInside = this->rect().contains(event->pos());
if (event->button() == Qt::LeftButton)
{
this->mouseDown_ = false;
if (isInside)
{
leftClicked();
}
}
if (isInside)
{
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;
}
auto menuSizeHint = this->menu_->sizeHint();
auto point = this->mapToGlobal(
QPoint(this->width() - menuSizeHint.width(), this->height()));
auto *screen = QApplication::screenAt(point);
if (screen == nullptr)
{
screen = QApplication::primaryScreen();
}
auto bounds = screen->availableGeometry();
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());
}
this->menu_->popup(point);
this->menuVisible_ = true;
}
int Button::getMargin() const
{
assert(this->enableMargin_);
int baseMargin = this->height() < 22 * this->scale() ? 3 : 6;
return static_cast<int>(baseMargin * this->scale());
}
} // namespace chatterino
-108
View File
@@ -1,108 +0,0 @@
#pragma once
#include "widgets/BaseWidget.hpp"
#include <QMenu>
#include <QMouseEvent>
#include <QPainter>
#include <QPoint>
#include <QSvgRenderer>
#include <QTimer>
#include <QWidget>
#include <optional>
namespace chatterino {
class Button : public BaseWidget
{
Q_OBJECT
struct ClickEffect {
double progress = 0.0;
QPoint position;
ClickEffect(QPoint _position)
: position(_position)
{
}
};
public:
enum class Dim { None, Some, Lots };
Button(BaseWidget *parent = nullptr);
void setMouseEffectColor(std::optional<QColor> color);
void setPixmap(const QPixmap &pixmap_);
void setSvgResource(const QString &resourcePath);
const QPixmap &getPixmap() const;
void setDim(Dim value);
Dim getDim() const;
qreal getCurrentDimAmount() const;
void setEnable(bool value);
bool getEnable() const;
void setEnableMargin(bool value);
bool getEnableMargin() const;
void setBorderColor(const QColor &color);
const QColor &getBorderColor() const;
void setMenu(std::unique_ptr<QMenu> menu);
Q_SIGNALS:
void leftClicked();
void clicked(Qt::MouseButton button);
void leftMousePress();
protected:
void paintEvent(QPaintEvent * /*event*/) override;
/// Paint this button.
/// This is intended for child classes that may want to paint the overlay.
/// This function should be used after rendering the custom button,
/// because the painter's state will be modified by this function.
void paintButton(QPainter &painter);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void enterEvent(QEnterEvent * /*event*/) override;
#else
void enterEvent(QEvent * /*event*/) override;
#endif
void leaveEvent(QEvent *) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void fancyPaint(QPainter &painter);
bool enabled_{true};
bool selected_{false};
bool mouseOver_{false};
bool mouseDown_{false};
bool menuVisible_{false};
private:
void onMouseEffectTimeout();
void showMenu();
int getMargin() const;
QColor borderColor_{};
QPixmap pixmap_{};
QSvgRenderer *svgRenderer{};
QString svgResourcePath;
QPixmap resizedPixmap_{};
Dim dimPixmap_{Dim::Some};
bool enableMargin_{true};
QPoint mousePos_{};
double hoverMultiplier_{0.0};
QTimer effectTimer_{};
std::vector<ClickEffect> clickEffects_{};
std::optional<QColor> mouseEffectColor_{};
std::unique_ptr<QMenu> menu_{};
};
} // namespace chatterino
+8 -10
View File
@@ -35,10 +35,10 @@
#include "util/IncognitoBrowser.hpp"
#include "util/QMagicEnum.hpp"
#include "util/Twitch.hpp"
#include "widgets/buttons/LabelButton.hpp"
#include "widgets/dialogs/ReplyThreadPopup.hpp"
#include "widgets/dialogs/SettingsDialog.hpp"
#include "widgets/dialogs/UserInfoPopup.hpp"
#include "widgets/helper/EffectLabel.hpp"
#include "widgets/helper/ScrollbarHighlight.hpp"
#include "widgets/helper/SearchPopup.hpp"
#include "widgets/Notebook.hpp"
@@ -372,19 +372,17 @@ ChannelView::ChannelView(InternalCtor /*tag*/, QWidget *parent, Split *split,
void ChannelView::initializeLayout()
{
this->goToBottom_ = new EffectLabel(this, 0);
this->goToBottom_ = new LabelButton("More messages below", this);
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::leftClicked, this, [this] {
QTimer::singleShot(180, this, [this] {
this->scrollBar_->scrollToBottom(
getSettings()->enableSmoothScrollingNewMessages.getValue());
});
QObject::connect(this->goToBottom_, &Button::leftClicked, this, [this] {
QTimer::singleShot(180, this, [this] {
this->scrollBar_->scrollToBottom(
getSettings()->enableSmoothScrollingNewMessages.getValue());
});
});
}
void ChannelView::initializeScrollbar()
@@ -624,7 +622,7 @@ void ChannelView::scaleChangedEvent(float scale)
std::max<float>(
0.01, this->logicalDpiX() * this->devicePixelRatioF());
#endif
this->goToBottom_->getLabel().setFont(
this->goToBottom_->setFont(
getApp()->getFonts()->getFont(FontStyle::UiMedium, factor));
}
}
+2 -2
View File
@@ -40,7 +40,7 @@ enum class MessageElementFlag : int64_t;
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
class Scrollbar;
class EffectLabel;
class LabelButton;
struct Link;
class MessageLayoutElement;
class Split;
@@ -381,7 +381,7 @@ private:
Split *split_;
Scrollbar *scrollBar_;
EffectLabel *goToBottom_{};
LabelButton *goToBottom_{};
bool showScrollBar_ = false;
FilterSetPtr channelFilters_;
-43
View File
@@ -1,43 +0,0 @@
#include "widgets/helper/EffectLabel.hpp"
#include <QBrush>
#include <QPainter>
namespace chatterino {
EffectLabel::EffectLabel(BaseWidget *parent, int spacing)
: Button(parent)
, label_(this)
{
setLayout(&this->hbox_);
this->label_.setAlignment(Qt::AlignCenter);
this->hbox_.setContentsMargins(0, 0, 0, 0);
this->hbox_.addSpacing(spacing);
this->hbox_.addWidget(&this->label_);
this->hbox_.addSpacing(spacing);
}
EffectLabel2::EffectLabel2(BaseWidget *parent, int padding)
: Button(parent)
, label_(this)
{
auto *hbox = new QHBoxLayout(this);
this->setLayout(hbox);
// this->label_.setAlignment(Qt::AlignCenter);
this->label_.setCentered(true);
hbox->setContentsMargins(0, 0, 0, 0);
// hbox.addSpacing(spacing);
hbox->addWidget(&this->label_);
// hbox.addSpacing(spacing);
}
Label &EffectLabel2::getLabel()
{
return this->label_;
}
} // namespace chatterino
-40
View File
@@ -1,40 +0,0 @@
#pragma once
#include "widgets/helper/Button.hpp"
#include "widgets/helper/SignalLabel.hpp"
#include "widgets/Label.hpp"
#include <QHBoxLayout>
#include <QLabel>
#include <QPaintEvent>
#include <QWidget>
namespace chatterino {
class EffectLabel : public Button
{
public:
explicit EffectLabel(BaseWidget *parent = nullptr, int spacing = 6);
SignalLabel &getLabel()
{
return this->label_;
}
private:
QHBoxLayout hbox_;
SignalLabel label_;
};
class EffectLabel2 : public Button
{
public:
explicit EffectLabel2(BaseWidget *parent = nullptr, int padding = 6);
Label &getLabel();
private:
Label label_;
};
} // namespace chatterino
-235
View File
@@ -1,235 +0,0 @@
#include "widgets/helper/NotebookButton.hpp"
#include "Application.hpp"
#include "common/QLogging.hpp"
#include "singletons/Theme.hpp"
#include "widgets/helper/Button.hpp"
#include "widgets/Notebook.hpp"
#include "widgets/splits/DraggedSplit.hpp"
#include "widgets/splits/Split.hpp"
#include "widgets/splits/SplitContainer.hpp"
#include <QMimeData>
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QRadialGradient>
namespace chatterino {
NotebookButton::NotebookButton(Notebook *parent)
: Button(parent)
, parent_(parent)
{
this->setAcceptDrops(true);
}
void NotebookButton::setIcon(Icon icon)
{
this->icon_ = icon;
this->update();
}
NotebookButton::Icon NotebookButton::getIcon() const
{
return this->icon_;
}
void NotebookButton::themeChangedEvent()
{
this->setMouseEffectColor(this->theme->tabs.regular.text);
}
void NotebookButton::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QColor background;
QColor foreground;
if (mouseDown_ || mouseOver_)
{
background = this->theme->tabs.regular.backgrounds.hover;
foreground = this->theme->tabs.regular.text;
}
else
{
background = this->theme->tabs.regular.backgrounds.regular;
foreground = this->theme->tabs.regular.text;
}
painter.setPen(Qt::NoPen);
float h = height(), w = width();
switch (icon_)
{
case Plus: {
painter.setPen([&] {
QColor tmp = foreground;
if (isDraggingSplit())
{
tmp = this->theme->tabs.selected.line.regular;
}
else if (!this->mouseOver_)
{
tmp.setAlpha(180);
}
return tmp;
}());
QRect rect = this->rect();
int s = h * 4 / 9;
painter.drawLine(rect.left() + rect.width() / 2 - (s / 2),
rect.top() + rect.height() / 2,
rect.left() + rect.width() / 2 + (s / 2),
rect.top() + rect.height() / 2);
painter.drawLine(rect.left() + rect.width() / 2,
rect.top() + rect.height() / 2 - (s / 2),
rect.left() + rect.width() / 2,
rect.top() + rect.height() / 2 + (s / 2));
}
break;
case User: {
painter.setRenderHint(QPainter::Antialiasing);
auto a = w / 8;
QPainterPath path;
path.arcMoveTo(a, 4 * a, 6 * a, 6 * a, 0);
path.arcTo(a, 4 * a, 6 * a, 6 * a, 0, 180);
QPainterPath remove;
remove.addEllipse(2 * a, 1 * a, 4 * a, 4 * a);
path = path.subtracted(remove);
path.addEllipse(2.5 * a, 1.5 * a, 3 * a, 3 * a);
painter.fillPath(path, foreground);
}
break;
case Settings: {
painter.setRenderHint(QPainter::Antialiasing);
auto a = w / 8;
QPainterPath path;
path.arcMoveTo(a, a, 6 * a, 6 * a, 0 - (360 / 32.0));
for (int i = 0; i < 8; i++)
{
path.arcTo(a, a, 6 * a, 6 * a, i * (360 / 8.0) - (360 / 32.0),
(360 / 32.0));
path.arcTo(2 * a, 2 * a, 4 * a, 4 * a,
i * (360 / 8.0) + (360 / 32.0), (360 / 32.0));
}
QPainterPath remove;
remove.addEllipse(3 * a, 3 * a, 2 * a, 2 * a);
painter.fillPath(path.subtracted(remove), foreground);
}
break;
default:;
}
this->paintButton(painter);
}
void NotebookButton::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
mouseDown_ = false;
update();
leftClicked();
}
Button::mouseReleaseEvent(event);
}
void NotebookButton::dragEnterEvent(QDragEnterEvent *event)
{
if (!event->mimeData()->hasFormat("chatterino/split"))
{
return;
}
event->acceptProposedAction();
auto *e =
new QMouseEvent(QMouseEvent::MouseButtonPress,
QPointF(this->width() / 2, this->height() / 2),
QCursor::pos(), Qt::LeftButton, Qt::LeftButton, {});
Button::mousePressEvent(e);
delete e;
}
void NotebookButton::dragLeaveEvent(QDragLeaveEvent *)
{
this->mouseDown_ = true;
this->update();
auto *e =
new QMouseEvent(QMouseEvent::MouseButtonRelease,
QPointF(this->width() / 2, this->height() / 2),
QCursor::pos(), Qt::LeftButton, Qt::LeftButton, {});
Button::mouseReleaseEvent(e);
delete e;
}
void NotebookButton::dropEvent(QDropEvent *event)
{
auto *draggedSplit = dynamic_cast<Split *>(event->source());
if (!draggedSplit)
{
qCDebug(chatterinoWidget)
<< "Dropped something that wasn't a split onto a notebook button";
return;
}
auto *notebook = dynamic_cast<Notebook *>(this->parentWidget());
if (!notebook)
{
qCDebug(chatterinoWidget) << "Dropped a split onto a notebook button "
"without a parent notebook";
return;
}
event->acceptProposedAction();
auto *page = new SplitContainer(notebook);
auto *tab = notebook->addPage(page);
page->setTab(tab);
draggedSplit->setParent(page);
page->insertSplit(draggedSplit);
}
void NotebookButton::hideEvent(QHideEvent *)
{
if (isAppAboutToQuit())
{
return;
}
this->parent_->refresh();
}
void NotebookButton::showEvent(QShowEvent *)
{
if (isAppAboutToQuit())
{
return;
}
this->parent_->refresh();
}
} // namespace chatterino
-43
View File
@@ -1,43 +0,0 @@
#pragma once
#include "widgets/helper/Button.hpp"
#include <QWidget>
namespace chatterino {
class Notebook;
class NotebookButton : public Button
{
Q_OBJECT
public:
enum Icon { None, Plus, User, Settings };
explicit NotebookButton(Notebook *parent);
void setIcon(Icon icon);
Icon getIcon() const;
protected:
void themeChangedEvent() override;
void paintEvent(QPaintEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
void dragEnterEvent(QDragEnterEvent *) override;
void dragLeaveEvent(QDragLeaveEvent *) override;
void dropEvent(QDropEvent *) override;
void hideEvent(QHideEvent *) override;
void showEvent(QShowEvent *) override;
Q_SIGNALS:
void leftClicked();
private:
Notebook *parent_ = nullptr;
QPoint mousePos_;
Icon icon_ = None;
};
} // namespace chatterino
+1
View File
@@ -87,6 +87,7 @@ NotebookTab::NotebookTab(Notebook *notebook)
, notebook_(notebook)
, menu_(this)
{
this->setContentCacheEnabled(false);
this->setAcceptDrops(true);
this->positionChangedAnimation_.setEasingCurve(
+4 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include "common/Common.hpp"
#include "widgets/helper/Button.hpp"
#include "widgets/buttons/Button.hpp"
#include "widgets/helper/ChannelView.hpp"
#include "widgets/Notebook.hpp"
@@ -91,6 +91,9 @@ protected:
void themeChangedEvent() override;
void paintEvent(QPaintEvent *) override;
void paintContent(QPainter &painter) override
{
}
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "widgets/helper/TitlebarButton.hpp"
#include "widgets/buttons/TitlebarButton.hpp"
#include <QPropertyAnimation>
#include <QWidget>
-41
View File
@@ -1,41 +0,0 @@
#include "widgets/helper/SignalLabel.hpp"
namespace chatterino {
SignalLabel::SignalLabel(QWidget *parent, Qt::WindowFlags f)
: QLabel(parent, f)
{
}
void SignalLabel::mouseDoubleClickEvent(QMouseEvent *ev)
{
this->mouseDoubleClick(ev);
}
void SignalLabel::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
leftMouseDown();
}
event->ignore();
}
void SignalLabel::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
leftMouseUp();
}
event->ignore();
}
void SignalLabel::mouseMoveEvent(QMouseEvent *event)
{
this->mouseMove(event);
event->ignore();
}
} // namespace chatterino
-32
View File
@@ -1,32 +0,0 @@
#pragma once
#include <QFlags>
#include <QLabel>
#include <QMouseEvent>
#include <QWidget>
namespace chatterino {
class SignalLabel : public QLabel
{
Q_OBJECT
public:
explicit SignalLabel(QWidget *parent = nullptr, Qt::WindowFlags f = {});
~SignalLabel() override = default;
Q_SIGNALS:
void mouseDoubleClick(QMouseEvent *ev);
void leftMouseDown();
void leftMouseUp();
void mouseMove(QMouseEvent *event);
protected:
void mouseDoubleClickEvent(QMouseEvent *ev) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
};
} // namespace chatterino
-162
View File
@@ -1,162 +0,0 @@
#include "widgets/helper/TitlebarButton.hpp"
#include "singletons/Theme.hpp"
#include <QPainterPath>
namespace chatterino {
TitleBarButton::TitleBarButton()
: Button(nullptr)
{
}
TitleBarButtonStyle TitleBarButton::getButtonStyle() const
{
return this->style_;
}
void TitleBarButton::setButtonStyle(TitleBarButtonStyle _style)
{
this->style_ = _style;
this->update();
}
void TitleBarButton::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setOpacity(this->getCurrentDimAmount());
QColor color = this->theme->window.text;
QColor background = this->theme->window.background;
int xD = this->height() / 3;
int centerX = this->width() / 2;
painter.setRenderHint(QPainter::Antialiasing, false);
switch (this->style_)
{
case TitleBarButtonStyle::Minimize: {
painter.fillRect(centerX - xD / 2, xD * 3 / 2, xD, 1, color);
break;
}
case TitleBarButtonStyle::Maximize: {
painter.setPen(color);
painter.drawRect(centerX - xD / 2, xD, xD - 1, xD - 1);
break;
}
case TitleBarButtonStyle::Unmaximize: {
int xD2 = xD * 1 / 5;
int xD3 = xD * 4 / 5;
painter.drawRect(centerX - xD / 2 + xD2, xD, xD3, xD3);
painter.fillRect(centerX - xD / 2, xD + xD2, xD3, xD3,
this->theme->window.background);
painter.drawRect(centerX - xD / 2, xD + xD2, xD3, xD3);
break;
}
case TitleBarButtonStyle::Close: {
QRect rect(centerX - xD / 2, xD, xD - 1, xD - 1);
painter.setPen(QPen(color, 1));
painter.drawLine(rect.topLeft(), rect.bottomRight());
painter.drawLine(rect.topRight(), rect.bottomLeft());
break;
}
case TitleBarButtonStyle::User: {
color = "#999";
painter.setRenderHint(QPainter::Antialiasing);
auto a = xD / 3;
QPainterPath path;
painter.save();
painter.translate(3, 3);
path.arcMoveTo(a, 4 * a, 6 * a, 6 * a, 0);
path.arcTo(a, 4 * a, 6 * a, 6 * a, 0, 180);
painter.fillPath(path, color);
painter.setBrush(background);
painter.drawEllipse(2 * a, 1 * a, 4 * a, 4 * a);
painter.setBrush(color);
painter.drawEllipse(2.5 * a, 1.5 * a, 3 * a + 1, 3 * a);
painter.restore();
break;
}
case TitleBarButtonStyle::Settings: {
color = "#999";
painter.setRenderHint(QPainter::Antialiasing);
painter.save();
painter.translate(3, 3);
auto a = xD / 3;
QPainterPath path;
path.arcMoveTo(a, a, 6 * a, 6 * a, 0 - (360 / 32.0));
for (int i = 0; i < 8; i++)
{
path.arcTo(a, a, 6 * a, 6 * a, i * (360 / 8.0) - (360 / 32.0),
(360 / 32.0));
path.arcTo(2 * a, 2 * a, 4 * a, 4 * a,
i * (360 / 8.0) + (360 / 32.0), (360 / 32.0));
}
painter.strokePath(path, color);
painter.fillPath(path, color);
painter.setBrush(background);
painter.drawEllipse(3 * a, 3 * a, 2 * a, 2 * a);
painter.restore();
break;
}
default:;
}
this->paintButton(painter);
}
void TitleBarButton::ncEnter()
{
this->enterEvent(nullptr);
this->update();
}
void TitleBarButton::ncLeave()
{
this->leaveEvent(nullptr);
this->update();
}
void TitleBarButton::ncMove(QPoint at)
{
QMouseEvent evt(QMouseEvent::MouseMove, at, QCursor::pos(), Qt::NoButton,
Qt::NoButton, Qt::NoModifier);
this->mouseMoveEvent(&evt);
}
void TitleBarButton::ncMousePress(QPoint at)
{
QMouseEvent evt(QMouseEvent::MouseButtonPress, at, QCursor::pos(),
Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
this->mousePressEvent(&evt);
this->update();
}
void TitleBarButton::ncMouseRelease(QPoint at)
{
QMouseEvent evt(QMouseEvent::MouseButtonRelease, at, QCursor::pos(),
Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
this->mouseReleaseEvent(&evt);
this->update();
}
} // namespace chatterino
-51
View File
@@ -1,51 +0,0 @@
#pragma once
#include "widgets/helper/Button.hpp"
namespace chatterino {
enum class TitleBarButtonStyle {
None = 0,
Minimize = 1,
Maximize = 2,
Unmaximize = 4,
Close = 8,
User = 16,
Settings = 32,
StreamerMode = 64,
};
class TitleBarButton : public Button
{
public:
TitleBarButton();
TitleBarButtonStyle getButtonStyle() const;
void setButtonStyle(TitleBarButtonStyle style_);
/// Simulate a `mouseEnter` event.
void ncEnter();
/// Simulate a `mouseLeave` event.
void ncLeave();
/// Simulate a `mouseMove` event.
/// @param at a local position relative to this widget
void ncMove(QPoint at);
/// Simulate a `mousePress` event with the left mouse button.
/// @param at a local position relative to this widget
void ncMousePress(QPoint at);
/// Simulate a `mouseRelease` event with the left mouse button.
/// @param at a local position relative to this widget
void ncMouseRelease(QPoint at);
protected:
void paintEvent(QPaintEvent *) override;
private:
TitleBarButtonStyle style_{};
};
} // namespace chatterino
-116
View File
@@ -1,116 +0,0 @@
#include "widgets/helper/TitlebarButtons.hpp"
#ifdef USEWINSDK
# include "widgets/helper/TitlebarButton.hpp"
# include <Windows.h>
# include <cassert>
namespace chatterino {
TitleBarButtons::TitleBarButtons(QWidget *window, TitleBarButton *minButton,
TitleBarButton *maxButton,
TitleBarButton *closeButton)
: QObject(window)
, window_(window)
, minButton_(minButton)
, maxButton_(maxButton)
, closeButton_(closeButton)
{
}
void TitleBarButtons::hover(size_t ht, QPoint at)
{
TitleBarButton *hovered{};
TitleBarButton *other1{};
TitleBarButton *other2{};
switch (ht)
{
case HTMAXBUTTON:
hovered = this->maxButton_;
other1 = this->minButton_;
other2 = this->closeButton_;
break;
case HTMINBUTTON:
hovered = this->minButton_;
other1 = this->maxButton_;
other2 = this->closeButton_;
break;
case HTCLOSE:
hovered = this->closeButton_;
other1 = this->minButton_;
other2 = this->maxButton_;
break;
default:
assert(false && "TitleBarButtons::hover precondition violated");
return;
}
hovered->ncEnter();
hovered->ncMove(hovered->mapFromGlobal(at));
other1->ncLeave();
other2->ncLeave();
}
void TitleBarButtons::leave()
{
this->minButton_->ncLeave();
this->maxButton_->ncLeave();
this->closeButton_->ncLeave();
}
void TitleBarButtons::mousePress(size_t ht, QPoint at)
{
auto *button = this->buttonForHt(ht);
button->ncMousePress(button->mapFromGlobal(at));
}
void TitleBarButtons::mouseRelease(size_t ht, QPoint at)
{
auto *button = this->buttonForHt(ht);
button->ncMouseRelease(button->mapFromGlobal(at));
}
void TitleBarButtons::updateMaxButton()
{
this->maxButton_->setButtonStyle(
this->window_->windowState().testFlag(Qt::WindowMaximized)
? TitleBarButtonStyle::Unmaximize
: TitleBarButtonStyle::Maximize);
}
void TitleBarButtons::setSmallSize()
{
this->minButton_->setScaleIndependentSize(30, 30);
this->maxButton_->setScaleIndependentSize(30, 30);
this->closeButton_->setScaleIndependentSize(30, 30);
}
void TitleBarButtons::setRegularSize()
{
this->minButton_->setScaleIndependentSize(46, 30);
this->maxButton_->setScaleIndependentSize(46, 30);
this->closeButton_->setScaleIndependentSize(46, 30);
}
TitleBarButton *TitleBarButtons::buttonForHt(size_t ht) const
{
switch (ht)
{
case HTMAXBUTTON:
return this->maxButton_;
case HTMINBUTTON:
return this->minButton_;
case HTCLOSE:
return this->closeButton_;
default:
assert(false &&
"TitleBarButtons::buttonForHt precondition violated");
return nullptr;
}
}
} // namespace chatterino
#endif
-70
View File
@@ -1,70 +0,0 @@
#pragma once
class QPoint;
class QWidget;
#include <QObject>
#include <QtGlobal>
namespace chatterino {
#ifdef USEWINSDK
class TitleBarButton;
class TitleBarButtons : QObject
{
public:
/// The parent of this object is set to `window`.
///
/// All parameters must have a parent;
/// they're not deleted in the destructor.
TitleBarButtons(QWidget *window, TitleBarButton *minButton,
TitleBarButton *maxButton, TitleBarButton *closeButton);
/// Hover over the button `ht` at the global position `at`.
///
/// @pre `ht` must be one of { HTMAXBUTTON, HTMINBUTTON, HTCLOSE }.
/// @param ht The hovered button
/// @param at The global position of the event
void hover(size_t ht, QPoint at);
/// Leave all buttons - simulate `leaveEvent` for all buttons.
void leave();
/// Press the left mouse over the button `ht` at the global position `at`.
///
/// @pre `ht` must be one of { HTMAXBUTTON, HTMINBUTTON, HTCLOSE }.
/// @param ht The clicked button
/// @param at The global position of the event
void mousePress(size_t ht, QPoint at);
/// Release the left mouse button over the button `ht` at the
/// global position `at`.
///
/// @pre `ht` must be one of { HTMAXBUTTON, HTMINBUTTON, HTCLOSE }.
/// @param ht The clicked button
/// @param at The global position of the event
void mouseRelease(size_t ht, QPoint at);
/// Update the maximize/restore button to show the correct image
/// according to the current window state.
void updateMaxButton();
/// Set buttons to be narrow.
void setSmallSize();
/// Set buttons to be regular size.
void setRegularSize();
private:
/// @pre ht must be one of { HTMAXBUTTON, HTMINBUTTON, HTCLOSE }.
TitleBarButton *buttonForHt(size_t ht) const;
QWidget *window_ = nullptr;
TitleBarButton *minButton_ = nullptr;
TitleBarButton *maxButton_ = nullptr;
TitleBarButton *closeButton_ = nullptr;
};
#endif
} // namespace chatterino