You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.7 KiB
158 lines
4.7 KiB
#include "emojipanel.h" |
|
#include "emoji.h" |
|
#include "emojitabbar.h" |
|
#include "animtimer.h" |
|
#include "lottieicon.h" |
|
#include <QPushButton> |
|
#include <QScrollArea> |
|
#include <QTabWidget> |
|
#include <QGridLayout> |
|
#include <QHBoxLayout> |
|
#include <QVBoxLayout> |
|
#include <QPainter> |
|
#include <QTimer> |
|
|
|
namespace { |
|
|
|
class EmojiTabWidget : public QTabWidget { |
|
public: |
|
using QTabWidget::setTabBar; |
|
}; |
|
|
|
class EmojiButton : public QPushButton { |
|
public: |
|
EmojiButton(const EmojiData &data, QWidget *parent = nullptr) |
|
: QPushButton(data.unicode, parent) |
|
, m_data(data) |
|
{ |
|
setFixedSize(32, 32); |
|
setCursor(Qt::PointingHandCursor); |
|
setStyleSheet( |
|
"QPushButton { border: none; border-radius: 4px; font-size: 18px; background: transparent; }" |
|
"QPushButton:hover { background: rgba(0,0,0,0.08); }" |
|
); |
|
if (data.type == EmojiType::Animation) { |
|
setMouseTracking(true); |
|
m_icon = AnimTimer::instance()->icon(data.animPath); |
|
m_timer.setInterval(33); |
|
connect(&m_timer, &QTimer::timeout, this, [this]() { |
|
if (m_icon && m_icon->isValid()) { |
|
m_frame = (m_frame + 1) % m_icon->frameCount(); |
|
update(); |
|
} |
|
}); |
|
} |
|
} |
|
const QString &unicode() const { return m_data.unicode; } |
|
|
|
protected: |
|
void enterEvent(QEvent *e) override { |
|
QPushButton::enterEvent(e); |
|
if (m_icon && m_icon->isValid()) { |
|
m_hovered = true; |
|
m_frame = 0; |
|
m_timer.start(); |
|
} |
|
} |
|
void leaveEvent(QEvent *e) override { |
|
QPushButton::leaveEvent(e); |
|
m_hovered = false; |
|
m_timer.stop(); |
|
update(); |
|
} |
|
void paintEvent(QPaintEvent *e) override { |
|
if (m_hovered && m_icon && m_icon->isValid()) { |
|
QPainter p(this); |
|
p.setRenderHint(QPainter::SmoothPixmapTransform); |
|
int sz = qMin(width(), height()) - 4; |
|
QImage frame = m_icon->renderFrame(m_frame, QSize(sz, sz)); |
|
int x = (width() - sz) / 2, y = (height() - sz) / 2; |
|
p.drawImage(x, y, frame); |
|
} else { |
|
QPushButton::paintEvent(e); |
|
} |
|
} |
|
|
|
private: |
|
EmojiData m_data; |
|
LottieIcon *m_icon = nullptr; |
|
QTimer m_timer; |
|
int m_frame = 0; |
|
bool m_hovered = false; |
|
}; |
|
|
|
} // namespace |
|
|
|
EmojiPanel::EmojiPanel(QWidget *parent) |
|
: QWidget(parent) |
|
{ |
|
setStyleSheet("EmojiPanel { background: palette(window); }"); |
|
buildPanel(builtinEmojiSet()); |
|
hide(); |
|
} |
|
|
|
void EmojiPanel::showEvent(QShowEvent *event) { |
|
if (parentWidget()) { |
|
setFixedHeight(qBound(200, parentWidget()->height() * 3 / 10, 800)); |
|
} |
|
QWidget::showEvent(event); |
|
} |
|
|
|
void EmojiPanel::buildPanel(const QVector<EmojiCategory> &categories) { |
|
auto *tabs = new EmojiTabWidget(); |
|
tabs->setDocumentMode(true); |
|
tabs->setTabBar(new EmojiTabBar(tabs)); |
|
tabs->setStyleSheet("QTabWidget::pane { border: none; background: rgba(255,255,255,0.6); }"); |
|
|
|
for (const auto &cat : categories) { |
|
tabs->addTab(buildCategoryPage(cat), cat.name); |
|
} |
|
|
|
auto *layout = new QVBoxLayout(this); |
|
layout->setContentsMargins(0, 0, 0, 0); |
|
layout->setSpacing(0); |
|
layout->addWidget(tabs); |
|
} |
|
|
|
QWidget *EmojiPanel::buildCategoryPage(const EmojiCategory &cat) { |
|
auto *scroll = new QScrollArea(); |
|
scroll->setWidgetResizable(true); |
|
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
scroll->setStyleSheet("QScrollArea { border: none; }"); |
|
|
|
auto *container = new QWidget(); |
|
auto *grid = new QGridLayout(container); |
|
grid->setContentsMargins(4, 4, 4, 4); |
|
grid->setSpacing(2); |
|
|
|
int cols = 9; |
|
for (int i = 0; i < cat.items.size(); ++i) { |
|
const auto &e = cat.items[i]; |
|
QPushButton *btn; |
|
if (e.type == EmojiType::Animation) |
|
btn = new EmojiButton(e, container); |
|
else { |
|
btn = new QPushButton(e.unicode, container); |
|
btn->setFixedSize(32, 32); |
|
btn->setCursor(Qt::PointingHandCursor); |
|
btn->setStyleSheet( |
|
"QPushButton { border: none; border-radius: 4px; font-size: 18px; background: transparent; }" |
|
"QPushButton:hover { background: rgba(0,0,0,0.08); }" |
|
); |
|
} |
|
btn->setToolTip(e.shortcode); |
|
connect(btn, &QPushButton::clicked, this, &EmojiPanel::onEmojiClicked); |
|
grid->addWidget(btn, i / cols, i % cols); |
|
} |
|
grid->setRowStretch(grid->rowCount(), 1); |
|
|
|
scroll->setWidget(container); |
|
return scroll; |
|
} |
|
|
|
void EmojiPanel::onEmojiClicked() { |
|
auto *btn = qobject_cast<QPushButton *>(sender()); |
|
if (!btn) return; |
|
auto *eb = dynamic_cast<EmojiButton *>(btn); |
|
emit emojiSelected(eb ? eb->unicode() : btn->text()); |
|
}
|
|
|