mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-31 14:38:15 +00:00
merged master
This commit is contained in:
@@ -25,9 +25,9 @@ void filedialogInit() {
|
||||
if (cDialogLastPath().isEmpty()) {
|
||||
#ifdef Q_OS_WIN
|
||||
// hack to restore previous dir without hurting performance
|
||||
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
|
||||
settings.beginGroup(QLatin1String("Qt"));
|
||||
QByteArray sd = settings.value(QLatin1String("filedialog")).toByteArray();
|
||||
QSettings settings(QSettings::UserScope, qstr("QtProject"));
|
||||
settings.beginGroup(qstr("Qt"));
|
||||
QByteArray sd = settings.value(qstr("filedialog")).toByteArray();
|
||||
QDataStream stream(&sd, QIODevice::ReadOnly);
|
||||
if (!stream.atEnd()) {
|
||||
int version = 3, _QFileDialogMagic = 190;
|
||||
|
@@ -45,7 +45,8 @@ namespace {
|
||||
InputStyle<InputField> _inputFieldStyle;
|
||||
}
|
||||
|
||||
FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent), _fullph(pholder), _oldtext(v), _kev(0), _customUpDown(false), _phVisible(!v.length()),
|
||||
FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent),
|
||||
_fullph(pholder), _oldtext(v), _fastph(false), _kev(0), _customUpDown(false), _phVisible(!v.length()),
|
||||
a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c),
|
||||
a_borderColor(st.borderColor->c), a_bgColor(st.bgColor->c), _notingBene(0), _st(st) {
|
||||
resize(_st.width, _st.height);
|
||||
@@ -133,7 +134,7 @@ QRect FlatInput::getTextRect() const {
|
||||
}
|
||||
|
||||
void FlatInput::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
Painter p(this);
|
||||
p.fillRect(rect(), a_bgColor.current());
|
||||
if (_st.borderWidth) {
|
||||
QBrush b(a_borderColor.current());
|
||||
@@ -154,9 +155,9 @@ void FlatInput::paintEvent(QPaintEvent *e) {
|
||||
if (phDraw) {
|
||||
p.save();
|
||||
p.setClipRect(rect());
|
||||
QRect phRect(_st.textMrg.left() + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
|
||||
p.setFont(_st.font->f);
|
||||
p.setPen(a_phColor.current());
|
||||
QRect phRect(placeholderRect());
|
||||
phRect.moveLeft(phRect.left() + a_phLeft.current());
|
||||
phPrepare(p);
|
||||
p.drawText(phRect, _ph, QTextOption(_st.phAlign));
|
||||
p.restore();
|
||||
}
|
||||
@@ -231,20 +232,53 @@ bool FlatInput::animStep(float64 ms) {
|
||||
return res;
|
||||
}
|
||||
|
||||
void FlatInput::setPlaceholder(const QString &ph) {
|
||||
_fullph = ph;
|
||||
resizeEvent(0);
|
||||
update();
|
||||
}
|
||||
|
||||
void FlatInput::setPlaceholderFast(bool fast) {
|
||||
_fastph = fast;
|
||||
if (_fastph) {
|
||||
a_phLeft = anim::ivalue(_phVisible ? 0 : _st.phShift, _phVisible ? 0 : _st.phShift);
|
||||
a_phAlpha = anim::fvalue(_phVisible ? 1 : 0, _phVisible ? 1 : 0);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void FlatInput::updatePlaceholder() {
|
||||
bool vis = !text().length();
|
||||
if (vis == _phVisible) return;
|
||||
|
||||
a_phLeft.start(vis ? 0 : _st.phShift);
|
||||
a_phAlpha.start(vis ? 1 : 0);
|
||||
anim::start(this);
|
||||
|
||||
if (_fastph) {
|
||||
a_phLeft = anim::ivalue(vis ? 0 : _st.phShift, vis ? 0 : _st.phShift);
|
||||
a_phAlpha = anim::fvalue(vis ? 1 : 0, vis ? 1 : 0);
|
||||
update();
|
||||
} else {
|
||||
a_phLeft.start(vis ? 0 : _st.phShift);
|
||||
a_phAlpha.start(vis ? 1 : 0);
|
||||
anim::start(this);
|
||||
}
|
||||
_phVisible = vis;
|
||||
}
|
||||
|
||||
const QString &FlatInput::placeholder() const {
|
||||
return _fullph;
|
||||
}
|
||||
|
||||
QRect FlatInput::placeholderRect() const {
|
||||
return QRect(_st.textMrg.left() + _st.phPos.x(), _st.textMrg.top() + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
|
||||
}
|
||||
|
||||
void FlatInput::correctValue(QKeyEvent *e, const QString &was) {
|
||||
}
|
||||
|
||||
void FlatInput::phPrepare(Painter &p) {
|
||||
p.setFont(_st.font->f);
|
||||
p.setPen(a_phColor.current());
|
||||
}
|
||||
|
||||
void FlatInput::keyPressEvent(QKeyEvent *e) {
|
||||
QString was(text());
|
||||
_kev = e;
|
||||
@@ -350,13 +384,18 @@ void CountryCodeInput::correctValue(QKeyEvent *e, const QString &was) {
|
||||
}
|
||||
}
|
||||
|
||||
InputField::InputField(QWidget *parent, const style::InputField &st, const QString &pholder, const QString &v) : QLineEdit(v, parent),
|
||||
_lastText(v),
|
||||
InputField::InputField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : QTextEdit(val, parent),
|
||||
_oldtext(val),
|
||||
_keyEvent(0),
|
||||
|
||||
_undoAvailable(false),
|
||||
_redoAvailable(false),
|
||||
|
||||
_fakeMargin(0),
|
||||
_customUpDown(false),
|
||||
|
||||
_placeholderFull(pholder),
|
||||
_placeholderVisible(!v.length()),
|
||||
_placeholderFull(ph),
|
||||
_placeholderVisible(val.isEmpty()),
|
||||
a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift),
|
||||
a_placeholderOpacity(_placeholderVisible ? 1 : 0),
|
||||
a_placeholderFg(st.placeholderFg->c),
|
||||
@@ -367,47 +406,67 @@ a_borderFg(st.borderFg->c),
|
||||
a_borderOpacityActive(0),
|
||||
_borderAnim(animFunc(this, &InputField::borderStep)),
|
||||
|
||||
_focused(false), _error(false), _st(&st) {
|
||||
_st(&st),
|
||||
|
||||
_touchPress(false),
|
||||
_touchRightButton(false),
|
||||
_touchMove(false),
|
||||
_replacingEmojis(false) {
|
||||
setAcceptRichText(false);
|
||||
resize(_st->width, _st->height);
|
||||
|
||||
setWordWrapMode(QTextOption::NoWrap);
|
||||
setLineWrapMode(QTextEdit::NoWrap);
|
||||
|
||||
setFont(_st->font->f);
|
||||
setAlignment(_st->textAlign);
|
||||
setLayoutDirection(cLangDir());
|
||||
setAlignment(cRtl() ? Qt::AlignRight : Qt::AlignLeft);
|
||||
|
||||
_placeholder = _st->font->m.elidedText(_placeholderFull, Qt::ElideRight, width() - _st->textMargins.left() - _st->textMargins.right() - _st->placeholderMargins.left() - _st->placeholderMargins.right() - 1);
|
||||
|
||||
QPalette p(palette());
|
||||
p.setColor(QPalette::Text, _st->textFg->c);
|
||||
setPalette(p);
|
||||
|
||||
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()));
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
setFrameStyle(QFrame::NoFrame | QFrame::Plain);
|
||||
viewport()->setAutoFillBackground(false);
|
||||
|
||||
setStyle(&_inputFieldStyle);
|
||||
setTextMargins(0, 0, 0, 0);
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
//switch (cScale()) {
|
||||
//case dbisOneAndQuarter: _fakeMargin = 1; break;
|
||||
//case dbisOneAndHalf: _fakeMargin = 2; break;
|
||||
//case dbisTwo: _fakeMargin = 4; break;
|
||||
//}
|
||||
//setStyleSheet(qsl("QTextEdit { margin: %1px; }").arg(_fakeMargin));
|
||||
setStyleSheet(qsl("QTextEdit { padding: 2px 74px; }"));
|
||||
|
||||
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
_touchTimer.setSingleShot(true);
|
||||
connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
|
||||
}
|
||||
|
||||
void InputField::setCustomUpDown(bool customUpDown) {
|
||||
_customUpDown = customUpDown;
|
||||
connect(document(), SIGNAL(contentsChange(int, int, int)), this, SLOT(onDocumentContentsChange(int, int, int)));
|
||||
connect(document(), SIGNAL(contentsChanged()), this, SLOT(onDocumentContentsChanged()));
|
||||
connect(this, SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool)));
|
||||
connect(this, SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool)));
|
||||
if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
|
||||
}
|
||||
|
||||
void InputField::onTouchTimer() {
|
||||
_touchRightButton = true;
|
||||
}
|
||||
|
||||
bool InputField::event(QEvent *e) {
|
||||
bool InputField::viewportEvent(QEvent *e) {
|
||||
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
|
||||
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
|
||||
if (ev->device()->type() == QTouchDevice::TouchScreen) {
|
||||
touchEvent(ev);
|
||||
return QLineEdit::event(e);
|
||||
return QTextEdit::viewportEvent(e);
|
||||
}
|
||||
}
|
||||
return QLineEdit::event(e);
|
||||
return QTextEdit::viewportEvent(e);
|
||||
}
|
||||
|
||||
void InputField::touchEvent(QTouchEvent *e) {
|
||||
@@ -450,18 +509,18 @@ void InputField::touchEvent(QTouchEvent *e) {
|
||||
}
|
||||
|
||||
QRect InputField::getTextRect() const {
|
||||
QMargins m = _st->textMargins + QMargins(-2, -1, -2, -1);
|
||||
if (rtl()) {
|
||||
int l = m.left();
|
||||
m.setLeft(m.right());
|
||||
m.setRight(l);
|
||||
}
|
||||
return rect().marginsRemoved(m);
|
||||
return rect().marginsRemoved(_st->textMargins + st::textRectMargins);
|
||||
}
|
||||
|
||||
int32 InputField::fakeMargin() const {
|
||||
return _fakeMargin;
|
||||
}
|
||||
|
||||
void InputField::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
Painter p(viewport());
|
||||
|
||||
QRect r(rect().intersected(e->rect()));
|
||||
p.fillRect(r, st::white->b);
|
||||
if (_st->border) {
|
||||
p.fillRect(0, height() - _st->border, width(), _st->border, _st->borderFg->b);
|
||||
}
|
||||
@@ -473,7 +532,7 @@ void InputField::paintEvent(QPaintEvent *e) {
|
||||
if (_st->iconSprite.pxWidth()) {
|
||||
p.drawSpriteLeft(_st->iconPosition, width(), _st->iconSprite);
|
||||
}
|
||||
|
||||
|
||||
bool drawPlaceholder = _placeholderVisible;
|
||||
if (_placeholderShiftAnim.animating()) {
|
||||
p.setOpacity(a_placeholderOpacity.current());
|
||||
@@ -481,57 +540,51 @@ void InputField::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
if (drawPlaceholder) {
|
||||
p.save();
|
||||
p.setClipRect(rect());
|
||||
p.setClipRect(r);
|
||||
|
||||
QRect r(rect().marginsRemoved(_st->textMargins + _st->placeholderMargins));
|
||||
r.moveLeft(r.left() + a_placeholderLeft.current());
|
||||
if (rtl()) r.moveLeft(width() - r.left() - r.width());
|
||||
|
||||
|
||||
p.setFont(_st->font->f);
|
||||
p.setPen(a_placeholderFg.current());
|
||||
p.drawText(r, _placeholder, _st->placeholderAlign);
|
||||
|
||||
|
||||
p.restore();
|
||||
}
|
||||
QLineEdit::paintEvent(e);
|
||||
QTextEdit::paintEvent(e);
|
||||
}
|
||||
|
||||
void InputField::focusInEvent(QFocusEvent *e) {
|
||||
if (!_focused) {
|
||||
_focused = true;
|
||||
|
||||
|
||||
a_placeholderFg.start(_st->placeholderFgActive->c);
|
||||
_placeholderFgAnim.start();
|
||||
|
||||
|
||||
a_borderFg.start((_error ? _st->borderFgError : _st->borderFgActive)->c);
|
||||
a_borderOpacityActive.start(1);
|
||||
_borderAnim.start();
|
||||
}
|
||||
QLineEdit::focusInEvent(e);
|
||||
QTextEdit::focusInEvent(e);
|
||||
emit focused();
|
||||
}
|
||||
|
||||
void InputField::focusOutEvent(QFocusEvent *e) {
|
||||
if (_focused) {
|
||||
_focused = false;
|
||||
|
||||
|
||||
a_placeholderFg.start(_st->placeholderFg->c);
|
||||
_placeholderFgAnim.start();
|
||||
|
||||
|
||||
a_borderFg.start((_error ? _st->borderFgError : _st->borderFg)->c);
|
||||
a_borderOpacityActive.start(_error ? 1 : 0);
|
||||
_borderAnim.start();
|
||||
}
|
||||
QLineEdit::focusOutEvent(e);
|
||||
QTextEdit::focusOutEvent(e);
|
||||
emit blurred();
|
||||
}
|
||||
|
||||
void InputField::resizeEvent(QResizeEvent *e) {
|
||||
int32 availw = width() - _st->textMargins.left() - _st->textMargins.right() - _st->placeholderMargins.left() - _st->placeholderMargins.right() - 2;
|
||||
_placeholder = (_st->font->m.width(_placeholderFull) > availw) ? _st->font->m.elidedText(_placeholderFull, Qt::ElideRight, availw) : _placeholderFull;
|
||||
update();
|
||||
}
|
||||
|
||||
QSize InputField::sizeHint() const {
|
||||
return geometry().size();
|
||||
}
|
||||
@@ -540,6 +593,264 @@ QSize InputField::minimumSizeHint() const {
|
||||
return geometry().size();
|
||||
}
|
||||
|
||||
QString InputField::getText(int32 start, int32 end) const {
|
||||
if (end >= 0 && end <= start) return QString();
|
||||
|
||||
if (start < 0) start = 0;
|
||||
bool full = (start == 0) && (end < 0);
|
||||
|
||||
QTextDocument *doc(document());
|
||||
QTextBlock from = full ? doc->begin() : doc->findBlock(start), till = (end < 0) ? doc->end() : doc->findBlock(end);
|
||||
if (till.isValid()) till = till.next();
|
||||
|
||||
int32 possibleLen = 0;
|
||||
for (QTextBlock b = from; b != till; b = b.next()) {
|
||||
possibleLen += b.length();
|
||||
}
|
||||
QString result;
|
||||
result.reserve(possibleLen + 1);
|
||||
if (!full && end < 0) {
|
||||
end = possibleLen;
|
||||
}
|
||||
|
||||
for (QTextBlock b = from; b != till; b = b.next()) {
|
||||
for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) {
|
||||
QTextFragment fragment(iter.fragment());
|
||||
if (!fragment.isValid()) continue;
|
||||
|
||||
int32 p = full ? 0 : fragment.position(), e = full ? 0 : (p + fragment.length());
|
||||
if (!full) {
|
||||
if (p >= end || e <= start) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
QTextCharFormat f = fragment.charFormat();
|
||||
QString emojiText;
|
||||
QString t(fragment.text());
|
||||
if (!full) {
|
||||
if (p < start) {
|
||||
t = t.mid(start - p, end - start);
|
||||
} else if (e > end) {
|
||||
t = t.mid(0, end - p);
|
||||
}
|
||||
}
|
||||
QChar *ub = t.data(), *uc = ub, *ue = uc + t.size();
|
||||
for (; uc != ue; ++uc) {
|
||||
switch (uc->unicode()) {
|
||||
case 0xfdd0: // QTextBeginningOfFrame
|
||||
case 0xfdd1: // QTextEndOfFrame
|
||||
case QChar::ParagraphSeparator:
|
||||
case QChar::LineSeparator:
|
||||
*uc = QLatin1Char('\n');
|
||||
break;
|
||||
case QChar::Nbsp:
|
||||
*uc = QLatin1Char(' ');
|
||||
break;
|
||||
case QChar::ObjectReplacementCharacter:
|
||||
if (emojiText.isEmpty() && f.isImageFormat()) {
|
||||
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
|
||||
if (imageName.startsWith(qstr("emoji://e."))) {
|
||||
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
|
||||
emojiText = emojiString(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uc > ub) result.append(ub, uc - ub);
|
||||
if (!emojiText.isEmpty()) result.append(emojiText);
|
||||
ub = uc + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (uc > ub) result.append(ub, uc - ub);
|
||||
}
|
||||
result.append('\n');
|
||||
}
|
||||
result.chop(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool InputField::hasText() const {
|
||||
QTextDocument *doc(document());
|
||||
QTextBlock from = doc->begin(), till = doc->end();
|
||||
|
||||
if (from == till) return false;
|
||||
|
||||
for (QTextBlock::Iterator iter = from.begin(); !iter.atEnd(); ++iter) {
|
||||
QTextFragment fragment(iter.fragment());
|
||||
if (!fragment.isValid()) continue;
|
||||
if (!fragment.text().isEmpty()) return true;
|
||||
}
|
||||
return (from.next() != till);
|
||||
}
|
||||
|
||||
bool InputField::isUndoAvailable() const {
|
||||
return _undoAvailable;
|
||||
}
|
||||
|
||||
bool InputField::isRedoAvailable() const {
|
||||
return _redoAvailable;
|
||||
}
|
||||
|
||||
void InputField::insertEmoji(EmojiPtr emoji, QTextCursor c) {
|
||||
QTextImageFormat imageFormat;
|
||||
int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st->font->height * cIntRetinaFactor();
|
||||
imageFormat.setWidth(ew / cIntRetinaFactor());
|
||||
imageFormat.setHeight(eh / cIntRetinaFactor());
|
||||
imageFormat.setName(qsl("emoji://e.") + QString::number(emojiKey(emoji), 16));
|
||||
imageFormat.setVerticalAlignment(QTextCharFormat::AlignBaseline);
|
||||
|
||||
static QString objectReplacement(QChar::ObjectReplacementCharacter);
|
||||
c.insertText(objectReplacement, imageFormat);
|
||||
}
|
||||
|
||||
QVariant InputField::loadResource(int type, const QUrl &name) {
|
||||
QString imageName = name.toDisplayString();
|
||||
if (imageName.startsWith(qstr("emoji://e."))) {
|
||||
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
|
||||
return QVariant(App::emojiSingle(emoji, _st->font->height));
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void InputField::processDocumentContentsChange(int position, int charsAdded) {
|
||||
int32 emojiPosition = 0, emojiLen = 0;
|
||||
const EmojiData *emoji = 0;
|
||||
|
||||
QTextDocument *doc(document());
|
||||
|
||||
while (true) {
|
||||
int32 start = position, end = position + charsAdded;
|
||||
QTextBlock from = doc->findBlock(start), till = doc->findBlock(end);
|
||||
if (till.isValid()) till = till.next();
|
||||
|
||||
for (QTextBlock b = from; b != till; b = b.next()) {
|
||||
for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) {
|
||||
QTextFragment fragment(iter.fragment());
|
||||
if (!fragment.isValid()) continue;
|
||||
|
||||
int32 fp = fragment.position(), fe = fp + fragment.length();
|
||||
if (fp >= end || fe <= start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString t(fragment.text());
|
||||
const QChar *ch = t.constData(), *e = ch + t.size();
|
||||
for (; ch != e; ++ch) {
|
||||
emoji = emojiFromText(ch, e, emojiLen);
|
||||
if (emoji) {
|
||||
emojiPosition = fp + (ch - t.constData());
|
||||
break;
|
||||
}
|
||||
if (ch + 1 < e && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
|
||||
}
|
||||
if (emoji) break;
|
||||
}
|
||||
if (emoji) break;
|
||||
}
|
||||
if (emoji) {
|
||||
if (!document()->pageSize().isNull()) {
|
||||
document()->setPageSize(QSizeF(0, 0));
|
||||
}
|
||||
|
||||
QTextCursor c(doc->docHandle(), emojiPosition);
|
||||
c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor);
|
||||
int32 removedUpto = c.position();
|
||||
|
||||
insertEmoji(emoji, c);
|
||||
|
||||
for (Insertions::iterator i = _insertions.begin(), e = _insertions.end(); i != e; ++i) {
|
||||
if (i->first >= removedUpto) {
|
||||
i->first -= removedUpto - emojiPosition - 1;
|
||||
} else if (i->first >= emojiPosition) {
|
||||
i->second -= removedUpto - emojiPosition;
|
||||
i->first = emojiPosition + 1;
|
||||
} else if (i->first + i->second > emojiPosition + 1) {
|
||||
i->second -= qMin(removedUpto, i->first + i->second) - emojiPosition;
|
||||
}
|
||||
}
|
||||
|
||||
charsAdded -= removedUpto - position;
|
||||
position = emojiPosition + 1;
|
||||
|
||||
emoji = 0;
|
||||
emojiPosition = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputField::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) {
|
||||
if (_replacingEmojis) return;
|
||||
|
||||
if (document()->availableRedoSteps() > 0) return;
|
||||
|
||||
const int takeBack = 3;
|
||||
|
||||
position -= takeBack;
|
||||
charsAdded += takeBack;
|
||||
if (position < 0) {
|
||||
charsAdded += position;
|
||||
position = 0;
|
||||
}
|
||||
if (charsAdded <= 0) return;
|
||||
|
||||
// _insertions.push_back(Insertion(position, charsAdded));
|
||||
_replacingEmojis = true;
|
||||
QSizeF s = document()->pageSize();
|
||||
processDocumentContentsChange(position, charsAdded);
|
||||
if (document()->pageSize() != s) {
|
||||
document()->setPageSize(s);
|
||||
}
|
||||
_replacingEmojis = false;
|
||||
}
|
||||
|
||||
void InputField::onDocumentContentsChanged() {
|
||||
if (_replacingEmojis) return;
|
||||
|
||||
if (!_insertions.isEmpty()) {
|
||||
if (document()->availableRedoSteps() > 0) {
|
||||
_insertions.clear();
|
||||
} else {
|
||||
_replacingEmojis = true;
|
||||
QSizeF s = document()->pageSize();
|
||||
|
||||
do {
|
||||
Insertion i = _insertions.front();
|
||||
_insertions.pop_front();
|
||||
if (i.second > 0) {
|
||||
processDocumentContentsChange(i.first, i.second);
|
||||
}
|
||||
} while (!_insertions.isEmpty());
|
||||
|
||||
if (document()->pageSize() != s) {
|
||||
document()->setPageSize(s);
|
||||
}
|
||||
_replacingEmojis = false;
|
||||
}
|
||||
}
|
||||
|
||||
QString curText(getText());
|
||||
if (_oldtext != curText) {
|
||||
_oldtext = curText;
|
||||
emit changed();
|
||||
}
|
||||
updatePlaceholder();
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
void InputField::onUndoAvailable(bool avail) {
|
||||
_undoAvailable = avail;
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
void InputField::onRedoAvailable(bool avail) {
|
||||
_redoAvailable = avail;
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
bool InputField::placeholderFgStep(float64 ms) {
|
||||
float dt = ms / _st->duration;
|
||||
bool res = true;
|
||||
@@ -582,9 +893,12 @@ bool InputField::borderStep(float64 ms) {
|
||||
update();
|
||||
return res;
|
||||
}
|
||||
const QString &InputField::getLastText() const {
|
||||
return _oldtext;
|
||||
}
|
||||
|
||||
void InputField::updatePlaceholder() {
|
||||
bool placeholderVisible = !_lastText.isEmpty();
|
||||
bool placeholderVisible = _oldtext.isEmpty();
|
||||
if (placeholderVisible != _placeholderVisible) {
|
||||
_placeholderVisible = placeholderVisible;
|
||||
|
||||
@@ -597,50 +911,71 @@ void InputField::updatePlaceholder() {
|
||||
void InputField::correctValue(QKeyEvent *e, const QString &was) {
|
||||
}
|
||||
|
||||
void InputField::keyPressEvent(QKeyEvent *e) {
|
||||
QString was(_lastText);
|
||||
QMimeData *InputField::createMimeDataFromSelection() const {
|
||||
QMimeData *result = new QMimeData();
|
||||
QTextCursor c(textCursor());
|
||||
int32 start = c.selectionStart(), end = c.selectionEnd();
|
||||
if (end > start) {
|
||||
result->setText(getText(start, end));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
_keyEvent = e;
|
||||
if (_customUpDown && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) {
|
||||
void InputField::customUpDown(bool custom) {
|
||||
_customUpDown = custom;
|
||||
}
|
||||
|
||||
void InputField::keyPressEvent(QKeyEvent *e) {
|
||||
bool shift = e->modifiers().testFlag(Qt::ShiftModifier);
|
||||
bool macmeta = (cPlatform() == dbipMac) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier);
|
||||
bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = (ctrl && cCtrlEnter()) || (!ctrl && !shift && !cCtrlEnter()) || (ctrl && shift);
|
||||
bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return);
|
||||
|
||||
if (macmeta && e->key() == Qt::Key_Backspace) {
|
||||
QTextCursor tc(textCursor()), start(tc);
|
||||
start.movePosition(QTextCursor::StartOfLine);
|
||||
tc.setPosition(start.position(), QTextCursor::KeepAnchor);
|
||||
tc.removeSelectedText();
|
||||
} else if (enter && ctrlGood) {
|
||||
emit submitted(ctrl && shift);
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
emit cancelled();
|
||||
} else if (e->key() == Qt::Key_Tab || (ctrl && e->key() == Qt::Key_Backtab)) {
|
||||
if (ctrl) {
|
||||
e->ignore();
|
||||
} else {
|
||||
emit tabbed();
|
||||
}
|
||||
} else if (e->key() == Qt::Key_Search || e == QKeySequence::Find) {
|
||||
e->ignore();
|
||||
} else {
|
||||
QLineEdit::keyPressEvent(e);
|
||||
}
|
||||
|
||||
if (was == _lastText) { // call correct manually
|
||||
correctValue(_keyEvent, was);
|
||||
_lastText = text();
|
||||
if (was != _lastText) emit changed();
|
||||
updatePlaceholder();
|
||||
}
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
emit cancelled();
|
||||
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
emit accepted();
|
||||
}
|
||||
_keyEvent = 0;
|
||||
}
|
||||
|
||||
void InputField::onTextEdited() {
|
||||
QString was(_lastText);
|
||||
correctValue(_keyEvent, was);
|
||||
_lastText = text();
|
||||
if (was != _lastText) emit changed();
|
||||
updatePlaceholder();
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
void InputField::onTextChange(const QString &text) {
|
||||
_lastText = text;
|
||||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
void InputField::setError(bool error) {
|
||||
if (error != _error) {
|
||||
_error = error;
|
||||
|
||||
a_borderFg.start((_error ? _st->borderFgError : (_focused ? _st->borderFgActive : _st->borderFg))->c);
|
||||
a_borderOpacityActive.start((_error || _focused) ? 1 : 0);
|
||||
_borderAnim.start();
|
||||
QTextCursor tc(textCursor());
|
||||
if (enter && ctrl) {
|
||||
e->setModifiers(e->modifiers() & ~Qt::ControlModifier);
|
||||
}
|
||||
QTextEdit::keyPressEvent(e);
|
||||
if (tc == textCursor()) {
|
||||
bool check = false;
|
||||
if (e->key() == Qt::Key_PageUp || e->key() == Qt::Key_Up) {
|
||||
tc.movePosition(QTextCursor::Start, e->modifiers().testFlag(Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
|
||||
check = true;
|
||||
} else if (e->key() == Qt::Key_PageDown || e->key() == Qt::Key_Down) {
|
||||
tc.movePosition(QTextCursor::End, e->modifiers().testFlag(Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
|
||||
check = true;
|
||||
}
|
||||
if (check) {
|
||||
if (tc == textCursor()) {
|
||||
e->ignore();
|
||||
} else {
|
||||
setTextCursor(tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputField::resizeEvent(QResizeEvent *e) {
|
||||
_placeholder = _st->font->m.elidedText(_placeholderFull, Qt::ElideRight, width() - _st->textMargins.left() - _st->textMargins.right() - _st->placeholderMargins.left() - _st->placeholderMargins.right() - 1);
|
||||
viewport()->setGeometry(rect().marginsRemoved(_st->textMargins));
|
||||
QTextEdit::resizeEvent(e);
|
||||
}
|
||||
|
@@ -38,7 +38,11 @@ public:
|
||||
|
||||
void notaBene();
|
||||
|
||||
void setPlaceholder(const QString &ph);
|
||||
void setPlaceholderFast(bool fast);
|
||||
void updatePlaceholder();
|
||||
const QString &placeholder() const;
|
||||
QRect placeholderRect() const;
|
||||
|
||||
QRect getTextRect() const;
|
||||
|
||||
@@ -68,9 +72,16 @@ protected:
|
||||
|
||||
virtual void correctValue(QKeyEvent *e, const QString &was);
|
||||
|
||||
style::font phFont() {
|
||||
return _st.font;
|
||||
}
|
||||
|
||||
void phPrepare(Painter &p);
|
||||
|
||||
private:
|
||||
|
||||
QString _ph, _fullph, _oldtext;
|
||||
bool _fastph;
|
||||
QKeyEvent *_kev;
|
||||
|
||||
bool _customUpDown;
|
||||
@@ -116,15 +127,118 @@ private:
|
||||
bool _nosignal;
|
||||
|
||||
};
|
||||
//
|
||||
//class InputField : public QTextEdit {
|
||||
// Q_OBJECT
|
||||
//
|
||||
//public:
|
||||
//
|
||||
// InputField(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString());
|
||||
//
|
||||
// bool event(QEvent *e);
|
||||
// void touchEvent(QTouchEvent *e);
|
||||
// void paintEvent(QPaintEvent *e);
|
||||
// void focusInEvent(QFocusEvent *e);
|
||||
// void focusOutEvent(QFocusEvent *e);
|
||||
// void keyPressEvent(QKeyEvent *e);
|
||||
// void resizeEvent(QResizeEvent *e);
|
||||
//
|
||||
// void setError(bool error);
|
||||
//
|
||||
// void updatePlaceholder();
|
||||
//
|
||||
// QRect getTextRect() const;
|
||||
//
|
||||
// bool placeholderFgStep(float64 ms);
|
||||
// bool placeholderShiftStep(float64 ms);
|
||||
// bool borderStep(float64 ms);
|
||||
//
|
||||
// QSize sizeHint() const;
|
||||
// QSize minimumSizeHint() const;
|
||||
//
|
||||
// void setCustomUpDown(bool customUpDown);
|
||||
//
|
||||
//public slots:
|
||||
//
|
||||
// void onTextChange(const QString &text);
|
||||
// void onTextEdited();
|
||||
//
|
||||
// void onTouchTimer();
|
||||
//
|
||||
// void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
||||
// void onDocumentContentsChanged();
|
||||
//
|
||||
// void onUndoAvailable(bool avail);
|
||||
// void onRedoAvailable(bool avail);
|
||||
//
|
||||
//signals:
|
||||
//
|
||||
// void changed();
|
||||
// void cancelled();
|
||||
// void accepted();
|
||||
// void focused();
|
||||
// void blurred();
|
||||
//
|
||||
//protected:
|
||||
//
|
||||
// virtual void correctValue(QKeyEvent *e, const QString &was);
|
||||
//
|
||||
// void insertEmoji(EmojiPtr emoji, QTextCursor c);
|
||||
// TWidget *tparent() {
|
||||
// return qobject_cast<TWidget*>(parentWidget());
|
||||
// }
|
||||
// const TWidget *tparent() const {
|
||||
// return qobject_cast<const TWidget*>(parentWidget());
|
||||
// }
|
||||
// void enterEvent(QEvent *e) {
|
||||
// TWidget *p(tparent());
|
||||
// if (p) p->leaveToChildEvent(e);
|
||||
// return QTextEdit::enterEvent(e);
|
||||
// }
|
||||
// void leaveEvent(QEvent *e) {
|
||||
// TWidget *p(tparent());
|
||||
// if (p) p->enterFromChildEvent(e);
|
||||
// return QTextEdit::leaveEvent(e);
|
||||
// }
|
||||
//
|
||||
// QVariant loadResource(int type, const QUrl &name);
|
||||
//
|
||||
//private:
|
||||
//
|
||||
// QString _lastText;
|
||||
// QKeyEvent *_keyEvent;
|
||||
//
|
||||
// bool _customUpDown;
|
||||
//
|
||||
// QString _placeholder, _placeholderFull;
|
||||
// bool _placeholderVisible;
|
||||
// anim::ivalue a_placeholderLeft;
|
||||
// anim::fvalue a_placeholderOpacity;
|
||||
// anim::cvalue a_placeholderFg;
|
||||
// Animation _placeholderFgAnim, _placeholderShiftAnim;
|
||||
//
|
||||
// anim::fvalue a_borderOpacityActive;
|
||||
// anim::cvalue a_borderFg;
|
||||
// Animation _borderAnim;
|
||||
//
|
||||
// bool _focused, _error;
|
||||
//
|
||||
// const style::InputField *_st;
|
||||
//
|
||||
// QTimer _touchTimer;
|
||||
// bool _touchPress, _touchRightButton, _touchMove;
|
||||
// QPoint _touchStart;
|
||||
//};
|
||||
|
||||
class InputField : public QLineEdit {
|
||||
|
||||
class InputField : public QTextEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
InputField(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString());
|
||||
|
||||
bool event(QEvent *e);
|
||||
bool viewportEvent(QEvent *e);
|
||||
void touchEvent(QTouchEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void focusInEvent(QFocusEvent *e);
|
||||
@@ -132,11 +246,11 @@ public:
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
void setError(bool error);
|
||||
|
||||
const QString &getLastText() const;
|
||||
void updatePlaceholder();
|
||||
|
||||
QRect getTextRect() const;
|
||||
int32 fakeMargin() const;
|
||||
|
||||
bool placeholderFgStep(float64 ms);
|
||||
bool placeholderShiftStep(float64 ms);
|
||||
@@ -145,50 +259,95 @@ public:
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
||||
void setCustomUpDown(bool customUpDown);
|
||||
QString getText(int32 start = 0, int32 end = -1) const;
|
||||
bool hasText() const;
|
||||
|
||||
bool isUndoAvailable() const;
|
||||
bool isRedoAvailable() const;
|
||||
|
||||
QMimeData *createMimeDataFromSelection() const;
|
||||
|
||||
void customUpDown(bool isCustom);
|
||||
|
||||
public slots:
|
||||
|
||||
void onTextChange(const QString &text);
|
||||
void onTextEdited();
|
||||
|
||||
void onTouchTimer();
|
||||
|
||||
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
||||
void onDocumentContentsChanged();
|
||||
|
||||
void onUndoAvailable(bool avail);
|
||||
void onRedoAvailable(bool avail);
|
||||
|
||||
signals:
|
||||
|
||||
void changed();
|
||||
void submitted(bool ctrlShiftEnter);
|
||||
void cancelled();
|
||||
void accepted();
|
||||
void tabbed();
|
||||
|
||||
void focused();
|
||||
void blurred();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void correctValue(QKeyEvent *e, const QString &was);
|
||||
|
||||
void insertEmoji(EmojiPtr emoji, QTextCursor c);
|
||||
TWidget *tparent() {
|
||||
return qobject_cast<TWidget*>(parentWidget());
|
||||
}
|
||||
const TWidget *tparent() const {
|
||||
return qobject_cast<const TWidget*>(parentWidget());
|
||||
}
|
||||
void enterEvent(QEvent *e) {
|
||||
TWidget *p(tparent());
|
||||
if (p) p->leaveToChildEvent(e);
|
||||
return QTextEdit::enterEvent(e);
|
||||
}
|
||||
void leaveEvent(QEvent *e) {
|
||||
TWidget *p(tparent());
|
||||
if (p) p->enterFromChildEvent(e);
|
||||
return QTextEdit::leaveEvent(e);
|
||||
}
|
||||
|
||||
QVariant loadResource(int type, const QUrl &name);
|
||||
|
||||
private:
|
||||
|
||||
QString _lastText;
|
||||
void processDocumentContentsChange(int position, int charsAdded);
|
||||
|
||||
QString _oldtext;
|
||||
|
||||
QKeyEvent *_keyEvent;
|
||||
|
||||
bool _customUpDown;
|
||||
bool _undoAvailable, _redoAvailable;
|
||||
|
||||
int32 _fakeMargin;
|
||||
|
||||
bool _customUpDown;
|
||||
|
||||
QString _placeholder, _placeholderFull;
|
||||
bool _placeholderVisible;
|
||||
anim::ivalue a_placeholderLeft;
|
||||
anim::fvalue a_placeholderOpacity;
|
||||
anim::cvalue a_placeholderFg;
|
||||
Animation _placeholderFgAnim, _placeholderShiftAnim;
|
||||
|
||||
|
||||
anim::fvalue a_borderOpacityActive;
|
||||
anim::cvalue a_borderFg;
|
||||
Animation _borderAnim;
|
||||
|
||||
|
||||
bool _focused, _error;
|
||||
|
||||
|
||||
const style::InputField *_st;
|
||||
|
||||
QTimer _touchTimer;
|
||||
bool _touchPress, _touchRightButton, _touchMove;
|
||||
QPoint _touchStart;
|
||||
|
||||
bool _replacingEmojis;
|
||||
typedef QPair<int, int> Insertion;
|
||||
typedef QList<Insertion> Insertions;
|
||||
Insertions _insertions;
|
||||
};
|
||||
|
@@ -128,7 +128,8 @@ int32 FlatTextarea::fakeMargin() const {
|
||||
|
||||
void FlatTextarea::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(viewport());
|
||||
p.fillRect(rect(), _st.bgColor->b);
|
||||
QRect r(rect().intersected(e->rect()));
|
||||
p.fillRect(r, _st.bgColor->b);
|
||||
bool phDraw = _phVisible;
|
||||
if (animating()) {
|
||||
p.setOpacity(a_phAlpha.current());
|
||||
@@ -136,7 +137,7 @@ void FlatTextarea::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
if (phDraw) {
|
||||
p.save();
|
||||
p.setClipRect(rect());
|
||||
p.setClipRect(r);
|
||||
QRect phRect(_st.textMrg.left() - _fakeMargin + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() - _fakeMargin + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
|
||||
p.setFont(_st.font->f);
|
||||
p.setPen(a_phColor.current());
|
||||
@@ -174,7 +175,10 @@ EmojiPtr FlatTextarea::getSingleEmoji() const {
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
QTextCharFormat format = fragment.charFormat();
|
||||
return emojiFromUrl(static_cast<const QTextImageFormat*>(&format)->name());
|
||||
QString imageName = static_cast<QTextImageFormat*>(&format)->name();
|
||||
if (imageName.startsWith(qstr("emoji://e."))) {
|
||||
return emojiFromUrl(imageName);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -303,7 +307,7 @@ void FlatTextarea::getSingleEmojiFragment(QString &text, QTextFragment &fragment
|
||||
}
|
||||
if (f.isImageFormat() && !t.isEmpty() && t.at(0).unicode() == QChar::ObjectReplacementCharacter) {
|
||||
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
|
||||
if (imageName.startsWith(QLatin1String("emoji://e."))) {
|
||||
if (imageName.startsWith(qstr("emoji://e."))) {
|
||||
fragment = fr;
|
||||
text = t;
|
||||
return;
|
||||
@@ -387,7 +391,7 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
|
||||
case QChar::ObjectReplacementCharacter:
|
||||
if (emojiText.isEmpty() && f.isImageFormat()) {
|
||||
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
|
||||
if (imageName.startsWith(QLatin1String("emoji://e."))) {
|
||||
if (imageName.startsWith(qstr("emoji://e."))) {
|
||||
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
|
||||
emojiText = emojiString(emoji);
|
||||
}
|
||||
@@ -530,17 +534,25 @@ void FlatTextarea::insertFromMimeData(const QMimeData *source) {
|
||||
}
|
||||
|
||||
void FlatTextarea::insertEmoji(EmojiPtr emoji, QTextCursor c) {
|
||||
c.removeSelectedText();
|
||||
|
||||
QPixmap img(App::emojiSingle(emoji, _st.font->height));
|
||||
QString url = qsl("emoji://e.") + QString::number(emojiKey(emoji), 16);
|
||||
document()->addResource(QTextDocument::ImageResource, QUrl(url), QVariant(img));
|
||||
QTextImageFormat imageFormat;
|
||||
imageFormat.setWidth(img.width() / cIntRetinaFactor());
|
||||
imageFormat.setHeight(img.height() / cIntRetinaFactor());
|
||||
imageFormat.setName(url);
|
||||
int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st.font->height * cIntRetinaFactor();
|
||||
imageFormat.setWidth(ew / cIntRetinaFactor());
|
||||
imageFormat.setHeight(eh / cIntRetinaFactor());
|
||||
imageFormat.setName(qsl("emoji://e.") + QString::number(emojiKey(emoji), 16));
|
||||
imageFormat.setVerticalAlignment(QTextCharFormat::AlignBaseline);
|
||||
c.insertImage(imageFormat);
|
||||
|
||||
static QString objectReplacement(QChar::ObjectReplacementCharacter);
|
||||
c.insertText(objectReplacement, imageFormat);
|
||||
}
|
||||
|
||||
QVariant FlatTextarea::loadResource(int type, const QUrl &name) {
|
||||
QString imageName = name.toDisplayString();
|
||||
if (imageName.startsWith(qstr("emoji://e."))) {
|
||||
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
|
||||
return QVariant(App::emojiSingle(emoji, _st.font->height));
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
@@ -579,6 +591,10 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
if (emoji) break;
|
||||
}
|
||||
if (emoji) {
|
||||
if (!document()->pageSize().isNull()) {
|
||||
document()->setPageSize(QSizeF(0, 0));
|
||||
}
|
||||
|
||||
QTextCursor c(doc->docHandle(), emojiPosition);
|
||||
c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor);
|
||||
int32 removedUpto = c.position();
|
||||
@@ -608,6 +624,8 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
||||
}
|
||||
|
||||
void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) {
|
||||
if (_replacingEmojis) return;
|
||||
|
||||
if (!_links.isEmpty()) {
|
||||
bool changed = false;
|
||||
for (LinkRanges::iterator i = _links.begin(); i != _links.end();) {
|
||||
@@ -624,7 +642,7 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int
|
||||
if (changed) emit linksChanged();
|
||||
}
|
||||
|
||||
if (_replacingEmojis || document()->availableRedoSteps() > 0) return;
|
||||
if (document()->availableRedoSteps() > 0) return;
|
||||
|
||||
const int takeBack = 3;
|
||||
|
||||
@@ -636,7 +654,14 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int
|
||||
}
|
||||
if (charsAdded <= 0) return;
|
||||
|
||||
_insertions.push_back(Insertion(position, charsAdded));
|
||||
// _insertions.push_back(Insertion(position, charsAdded));
|
||||
_replacingEmojis = true;
|
||||
QSizeF s = document()->pageSize();
|
||||
processDocumentContentsChange(position, charsAdded);
|
||||
if (document()->pageSize() != s) {
|
||||
document()->setPageSize(s);
|
||||
}
|
||||
_replacingEmojis = false;
|
||||
}
|
||||
|
||||
void FlatTextarea::onDocumentContentsChanged() {
|
||||
@@ -647,6 +672,8 @@ void FlatTextarea::onDocumentContentsChanged() {
|
||||
_insertions.clear();
|
||||
} else {
|
||||
_replacingEmojis = true;
|
||||
QSizeF s = document()->pageSize();
|
||||
|
||||
do {
|
||||
Insertion i = _insertions.front();
|
||||
_insertions.pop_front();
|
||||
@@ -654,6 +681,10 @@ void FlatTextarea::onDocumentContentsChanged() {
|
||||
processDocumentContentsChange(i.first, i.second);
|
||||
}
|
||||
} while (!_insertions.isEmpty());
|
||||
|
||||
if (document()->pageSize() != s) {
|
||||
document()->setPageSize(s);
|
||||
}
|
||||
_replacingEmojis = false;
|
||||
}
|
||||
}
|
||||
@@ -743,6 +774,8 @@ void FlatTextarea::keyPressEvent(QKeyEvent *e) {
|
||||
} else {
|
||||
emit tabbed();
|
||||
}
|
||||
} else if (e->key() == Qt::Key_Search || e == QKeySequence::Find) {
|
||||
e->ignore();
|
||||
} else {
|
||||
QTextCursor tc(textCursor());
|
||||
if (enter && ctrl) {
|
||||
@@ -781,7 +814,3 @@ void FlatTextarea::resizeEvent(QResizeEvent *e) {
|
||||
_phelided = _st.font->m.elidedText(_ph, Qt::ElideRight, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1);
|
||||
QTextEdit::resizeEvent(e);
|
||||
}
|
||||
|
||||
void FlatTextarea::mousePressEvent(QMouseEvent *e) {
|
||||
QTextEdit::mousePressEvent(e);
|
||||
}
|
||||
|
@@ -35,7 +35,6 @@ public:
|
||||
void focusOutEvent(QFocusEvent *e);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
const QString &getLastText() const;
|
||||
void updatePlaceholder();
|
||||
@@ -62,6 +61,8 @@ public:
|
||||
|
||||
void insertFromMimeData(const QMimeData *source);
|
||||
|
||||
QMimeData *createMimeDataFromSelection() const;
|
||||
|
||||
public slots:
|
||||
|
||||
void onTouchTimer();
|
||||
@@ -103,13 +104,13 @@ protected:
|
||||
return QTextEdit::leaveEvent(e);
|
||||
}
|
||||
|
||||
QVariant loadResource(int type, const QUrl &name);
|
||||
|
||||
private:
|
||||
|
||||
void getSingleEmojiFragment(QString &text, QTextFragment &fragment) const;
|
||||
void processDocumentContentsChange(int position, int charsAdded);
|
||||
|
||||
QMimeData *createMimeDataFromSelection() const;
|
||||
|
||||
QString _ph, _phelided, _oldtext;
|
||||
bool _phVisible;
|
||||
anim::ivalue a_phLeft;
|
||||
|
@@ -29,6 +29,9 @@ struct StorageImageLocation {
|
||||
}
|
||||
StorageImageLocation(int32 width, int32 height, const MTPDfileLocation &location) : width(width), height(height), dc(location.vdc_id.v), volume(location.vvolume_id.v), local(location.vlocal_id.v), secret(location.vsecret.v) {
|
||||
}
|
||||
bool isNull() const {
|
||||
return !dc;
|
||||
}
|
||||
int32 width, height;
|
||||
int32 dc;
|
||||
uint64 volume;
|
||||
@@ -36,6 +39,13 @@ struct StorageImageLocation {
|
||||
uint64 secret;
|
||||
};
|
||||
|
||||
inline bool operator==(const StorageImageLocation &a, const StorageImageLocation &b) {
|
||||
return !memcmp(&a, &b, sizeof(StorageImageLocation));
|
||||
}
|
||||
inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
class Image {
|
||||
public:
|
||||
|
||||
@@ -144,6 +154,10 @@ inline StorageKey storageKey(int32 dc, const uint64 &volume, int32 local) {
|
||||
inline StorageKey storageKey(const MTPDfileLocation &location) {
|
||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
}
|
||||
inline StorageKey storageKey(const StorageImageLocation &location) {
|
||||
return storageKey(location.dc, location.volume, location.local);
|
||||
}
|
||||
|
||||
enum StorageFileType {
|
||||
StorageFileUnknown = 0xaa963b05, // mtpc_storage_fileUnknown
|
||||
StorageFileJpeg = 0x7efe0e, // mtpc_storage_fileJpeg
|
||||
|
@@ -19,8 +19,30 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
#include "style.h"
|
||||
|
||||
#include "gui/phoneinput.h"
|
||||
#include "numbers.h"
|
||||
#include "lang.h"
|
||||
|
||||
PhoneInput::PhoneInput(QWidget *parent, const style::flatInput &st, const QString &ph) : FlatInput(parent, st, ph) {
|
||||
PhoneInput::PhoneInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st, lang(lng_phone_ph)) {
|
||||
}
|
||||
|
||||
void PhoneInput::paintEvent(QPaintEvent *e) {
|
||||
FlatInput::paintEvent(e);
|
||||
|
||||
Painter p(this);
|
||||
QString t(text());
|
||||
if (!pattern.isEmpty() && !t.isEmpty()) {
|
||||
QString ph = placeholder().mid(t.size());
|
||||
if (!ph.isEmpty()) {
|
||||
p.setClipRect(rect());
|
||||
QRect phRect(placeholderRect());
|
||||
int tw = phFont()->m.width(t);
|
||||
if (tw < phRect.width()) {
|
||||
phRect.setLeft(phRect.left() + tw);
|
||||
phPrepare(p);
|
||||
p.drawText(phRect, ph, style::al_left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneInput::correctValue(QKeyEvent *e, const QString &was) {
|
||||
@@ -36,34 +58,58 @@ void PhoneInput::correctValue(QKeyEvent *e, const QString &was) {
|
||||
}
|
||||
}
|
||||
if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength;
|
||||
bool strict = (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();
|
||||
}
|
||||
|
||||
QChar ch(oldText[i]);
|
||||
if (ch.isDigit()) {
|
||||
if (!digitCount--) {
|
||||
break;
|
||||
}
|
||||
newText += ch;
|
||||
if (strict && !digitCount) {
|
||||
break;
|
||||
if (inPart) {
|
||||
if (leftInPart) {
|
||||
--leftInPart;
|
||||
} else {
|
||||
newText += ' ';
|
||||
++curPart;
|
||||
inPart = curPart < pattern.size();
|
||||
leftInPart = inPart ? (pattern.at(curPart) - 1) : 0;
|
||||
|
||||
++oldPos;
|
||||
}
|
||||
}
|
||||
} else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') {
|
||||
newText += ch;
|
||||
}
|
||||
if (i == oldPos) {
|
||||
newPos = newText.length();
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
int32 newlen = newText.size();
|
||||
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
||||
--newlen;
|
||||
}
|
||||
if (newlen < newText.size()) newText = newText.mid(0, newlen);
|
||||
if (newPos < 0) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
if (newText != oldText) {
|
||||
setText(newText);
|
||||
if (newPos != oldPos) {
|
||||
setCursorPosition(newPos);
|
||||
}
|
||||
setCursorPosition(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +122,29 @@ void PhoneInput::addedToNumber(const QString &added) {
|
||||
updatePlaceholder();
|
||||
}
|
||||
|
||||
void PhoneInput::onChooseCode(const QString &code) {
|
||||
pattern = phoneNumberParse(code);
|
||||
if (!pattern.isEmpty() && pattern.at(0) == code.size()) {
|
||||
pattern.pop_front();
|
||||
} else {
|
||||
pattern.clear();
|
||||
}
|
||||
if (pattern.isEmpty()) {
|
||||
setPlaceholder(lang(lng_phone_ph));
|
||||
} else {
|
||||
QString ph;
|
||||
ph.reserve(20);
|
||||
for (int i = 0, l = pattern.size(); i < l; ++i) {
|
||||
ph.append(' ');
|
||||
ph.append(QString(QChar(0x2212)).repeated(pattern.at(i)));
|
||||
}
|
||||
setPlaceholder(ph);
|
||||
}
|
||||
correctValue(0, text());
|
||||
setPlaceholderFast(!pattern.isEmpty());
|
||||
updatePlaceholder();
|
||||
}
|
||||
|
||||
PortInput::PortInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val) : FlatInput(parent, st, ph, val) {
|
||||
correctValue(0, QString());
|
||||
}
|
||||
|
@@ -24,11 +24,14 @@ class PhoneInput : public FlatInput {
|
||||
|
||||
public:
|
||||
|
||||
PhoneInput(QWidget *parent, const style::flatInput &st, const QString &ph);
|
||||
PhoneInput(QWidget *parent, const style::flatInput &st);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
public slots:
|
||||
|
||||
void addedToNumber(const QString &added);
|
||||
void onChooseCode(const QString &code);
|
||||
|
||||
signals:
|
||||
|
||||
@@ -38,6 +41,10 @@ protected:
|
||||
|
||||
void correctValue(QKeyEvent *e, const QString &was);
|
||||
|
||||
private:
|
||||
|
||||
QVector<int> pattern;
|
||||
|
||||
};
|
||||
|
||||
class PortInput : public FlatInput {
|
||||
|
@@ -47,7 +47,7 @@ ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::flatScroll *st)
|
||||
_hideTimer.setSingleShot(true);
|
||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimer()));
|
||||
|
||||
connect(_connected, SIGNAL(valueChanged(int)), this, SLOT(updateBar()));
|
||||
connect(_connected, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged()));
|
||||
connect(_connected, SIGNAL(rangeChanged(int, int)), this, SLOT(updateBar()));
|
||||
|
||||
updateBar();
|
||||
@@ -57,6 +57,11 @@ void ScrollBar::recountSize() {
|
||||
setGeometry(_vertical ? QRect(rtl() ? 0 : (_area->width() - _st->width), _st->deltat, _st->width, _area->height() - _st->deltat - _st->deltab) : QRect(_st->deltat, _area->height() - _st->width, _area->width() - _st->deltat - _st->deltab, _st->width));
|
||||
}
|
||||
|
||||
void ScrollBar::onValueChanged() {
|
||||
_area->onScrolled();
|
||||
updateBar();
|
||||
}
|
||||
|
||||
void ScrollBar::updateBar(bool force) {
|
||||
QRect newBar;
|
||||
if (_connected->maximum() != _scrollMax) {
|
||||
@@ -266,8 +271,6 @@ _touchScrollState(TouchScrollManual), _touchPrevPosValid(false), _touchWaitingAc
|
||||
_touchSpeedTime(0), _touchAccelerationTime(0), _touchTime(0), _widgetAcceptsTouch(false) {
|
||||
setLayoutDirection(cLangDir());
|
||||
|
||||
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onScrolled()));
|
||||
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onScrolled()));
|
||||
connect(&vert, SIGNAL(topShadowVisibility(bool)), &topSh, SLOT(changeVisibility(bool)));
|
||||
connect(&vert, SIGNAL(bottomShadowVisibility(bool)), &bottomSh, SLOT(changeVisibility(bool)));
|
||||
vert.updateBar(true);
|
||||
@@ -297,6 +300,8 @@ void ScrollArea::touchDeaccelerate(int32 elapsed) {
|
||||
}
|
||||
|
||||
void ScrollArea::onScrolled() {
|
||||
myEnsureResized(widget());
|
||||
|
||||
bool em = false;
|
||||
int32 horValue = horizontalScrollBar()->value(), vertValue = verticalScrollBar()->value();
|
||||
if (_horValue != horValue) {
|
||||
@@ -325,27 +330,29 @@ void ScrollArea::onScrolled() {
|
||||
}
|
||||
|
||||
int ScrollArea::scrollWidth() const {
|
||||
return scrollLeftMax() + width();
|
||||
QWidget *w(widget());
|
||||
return w ? qMax(w->width(), width()) : width();
|
||||
}
|
||||
|
||||
int ScrollArea::scrollHeight() const {
|
||||
return scrollTopMax() + height();
|
||||
QWidget *w(widget());
|
||||
return w ? qMax(w->height(), height()) : height();
|
||||
}
|
||||
|
||||
int ScrollArea::scrollLeftMax() const {
|
||||
return horizontalScrollBar()->maximum();
|
||||
return scrollWidth() - width();
|
||||
}
|
||||
|
||||
int ScrollArea::scrollTopMax() const {
|
||||
return verticalScrollBar()->maximum();
|
||||
return scrollHeight() - height();
|
||||
}
|
||||
|
||||
int ScrollArea::scrollLeft() const {
|
||||
return horizontalScrollBar()->value();
|
||||
return _horValue;
|
||||
}
|
||||
|
||||
int ScrollArea::scrollTop() const {
|
||||
return verticalScrollBar()->value();
|
||||
return _vertValue;
|
||||
}
|
||||
|
||||
void ScrollArea::onTouchTimer() {
|
||||
@@ -612,6 +619,8 @@ void ScrollArea::leaveEvent(QEvent *e) {
|
||||
}
|
||||
|
||||
void ScrollArea::scrollToY(int toTop, int toBottom) {
|
||||
myEnsureResized(widget());
|
||||
|
||||
int toMin = 0, toMax = scrollTopMax();
|
||||
if (toTop < toMin) {
|
||||
toTop = toMin;
|
||||
|
@@ -70,6 +70,7 @@ public:
|
||||
|
||||
public slots:
|
||||
|
||||
void onValueChanged();
|
||||
void updateBar(bool force = false);
|
||||
void onHideTimer();
|
||||
|
||||
|
@@ -26,8 +26,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
#include <QtGui/QCursor>
|
||||
#include <QtGui/QFont>
|
||||
|
||||
inline QPoint rtlpoint(int x, int y, int outerw) {
|
||||
return QPoint(rtl() ? (outerw - x) : x, y);
|
||||
}
|
||||
inline QPoint rtlpoint(const QPoint &p, int outerw) {
|
||||
return rtl() ? QPoint(outerw - p.x(), p.y()) : p;
|
||||
}
|
||||
inline QRect rtlrect(int x, int y, int w, int h, int outerw) {
|
||||
return rtl() ? QRect(outerw - x - w, y, w, h) : QRect(x, y, w, h);
|
||||
return QRect(rtl() ? (outerw - x - w) : x, y, w, h);
|
||||
}
|
||||
inline QRect rtlrect(const QRect &r, int outerw) {
|
||||
return rtl() ? QRect(outerw - r.x() - r.width(), r.y(), r.width(), r.height()) : r;
|
||||
}
|
||||
inline QRect centerrect(const QRect &inRect, const QRect &rect) {
|
||||
return QRect(inRect.x() + (inRect.width() - rect.width()) / 2, inRect.y() + (inRect.height() - rect.height()) / 2, rect.width(), rect.height());
|
||||
|
@@ -24,7 +24,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
namespace {
|
||||
|
||||
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,10}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reExplicitDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){0,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$"));
|
||||
const QRegularExpression _reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
|
||||
@@ -863,7 +863,7 @@ public:
|
||||
}
|
||||
|
||||
void draw(int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, uint16 selectedFrom = 0, uint16 selectedTo = 0) {
|
||||
if (_t->_blocks.isEmpty()) return;
|
||||
if (_t->isEmpty()) return;
|
||||
|
||||
_blocksSize = _t->_blocks.size();
|
||||
if (!_textStyle) _initDefault();
|
||||
@@ -1043,7 +1043,7 @@ public:
|
||||
}
|
||||
|
||||
void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo, int32 removeFromEnd) {
|
||||
if (lines <= 0) return;
|
||||
if (lines <= 0 || _t->isNull()) return;
|
||||
|
||||
if (yTo < 0 || (lines - 1) * _t->_font->height < yTo) {
|
||||
yTo = lines * _t->_font->height;
|
||||
@@ -1057,7 +1057,7 @@ public:
|
||||
_lnkX = x;
|
||||
_lnkY = y;
|
||||
_lnkResult = &_zeroLnk;
|
||||
if (_lnkX >= 0 && _lnkX < w && _lnkY >= 0) {
|
||||
if (!_t->isNull() && _lnkX >= 0 && _lnkX < w && _lnkY >= 0) {
|
||||
draw(0, 0, w, align, _lnkY, _lnkY + 1);
|
||||
}
|
||||
return *_lnkResult;
|
||||
@@ -1067,7 +1067,7 @@ public:
|
||||
lnk = TextLinkPtr();
|
||||
inText = false;
|
||||
|
||||
if (x >= 0 && x < w && y >= 0) {
|
||||
if (!_t->isNull() && x >= 0 && x < w && y >= 0) {
|
||||
_lnkX = x;
|
||||
_lnkY = y;
|
||||
_lnkResult = &lnk;
|
||||
@@ -1081,8 +1081,7 @@ public:
|
||||
symbol = 0;
|
||||
after = false;
|
||||
upon = false;
|
||||
|
||||
if (y >= 0) {
|
||||
if (!_t->isNull() && y >= 0) {
|
||||
_lnkX = x;
|
||||
_lnkY = y;
|
||||
_getSymbol = &symbol;
|
||||
@@ -1615,25 +1614,36 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
style::font applyFlags(int32 flags, const style::font &f) {
|
||||
style::font result = f;
|
||||
if (flags & TextBlockBold) result = result->bold();
|
||||
if (flags & TextBlockItalic) result = result->italic();
|
||||
if (flags & TextBlockUnderline) result = result->underline();
|
||||
return result;
|
||||
}
|
||||
|
||||
void eSetFont(ITextBlock *block) {
|
||||
style::font newFont = _t->_font;
|
||||
int flags = block->flags();
|
||||
if (!flags && block->lnkIndex()) {
|
||||
if (flags) {
|
||||
newFont = applyFlags(flags, _t->_font);
|
||||
}
|
||||
if (block->lnkIndex()) {
|
||||
const TextLinkPtr &l(_t->_links.at(block->lnkIndex() - 1));
|
||||
if (l == _overLnk) {
|
||||
if (l == _downLnk || !_downLnk) {
|
||||
flags = _textStyle->lnkOverFlags->flags();
|
||||
if (_t->_font != _textStyle->lnkOverFlags) newFont = _textStyle->lnkOverFlags;
|
||||
} else {
|
||||
flags = _textStyle->lnkFlags->flags();
|
||||
if (_t->_font != _textStyle->lnkFlags) newFont = _textStyle->lnkFlags;
|
||||
}
|
||||
} else {
|
||||
flags = _textStyle->lnkFlags->flags();
|
||||
if (_t->_font != _textStyle->lnkFlags) newFont = _textStyle->lnkFlags;
|
||||
}
|
||||
}
|
||||
if (flags & TextBlockBold) newFont = newFont->bold();
|
||||
if (flags & TextBlockItalic) newFont = newFont->italic();
|
||||
if (flags & TextBlockUnderline) newFont = newFont->underline();
|
||||
if (newFont != _f) {
|
||||
if (newFont->family() == _t->_font->family()) {
|
||||
newFont = applyFlags(flags | newFont->flags(), _t->_font);
|
||||
}
|
||||
_f = newFont;
|
||||
_e->fnt = _f->f;
|
||||
_e->resetFontEngineCache();
|
||||
|
@@ -259,13 +259,23 @@ public:
|
||||
virtual QString encoded() const {
|
||||
return QString();
|
||||
}
|
||||
virtual const QLatin1String &type() const = 0;
|
||||
virtual ~ITextLink() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define TEXT_LINK_CLASS(ClassName) public: \
|
||||
const QLatin1String &type() const { \
|
||||
static const QLatin1String _type(qstr(#ClassName)); \
|
||||
return _type; \
|
||||
}
|
||||
|
||||
typedef QSharedPointer<ITextLink> TextLinkPtr;
|
||||
|
||||
class TextLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(TextLink)
|
||||
|
||||
public:
|
||||
|
||||
TextLink(const QString &url, bool fullDisplayed = true) : _url(url), _fullDisplayed(fullDisplayed) {
|
||||
@@ -289,7 +299,7 @@ public:
|
||||
|
||||
QString encoded() const {
|
||||
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
|
||||
QString result(good.isValid() ? good.toEncoded() : _url);
|
||||
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _url);
|
||||
|
||||
if (!QRegularExpression(qsl("^[a-zA-Z]+://")).match(result).hasMatch()) { // no protocol
|
||||
return qsl("http://") + result;
|
||||
@@ -305,6 +315,8 @@ private:
|
||||
};
|
||||
|
||||
class EmailLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(EmailLink)
|
||||
|
||||
public:
|
||||
|
||||
EmailLink(const QString &email) : _email(email) {
|
||||
@@ -335,6 +347,8 @@ private:
|
||||
};
|
||||
|
||||
class MentionLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(MentionLink)
|
||||
|
||||
public:
|
||||
|
||||
MentionLink(const QString &tag) : _tag(tag) {
|
||||
@@ -361,6 +375,8 @@ private:
|
||||
};
|
||||
|
||||
class HashtagLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(HashtagLink)
|
||||
|
||||
public:
|
||||
|
||||
HashtagLink(const QString &tag) : _tag(tag) {
|
||||
@@ -387,6 +403,8 @@ private:
|
||||
};
|
||||
|
||||
class BotCommandLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(BotCommandLink)
|
||||
|
||||
public:
|
||||
|
||||
BotCommandLink(const QString &cmd) : _cmd(cmd) {
|
||||
@@ -485,6 +503,9 @@ public:
|
||||
bool isEmpty() const {
|
||||
return _text.isEmpty();
|
||||
}
|
||||
bool isNull() const {
|
||||
return !_font;
|
||||
}
|
||||
QString original(uint16 selectedFrom = 0, uint16 selectedTo = 0xFFFF, bool expandLinks = true) const;
|
||||
|
||||
bool lastDots(int32 dots, int32 maxdots = 3) { // hack for typing animation
|
||||
|
@@ -34,12 +34,16 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
void myEnsureResized(QWidget *target) {
|
||||
if (target && (target->testAttribute(Qt::WA_PendingResizeEvent) || !target->testAttribute(Qt::WA_WState_Created))) {
|
||||
_sendResizeEvents(target);
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap myGrab(QWidget *target, const QRect &rect) {
|
||||
if (!cRetina()) return target->grab(rect);
|
||||
|
||||
if (target->testAttribute(Qt::WA_PendingResizeEvent) || !target->testAttribute(Qt::WA_WState_Created)) {
|
||||
_sendResizeEvents(target);
|
||||
}
|
||||
|
||||
myEnsureResized(target);
|
||||
|
||||
qreal dpr = App::app()->devicePixelRatio();
|
||||
QPixmap result(rect.size() * dpr);
|
||||
|
@@ -17,20 +17,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class Widget : public QWidget {
|
||||
public:
|
||||
|
||||
Widget(QWidget *parent = 0) : QWidget(parent) {
|
||||
}
|
||||
void moveToLeft(int x, int y, int outerw) {
|
||||
move(rtl() ? (outerw - x - width()) : x, y);
|
||||
}
|
||||
void moveToRight(int x, int y, int outerw) {
|
||||
move(rtl() ? x : (outerw - x - width()), y);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace App {
|
||||
const QPixmap &sprite();
|
||||
}
|
||||
@@ -119,14 +105,20 @@ public:
|
||||
void drawSpriteCenter(const QRect &in, const style::sprite &sprite) {
|
||||
return drawPixmap(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), App::sprite(), sprite);
|
||||
}
|
||||
void drawSpriteCenterLeft(const QRect &in, int outerw, const style::sprite &sprite) {
|
||||
return drawPixmapLeft(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), outerw, App::sprite(), sprite);
|
||||
}
|
||||
void drawSpriteCenterRight(const QRect &in, int outerw, const style::sprite &sprite) {
|
||||
return drawPixmapRight(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), outerw, App::sprite(), sprite);
|
||||
}
|
||||
};
|
||||
|
||||
class TWidget : public Widget {
|
||||
class TWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
TWidget(QWidget *parent = 0) : Widget(parent) {
|
||||
TWidget(QWidget *parent = 0) : QWidget(parent) {
|
||||
}
|
||||
TWidget *tparent() {
|
||||
return qobject_cast<TWidget*>(parentWidget());
|
||||
@@ -140,6 +132,27 @@ public:
|
||||
virtual void enterFromChildEvent(QEvent *e) { // e -- from leaveEvent() of child TWidget
|
||||
}
|
||||
|
||||
void moveToLeft(int x, int y, int outerw) {
|
||||
move(rtl() ? (outerw - x - width()) : x, y);
|
||||
}
|
||||
void moveToRight(int x, int y, int outerw) {
|
||||
move(rtl() ? x : (outerw - x - width()), y);
|
||||
}
|
||||
QPoint myrtlpoint(int x, int y) const {
|
||||
return rtlpoint(x, y, width());
|
||||
}
|
||||
QPoint myrtlpoint(const QPoint p) const {
|
||||
return rtlpoint(p, width());
|
||||
}
|
||||
QRect myrtlrect(int x, int y, int w, int h) const {
|
||||
return rtlrect(x, y, w, h, width());
|
||||
}
|
||||
QRect myrtlrect(const QRect &r) {
|
||||
return rtlrect(r, width());
|
||||
}
|
||||
void rtlupdate(const QRect &r) {
|
||||
update(myrtlrect(r));
|
||||
}
|
||||
bool event(QEvent *e) {
|
||||
return QWidget::event(e);
|
||||
}
|
||||
@@ -149,16 +162,17 @@ protected:
|
||||
void enterEvent(QEvent *e) {
|
||||
TWidget *p(tparent());
|
||||
if (p) p->leaveToChildEvent(e);
|
||||
return Widget::enterEvent(e);
|
||||
return QWidget::enterEvent(e);
|
||||
}
|
||||
void leaveEvent(QEvent *e) {
|
||||
TWidget *p(tparent());
|
||||
if (p) p->enterFromChildEvent(e);
|
||||
return Widget::leaveEvent(e);
|
||||
return QWidget::leaveEvent(e);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
void myEnsureResized(QWidget *target);
|
||||
QPixmap myGrab(QWidget *target, const QRect &rect);
|
||||
|
Reference in New Issue
Block a user