diff --git a/src/textutil.cpp b/src/textutil.cpp index 81209a1f1..d0f278008 100644 --- a/src/textutil.cpp +++ b/src/textutil.cpp @@ -294,7 +294,7 @@ static void emojiconifyPlainText(RTParse &p, const QString &in) p.putRich(QLatin1String(R"html()html") + code + QLatin1String("")); #else // FIXME custom style here is a hack. This supposed to be handled via style resource in PsiTextView - p.putRich(QString(R"()") + p.putRich(QString(R"()") .arg(code)); #endif }; diff --git a/src/widgets/psirichtext.cpp b/src/widgets/psirichtext.cpp index ef9430138..cf5d32918 100644 --- a/src/widgets/psirichtext.cpp +++ b/src/widgets/psirichtext.cpp @@ -105,7 +105,8 @@ class TextIconFormat : public QTextCharFormat { TextIconFormat(const QString &iconName, const QString &text, std::optional width = {}, std::optional height = {}, std::optional minWidth = {}, std::optional minHeight = {}, std::optional maxWidth = {}, - std::optional maxHeight = {}, std::optional valign = {}); + std::optional maxHeight = {}, std::optional valign = {}, + std::optional fontSize = {}); enum Property { IconName = QTextFormat::UserProperty + 1, @@ -115,7 +116,8 @@ class TextIconFormat : public QTextCharFormat { IconMinWidth = QTextFormat::UserProperty + 5, IconMinHeight = QTextFormat::UserProperty + 6, IconMaxWidth = QTextFormat::UserProperty + 7, - IconMaxHeight = QTextFormat::UserProperty + 8 + IconMaxHeight = QTextFormat::UserProperty + 8, + IconFontSize = QTextFormat::UserProperty + 9 }; }; @@ -123,7 +125,8 @@ TextIconFormat::TextIconFormat(const QString &iconName, const QString &text, std std::optional height, std::optional minWidth, std::optional minHeight, std::optional maxWidth, std::optional maxHeight, - std::optional valign) : QTextCharFormat() + std::optional valign, + std::optional fontSize) : QTextCharFormat() { Q_UNUSED(text); @@ -148,10 +151,12 @@ TextIconFormat::TextIconFormat(const QString &iconName, const QString &text, std if (maxHeight) { QTextFormat::setProperty(IconMaxHeight, QVariant::fromValue(*maxHeight)); } - if (valign) { setVerticalAlignment(*valign); } + if (fontSize) { + QTextFormat::setProperty(IconFontSize, QVariant::fromValue(*fontSize)); + } // TODO: handle animations } @@ -171,6 +176,59 @@ class TextIconHandler : public QObject, public QTextObjectInterface { virtual QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format); virtual void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format); + +private: + + QFont adjustFontSize(const QTextCharFormat charFormat) { + auto propHeight = charFormat.property(TextIconFormat::IconHeight); + auto propMinHeight = charFormat.property(TextIconFormat::IconMinHeight); + auto propMaxHeight = charFormat.property(TextIconFormat::IconMaxHeight); + auto propFontSize = charFormat.property(TextIconFormat::IconFontSize); + + std::optional height; + std::optional minHeight; + std::optional maxHeight; + + if (propMinHeight.isValid()) { + minHeight = htmlSizeToPixels(propMinHeight.value(), charFormat); + } + if (propMaxHeight.isValid()) { + maxHeight = htmlSizeToPixels(propMaxHeight.value(), charFormat); + } + if (propHeight.isValid()) { // we want to scale ignoring aspect ratio + int limitMin = minHeight ? *minHeight : 8; + int limitMax = maxHeight ? *maxHeight : 1080; + height = htmlSizeToPixels(propHeight.value(), charFormat); + height = qMax(qMin(limitMax, *height), limitMin); + } + + auto font = charFormat.font(); + int ps = font.pixelSize(); + if (ps == -1) { + ps = pointToPixel(font.pointSizeF()); + } + if (propFontSize.isValid()) { + auto fontSize = propFontSize.value(); + if (fontSize.unit == HtmlSize::Em) { + ps *= fontSize.size; + } else if (fontSize.unit == HtmlSize::Px) { + ps = fontSize.size; + } else if (fontSize.unit == HtmlSize::Pt) { + ps = pointToPixel(fontSize.size); + } + } + if (height) { + ps = *height; + } else if (minHeight && maxHeight) { + ps = (*minHeight + *maxHeight) / 2; + } else if (minHeight && ps < *minHeight) { + ps = *minHeight; + } else if (maxHeight && ps > *maxHeight) { + ps = *maxHeight; + } + font.setPixelSize(ps); + return font; + } }; TextIconHandler::TextIconHandler(QObject *parent) : QObject(parent) { } @@ -194,9 +252,9 @@ QSizeF TextIconHandler::intrinsicSize(QTextDocument *doc, int posInDocument, con } ret = icon->size(); doScaling = icon->isScalable(); - } else { - QFontMetrics fm(charFormat.font()); - ret = fm.boundingRect(iconText).size(); + } else if (!iconText.isEmpty()) { + auto font = adjustFontSize(charFormat); + return QFontMetricsF(font).tightBoundingRect(iconText).size()*1.16; // 1.16 - magic for Windows } if (ret.isEmpty()) { // something went wrong with this icon @@ -297,6 +355,7 @@ QSizeF TextIconHandler::intrinsicSize(QTextDocument *doc, int posInDocument, con ret = desiredSize; } } + qDebug() << ret; return ret; } @@ -317,10 +376,10 @@ void TextIconHandler::drawObject(QPainter *painter, const QRectF &rect, QTextDoc // qDebug() << "render icon " << iconText << iconName << " in " << rect; if (iconName.isEmpty()) { - auto font = charFormat.font(); - font.setPixelSize(rect.height()); + auto font = adjustFontSize(charFormat); + font.setPixelSize(font.pixelSize()); painter->setFont(font); - painter->drawText(rect, iconText); + painter->drawText(rect, Qt::AlignHCenter | Qt::AlignTop, iconText); } else { auto pixmap = IconsetFactory::iconPixmap(iconName, rect.size().toSize()); auto alignedSize = rect.size().toSize(); @@ -481,6 +540,7 @@ static QString convertIconsToObjectReplacementCharacters(const QStringView &text std::optional minHeight; std::optional maxWidth; std::optional maxHeight; + std::optional fontSize; QString iconName; QString iconText; QString iconType; @@ -524,13 +584,15 @@ static QString convertIconsToObjectReplacementCharacters(const QStringView &text } } else if (match.capturedView(1) == QLatin1String("type")) { iconType = match.captured(2); + } else if (match.capturedView(1) == QLatin1String("font-size")) { + fontSize = parseSize(match.capturedView(2)); } } if (!iconName.isEmpty() || !iconText.isEmpty()) { auto format = new TextIconFormat(iconName, iconText, std::move(width), std::move(height), std::move(minWidth), std::move(minHeight), std::move(maxWidth), - std::move(maxHeight), std::move(valign)); + std::move(maxHeight), std::move(valign), std::move(fontSize)); if (iconType == QLatin1String("smiley") && iconName.isEmpty()) { format->setFontFamilies(emojiFontFamilies); }