blob: 901ddc7290229002a1a1ff0173cd189ace74779b [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.elt.emulator.textcanvas;
import static org.eclipse.core.runtime.IStatus.*;
import org.eclipse.core.runtime.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import com.google.eclipse.elt.emulator.impl.TerminalPlugin;
/**
* A {@code Canvas} 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 virtualBounds = new Rectangle(0, 0, 0, 0);
/** Called when the viewed part is changing. */
private final Rectangle viewRectangle = new Rectangle(0, 0, 0, 0);
private Rectangle clientArea;
/** Prevent infinite loop in {@link #updateScrollbars()} */
private boolean inUpdateScrollbars;
private static boolean inUpdateScrollbarsLogged;
public VirtualCanvas(Composite parent, int style) {
super(parent, style | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE);
clientArea = getClientArea();
addListener(SWT.Paint, new Listener() {
@Override public void handleEvent(Event event) {
paint(event.gc);
}
});
addListener(SWT.Resize, new Listener() {
@Override public void handleEvent(Event event) {
clientArea = getClientArea();
onResize();
}
});
getVerticalBar().addListener(SWT.Selection, new Listener() {
@Override public void handleEvent(Event e) {
scrollY((ScrollBar) e.widget);
}
});
getHorizontalBar().addListener(SWT.Selection, new Listener() {
@Override public void handleEvent(Event e) {
scrollX((ScrollBar) e.widget);
}
});
}
protected void onResize() {
updateViewRectangle();
}
protected void scrollX(ScrollBar horizontalBar) {
int selection = horizontalBar.getSelection();
int destinationX = -selection - virtualBounds.x;
virtualBounds.x = -selection;
scrollSmart(destinationX, 0);
updateViewRectangle();
}
protected void scrollXDelta(int delta) {
getHorizontalBar().setSelection(-virtualBounds.x + delta);
scrollX(getHorizontalBar());
}
protected void scrollY(ScrollBar vBar) {
int vSelection = vBar.getSelection();
int destY = -vSelection - virtualBounds.y;
if (destY != 0) {
virtualBounds.y = -vSelection;
scrollSmart(0, destY);
updateViewRectangle();
}
}
protected void scrollYDelta(int delta) {
getVerticalBar().setSelection(-virtualBounds.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);
}
}
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(-virtualBounds.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(-virtualBounds.y + deltaY);
scrollY(getVerticalBar());
}
}
protected void repaint(Rectangle r) {
if (isDisposed()) {
return;
}
if (inClipping(r, clientArea)) {
redraw(r.x, r.y, r.width, r.height, true);
update();
}
}
abstract protected void paint(GC gc);
protected Color getTerminalBackgroundColor() {
return getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
}
protected void paintUnoccupiedSpace(GC gc, Rectangle clipping) {
int width = virtualBounds.width + virtualBounds.x;
int height = virtualBounds.height + virtualBounds.y;
int marginWidth = (clipping.x + clipping.width) - width;
int marginHeight = (clipping.y + clipping.height) - height;
if (marginWidth > 0 || marginHeight > 0) {
Color background = 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(background);
}
}
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;
}
protected Rectangle getScreenRectInVirtualSpace() {
return new Rectangle(
clientArea.x - virtualBounds.x, clientArea.y - virtualBounds.y, clientArea.width, clientArea.height);
}
protected Rectangle getRectInVirtualSpace(Rectangle r) {
return new Rectangle(r.x - virtualBounds.x, r.y - virtualBounds.y, r.width, r.height);
}
protected void setVirtualExtend(int width, int height) {
virtualBounds.width = width;
virtualBounds.height = height;
updateScrollbars();
updateViewRectangle();
}
protected void setVirtualOrigin(int x, int y) {
if (virtualBounds.x != x || virtualBounds.y != y) {
virtualBounds.x = x;
virtualBounds.y = y;
getHorizontalBar().setSelection(-x);
getVerticalBar().setSelection(-y);
updateViewRectangle();
}
}
protected Rectangle getVirtualBounds() {
return cloneRectangle(virtualBounds);
}
protected int virtualXtoScreen(int x) {
return x + virtualBounds.x;
}
protected int virtualYtoScreen(int y) {
return y + virtualBounds.y;
}
protected int screenXtoVirtual(int x) {
return x - virtualBounds.x;
}
protected int screenYtoVirtual(int y) {
return y - virtualBounds.y;
}
protected void updateViewRectangle() {
if (viewRectangle.x == -virtualBounds.x && viewRectangle.y == -virtualBounds.y
&& viewRectangle.width == clientArea.width && viewRectangle.height == clientArea.height) {
return;
}
viewRectangle.x = -virtualBounds.x;
viewRectangle.y = -virtualBounds.y;
viewRectangle.width = clientArea.width;
viewRectangle.height = clientArea.height;
viewRectangleChanged(viewRectangle.x, viewRectangle.y, viewRectangle.width, viewRectangle.height);
}
protected Rectangle getViewRectangle() {
return cloneRectangle(viewRectangle);
}
private Rectangle cloneRectangle(Rectangle r) {
return new Rectangle(r.x, r.y, r.width, r.height);
}
protected void viewRectangleChanged(int x, int y, int width, int height) {}
private void updateScrollbars() {
// don't get into infinite loops....
if (!inUpdateScrollbars) {
inUpdateScrollbars = true;
try {
doUpdateScrollbar();
} finally {
inUpdateScrollbars = false;
}
} else {
if (!inUpdateScrollbarsLogged) {
inUpdateScrollbarsLogged = true;
ILog logger = TerminalPlugin.getDefault().getLog();
logger.log(new Status(WARNING, TerminalPlugin.PLUGIN_ID, OK, "Unexpected Recursion in terminal", null));
}
}
}
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 = virtualBounds.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 = virtualBounds.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);
}
}