Add support for Underline and Strike-through text.

This commit is contained in:
John Preston 2019-06-23 15:40:59 +02:00
parent d864ebd695
commit 8741266819
13 changed files with 166 additions and 39 deletions

View File

@ -1536,6 +1536,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_menu_formatting" = "Formatting"; "lng_menu_formatting" = "Formatting";
"lng_menu_formatting_bold" = "Bold"; "lng_menu_formatting_bold" = "Bold";
"lng_menu_formatting_italic" = "Italic"; "lng_menu_formatting_italic" = "Italic";
"lng_menu_formatting_underline" = "Underline";
"lng_menu_formatting_strike_out" = "Strike-through";
"lng_menu_formatting_monospace" = "Monospace"; "lng_menu_formatting_monospace" = "Monospace";
"lng_menu_formatting_link_create" = "Create link"; "lng_menu_formatting_link_create" = "Create link";
"lng_menu_formatting_link_edit" = "Edit link"; "lng_menu_formatting_link_edit" = "Edit link";

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/text/text_utilities.h"
#include "core/click_handler_types.h" // UrlClickHandler #include "core/click_handler_types.h" // UrlClickHandler
#include "base/qthelp_url.h" // qthelp::url_encode #include "base/qthelp_url.h" // qthelp::url_encode
#include "platform/platform_info.h" // Platform::SystemVersionPretty #include "platform/platform_info.h" // Platform::SystemVersionPretty
@ -268,15 +269,13 @@ void ConfirmPhoneBox::launch() {
} }
void ConfirmPhoneBox::prepare() { void ConfirmPhoneBox::prepare() {
_about.create(this, st::confirmPhoneAboutLabel); _about.create(
TextWithEntities aboutText; this,
auto formattedPhone = App::formatPhone(_phone); tr::lng_confirm_phone_about(
aboutText.text = tr::lng_confirm_phone_about(tr::now, lt_phone, formattedPhone); lt_phone,
auto phonePosition = aboutText.text.indexOf(formattedPhone); rpl::single(Ui::Text::Bold(App::formatPhone(_phone))),
if (phonePosition >= 0) { Ui::Text::WithEntities),
aboutText.entities.push_back({ EntityType::Bold, phonePosition, formattedPhone.size() }); st::confirmPhoneAboutLabel);
}
_about->setMarkedText(aboutText);
_code.create(this, st::confirmPhoneCodeField, tr::lng_code_ph()); _code.create(this, st::confirmPhoneCodeField, tr::lng_code_ph());
_code->setAutoSubmit(_sentCodeLength, [=] { sendCode(); }); _code->setAutoSubmit(_sentCodeLength, [=] { sendCode(); });

View File

@ -237,6 +237,10 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
push(EntityType::Bold); push(EntityType::Bold);
} else if (tag.id == Ui::InputField::kTagItalic) { } else if (tag.id == Ui::InputField::kTagItalic) {
push(EntityType::Italic); push(EntityType::Italic);
} else if (tag.id == Ui::InputField::kTagUnderline) {
push(EntityType::Underline);
} else if (tag.id == Ui::InputField::kTagStrikeOut) {
push(EntityType::StrikeOut);
} else if (tag.id == Ui::InputField::kTagCode) { } else if (tag.id == Ui::InputField::kTagCode) {
push(EntityType::Code); push(EntityType::Code);
} else if (tag.id == Ui::InputField::kTagPre) { // #TODO entities } else if (tag.id == Ui::InputField::kTagPre) { // #TODO entities
@ -274,8 +278,14 @@ TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) {
} }
} break; } break;
case EntityType::Bold: push(Ui::InputField::kTagBold); break; case EntityType::Bold: push(Ui::InputField::kTagBold); break;
case EntityType::Italic: push(Ui::InputField::kTagItalic); break; // #TODO entities case EntityType::Italic: push(Ui::InputField::kTagItalic); break;
case EntityType::Code: push(Ui::InputField::kTagCode); break; case EntityType::Underline:
push(Ui::InputField::kTagUnderline);
break;
case EntityType::StrikeOut:
push(Ui::InputField::kTagStrikeOut);
break;
case EntityType::Code: push(Ui::InputField::kTagCode); break; // #TODO entities
case EntityType::Pre: push(Ui::InputField::kTagPre); break; case EntityType::Pre: push(Ui::InputField::kTagPre); break;
} }
} }

