1 #include "listingrenderercommon.h"
2 #include "../redasmsettings.h"
3 #include "../themeprovider.h"
4 #include <QApplication>
5 #include <QRegularExpression>
6 #include <QTextCharFormat>
7 #include <QTextDocument>
8 #include <QPalette>
9 #include <QPainter>
10
ListingRendererCommon(REDasm::DisassemblerAPI * disassembler)11 ListingRendererCommon::ListingRendererCommon(REDasm::DisassemblerAPI *disassembler): REDasm::ListingRenderer(disassembler), m_fontmetrics(REDasmSettings::font()), m_maxwidth(0), m_firstline(0) { }
12
moveTo(const QPointF & pos)13 void ListingRendererCommon::moveTo(const QPointF &pos)
14 {
15 REDasm::ListingCursor::Position cp = this->hitTest(pos);
16 m_cursor->moveTo(cp.first, cp.second);
17 }
18
select(const QPointF & pos)19 void ListingRendererCommon::select(const QPointF &pos)
20 {
21 REDasm::ListingCursor::Position cp = this->hitTest(pos);
22 m_cursor->select(cp.first, cp.second);
23 }
24
hitTest(const QPointF & pos)25 REDasm::ListingCursor::Position ListingRendererCommon::hitTest(const QPointF &pos)
26 {
27 REDasm::ListingCursor::Position cp;
28 cp.first = std::min(static_cast<size_t>(m_firstline + std::floor(pos.y() / m_fontmetrics.height())), m_document->lastLine());
29 cp.second = std::numeric_limits<size_t>::max();
30
31 REDasm::RendererLine rl(true);
32
33 if(!this->getRendererLine(cp.first, rl))
34 cp.second = 0;
35
36 std::string s = rl.text;
37 qreal x = 0;
38
39 for(size_t i = 0; i < s.length(); i++)
40 {
41 qreal w = m_fontmetrics.width(s[i]);
42
43 if(x >= pos.x())
44 {
45 cp.second = i - 1;
46 break;
47 }
48
49 x += w;
50 }
51
52 if(cp.second == std::numeric_limits<size_t>::max())
53 cp.second = s.length() - 1;
54
55 return cp;
56 }
57
getWordFromPos(const QPointF & pos,REDasm::ListingRenderer::Range * wordpos)58 std::string ListingRendererCommon::getWordFromPos(const QPointF &pos, REDasm::ListingRenderer::Range* wordpos)
59 {
60 REDasm::ListingCursor::Position cp = this->hitTest(pos);
61 return this->wordFromPosition(cp, wordpos);
62 }
63
selectWordAt(const QPointF & pos)64 void ListingRendererCommon::selectWordAt(const QPointF& pos)
65 {
66 auto lock = REDasm::s_lock_safe_ptr(this->document());
67 REDasm::ListingCursor* cur = lock->cursor();
68 Range r = this->wordHitTest(pos);
69
70 if(r.first > r.second)
71 return;
72
73 cur->moveTo(cur->currentLine(), r.first);
74 cur->select(cur->currentLine(), r.second);
75 }
76
wordHitTest(const QPointF & pos)77 REDasm::ListingRenderer::Range ListingRendererCommon::wordHitTest(const QPointF &pos)
78 {
79 REDasm::ListingRenderer::Range wordpos;
80 this->getWordFromPos(pos, &wordpos);
81 return wordpos;
82 }
83
setFirstVisibleLine(size_t line)84 void ListingRendererCommon::setFirstVisibleLine(size_t line) { m_firstline = line; }
fontMetrics() const85 const QFontMetricsF ListingRendererCommon::fontMetrics() const { return m_fontmetrics; }
maxWidth() const86 qreal ListingRendererCommon::maxWidth() const { return m_maxwidth; }
87
insertText(const REDasm::RendererLine & rl,QTextCursor * textcursor)88 void ListingRendererCommon::insertText(const REDasm::RendererLine &rl, QTextCursor *textcursor)
89 {
90 if(rl.index > 0)
91 {
92 textcursor->movePosition(QTextCursor::End);
93 textcursor->insertBlock(QTextBlockFormat());
94 }
95
96 for(const REDasm::RendererFormat& rf : rl.formats)
97 {
98 QTextCharFormat charformat;
99
100 if(!rf.fgstyle.empty())
101 {
102 if((rf.fgstyle == "cursor_fg") || (rf.fgstyle == "selection_fg"))
103 charformat.setForeground(qApp->palette().color(QPalette::HighlightedText));
104 else
105 charformat.setForeground(THEME_VALUE(QString::fromStdString(rf.fgstyle)));
106 }
107
108 if(!rf.bgstyle.empty())
109 {
110 if(rf.bgstyle == "cursor_bg")
111 charformat.setBackground(qApp->palette().color(QPalette::WindowText));
112 else if(rf.bgstyle == "selection_bg")
113 charformat.setBackground(qApp->palette().color(QPalette::Highlight));
114 else
115 charformat.setBackground(THEME_VALUE(QString::fromStdString(rf.bgstyle)));
116 }
117
118 textcursor->insertText(QString::fromStdString(rl.formatText(rf)), charformat);
119 }
120
121 if(!rl.highlighted)
122 return;
123
124 QTextBlockFormat blockformat;
125 blockformat.setBackground(THEME_VALUE("seek"));
126 textcursor->setBlockFormat(blockformat);
127 }
128
renderText(const REDasm::RendererLine & rl,float x,float y,const QFontMetricsF & fm)129 void ListingRendererCommon::renderText(const REDasm::RendererLine &rl, float x, float y, const QFontMetricsF& fm)
130 {
131 QPainter* painter = reinterpret_cast<QPainter*>(rl.userdata);
132
133 if(rl.highlighted)
134 {
135 QRect vpr = painter->viewport();
136 painter->fillRect(0, y, vpr.width(), fm.height(), THEME_VALUE("seek"));
137 }
138
139 for(const REDasm::RendererFormat& rf : rl.formats)
140 {
141 if(!rf.fgstyle.empty())
142 {
143 if((rf.fgstyle == "cursor_fg") || (rf.fgstyle == "selection_fg"))
144 painter->setPen(qApp->palette().color(QPalette::HighlightedText));
145 else
146 painter->setPen(THEME_VALUE(QString::fromStdString(rf.fgstyle)));
147 }
148 else
149 painter->setPen(qApp->palette().color(QPalette::WindowText));
150
151 QString chunk = QString::fromStdString(rl.formatText(rf));
152 QRectF chunkrect = painter->boundingRect(QRectF(x, y, fm.width(chunk), fm.height()), Qt::TextIncludeTrailingSpaces, chunk);
153
154 if(!rf.bgstyle.empty())
155 {
156 if(rf.bgstyle == "cursor_bg")
157 painter->fillRect(chunkrect, qApp->palette().color(QPalette::WindowText));
158 else if(rf.bgstyle == "selection_bg")
159 painter->fillRect(chunkrect, qApp->palette().color(QPalette::Highlight));
160 else
161 painter->fillRect(chunkrect, THEME_VALUE(QString::fromStdString(rf.bgstyle)));
162 }
163
164 painter->drawText(chunkrect, Qt::TextSingleLine, chunk);
165 x += chunkrect.width();
166 }
167 }
168