mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-06 11:52:58 +00:00
Move many widget classes to lib_ui.
This commit is contained in:
@@ -8,21 +8,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/input_fields.h"
|
||||
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/countryinput.h"
|
||||
#include "ui/text/text.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "chat_helpers/emoji_suggestions_helper.h"
|
||||
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities
|
||||
#include "platform/platform_info.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_countries.h" // Data::ValidPhoneCode
|
||||
#include "mainwindow.h"
|
||||
#include "numbers.h"
|
||||
#include "main/main_session.h"
|
||||
#include "core/application.h"
|
||||
#include "app.h"
|
||||
|
||||
#include <QtWidgets/QCommonStyle>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
@@ -31,11 +22,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <QtGui/QTextBlock>
|
||||
#include <QtGui/QTextDocumentFragment>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxUsernameLength = 32;
|
||||
constexpr auto kInstantReplaceRandomId = QTextFormat::UserProperty;
|
||||
constexpr auto kInstantReplaceWhatId = QTextFormat::UserProperty + 1;
|
||||
constexpr auto kInstantReplaceWithId = QTextFormat::UserProperty + 2;
|
||||
@@ -74,7 +65,7 @@ private:
|
||||
InputDocument::InputDocument(QObject *parent, const style::InputField &st)
|
||||
: QTextDocument(parent)
|
||||
, _st(st) {
|
||||
Ui::Emoji::Updated(
|
||||
Emoji::Updated(
|
||||
) | rpl::start_with_next([=] {
|
||||
_emojiCache.clear();
|
||||
}, _lifetime);
|
||||
@@ -90,11 +81,11 @@ QVariant InputDocument::loadResource(int type, const QUrl &name) {
|
||||
return i->second;
|
||||
}
|
||||
auto result = [&] {
|
||||
if (const auto emoji = Ui::Emoji::FromUrl(name.toDisplayString())) {
|
||||
if (const auto emoji = Emoji::FromUrl(name.toDisplayString())) {
|
||||
const auto height = std::max(
|
||||
_st.font->height * cIntRetinaFactor(),
|
||||
Ui::Emoji::GetSizeNormal());
|
||||
return QVariant(Ui::Emoji::SinglePixmap(emoji, height));
|
||||
_st.font->height * style::DevicePixelRatio(),
|
||||
Emoji::GetSizeNormal());
|
||||
return QVariant(Emoji::SinglePixmap(emoji, height));
|
||||
}
|
||||
return QVariant();
|
||||
}();
|
||||
@@ -624,8 +615,8 @@ QString AccumulateText(Iterator begin, Iterator end) {
|
||||
}
|
||||
|
||||
QTextImageFormat PrepareEmojiFormat(EmojiPtr emoji, const QFont &font) {
|
||||
const auto factor = cIntRetinaFactor();
|
||||
const auto size = Ui::Emoji::GetSizeNormal();
|
||||
const auto factor = style::DevicePixelRatio();
|
||||
const auto size = Emoji::GetSizeNormal();
|
||||
const auto width = size + st::emojiPadding * factor * 2;
|
||||
const auto height = std::max(QFontMetrics(font).height() * factor, size);
|
||||
auto result = QTextImageFormat();
|
||||
@@ -702,7 +693,7 @@ QTextCharFormat PrepareTagFormat(
|
||||
result.setFont(st.font->strikeout());
|
||||
} else if (tag == kTagCode || tag == kTagPre) {
|
||||
result.setForeground(st::defaultTextPalette.monoFg);
|
||||
result.setFont(AdjustFont(App::monofont(), st.font));
|
||||
result.setFont(AdjustFont(style::MonospaceFont(), st.font));
|
||||
} else {
|
||||
result.setForeground(st.textFg);
|
||||
result.setFont(st.font);
|
||||
@@ -816,42 +807,16 @@ struct FormattingAction {
|
||||
|
||||
};
|
||||
|
||||
QString ExpandCustomLinks(const TextWithTags &text) {
|
||||
const auto entities = ConvertTextTagsToEntities(text.tags);
|
||||
auto &&urls = ranges::make_iterator_range(
|
||||
entities.begin(),
|
||||
entities.end()
|
||||
) | ranges::view::filter([](const EntityInText &entity) {
|
||||
return entity.type() == EntityType::CustomUrl;
|
||||
});
|
||||
const auto &original = text.text;
|
||||
if (urls.begin() == urls.end()) {
|
||||
return original;
|
||||
}
|
||||
auto result = QString();
|
||||
auto offset = 0;
|
||||
for (const auto &entity : urls) {
|
||||
const auto till = entity.offset() + entity.length();
|
||||
if (till > offset) {
|
||||
result.append(original.midRef(offset, till - offset));
|
||||
}
|
||||
result.append(qstr(" (")).append(entity.data()).append(')');
|
||||
offset = till;
|
||||
}
|
||||
if (original.size() > offset) {
|
||||
result.append(original.midRef(offset));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const QString InputField::kTagBold = qsl("**");
|
||||
const QString InputField::kTagItalic = qsl("__");
|
||||
const QString InputField::kTagUnderline = qsl("^^"); // Not for Markdown.
|
||||
const QString InputField::kTagStrikeOut = qsl("~~");
|
||||
const QString InputField::kTagCode = qsl("`");
|
||||
const QString InputField::kTagPre = qsl("```");
|
||||
// kTagUnderline is not used for Markdown.
|
||||
|
||||
const QString InputField::kTagBold = QStringLiteral("**");
|
||||
const QString InputField::kTagItalic = QStringLiteral("__");
|
||||
const QString InputField::kTagUnderline = QStringLiteral("^^");
|
||||
const QString InputField::kTagStrikeOut = QStringLiteral("~~");
|
||||
const QString InputField::kTagCode = QStringLiteral("`");
|
||||
const QString InputField::kTagPre = QStringLiteral("```");
|
||||
|
||||
class InputField::Inner final : public QTextEdit {
|
||||
public:
|
||||
@@ -979,16 +944,17 @@ FlatInput::FlatInput(
|
||||
refreshPlaceholder(text);
|
||||
}, lifetime());
|
||||
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
updatePalette();
|
||||
}
|
||||
});
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
updatePalette();
|
||||
}, lifetime());
|
||||
updatePalette();
|
||||
|
||||
connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(onTextChange(const QString &)));
|
||||
connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited()));
|
||||
if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
|
||||
connect(this, &FlatInput::selectionChanged, [] {
|
||||
Integration::Instance().textActionsUpdated();
|
||||
});
|
||||
|
||||
setStyle(InputStyle<FlatInput>::instance());
|
||||
QLineEdit::setTextMargins(0, 0, 0, 0);
|
||||
@@ -1168,7 +1134,7 @@ void FlatInput::refreshPlaceholder(const QString &text) {
|
||||
|
||||
void FlatInput::contextMenuEvent(QContextMenuEvent *e) {
|
||||
if (auto menu = createStandardContextMenu()) {
|
||||
(new Ui::PopupMenu(this, menu))->popup(e->globalPos());
|
||||
(new PopupMenu(this, menu))->popup(e->globalPos());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1214,7 +1180,7 @@ QRect FlatInput::placeholderRect() const {
|
||||
void FlatInput::correctValue(const QString &was, QString &now) {
|
||||
}
|
||||
|
||||
void FlatInput::phPrepare(Painter &p, float64 placeholderFocused) {
|
||||
void FlatInput::phPrepare(QPainter &p, float64 placeholderFocused) {
|
||||
p.setFont(_st.font);
|
||||
p.setPen(anim::pen(_st.phColor, _st.phFocusColor, placeholderFocused));
|
||||
}
|
||||
@@ -1257,12 +1223,12 @@ void FlatInput::onTextEdited() {
|
||||
if (wasText != _oldtext) emit changed();
|
||||
updatePlaceholder();
|
||||
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
void FlatInput::onTextChange(const QString &text) {
|
||||
_oldtext = text;
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
InputField::InputField(
|
||||
@@ -1306,7 +1272,7 @@ InputField::InputField(
|
||||
, _inner(std::make_unique<Inner>(this))
|
||||
, _lastTextWithTags(value)
|
||||
, _placeholderFull(std::move(placeholder)) {
|
||||
_inner->setDocument(Ui::CreateChild<InputDocument>(_inner.get(), _st));
|
||||
_inner->setDocument(CreateChild<InputDocument>(_inner.get(), _st));
|
||||
|
||||
_inner->setAcceptRichText(false);
|
||||
resize(_st.width, _minHeight);
|
||||
@@ -1326,12 +1292,10 @@ InputField::InputField(
|
||||
refreshPlaceholder(text);
|
||||
}, lifetime());
|
||||
|
||||
subscribe(Window::Theme::Background(), [=](
|
||||
const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
updatePalette();
|
||||
}
|
||||
});
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
updatePalette();
|
||||
}, lifetime());
|
||||
|
||||
_defaultCharFormat = _inner->textCursor().charFormat();
|
||||
updatePalette();
|
||||
@@ -1355,9 +1319,9 @@ InputField::InputField(
|
||||
connect(_inner.get(), SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool)));
|
||||
connect(_inner.get(), SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool)));
|
||||
connect(_inner.get(), SIGNAL(cursorPositionChanged()), this, SLOT(onCursorPositionChanged()));
|
||||
if (App::wnd()) {
|
||||
connect(_inner.get(), SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
|
||||
}
|
||||
connect(_inner.get(), &Inner::selectionChanged, [] {
|
||||
Integration::Instance().textActionsUpdated();
|
||||
});
|
||||
|
||||
const auto bar = _inner->verticalScrollBar();
|
||||
_scrollTop = bar->value();
|
||||
@@ -1483,7 +1447,8 @@ void InputField::setTagMimeProcessor(
|
||||
}
|
||||
|
||||
void InputField::setAdditionalMargin(int margin) {
|
||||
_inner->setStyleSheet(qsl("QTextEdit { margin: %1px; }").arg(margin));
|
||||
_inner->setStyleSheet(
|
||||
QString::fromLatin1("QTextEdit { margin: %1px; }").arg(margin));
|
||||
_additionalMargin = margin;
|
||||
checkContentHeight();
|
||||
}
|
||||
@@ -1613,7 +1578,7 @@ bool InputField::heightAutoupdated() {
|
||||
+ _st.textMargins.top()
|
||||
+ _st.textMargins.bottom()
|
||||
+ 2 * _additionalMargin;
|
||||
const auto newHeight = snap(contentHeight, _minHeight, _maxHeight);
|
||||
const auto newHeight = std::clamp(contentHeight, _minHeight, _maxHeight);
|
||||
if (height() != newHeight) {
|
||||
resize(width(), newHeight);
|
||||
return true;
|
||||
@@ -1684,7 +1649,7 @@ void InputField::paintEvent(QPaintEvent *e) {
|
||||
auto borderShownDegree = _a_borderShown.value(1.);
|
||||
auto borderOpacity = _a_borderOpacity.value(_borderVisible ? 1. : 0.);
|
||||
if (_st.borderActive && (borderOpacity > 0.)) {
|
||||
auto borderStart = snap(_borderAnimationStart, 0, width());
|
||||
auto borderStart = std::clamp(_borderAnimationStart, 0, width());
|
||||
auto borderFrom = qRound(borderStart * (1. - borderShownDegree));
|
||||
auto borderTo = borderStart + qRound((width() - borderStart) * borderShownDegree);
|
||||
if (borderTo > borderFrom) {
|
||||
@@ -1704,7 +1669,7 @@ void InputField::paintEvent(QPaintEvent *e) {
|
||||
|
||||
QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
|
||||
r.moveTop(r.top() + placeholderTop);
|
||||
if (rtl()) r.moveLeft(width() - r.left() - r.width());
|
||||
if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
|
||||
|
||||
auto placeholderScale = 1. - (1. - _st.placeholderScale) * placeholderShiftDegree;
|
||||
auto placeholderFg = anim::color(_st.placeholderFg, _st.placeholderFgActive, focusedDegree);
|
||||
@@ -1739,7 +1704,7 @@ void InputField::paintEvent(QPaintEvent *e) {
|
||||
} else {
|
||||
auto r = rect().marginsRemoved(_st.textMargins + _st.placeholderMargins);
|
||||
r.moveLeft(r.left() + placeholderLeft);
|
||||
if (rtl()) r.moveLeft(width() - r.left() - r.width());
|
||||
if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
|
||||
p.drawText(r, _placeholder, _st.placeholderAlign);
|
||||
}
|
||||
|
||||
@@ -1924,7 +1889,7 @@ QString InputField::getTextPart(
|
||||
const auto emojiText = [&] {
|
||||
if (format.isImageFormat()) {
|
||||
const auto imageName = format.toImageFormat().name();
|
||||
if (const auto emoji = Ui::Emoji::FromUrl(imageName)) {
|
||||
if (const auto emoji = Emoji::FromUrl(imageName)) {
|
||||
return emoji->text();
|
||||
}
|
||||
}
|
||||
@@ -2003,7 +1968,7 @@ bool InputField::isRedoAvailable() const {
|
||||
|
||||
void InputField::processFormatting(int insertPosition, int insertEnd) {
|
||||
// Tilde formatting.
|
||||
const auto tildeFormatting = (_st.font->f.pixelSize() * cIntRetinaFactor() == 13)
|
||||
const auto tildeFormatting = (_st.font->f.pixelSize() * style::DevicePixelRatio() == 13)
|
||||
&& (_st.font->f.family() == qstr("Open Sans"));
|
||||
auto isTildeFragment = false;
|
||||
const auto tildeFixedFont = AdjustFont(st::semiboldFont, _st.font);
|
||||
@@ -2103,7 +2068,7 @@ void InputField::processFormatting(int insertPosition, int insertEnd) {
|
||||
}
|
||||
|
||||
auto emojiLength = 0;
|
||||
if (const auto emoji = Ui::Emoji::Find(ch, textEnd, &emojiLength)) {
|
||||
if (const auto emoji = Emoji::Find(ch, textEnd, &emojiLength)) {
|
||||
// Replace emoji if no current action is prepared.
|
||||
if (action.type == ActionType::Invalid) {
|
||||
action.type = ActionType::InsertEmoji;
|
||||
@@ -2324,7 +2289,7 @@ void InputField::handleContentsChanged() {
|
||||
checkContentHeight();
|
||||
}
|
||||
startPlaceholderAnimation();
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
void InputField::highlightMarkdown() {
|
||||
@@ -2362,12 +2327,12 @@ void InputField::highlightMarkdown() {
|
||||
|
||||
void InputField::onUndoAvailable(bool avail) {
|
||||
_undoAvailable = avail;
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
void InputField::onRedoAvailable(bool avail) {
|
||||
_redoAvailable = avail;
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
void InputField::setDisplayFocused(bool focused) {
|
||||
@@ -2414,28 +2379,13 @@ void InputField::startPlaceholderAnimation() {
|
||||
}
|
||||
|
||||
QMimeData *InputField::createMimeDataFromSelectionInner() const {
|
||||
auto result = std::make_unique<QMimeData>();
|
||||
const auto cursor = _inner->textCursor();
|
||||
const auto start = cursor.selectionStart();
|
||||
const auto end = cursor.selectionEnd();
|
||||
if (end > start) {
|
||||
auto textWithTags = getTextWithTagsPart(start, end);
|
||||
result->setText(ExpandCustomLinks(textWithTags));
|
||||
if (!textWithTags.tags.isEmpty()) {
|
||||
if (_tagMimeProcessor) {
|
||||
for (auto &tag : textWithTags.tags) {
|
||||
tag.id = _tagMimeProcessor->mimeTagFromTag(tag.id);
|
||||
}
|
||||
}
|
||||
result->setData(
|
||||
TextUtilities::TagsTextMimeType(),
|
||||
textWithTags.text.toUtf8());
|
||||
result->setData(
|
||||
TextUtilities::TagsMimeType(),
|
||||
TextUtilities::SerializeTags(textWithTags.tags));
|
||||
}
|
||||
}
|
||||
return result.release();
|
||||
return TextUtilities::MimeDataFromText((end > start)
|
||||
? getTextWithTagsPart(start, end)
|
||||
: TextWithTags()
|
||||
).release();
|
||||
}
|
||||
|
||||
void InputField::customUpDown(bool isCustom) {
|
||||
@@ -3058,21 +3008,12 @@ void InputField::commitInstantReplacement(
|
||||
|
||||
auto format = [&]() -> QTextCharFormat {
|
||||
auto emojiLength = 0;
|
||||
const auto emoji = Ui::Emoji::Find(with, &emojiLength);
|
||||
const auto emoji = Emoji::Find(with, &emojiLength);
|
||||
if (!emoji || with.size() != emojiLength) {
|
||||
return _defaultCharFormat;
|
||||
}
|
||||
const auto use = [&] {
|
||||
if (!emoji->hasVariants()) {
|
||||
return emoji;
|
||||
}
|
||||
const auto nonColored = emoji->nonColoredId();
|
||||
const auto it = cEmojiVariants().constFind(nonColored);
|
||||
return (it != cEmojiVariants().cend())
|
||||
? emoji->variant(it.value())
|
||||
: emoji;
|
||||
}();
|
||||
AddRecentEmoji(use);
|
||||
const auto use = Integration::Instance().defaultEmojiVariant(
|
||||
emoji);
|
||||
return PrepareEmojiFormat(use, _st.font);
|
||||
}();
|
||||
const auto replacement = format.isImageFormat()
|
||||
@@ -3080,7 +3021,9 @@ void InputField::commitInstantReplacement(
|
||||
: with;
|
||||
format.setProperty(kInstantReplaceWhatId, original);
|
||||
format.setProperty(kInstantReplaceWithId, replacement);
|
||||
format.setProperty(kInstantReplaceRandomId, rand_value<uint32>());
|
||||
format.setProperty(
|
||||
kInstantReplaceRandomId,
|
||||
openssl::RandomValue<uint32>());
|
||||
ApplyTagFormat(format, cursor.charFormat());
|
||||
cursor.insertText(replacement, format);
|
||||
}
|
||||
@@ -3362,7 +3305,7 @@ bool InputField::revertFormatReplace() {
|
||||
void InputField::contextMenuEventInner(QContextMenuEvent *e) {
|
||||
if (const auto menu = _inner->createStandardContextMenu()) {
|
||||
addMarkdownActions(menu, e);
|
||||
_contextMenu = base::make_unique_q<Ui::PopupMenu>(this, menu);
|
||||
_contextMenu = base::make_unique_q<PopupMenu>(this, menu);
|
||||
_contextMenu->popup(e->globalPos());
|
||||
}
|
||||
}
|
||||
@@ -3373,7 +3316,11 @@ void InputField::addMarkdownActions(
|
||||
if (!_markdownEnabled) {
|
||||
return;
|
||||
}
|
||||
const auto formatting = new QAction(tr::lng_menu_formatting(tr::now), menu);
|
||||
auto &integration = Integration::Instance();
|
||||
|
||||
const auto formatting = new QAction(
|
||||
integration.phraseFormattingTitle(),
|
||||
menu);
|
||||
addMarkdownMenuAction(menu, formatting);
|
||||
|
||||
const auto submenu = new QMenu(menu);
|
||||
@@ -3417,24 +3364,24 @@ void InputField::addMarkdownActions(
|
||||
const auto selection = editLinkSelection(e);
|
||||
const auto data = selectionEditLinkData(selection);
|
||||
const auto base = data.link.isEmpty()
|
||||
? tr::lng_menu_formatting_link_create(tr::now)
|
||||
: tr::lng_menu_formatting_link_edit(tr::now);
|
||||
? integration.phraseFormattingLinkCreate()
|
||||
: integration.phraseFormattingLinkEdit();
|
||||
add(base, kEditLinkSequence, false, [=] {
|
||||
editMarkdownLink(selection);
|
||||
});
|
||||
};
|
||||
const auto addclear = [&] {
|
||||
const auto disabled = !hasText || !hasTags;
|
||||
add(tr::lng_menu_formatting_clear(tr::now), kClearFormatSequence, disabled, [=] {
|
||||
add(integration.phraseFormattingClear(), kClearFormatSequence, disabled, [=] {
|
||||
clearSelectionMarkdown();
|
||||
});
|
||||
};
|
||||
|
||||
addtag(tr::lng_menu_formatting_bold(tr::now), QKeySequence::Bold, kTagBold);
|
||||
addtag(tr::lng_menu_formatting_italic(tr::now), QKeySequence::Italic, kTagItalic);
|
||||
addtag(tr::lng_menu_formatting_underline(tr::now), QKeySequence::Underline, kTagUnderline);
|
||||
addtag(tr::lng_menu_formatting_strike_out(tr::now), kStrikeOutSequence, kTagStrikeOut);
|
||||
addtag(tr::lng_menu_formatting_monospace(tr::now), kMonospaceSequence, kTagCode);
|
||||
addtag(integration.phraseFormattingBold(), QKeySequence::Bold, kTagBold);
|
||||
addtag(integration.phraseFormattingItalic(), QKeySequence::Italic, kTagItalic);
|
||||
addtag(integration.phraseFormattingUnderline(), QKeySequence::Underline, kTagUnderline);
|
||||
addtag(integration.phraseFormattingStrikeOut(), kStrikeOutSequence, kTagStrikeOut);
|
||||
addtag(integration.phraseFormattingMonospace(), kMonospaceSequence, kTagCode);
|
||||
|
||||
if (_editLinkCallback) {
|
||||
submenu->addSeparator();
|
||||
@@ -3595,11 +3542,10 @@ MaskedInputField::MaskedInputField(
|
||||
refreshPlaceholder(text);
|
||||
}, lifetime());
|
||||
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.paletteChanged()) {
|
||||
updatePalette();
|
||||
}
|
||||
});
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
updatePalette();
|
||||
}, lifetime());
|
||||
updatePalette();
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
@@ -3608,7 +3554,9 @@ MaskedInputField::MaskedInputField(
|
||||
connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onCursorPositionChanged(int,int)));
|
||||
|
||||
connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(onTextEdited()));
|
||||
if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
|
||||
connect(this, &MaskedInputField::selectionChanged, [] {
|
||||
Integration::Instance().textActionsUpdated();
|
||||
});
|
||||
|
||||
setStyle(InputStyle<MaskedInputField>::instance());
|
||||
QLineEdit::setTextMargins(0, 0, 0, 0);
|
||||
@@ -3738,7 +3686,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
|
||||
auto borderShownDegree = _a_borderShown.value(1.);
|
||||
auto borderOpacity = _a_borderOpacity.value(_borderVisible ? 1. : 0.);
|
||||
if (_st.borderActive && (borderOpacity > 0.)) {
|
||||
auto borderStart = snap(_borderAnimationStart, 0, width());
|
||||
auto borderStart = std::clamp(_borderAnimationStart, 0, width());
|
||||
auto borderFrom = qRound(borderStart * (1. - borderShownDegree));
|
||||
auto borderTo = borderStart + qRound((width() - borderStart) * borderShownDegree);
|
||||
if (borderTo > borderFrom) {
|
||||
@@ -3759,7 +3707,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
|
||||
|
||||
QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins));
|
||||
r.moveTop(r.top() + placeholderTop);
|
||||
if (rtl()) r.moveLeft(width() - r.left() - r.width());
|
||||
if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
|
||||
|
||||
auto placeholderScale = 1. - (1. - _st.placeholderScale) * placeholderShiftDegree;
|
||||
auto placeholderFg = anim::color(_st.placeholderFg, _st.placeholderFgActive, focusedDegree);
|
||||
@@ -3784,7 +3732,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
|
||||
|
||||
QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins));
|
||||
r.moveLeft(r.left() + placeholderLeft);
|
||||
if (rtl()) r.moveLeft(width() - r.left() - r.width());
|
||||
if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
|
||||
|
||||
p.setFont(_st.placeholderFont);
|
||||
p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, focusedDegree));
|
||||
@@ -3869,7 +3817,7 @@ void MaskedInputField::setPlaceholder(rpl::producer<QString> placeholder) {
|
||||
|
||||
void MaskedInputField::contextMenuEvent(QContextMenuEvent *e) {
|
||||
if (const auto menu = createStandardContextMenu()) {
|
||||
(new Ui::PopupMenu(this, menu))->popup(e->globalPos());
|
||||
(new PopupMenu(this, menu))->popup(e->globalPos());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3982,213 +3930,19 @@ void MaskedInputField::onTextEdited() {
|
||||
if (wasText != _oldtext) emit changed();
|
||||
startPlaceholderAnimation();
|
||||
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
void MaskedInputField::onTextChange(const QString &text) {
|
||||
_oldtext = QLineEdit::text();
|
||||
setErrorShown(false);
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
Integration::Instance().textActionsUpdated();
|
||||
}
|
||||
|
||||
void MaskedInputField::onCursorPositionChanged(int oldPosition, int position) {
|
||||
_oldcursor = position;
|
||||
}
|
||||
|
||||
CountryCodeInput::CountryCodeInput(QWidget *parent, const style::InputField &st) : MaskedInputField(parent, st)
|
||||
, _nosignal(false) {
|
||||
}
|
||||
|
||||
void CountryCodeInput::startErasing(QKeyEvent *e) {
|
||||
setFocus();
|
||||
keyPressEvent(e);
|
||||
}
|
||||
|
||||
void CountryCodeInput::codeSelected(const QString &code) {
|
||||
auto wasText = getLastText();
|
||||
auto wasCursor = cursorPosition();
|
||||
auto newText = '+' + code;
|
||||
auto newCursor = newText.size();
|
||||
setText(newText);
|
||||
_nosignal = true;
|
||||
correctValue(wasText, wasCursor, newText, newCursor);
|
||||
_nosignal = false;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void CountryCodeInput::correctValue(
|
||||
const QString &was,
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
QString newText, addToNumber;
|
||||
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), start = 0, digits = 5;
|
||||
newText.reserve(oldLen + 1);
|
||||
if (oldLen && now[0] == '+') {
|
||||
if (start == oldPos) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
++start;
|
||||
}
|
||||
newText += '+';
|
||||
for (int i = start; i < oldLen; ++i) {
|
||||
if (i == oldPos) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
auto ch = now[i];
|
||||
if (ch.isDigit()) {
|
||||
if (!digits || !--digits) {
|
||||
addToNumber += ch;
|
||||
} else {
|
||||
newText += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!addToNumber.isEmpty()) {
|
||||
auto validCode = Data::ValidPhoneCode(newText.mid(1));
|
||||
addToNumber = newText.mid(1 + validCode.length()) + addToNumber;
|
||||
newText = '+' + validCode;
|
||||
}
|
||||
setCorrectedText(now, nowCursor, newText, newPos);
|
||||
|
||||
if (!_nosignal && was != newText) {
|
||||
emit codeChanged(newText.mid(1));
|
||||
}
|
||||
if (!addToNumber.isEmpty()) {
|
||||
emit addedToNumber(addToNumber);
|
||||
}
|
||||
}
|
||||
|
||||
PhonePartInput::PhonePartInput(QWidget *parent, const style::InputField &st) : MaskedInputField(parent, st/*, tr::lng_phone_ph(tr::now)*/) {
|
||||
}
|
||||
|
||||
void PhonePartInput::paintAdditionalPlaceholder(Painter &p) {
|
||||
if (!_pattern.isEmpty()) {
|
||||
auto t = getDisplayedText();
|
||||
auto ph = _additionalPlaceholder.mid(t.size());
|
||||
if (!ph.isEmpty()) {
|
||||
p.setClipRect(rect());
|
||||
auto phRect = placeholderRect();
|
||||
int tw = phFont()->width(t);
|
||||
if (tw < phRect.width()) {
|
||||
phRect.setLeft(phRect.left() + tw);
|
||||
placeholderAdditionalPrepare(p);
|
||||
p.drawText(phRect, ph, style::al_topleft);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhonePartInput::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Backspace && getLastText().isEmpty()) {
|
||||
emit voidBackspace(e);
|
||||
} else {
|
||||
MaskedInputField::keyPressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void PhonePartInput::correctValue(
|
||||
const QString &was,
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
QString newText;
|
||||
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), digitCount = 0;
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
if (now[i].isDigit()) {
|
||||
++digitCount;
|
||||
}
|
||||
}
|
||||
if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength;
|
||||
|
||||
bool inPart = !_pattern.isEmpty();
|
||||
int curPart = -1, leftInPart = 0;
|
||||
newText.reserve(oldLen);
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
if (i == oldPos && newPos < 0) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
|
||||
auto ch = now[i];
|
||||
if (ch.isDigit()) {
|
||||
if (!digitCount--) {
|
||||
break;
|
||||
}
|
||||
if (inPart) {
|
||||
if (leftInPart) {
|
||||
--leftInPart;
|
||||
} else {
|
||||
newText += ' ';
|
||||
++curPart;
|
||||
inPart = curPart < _pattern.size();
|
||||
leftInPart = inPart ? (_pattern.at(curPart) - 1) : 0;
|
||||
|
||||
++oldPos;
|
||||
}
|
||||
}
|
||||
newText += ch;
|
||||
} else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') {
|
||||
if (inPart) {
|
||||
if (leftInPart) {
|
||||
} else {
|
||||
newText += ch;
|
||||
++curPart;
|
||||
inPart = curPart < _pattern.size();
|
||||
leftInPart = inPart ? _pattern.at(curPart) : 0;
|
||||
}
|
||||
} else {
|
||||
newText += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto newlen = newText.size();
|
||||
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
||||
--newlen;
|
||||
}
|
||||
if (newlen < newText.size()) {
|
||||
newText = newText.mid(0, newlen);
|
||||
}
|
||||
setCorrectedText(now, nowCursor, newText, newPos);
|
||||
}
|
||||
|
||||
void PhonePartInput::addedToNumber(const QString &added) {
|
||||
setFocus();
|
||||
auto wasText = getLastText();
|
||||
auto wasCursor = cursorPosition();
|
||||
auto newText = added + wasText;
|
||||
auto newCursor = newText.size();
|
||||
setText(newText);
|
||||
setCursorPosition(added.length());
|
||||
correctValue(wasText, wasCursor, newText, newCursor);
|
||||
startPlaceholderAnimation();
|
||||
}
|
||||
|
||||
void PhonePartInput::onChooseCode(const QString &code) {
|
||||
_pattern = phoneNumberParse(code);
|
||||
if (!_pattern.isEmpty() && _pattern.at(0) == code.size()) {
|
||||
_pattern.pop_front();
|
||||
} else {
|
||||
_pattern.clear();
|
||||
}
|
||||
_additionalPlaceholder = QString();
|
||||
if (!_pattern.isEmpty()) {
|
||||
_additionalPlaceholder.reserve(20);
|
||||
for (const auto part : _pattern) {
|
||||
_additionalPlaceholder.append(' ');
|
||||
_additionalPlaceholder.append(QString(part, QChar(0x2212)));
|
||||
}
|
||||
}
|
||||
setPlaceholderHidden(!_additionalPlaceholder.isEmpty());
|
||||
|
||||
auto wasText = getLastText();
|
||||
auto wasCursor = cursorPosition();
|
||||
auto newText = getLastText();
|
||||
auto newCursor = newText.size();
|
||||
correctValue(wasText, wasCursor, newText, newCursor);
|
||||
|
||||
startPlaceholderAnimation();
|
||||
}
|
||||
|
||||
PasswordInput::PasswordInput(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
@@ -4266,194 +4020,4 @@ void HexInput::correctValue(
|
||||
setCorrectedText(now, nowCursor, newText, newPos);
|
||||
}
|
||||
|
||||
UsernameInput::UsernameInput(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
rpl::producer<QString> placeholder,
|
||||
const QString &val,
|
||||
bool isLink)
|
||||
: MaskedInputField(parent, st, std::move(placeholder), val) {
|
||||
setLinkPlaceholder(
|
||||
isLink ? Core::App().createInternalLink(QString()) : QString());
|
||||
}
|
||||
|
||||
void UsernameInput::setLinkPlaceholder(const QString &placeholder) {
|
||||
_linkPlaceholder = placeholder;
|
||||
if (!_linkPlaceholder.isEmpty()) {
|
||||
setTextMargins(style::margins(_st.textMargins.left() + _st.font->width(_linkPlaceholder), _st.textMargins.top(), _st.textMargins.right(), _st.textMargins.bottom()));
|
||||
setPlaceholderHidden(true);
|
||||
}
|
||||
}
|
||||
|
||||
void UsernameInput::paintAdditionalPlaceholder(Painter &p) {
|
||||
if (!_linkPlaceholder.isEmpty()) {
|
||||
p.setFont(_st.font);
|
||||
p.setPen(_st.placeholderFg);
|
||||
p.drawText(QRect(_st.textMargins.left(), _st.textMargins.top(), width(), height() - _st.textMargins.top() - _st.textMargins.bottom()), _linkPlaceholder, style::al_topleft);
|
||||
}
|
||||
}
|
||||
|
||||
void UsernameInput::correctValue(
|
||||
const QString &was,
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
auto newPos = nowCursor;
|
||||
auto from = 0, len = now.size();
|
||||
for (; from < len; ++from) {
|
||||
if (!now.at(from).isSpace()) {
|
||||
break;
|
||||
}
|
||||
if (newPos > 0) --newPos;
|
||||
}
|
||||
len -= from;
|
||||
if (len > kMaxUsernameLength) {
|
||||
len = kMaxUsernameLength + (now.at(from) == '@' ? 1 : 0);
|
||||
}
|
||||
for (int32 to = from + len; to > from;) {
|
||||
--to;
|
||||
if (!now.at(to).isSpace()) {
|
||||
break;
|
||||
}
|
||||
--len;
|
||||
}
|
||||
setCorrectedText(now, nowCursor, now.mid(from, len), newPos);
|
||||
}
|
||||
|
||||
PhoneInput::PhoneInput(
|
||||
QWidget *parent,
|
||||
const style::InputField &st,
|
||||
rpl::producer<QString> placeholder,
|
||||
const QString &defaultValue,
|
||||
QString value)
|
||||
: MaskedInputField(parent, st, std::move(placeholder), value)
|
||||
, _defaultValue(defaultValue) {
|
||||
if (value.isEmpty()) {
|
||||
clearText();
|
||||
} else {
|
||||
auto pos = value.size();
|
||||
correctValue(QString(), 0, value, pos);
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneInput::focusInEvent(QFocusEvent *e) {
|
||||
MaskedInputField::focusInEvent(e);
|
||||
setSelection(cursorPosition(), cursorPosition());
|
||||
}
|
||||
|
||||
void PhoneInput::clearText() {
|
||||
auto value = _defaultValue;
|
||||
setText(value);
|
||||
auto pos = value.size();
|
||||
correctValue(QString(), 0, value, pos);
|
||||
}
|
||||
|
||||
void PhoneInput::paintAdditionalPlaceholder(Painter &p) {
|
||||
if (!_pattern.isEmpty()) {
|
||||
auto t = getDisplayedText();
|
||||
auto ph = _additionalPlaceholder.mid(t.size());
|
||||
if (!ph.isEmpty()) {
|
||||
p.setClipRect(rect());
|
||||
auto phRect = placeholderRect();
|
||||
int tw = phFont()->width(t);
|
||||
if (tw < phRect.width()) {
|
||||
phRect.setLeft(phRect.left() + tw);
|
||||
placeholderAdditionalPrepare(p);
|
||||
p.drawText(phRect, ph, style::al_topleft);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneInput::correctValue(
|
||||
const QString &was,
|
||||
int wasCursor,
|
||||
QString &now,
|
||||
int &nowCursor) {
|
||||
auto digits = now;
|
||||
digits.replace(QRegularExpression(qsl("[^\\d]")), QString());
|
||||
_pattern = phoneNumberParse(digits);
|
||||
|
||||
QString newPlaceholder;
|
||||
if (_pattern.isEmpty()) {
|
||||
newPlaceholder = QString();
|
||||
} else if (_pattern.size() == 1 && _pattern.at(0) == digits.size()) {
|
||||
newPlaceholder = QString(_pattern.at(0) + 2, ' ') + tr::lng_contact_phone(tr::now);
|
||||
} else {
|
||||
newPlaceholder.reserve(20);
|
||||
for (int i = 0, l = _pattern.size(); i < l; ++i) {
|
||||
if (i) {
|
||||
newPlaceholder.append(' ');
|
||||
} else {
|
||||
newPlaceholder.append('+');
|
||||
}
|
||||
newPlaceholder.append(i ? QString(_pattern.at(i), QChar(0x2212)) : digits.mid(0, _pattern.at(i)));
|
||||
}
|
||||
}
|
||||
if (_additionalPlaceholder != newPlaceholder) {
|
||||
_additionalPlaceholder = newPlaceholder;
|
||||
setPlaceholderHidden(!_additionalPlaceholder.isEmpty());
|
||||
update();
|
||||
}
|
||||
|
||||
QString newText;
|
||||
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), digitCount = qMin(digits.size(), MaxPhoneCodeLength + MaxPhoneTailLength);
|
||||
|
||||
bool inPart = !_pattern.isEmpty(), plusFound = false;
|
||||
int curPart = 0, leftInPart = inPart ? _pattern.at(curPart) : 0;
|
||||
newText.reserve(oldLen + 1);
|
||||
newText.append('+');
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
if (i == oldPos && newPos < 0) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
|
||||
QChar ch(now[i]);
|
||||
if (ch.isDigit()) {
|
||||
if (!digitCount--) {
|
||||
break;
|
||||
}
|
||||
if (inPart) {
|
||||
if (leftInPart) {
|
||||
--leftInPart;
|
||||
} else {
|
||||
newText += ' ';
|
||||
++curPart;
|
||||
inPart = curPart < _pattern.size();
|
||||
leftInPart = inPart ? (_pattern.at(curPart) - 1) : 0;
|
||||
|
||||
++oldPos;
|
||||
}
|
||||
}
|
||||
newText += ch;
|
||||
} else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') {
|
||||
if (inPart) {
|
||||
if (leftInPart) {
|
||||
} else {
|
||||
newText += ch;
|
||||
++curPart;
|
||||
inPart = curPart < _pattern.size();
|
||||
leftInPart = inPart ? _pattern.at(curPart) : 0;
|
||||
}
|
||||
} else {
|
||||
newText += ch;
|
||||
}
|
||||
} else if (ch == '+') {
|
||||
plusFound = true;
|
||||
}
|
||||
}
|
||||
if (!plusFound && newText == qstr("+")) {
|
||||
newText = QString();
|
||||
newPos = 0;
|
||||
}
|
||||
int32 newlen = newText.size();
|
||||
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
||||
--newlen;
|
||||
}
|
||||
if (newlen < newText.size()) {
|
||||
newText = newText.mid(0, newlen);
|
||||
}
|
||||
setCorrectedText(now, nowCursor, newText, newPos);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
Reference in New Issue
Block a user