Allow attaching length limit to InputField.

This commit is contained in:
John Preston 2024-05-24 09:37:18 +04:00
parent 037ceb272c
commit b0e408e53d
3 changed files with 59 additions and 5 deletions

View file

@ -6,8 +6,9 @@
//
#include "ui/widgets/fields/input_field.h"
#include "ui/widgets/popup_menu.h"
#include "ui/text/text.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/popup_menu.h"
#include "ui/emoji_config.h"
#include "ui/ui_utility.h"
#include "ui/painter.h"
@ -134,7 +135,7 @@ bool IsNewline(QChar ch) {
}
[[nodiscard]] bool IsCustomEmojiLink(QStringView link) {
return link.startsWith(Ui::InputField::kCustomEmojiTagStart);
return link.startsWith(InputField::kCustomEmojiTagStart);
}
[[nodiscard]] QString MakeUniqueCustomEmojiLink(QStringView link) {
@ -153,7 +154,7 @@ bool IsNewline(QChar ch) {
}
[[nodiscard]] uint64 CustomEmojiIdFromLink(QStringView link) {
const auto skip = Ui::InputField::kCustomEmojiTagStart.size();
const auto skip = InputField::kCustomEmojiTagStart.size();
const auto index = link.indexOf('?', skip + 1);
return base::StringViewMid(
link,
@ -1131,7 +1132,7 @@ QSizeF CustomEmojiObject::intrinsicSize(
const auto width = size + st::emojiPadding * 2.;
const auto height = std::max(_font->height * 1., size);
if (!_skip) {
const auto emoji = Ui::Text::AdjustCustomEmojiSize(st::emojiSize);
const auto emoji = Text::AdjustCustomEmojiSize(st::emojiSize);
_skip = (st::emojiSize - emoji) / 2;
}
return { width, height };
@ -3190,7 +3191,7 @@ void InputField::inputMethodEventInner(QInputMethodEvent *e) {
}
_inputMethodCommit = e->commitString();
const auto weak = Ui::MakeWeak(this);
const auto weak = MakeWeak(this);
_inner->QTextEdit::inputMethodEvent(e);
if (weak && _inputMethodCommit.has_value()) {
@ -4066,4 +4067,52 @@ int FieldCharacterCount(not_null<InputField*> field) {
return field->lastTextSizeWithoutSurrogatePairsCount();
}
void AddLengthLimitLabel(not_null<InputField*> field, int limit) {
struct State {
rpl::variable<int> length;
};
const auto state = field->lifetime().make_state<State>();
state->length = rpl::single(
rpl::empty
) | rpl::then(field->changes()) | rpl::map([=] {
return int(field->getLastText().size());
});
const auto allowExceed = std::max(limit / 2, 9);
field->setMaxLength(limit + allowExceed);
const auto threshold = std::min(limit / 2, 9);
auto warningText = state->length.value() | rpl::map([=](int count) {
const auto left = limit - count;
return (left < threshold) ? QString::number(left) : QString();
});
const auto warning = CreateChild<FlatLabel>(
field.get(),
std::move(warningText),
st::defaultInputFieldLimit);
const auto maxSize = st::defaultInputFieldLimit.style.font->width(
QString::number(-allowExceed));
const auto add = std::max(maxSize - field->st().textMargins.right(), 0);
if (add) {
field->setAdditionalMargins({ 0, 0, add, 0 });
}
state->length.value() | rpl::map(
rpl::mappers::_1 > limit
) | rpl::start_with_next([=](bool exceeded) {
warning->setTextColorOverride(exceeded
? st::attentionButtonFg->c
: std::optional<QColor>());
}, warning->lifetime());
rpl::combine(
field->sizeValue(),
warning->sizeValue()
) | rpl::start_with_next([=] {
// Baseline alignment.
const auto top = field->st().textMargins.top()
+ field->st().font->ascent
- st::defaultInputFieldLimit.style.font->ascent;
warning->moveToRight(0, top);
}, warning->lifetime());
warning->setAttribute(Qt::WA_TransparentForMouseEvents);
}
} // namespace Ui

View file

@ -586,4 +586,6 @@ void PrepareFormattingOptimization(not_null<QTextDocument*> document);
[[nodiscard]] int FieldCharacterCount(not_null<InputField*> field);
void AddLengthLimitLabel(not_null<InputField*> field, int limit);
} // namespace Ui

View file

@ -910,6 +910,9 @@ defaultInputField: InputField {
heightMin: 55px;
heightMax: 148px;
}
defaultInputFieldLimit: FlatLabel(defaultFlatLabel) {
textFg: windowSubTextFg;
}
defaultIconButton: IconButton {
iconPosition: point(-1px, -1px);