ref: merge TooltipPreviewImage and TooltipWidget (#4268)

* merge TooltipPreviewImage and TooltipWidget

* changelog

* add empty line before return

* fix signalholder include

* add changelog for bugfix

* fix custom scaling issue

Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
kornes 2022-12-29 15:07:46 +00:00 committed by GitHub
parent 448c8622e7
commit 11fdd7ed74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 174 deletions

View file

@ -16,11 +16,13 @@
- Bugfix: Fixed crash that could occur when changing Tab layout and utilizing multiple windows. (#4248) - Bugfix: Fixed crash that could occur when changing Tab layout and utilizing multiple windows. (#4248)
- Bugfix: Fixed text sometimes not pasting properly when image uploader was disabled. (#4246) - Bugfix: Fixed text sometimes not pasting properly when image uploader was disabled. (#4246)
- Bugfix: Fixed text cursor(caret) not showing in open channel dialog. (#4196) - Bugfix: Fixed text cursor(caret) not showing in open channel dialog. (#4196)
- Bugfix: Fixed tooltip images not appearing if mouse hovered only first pixel. (#4268)
- Dev: Remove protocol from QApplication's Organization Domain (so changed from `https://www.chatterino.com` to `chatterino.com`). (#4256) - Dev: Remove protocol from QApplication's Organization Domain (so changed from `https://www.chatterino.com` to `chatterino.com`). (#4256)
- Dev: Ignore `WM_SHOWWINDOW` hide events, causing fewer attempted rescales. (#4198) - Dev: Ignore `WM_SHOWWINDOW` hide events, causing fewer attempted rescales. (#4198)
- Dev: Migrated to C++ 20 (#4252, #4257) - Dev: Migrated to C++ 20 (#4252, #4257)
- Dev: Enable LTO for main branch builds. (#4258, #4260) - Dev: Enable LTO for main branch builds. (#4258, #4260)
- Dev: Removed unused include directives. (#4266) - Dev: Removed unused include directives. (#4266)
- Dev: Removed TooltipPreviewImage. (#4268)
- Dev: Removed unused operators in `Image` (#4267) - Dev: Removed unused operators in `Image` (#4267)
## 2.4.0 ## 2.4.0

View file

@ -316,8 +316,6 @@ set(SOURCE_FILES
singletons/Theme.hpp singletons/Theme.hpp
singletons/Toasts.cpp singletons/Toasts.cpp
singletons/Toasts.hpp singletons/Toasts.hpp
singletons/TooltipPreviewImage.cpp
singletons/TooltipPreviewImage.hpp
singletons/Updates.cpp singletons/Updates.cpp
singletons/Updates.hpp singletons/Updates.hpp
singletons/WindowManager.cpp singletons/WindowManager.cpp

View file

@ -1,81 +0,0 @@
#include "TooltipPreviewImage.hpp"
#include "Application.hpp"
#include "singletons/WindowManager.hpp"
#include "widgets/TooltipWidget.hpp"
namespace chatterino {
TooltipPreviewImage &TooltipPreviewImage::instance()
{
static TooltipPreviewImage *instance = new TooltipPreviewImage();
return *instance;
}
TooltipPreviewImage::TooltipPreviewImage()
{
auto windows = getApp()->windows;
this->connections_.managedConnect(windows->gifRepaintRequested, [&] {
if (this->image_ && this->image_->animated())
{
this->refreshTooltipWidgetPixmap();
}
});
this->connections_.managedConnect(windows->miscUpdate, [&] {
if (this->attemptRefresh)
{
this->refreshTooltipWidgetPixmap();
}
});
}
void TooltipPreviewImage::setImage(ImagePtr image)
{
this->image_ = std::move(image);
this->refreshTooltipWidgetPixmap();
}
void TooltipPreviewImage::setImageScale(int w, int h)
{
this->imageWidth_ = w;
this->imageHeight_ = h;
this->refreshTooltipWidgetPixmap();
}
void TooltipPreviewImage::refreshTooltipWidgetPixmap()
{
auto tooltipWidget = TooltipWidget::instance();
if (this->image_ && !tooltipWidget->isHidden())
{
if (auto pixmap = this->image_->pixmapOrLoad())
{
if (this->imageWidth_ != 0 && this->imageHeight_)
{
tooltipWidget->setImage(pixmap->scaled(this->imageWidth_,
this->imageHeight_,
Qt::KeepAspectRatio));
}
else
{
tooltipWidget->setImage(*pixmap);
}
this->attemptRefresh = false;
}
else
{
this->attemptRefresh = true;
}
}
else
{
tooltipWidget->clearImage();
}
}
} // namespace chatterino

View file

@ -1,36 +0,0 @@
#pragma once
#include "messages/Image.hpp"
#include <pajlada/signals/signalholder.hpp>
namespace chatterino {
class TooltipPreviewImage
{
public:
static TooltipPreviewImage &instance();
void setImage(ImagePtr image);
void setImageScale(int w, int h);
TooltipPreviewImage(const TooltipPreviewImage &) = delete;
private:
TooltipPreviewImage();
private:
ImagePtr image_ = nullptr;
int imageWidth_ = 0;
int imageHeight_ = 0;
pajlada::Signals::SignalHolder connections_;
// attemptRefresh is set to true in case we want to preview an image that has not loaded yet (if pixmapOrLoad fails)
bool attemptRefresh{false};
// Refresh the pixmap used in the Tooltip Widget
// Called from setImage and from the "gif repaint" signal if the image is animated
void refreshTooltipWidgetPixmap();
};
} // namespace chatterino

View file

@ -1,17 +1,11 @@
#include "TooltipWidget.hpp" #include "TooltipWidget.hpp"
#include "Application.hpp"
#include "singletons/Fonts.hpp" #include "singletons/Fonts.hpp"
#include "singletons/WindowManager.hpp"
#include <QDebug>
#include <QDesktopWidget>
#include <QStyle>
#include <QVBoxLayout>
#ifdef USEWINSDK
# include <Windows.h>
#endif
#include <QPainter> #include <QPainter>
#include <QVBoxLayout>
namespace chatterino { namespace chatterino {
@ -25,44 +19,52 @@ TooltipWidget::TooltipWidget(BaseWidget *parent)
: BaseWindow({BaseWindow::TopMost, BaseWindow::DontFocus, : BaseWindow({BaseWindow::TopMost, BaseWindow::DontFocus,
BaseWindow::DisableLayoutSave}, BaseWindow::DisableLayoutSave},
parent) parent)
, displayImage_(new QLabel()) , displayImage_(new QLabel(this))
, displayText_(new QLabel()) , displayText_(new QLabel(this))
{ {
this->setStyleSheet("color: #fff; background: rgba(11, 11, 11, 0.8)"); this->setStyleSheet("color: #fff; background: rgba(11, 11, 11, 0.8)");
this->setAttribute(Qt::WA_TranslucentBackground); this->setAttribute(Qt::WA_TranslucentBackground);
//this->setWindowOpacity(0.8); this->setWindowFlag(Qt::WindowStaysOnTopHint, true);
this->updateFont();
this->setStayInScreenRect(true); this->setStayInScreenRect(true);
displayImage_->hide();
displayImage_->setAlignment(Qt::AlignHCenter); displayImage_->setAlignment(Qt::AlignHCenter);
displayImage_->setStyleSheet("background: transparent"); displayImage_->setStyleSheet("background: transparent");
displayText_->setAlignment(Qt::AlignHCenter); displayText_->setAlignment(Qt::AlignHCenter);
displayText_->setText("tooltip text");
displayText_->setStyleSheet("background: transparent"); displayText_->setStyleSheet("background: transparent");
auto layout = new QVBoxLayout();
auto *layout = new QVBoxLayout(this);
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setContentsMargins(10, 5, 10, 5); layout->setContentsMargins(10, 5, 10, 5);
layout->addWidget(displayImage_); layout->addWidget(displayImage_);
layout->addWidget(displayText_); layout->addWidget(displayText_);
this->setLayout(layout); this->setLayout(layout);
this->fontChangedConnection_ = getFonts()->fontChanged.connect([this] { this->connections_.managedConnect(getFonts()->fontChanged, [this] {
this->updateFont(); this->updateFont();
}); });
} this->updateFont();
TooltipWidget::~TooltipWidget() auto windows = getApp()->windows;
{ this->connections_.managedConnect(windows->gifRepaintRequested, [this] {
this->fontChangedConnection_.disconnect(); if (this->image_ && this->image_->animated())
} {
this->refreshPixmap();
}
});
#ifdef USEWINSDK this->connections_.managedConnect(windows->miscUpdate, [this] {
void TooltipWidget::raise() if (this->image_ && this->attemptRefresh)
{ {
::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0, if (this->refreshPixmap())
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); {
this->attemptRefresh = false;
this->adjustSize();
}
}
});
} }
#endif
void TooltipWidget::themeChangedEvent() void TooltipWidget::themeChangedEvent()
{ {
@ -100,12 +102,69 @@ void TooltipWidget::setWordWrap(bool wrap)
void TooltipWidget::clearImage() void TooltipWidget::clearImage()
{ {
this->displayImage_->hide(); this->displayImage_->hide();
this->image_ = nullptr;
this->setImageScale(0, 0);
} }
void TooltipWidget::setImage(QPixmap image) void TooltipWidget::setImage(ImagePtr image)
{ {
if (this->image_ == image)
{
return;
}
// hide image until loaded and reset scale
this->clearImage();
this->image_ = std::move(image);
this->refreshPixmap();
}
void TooltipWidget::setImageScale(int w, int h)
{
if (this->customImgWidth == w && this->customImgHeight == h)
{
return;
}
this->customImgWidth = w;
this->customImgHeight = h;
this->refreshPixmap();
}
void TooltipWidget::hideEvent(QHideEvent *)
{
this->clearImage();
}
void TooltipWidget::showEvent(QShowEvent *)
{
this->adjustSize();
}
bool TooltipWidget::refreshPixmap()
{
if (!this->image_)
{
return false;
}
auto pixmap = this->image_->pixmapOrLoad();
if (!pixmap)
{
this->attemptRefresh = true;
return false;
}
if (this->customImgWidth > 0 || this->customImgHeight > 0)
{
this->displayImage_->setPixmap(pixmap->scaled(
this->customImgWidth, this->customImgHeight, Qt::KeepAspectRatio));
}
else
{
this->displayImage_->setPixmap(*pixmap);
}
this->displayImage_->show(); this->displayImage_->show();
this->displayImage_->setPixmap(image);
return true;
} }
void TooltipWidget::changeEvent(QEvent *) void TooltipWidget::changeEvent(QEvent *)

View file

@ -1,8 +1,9 @@
#pragma once #pragma once
#include "messages/Image.hpp"
#include "widgets/BaseWindow.hpp" #include "widgets/BaseWindow.hpp"
#include <pajlada/signals/signal.hpp> #include <pajlada/signals/signalholder.hpp>
#include <QLabel> #include <QLabel>
#include <QWidget> #include <QWidget>
@ -16,18 +17,17 @@ public:
static TooltipWidget *instance(); static TooltipWidget *instance();
TooltipWidget(BaseWidget *parent = nullptr); TooltipWidget(BaseWidget *parent = nullptr);
~TooltipWidget() override; ~TooltipWidget() override = default;
void setText(QString text); void setText(QString text);
void setWordWrap(bool wrap); void setWordWrap(bool wrap);
void clearImage(); void clearImage();
void setImage(QPixmap image); void setImage(ImagePtr image);
void setImageScale(int w, int h);
#ifdef USEWINSDK
void raise();
#endif
protected: protected:
void showEvent(QShowEvent *) override;
void hideEvent(QHideEvent *) override;
void changeEvent(QEvent *) override; void changeEvent(QEvent *) override;
void leaveEvent(QEvent *) override; void leaveEvent(QEvent *) override;
void themeChangedEvent() override; void themeChangedEvent() override;
@ -37,9 +37,18 @@ protected:
private: private:
void updateFont(); void updateFont();
// used by WindowManager::gifRepaintRequested signal to progress frames when tooltip image is animated
bool refreshPixmap();
// set to true when tooltip image did not finish loading yet (pixmapOrLoad returned false)
bool attemptRefresh{false};
ImagePtr image_ = nullptr;
int customImgWidth = 0;
int customImgHeight = 0;
QLabel *displayImage_; QLabel *displayImage_;
QLabel *displayText_; QLabel *displayText_;
pajlada::Signals::Connection fontChangedConnection_; pajlada::Signals::SignalHolder connections_;
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -20,7 +20,6 @@
#include "singletons/Resources.hpp" #include "singletons/Resources.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "singletons/TooltipPreviewImage.hpp"
#include "singletons/WindowManager.hpp" #include "singletons/WindowManager.hpp"
#include "util/Clipboard.hpp" #include "util/Clipboard.hpp"
#include "util/DistanceBetweenPoints.hpp" #include "util/DistanceBetweenPoints.hpp"
@ -1659,8 +1658,6 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
} }
else else
{ {
auto &tooltipPreviewImage = TooltipPreviewImage::instance();
tooltipPreviewImage.setImageScale(0, 0);
auto badgeElement = dynamic_cast<const BadgeElement *>(element); auto badgeElement = dynamic_cast<const BadgeElement *>(element);
if ((badgeElement || emoteElement) && if ((badgeElement || emoteElement) &&
@ -1671,18 +1668,18 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
{ {
if (emoteElement) if (emoteElement)
{ {
tooltipPreviewImage.setImage( tooltipWidget->setImage(
emoteElement->getEmote()->images.getImage(3.0)); emoteElement->getEmote()->images.getImage(3.0));
} }
else if (badgeElement) else if (badgeElement)
{ {
tooltipPreviewImage.setImage( tooltipWidget->setImage(
badgeElement->getEmote()->images.getImage(3.0)); badgeElement->getEmote()->images.getImage(3.0));
} }
} }
else else
{ {
tooltipPreviewImage.setImage(nullptr); tooltipWidget->clearImage();
} }
} }
else else
@ -1705,7 +1702,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
auto thumbnailSize = getSettings()->thumbnailSize; auto thumbnailSize = getSettings()->thumbnailSize;
if (!thumbnailSize) if (!thumbnailSize)
{ {
tooltipPreviewImage.setImage(nullptr); tooltipWidget->clearImage();
} }
else else
{ {
@ -1718,13 +1715,12 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
shouldHideThumbnail shouldHideThumbnail
? Image::fromResourcePixmap(getResources().streamerMode) ? Image::fromResourcePixmap(getResources().streamerMode)
: element->getThumbnail(); : element->getThumbnail();
tooltipPreviewImage.setImage(std::move(thumb)); tooltipWidget->setImage(std::move(thumb));
if (element->getThumbnailType() == if (element->getThumbnailType() ==
MessageElement::ThumbnailType::Link_Thumbnail) MessageElement::ThumbnailType::Link_Thumbnail)
{ {
tooltipPreviewImage.setImageScale(thumbnailSize, tooltipWidget->setImageScale(thumbnailSize, thumbnailSize);
thumbnailSize);
} }
} }
} }
@ -1732,10 +1728,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
tooltipWidget->moveTo(this, event->globalPos()); tooltipWidget->moveTo(this, event->globalPos());
tooltipWidget->setWordWrap(isLinkValid); tooltipWidget->setWordWrap(isLinkValid);
tooltipWidget->setText(element->getTooltip()); tooltipWidget->setText(element->getTooltip());
tooltipWidget->adjustSize();
tooltipWidget->setWindowFlag(Qt::WindowStaysOnTopHint, true);
tooltipWidget->show(); tooltipWidget->show();
tooltipWidget->raise();
} }
// check if word has a link // check if word has a link

View file

@ -13,7 +13,6 @@
#include "singletons/Resources.hpp" #include "singletons/Resources.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "singletons/TooltipPreviewImage.hpp"
#include "singletons/WindowManager.hpp" #include "singletons/WindowManager.hpp"
#include "util/Helpers.hpp" #include "util/Helpers.hpp"
#include "util/LayoutCreator.hpp" #include "util/LayoutCreator.hpp"
@ -928,9 +927,8 @@ void SplitHeader::enterEvent(QEvent *event)
dynamic_cast<TwitchChannel *>(channel)->refreshTitle(); dynamic_cast<TwitchChannel *>(channel)->refreshTitle();
} }
TooltipPreviewImage::instance().setImage(nullptr);
auto tooltip = TooltipWidget::instance(); auto tooltip = TooltipWidget::instance();
tooltip->clearImage();
tooltip->setText(this->tooltipText_); tooltip->setText(this->tooltipText_);
tooltip->setWordWrap(true); tooltip->setWordWrap(true);
tooltip->adjustSize(); tooltip->adjustSize();
@ -939,7 +937,6 @@ void SplitHeader::enterEvent(QEvent *event)
tooltip->moveTo(this, pos, false); tooltip->moveTo(this, pos, false);
tooltip->show(); tooltip->show();
tooltip->raise();
} }
BaseWidget::enterEvent(event); BaseWidget::enterEvent(event);