tools/chatgui: input bar with emoji panel, custom tab bar, Ctrl+Enter multiline, scroll fixes
This commit is contained in:
1 parent
b667d6f352
commit
e50ca9978e
11 files changed
+521
-23
No files matched your search
@@ -0,0 +1,125 @@
|
||||
#include "inputbar.h"
|
||||
#include "emojipanel.h"
|
||||
#include <QTextEdit>
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QDebug>
|
||||
#include <QKeyEvent>
|
||||
#include <QFontMetrics>
|
||||
#include <QScrollBar>
|
||||
#include <QApplication>
|
||||
|
||||
static QPushButton *makeIconBtn(const QString &text, const QString &tooltip, QWidget *parent) {
|
||||
auto *btn = new QPushButton(text, parent);
|
||||
btn->setFixedSize(34, 34);
|
||||
btn->setCursor(Qt::PointingHandCursor);
|
||||
btn->setToolTip(tooltip);
|
||||
btn->setStyleSheet(
|
||||
"QPushButton { border: none; border-radius: 4px; font-size: 18px; background: transparent; }"
|
||||
"QPushButton:hover { background: palette(light); }"
|
||||
);
|
||||
return btn;
|
||||
}
|
||||
|
||||
InputBar::InputBar(EmojiPanel *emojiPanel, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_input(new QTextEdit(this))
|
||||
, m_emojiBtn(nullptr)
|
||||
, m_emojiPanel(emojiPanel)
|
||||
{
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(8, 4, 8, 4);
|
||||
layout->setSpacing(4);
|
||||
|
||||
auto *attachBtn = makeIconBtn(QString::fromUtf8("\xF0\x9F\x93\x8E"),
|
||||
QString::fromUtf8("Прикрепить"), this);
|
||||
connect(attachBtn, &QPushButton::clicked, this, [this]() {
|
||||
QString path = QFileDialog::getOpenFileName(this, QString::fromUtf8("Прикрепить файл"));
|
||||
if (!path.isEmpty()) {
|
||||
qDebug() << "Attached:" << path;
|
||||
}
|
||||
});
|
||||
layout->addWidget(attachBtn, 0, Qt::AlignBottom);
|
||||
|
||||
m_input->setAcceptRichText(false);
|
||||
m_input->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_input->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_input->setTabChangesFocus(true);
|
||||
m_input->setStyleSheet(
|
||||
"QTextEdit { border: 1px solid palette(mid); border-radius: 6px;"
|
||||
" padding: 4px 8px; background: palette(base); }"
|
||||
);
|
||||
m_input->installEventFilter(this);
|
||||
QFontMetrics fm(m_input->font());
|
||||
m_input->setFixedHeight(fm.lineSpacing() + 12);
|
||||
layout->addWidget(m_input, 1);
|
||||
|
||||
m_emojiBtn = makeIconBtn(QString::fromUtf8("\xF0\x9F\x99\x82"),
|
||||
QString::fromUtf8("Смайлики"), this);
|
||||
layout->addWidget(m_emojiBtn, 0, Qt::AlignBottom);
|
||||
|
||||
auto *sendBtn = makeIconBtn(QString::fromUtf8("\xE2\x9E\xA4"),
|
||||
QString::fromUtf8("Отправить"), this);
|
||||
sendBtn->setStyleSheet(sendBtn->styleSheet() +
|
||||
"QPushButton { color: palette(highlight); font-weight: bold; }");
|
||||
layout->addWidget(sendBtn, 0, Qt::AlignBottom);
|
||||
|
||||
connect(m_input, &QTextEdit::textChanged, this, &InputBar::adjustInputHeight);
|
||||
connect(sendBtn, &QPushButton::clicked, this, &InputBar::onSendClicked);
|
||||
|
||||
if (m_emojiPanel) {
|
||||
connect(m_emojiBtn, &QPushButton::clicked, this, [this]() {
|
||||
m_emojiPanel->setVisible(!m_emojiPanel->isVisible());
|
||||
});
|
||||
connect(m_emojiPanel, &EmojiPanel::emojiSelected, this, [this](const QString &emoji) {
|
||||
m_input->insertPlainText(emoji);
|
||||
m_input->setFocus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool InputBar::eventFilter(QObject *obj, QEvent *event) {
|
||||
if (obj == m_input && event->type() == QEvent::KeyPress) {
|
||||
auto *ke = static_cast<QKeyEvent *>(event);
|
||||
if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) {
|
||||
if (ke->modifiers() & Qt::ControlModifier) {
|
||||
m_input->insertPlainText("\n");
|
||||
return true;
|
||||
} else {
|
||||
onSendClicked();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void InputBar::adjustInputHeight() {
|
||||
m_input->document()->adjustSize();
|
||||
|
||||
int lineSpacing = m_input->fontMetrics().lineSpacing();
|
||||
int docH = (int)m_input->document()->size().height() + 12;
|
||||
int maxH = 12 * lineSpacing + 12;
|
||||
int h = qBound(lineSpacing + 12, docH, maxH);
|
||||
m_input->setFixedHeight(h);
|
||||
|
||||
bool needScroll = docH > maxH;
|
||||
m_input->setVerticalScrollBarPolicy(needScroll ? Qt::ScrollBarAlwaysOn
|
||||
: Qt::ScrollBarAlwaysOff);
|
||||
if (needScroll) {
|
||||
QTextCursor c = m_input->textCursor();
|
||||
if (c.atEnd())
|
||||
m_input->verticalScrollBar()->setValue(m_input->verticalScrollBar()->maximum());
|
||||
else
|
||||
m_input->ensureCursorVisible();
|
||||
}
|
||||
}
|
||||
|
||||
void InputBar::onSendClicked() {
|
||||
QString text = m_input->toPlainText().trimmed();
|
||||
if (text.isEmpty()) return;
|
||||
emit sendMessage(text);
|
||||
m_input->clear();
|
||||
if (m_emojiPanel) m_emojiPanel->hide();
|
||||
}
|
||||
Reference in new issue
Block a user