mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 03:16:10 +00:00
Fix non-integer Font Metrics in Graph (#1545)
This commit is contained in:
parent
61b0374a82
commit
ef22f20548
@ -1,84 +1,104 @@
|
||||
#ifndef CACHEDFONTMETRICS_H
|
||||
#define CACHEDFONTMETRICS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
|
||||
class CachedFontMetrics : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CachedFontMetrics(QObject *parent, const QFont &font)
|
||||
: QObject(parent),
|
||||
mFontMetrics(font)
|
||||
{
|
||||
memset(mWidths, 0, sizeof(mWidths));
|
||||
mHeight = mFontMetrics.height();
|
||||
}
|
||||
|
||||
int width(const QChar &ch)
|
||||
{
|
||||
auto unicode = ch.unicode();
|
||||
if (unicode >= 0xD800) {
|
||||
if (unicode >= 0xE000)
|
||||
unicode -= 0xE000 - 0xD800;
|
||||
else
|
||||
// is lonely surrogate
|
||||
return mFontMetrics.width(ch);
|
||||
}
|
||||
if (!mWidths[unicode])
|
||||
return mWidths[unicode] = mFontMetrics.width(ch);
|
||||
return mWidths[unicode];
|
||||
}
|
||||
|
||||
int width(const QString &text)
|
||||
{
|
||||
int result = 0;
|
||||
QChar temp;
|
||||
for (const QChar &ch : text) {
|
||||
if (ch.isHighSurrogate())
|
||||
temp = ch;
|
||||
else if (ch.isLowSurrogate())
|
||||
result += mFontMetrics.width(QString(temp) + ch);
|
||||
else
|
||||
result += width(ch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int height()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
int position(const QString &text, int offset)
|
||||
{
|
||||
int curWidth = 0;
|
||||
QChar temp;
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
QChar ch = text[i];
|
||||
|
||||
if (ch.isHighSurrogate())
|
||||
temp = ch;
|
||||
else if (ch.isLowSurrogate())
|
||||
curWidth += mFontMetrics.width(QString(temp) + ch);
|
||||
else
|
||||
curWidth += width(ch);
|
||||
|
||||
if (curWidth >= offset) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
QFontMetrics mFontMetrics;
|
||||
uchar mWidths[0x10000 - 0xE000 + 0xD800];
|
||||
int mHeight;
|
||||
};
|
||||
|
||||
#endif // CACHEDFONTMETRICS_H
|
||||
#ifndef CACHEDFONTMETRICS_H
|
||||
#define CACHEDFONTMETRICS_H
|
||||
|
||||
#include "common/Metrics.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
|
||||
template<typename T>
|
||||
class CachedFontMetrics
|
||||
{
|
||||
public:
|
||||
explicit CachedFontMetrics(const QFont &font)
|
||||
: mFontMetrics(font)
|
||||
{
|
||||
memset(mWidths, 0, sizeof(mWidths));
|
||||
mHeight = mFontMetrics.height();
|
||||
}
|
||||
|
||||
T width(const QChar &ch)
|
||||
{
|
||||
//return mFontMetrics.width(ch);
|
||||
auto unicode = ch.unicode();
|
||||
if (unicode >= 0xD800) {
|
||||
if (unicode >= 0xE000)
|
||||
unicode -= 0xE000 - 0xD800;
|
||||
else
|
||||
// is lonely surrogate
|
||||
return fetchWidth(ch);
|
||||
}
|
||||
if (!mWidths[unicode])
|
||||
return mWidths[unicode] = fetchWidth(ch);
|
||||
return mWidths[unicode];
|
||||
}
|
||||
|
||||
T width(const QString &text)
|
||||
{
|
||||
T result = 0;
|
||||
QChar temp;
|
||||
for (const QChar &ch : text) {
|
||||
if (ch.isHighSurrogate())
|
||||
temp = ch;
|
||||
else if (ch.isLowSurrogate())
|
||||
result += fetchWidth(QString(temp) + ch);
|
||||
else
|
||||
result += width(ch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
T height()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
T position(const QString &text, T offset)
|
||||
{
|
||||
T curWidth = 0;
|
||||
QChar temp;
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
QChar ch = text[i];
|
||||
|
||||
if (ch.isHighSurrogate())
|
||||
temp = ch;
|
||||
else if (ch.isLowSurrogate())
|
||||
curWidth += fetchWidth(QString(temp) + ch);
|
||||
else
|
||||
curWidth += width(ch);
|
||||
|
||||
if (curWidth >= offset) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
typename Metrics<T>::FontMetrics mFontMetrics;
|
||||
T mWidths[0x10000 - 0xE000 + 0xD800];
|
||||
T mHeight;
|
||||
|
||||
T fetchWidth(QChar c)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|
||||
return mFontMetrics.width(c);
|
||||
#else
|
||||
return mFontMetrics.horizontalAdvance(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
T fetchWidth(const QString &s)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|
||||
return mFontMetrics.width(s);
|
||||
#else
|
||||
return mFontMetrics.horizontalAdvance(s);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CACHEDFONTMETRICS_H
|
||||
|
26
src/common/Metrics.h
Normal file
26
src/common/Metrics.h
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#ifndef METRICS_H
|
||||
#define METRICS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
class QRect;
|
||||
class QRectF;
|
||||
class QFontMetrics;
|
||||
class QFontMetricsF;
|
||||
|
||||
template<typename T> struct Metrics {};
|
||||
|
||||
template<> struct Metrics<int>
|
||||
{
|
||||
using Rect = QRect;
|
||||
using FontMetrics = QFontMetrics;
|
||||
};
|
||||
|
||||
template<> struct Metrics<qreal>
|
||||
{
|
||||
using Rect = QRectF;
|
||||
using FontMetrics = QFontMetricsF;
|
||||
};
|
||||
|
||||
#endif //METRICS_H
|
@ -1,188 +1,196 @@
|
||||
/* x64dbg RichTextPainter */
|
||||
#include "RichTextPainter.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include "common/Configuration.h"
|
||||
#include <QPainter>
|
||||
#include <QTextBlock>
|
||||
#include <QTextFragment>
|
||||
|
||||
//TODO: fix performance (possibly use QTextLayout?)
|
||||
void RichTextPainter::paintRichText(QPainter *painter, int x, int y, int w, int h, int xinc,
|
||||
const List &richText, CachedFontMetrics *fontMetrics)
|
||||
{
|
||||
QPen pen;
|
||||
QPen highlightPen;
|
||||
QBrush brush(Qt::cyan);
|
||||
for (const CustomRichText_t &curRichText : richText) {
|
||||
int textWidth = fontMetrics->width(curRichText.text);
|
||||
int backgroundWidth = textWidth;
|
||||
if (backgroundWidth + xinc > w)
|
||||
backgroundWidth = w - xinc;
|
||||
if (backgroundWidth <= 0) //stop drawing when going outside the specified width
|
||||
break;
|
||||
switch (curRichText.flags) {
|
||||
case FlagNone: //defaults
|
||||
pen.setColor(ConfigColor("btext").name());
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
case FlagColor: //color only
|
||||
pen.setColor(curRichText.textColor);
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
case FlagBackground: //background only
|
||||
if (backgroundWidth > 0 && curRichText.textBackground.alpha()) {
|
||||
brush.setColor(curRichText.textBackground);
|
||||
painter->fillRect(QRect(x + xinc, y, backgroundWidth, h), brush);
|
||||
}
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
if (backgroundWidth > 0 && curRichText.textBackground.alpha()) {
|
||||
brush.setColor(curRichText.textBackground);
|
||||
painter->fillRect(QRect(x + xinc, y, backgroundWidth, h), brush);
|
||||
}
|
||||
pen.setColor(curRichText.textColor);
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
}
|
||||
painter->drawText(QRect(x + xinc, y, w - xinc, h), Qt::TextBypassShaping, curRichText.text);
|
||||
if (curRichText.highlight && curRichText.highlightColor.alpha()) {
|
||||
highlightPen.setColor(curRichText.highlightColor);
|
||||
highlightPen.setWidth(curRichText.highlightWidth);
|
||||
painter->setPen(highlightPen);
|
||||
int highlightOffsetX = curRichText.highlightConnectPrev ? -1 : 1;
|
||||
painter->drawLine(x + xinc + highlightOffsetX, y + h - 1, x + xinc + backgroundWidth - 1,
|
||||
y + h - 1);
|
||||
}
|
||||
xinc += textWidth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RichTextPainter::htmlRichText Convert rich text in x64dbg to HTML, for use by other applications
|
||||
* @param richText The rich text to be converted to HTML format
|
||||
* @param textHtml The HTML source. Any previous content will be preserved and new content will be appended at the end.
|
||||
* @param textPlain The plain text. Any previous content will be preserved and new content will be appended at the end.
|
||||
*/
|
||||
void RichTextPainter::htmlRichText(const List &richText, QString &textHtml, QString &textPlain)
|
||||
{
|
||||
for (const CustomRichText_t &curRichText : richText) {
|
||||
if (curRichText.text == " ") { //blank
|
||||
textHtml += " ";
|
||||
textPlain += " ";
|
||||
continue;
|
||||
}
|
||||
switch (curRichText.flags) {
|
||||
case FlagNone: //defaults
|
||||
textHtml += "<span>";
|
||||
break;
|
||||
case FlagColor: //color only
|
||||
textHtml += QString("<span style=\"color:%1\">").arg(curRichText.textColor.name());
|
||||
break;
|
||||
case FlagBackground: //background only
|
||||
if (curRichText.textBackground !=
|
||||
Qt::transparent) // QColor::name() returns "#000000" for transparent color. That's not desired. Leave it blank.
|
||||
textHtml += QString("<span style=\"background-color:%1\">").arg(curRichText.textBackground.name());
|
||||
else
|
||||
textHtml += QString("<span>");
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
if (curRichText.textBackground !=
|
||||
Qt::transparent) // QColor::name() returns "#000000" for transparent color. That's not desired. Leave it blank.
|
||||
textHtml += QString("<span style=\"color:%1; background-color:%2\">").arg(
|
||||
curRichText.textColor.name(), curRichText.textBackground.name());
|
||||
else
|
||||
textHtml += QString("<span style=\"color:%1\">").arg(curRichText.textColor.name());
|
||||
break;
|
||||
}
|
||||
if (curRichText.highlight) //Underline highlighted token
|
||||
textHtml += "<u>";
|
||||
textHtml += curRichText.text.toHtmlEscaped();
|
||||
if (curRichText.highlight)
|
||||
textHtml += "</u>";
|
||||
textHtml += "</span>"; //Close the tag
|
||||
textPlain += curRichText.text;
|
||||
}
|
||||
}
|
||||
|
||||
RichTextPainter::List RichTextPainter::fromTextDocument(const QTextDocument &doc)
|
||||
{
|
||||
List r;
|
||||
|
||||
for (QTextBlock block = doc.begin(); block != doc.end(); block = block.next()) {
|
||||
for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
|
||||
QTextFragment fragment = it.fragment();
|
||||
QTextCharFormat format = fragment.charFormat();
|
||||
|
||||
CustomRichText_t text;
|
||||
text.text = fragment.text();
|
||||
text.textColor = format.foreground().color();
|
||||
text.textBackground = format.background().color();
|
||||
|
||||
bool hasForeground = format.hasProperty(QTextFormat::ForegroundBrush);
|
||||
bool hasBackground = format.hasProperty(QTextFormat::BackgroundBrush);
|
||||
|
||||
if (hasForeground && !hasBackground) {
|
||||
text.flags = FlagColor;
|
||||
} else if (!hasForeground && hasBackground) {
|
||||
text.flags = FlagBackground;
|
||||
} else if (hasForeground && hasBackground) {
|
||||
text.flags = FlagAll;
|
||||
} else {
|
||||
text.flags = FlagNone;
|
||||
}
|
||||
|
||||
r.push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
RichTextPainter::List RichTextPainter::cropped(const RichTextPainter::List &richText, int maxCols,
|
||||
const QString &indicator, bool *croppedOut)
|
||||
{
|
||||
List r;
|
||||
r.reserve(richText.size());
|
||||
|
||||
int cols = 0;
|
||||
bool cropped = false;
|
||||
for (const auto &text : richText) {
|
||||
int textLength = text.text.size();
|
||||
if (cols + textLength <= maxCols) {
|
||||
r.push_back(text);
|
||||
cols += textLength;
|
||||
} else if (cols == maxCols) {
|
||||
break;
|
||||
} else {
|
||||
CustomRichText_t croppedText = text;
|
||||
croppedText.text.truncate(maxCols - cols);
|
||||
r.push_back(croppedText);
|
||||
cropped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cropped && !indicator.isEmpty()) {
|
||||
int indicatorCropLength = indicator.length();
|
||||
if (indicatorCropLength > maxCols) {
|
||||
indicatorCropLength = maxCols;
|
||||
}
|
||||
|
||||
while (!r.empty()) {
|
||||
auto &text = r.back();
|
||||
|
||||
if (text.text.length() >= indicatorCropLength) {
|
||||
text.text.replace(text.text.length() - indicatorCropLength, indicatorCropLength, indicator);
|
||||
break;
|
||||
}
|
||||
|
||||
indicatorCropLength -= text.text.length();
|
||||
r.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (croppedOut) {
|
||||
*croppedOut = cropped;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
/* x64dbg RichTextPainter */
|
||||
#include "RichTextPainter.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include "common/Configuration.h"
|
||||
#include <QPainter>
|
||||
#include <QTextBlock>
|
||||
#include <QTextFragment>
|
||||
|
||||
//TODO: fix performance (possibly use QTextLayout?)
|
||||
|
||||
|
||||
template<typename T>
|
||||
void RichTextPainter::paintRichText(QPainter *painter, T x, T y, T w, T h, T xinc,
|
||||
const List &richText, CachedFontMetrics<T> *fontMetrics)
|
||||
{
|
||||
QPen pen;
|
||||
QPen highlightPen;
|
||||
QBrush brush(Qt::cyan);
|
||||
for (const CustomRichText_t &curRichText : richText) {
|
||||
T textWidth = fontMetrics->width(curRichText.text);
|
||||
T backgroundWidth = textWidth;
|
||||
if (backgroundWidth + xinc > w)
|
||||
backgroundWidth = w - xinc;
|
||||
if (backgroundWidth <= 0) //stop drawing when going outside the specified width
|
||||
break;
|
||||
switch (curRichText.flags) {
|
||||
case FlagNone: //defaults
|
||||
pen.setColor(ConfigColor("btext").name());
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
case FlagColor: //color only
|
||||
pen.setColor(curRichText.textColor);
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
case FlagBackground: //background only
|
||||
if (backgroundWidth > 0 && curRichText.textBackground.alpha()) {
|
||||
brush.setColor(curRichText.textBackground);
|
||||
painter->fillRect(QRectF(x + xinc, y, backgroundWidth, h), brush);
|
||||
}
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
if (backgroundWidth > 0 && curRichText.textBackground.alpha()) {
|
||||
brush.setColor(curRichText.textBackground);
|
||||
painter->fillRect(QRectF(x + xinc, y, backgroundWidth, h), brush);
|
||||
}
|
||||
pen.setColor(curRichText.textColor);
|
||||
painter->setPen(pen);
|
||||
break;
|
||||
}
|
||||
painter->drawText(typename Metrics<T>::Rect(x + xinc, y, w - xinc, h), Qt::TextBypassShaping, curRichText.text);
|
||||
if (curRichText.highlight && curRichText.highlightColor.alpha()) {
|
||||
highlightPen.setColor(curRichText.highlightColor);
|
||||
highlightPen.setWidth(curRichText.highlightWidth);
|
||||
painter->setPen(highlightPen);
|
||||
T highlightOffsetX = curRichText.highlightConnectPrev ? -1 : 1;
|
||||
painter->drawLine(x + xinc + highlightOffsetX, y + h - 1, x + xinc + backgroundWidth - 1,
|
||||
y + h - 1);
|
||||
}
|
||||
xinc += textWidth;
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void RichTextPainter::paintRichText<qreal>(QPainter *painter, qreal x, qreal y, qreal w, qreal h, qreal xinc,
|
||||
const List &richText, CachedFontMetrics<qreal> *fontMetrics);
|
||||
|
||||
|
||||
/**
|
||||
* @brief RichTextPainter::htmlRichText Convert rich text in x64dbg to HTML, for use by other applications
|
||||
* @param richText The rich text to be converted to HTML format
|
||||
* @param textHtml The HTML source. Any previous content will be preserved and new content will be appended at the end.
|
||||
* @param textPlain The plain text. Any previous content will be preserved and new content will be appended at the end.
|
||||
*/
|
||||
void RichTextPainter::htmlRichText(const List &richText, QString &textHtml, QString &textPlain)
|
||||
{
|
||||
for (const CustomRichText_t &curRichText : richText) {
|
||||
if (curRichText.text == " ") { //blank
|
||||
textHtml += " ";
|
||||
textPlain += " ";
|
||||
continue;
|
||||
}
|
||||
switch (curRichText.flags) {
|
||||
case FlagNone: //defaults
|
||||
textHtml += "<span>";
|
||||
break;
|
||||
case FlagColor: //color only
|
||||
textHtml += QString("<span style=\"color:%1\">").arg(curRichText.textColor.name());
|
||||
break;
|
||||
case FlagBackground: //background only
|
||||
if (curRichText.textBackground !=
|
||||
Qt::transparent) // QColor::name() returns "#000000" for transparent color. That's not desired. Leave it blank.
|
||||
textHtml += QString("<span style=\"background-color:%1\">").arg(curRichText.textBackground.name());
|
||||
else
|
||||
textHtml += QString("<span>");
|
||||
break;
|
||||
case FlagAll: //color+background
|
||||
if (curRichText.textBackground !=
|
||||
Qt::transparent) // QColor::name() returns "#000000" for transparent color. That's not desired. Leave it blank.
|
||||
textHtml += QString("<span style=\"color:%1; background-color:%2\">").arg(
|
||||
curRichText.textColor.name(), curRichText.textBackground.name());
|
||||
else
|
||||
textHtml += QString("<span style=\"color:%1\">").arg(curRichText.textColor.name());
|
||||
break;
|
||||
}
|
||||
if (curRichText.highlight) //Underline highlighted token
|
||||
textHtml += "<u>";
|
||||
textHtml += curRichText.text.toHtmlEscaped();
|
||||
if (curRichText.highlight)
|
||||
textHtml += "</u>";
|
||||
textHtml += "</span>"; //Close the tag
|
||||
textPlain += curRichText.text;
|
||||
}
|
||||
}
|
||||
|
||||
RichTextPainter::List RichTextPainter::fromTextDocument(const QTextDocument &doc)
|
||||
{
|
||||
List r;
|
||||
|
||||
for (QTextBlock block = doc.begin(); block != doc.end(); block = block.next()) {
|
||||
for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
|
||||
QTextFragment fragment = it.fragment();
|
||||
QTextCharFormat format = fragment.charFormat();
|
||||
|
||||
CustomRichText_t text;
|
||||
text.text = fragment.text();
|
||||
text.textColor = format.foreground().color();
|
||||
text.textBackground = format.background().color();
|
||||
|
||||
bool hasForeground = format.hasProperty(QTextFormat::ForegroundBrush);
|
||||
bool hasBackground = format.hasProperty(QTextFormat::BackgroundBrush);
|
||||
|
||||
if (hasForeground && !hasBackground) {
|
||||
text.flags = FlagColor;
|
||||
} else if (!hasForeground && hasBackground) {
|
||||
text.flags = FlagBackground;
|
||||
} else if (hasForeground && hasBackground) {
|
||||
text.flags = FlagAll;
|
||||
} else {
|
||||
text.flags = FlagNone;
|
||||
}
|
||||
|
||||
r.push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
RichTextPainter::List RichTextPainter::cropped(const RichTextPainter::List &richText, int maxCols,
|
||||
const QString &indicator, bool *croppedOut)
|
||||
{
|
||||
List r;
|
||||
r.reserve(richText.size());
|
||||
|
||||
int cols = 0;
|
||||
bool cropped = false;
|
||||
for (const auto &text : richText) {
|
||||
int textLength = text.text.size();
|
||||
if (cols + textLength <= maxCols) {
|
||||
r.push_back(text);
|
||||
cols += textLength;
|
||||
} else if (cols == maxCols) {
|
||||
break;
|
||||
} else {
|
||||
CustomRichText_t croppedText = text;
|
||||
croppedText.text.truncate(maxCols - cols);
|
||||
r.push_back(croppedText);
|
||||
cropped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cropped && !indicator.isEmpty()) {
|
||||
int indicatorCropLength = indicator.length();
|
||||
if (indicatorCropLength > maxCols) {
|
||||
indicatorCropLength = maxCols;
|
||||
}
|
||||
|
||||
while (!r.empty()) {
|
||||
auto &text = r.back();
|
||||
|
||||
if (text.text.length() >= indicatorCropLength) {
|
||||
text.text.replace(text.text.length() - indicatorCropLength, indicatorCropLength, indicator);
|
||||
break;
|
||||
}
|
||||
|
||||
indicatorCropLength -= text.text.length();
|
||||
r.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (croppedOut) {
|
||||
*croppedOut = cropped;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -1,48 +1,52 @@
|
||||
/* x64dbg RichTextPainter */
|
||||
#ifndef RICHTEXTPAINTER_H
|
||||
#define RICHTEXTPAINTER_H
|
||||
|
||||
#include <QString>
|
||||
#include <QTextDocument>
|
||||
#include <QColor>
|
||||
#include <vector>
|
||||
|
||||
class CachedFontMetrics;
|
||||
class QPainter;
|
||||
|
||||
class RichTextPainter
|
||||
{
|
||||
public:
|
||||
//structures
|
||||
enum CustomRichTextFlags {
|
||||
FlagNone,
|
||||
FlagColor,
|
||||
FlagBackground,
|
||||
FlagAll
|
||||
};
|
||||
|
||||
struct CustomRichText_t {
|
||||
QString text;
|
||||
QColor textColor;
|
||||
QColor textBackground;
|
||||
CustomRichTextFlags flags;
|
||||
bool highlight = false;
|
||||
QColor highlightColor;
|
||||
int highlightWidth = 2;
|
||||
bool highlightConnectPrev = false;
|
||||
};
|
||||
|
||||
typedef std::vector<CustomRichText_t> List;
|
||||
|
||||
//functions
|
||||
static void paintRichText(QPainter *painter, int x, int y, int w, int h, int xinc,
|
||||
const List &richText, CachedFontMetrics *fontMetrics);
|
||||
static void htmlRichText(const List &richText, QString &textHtml, QString &textPlain);
|
||||
|
||||
static List fromTextDocument(const QTextDocument &doc);
|
||||
|
||||
static List cropped(const List &richText, int maxCols, const QString &indicator = nullptr,
|
||||
bool *croppedOut = nullptr);
|
||||
};
|
||||
|
||||
#endif // RICHTEXTPAINTER_H
|
||||
/* x64dbg RichTextPainter */
|
||||
#ifndef RICHTEXTPAINTER_H
|
||||
#define RICHTEXTPAINTER_H
|
||||
|
||||
#include "common/Metrics.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QTextDocument>
|
||||
#include <QColor>
|
||||
#include <vector>
|
||||
|
||||
class QFontMetricsF;
|
||||
template<typename T> class CachedFontMetrics;
|
||||
class QPainter;
|
||||
|
||||
class RichTextPainter
|
||||
{
|
||||
public:
|
||||
//structures
|
||||
enum CustomRichTextFlags {
|
||||
FlagNone,
|
||||
FlagColor,
|
||||
FlagBackground,
|
||||
FlagAll
|
||||
};
|
||||
|
||||
struct CustomRichText_t {
|
||||
QString text;
|
||||
QColor textColor;
|
||||
QColor textBackground;
|
||||
CustomRichTextFlags flags;
|
||||
bool highlight = false;
|
||||
QColor highlightColor;
|
||||
int highlightWidth = 2;
|
||||
bool highlightConnectPrev = false;
|
||||
};
|
||||
|
||||
typedef std::vector<CustomRichText_t> List;
|
||||
|
||||
//functions
|
||||
template<typename T = qreal>
|
||||
static void paintRichText(QPainter *painter, T x, T y, T w, T h, T xinc,
|
||||
const List &richText, CachedFontMetrics<T> *fontMetrics);
|
||||
static void htmlRichText(const List &richText, QString &textHtml, QString &textPlain);
|
||||
|
||||
static List fromTextDocument(const QTextDocument &doc);
|
||||
|
||||
static List cropped(const List &richText, int maxCols, const QString &indicator = nullptr,
|
||||
bool *croppedOut = nullptr);
|
||||
};
|
||||
|
||||
#endif // RICHTEXTPAINTER_H
|
||||
|
@ -377,8 +377,7 @@ void DisassemblerGraphView::initFont()
|
||||
charWidth = metrics.width('X');
|
||||
charHeight = static_cast<int>(metrics.height());
|
||||
charOffset = 0;
|
||||
delete mFontMetrics;
|
||||
mFontMetrics = new CachedFontMetrics(this, font());
|
||||
mFontMetrics.reset(new CachedFontMetrics<qreal>(font()));
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
@ -464,7 +463,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
// Highlight selected tokens
|
||||
if (highlight_token != nullptr) {
|
||||
int y = static_cast<int>(blockY + (2 * charWidth) + (db.header_text.lines.size() * charHeight));
|
||||
int tokenWidth = mFontMetrics->width(highlight_token->content);
|
||||
qreal tokenWidth = mFontMetrics->width(highlight_token->content);
|
||||
|
||||
for (const Instr &instr : db.instrs) {
|
||||
int pos = -1;
|
||||
@ -477,19 +476,19 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
continue;
|
||||
}
|
||||
|
||||
int widthBefore = mFontMetrics->width(instr.plainText.left(pos));
|
||||
qreal widthBefore = mFontMetrics->width(instr.plainText.left(pos));
|
||||
if (charWidth * 3 + widthBefore > block.width - (10 + 2 * charWidth)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int highlightWidth = tokenWidth;
|
||||
qreal highlightWidth = tokenWidth;
|
||||
if (charWidth * 3 + widthBefore + tokenWidth >= block.width - (10 + 2 * charWidth)) {
|
||||
highlightWidth = static_cast<int>(block.width - widthBefore - (10 + 4 * charWidth));
|
||||
highlightWidth = block.width - widthBefore - (10 + 4 * charWidth);
|
||||
}
|
||||
|
||||
QColor selectionColor = ConfigColor("wordhl");
|
||||
|
||||
p.fillRect(QRect(static_cast<int>(blockX + charWidth * 3 + widthBefore), y, highlightWidth,
|
||||
p.fillRect(QRectF(blockX + charWidth * 3 + widthBefore, y, highlightWidth,
|
||||
charHeight), selectionColor);
|
||||
}
|
||||
|
||||
@ -535,8 +534,8 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
continue;
|
||||
}
|
||||
|
||||
RichTextPainter::paintRichText(&p, static_cast<int>(x), y, block.width, charHeight, 0, line,
|
||||
mFontMetrics);
|
||||
RichTextPainter::paintRichText<qreal>(&p, x, y, block.width, charHeight, 0, line,
|
||||
mFontMetrics.get());
|
||||
y += charHeight;
|
||||
}
|
||||
|
||||
@ -569,9 +568,9 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
QRectF bpRect(x - rectSize / 3.0, y + (charHeight - rectSize) / 2.0, rectSize, rectSize);
|
||||
Q_UNUSED(bpRect);
|
||||
|
||||
RichTextPainter::paintRichText(&p, static_cast<int>(x + charWidth), y,
|
||||
static_cast<int>(block.width - charWidth), charHeight, 0, line,
|
||||
mFontMetrics);
|
||||
RichTextPainter::paintRichText<qreal>(&p, x + charWidth, y,
|
||||
block.width - charWidth, charHeight, 0, line,
|
||||
mFontMetrics.get());
|
||||
y += charHeight;
|
||||
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ private:
|
||||
|
||||
Token *highlight_token;
|
||||
// Font data
|
||||
CachedFontMetrics *mFontMetrics;
|
||||
std::unique_ptr<CachedFontMetrics<qreal>> mFontMetrics;
|
||||
qreal charWidth;
|
||||
int charHeight;
|
||||
int charOffset;
|
||||
|
Loading…
Reference in New Issue
Block a user