#include "inputbar.h" #include "emojipanel.h" #include "debug_ui.h" #include #include #include #include #include #include #include #include #include #include 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; } static QWidget *wrapBottomBtn(QPushButton *btn, int pad) { auto *w = new QWidget(btn->parentWidget()); auto *l = new QVBoxLayout(w); l->setContentsMargins(0, 0, 0, 0); l->setSpacing(0); l->addWidget(btn); l->addSpacing(pad); return w; } 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(wrapBottomBtn(attachBtn, 3), 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(wrapBottomBtn(m_emojiBtn, 3), 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(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(); GUI_INFO("send: len=%d hasLF=%d text='%s'", text.length(), text.contains('\n'), qPrintable(text)); while (!text.isEmpty() && (text.back() == ' ' || text.back() == '\t')) text.chop(1); if (text.isEmpty()) return; emit sendMessage(text); m_input->clear(); if (m_emojiPanel) m_emojiPanel->hide(); m_input->setFocus(); }