diff options
author | Felipe Heidrich <fheidric> | 2005-11-21 20:52:42 +0000 |
---|---|---|
committer | Felipe Heidrich <fheidric> | 2005-11-21 20:52:42 +0000 |
commit | 73be0ec89889e2c1322c1bfa09d83f81f689ab7f (patch) | |
tree | 2f37c92d8010b642afb826fcc6e090ac46d12a7d | |
parent | bf221f66369037ceea33728d5ed71d69549dd596 (diff) | |
download | eclipse.platform.swt-73be0ec89889e2c1322c1bfa09d83f81f689ab7f.tar.gz eclipse.platform.swt-73be0ec89889e2c1322c1bfa09d83f81f689ab7f.tar.xz eclipse.platform.swt-73be0ec89889e2c1322c1bfa09d83f81f689ab7f.zip |
fixes, merges styles, show location, new calculatetopindex, etc
2 files changed, 402 insertions, 391 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java index c9392502bd..685718f0aa 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java @@ -108,7 +108,7 @@ public class StyledText extends Canvas { int verticalScrollOffset = 0; // pixel based int horizontalScrollOffset = 0; // pixel based int topIndex = 0; // top visible line - int topOffset = 0; // offset of first character in top line + int topIndexY; int clientAreaHeight = 0; // the client area height. Needed to calculate content width for new visible lines during Resize callback int clientAreaWidth = 0; // the client area width. Needed during Resize callback to determine if line wrap needs to be recalculated int tabLength = 4; // number of characters in a tab @@ -149,7 +149,6 @@ public class StyledText extends Canvas { int caretDirection = SWT.NULL; Caret defaultCaret = null; boolean updateCaretDirection = true; - int partialHeight; // amount, in pixels, of the partial top index that is visible boolean fixedLineHeight; int alignment; @@ -274,7 +273,7 @@ public class StyledText extends Canvas { if (printerColor == null) { printerColor = new Color (printer, color.getRGB()); resources.put(color, printerColor); - } + } printerRenderer.setLineBackground(i, 1, printerColor); } else { printerRenderer.setLineBackground(i, 1, null); @@ -1454,7 +1453,8 @@ void calculateScrollBars() { * The top index starts at 0. */ void calculateTopIndex(int delta) { - int oldTopIndex = topIndex; + int oldTopIndex = topIndex; + int oldTopIndexY = topIndexY; if (isFixedLineHeight()) { int verticalIncrement = getVerticalIncrement(); if (verticalIncrement == 0) { @@ -1480,48 +1480,40 @@ void calculateTopIndex(int delta) { } } } else { - if (delta > 0) { - if (partialHeight > delta) { - partialHeight -= delta; - return; - } - delta -= partialHeight; - partialHeight = 0; - + if (delta >= 0) { + delta -= topIndexY; + int lineIndex = topIndex; int lineCount = content.getLineCount(); - while (delta > 0 && topIndex < lineCount -1) { - int lineHeight = renderer.getLineHeight(topIndex); - topIndex++; - if (lineHeight > delta) { - partialHeight = lineHeight - delta; - break; - } - delta -= lineHeight; + while (lineIndex < lineCount) { + if (delta <= 0) break; + delta -= renderer.getLineHeight(lineIndex++); } - } else { - if (topIndex > 0) { - int height = renderer.getLineHeight(topIndex - 1) - partialHeight; - if (height > -delta) { - partialHeight -= delta; - return; - } - delta += height; - partialHeight = 0; - topIndex--; + if (lineIndex < lineCount && -delta + renderer.getLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) { + topIndex = lineIndex; + topIndexY = -delta; + } else { + topIndex = lineIndex - 1; + topIndexY = -renderer.getLineHeight(topIndex) - delta; } - while (-delta > 0 && topIndex > 0) { - int lineHeight = renderer.getLineHeight(topIndex - 1); - if (lineHeight > -delta) { - partialHeight = -delta; - break; - } - topIndex--; + } else { + delta -= topIndexY; + int lineIndex = topIndex; + while (lineIndex > 0) { + int lineHeight = renderer.getLineHeight(lineIndex - 1); + if (delta + lineHeight > 0) break; delta += lineHeight; + lineIndex--; + } + if (lineIndex == 0 || -delta + renderer.getLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) { + topIndex = lineIndex; + topIndexY = - delta; + } else { + topIndex = lineIndex - 1; + topIndexY = - renderer.getLineHeight(topIndex) - delta; } } } - if (topIndex != oldTopIndex) { - topOffset = content.getOffsetAtLine(topIndex); + if (topIndex != oldTopIndex || oldTopIndexY != topIndexY) { renderer.calculateClientArea(); setScrollBars(false); } @@ -1558,26 +1550,7 @@ void claimBottomFreeSpace() { int bottomIndex = getPartialBottomIndex(); int height = getLinePixel(bottomIndex + 1); if (clientAreaHeight > height) { - int delta = clientAreaHeight - height; - int maxDelta = verticalScrollOffset; - if (maxDelta == -1) { - int index = getPartialTopIndex(); - maxDelta = renderer.getLineHeight(index) - partialHeight; - while (delta > maxDelta && index > 0) { - index--; - maxDelta += renderer.getLineHeight(index); - } - } - delta = Math.min(maxDelta, delta); - if (verticalScrollOffset != -1) { - scrollVertical(-delta, true); - } else { - // scrolling when verticalScrollOffset is invalid is a slow operation - // only update the top index and the caret, caller needs to invalidate the area - // verticalScrollOffset is valid at the end of the calculate idle - calculateTopIndex(-delta); - } - + scrollVertical(-getAvailableHeightAbove(clientAreaHeight - height), true); } } } @@ -1725,6 +1698,20 @@ public int getAlignment() { checkWidget(); return alignment; } +int getAvailableHeightAbove(int height) { + int maxHeight = verticalScrollOffset; + if (maxHeight == -1) { + int lineIndex = topIndex - 1; + maxHeight = -topIndexY; + if (topIndexY > 0) { + maxHeight += renderer.getLineHeight(lineIndex--); + } + while (height > maxHeight && lineIndex > 0) { + maxHeight += renderer.getLineHeight(lineIndex--); + } + } + return Math.min(height, maxHeight); +} /** * Returns a string that uses only the line delimiter specified by the * StyledTextContent implementation. @@ -2197,29 +2184,23 @@ void doLineDown(boolean select) { int lineOffset = content.getOffsetAtLine(caretLine); int offsetInLine = caretOffset - lineOffset; TextLayout layout = renderer.getTextLayout(caretLine); - int lineIndex = layout.getLineIndex(offsetInLine); - int[] offsets = layout.getLineOffsets(); + int lineIndex = getVisualLineIndex(layout, offsetInLine); int layoutLineCount = layout.getLineCount(); - if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { - lineIndex--; - } - Rectangle bounds = layout.getLineBounds(lineIndex); - lastLine = caretLine == lineCount - 1 && lineIndex == layoutLineCount - 1; - y += bounds.y + bounds.height; if (lineIndex == layoutLineCount - 1) { - y += layout.getSpacing(); + lastLine = caretLine == lineCount - 1; + caretLine++; + } else { + y = layout.getLineBounds(lineIndex + 1).y; } renderer.disposeTextLayout(layout); } else { - lastLine = caretLine == content.getLineCount() - 1; - y += renderer.getLineHeight(caretLine); + lastLine = caretLine == lineCount - 1; + caretLine++; } if (lastLine) { - if (select) { - caretOffset = content.getCharCount(); - } + if (select) caretOffset = content.getCharCount(); } else { - caretOffset = getOffsetAtPoint(columnX, y + getLinePixel(caretLine)); + caretOffset = getOffsetAtPoint(columnX, y, caretLine); } int oldColumnX = columnX; int oldHScrollOffset = horizontalScrollOffset; @@ -2241,15 +2222,12 @@ void doLineEnd() { int lineOffset = content.getOffsetAtLine(caretLine); int lineEndOffset; if (wordWrap) { - int offsetInLine = caretOffset - lineOffset; TextLayout layout = renderer.getTextLayout(caretLine); - int lineIndex = layout.getLineIndex(offsetInLine); + int offsetInLine = caretOffset - lineOffset; + int lineIndex = getVisualLineIndex(layout, offsetInLine); int[] offsets = layout.getLineOffsets(); - if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { - lineIndex--; - } - renderer.disposeTextLayout(layout); lineEndOffset = lineOffset + offsets[lineIndex + 1]; + renderer.disposeTextLayout(layout); } else { int lineLength = content.getLine(caretLine).length(); lineEndOffset = lineOffset + lineLength; @@ -2267,15 +2245,12 @@ void doLineStart() { int caretLine = getCaretLine(); int lineOffset = content.getOffsetAtLine(caretLine); if (wordWrap) { - int offsetInLine = caretOffset - lineOffset; TextLayout layout = renderer.getTextLayout(caretLine); - int lineIndex = layout.getLineIndex(offsetInLine); + int offsetInLine = caretOffset - lineOffset; + int lineIndex = getVisualLineIndex(layout, offsetInLine); int[] offsets = layout.getLineOffsets(); - if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { - lineIndex--; - } - renderer.disposeTextLayout(layout); lineOffset += offsets[lineIndex]; + renderer.disposeTextLayout(layout); } if (caretOffset > lineOffset) { caretOffset = lineOffset; @@ -2291,29 +2266,31 @@ void doLineStart() { * @return index of the new line relative to the first line in the document */ void doLineUp(boolean select) { - int caretLine = getCaretLine(); - int y = 0; - boolean firstLine; + int caretLine = getCaretLine(), y = 0; + boolean firstLine = false; if (wordWrap) { int lineOffset = content.getOffsetAtLine(caretLine); int offsetInLine = caretOffset - lineOffset; TextLayout layout = renderer.getTextLayout(caretLine); - int lineIndex = layout.getLineIndex(offsetInLine); - int[] offsets = layout.getLineOffsets(); - if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { - lineIndex--; + int lineIndex = getVisualLineIndex(layout, offsetInLine); + if (lineIndex == 0) { + firstLine = caretLine == 0; + if (!firstLine) { + caretLine--; + y = renderer.getLineHeight(caretLine) - 1; + } + } else { + y = layout.getLineBounds(lineIndex - 1).y; } - Rectangle bounds = layout.getLineBounds(lineIndex); renderer.disposeTextLayout(layout); - firstLine = caretLine == 0 && lineIndex == 0; - y += bounds.y; } else { firstLine = caretLine == 0; + caretLine--; } if (firstLine) { if (select) caretOffset = 0; } else { - caretOffset = getOffsetAtPoint(columnX, y - 1 + getLinePixel(caretLine)); + caretOffset = getOffsetAtPoint(columnX, y, caretLine); } int oldColumnX = columnX; int oldHScrollOffset = horizontalScrollOffset; @@ -2467,10 +2444,10 @@ void doPageDown(boolean select, int height) { int lineHeight = renderer.getLineHeight(partialBottomIndex); if (height == -1) { height = topY; - if (wordWrap) { - if (topY + lineHeight >= clientAreaHeight) { - height += lineHeight; - } else { + if (topY + lineHeight <= clientAreaHeight) { + height += lineHeight; + } else { + if (wordWrap) { TextLayout layout = renderer.getTextLayout(partialBottomIndex); int y = clientAreaHeight - topY; for (int i = 0; i < layout.getLineCount(); i++) { @@ -2511,13 +2488,9 @@ void doPageDown(boolean select, int height) { } int caretHeight = height; if (wordWrap) { - int offsetInLine = caretOffset - content.getOffsetAtLine(caretLine); TextLayout layout = renderer.getTextLayout(caretLine); - lineIndex = layout.getLineIndex(offsetInLine); - int[] offsets = layout.getLineOffsets(); - if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { - lineIndex--; - } + int offsetInLine = caretOffset - content.getOffsetAtLine(caretLine); + lineIndex = getVisualLineIndex(layout, offsetInLine); caretHeight += layout.getLineBounds(lineIndex).y; renderer.disposeTextLayout(layout); } @@ -2545,10 +2518,30 @@ void doPageEnd() { if (isSingleLine()) { doLineEnd(); } else { - int line = getBottomIndex(); - int bottomCaretOffset = content.getOffsetAtLine(line) + content.getLine(line).length(); - if (caretOffset < bottomCaretOffset) { - caretOffset = bottomCaretOffset; + int bottomOffset; + if (wordWrap) { + int lineIndex = getPartialBottomIndex(); + TextLayout layout = renderer.getTextLayout(lineIndex); + int y = (clientAreaHeight - bottomMargin) - getLinePixel(lineIndex); + int index = layout.getLineCount() - 1; + while (index >= 0) { + Rectangle bounds = layout.getLineBounds(index); + if (y >= bounds.y + bounds.height) break; + index--; + } + if (index == -1 && lineIndex > 0) { + bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length(); + } else { + bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, layout.getLineOffsets()[index + 1] - 1); + } + renderer.disposeTextLayout(layout); + } else { + int lineIndex = getBottomIndex(); + bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length(); + } + if (caretOffset < bottomOffset) { + caretOffset = bottomOffset; + caretAlignment = OFFSET_LEADING; showCaret(); } } @@ -2557,9 +2550,36 @@ void doPageEnd() { * Moves the cursor to the beginning of the first fully visible line. */ void doPageStart() { - int topCaretOffset = content.getOffsetAtLine(topIndex); - if (caretOffset > topCaretOffset) { - caretOffset = topCaretOffset; + int topOffset; + if (wordWrap) { + int y, lineIndex; + if (topIndexY > 0) { + lineIndex = topIndex - 1; + y = renderer.getLineHeight(lineIndex) - topIndexY; + } else { + lineIndex = topIndex; + y = -topIndexY; + } + TextLayout layout = renderer.getTextLayout(lineIndex); + int index = 0; + int lineCount = layout.getLineCount(); + while (index < lineCount) { + Rectangle bounds = layout.getLineBounds(index); + if (y <= bounds.y) break; + index++; + } + if (index == lineCount) { + topOffset = content.getOffsetAtLine(lineIndex + 1); + } else { + topOffset = content.getOffsetAtLine(lineIndex) + layout.getLineOffsets()[index]; + } + renderer.disposeTextLayout(layout); + } else { + topOffset = content.getOffsetAtLine(topIndex); + } + if (caretOffset > topOffset) { + caretOffset = topOffset; + caretAlignment = OFFSET_LEADING; showCaret(); } } @@ -2594,16 +2614,25 @@ void doPageUp(boolean select, int height) { } } else { int caretLine = getCaretLine(); - int partialTopIndex = getPartialTopIndex(); - int lineHeight = renderer.getLineHeight(partialTopIndex); + int lineHeight, lineIndex; if (height == -1) { - if (partialHeight == 0) { + if (topIndexY == 0) { height = clientAreaHeight; } else { - height = clientAreaHeight - partialHeight; + int y; + if (topIndex > 0) { + lineIndex = topIndex - 1; + lineHeight = renderer.getLineHeight(lineIndex); + height = clientAreaHeight - topIndexY; + y = lineHeight - topIndexY; + } else { + lineIndex = topIndex; + lineHeight = renderer.getLineHeight(lineIndex); + height = clientAreaHeight - (lineHeight + topIndexY); + y = -topIndexY; + } if (wordWrap) { - int y = lineHeight - partialHeight; - TextLayout layout = renderer.getTextLayout(partialTopIndex); + TextLayout layout = renderer.getTextLayout(lineIndex); for (int i = 0; i < layout.getLineCount(); i++) { Rectangle bounds = layout.getLineBounds(i); if (bounds.contains(bounds.x, y)) { @@ -2615,7 +2644,7 @@ void doPageUp(boolean select, int height) { } } } else { - int lineIndex = getLineIndex(clientAreaHeight - height); + lineIndex = getLineIndex(clientAreaHeight - height); int topLineY = getLinePixel(lineIndex); if (wordWrap) { TextLayout layout = renderer.getTextLayout(lineIndex); @@ -2632,23 +2661,11 @@ void doPageUp(boolean select, int height) { height = clientAreaHeight - topLineY; } } - int availableHeight = 0; - if (partialHeight != 0) { - availableHeight = lineHeight - partialHeight; - } - int lineIndex = partialTopIndex - 1; - while (height > availableHeight && lineIndex >= 0) { - availableHeight += renderer.getLineHeight(lineIndex--); - } int caretHeight = height; if (wordWrap) { - int offsetInLine = caretOffset - content.getOffsetAtLine(caretLine); TextLayout layout = renderer.getTextLayout(caretLine); - lineIndex = layout.getLineIndex(offsetInLine); - int[] offsets = layout.getLineOffsets(); - if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { - lineIndex--; - } + int offsetInLine = caretOffset - content.getOffsetAtLine(caretLine); + lineIndex = getVisualLineIndex(layout, offsetInLine); caretHeight += layout.getBounds().height - layout.getLineBounds(lineIndex).y; renderer.disposeTextLayout(layout); } @@ -2661,7 +2678,7 @@ void doPageUp(boolean select, int height) { lineHeight = renderer.getLineHeight(lineIndex); caretOffset = getOffsetAtPoint(columnX, lineHeight - caretHeight, lineIndex); if (select) doSelection(ST.COLUMN_PREVIOUS); - height = Math.min(height, availableHeight); + height = getAvailableHeightAbove(height); scrollVertical(-height, true); if (height == 0) setCaretLocation(); } @@ -3006,12 +3023,31 @@ int getBottomIndex() { int linePixel = getLinePixel(bottomIndex); int lineHeight = renderer.getLineHeight(bottomIndex); if (linePixel + lineHeight > clientAreaHeight) { - bottomIndex--; + if (getLinePixel(bottomIndex - 1) >= topMargin) { + bottomIndex--; + } } } } return bottomIndex; } +Rectangle getBoundsAtOffset(int offset) { + int lineIndex = content.getLineAtOffset(offset); + String line = content.getLine(lineIndex); + Rectangle bounds; + if (line.length() != 0) { + int offsetInLine = offset - content.getOffsetAtLine(lineIndex); + TextLayout layout = renderer.getTextLayout(lineIndex); + bounds = layout.getBounds(offsetInLine, offsetInLine); + renderer.disposeTextLayout(layout); + } else { + bounds = new Rectangle (0, 0, 0, renderer.getLineHeight()); + } + bounds.x += leftMargin - horizontalScrollOffset; + bounds.y += getLinePixel(lineIndex); + return bounds; +} + /** * Returns the caret position relative to the start of the text. * <p> @@ -3535,9 +3571,8 @@ int getLinePixel(int lineIndex) { int lineHeight = renderer.getLineHeight(); return lineIndex * lineHeight - getVerticalScrollOffset() + topMargin; } - - if (lineIndex == topIndex) return partialHeight + topMargin; - int height = partialHeight; + if (lineIndex == topIndex) return topIndexY + topMargin; + int height = topIndexY; if (lineIndex > topIndex) { for (int i = topIndex; i < lineIndex; i++) { height += renderer.getLineHeight(i); @@ -3563,25 +3598,18 @@ int getLineIndex(int y) { } return lineIndex; } - + if (y == topIndexY) return topIndex; int line = topIndex; - if (y < 0) { - if (line == 0) return 0; - line--; - y += renderer.getLineHeight(line) - partialHeight; - while (y < 0 && line > 0) { - line--; - y += renderer.getLineHeight(line); + if (y < topIndexY) { + while (y <= topIndexY && line > 0) { + y += renderer.getLineHeight(--line); } } else { - if (partialHeight > y) return line - 1; - y -= partialHeight; int lineCount = content.getLineCount(); - while (line < lineCount - 1) { - int lineHeight = renderer.getLineHeight(line); - if (lineHeight > y) break; + int lineHeight = renderer.getLineHeight(line); + while (y - lineHeight >= topIndexY && line < lineCount - 1) { y -= lineHeight; - line++; + lineHeight = renderer.getLineHeight(++line); } } return line; @@ -3782,7 +3810,7 @@ int getPartialTopIndex() { int lineHeight = renderer.getLineHeight(); return getVerticalScrollOffset() / lineHeight; } - return partialHeight == 0 ? topIndex : topIndex - 1; + return topIndexY <= 0 ? topIndex : topIndex - 1; } /** * Returns the content in the specified range using the platform line @@ -4442,11 +4470,19 @@ int getVerticalScrollOffset() { for (int i = 0; i < topIndex; i++) { height += renderer.getLineHeight(i); } - height -= partialHeight; + height -= topIndexY; verticalScrollOffset = height; } return verticalScrollOffset; } +int getVisualLineIndex(TextLayout layout, int offsetInLine) { + int lineIndex = layout.getLineIndex(offsetInLine); + int[] offsets = layout.getLineOffsets(); + if (lineIndex != 0 && offsetInLine == offsets[lineIndex] && caretAlignment == PREVIOUS_OFFSET_TRAILING) { + lineIndex--; + } + return lineIndex; +} int getCaretDirection() { if (!isBidiCaret()) return SWT.DEFAULT; if (!updateCaretDirection && caretDirection != SWT.NULL) return caretDirection; @@ -4732,88 +4768,92 @@ void installListeners() { }); } } -/** - * Redraws the specified text range. - * <p> - * - * @param start offset of the first character to redraw - * @param length number of characters to redraw - */ void internalRedrawRange(int start, int length) { if (length <= 0) return; - int end = start + length - 1; - int firstLine = content.getLineAtOffset(start); - int lastLine = content.getLineAtOffset(end); + int end = start + length; + int startLine = content.getLineAtOffset(start); + int endLine = content.getLineAtOffset(end); int partialBottomIndex = getPartialBottomIndex(); int partialTopIndex = getPartialTopIndex(); - if (firstLine > partialBottomIndex || lastLine < partialTopIndex) { + if (startLine > partialBottomIndex || endLine < partialTopIndex) { return; } - int lineOffset = content.getOffsetAtLine(firstLine); - if (partialTopIndex > firstLine) { - firstLine = partialTopIndex; - start = lineOffset; + if (partialTopIndex > startLine) { + startLine = partialTopIndex; + start = 0; + } else { + start -= content.getOffsetAtLine(startLine); } - if (partialBottomIndex < lastLine) { - lastLine = partialBottomIndex; - end = content.getOffsetAtLine(lastLine) + content.getLine(lastLine).length(); + if (partialBottomIndex < endLine) { + endLine = partialBottomIndex + 1; + end = 0; + } else { + end -= content.getOffsetAtLine(endLine); } - boolean fullSelection = (getStyle() & SWT.FULL_SELECTION) != 0; + + TextLayout layout = renderer.getTextLayout(startLine); + int lineX = leftMargin - horizontalScrollOffset, startLineY = getLinePixel(startLine); + int[] offsets = layout.getLineOffsets(); + int startIndex = layout.getLineIndex(Math.min(start, layout.getText().length())); - //redraw first line from start to end - TextLayout layout = renderer.getTextLayout(firstLine); - Rectangle rect = layout.getBounds(start - lineOffset, end - lineOffset); - rect.x += leftMargin - horizontalScrollOffset; - rect.y += getLinePixel(firstLine); - if (end - lineOffset >= layout.getText().length()) { - if (fullSelection) { - rect.width = clientAreaWidth; - } else { - rect.width += renderer.getLineEndSpace(); - } - } else { - if (wordWrap && fullSelection) { - if (layout.getLineIndex(start - lineOffset) != layout.getLineIndex(end - lineOffset)) { - rect.width = clientAreaWidth; - } - } + /* Redraw end of line before start line if wrapped and start offset is first char */ + if (wordWrap && startIndex > 0 && offsets[startIndex] == start) { + Rectangle rect = layout.getLineBounds(startIndex - 1); + rect.x = rect.width; + rect.width = clientAreaWidth - rightMargin - rect.x; + rect.x += lineX; + rect.y += startLineY; + super.redraw(rect.x, rect.y, rect.width, rect.height, false); } - renderer.disposeTextLayout(layout); - //emtpy lines can have no height - if (rect.height == 0) rect.height = renderer.getLineHeight(); - super.redraw(rect.x, rect.y, rect.width, rect.height, false); - int lineCount = lastLine - firstLine + 1; - if (lineCount > 1) { - // redraw center lines completely - int lastLineY = getLinePixel(lastLine); - if (lineCount > 2) { - rect.y += rect.height; - super.redraw(0, rect.y, clientAreaWidth, lastLineY - rect.y, false); + + if (startLine == endLine) { + int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length())); + if (startIndex == endIndex) { + /* Redraw rect between start and end offset if start and end offsets are in same wrapped line */ + Rectangle rect = layout.getBounds(start, end - 1); + rect.x += lineX; + rect.y += startLineY; + super.redraw(rect.x, rect.y, rect.width, rect.height, false); + renderer.disposeTextLayout(layout); + return; } + } - // redraw last line from zero to end - layout = renderer.getTextLayout(lastLine); - lineOffset = content.getOffsetAtLine(lastLine); - rect = layout.getBounds(0, end - lineOffset); - rect.x += leftMargin - horizontalScrollOffset; - rect.y += lastLineY; - if (end - lineOffset >= layout.getText().length()) { - if (fullSelection) { - rect.width = clientAreaWidth; - } else { - rect.width += renderer.getLineEndSpace(); - } - } else { - if (wordWrap && fullSelection) { - if (0 != layout.getLineIndex(end - lineOffset)) { - rect.width = clientAreaWidth; - } - } - } + /* Redraw start line from the start offset to the end of client area */ + Rectangle startRect = layout.getBounds(start, offsets[startIndex + 1] - 1); + if (startRect.height == 0) { + Rectangle bounds = layout.getLineBounds(startIndex); + startRect.x = bounds.width; + startRect.y = bounds.y; + startRect.height = bounds.height; + } + startRect.x += lineX; + startRect.y += startLineY; + startRect.width = clientAreaWidth - rightMargin - startRect.x; + super.redraw(startRect.x, startRect.y, startRect.width, startRect.height, false); + + /* Redraw end line from the begining of the line to the end offset */ + if (startLine != endLine) { renderer.disposeTextLayout(layout); -// emtpy lines can have no height - if (rect.height == 0) rect.height = renderer.getLineHeight(); - super.redraw(rect.x, rect.y, rect.width, rect.height, false); + layout = renderer.getTextLayout(endLine); + offsets = layout.getLineOffsets(); + } + int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length())); + Rectangle endRect = layout.getBounds(offsets[endIndex], end - 1); + if (endRect.height == 0) { + Rectangle bounds = layout.getLineBounds(endIndex); + endRect.y = bounds.y; + endRect.height = bounds.height; + } + endRect.x += lineX; + endRect.y += getLinePixel(endLine); + super.redraw(endRect.x, endRect.y, endRect.width, endRect.height, false); + renderer.disposeTextLayout(layout); + + /* Redraw all lines in between start and end line */ + int y = startRect.y + startRect.height; + if (endRect.y > y) { + super.redraw(leftMargin, y, clientAreaWidth - rightMargin - leftMargin, endRect.y - y, false); } } /** @@ -5088,16 +5128,16 @@ void handlePaint(Event event) { // fill the margin background gc.setBackground(background); if (topMargin > 0) { - gc.fillRectangle(0, -y, clientAreaWidth, topMargin); + gc.fillRectangle(0, 0, clientAreaWidth, topMargin); } if (bottomMargin > 0) { - gc.fillRectangle(0, clientAreaHeight - bottomMargin - y, clientAreaWidth, bottomMargin); + gc.fillRectangle(0, clientAreaHeight - bottomMargin, clientAreaWidth, bottomMargin); } if (leftMargin > 0) { - gc.fillRectangle(0, -y, leftMargin, clientAreaHeight); + gc.fillRectangle(0, 0, leftMargin, clientAreaHeight); } if (rightMargin > 0) { - gc.fillRectangle(clientAreaWidth - rightMargin, -y, rightMargin, clientAreaHeight); + gc.fillRectangle(clientAreaWidth - rightMargin, 0, rightMargin, clientAreaHeight); } } /** @@ -5128,17 +5168,6 @@ void handleResize(Event event) { } if (wordWrap) { if (oldWidth != clientAreaWidth) { - if (partialHeight > 0) { - int partialTopIndex = getPartialTopIndex(); - TextLayout layout = renderer.getTextLayout(partialTopIndex); - layout.setWidth(oldWidth); - int height = layout.getBounds().height; - layout.setWidth(clientAreaWidth); - int newHeight = layout.getBounds().height; - renderer.disposeTextLayout(layout); - partialHeight += newHeight - height; - if (partialHeight < 0) partialHeight = 0; - } renderer.reset(0, content.getLineCount()); verticalScrollOffset = -1; renderer.calculateIdle(); @@ -5154,6 +5183,9 @@ void handleResize(Event event) { claimRightFreeSpace(); } claimBottomFreeSpace(); + if (oldHeight != clientAreaHeight || wordWrap) { + calculateTopIndex(0); + } } /** * Updates the caret position and selection and the scroll bars to reflect @@ -5176,10 +5208,10 @@ void handleTextChanged(TextChangedEvent event) { // in some cases new text would be drawn in scroll source area even // though the intent is to scroll it. updateSelection(lastTextChangeStart, lastTextChangeReplaceCharCount, lastTextChangeNewCharCount); - if (newLastLineBottom == lastLineBottom) { + if (newLastLineBottom == lastLineBottom) { update(); } - if (lastTextChangeReplaceLineCount > 0) { + if (lastTextChangeReplaceLineCount > 0 || wordWrap) { claimBottomFreeSpace(); } if (lastTextChangeReplaceCharCount > 0) { @@ -6133,7 +6165,6 @@ void reset() { ScrollBar horizontalBar = getHorizontalBar(); caretOffset = 0; topIndex = 0; - topOffset = 0; verticalScrollOffset = 0; horizontalScrollOffset = 0; resetSelection(); @@ -6187,7 +6218,30 @@ boolean scrollHorizontal(int pixels, boolean adjustScrollBar) { if (horizontalBar != null && adjustScrollBar) { horizontalBar.setSelection(horizontalScrollOffset + pixels); } - scroll(pixels, 0); + int scrollHeight = clientAreaHeight - topMargin - bottomMargin; + if (pixels > 0) { + int sourceX = leftMargin + pixels; + int scrollWidth = clientAreaWidth - sourceX - rightMargin; + if (scrollWidth > 0) { + scroll(leftMargin, topMargin, sourceX, topMargin, scrollWidth, scrollHeight, true); + } + if (sourceX > scrollWidth) { + super.redraw(leftMargin + scrollWidth, topMargin, pixels - scrollWidth, scrollHeight, true); + } + } else { + int destinationX = leftMargin - pixels; + int scrollWidth = clientAreaWidth - destinationX - rightMargin; + if (scrollWidth > 0) { + scroll(destinationX, topMargin, leftMargin, topMargin, scrollWidth, scrollHeight, true); + } + if (destinationX > scrollWidth) { + super.redraw(leftMargin + scrollWidth, topMargin, -pixels - scrollWidth, scrollHeight, true); + } + } + horizontalScrollOffset += pixels; + int oldColumnX = columnX; + setCaretLocation(); + columnX = oldColumnX; return true; } /** @@ -6200,7 +6254,7 @@ boolean scrollHorizontal(int pixels, boolean adjustScrollBar) { * false = the scroll thumb will not be moved * @return * true=the widget was scrolled - * false=the widget was not scrolled, the given offset is not valid. + * false=the widget was not scrolled */ boolean scrollVertical(int pixels, boolean adjustScrollBar) { if (pixels == 0) { @@ -6210,75 +6264,37 @@ boolean scrollVertical(int pixels, boolean adjustScrollBar) { if (verticalBar != null && adjustScrollBar) { verticalBar.setSelection(getVerticalScrollOffset() + pixels); } - scroll(0, pixels); - return true; -} -/** - * Scrolls the widget horizontally or vertically. - * <p> - * NOTE: This fuction can not be used to scroll the widget - * horizontally and vertically at the same time. - */ -void scroll(int hscroll, int vscroll) { - if (hscroll > 0 || vscroll > 0) { - int sourceX = leftMargin + hscroll; - int sourceY = topMargin + vscroll; - int scrollWidth = clientAreaWidth - sourceX - rightMargin; - int scrollHeight = clientAreaHeight - sourceY - bottomMargin; - scroll( - leftMargin, topMargin, // destination x, y - sourceX, sourceY, // source x, y - scrollWidth, scrollHeight, true); - - // redraw from end of scrolled area to beginning of scroll - // invalidated area - if (sourceX > scrollWidth) { - super.redraw( - leftMargin + scrollWidth, topMargin, - hscroll - scrollWidth, scrollHeight, true); - } - if (sourceY > scrollHeight) { - super.redraw( - leftMargin, topMargin + scrollHeight, - scrollWidth, vscroll - scrollHeight, true); + if (verticalScrollOffset != -1) { + int scrollWidth = clientAreaWidth - leftMargin - rightMargin; + if (pixels > 0) { + int sourceY = topMargin + pixels; + int scrollHeight = clientAreaHeight - sourceY - bottomMargin; + if (scrollHeight > 0) { + scroll(leftMargin, topMargin, leftMargin, sourceY, scrollWidth, scrollHeight, true); + } + if (sourceY > scrollHeight) { + super.redraw(leftMargin, topMargin + scrollHeight, scrollWidth, pixels - scrollHeight, true); + } + } else { + int destinationY = topMargin - pixels; + int scrollHeight = clientAreaHeight - destinationY - bottomMargin; + if (scrollHeight > 0) { + scroll(leftMargin, destinationY, leftMargin, topMargin, scrollWidth, scrollHeight, true); + } + if (destinationY > scrollHeight) { + super.redraw(leftMargin, topMargin + scrollHeight, scrollWidth, -pixels - scrollHeight, true); + } } + verticalScrollOffset += pixels; + calculateTopIndex(pixels); } else { - int destinationX = leftMargin - hscroll; - int destinationY = topMargin - vscroll; - int scrollWidth = clientAreaWidth - destinationX - rightMargin; - int scrollHeight = clientAreaHeight - destinationY - bottomMargin; - scroll( - destinationX, destinationY, // destination x, y - leftMargin, topMargin, // source x, y - scrollWidth, scrollHeight, true); - - // redraw from end of scroll invalidated area to scroll - // destination - if (destinationX > scrollWidth) { - super.redraw( - leftMargin + scrollWidth, topMargin, - -hscroll - scrollWidth, scrollHeight, true); - } - if (destinationY > scrollHeight) { - // redraw from end of scroll invalidated area to scroll - // destination - super.redraw( - leftMargin, topMargin + scrollHeight, - scrollWidth, -vscroll - scrollHeight, true); - } - } - horizontalScrollOffset += hscroll; - if (vscroll != 0) { - if (verticalScrollOffset == -1) { - // assure verticalScrollOffset is up to date - getVerticalScrollOffset(); - } - verticalScrollOffset += vscroll; - calculateTopIndex(vscroll); + calculateTopIndex(pixels); + super.redraw(); } int oldColumnX = columnX; setCaretLocation(); columnX = oldColumnX; + return true; } void scrollText(int srcY, int destY) { if (srcY == destY) return; @@ -6468,12 +6484,7 @@ void setCaretLocation(Point location, int direction) { int lineHeight = renderer.getLineHeight(); int caretHeight = lineHeight; if (!isFixedLineHeight()) { - int caretLine = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(caretLine); - TextLayout layout = renderer.getTextLayout(caretLine); - int lineInParagraph = layout.getLineIndex(caretOffset - lineOffset); - caretHeight = layout.getLineBounds(lineInParagraph).height; - renderer.disposeTextLayout(layout); + caretHeight = getBoundsAtOffset(caretOffset).height; if (caretHeight != lineHeight) { direction = SWT.DEFAULT; } @@ -7827,18 +7838,19 @@ public void setTopPixel(int pixel) { } if (pixel < 0) pixel = 0; int lineCount = content.getLineCount(); - int height = clientAreaHeight; + int height = clientAreaHeight - topMargin - bottomMargin; if (isFixedLineHeight()) { int maxTopPixel = Math.max(0, lineCount * getVerticalIncrement() - height); if (pixel > maxTopPixel) pixel = maxTopPixel; } else { - if (pixel > getVerticalScrollOffset()) { - int bottomIndex = getLineIndex(height) + 1; - int bottomPixel = getLinePixel(bottomIndex); - while (pixel + height > bottomPixel && lineCount > bottomIndex) { - bottomPixel += renderer.getLineHeight(bottomIndex++); + int verticalOffset = getVerticalScrollOffset(); + if (pixel > verticalOffset) { + int lineIndex = topIndex; + int maxTopPixel = verticalOffset + getLinePixel(lineIndex) - height; + while (maxTopPixel < pixel && lineIndex < lineCount) { + maxTopPixel += renderer.getLineHeight(lineIndex++); } - if (pixel + height > bottomPixel) pixel = bottomPixel - height; + if (pixel > maxTopPixel) pixel = maxTopPixel; } } scrollVertical(pixel - getVerticalScrollOffset(), true); @@ -7879,27 +7891,24 @@ public void setWordWrap(boolean wrap) { * false=the specified location is already visible, the widget was * not scrolled. */ -boolean showLocation(Point point) { - int clientAreaWidth = this.clientAreaWidth - leftMargin; - int horizontalIncrement = clientAreaWidth / 4; +boolean showLocation(Rectangle rect) { + int clientAreaWidth = this.clientAreaWidth - leftMargin - rightMargin; + int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin; boolean scrolled = false; if (clientAreaWidth > 0) { - if (point.x < leftMargin) { - // always make 1/4 of a page visible - point.x = Math.max(-horizontalScrollOffset, point.x - horizontalIncrement); - scrolled = scrollHorizontal(point.x, true); - } else if (point.x >= clientAreaWidth) { - // always make 1/4 of a page visible - point.x = Math.min(renderer.getWidth() - horizontalScrollOffset, point.x + horizontalIncrement); - scrolled = scrollHorizontal(point.x - clientAreaWidth, true); + // always make 1/4 of a page visible + if (rect.x < leftMargin) { + int scrollWidth = Math.min(horizontalScrollOffset, clientAreaWidth / 4); + scrolled = scrollHorizontal(-scrollWidth, true); + } else if (rect.x + rect.width > clientAreaWidth) { + int scrollWidth = Math.min(renderer.getWidth() - horizontalScrollOffset, clientAreaWidth / 4); + scrolled = scrollHorizontal(scrollWidth, true); } } - if (clientAreaHeight > 0) { - if (point.y < topMargin) { - scrolled = scrollVertical(point.y - topMargin, true); - } else if (point.y >= clientAreaHeight - bottomMargin) { - scrolled = scrollVertical(point.y - clientAreaHeight + bottomMargin, true); - } + if (rect.y <= topMargin) { + scrolled = scrollVertical(rect.y - topMargin, true); + } else if (rect.y + rect.height > clientAreaHeight) { + scrolled = scrollVertical(rect.y + rect.height - clientAreaHeight, true); } return scrolled; } @@ -7907,24 +7916,9 @@ boolean showLocation(Point point) { * Sets the caret location and scrolls the caret offset into view. */ void showCaret() { - Point newCaretPos = getPointAtOffset(caretOffset); - boolean scrolled = showLocation(newCaretPos); - - //TODO FIX ME - assure caret bottom is visible - if (!scrolled) { - int caretLine = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(caretLine); - TextLayout layout = renderer.getTextLayout(caretLine); - Point point = new Point(newCaretPos.x, newCaretPos.y); - int offsetInLine = caretOffset - lineOffset; - point.y += layout.getLineBounds(layout.getLineIndex(offsetInLine)).height; - renderer.disposeTextLayout(layout); - scrolled = showLocation(point); - } - - if (!scrolled) { - // set the caret location if a scroll operation did not set it - setCaretLocation(newCaretPos, getCaretDirection()); + Rectangle bounds = getBoundsAtOffset(caretOffset); + if (!showLocation(bounds)) { + setCaretLocation(); } } /** @@ -7950,25 +7944,25 @@ public void showSelection() { startOffset = selection.x; endOffset = selection.y; } - Point startPos = getPointAtOffset(startOffset); - Point endPos = getPointAtOffset(endOffset); - //TODO endPos.y should be the bottom of the line not the top + + Rectangle startBounds = getBoundsAtOffset(startOffset); + Rectangle endBounds = getBoundsAtOffset(endOffset); // can the selection be fully displayed within the widget's visible width? int w = clientAreaWidth; - boolean selectionFits = rightToLeft ? startPos.x - endPos.x <= w : endPos.x - startPos.x <= w; + boolean selectionFits = rightToLeft ? startBounds.x - endBounds.x <= w : endBounds.x - startBounds.x <= w; if (selectionFits) { // show as much of the selection as possible by first showing // the start of the selection - if (showLocation(startPos)) { + if (showLocation(startBounds)) { // endX value could change if showing startX caused a scroll to occur - endPos = getPointAtOffset(endOffset); + endBounds = getBoundsAtOffset(endOffset); } - showLocation(endPos); + showLocation(endBounds); } else { // just show the end of the selection since the selection start // will not be visible - showLocation(endPos); + showLocation(endBounds); } } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java index 24023ba565..d60de083c3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java @@ -246,7 +246,7 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun Rectangle lineBounds = layout.getLineBounds(lineCount - 1); int x = paintX + lineBounds.x + lineBounds.width; if (fullSelection) { - gc.fillRectangle(x, paintY + lineBounds.y, client.width - x, lineBounds.height); + gc.fillRectangle(x, paintY + lineBounds.y, client.width - styledText.rightMargin - x, lineBounds.height); } else { gc.fillRectangle(x, paintY + lineBounds.y, lineEndSpaceWidth, lineBounds.height); } @@ -901,17 +901,11 @@ void setStyleRanges (int[] newRanges, StyleRange[] newStyles) { } else { int start = newStyles[0].start; int modifyStart = getRangeIndex(start, -1, styleCount); + int modifyEnd = modifyStart; if (modifyStart == styleCount) { - if (newStyles.length + styleCount >= styles.length) { - StyleRange[] tmpStyles = new StyleRange[styles.length + newStyles.length]; - System.arraycopy(styles, 0, tmpStyles, 0, styles.length); - styles = tmpStyles; - } - System.arraycopy(newStyles, 0, styles, styleCount, newStyles.length); - styleCount += newStyles.length; + addMerge(newStyles, newStyles.length, modifyStart, modifyEnd); return; } - int modifyEnd = modifyStart; StyleRange[] mergeStyles = new StyleRange[3]; for (int i = 0; i < newStyles.length; i++) { StyleRange newStyle = newStyles[i], style; @@ -939,25 +933,48 @@ void setStyleRanges (int[] newRanges, StyleRange[] newStyles) { modifyLast = 1; } } - modifyEnd += modifyLast; - int grow = mergeCount - (modifyEnd - modifyStart); - if (styleCount + grow >= styles.length) { - StyleRange[] tmpStyles = new StyleRange[styles.length + grow + GROW]; - System.arraycopy(styles, 0, tmpStyles, 0, modifyStart); - if (styleCount > modifyEnd) { - System.arraycopy(styles, modifyEnd, tmpStyles, modifyStart + mergeCount, styleCount - modifyEnd); - } - styles = tmpStyles; - } else { - if (styleCount > modifyEnd) { - System.arraycopy(styles, modifyEnd, styles, modifyStart + mergeCount, styleCount - modifyEnd); - } - } - System.arraycopy(mergeStyles, 0, styles, modifyStart, mergeCount); - styleCount += grow; - modifyStart = modifyEnd = modifyEnd + grow - modifyLast; - } + int grow = addMerge(mergeStyles, mergeCount, modifyStart, modifyEnd + modifyLast); + modifyStart = modifyEnd += grow; + } + } +} +int addMerge(StyleRange[] mergeStyles, int mergeCount, int modifyStart, int modifyEnd) { + int grow = mergeCount - (modifyEnd - modifyStart); + StyleRange endStyle = null; + if (modifyEnd < styleCount) endStyle = styles[modifyEnd]; + if (styleCount + grow >= styles.length) { + StyleRange[] tmpStyles = new StyleRange[styles.length + grow + GROW]; + System.arraycopy(styles, 0, tmpStyles, 0, modifyStart); + if (styleCount > modifyEnd) { + System.arraycopy(styles, modifyEnd, tmpStyles, modifyStart + mergeCount, styleCount - modifyEnd); + } + styles = tmpStyles; + } else { + if (styleCount > modifyEnd) { + System.arraycopy(styles, modifyEnd, styles, modifyStart + mergeCount, styleCount - modifyEnd); + } + } + int j = modifyStart; + for (int i = 0; i < mergeCount; i++) { + StyleRange newStyle = mergeStyles[i], style; + if (j > 0 && (style = styles[j - 1]).start + style.length == newStyle.start && newStyle.similarTo(style)) { + style.length += newStyle.length; + } else { + styles[j++] = newStyle; + } + } + StyleRange style = styles[j - 1]; + if (endStyle != null && style.start + style.length == endStyle.start && endStyle.similarTo(style)) { + style.length += endStyle.length; + modifyEnd++; + mergeCount++; + } + if (styleCount > modifyEnd) { + System.arraycopy(styles, modifyStart + mergeCount, styles, j, styleCount - modifyEnd); } + grow = (j - modifyStart) - (modifyEnd - modifyStart); + styleCount += grow; + return grow; } void textChanging(TextChangingEvent event) { int start = event.start; |