polishing of block highlighting, and a new folder bar.

This commit is contained in:
mae
2009-04-24 16:44:48 +02:00
parent dfd2c5dbc3
commit 5f89921179
4 changed files with 183 additions and 159 deletions

View File

@@ -135,6 +135,7 @@ ITextEditor *BaseTextEditor::openEditorAt(const QString &fileName,
texteditor->gotoLine(line, column);
return texteditor;
}
return 0;
}
@@ -161,9 +162,8 @@ BaseTextEditor::BaseTextEditor(QWidget *parent)
d->extraAreaSelectionAnchorBlockNumber
= d->extraAreaToggleMarkBlockNumber
= d->extraAreaHighlightCollapseBlockNumber
= d->extraAreaHighlightFadingBlockNumber
= d->extraAreaHighlightCollapseColumn
= -1;
d->extraAreaCollapseAlpha = 255;
d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber = -1;
@@ -199,13 +199,6 @@ BaseTextEditor::BaseTextEditor(QWidget *parent)
slotCursorPositionChanged();
setFrameStyle(QFrame::NoFrame);
d->extraAreaTimeLine = new QTimeLine(150, this);
d->extraAreaTimeLine->setFrameRange(0, 255);
connect(d->extraAreaTimeLine, SIGNAL(frameChanged(int)), this,
SLOT(setCollapseIndicatorAlpha(int)));
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
this, SLOT(currentEditorChanged(Core::IEditor*)));
}
@@ -1227,7 +1220,7 @@ void BaseTextEditor::setHighlightBlocks(bool b)
if (d->m_highlightBlocks == b)
return;
d->m_highlightBlocks = b;
d->m_highlightBlocksInfo = BaseTextEditorPrivateHighlightBlocks();
d->extraAreaHighlightCollapseBlockNumber = -1;
_q_highlightBlocks();
}
@@ -1512,14 +1505,22 @@ void BaseTextEditor::resizeEvent(QResizeEvent *e)
QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
}
QRect BaseTextEditor::collapseBox(const QTextBlock &block)
QRect BaseTextEditor::collapseBox()
{
QRectF br = blockBoundingGeometry(block).translated(contentOffset());
int collapseBoxWidth = fontMetrics().lineSpacing() + 1;
return QRect(d->m_extraArea->width() - collapseBoxWidth + collapseBoxWidth/4,
int(br.top()) + collapseBoxWidth/4,
2 * (collapseBoxWidth/4) + 1, 2 * (collapseBoxWidth/4) + 1);
if (d->m_highlightBlocksInfo.isEmpty() || d->extraAreaHighlightCollapseBlockNumber < 0)
return QRect();
QTextBlock begin = document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last());
QTextBlock end= document()->findBlockByNumber(d->m_highlightBlocksInfo.close.first());
if (!begin.isValid() || !end.isValid())
return QRect();
QRectF br = blockBoundingGeometry(begin).translated(contentOffset());
QRectF er = blockBoundingGeometry(end).translated(contentOffset());
int collapseBoxWidth = fontMetrics().lineSpacing() + 1;
return QRect(d->m_extraArea->width() - collapseBoxWidth,
int(br.top()),
collapseBoxWidth,
er.bottom() - br.top());
}
QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const {
@@ -1703,9 +1704,8 @@ void BaseTextEditorPrivate::moveCursorVisible(bool ensureVisible)
static QColor calcBlendColor(const QColor &baseColor, int factor = 1)
{
const int blendBase = (baseColor.value() > 128) ? 0 : 255;
const int blendBase = (baseColor.value() > 128) ? 0 : 255;
// Darker backgrounds may need a bit more contrast
// (this calculation is temporary solution until we have a setting for this color)
const int blendFactor = (baseColor.value() > 128) ? 8 : 16;
QColor blendColor = baseColor;
@@ -1791,7 +1791,7 @@ void BaseTextEditor::paintEvent(QPaintEvent *e)
QRectF r = blockBoundingRect(block).translated(offset);
if (d->m_highlightBlocks) {
if (!d->m_highlightBlocksInfo.isEmpty()) {
int n = block.blockNumber();
int depth = 0;
@@ -2169,6 +2169,9 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
QTC_ASSERT(documentLayout, return);
int cursorBlockNumber = textCursor().blockNumber();
const QColor baseColor = palette().base().color();
QPalette pal = d->m_extraArea->palette();
pal.setCurrentColorGroup(QPalette::Active);
QPainter painter(d->m_extraArea);
@@ -2188,12 +2191,12 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
painter.fillRect(e->rect().intersected(QRect(0, 0, extraAreaWidth, INT_MAX)),
pal.color(QPalette::Background));
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top;
#if 0
int extraAreaHighlightCollapseEndBlockNumber = -1;
int extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
@@ -2208,7 +2211,7 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
else
extraAreaHighlightCollapseEndBlockNumber = extraAreaHighlightCollapseBlockNumber;
}
#endif
while (block.isValid() && top <= e->rect().bottom()) {
@@ -2274,68 +2277,57 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
}
if (d->m_codeFoldingVisible) {
const QRect box(extraAreaWidth + collapseBoxWidth/4, top + collapseBoxWidth/4,
2 * (collapseBoxWidth/4) + 1, 2 * (collapseBoxWidth/4) + 1);
const QPoint boxCenter = box.center();
const QRect r(extraAreaWidth+2, top, collapseBoxWidth-4, bottom - top);
bool drawBox = !nextBlock.isVisible();
QColor textColorAlpha = pal.text().color();
textColorAlpha.setAlpha(d->extraAreaCollapseAlpha);
QColor textColorInactive = pal.text().color();
textColorInactive.setAlpha(100);
QColor textColor = pal.text().color();
textColor.setAlpha(qMax(textColorInactive.alpha(), d->extraAreaCollapseAlpha));
const QPen pen( (blockNumber >= extraAreaHighlightCollapseBlockNumber
&& blockNumber <= extraAreaHighlightCollapseEndBlockNumber) ?
textColorAlpha : pal.base().color());
const QPen boxPen((blockNumber == extraAreaHighlightCollapseBlockNumber) ?
textColor : textColorInactive);
const QPen endPen((blockNumber == extraAreaHighlightCollapseEndBlockNumber) ?
textColorAlpha : pal.base().color());
const QPen previousPen((blockNumber-1 >= extraAreaHighlightCollapseBlockNumber
&& blockNumber-1 < extraAreaHighlightCollapseEndBlockNumber) ?
textColorAlpha : pal.base().color());
const QPen nextPen((blockNumber+1 > extraAreaHighlightCollapseBlockNumber
&& blockNumber+1 <= extraAreaHighlightCollapseEndBlockNumber) ?
textColorAlpha : pal.base().color());
TextBlockUserData *nextBlockUserData = TextEditDocumentLayout::testUserData(nextBlock);
bool collapseNext = nextBlockUserData
&& nextBlockUserData->collapseMode()
== TextBlockUserData::CollapseThis
&& !nextBlockUserData->ifdefedOut();
bool nextHasClosingCollapse = nextBlockUserData
&& nextBlockUserData->hasClosingCollapseInside()
&& nextBlockUserData->ifdefedOut();
bool drawBox = ((collapseAfter || collapseNext) && !nextHasClosingCollapse);
if (braceDepth || (collapseNext && nextBlock.isVisible())) {
painter.setPen((hasClosingCollapse || !nextBlock.isVisible())? nextPen : pen);
painter.drawLine(boxCenter.x(), boxCenter.y(), boxCenter.x(), bottom - 1);
int minBraceDepth = qMax(braceDepth, previousBraceDepth);
if (minBraceDepth > 0) {
QColor color = calcBlendColor(baseColor, minBraceDepth);
if (!d->m_highlightBlocksInfo.isEmpty()
&& blockNumber >= d->m_highlightBlocksInfo.open.last()
&& blockNumber <= d->m_highlightBlocksInfo.close.first())
color = color.light();
painter.fillRect(r, color);
}
bool drawDown = !d->m_highlightBlocksInfo.isEmpty()
&& blockNumber == d->m_highlightBlocksInfo.open.last();
bool drawUp = !d->m_highlightBlocksInfo.isEmpty()
&& blockNumber == d->m_highlightBlocksInfo.close.first();
if (previousBraceDepth || collapseThis) {
painter.setPen((collapseAfter || collapseNext) ? previousPen : pen);
painter.drawLine(boxCenter.x(), top, boxCenter.x(), boxCenter.y());
}
if (drawBox) {
painter.setPen(boxPen);
painter.setBrush(pal.base());
painter.drawRect(box.adjusted(0, 0, -1, -1));
if (!nextBlock.isVisible())
painter.drawLine(boxCenter.x(), box.top() + 2, boxCenter.x(), box.bottom() - 2);
painter.drawLine(box.left() + 2, boxCenter.y(), box.right() - 2, boxCenter.y());
} else if (hasClosingCollapse || collapseAfter || collapseNext) {
painter.setPen(endPen);
painter.drawLine(boxCenter.x() + 1, boxCenter.y(), box.right() - 1, boxCenter.y());
if (drawBox || drawDown || drawUp) {
painter.setRenderHint(QPainter::Antialiasing, true);
painter.translate(.5, .5);
painter.setPen(pal.text().color());
painter.setBrush(pal.text().color());
if (drawBox) {
QPointF points1[3] = { QPointF(r.left(), r.center().y()-1),
QPointF(r.center().x(), r.top()),
QPointF(r.right(), r.center().y()-1) };
QPointF points2[3] = { QPointF(r.left(), r.center().y()+1),
QPointF(r.center().x(), r.bottom()-1),
QPointF(r.right(), r.center().y()+1) };
painter.drawPolygon(points1, 3);
painter.drawPolygon(points2, 3);
} else if (drawUp) {
QPointF points[3] = { QPointF(r.left(), r.bottom()-1),
QPointF(r.center().x(), r.center().y()),
QPointF(r.right(), r.bottom()-1) };
painter.drawPolygon(points, 3);
} else if(drawDown) {
QPointF points[3] = { QPointF(r.left(), r.top()),
QPointF(r.center().x(), r.center().y()),
QPointF(r.right(), r.top()) };
painter.drawPolygon(points, 3);
}
painter.translate(-.5, -.5);
painter.setRenderHint(QPainter::Antialiasing, false);
}
}
painter.restore();
}
@@ -2353,12 +2345,34 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
if (d->m_lineNumbersVisible) {
const QString &number = QString::number(blockNumber + 1);
if (blockNumber == cursorBlockNumber) {
painter.save();
painter.setPen(pal.color(QPalette::Background).value() < 128 ? Qt::white : Qt::black);
}
painter.drawText(markWidth, top, extraAreaWidth - markWidth - 4, fm.height(), Qt::AlignRight, number);
if (blockNumber == cursorBlockNumber)
painter.restore();
}
block = nextVisibleBlock;
blockNumber = nextVisibleBlockNumber;
}
if (d->m_codeFoldingVisible) {
painter.drawLine(extraAreaWidth, 0,
extraAreaWidth, viewport()->height());
painter.drawLine(extraAreaWidth + collapseBoxWidth - 1, 0,
extraAreaWidth + collapseBoxWidth - 1, viewport()->height());
QRect cb = collapseBox();
// if (!cb.isEmpty()) {
// QPen pen(baseColor.value() < 128 ? Qt::white : Qt::black);
// pen.setWidth(2);
// painter.setPen(pen);
// painter.setRenderHint(QPainter::Antialiasing, true);
// painter.translate(.5, .5);
// painter.drawRoundedRect(QRect(cb.adjusted(0, 0,-2, -2)), 4, 4);
// }
}
}
void BaseTextEditor::slotModificationChanged(bool m)
@@ -2429,6 +2443,9 @@ void BaseTextEditor::slotCursorPositionChanged()
setExtraSelections(CurrentLineSelection, extraSelections);
if (d->m_highlightBlocks) {
QTextCursor cursor = textCursor();
d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
d->m_highlightBlocksTimer->start(100);
}
}
@@ -2450,12 +2467,6 @@ void BaseTextEditor::slotUpdateBlockNotify(const QTextBlock &block)
}
}
void BaseTextEditor::setCollapseIndicatorAlpha(int alpha)
{
d->extraAreaCollapseAlpha = alpha;
d->m_extraArea->update();
}
void BaseTextEditor::timerEvent(QTimerEvent *e)
{
if (e->timerId() == d->autoScrollTimer.timerId()) {
@@ -2545,13 +2556,9 @@ void BaseTextEditor::mousePressEvent(QMouseEvent *e)
void BaseTextEditor::extraAreaLeaveEvent(QEvent *)
{
if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
d->extraAreaHighlightFadingBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
d->extraAreaHighlightCollapseBlockNumber = -1; // missing mouse move event from Qt
d->extraAreaTimeLine->setDirection(QTimeLine::Backward);
if (d->extraAreaTimeLine->state() != QTimeLine::Running)
d->extraAreaTimeLine->start();
}
// fake missing mouse move event from Qt
QMouseEvent me(QEvent::MouseMove, QPoint(-1, -1), Qt::NoButton, 0, 0);
extraAreaMouseEvent(&me);
}
void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
@@ -2562,43 +2569,48 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
int markWidth;
extraAreaWidth(&markWidth);
if (e->type() == QEvent::MouseMove && e->buttons() == 0) { // mouse tracking
if (d->m_codeFoldingVisible
&& e->type() == QEvent::MouseMove && e->buttons() == 0) { // mouse tracking
// Update which folder marker is highlighted
const int highlightBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
const int highlightColumn = d->extraAreaHighlightCollapseColumn;
d->extraAreaHighlightCollapseBlockNumber = -1;
d->extraAreaHighlightCollapseColumn = -1;
if (d->m_codeFoldingVisible
&& TextBlockUserData::canCollapse(cursor.block())
&& !TextBlockUserData::hasClosingCollapseInside(cursor.block().next())
&& collapseBox(cursor.block()).contains(e->pos()))
if (d->m_highlightBlocks) {
QTextCursor cursor = textCursor();
d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
// Set whether the mouse cursor is a hand or normal arrow
bool hand = (e->pos().x() <= markWidth || d->extraAreaHighlightCollapseBlockNumber >= 0);
if (hand != (d->m_extraArea->cursor().shape() == Qt::PointingHandCursor))
d->m_extraArea->setCursor(hand ? Qt::PointingHandCursor : Qt::ArrowCursor);
// Start fading in or out the highlighted folding marker
if (highlightBlockNumber != d->extraAreaHighlightCollapseBlockNumber) {
d->extraAreaTimeLine->stop();
d->extraAreaTimeLine->setDirection(d->extraAreaHighlightCollapseBlockNumber >= 0?
QTimeLine::Forward : QTimeLine::Backward);
if (d->extraAreaTimeLine->direction() == QTimeLine::Backward)
d->extraAreaHighlightFadingBlockNumber = highlightBlockNumber;
else
d->extraAreaHighlightFadingBlockNumber = -1;
if (d->extraAreaTimeLine->state() != QTimeLine::Running)
d->extraAreaTimeLine->start();
d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
}
int collapseBoxWidth = fontMetrics().lineSpacing() + 1;
if (e->pos().x() > extraArea()->width() - collapseBoxWidth) {
d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
if (!TextBlockUserData::hasClosingCollapse(cursor.block()))
d->extraAreaHighlightCollapseColumn = cursor.block().length()-1;
}
if (highlightBlockNumber != d->extraAreaHighlightCollapseBlockNumber
|| highlightColumn != d->extraAreaHighlightCollapseColumn)
d->m_highlightBlocksTimer->start(100);
}
if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
if (e->button() == Qt::LeftButton) {
if (d->m_codeFoldingVisible && TextBlockUserData::canCollapse(cursor.block())
&& !TextBlockUserData::hasClosingCollapseInside(cursor.block().next())
&& collapseBox(cursor.block()).contains(e->pos())) {
toggleBlockVisible(cursor.block());
d->moveCursorVisible(false);
int collapseBoxWidth = fontMetrics().lineSpacing() + 1;
if (d->m_codeFoldingVisible && e->pos().x() > extraArea()->width() - collapseBoxWidth) {
if (!cursor.block().next().isVisible()) {
toggleBlockVisible(cursor.block());
d->moveCursorVisible(false);
} else if (collapseBox().contains(e->pos())) {
cursor.setPosition(
document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last()).position()
);
QTextBlock c = cursor.block();
if (!TextBlockUserData::canCollapse(c))
c = c.previous();
toggleBlockVisible(c);
d->moveCursorVisible(false);
}
} else if (d->m_marksVisible && e->pos().x() > markWidth) {
QTextCursor selection = cursor;
selection.setVisualNavigation(true);
@@ -3153,33 +3165,6 @@ bool TextBlockUserData::findPreviousOpenParenthesis(QTextCursor *cursor, bool se
return false;
}
bool TextBlockUserData::findNextClosingParenthesis(QTextCursor *cursor, bool select)
{
QTextBlock block = cursor->block();
int position = cursor->position();
int ignore = 0;
while (block.isValid()) {
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
for (int i = 0; i < parenList.count(); ++i) {
Parenthesis paren = parenList.at(i);
if (block == cursor->block() && position - block.position() >= paren.pos)
continue;
if (paren.type == Parenthesis::Opened) {
++ignore;
} else if (ignore > 0) {
--ignore;
} else {
cursor->setPosition(block.position() + paren.pos+1, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
return true;
}
}
}
block = block.next();
}
return false;
}
bool TextBlockUserData::findPreviousBlockOpenParenthesis(QTextCursor *cursor)
{
QTextBlock block = cursor->block();
@@ -3194,7 +3179,7 @@ bool TextBlockUserData::findPreviousBlockOpenParenthesis(QTextCursor *cursor)
&& paren.chr != QLatin1Char('+') && paren.chr != QLatin1Char('-'))
continue;
if (block == cursor->block() &&
(position - block.position() <= paren.pos))
(position - block.position() <= paren.pos + (paren.type == Parenthesis::Closed ? 1 : 0)))
continue;
if (paren.type == Parenthesis::Closed) {
++ignore;
@@ -3211,6 +3196,34 @@ bool TextBlockUserData::findPreviousBlockOpenParenthesis(QTextCursor *cursor)
return false;
}
bool TextBlockUserData::findNextClosingParenthesis(QTextCursor *cursor, bool select)
{
QTextBlock block = cursor->block();
int position = cursor->position();
int ignore = 0;
while (block.isValid()) {
Parentheses parenList = TextEditDocumentLayout::parentheses(block);
if (!parenList.isEmpty() && !TextEditDocumentLayout::ifdefedOut(block)) {
for (int i = 0; i < parenList.count(); ++i) {
Parenthesis paren = parenList.at(i);
if (block == cursor->block() &&
(position - block.position() > paren.pos - (paren.type == Parenthesis::Opened ? 1 : 0)))
continue;
if (paren.type == Parenthesis::Opened) {
++ignore;
} else if (ignore > 0) {
--ignore;
} else {
cursor->setPosition(block.position() + paren.pos+1, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor);
return true;
}
}
}
block = block.next();
}
return false;
}
bool TextBlockUserData::findNextBlockClosingParenthesis(QTextCursor *cursor)
{
QTextBlock block = cursor->block();
@@ -3224,7 +3237,8 @@ bool TextBlockUserData::findNextBlockClosingParenthesis(QTextCursor *cursor)
if (paren.chr != QLatin1Char('{') && paren.chr != QLatin1Char('}')
&& paren.chr != QLatin1Char('+') && paren.chr != QLatin1Char('-'))
continue;
if (block == cursor->block() && position - block.position() >= paren.pos)
if (block == cursor->block() &&
(position - block.position() > paren.pos - (paren.type == Parenthesis::Opened ? 1 : 0)))
continue;
if (paren.type == Parenthesis::Opened) {
++ignore;
@@ -3378,18 +3392,31 @@ void BaseTextEditor::_q_matchParentheses()
void BaseTextEditor::_q_highlightBlocks()
{
QTextCursor cursor = textCursor();
QTextCursor closeCursor = cursor;
BaseTextEditorPrivateHighlightBlocks highlightBlocksInfo;
while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor)) {
highlightBlocksInfo.open.prepend(cursor.blockNumber());
highlightBlocksInfo.visualIndent.prepend(d->visualIndent(cursor.block()));
if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor))
highlightBlocksInfo.close.append(closeCursor.blockNumber());
if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
QTextBlock block = document()->findBlockByNumber(d->extraAreaHighlightCollapseBlockNumber);
if (block.isValid()) {
QTextCursor cursor(block);
if (d->extraAreaHighlightCollapseColumn >= 0)
cursor.setPosition(cursor.position() + qMin(d->extraAreaHighlightCollapseColumn+1,
block.length()));
QTextCursor closeCursor;
while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor)) {
highlightBlocksInfo.open.prepend(cursor.blockNumber());
highlightBlocksInfo.visualIndent.prepend(d->visualIndent(cursor.block()));
if (closeCursor.isNull())
closeCursor = cursor;
if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor))
highlightBlocksInfo.close.append(closeCursor.blockNumber());
}
}
}
if (d->m_highlightBlocksInfo != highlightBlocksInfo) {
d->m_highlightBlocksInfo = highlightBlocksInfo;
viewport()->update();
d->m_extraArea->update();
}
}