stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
This commit is contained in:
1 parent
a3783b5f55
commit
38c9f229bc
1272 files changed
+968388
-1
No files matched your search
@@ -0,0 +1,162 @@
|
||||
#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:
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
void enterEvent(QEnterEvent *e) override {
|
||||
#else
|
||||
void enterEvent(QEvent *e) override {
|
||||
#endif
|
||||
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());
|
||||
}
|
||||
Reference in new issue
Block a user