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