View File

@ -64,6 +64,7 @@ FontData::FontData(int size, uint32 flags, int family, Font *other)
} }
f.setItalic(_flags & FontItalic); f.setItalic(_flags & FontItalic);
f.setUnderline(_flags & FontUnderline); f.setUnderline(_flags & FontUnderline);
f.setStrikeOut(_flags & FontStrikeOut);
f.setStyleStrategy(QFont::PreferQuality); f.setStyleStrategy(QFont::PreferQuality);
m = QFontMetrics(f); m = QFontMetrics(f);
@ -86,6 +87,10 @@ Font FontData::underline(bool set) const {
return otherFlagsFont(FontUnderline, set); return otherFlagsFont(FontUnderline, set);
} }
Font FontData::strikeout(bool set) const {
return otherFlagsFont(FontStrikeOut, set);
}
int FontData::size() const { int FontData::size() const {
return _size; return _size;
} }

View File

@ -56,8 +56,9 @@ enum FontFlags {
FontBold = 0x01, FontBold = 0x01,
FontItalic = 0x02, FontItalic = 0x02,
FontUnderline = 0x04, FontUnderline = 0x04,
FontStrikeOut = 0x08,
FontDifferentFlags = 0x08, FontDifferentFlags = 0x10,
}; };
class FontData { class FontData {
@ -79,6 +80,7 @@ public:
Font bold(bool set = true) const; Font bold(bool set = true) const;
Font italic(bool set = true) const; Font italic(bool set = true) const;
Font underline(bool set = true) const; Font underline(bool set = true) const;
Font strikeout(bool set = true) const;
int size() const; int size() const;
uint32 flags() const; uint32 flags() const;

View File

@ -84,7 +84,12 @@ TextWithEntities PrepareRichFromRich(
(type == EntityType::Hashtag && !parseHashtags) || (type == EntityType::Hashtag && !parseHashtags) ||
(type == EntityType::Cashtag && !parseHashtags) || (type == EntityType::Cashtag && !parseHashtags) ||
(type == EntityType::BotCommand && !parseBotCommands) || // #TODO entities (type == EntityType::BotCommand && !parseBotCommands) || // #TODO entities
((type == EntityType::Bold || type == EntityType::Italic || type == EntityType::Code || type == EntityType::Pre) && !parseMarkdown)) { (!parseMarkdown && (type == EntityType::Bold
|| type == EntityType::Italic
|| type == EntityType::Underline
|| type == EntityType::StrikeOut
|| type == EntityType::Code
|| type == EntityType::Pre))) {
continue; continue;
} }
result.entities.push_back(preparsed.at(i)); result.entities.push_back(preparsed.at(i));
@ -545,6 +550,10 @@ bool Parser::checkEntities() {
flags = TextBlockFSemibold; flags = TextBlockFSemibold;
} else if (entityType == EntityType::Italic) { } else if (entityType == EntityType::Italic) {
flags = TextBlockFItalic; flags = TextBlockFItalic;
} else if (entityType == EntityType::Underline) {
flags = TextBlockFUnderline;
} else if (entityType == EntityType::StrikeOut) {
flags = TextBlockFStrikeOut;
} else if (entityType == EntityType::Code) { // #TODO entities } else if (entityType == EntityType::Code) { // #TODO entities
flags = TextBlockFCode; flags = TextBlockFCode;
} else if (entityType == EntityType::Pre) { } else if (entityType == EntityType::Pre) {
@ -699,6 +708,20 @@ bool Parser::readCommand() {
} }
break; break;
case TextCommandStrikeOut:
if (!(_flags & TextBlockFStrikeOut)) {
createBlock();
_flags |= TextBlockFStrikeOut;
}
break;
case TextCommandNoStrikeOut:
if (_flags & TextBlockFStrikeOut) {
createBlock();
_flags &= ~TextBlockFStrikeOut;
}
break;
case TextCommandLinkIndex: case TextCommandLinkIndex:
if (_ptr->unicode() != _lnkIndex) { if (_ptr->unicode() != _lnkIndex) {
createBlock(); createBlock();
@ -2035,6 +2058,7 @@ private:
} }
if (flags & TextBlockFItalic) result = result->italic(); if (flags & TextBlockFItalic) result = result->italic();
if (flags & TextBlockFUnderline) result = result->underline(); if (flags & TextBlockFUnderline) result = result->underline();
if (flags & TextBlockFStrikeOut) result = result->strikeout();
if (flags & TextBlockFTilde) { // tilde fix in OpenSans if (flags & TextBlockFTilde) { // tilde fix in OpenSans
result = st::semiboldFont; result = st::semiboldFont;
} }
@ -3217,6 +3241,8 @@ TextForMimeData String::toText(
? std::vector<MarkdownTagTracker>{ ? std::vector<MarkdownTagTracker>{
{ TextBlockFItalic, EntityType::Italic }, { TextBlockFItalic, EntityType::Italic },
{ TextBlockFSemibold, EntityType::Bold }, { TextBlockFSemibold, EntityType::Bold },
{ TextBlockFUnderline, EntityType::Underline },
{ TextBlockFStrikeOut, EntityType::StrikeOut },
{ TextBlockFCode, EntityType::Code }, // #TODO entities { TextBlockFCode, EntityType::Code }, // #TODO entities
{ TextBlockFPre, EntityType::Pre } { TextBlockFPre, EntityType::Pre }
} : std::vector<MarkdownTagTracker>(); } : std::vector<MarkdownTagTracker>();

View File

@ -21,10 +21,12 @@ enum TextCommands {
TextCommandNoItalic = 0x04, TextCommandNoItalic = 0x04,
TextCommandUnderline = 0x05, TextCommandUnderline = 0x05,
TextCommandNoUnderline = 0x06, TextCommandNoUnderline = 0x06,
TextCommandSemibold = 0x07, TextCommandStrikeOut = 0x07,
TextCommandNoSemibold = 0x08, TextCommandNoStrikeOut = 0x08,
TextCommandLinkIndex = 0x09, // 0 - NoLink TextCommandSemibold = 0x09,
TextCommandLinkText = 0x0A, TextCommandNoSemibold = 0x0A,
TextCommandLinkIndex = 0x0B, // 0 - NoLink
TextCommandLinkText = 0x0C,
TextCommandSkipBlock = 0x0D, TextCommandSkipBlock = 0x0D,
TextCommandLangTag = 0x20, TextCommandLangTag = 0x20,

View File

@ -322,6 +322,7 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
} }
if (flags & TextBlockFItalic) blockFont = blockFont->italic(); if (flags & TextBlockFItalic) blockFont = blockFont->italic();
if (flags & TextBlockFUnderline) blockFont = blockFont->underline(); if (flags & TextBlockFUnderline) blockFont = blockFont->underline();
if (flags & TextBlockFStrikeOut) blockFont = blockFont->strikeout();
if (flags & TextBlockFTilde) { // tilde fix in OpenSans if (flags & TextBlockFTilde) { // tilde fix in OpenSans
blockFont = st::semiboldFont; blockFont = st::semiboldFont;
} }

