📄 richbox.java
字号:
// Check if there is work to do. We never want to try and create
// an Image with 0 width or 0 height.
if (clientArea.width == 0)
return;
if (renderHeight > 0) {
// renderHeight will be negative when only top margin needs
// redrawing
Color foreground = getForeground();
int lineCount = content.getLineCount();
int paintY, paintHeight;
Image lineBuffer;
GC lineGC;
boolean doubleBuffer = DOUBLE_BUFFERED && lastPaintTopLine == topLine;
lastPaintTopLine = topLine;
if (doubleBuffer) {
paintY = 0;
paintHeight = renderHeight;
lineBuffer = new Image(getDisplay(), clientArea.width, renderHeight);
lineGC = new GC(lineBuffer);
lineGC.setForeground(foreground);
lineGC.setBackground(background);
} else {
paintY = startY;
paintHeight = startY + renderHeight;
lineBuffer = null;
lineGC = gc;
}
for (int i = startLine; paintY < paintHeight && i < lineCount; paintY += contentHelper.getLineHeight(lineGC, i), i++) {
drawLine(lineGC, i, paintY);
}
if (paintY < paintHeight) {
lineGC.setBackground(background);
lineGC.fillRectangle(0, paintY, clientArea.width, paintHeight - paintY);
}
if (doubleBuffer) {
clearMargin(lineGC, background, clientArea, startY);
gc.drawImage(lineBuffer, 0, startY);
lineGC.dispose();
lineBuffer.dispose();
}
}
clearMargin(gc, background, clientArea, 0);
}
/**
* Clears the widget margin.
*
* @param gc
* GC to render on
* @param background
* background color to use for clearing the margin
* @param clientArea
* widget client area dimensions
*/
private void clearMargin(GC gc, Color background, Rectangle clientArea, int y) {
// clear the margin background
Color old = gc.getBackground();
gc.setBackground(background);
if (topMargin > 0) {
gc.fillRectangle(0, -y, clientArea.width, topMargin);
}
if (bottomMargin > 0) {
gc.fillRectangle(0, clientArea.height - bottomMargin - y, clientArea.width, bottomMargin);
}
if (leftMargin > 0) {
gc.fillRectangle(0, -y, leftMargin, clientArea.height);
}
if (rightMargin > 0) {
gc.fillRectangle(clientArea.width - rightMargin, -y, rightMargin, clientArea.height);
}
gc.setBackground(old);
}
/**
* Adjusts the maximum and the page size of the scroll bars to reflect
* content width/length changes.
*/
private void setScrollBars() {
ScrollBar verticalBar = getVerticalBar();
if (verticalBar != null) {
Rectangle clientArea = getClientArea();
clientArea.height -= topMargin + bottomMargin;
int maximum = contentHelper.getHeightOfLines(getGC(), 0, content.getLineCount());
releaseGC();
// only set the real values if the scroll bar can be used
// (ie. because the thumb size is less than the scroll maximum)
// avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92
boolean largerThanClient = clientArea.height < maximum;
if (largerThanClient) {
verticalBar.setValues(verticalBar.getSelection(),
verticalBar.getMinimum(),
maximum,
clientArea.height,
verticalBar.getIncrement(),
clientArea.height);
}
verticalBar.setVisible(largerThanClient || verticalBar.getSelection() > 0);
}
}
/**
* 设置内容
*
* @param text
* 内容
*/
public void setText(String text) {
checkWidget();
content.setText(text);
caretOffset = 0;
resetSelection();
setScrollBars();
redraw();
showCaret();
animationManager.stopAll();
startAnimation(text);
}
/**
* 画一行
*
* @param lineGC
* GC
* @param i
* 行号
* @param paintY
* 需要重绘区域的起始Y坐标
*/
private void drawLine(GC lineGC, int i, int paintY) {
ILineStyler styler = content.getLineStyler();
LineStyle style = styler.getLineStyle(i);
Rectangle clientArea = getClientArea();
Color oldForeground = lineGC.getForeground();
Color oldBackground = lineGC.getBackground();
if(style.foreground != null)
lineGC.setForeground(style.foreground);
if(style.background != null)
lineGC.setBackground(style.background);
lineGC.setFont(styler.getLineFont(i));
lineGC.fillRectangle(leftMargin, paintY, clientArea.width, contentHelper.getLineHeight(lineGC, i));
String line = content.getLine(i);
int textHeight = lineGC.textExtent(line).y;
int lineHeight = contentHelper.getLineHeight(lineGC, i);
int textY = (lineHeight > textHeight) ? (paintY + ((lineHeight - textHeight) >>> 1)) : paintY;
drawString(lineGC, i, line, leftMargin, paintY, textY, lineHeight, null, null);
lineGC.setForeground(oldForeground);
lineGC.setBackground(oldBackground);
}
/**
* 画一行,行内可能有被选择的部分
*
* @param gc
* GC
* @param i
* 行号
* @param line
* 行字符串,不包括回车换行
* @param paintX
* 画字符串的起始X位置
* @param paintY
* 重画区域的起始Y
* @param textY
* 画文本的起始Y位置
* @param lineHeight
* 行高
* @param selectionForeground
* 选择文本的前景
* @param selectionBackground
* 选择文本的背景
*
* @author luma
*/
private void drawString(GC gc, int i, String line, int paintX, int paintY, int textY, int lineHeight, Color selectionForeground, Color selectionBackground) {
if (selectionForeground == null) selectionForeground = getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT);
if (selectionBackground == null) selectionBackground = getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
boolean hasSelection = hasSelectionInLine(i);
if (hasSelection) {
// 得到行内的被选择区域的相对起始偏移和结束偏移
int lineStartOffset = content.getLineStartOffset(i);
int start = selectionStart - lineStartOffset;
if(start < 0)
start = 0;
int end = selectionEnd - lineStartOffset;
if(end >= line.length())
end = line.length();
// 画这行
if(start > 0)
paintX = drawString(gc, line.substring(0, start), paintX, paintY, textY, lineHeight, false);
paintX = drawString(gc, line.substring(start, end), paintX, paintY, textY, lineHeight, selectionForeground, selectionBackground, true);
if(end < line.length())
drawString(gc, line.substring(end), paintX, paintY, textY, lineHeight, false);
} else
drawString(gc, line, paintX, paintY, textY, lineHeight, false);
}
/**
* @param i
* 行号
* @return
* true表示行中有被选择的部分
*/
private boolean hasSelectionInLine(int i) {
if(selectionStart == selectionEnd)
return false;
int lineStartOffset = content.getLineStartOffset(i);
int nextLineStartOffset = content.getLineStartOffset(i + 1);
if(selectionEnd <= lineStartOffset || selectionStart >= nextLineStartOffset)
return false;
return true;
}
/**
* Draw a line with specified foreground and background
*
* @param gc
* @param line
* @param paintX
* @param paintY
* 重画区域的起始Y
* @param textY
* 画文本的起始Y位置
* @param lineHeight
* 行高
* @param foreground
* @param background
* @param selection
* true表示这段文本是被选择的
*
* @author luma
*/
private int drawString(GC gc, String line, int paintX, int paintY, int textY, int lineHeight, Color foreground, Color background, boolean selection) {
Color oldForeground = gc.getForeground();
Color oldBackground = gc.getBackground();
gc.setForeground(foreground);
gc.setBackground(background);
int x = drawString(gc, line, paintX, paintY, textY, lineHeight, selection);
gc.setForeground(oldForeground);
gc.setBackground(oldBackground);
return x;
}
/**
* Draw a line without any seletion in it
*
* @param gc
* @param line
* @param paintX
* @param paintY
* 重画区域的起始Y
* @param textY
* 画文本的起始Y位置
* @param lineHeight
* 行高
* @param selection
* true表示这段文本是被选择的
* @return
* the paintX after draw finished
*
* @author luma
*/
private int drawString(GC gc, String line, int paintX, int paintY, int textY, int lineHeight, boolean selection) {
int i = 0;
int j = contentHelper.findNextImage(line, 0);
for (; j != -1; i = j + 2, j = contentHelper.findNextImage(line, i)) {
// 画文本
String sub = line.substring(i, j);
int textWidth = gc.textExtent(sub).x;
gc.fillRectangle(paintX, paintY, textWidth, lineHeight);
gc.drawString(sub, paintX, textY);
paintX += textWidth;
// 画图片
int tag = line.charAt(j);
int code = line.charAt(j + 1);
Image image = imageResolver.getImage(tag, code);
int imageY = (lineHeight > image.getBounds().height) ? (paintY + ((lineHeight - image.getBounds().height) >>> 1)) : paintY;
gc.drawImage(image, paintX, imageY);
// 如果图片处于被选择状态,在图片上做一个反色
if(selection) {
gc.setXORMode(true);
Color old = gc.getBackground();
gc.setBackground(backXorColor);
gc.fillRectangle(paintX, paintY, image.getBounds().width, lineHeight);
gc.setBackground(old);
gc.setXORMode(false);
}
paintX += image.getBounds().width;
}
// 检查结尾
if (i < line.length()) {
String sub = line.substring(i);
int textWidth = gc.textExtent(sub).x;
gc.fillRectangle(paintX, paintY, textWidth, lineHeight);
gc.drawString(sub, paintX, textY);
paintX += textWidth;
}
return paintX;
}
/**
* 为某行添加style,设置为null相当于使用缺省style
*
* @param lineIndex
* 行号
* @param style
* 样式
*/
public void setLineStyle(int lineIndex, LineStyle style) {
content.setLineStyle(lineIndex, style);
setCaretLocation();
}
/**
* 设置缺省style
*
* @param style
*/
public void setDefaultStyle(LineStyle style) {
if(style != null) {
content.setDefaultStyle(style);
setCaretLocation();
}
}
/**
* @return
* 全部的内容
*/
public String getText() {
return content.getText(0, content.getCharCount());
}
/**
* 得到全部的内容,用指定的适配器转换格式
*
* @param adapter
* 格式适配器
* @return
* 转换后的内容
*/
public String getText(IFormatAdapter adapter) {
return adapter.convert(getText());
}
/**
* 添加文本,文本如果包含多行,则都使用指定的style。文本将以行的形式添加,即在文本
* 的开头会追加换行
*
* @param text
* 文本
* @param style
* 文本的style
*/
public void appendText(String text, LineStyle style) {
checkWidget();
if(text == null || text.equals(""))
return;
int oldLineCount = content.getHardLineCount();
caretOffset = content.getCharCount();
resetSelection(caretOffset, caretOffset);
if(content.isDelimit(caretOffset - 1))
doContent(text);
else
doContent(CRLF + text);
if(style != null) {
int newLineCount = content.getHardLineCount();
if(newLineCount == oldLineCount)
content.setLineStyle(newLineCount - 1, style);
else {
for(int i = oldLineCount; i < newLineCount; i++)
content.setLineStyle(i, style);
}
}
caretOffset = content.getCharCount();
setScrollBars();
showCaret();
}
/**
* 在一段内容中寻找动画
*
* @param text
*/
private void startAnimation(String text) {
if(forbiddenAnimation)
return;
int count = AnimationThread.MAX;
int i = contentHelper.findPreviousImage(text, text.length() - 1);
while(i != -1 && count > 0) {
animationManager.startAnimation(text.charAt(i), text.charAt(i + 1));
count--;
i = contentHelper.findPreviousImage(text, i - 1);
}
}
/**
* 在一段内容中寻找动画,停止它们
*
* @param text
*/
private void stopAnimation(String text) {
if(forbiddenAnimation)
return;
int i = contentHelper.findNextImage(text, 0);
while(i != -1) {
animationManager.stopAnimation(text.charAt(i), text.charAt(i + 1));
i = contentHelper.findNextImage(text, i + 2);
}
}
/**
* 在光标的当前位置插入图片
*
* @param tag
* 图片类型
* @param index
* 索引,最大值65535
*/
public void insertImage(int tag, int index) {
checkWidget();
if(readonly)
return;
char[] c = new char[2];
c[0] = (char)tag;
c[1] = (char)index;
String
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -