Vuo  2.0.2
VuoCodeGutter.cc
Go to the documentation of this file.
1 
10 #include "VuoCodeGutter.hh"
11 
12 #include <sys/param.h>
13 
14 #include "VuoCodeEditor.hh"
15 #include "VuoCodeEditorStages.hh"
16 #include "VuoCodeWindow.hh"
17 #include "VuoShaderIssues.hh"
18 
19 qreal VuoCodeGutter::leftMargin = 5;
20 qreal VuoCodeGutter::rightMargin = 5;
21 
26  : QWidget(editor)
27 {
28  codeEditor = editor;
29  scrollPosition = 0;
30 
31  lineNumberFont = QFont("Menlo");
32 
33  connect(codeEditor, &QTextEdit::textChanged, this, &VuoCodeGutter::textChanged);
34  connect(codeEditor->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &VuoCodeGutter::handleSliderMoved);
35 }
36 
41 {
42  lineNumberFont.setPointSize(codeEditor->font().pointSize() * .8);
43  resizeEvent(NULL);
44  update();
45 }
46 
47 void VuoCodeGutter::paintEvent(QPaintEvent *event)
48 {
49  QRect r = event->rect();
50 
51  QPainter painter(this);
52  painter.fillRect(r, codeEditor->gutterColor);
53 
54  painter.setPen(codeEditor->gutterTextColor);
55  painter.setFont(lineNumberFont);
56  QFontMetrics lineNumberFontMetrics(lineNumberFont);
57  int lineHeight = codeEditor->fontMetrics().height();
58  int baselineAdjustment = codeEditor->fontMetrics().ascent() - lineNumberFontMetrics.ascent();
59  int gutterWidth = width() - rightMargin;
60 
61  // QFontMetrics.lineHeight is in pixels, but QTextEdit doesn't quantize lines to pixels,
62  // so we can't just draw at multiples of lineHeight.
63  // Instead, get the actual position of each line from the QTextLayout.
64  QTextCursor cursor = codeEditor->textCursor();
65  cursor.movePosition(QTextCursor::Start);
66  QTextBlock block = cursor.block();
67  int viewportHeight = codeEditor->viewport()->geometry().height();
68  int lineNumber = 0;
69 
70  VuoCodeWindow *codeWindow = static_cast<VuoCodeWindow *>(window());
71  if (codeWindow->issues)
72  {
73  vector<VuoShaderIssues::Issue> issues = codeWindow->issues->issuesForStage(codeWindow->stages->currentStage());
74  // The issue list is assumed to be sorted by line number.
75  // Therefore we only need to advance through it once, instead of once for every line number.
76  vector<VuoShaderIssues::Issue>::iterator issueIterator = issues.begin();
77 
78  int iconSize = codeEditor->errorIcon->height() / window()->devicePixelRatio();
79 
80  do
81  {
82  ++lineNumber;
83  qreal y = block.layout()->position().y() - scrollPosition;
84  if (y < -lineHeight)
85  continue;
86  if (y > viewportHeight)
87  break;
88 
89  painter.drawText(QRectF(0, y + baselineAdjustment + 1, gutterWidth, lineHeight),
90  Qt::AlignRight, QString::number(lineNumber));
91 
92  bool haveIssue = false;
93  while (issueIterator != issues.end())
94  {
95  if (issueIterator->lineNumber == lineNumber)
96  {
97  haveIssue = true;
98  break;
99  }
100  if (issueIterator->lineNumber > lineNumber)
101  break;
102  ++issueIterator;
103  }
104  if (haveIssue)
105  painter.drawPixmap(leftMargin, y + (lineHeight - iconSize) / 2, iconSize, iconSize, *codeEditor->errorIcon);
106  } while ((block = block.next()).isValid());
107  }
108 }
109 
110 void VuoCodeGutter::handleSliderMoved(int value)
111 {
112  scrollPosition = value;
113  update();
114 }
115 
116 void VuoCodeGutter::textChanged()
117 {
118  resizeEvent(NULL);
119  update();
120 }
121 
122 void VuoCodeGutter::resizeEvent(QResizeEvent *event)
123 {
124  int lineNumberDigits = MAX(2, log10(codeEditor->document()->lineCount()) + 1);
125  QFontMetrics lineNumberFontMetrics(lineNumberFont);
126  int iconSize = codeEditor->errorIcon->height() / window()->devicePixelRatio();
127  int width = leftMargin + iconSize + leftMargin + lineNumberFontMetrics.width('0') * lineNumberDigits + rightMargin;
128 
129  if (width == size().width())
130  return;
131 
132  QRect c = codeEditor->rect();
133  setGeometry(QRect(c.left(), c.top(), width, c.height()));
134 
135  codeEditor->setViewportMargins(width, 0, 0, 0);
136 
137  if (codeEditor->parent())
138  {
139  VuoCodeEditorStages *stages = static_cast<VuoCodeEditorStages *>(codeEditor->parent()->parent());
140  stages->updatePosition();
141  }
142 }