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.
142 lines
5.0 KiB
142 lines
5.0 KiB
#include "inputbar.h" |
|
#include "emojipanel.h" |
|
#include "debug_ui.h" |
|
#include <QDebug> |
|
#include <QTextEdit> |
|
#include <QPushButton> |
|
#include <QHBoxLayout> |
|
#include <QVBoxLayout> |
|
#include <QFileDialog> |
|
#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; |
|
} |
|
|
|
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<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(); |
|
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(); |
|
}
|
|
|