View File

@ -23,10 +23,11 @@ enum TextBlockFlags {
TextBlockFBold = 0x01, TextBlockFBold = 0x01,
TextBlockFItalic = 0x02, TextBlockFItalic = 0x02,
TextBlockFUnderline = 0x04, TextBlockFUnderline = 0x04,
TextBlockFTilde = 0x08, // tilde fix in OpenSans TextBlockFStrikeOut = 0x08,
TextBlockFSemibold = 0x10, TextBlockFTilde = 0x10, // tilde fix in OpenSans
TextBlockFCode = 0x20, TextBlockFSemibold = 0x20,
TextBlockFPre = 0x40, TextBlockFCode = 0x40,
TextBlockFPre = 0x80,
}; };
class AbstractBlock { class AbstractBlock {

View File

@ -36,7 +36,7 @@ QString ExpressionSeparators(const QString &additional) {
QString Separators(const QString &additional) { QString Separators(const QString &additional) {
static const auto quotes = Quotes(); static const auto quotes = Quotes();
return qsl(" \x10\n\r\t.,:;<>|'\"[]{}~!?%^()-+=") return qsl(" \x10\n\r\t.,:;<>|'\"[]{}!?%^()-+=")
+ QChar(0xfdd0) // QTextBeginningOfFrame + QChar(0xfdd0) // QTextBeginningOfFrame
+ QChar(0xfdd1) // QTextEndOfFrame + QChar(0xfdd1) // QTextEndOfFrame
+ QChar(QChar::ParagraphSeparator) + QChar(QChar::ParagraphSeparator)
@ -46,15 +46,19 @@ QString Separators(const QString &additional) {
} }
QString SeparatorsBold() { QString SeparatorsBold() {
return Separators(qsl("`/")); return Separators(qsl("`~/"));
} }
QString SeparatorsItalic() { QString SeparatorsItalic() {
return Separators(qsl("`*/")); return Separators(qsl("`*~/"));
}
QString SeparatorsStrikeOut() {
return Separators(qsl("`*~/"));
} }
QString SeparatorsMono() { QString SeparatorsMono() {
return Separators(qsl("*/")); return Separators(qsl("*~/"));
} }
QString ExpressionHashtag() { QString ExpressionHashtag() {
@ -1173,6 +1177,14 @@ QString MarkdownItalicBadAfter() {
return qsl("_"); return qsl("_");
} }
QString MarkdownStrikeOutGoodBefore() {
return SeparatorsStrikeOut();
}
QString MarkdownStrikeOutBadAfter() {
return qsl("~");
}
QString MarkdownCodeGoodBefore() { QString MarkdownCodeGoodBefore() {
return SeparatorsMono(); return SeparatorsMono();
} }
@ -1500,6 +1512,8 @@ EntitiesInText EntitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset.v, d.vlength.v }); } break; case mtpc_messageEntityBotCommand: { auto &d = entity.c_messageEntityBotCommand(); result.push_back({ EntityType::BotCommand, d.voffset.v, d.vlength.v }); } break;
case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset.v, d.vlength.v }); } break; case mtpc_messageEntityBold: { auto &d = entity.c_messageEntityBold(); result.push_back({ EntityType::Bold, d.voffset.v, d.vlength.v }); } break;
case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset.v, d.vlength.v }); } break; case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset.v, d.vlength.v }); } break;
case mtpc_messageEntityUnderline: { auto &d = entity.c_messageEntityUnderline(); result.push_back({ EntityType::Underline, d.voffset.v, d.vlength.v }); } break;
case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset.v, d.vlength.v }); } break;
case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset.v, d.vlength.v }); } break; case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset.v, d.vlength.v }); } break;
case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset.v, d.vlength.v, Clean(qs(d.vlanguage)) }); } break; case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset.v, d.vlength.v, Clean(qs(d.vlanguage)) }); } break;
// #TODO entities // #TODO entities
@ -1517,6 +1531,8 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(const EntitiesInText &entities, Conver
if (option == ConvertOption::SkipLocal if (option == ConvertOption::SkipLocal
&& entity.type() != EntityType::Bold && entity.type() != EntityType::Bold
&& entity.type() != EntityType::Italic && entity.type() != EntityType::Italic
&& entity.type() != EntityType::Underline
&& entity.type() != EntityType::StrikeOut
&& entity.type() != EntityType::Code // #TODO entities && entity.type() != EntityType::Code // #TODO entities
&& entity.type() != EntityType::Pre && entity.type() != EntityType::Pre
&& entity.type() != EntityType::MentionName && entity.type() != EntityType::MentionName
@ -1550,6 +1566,8 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(const EntitiesInText &entities, Conver
case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break; case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break;
case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break; case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break;
case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break; case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break;
case EntityType::Underline: v.push_back(MTP_messageEntityUnderline(offset, length)); break;
case EntityType::StrikeOut: v.push_back(MTP_messageEntityStrike(offset, length)); break;
case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities
case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break; case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break;
} }

View File

@ -21,6 +21,8 @@ enum class EntityType {
Bold, Bold,
Italic, Italic,
Underline,
StrikeOut,
Code, // inline Code, // inline
Pre, // block Pre, // block
}; };
@ -267,6 +269,8 @@ QString MarkdownBoldGoodBefore();
QString MarkdownBoldBadAfter(); QString MarkdownBoldBadAfter();
QString MarkdownItalicGoodBefore(); QString MarkdownItalicGoodBefore();
QString MarkdownItalicBadAfter(); QString MarkdownItalicBadAfter();
QString MarkdownStrikeOutGoodBefore();
QString MarkdownStrikeOutBadAfter();
QString MarkdownCodeGoodBefore(); QString MarkdownCodeGoodBefore();
QString MarkdownCodeBadAfter(); QString MarkdownCodeBadAfter();
QString MarkdownPreGoodBefore(); QString MarkdownPreGoodBefore();

View File

@ -38,6 +38,8 @@ const auto kObjectReplacement = QString::fromRawData(
1); 1);
const auto &kTagBold = InputField::kTagBold; const auto &kTagBold = InputField::kTagBold;
const auto &kTagItalic = InputField::kTagItalic; const auto &kTagItalic = InputField::kTagItalic;
const auto &kTagUnderline = InputField::kTagUnderline;
const auto &kTagStrikeOut = InputField::kTagStrikeOut;
const auto &kTagCode = InputField::kTagCode; const auto &kTagCode = InputField::kTagCode;
const auto &kTagPre = InputField::kTagPre; const auto &kTagPre = InputField::kTagPre;
const auto kNewlineChars = QString("\r\n") const auto kNewlineChars = QString("\r\n")
@ -46,6 +48,7 @@ const auto kNewlineChars = QString("\r\n")
+ QChar(QChar::ParagraphSeparator) + QChar(QChar::ParagraphSeparator)
+ QChar(QChar::LineSeparator); + QChar(QChar::LineSeparator);
const auto kClearFormatSequence = QKeySequence("ctrl+shift+n"); const auto kClearFormatSequence = QKeySequence("ctrl+shift+n");
const auto kStrikeOutSequence = QKeySequence("ctrl+shift+x");
const auto kMonospaceSequence = QKeySequence("ctrl+shift+m"); const auto kMonospaceSequence = QKeySequence("ctrl+shift+m");
const auto kEditLinkSequence = QKeySequence("ctrl+k"); const auto kEditLinkSequence = QKeySequence("ctrl+k");
@ -175,12 +178,16 @@ struct TagStartExpression {
QString tag; QString tag;
QString goodBefore; QString goodBefore;
QString badAfter; QString badAfter;
QString badBefore;
QString goodAfter;
}; };
constexpr auto kTagBoldIndex = 0; constexpr auto kTagBoldIndex = 0;
constexpr auto kTagItalicIndex = 1; constexpr auto kTagItalicIndex = 1;
constexpr auto kTagCodeIndex = 2; //constexpr auto kTagUnderlineIndex = 2;
constexpr auto kTagPreIndex = 3; constexpr auto kTagStrikeOutIndex = 2;
constexpr auto kTagCodeIndex = 3;
constexpr auto kTagPreIndex = 4;
constexpr auto kInvalidPosition = std::numeric_limits<int>::max() / 2; constexpr auto kInvalidPosition = std::numeric_limits<int>::max() / 2;
class TagSearchItem { class TagSearchItem {
@ -208,24 +215,34 @@ public:
const auto length = text.size(); const auto length = text.size();
const auto &tag = expression.tag; const auto &tag = expression.tag;
const auto tagLength = tag.size(); const auto tagLength = tag.size();
const auto isGood = [&](QChar ch) { const auto isGoodBefore = [&](QChar ch) {
return (expression.goodBefore.indexOf(ch) >= 0); return expression.goodBefore.isEmpty()
|| (expression.goodBefore.indexOf(ch) >= 0);
}; };
const auto isBad = [&](QChar ch) { const auto isBadAfter = [&](QChar ch) {
return (expression.badAfter.indexOf(ch) >= 0); return !expression.badAfter.isEmpty()
&& (expression.badAfter.indexOf(ch) >= 0);
};
const auto isBadBefore = [&](QChar ch) {
return !expression.badBefore.isEmpty()
&& (expression.badBefore.indexOf(ch) >= 0);
};
const auto isGoodAfter = [&](QChar ch) {
return expression.goodAfter.isEmpty()
|| (expression.goodAfter.indexOf(ch) >= 0);
}; };
const auto check = [&](Edge edge) { const auto check = [&](Edge edge) {
if (_position > 0) { if (_position > 0) {
const auto before = text[_position - 1]; const auto before = text[_position - 1];
if ((edge == Edge::Open && !isGood(before)) if ((edge == Edge::Open && !isGoodBefore(before))
|| (edge == Edge::Close && isBad(before))) { || (edge == Edge::Close && isBadBefore(before))) {
return false; return false;
} }
} }
if (_position + tagLength < length) { if (_position + tagLength < length) {
const auto after = text[_position + tagLength]; const auto after = text[_position + tagLength];
if ((edge == Edge::Open && isBad(after)) if ((edge == Edge::Open && isBadAfter(after))
|| (edge == Edge::Close && !isGood(after))) { || (edge == Edge::Close && !isGoodAfter(after))) {
return false; return false;
} }
} }
@ -275,22 +292,44 @@ const std::vector<TagStartExpression> &TagStartExpressions() {
{ {
kTagBold, kTagBold,
TextUtilities::MarkdownBoldGoodBefore(), TextUtilities::MarkdownBoldGoodBefore(),
TextUtilities::MarkdownBoldBadAfter() TextUtilities::MarkdownBoldBadAfter(),
TextUtilities::MarkdownBoldBadAfter(),
TextUtilities::MarkdownBoldGoodBefore()
}, },
{ {
kTagItalic, kTagItalic,
TextUtilities::MarkdownItalicGoodBefore(), TextUtilities::MarkdownItalicGoodBefore(),
TextUtilities::MarkdownItalicBadAfter() TextUtilities::MarkdownItalicBadAfter(),
TextUtilities::MarkdownItalicBadAfter(),
TextUtilities::MarkdownItalicGoodBefore()
},
//{
// kTagUnderline,
// TextUtilities::MarkdownUnderlineGoodBefore(),
// TextUtilities::MarkdownUnderlineBadAfter(),
// TextUtilities::MarkdownUnderlineBadAfter(),
// TextUtilities::MarkdownUnderlineGoodBefore()
//},
{
kTagStrikeOut,
TextUtilities::MarkdownStrikeOutGoodBefore(),
TextUtilities::MarkdownStrikeOutBadAfter(),
TextUtilities::MarkdownStrikeOutBadAfter(),
QString(),
}, },
{ {
kTagCode, kTagCode,
TextUtilities::MarkdownCodeGoodBefore(), TextUtilities::MarkdownCodeGoodBefore(),
TextUtilities::MarkdownCodeBadAfter() TextUtilities::MarkdownCodeBadAfter(),
TextUtilities::MarkdownCodeBadAfter(),
TextUtilities::MarkdownCodeGoodBefore()
}, },
{ {
kTagPre, kTagPre,
TextUtilities::MarkdownPreGoodBefore(), TextUtilities::MarkdownPreGoodBefore(),
TextUtilities::MarkdownPreBadAfter() TextUtilities::MarkdownPreBadAfter(),
TextUtilities::MarkdownPreBadAfter(),
TextUtilities::MarkdownPreGoodBefore()
}, },
}; };
return cached; return cached;
@ -300,6 +339,8 @@ const std::map<QString, int> &TagIndices() {
static auto cached = std::map<QString, int> { static auto cached = std::map<QString, int> {
{ kTagBold, kTagBoldIndex }, { kTagBold, kTagBoldIndex },
{ kTagItalic, kTagItalicIndex }, { kTagItalic, kTagItalicIndex },
//{ kTagUnderline, kTagUnderlineIndex },
{ kTagStrikeOut, kTagStrikeOutIndex },
{ kTagCode, kTagCodeIndex }, { kTagCode, kTagCodeIndex },
{ kTagPre, kTagPreIndex }, { kTagPre, kTagPreIndex },
}; };
@ -646,6 +687,12 @@ QTextCharFormat PrepareTagFormat(
} else if (tag == kTagItalic) { } else if (tag == kTagItalic) {
result.setForeground(st.textFg); result.setForeground(st.textFg);
result.setFont(st.font->italic()); result.setFont(st.font->italic());
} else if (tag == kTagUnderline) {
result.setForeground(st.textFg);
result.setFont(st.font->underline());
} else if (tag == kTagStrikeOut) {
result.setForeground(st.textFg);
result.setFont(st.font->strikeout());
} else if (tag == kTagCode || tag == kTagPre) { } else if (tag == kTagCode || tag == kTagPre) {
result.setForeground(st::defaultTextPalette.monoFg); result.setForeground(st::defaultTextPalette.monoFg);
result.setFont(AdjustFont(App::monofont(), st.font)); result.setFont(AdjustFont(App::monofont(), st.font));
@ -794,6 +841,8 @@ QString ExpandCustomLinks(const TextWithTags &text) {
const QString InputField::kTagBold = qsl("**"); const QString InputField::kTagBold = qsl("**");
const QString InputField::kTagItalic = 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::kTagCode = qsl("`");
const QString InputField::kTagPre = qsl("```"); const QString InputField::kTagPre = qsl("```");
@ -2694,6 +2743,10 @@ bool InputField::handleMarkdownKey(QKeyEvent *e) {
toggleSelectionMarkdown(kTagBold); toggleSelectionMarkdown(kTagBold);
} else if (e == QKeySequence::Italic) { } else if (e == QKeySequence::Italic) {
toggleSelectionMarkdown(kTagItalic); toggleSelectionMarkdown(kTagItalic);
} else if (e == QKeySequence::Underline) {
toggleSelectionMarkdown(kTagUnderline);
} else if (matches(kStrikeOutSequence)) {
toggleSelectionMarkdown(kTagStrikeOut);
} else if (matches(kMonospaceSequence)) { } else if (matches(kMonospaceSequence)) {
toggleSelectionMarkdown(kTagCode); toggleSelectionMarkdown(kTagCode);
} else if (matches(kClearFormatSequence)) { } else if (matches(kClearFormatSequence)) {
@ -3358,6 +3411,8 @@ void InputField::addMarkdownActions(
addtag(tr::lng_menu_formatting_bold(tr::now), QKeySequence::Bold, kTagBold); 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_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(tr::lng_menu_formatting_monospace(tr::now), kMonospaceSequence, kTagCode);
if (_editLinkCallback) { if (_editLinkCallback) {

View File

@ -151,6 +151,8 @@ public:
}; };
static const QString kTagBold; static const QString kTagBold;
static const QString kTagItalic; static const QString kTagItalic;
static const QString kTagUnderline;
static const QString kTagStrikeOut;
static const QString kTagCode; static const QString kTagCode;
static const QString kTagPre; static const QString kTagPre;