blob: f3c2ed37fb3344bcda6ce7e7e60589140b43c11f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.google.eclipse.tm.internal.terminal.textcanvas;
import static org.eclipse.swt.SWT.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Display;
import com.google.eclipse.tm.terminal.model.*;
public class TextLineRenderer implements ILinelRenderer {
private final ITextCanvasModel model;
private final StyleMap styleMap = new StyleMap();
public TextLineRenderer(TextCanvas c, ITextCanvasModel model) {
this.model = model;
}
@Override public int getCellWidth() {
return styleMap.getFontWidth();
}
@Override public int getCellHeight() {
return styleMap.getFontHeight();
}
@Override public void drawLine(
ITextCanvasModel model, GC gc, int line, int x, int y, int firstColumn, int lastColumn) {
if (line < 0 || line >= getTerminalText().getHeight() || firstColumn >= getTerminalText().getWidth()
|| firstColumn - lastColumn == 0) {
fillBackground(gc, x, y, getCellWidth() * (lastColumn - firstColumn), getCellHeight());
return;
}
lastColumn = Math.min(lastColumn, getTerminalText().getWidth());
LineSegment[] segments = getTerminalText().getLineSegments(line, firstColumn, lastColumn - firstColumn);
for (int i = 0; i < segments.length; i++) {
LineSegment segment = segments[i];
Style style = segment.getStyle();
setupGC(gc, style);
String text = segment.getText();
drawText(gc, x, y, firstColumn, segment.getColumn(), text);
drawCursor(model, gc, line, x, y, firstColumn);
}
if (this.model.hasLineSelection(line)) {
Display display = Display.getCurrent();
gc.setForeground(display.getSystemColor(COLOR_LIST_SELECTION_TEXT));
gc.setBackground(display.getSystemColor(COLOR_LIST_SELECTION));
Point start = model.getSelectionStart();
Point end = model.getSelectionEnd();
char[] chars = model.getTerminalText().getChars(line);
if (chars == null) {
return;
}
int offset = 0;
if (start.y == line) {
offset = start.x;
}
offset = Math.max(offset, firstColumn);
int len;
if (end.y == line) {
len = end.x - offset + 1;
} else {
len = chars.length - offset + 1;
}
len = Math.min(len, chars.length - offset);
if (len > 0) {
String text = new String(chars, offset, len);
drawText(gc, x, y, firstColumn, offset, text);
}
}
}
private void fillBackground(GC gc, int x, int y, int width, int height) {
Color bg = gc.getBackground();
gc.setBackground(getDefaultBackgroundColor());
gc.fillRectangle(x, y, width, height);
gc.setBackground(bg);
}
@Override public Color getDefaultBackgroundColor() {
// null == default style
return styleMap.getBackgroundColor(null);
}
private void drawCursor(ITextCanvasModel model, GC gc, int row, int x, int y, int colFirst) {
if (!model.isCursorOn()) {
return;
}
int cursorLine = model.getCursorLine();
if (row == cursorLine) {
int cursorColumn = model.getCursorColumn();
if (cursorColumn < getTerminalText().getWidth()) {
Style style = getTerminalText().getStyle(row, cursorColumn);
if (style == null) {
// TODO make the cursor color customizable
style = Style.getStyle("BLACK", "WHITE");
}
style = style.setReverse(!style.isReverse());
setupGC(gc, style);
String text = String.valueOf(getTerminalText().getChar(row, cursorColumn));
drawText(gc, x, y, colFirst, cursorColumn, text);
}
}
}
private void drawText(GC gc, int x, int y, int colFirst, int col, String text) {
int offset = (col - colFirst) * getCellWidth();
if (styleMap.isFontProportional()) {
// Draw the background.
// TODO why does this not work?
// gc.fillRectangle(x, y, styleMap.getFontWidth() * text.length(), styleMap.getFontHeight());
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
int newX = x + offset + i * styleMap.getFontWidth();
// TODO why do I have to draw the background character by character?
gc.fillRectangle(newX, y, styleMap.getFontWidth(), styleMap.getFontHeight());
if (c != ' ' && c != '\000') {
gc.drawString(String.valueOf(c), styleMap.getCharOffset(c) + newX, y, true);
}
}
} else {
text = text.replace('\000', ' ');
gc.drawString(text, x + offset, y, false);
}
}
private void setupGC(GC gc, Style style) {
Color c = styleMap.getForegrondColor(style);
if (c != gc.getForeground()) {
gc.setForeground(c);
}
c = styleMap.getBackgroundColor(style);
if (c != gc.getBackground()) {
gc.setBackground(c);
}
Font f = styleMap.getFont(style);
if (f != gc.getFont()) {
gc.setFont(f);
}
}
ITerminalTextDataReadOnly getTerminalText() {
return model.getTerminalText();
}
@Override public void onFontChange() {
styleMap.updateFont();
}
@Override public void setInvertedColors(boolean invert) {
styleMap.setInvertedColors(invert);
}
@Override public void setColors(RGB background, RGB foreground) {
styleMap.setColors(background, foreground);
}
@Override public void setFont(Font font) {
styleMap.setFont(font);
}
}