Formalize zero-width emote implementation (#4314)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
#include "widgets/TooltipEntryWidget.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
TooltipEntryWidget::TooltipEntryWidget(QWidget *parent)
|
||||
: TooltipEntryWidget(nullptr, "", 0, 0, parent)
|
||||
{
|
||||
}
|
||||
|
||||
TooltipEntryWidget::TooltipEntryWidget(ImagePtr image, const QString &text,
|
||||
int customWidth, int customHeight,
|
||||
QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, image_(image)
|
||||
, customImgWidth_(customWidth)
|
||||
, customImgHeight_(customHeight)
|
||||
{
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->setLayout(layout);
|
||||
|
||||
this->displayImage_ = new QLabel();
|
||||
this->displayImage_->setAlignment(Qt::AlignHCenter);
|
||||
this->displayImage_->setStyleSheet("background: transparent");
|
||||
this->displayText_ = new QLabel(text);
|
||||
this->displayText_->setAlignment(Qt::AlignHCenter);
|
||||
this->displayText_->setStyleSheet("background: transparent");
|
||||
|
||||
layout->addWidget(this->displayImage_);
|
||||
layout->addWidget(this->displayText_);
|
||||
}
|
||||
|
||||
void TooltipEntryWidget::setWordWrap(bool wrap)
|
||||
{
|
||||
this->displayText_->setWordWrap(wrap);
|
||||
}
|
||||
|
||||
void TooltipEntryWidget::setImageScale(int w, int h)
|
||||
{
|
||||
if (this->customImgWidth_ == w && this->customImgHeight_ == h)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->customImgWidth_ = w;
|
||||
this->customImgHeight_ = h;
|
||||
this->refreshPixmap();
|
||||
}
|
||||
|
||||
void TooltipEntryWidget::setText(const QString &text)
|
||||
{
|
||||
this->displayText_->setText(text);
|
||||
}
|
||||
|
||||
void TooltipEntryWidget::setImage(ImagePtr image)
|
||||
{
|
||||
if (this->image_ == image)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->clearImage();
|
||||
this->image_ = std::move(image);
|
||||
this->refreshPixmap();
|
||||
}
|
||||
|
||||
void TooltipEntryWidget::clearImage()
|
||||
{
|
||||
this->displayImage_->hide();
|
||||
this->image_ = nullptr;
|
||||
this->setImageScale(0, 0);
|
||||
}
|
||||
|
||||
bool TooltipEntryWidget::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();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TooltipEntryWidget::animated() const
|
||||
{
|
||||
return this->image_ && this->image_->animated();
|
||||
}
|
||||
|
||||
bool TooltipEntryWidget::hasImage() const
|
||||
{
|
||||
return this->image_ != nullptr;
|
||||
}
|
||||
|
||||
bool TooltipEntryWidget::attemptRefresh() const
|
||||
{
|
||||
return this->attemptRefresh_;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "messages/Image.hpp"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class TooltipEntryWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TooltipEntryWidget(QWidget *parent = nullptr);
|
||||
TooltipEntryWidget(ImagePtr image, const QString &text, int customWidth,
|
||||
int customHeight, QWidget *parent = nullptr);
|
||||
|
||||
void setImageScale(int w, int h);
|
||||
void setWordWrap(bool wrap);
|
||||
|
||||
void setText(const QString &text);
|
||||
void setImage(ImagePtr image);
|
||||
void clearImage();
|
||||
bool refreshPixmap();
|
||||
|
||||
bool animated() const;
|
||||
bool hasImage() const;
|
||||
bool attemptRefresh() const;
|
||||
|
||||
private:
|
||||
QLabel *displayImage_ = nullptr;
|
||||
QLabel *displayText_ = nullptr;
|
||||
|
||||
bool attemptRefresh_ = false;
|
||||
|
||||
ImagePtr image_ = nullptr;
|
||||
int customImgWidth_ = 0;
|
||||
int customImgHeight_ = 0;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
+217
-81
@@ -6,7 +6,9 @@
|
||||
#include "singletons/WindowManager.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
// number of columns in grid mode
|
||||
#define GRID_NUM_COLS 3
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
@@ -20,8 +22,6 @@ TooltipWidget::TooltipWidget(BaseWidget *parent)
|
||||
: BaseWindow({BaseWindow::TopMost, BaseWindow::DontFocus,
|
||||
BaseWindow::DisableLayoutSave},
|
||||
parent)
|
||||
, displayImage_(new QLabel(this))
|
||||
, displayText_(new QLabel(this))
|
||||
{
|
||||
this->setStyleSheet("color: #fff; background: rgba(11, 11, 11, 0.8)");
|
||||
this->setAttribute(Qt::WA_TranslucentBackground);
|
||||
@@ -29,18 +29,10 @@ TooltipWidget::TooltipWidget(BaseWidget *parent)
|
||||
|
||||
this->setStayInScreenRect(true);
|
||||
|
||||
displayImage_->setAlignment(Qt::AlignHCenter);
|
||||
displayImage_->setStyleSheet("background: transparent");
|
||||
|
||||
displayText_->setAlignment(Qt::AlignHCenter);
|
||||
displayText_->setStyleSheet("background: transparent");
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
layout->setContentsMargins(10, 5, 10, 5);
|
||||
layout->addWidget(displayImage_);
|
||||
layout->addWidget(displayText_);
|
||||
this->setLayout(layout);
|
||||
// Default to using vertical layout
|
||||
this->initializeVLayout();
|
||||
this->setLayout(this->vLayout_);
|
||||
this->currentStyle_ = TooltipStyle::Vertical;
|
||||
|
||||
this->connections_.managedConnect(getFonts()->fontChanged, [this] {
|
||||
this->updateFont();
|
||||
@@ -49,24 +41,219 @@ TooltipWidget::TooltipWidget(BaseWidget *parent)
|
||||
|
||||
auto windows = getApp()->windows;
|
||||
this->connections_.managedConnect(windows->gifRepaintRequested, [this] {
|
||||
if (this->image_ && this->image_->animated())
|
||||
for (int i = 0; i < this->visibleEntries_; ++i)
|
||||
{
|
||||
this->refreshPixmap();
|
||||
auto entry = this->entryAt(i);
|
||||
if (entry && entry->animated())
|
||||
{
|
||||
entry->refreshPixmap();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this->connections_.managedConnect(windows->miscUpdate, [this] {
|
||||
if (this->image_ && this->attemptRefresh)
|
||||
bool needSizeAdjustment = false;
|
||||
for (int i = 0; i < this->visibleEntries_; ++i)
|
||||
{
|
||||
if (this->refreshPixmap())
|
||||
auto entry = this->entryAt(i);
|
||||
if (entry->hasImage() && entry->attemptRefresh())
|
||||
{
|
||||
this->attemptRefresh = false;
|
||||
this->adjustSize();
|
||||
bool successfullyUpdated = entry->refreshPixmap();
|
||||
needSizeAdjustment |= successfullyUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
if (needSizeAdjustment)
|
||||
{
|
||||
this->adjustSize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TooltipWidget::setOne(const TooltipEntry &entry, TooltipStyle style)
|
||||
{
|
||||
this->set({entry}, style);
|
||||
}
|
||||
|
||||
void TooltipWidget::set(const std::vector<TooltipEntry> &entries,
|
||||
TooltipStyle style)
|
||||
{
|
||||
this->setCurrentStyle(style);
|
||||
|
||||
int delta = entries.size() - this->currentLayoutCount();
|
||||
if (delta > 0)
|
||||
{
|
||||
// Need to add more TooltipEntry instances
|
||||
int base = this->currentLayoutCount();
|
||||
for (int i = 0; i < delta; ++i)
|
||||
{
|
||||
this->addNewEntry(base + i);
|
||||
}
|
||||
}
|
||||
|
||||
this->setVisibleEntries(entries.size());
|
||||
|
||||
for (int i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
if (auto entryWidget = this->entryAt(i))
|
||||
{
|
||||
auto &entry = entries[i];
|
||||
entryWidget->setImage(entry.image);
|
||||
entryWidget->setText(entry.text);
|
||||
entryWidget->setImageScale(entry.customWidth, entry.customHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TooltipWidget::setVisibleEntries(int n)
|
||||
{
|
||||
for (int i = 0; i < this->currentLayoutCount(); ++i)
|
||||
{
|
||||
auto *entry = this->entryAt(i);
|
||||
if (entry == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i >= n)
|
||||
{
|
||||
entry->hide();
|
||||
entry->clearImage();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->show();
|
||||
}
|
||||
}
|
||||
this->visibleEntries_ = n;
|
||||
}
|
||||
|
||||
void TooltipWidget::addNewEntry(int absoluteIndex)
|
||||
{
|
||||
switch (this->currentStyle_)
|
||||
{
|
||||
case TooltipStyle::Vertical:
|
||||
this->vLayout_->addWidget(new TooltipEntryWidget(),
|
||||
Qt::AlignHCenter);
|
||||
return;
|
||||
case TooltipStyle::Grid:
|
||||
if (absoluteIndex == 0)
|
||||
{
|
||||
// Top row spans all columns
|
||||
this->gLayout_->addWidget(new TooltipEntryWidget(), 0, 0, 1,
|
||||
GRID_NUM_COLS, Qt::AlignCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
int row = ((absoluteIndex - 1) / GRID_NUM_COLS) + 1;
|
||||
int col = (absoluteIndex - 1) % GRID_NUM_COLS;
|
||||
this->gLayout_->addWidget(new TooltipEntryWidget(), row, col,
|
||||
Qt::AlignHCenter | Qt::AlignBottom);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// May be nullptr
|
||||
QLayout *TooltipWidget::currentLayout() const
|
||||
{
|
||||
switch (this->currentStyle_)
|
||||
{
|
||||
case TooltipStyle::Vertical:
|
||||
return this->vLayout_;
|
||||
case TooltipStyle::Grid:
|
||||
return this->gLayout_;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int TooltipWidget::currentLayoutCount() const
|
||||
{
|
||||
if (auto *layout = this->currentLayout())
|
||||
{
|
||||
return layout->count();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// May be nullptr
|
||||
TooltipEntryWidget *TooltipWidget::entryAt(int n)
|
||||
{
|
||||
if (auto *layout = this->currentLayout())
|
||||
{
|
||||
return dynamic_cast<TooltipEntryWidget *>(layout->itemAt(n)->widget());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TooltipWidget::setCurrentStyle(TooltipStyle style)
|
||||
{
|
||||
if (this->currentStyle_ == style)
|
||||
{
|
||||
// Nothing to update
|
||||
return;
|
||||
}
|
||||
|
||||
this->clearEntries();
|
||||
this->deleteCurrentLayout();
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case TooltipStyle::Vertical:
|
||||
this->initializeVLayout();
|
||||
this->setLayout(this->vLayout_);
|
||||
break;
|
||||
case TooltipStyle::Grid:
|
||||
this->initializeGLayout();
|
||||
this->setLayout(this->gLayout_);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this->currentStyle_ = style;
|
||||
}
|
||||
|
||||
void TooltipWidget::deleteCurrentLayout()
|
||||
{
|
||||
auto *currentLayout = this->layout();
|
||||
delete currentLayout;
|
||||
|
||||
switch (this->currentStyle_)
|
||||
{
|
||||
case TooltipStyle::Vertical:
|
||||
this->vLayout_ = nullptr;
|
||||
break;
|
||||
case TooltipStyle::Grid:
|
||||
this->gLayout_ = nullptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TooltipWidget::initializeVLayout()
|
||||
{
|
||||
auto *vLayout = new QVBoxLayout(this);
|
||||
vLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
vLayout->setContentsMargins(10, 5, 10, 5);
|
||||
vLayout->setSpacing(10);
|
||||
this->vLayout_ = vLayout;
|
||||
}
|
||||
|
||||
void TooltipWidget::initializeGLayout()
|
||||
{
|
||||
auto *gLayout = new QGridLayout(this);
|
||||
gLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
gLayout->setContentsMargins(10, 5, 10, 5);
|
||||
gLayout->setHorizontalSpacing(8);
|
||||
gLayout->setVerticalSpacing(10);
|
||||
this->gLayout_ = gLayout;
|
||||
}
|
||||
|
||||
void TooltipWidget::themeChangedEvent()
|
||||
{
|
||||
// this->setStyleSheet("color: #fff; background: #000");
|
||||
@@ -90,49 +277,26 @@ void TooltipWidget::updateFont()
|
||||
getFonts()->getFont(FontStyle::ChatMediumSmall, this->scale()));
|
||||
}
|
||||
|
||||
void TooltipWidget::setText(QString text)
|
||||
{
|
||||
this->displayText_->setText(text);
|
||||
}
|
||||
|
||||
void TooltipWidget::setWordWrap(bool wrap)
|
||||
{
|
||||
this->displayText_->setWordWrap(wrap);
|
||||
}
|
||||
|
||||
void TooltipWidget::clearImage()
|
||||
{
|
||||
this->displayImage_->hide();
|
||||
this->image_ = nullptr;
|
||||
this->setImageScale(0, 0);
|
||||
}
|
||||
|
||||
void TooltipWidget::setImage(ImagePtr image)
|
||||
{
|
||||
if (this->image_ == image)
|
||||
for (int i = 0; i < this->visibleEntries_; ++i)
|
||||
{
|
||||
return;
|
||||
auto entry = this->entryAt(i);
|
||||
if (entry)
|
||||
{
|
||||
entry->setWordWrap(wrap);
|
||||
}
|
||||
}
|
||||
// hide image until loaded and reset scale
|
||||
this->clearImage();
|
||||
this->image_ = std::move(image);
|
||||
this->refreshPixmap();
|
||||
}
|
||||
|
||||
void TooltipWidget::setImageScale(int w, int h)
|
||||
void TooltipWidget::clearEntries()
|
||||
{
|
||||
if (this->customImgWidth == w && this->customImgHeight == h)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->customImgWidth = w;
|
||||
this->customImgHeight = h;
|
||||
this->refreshPixmap();
|
||||
this->setVisibleEntries(0);
|
||||
}
|
||||
|
||||
void TooltipWidget::hideEvent(QHideEvent *)
|
||||
{
|
||||
this->clearImage();
|
||||
this->clearEntries();
|
||||
}
|
||||
|
||||
void TooltipWidget::showEvent(QShowEvent *)
|
||||
@@ -140,34 +304,6 @@ 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();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TooltipWidget::changeEvent(QEvent *)
|
||||
{
|
||||
// clear parents event
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
#include "widgets/TooltipEntryWidget.hpp"
|
||||
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
namespace chatterino {
|
||||
@@ -11,6 +15,15 @@ namespace chatterino {
|
||||
class Image;
|
||||
using ImagePtr = std::shared_ptr<Image>;
|
||||
|
||||
struct TooltipEntry {
|
||||
ImagePtr image;
|
||||
QString text;
|
||||
int customWidth = 0;
|
||||
int customHeight = 0;
|
||||
};
|
||||
|
||||
enum class TooltipStyle { Vertical, Grid };
|
||||
|
||||
class TooltipWidget : public BaseWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -21,11 +34,13 @@ public:
|
||||
TooltipWidget(BaseWidget *parent = nullptr);
|
||||
~TooltipWidget() override = default;
|
||||
|
||||
void setText(QString text);
|
||||
void setOne(const TooltipEntry &entry,
|
||||
TooltipStyle style = TooltipStyle::Vertical);
|
||||
void set(const std::vector<TooltipEntry> &entries,
|
||||
TooltipStyle style = TooltipStyle::Vertical);
|
||||
|
||||
void setWordWrap(bool wrap);
|
||||
void clearImage();
|
||||
void setImage(ImagePtr image);
|
||||
void setImageScale(int w, int h);
|
||||
void clearEntries();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *) override;
|
||||
@@ -39,17 +54,24 @@ protected:
|
||||
private:
|
||||
void updateFont();
|
||||
|
||||
// used by WindowManager::gifRepaintRequested signal to progress frames when tooltip image is animated
|
||||
bool refreshPixmap();
|
||||
QLayout *currentLayout() const;
|
||||
int currentLayoutCount() const;
|
||||
TooltipEntryWidget *entryAt(int n);
|
||||
|
||||
// set to true when tooltip image did not finish loading yet (pixmapOrLoad returned false)
|
||||
bool attemptRefresh{false};
|
||||
void setVisibleEntries(int n);
|
||||
void setCurrentStyle(TooltipStyle style);
|
||||
void addNewEntry(int absoluteIndex);
|
||||
|
||||
void deleteCurrentLayout();
|
||||
void initializeVLayout();
|
||||
void initializeGLayout();
|
||||
|
||||
int visibleEntries_ = 0;
|
||||
|
||||
TooltipStyle currentStyle_;
|
||||
QVBoxLayout *vLayout_;
|
||||
QGridLayout *gLayout_;
|
||||
|
||||
ImagePtr image_ = nullptr;
|
||||
int customImgWidth = 0;
|
||||
int customImgHeight = 0;
|
||||
QLabel *displayImage_;
|
||||
QLabel *displayText_;
|
||||
pajlada::Signals::SignalHolder connections_;
|
||||
};
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
#define DRAW_WIDTH (this->width())
|
||||
#define SELECTION_RESUME_SCROLLING_MSG_THRESHOLD 3
|
||||
#define CHAT_HOVER_PAUSE_DURATION 1000
|
||||
#define TOOLTIP_EMOTE_ENTRIES_LIMIT 7
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
@@ -1658,10 +1659,12 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
auto element = &hoverLayoutElement->getCreator();
|
||||
bool isLinkValid = hoverLayoutElement->getLink().isValid();
|
||||
auto emoteElement = dynamic_cast<const EmoteElement *>(element);
|
||||
auto layeredEmoteElement =
|
||||
dynamic_cast<const LayeredEmoteElement *>(element);
|
||||
bool isNotEmote = emoteElement == nullptr && layeredEmoteElement == nullptr;
|
||||
|
||||
if (element->getTooltip().isEmpty() ||
|
||||
(isLinkValid && emoteElement == nullptr &&
|
||||
!getSettings()->linkInfoTooltip))
|
||||
(isLinkValid && isNotEmote && !getSettings()->linkInfoTooltip))
|
||||
{
|
||||
tooltipWidget->hide();
|
||||
}
|
||||
@@ -1669,7 +1672,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
auto badgeElement = dynamic_cast<const BadgeElement *>(element);
|
||||
|
||||
if ((badgeElement || emoteElement) &&
|
||||
if ((badgeElement || emoteElement || layeredEmoteElement) &&
|
||||
getSettings()->emotesTooltipPreview.getValue())
|
||||
{
|
||||
if (event->modifiers() == Qt::ShiftModifier ||
|
||||
@@ -1677,18 +1680,73 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (emoteElement)
|
||||
{
|
||||
tooltipWidget->setImage(
|
||||
emoteElement->getEmote()->images.getImage(3.0));
|
||||
tooltipWidget->setOne({
|
||||
emoteElement->getEmote()->images.getImage(3.0),
|
||||
element->getTooltip(),
|
||||
});
|
||||
}
|
||||
else if (layeredEmoteElement)
|
||||
{
|
||||
auto &layeredEmotes = layeredEmoteElement->getEmotes();
|
||||
// Should never be empty but ensure it
|
||||
if (!layeredEmotes.empty())
|
||||
{
|
||||
std::vector<TooltipEntry> entries;
|
||||
entries.reserve(layeredEmotes.size());
|
||||
|
||||
auto &emoteTooltips =
|
||||
layeredEmoteElement->getEmoteTooltips();
|
||||
|
||||
// Someone performing some tomfoolery could put an emote with tens,
|
||||
// if not hundreds of zero-width emotes on a single emote. If the
|
||||
// tooltip may take up more than three rows, truncate everything else.
|
||||
bool truncating = false;
|
||||
size_t upperLimit = layeredEmotes.size();
|
||||
if (layeredEmotes.size() > TOOLTIP_EMOTE_ENTRIES_LIMIT)
|
||||
{
|
||||
upperLimit = TOOLTIP_EMOTE_ENTRIES_LIMIT - 1;
|
||||
truncating = true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < upperLimit; ++i)
|
||||
{
|
||||
auto &emote = layeredEmotes[i];
|
||||
if (i == 0)
|
||||
{
|
||||
// First entry gets a large image and full description
|
||||
entries.push_back({emote->images.getImage(3.0),
|
||||
emoteTooltips[i]});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Every other entry gets a small image and just the emote name
|
||||
entries.push_back({emote->images.getImage(1.0),
|
||||
emote->name.string});
|
||||
}
|
||||
}
|
||||
|
||||
if (truncating)
|
||||
{
|
||||
entries.push_back({nullptr, "..."});
|
||||
}
|
||||
|
||||
auto style = layeredEmotes.size() > 2
|
||||
? TooltipStyle::Grid
|
||||
: TooltipStyle::Vertical;
|
||||
tooltipWidget->set(entries, style);
|
||||
}
|
||||
}
|
||||
else if (badgeElement)
|
||||
{
|
||||
tooltipWidget->setImage(
|
||||
badgeElement->getEmote()->images.getImage(3.0));
|
||||
tooltipWidget->setOne({
|
||||
badgeElement->getEmote()->images.getImage(3.0),
|
||||
element->getTooltip(),
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltipWidget->clearImage();
|
||||
tooltipWidget->clearEntries();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1711,7 +1769,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
auto thumbnailSize = getSettings()->thumbnailSize;
|
||||
if (!thumbnailSize)
|
||||
{
|
||||
tooltipWidget->clearImage();
|
||||
tooltipWidget->clearEntries();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1724,19 +1782,23 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||
shouldHideThumbnail
|
||||
? Image::fromResourcePixmap(getResources().streamerMode)
|
||||
: element->getThumbnail();
|
||||
tooltipWidget->setImage(std::move(thumb));
|
||||
|
||||
if (element->getThumbnailType() ==
|
||||
MessageElement::ThumbnailType::Link_Thumbnail)
|
||||
{
|
||||
tooltipWidget->setImageScale(thumbnailSize, thumbnailSize);
|
||||
tooltipWidget->setOne({std::move(thumb),
|
||||
element->getTooltip(), thumbnailSize,
|
||||
thumbnailSize});
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltipWidget->setOne({std::move(thumb), ""});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tooltipWidget->moveTo(this, event->globalPos());
|
||||
tooltipWidget->setWordWrap(isLinkValid);
|
||||
tooltipWidget->setText(element->getTooltip());
|
||||
tooltipWidget->show();
|
||||
}
|
||||
|
||||
@@ -2134,6 +2196,18 @@ void ChannelView::addImageContextMenuItems(
|
||||
addEmoteContextMenuItems(*emoteElement->getEmote(), creatorFlags,
|
||||
menu);
|
||||
}
|
||||
else if (auto layeredElement =
|
||||
dynamic_cast<const LayeredEmoteElement *>(&creator))
|
||||
{
|
||||
// Give each emote its own submenu
|
||||
for (auto &emote : layeredElement->getUniqueEmotes())
|
||||
{
|
||||
auto emoteAction = menu.addAction(emote->name.string);
|
||||
auto emoteMenu = new QMenu(&menu);
|
||||
emoteAction->setMenu(emoteMenu);
|
||||
addEmoteContextMenuItems(*emote, creatorFlags, *emoteMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add seperator
|
||||
|
||||
@@ -374,6 +374,10 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||
layout.addCheckbox("Animate", s.animateEmotes);
|
||||
layout.addCheckbox("Animate only when Chatterino is focused",
|
||||
s.animationsWhenFocused);
|
||||
layout.addCheckbox(
|
||||
"Enable zero-width emotes", s.enableZeroWidthEmotes,
|
||||
"When disabled, emotes that overlap other emotes, such as BTTV's "
|
||||
"cvMask and 7TV's RainTime, will appear as normal emotes.");
|
||||
layout.addCheckbox("Enable emote auto-completion by typing :",
|
||||
s.emoteCompletionWithColon);
|
||||
layout.addDropdown<float>(
|
||||
|
||||
@@ -960,8 +960,7 @@ void SplitHeader::enterEvent(QEvent *event)
|
||||
}
|
||||
|
||||
auto *tooltip = TooltipWidget::instance();
|
||||
tooltip->clearImage();
|
||||
tooltip->setText(this->tooltipText_);
|
||||
tooltip->setOne({nullptr, this->tooltipText_});
|
||||
tooltip->setWordWrap(true);
|
||||
tooltip->adjustSize();
|
||||
auto pos = this->mapToGlobal(this->rect().bottomLeft()) +
|
||||
|
||||
Reference in New Issue
Block a user