Vertikale Linien zur Visualisierung von Einsprüngen implementiert
This commit is contained in:
@@ -194,6 +194,126 @@ void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeEditor::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
// Zuerst den normalen Editor-Inhalt zeichnen
|
||||||
|
QPlainTextEdit::paintEvent(event);
|
||||||
|
|
||||||
|
// Danach die Einrück-Führungslinien darüber legen
|
||||||
|
const int tabSize = m_settings->tabSize();
|
||||||
|
if (tabSize <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(viewport());
|
||||||
|
|
||||||
|
// Farbe: subtil, passt zu Hell- und Dunkeltheme
|
||||||
|
QColor guideColor = palette().color(QPalette::Text);
|
||||||
|
guideColor.setAlpha(30);
|
||||||
|
painter.setPen(QPen(guideColor, 1, Qt::SolidLine));
|
||||||
|
|
||||||
|
const QFontMetrics fm(font());
|
||||||
|
const int spaceWidth = fm.horizontalAdvance(' ');
|
||||||
|
const int tabPixels = tabSize * spaceWidth;
|
||||||
|
|
||||||
|
if (tabPixels <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// X-Startposition des Textes direkt aus dem Layout des ersten Blocks holen.
|
||||||
|
// Das ist der einzige zuverlässige Weg — Qt berücksichtigt intern Margins,
|
||||||
|
// Gutter und Frame-Abstände die sich nicht sauber manuell nachrechnen lassen.
|
||||||
|
int textOriginX = 0;
|
||||||
|
{
|
||||||
|
QTextBlock firstBlock = firstVisibleBlock();
|
||||||
|
if (!firstBlock.isValid())
|
||||||
|
{
|
||||||
|
firstBlock = document()->begin();
|
||||||
|
}
|
||||||
|
if (firstBlock.isValid())
|
||||||
|
{
|
||||||
|
const QRectF blockRect = blockBoundingGeometry(firstBlock)
|
||||||
|
.translated(contentOffset());
|
||||||
|
// Position des ersten Zeichens im Layout
|
||||||
|
const QTextLayout *layout = firstBlock.layout();
|
||||||
|
if (layout && layout->lineCount() > 0)
|
||||||
|
{
|
||||||
|
textOriginX = static_cast<int>(blockRect.left()
|
||||||
|
+ layout->lineAt(0).position().x());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textOriginX = static_cast<int>(blockRect.left());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontalen Scroll-Offset berücksichtigen
|
||||||
|
const int scrollX = horizontalScrollBar()->value();
|
||||||
|
|
||||||
|
// Sichtbaren Zeilenbereich bestimmen
|
||||||
|
QTextBlock block = firstVisibleBlock();
|
||||||
|
const int bottom = event->rect().bottom();
|
||||||
|
|
||||||
|
while (block.isValid())
|
||||||
|
{
|
||||||
|
const QRectF blockRect = blockBoundingGeometry(block).translated(contentOffset());
|
||||||
|
|
||||||
|
if (blockRect.top() > bottom)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block.isVisible())
|
||||||
|
{
|
||||||
|
const QString text = block.text();
|
||||||
|
|
||||||
|
// Einrückungstiefe der Zeile zählen (Leerzeichen / Tabs)
|
||||||
|
int indentSpaces = 0;
|
||||||
|
for (const QChar &ch : text)
|
||||||
|
{
|
||||||
|
if (ch == ' ')
|
||||||
|
{
|
||||||
|
++indentSpaces;
|
||||||
|
}
|
||||||
|
else if (ch == '\t')
|
||||||
|
{
|
||||||
|
// Tab auffüllen auf nächsten Tab-Stop
|
||||||
|
indentSpaces = ((indentSpaces / tabSize) + 1) * tabSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int indentStops = indentSpaces / tabSize;
|
||||||
|
|
||||||
|
// Für jeden Einrückungslevel eine vertikale Linie zeichnen
|
||||||
|
for (int stop = 1; stop <= indentStops; ++stop)
|
||||||
|
{
|
||||||
|
const int xPixel = textOriginX + stop * tabPixels - scrollX;
|
||||||
|
|
||||||
|
// Nur im sichtbaren Bereich zeichnen
|
||||||
|
if (xPixel < lineNumberAreaWidth() || xPixel > viewport()->width())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int y1 = static_cast<int>(blockRect.top());
|
||||||
|
const int y2 = static_cast<int>(blockRect.bottom());
|
||||||
|
|
||||||
|
painter.drawLine(xPixel, y1, xPixel, y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block = block.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeEditor::resizeEvent(QResizeEvent *event)
|
void CodeEditor::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
QPlainTextEdit::resizeEvent(event);
|
QPlainTextEdit::resizeEvent(event);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ signals:
|
|||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateLineNumberAreaWidth(int newBlockCount);
|
void updateLineNumberAreaWidth(int newBlockCount);
|
||||||
|
|||||||
Reference in New Issue
Block a user