blob: 42ced4a1930c271aab7ddd80d628c89151e0ee33 [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
*
* Contributors:
* Michael Scharf (Wind River) - initial API and implementation
* Anton Leherbauer (Wind River) - [294468] Fix scroller and text line rendering
*******************************************************************************/
package org.eclipse.tm.internal.terminal.textcanvas;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
/**
* A <code>Canvas</code> showing a virtual object.
* Virtual: the extent of the total canvas.
* Screen: the visible client area in the screen.
*/
public abstract class VirtualCanvas extends Canvas {
private final Rectangle fVirtualBounds = new Rectangle(0,0,0,0);
private Rectangle fClientArea;
/**
* prevent infinite loop in {@link #updateScrollbars()}
*/
private boolean fInUpdateScrollbars;
private static boolean fInUpdateScrollbarsLogged;
public VirtualCanvas(Composite parent, int style) {
super(parent, style|SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE);
fClientArea=getClientArea();
addListener(SWT.Paint, new Listener() {
public void handleEvent(Event event) {
paint(event.gc);
}
});
addListener(SWT.Resize, new Listener() {
public void handleEvent(Event event) {
fClientArea=getClientArea();
onResize();
}
});
getVerticalBar().addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
scrollY((ScrollBar)e.widget);
}
});
getHorizontalBar().addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
scrollX((ScrollBar)e.widget);
}
});
}
protected void onResize() {
updateViewRectangle();
}
protected void scrollX(ScrollBar hBar) {
int hSelection = hBar.getSelection ();
int destX = -hSelection - fVirtualBounds.x;
fVirtualBounds.x = -hSelection;
scrollSmart(destX, 0);
updateViewRectangle();
}
protected void scrollXDelta(int delta) {
getHorizontalBar().setSelection(-fVirtualBounds.x+delta);
scrollX(getHorizontalBar());
}
protected void scrollY(ScrollBar vBar) {
int vSelection = vBar.getSelection ();
int destY = -vSelection - fVirtualBounds.y;
if(destY!=0) {
fVirtualBounds.y = -vSelection;
scrollSmart(0,destY);
updateViewRectangle();
}
}
protected void scrollYDelta(int delta) {
getVerticalBar().setSelection(-fVirtualBounds.y+delta);
scrollY(getVerticalBar());
}
protected void scrollSmart(int deltaX, int deltaY) {
if (deltaX != 0 || deltaY != 0) {
Rectangle rect = getBounds();
scroll (deltaX, deltaY, 0, 0, rect.width, rect.height, false);
}
}
/**
* @param rect in virtual space
*/
protected void revealRect(Rectangle rect) {
Rectangle visibleRect=getScreenRectInVirtualSpace();
// scroll the X part
int deltaX=0;
if(rect.x<visibleRect.x) {
deltaX=rect.x-visibleRect.x;
} else if(visibleRect.x+visibleRect.width<rect.x+rect.width){
deltaX=(rect.x+rect.width)-(visibleRect.x+visibleRect.width);
}
if(deltaX!=0) {
getHorizontalBar().setSelection(-fVirtualBounds.x+deltaX);
scrollX(getHorizontalBar());
}
// scroll the Y part
int deltaY=0;
if(rect.y<visibleRect.y){
deltaY=rect.y-visibleRect.y;
} else if(visibleRect.y+visibleRect.height<rect.y+rect.height){
deltaY=(rect.y+rect.height)-(visibleRect.y+visibleRect.height);
}
if(deltaY!=0) {
getVerticalBar().setSelection(-fVirtualBounds.y+deltaY);
scrollY(getVerticalBar());
}
}
protected void repaint(Rectangle r) {
if(isDisposed())
return;
if(inClipping(r,fClientArea)) {
redraw(r.x, r.y, r.width, r.height, true);
update();
}
}
/**
* Paint the virtual canvas.
* Override to implement actual paint method.
* @param gc graphics context to paint in
*/
abstract protected void paint(GC gc);
protected Color getTerminalBackgroundColor() {
// return getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
return getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
}
protected void paintUnoccupiedSpace(GC gc, Rectangle clipping) {
int width=fVirtualBounds.width + fVirtualBounds.x;
int height=fVirtualBounds.height + fVirtualBounds.y;
int marginWidth = (clipping.x+clipping.width) - width;
int marginHeight = (clipping.y+clipping.height) - height;
if(marginWidth>0||marginHeight>0){
Color bg=getBackground();
gc.setBackground(getTerminalBackgroundColor());
if (marginWidth > 0) {
gc.fillRectangle (width, clipping.y, marginWidth, clipping.height);
}
if (marginHeight > 0) {
gc.fillRectangle (clipping.x, height, clipping.width, marginHeight);
}
gc.setBackground(bg);
}
}
/**
* @private
*/
protected boolean inClipping(Rectangle clipping, Rectangle r) {
// TODO check if this is OK in all cases (the <=!)
//
if(r.x+r.width<=clipping.x)
return false;
if(clipping.x+clipping.width<=r.x)
return false;
if(r.y+r.height<=clipping.y)
return false;
if(clipping.y+clipping.height<=r.y)
return false;
return true;
}
/**
* @return the screen rect in virtual space (starting with (0,0))
* of the visible screen. (x,y>=0)
*/
protected Rectangle getScreenRectInVirtualSpace() {
Rectangle r= new Rectangle(fClientArea.x-fVirtualBounds.x,fClientArea.y-fVirtualBounds.y,fClientArea.width,fClientArea.height);
return r;
}
/**
* @return the rect in virtual space (starting with (0,0))
* of the visible screen. (x,y>=0)
*/
protected Rectangle getRectInVirtualSpace(Rectangle r) {
return new Rectangle(r.x-fVirtualBounds.x,r.y-fVirtualBounds.y,r.width,r.height);
}
/**
* Sets the extent of the virtual display area
* @param width width of the display area
* @param height height of the display area
*/
protected void setVirtualExtend(int width, int height) {
fVirtualBounds.width=width;
fVirtualBounds.height=height;
updateScrollbars();
updateViewRectangle();
}
/**
* sets the scrolling origin. Also sets the scrollbars.
* Does NOT redraw!
* Use negative values (move the virtual origin to the top left
* to see something in the screen (which is located at (0,0))
* @param x
* @param y
*/
protected void setVirtualOrigin(int x, int y) {
if (fVirtualBounds.x != x || fVirtualBounds.y != y) {
fVirtualBounds.x=x;
fVirtualBounds.y=y;
getHorizontalBar().setSelection(-x);
getVerticalBar().setSelection(-y);
updateViewRectangle();
}
}
protected Rectangle getVirtualBounds() {
return cloneRectangle(fVirtualBounds);
}
/**
* @param x
* @return the virtual coordinate in screen space
*/
protected int virtualXtoScreen(int x) {
return x+fVirtualBounds.x;
}
protected int virtualYtoScreen(int y) {
return y+fVirtualBounds.y;
}
protected int screenXtoVirtual(int x) {
return x-fVirtualBounds.x;
}
protected int screenYtoVirtual(int y) {
return y-fVirtualBounds.y;
}
/** called when the viewed part is changing */
private final Rectangle fViewRectangle=new Rectangle(0,0,0,0);
protected void updateViewRectangle() {
if(
fViewRectangle.x==-fVirtualBounds.x
&& fViewRectangle.y==-fVirtualBounds.y
&& fViewRectangle.width==fClientArea.width
&& fViewRectangle.height==fClientArea.height
)
return;
fViewRectangle.x=-fVirtualBounds.x;
fViewRectangle.y=-fVirtualBounds.y;
fViewRectangle.width=fClientArea.width;
fViewRectangle.height=fClientArea.height;
viewRectangleChanged(fViewRectangle.x,fViewRectangle.y,fViewRectangle.width,fViewRectangle.height);
}
protected Rectangle getViewRectangle() {
return cloneRectangle(fViewRectangle);
}
private Rectangle cloneRectangle(Rectangle r) {
return new Rectangle(r.x,r.y,r.width,r.height);
}
/**
* Called when the viewed part has changed.
* Override when you need this information....
* Is only called if the values change!
* @param x visible in virtual space
* @param y visible in virtual space
* @param width
* @param height
*/
protected void viewRectangleChanged(int x, int y, int width, int height) {
}
/**
* @private
*/
private void updateScrollbars() {
// don't get into infinite loops....
if(!fInUpdateScrollbars) {
fInUpdateScrollbars=true;
try {
doUpdateScrollbar();
} finally {
fInUpdateScrollbars=false;
}
} else {
if(!fInUpdateScrollbarsLogged) {
fInUpdateScrollbarsLogged=true;
TerminalPlugin.getDefault().getLog().log(new Status(IStatus.WARNING,
TerminalPlugin.PLUGIN_ID, IStatus.OK, "Unexpected Recursion in terminal", //$NON-NLS-1$
new RuntimeException()));
}
}
}
private void doUpdateScrollbar() {
Rectangle clientArea= getClientArea();
ScrollBar horizontal= getHorizontalBar();
// even if setVisible was called on the scrollbar, isVisible
// returns false if its parent is not visible.
if(!isVisible() || horizontal.isVisible()) {
horizontal.setPageIncrement(clientArea.width - horizontal.getIncrement());
int max= fVirtualBounds.width;
horizontal.setMaximum(max);
horizontal.setThumb(clientArea.width);
}
ScrollBar vertical= getVerticalBar();
// even if setVisible was called on the scrollbar, isVisible
// returns false if its parent is not visible.
if(!isVisible() || vertical.isVisible()) {
vertical.setPageIncrement(clientArea.height - vertical.getIncrement());
int max= fVirtualBounds.height;
vertical.setMaximum(max);
vertical.setThumb(clientArea.height);
}
}
protected boolean isVertialBarVisible() {
return getVerticalBar().isVisible();
}
protected void serVerticalBarVisible(boolean showVScrollBar) {
ScrollBar vertical= getVerticalBar();
vertical.setVisible(showVScrollBar);
vertical.setSelection(0);
}
protected boolean isHorizontalBarVisble() {
return getHorizontalBar().isVisible();
}
protected void setHorizontalBarVisible(boolean showHScrollBar) {
ScrollBar horizontal= getHorizontalBar();
horizontal.setVisible(showHScrollBar);
horizontal.setSelection(0);
}
}