/*******************************************************************************
* 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 org.eclipse.jface.text.source.projection;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.source.IAnnotationPresentation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
/**
* @author Kevin Sawicki (ksawicki@aptana.com)
*/
public class UnifiedProjectionAnnotation extends ProjectionAnnotation
{
/**
* The type of projection annotations.
*/
public static final String TYPE = "org.eclipse.projection"; //$NON-NLS-1$
private static final int COLOR = SWT.COLOR_GRAY;
private Image fgCollapsedImage;
private Image fgExpandedImage;
private Color color;
/** The state of this annotation */
private boolean fIsCollapsed = false;
/** Indicates whether this annotation should be painted as range */
private boolean fIsRangeIndication = false;
/**
* Creates a new expanded projection annotation.
*/
public UnifiedProjectionAnnotation()
{
this(false);
}
/**
* Creates a new projection annotation. When <code>isCollapsed</code> is <code>true</code> the annotation is
* initially collapsed.
*
* @param isCollapsed
* <code>true</code> if the annotation should initially be collapsed, <code>false</code> otherwise
*/
public UnifiedProjectionAnnotation(boolean isCollapsed)
{
super(isCollapsed);
fIsCollapsed = isCollapsed;
}
/**
* Enables and disables the range indication for this annotation.
*
* @param rangeIndication
* the enable state for the range indication
*/
public void setRangeIndication(boolean rangeIndication)
{
fIsRangeIndication = rangeIndication;
}
private void drawRangeIndication(GC gc, Canvas canvas, Rectangle r)
{
final int MARGIN = 3;
Color fg = gc.getForeground();
gc.setForeground(color == null ? canvas.getDisplay().getSystemColor(COLOR) : color);
gc.setLineWidth(1);
/*
* cap the height - at least on GTK, large numbers are converted to negatives at some point
*/
int height = Math.min(r.y + r.height - MARGIN, canvas.getSize().y);
gc.drawLine(r.x + 4, r.y + 12, r.x + 4, height);
gc.drawLine(r.x + 4, height, r.x + r.width - MARGIN, height);
gc.setForeground(fg);
}
/**
* @see org.eclipse.jface.text.source.IAnnotationPresentation#paint(org.eclipse.swt.graphics.GC,
* org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
*/
public void paint(GC gc, Canvas canvas, Rectangle rectangle)
{
Image image = getImage(canvas);
if (image != null)
{
// int halign = SWT.LEFT;
int valign = SWT.TOP;
if (image != null)
{
Rectangle bounds = image.getBounds();
// int x = 0;
// switch (halign)
// {
// case SWT.LEFT:
// break;
// case SWT.CENTER:
// x = (rectangle.width - bounds.width) / 2;
// break;
// case SWT.RIGHT:
// x = rectangle.width - bounds.width;
// break;
// }
int y = 0;
switch (valign)
{
case SWT.TOP:
{
FontMetrics fontMetrics = gc.getFontMetrics();
y = (fontMetrics.getHeight() - bounds.height) / 2;
break;
}
case SWT.CENTER:
y = (rectangle.height - bounds.height) / 2;
break;
case SWT.BOTTOM:
{
FontMetrics fontMetrics = gc.getFontMetrics();
y = rectangle.height - (fontMetrics.getHeight() + bounds.height) / 2;
break;
}
}
gc.drawImage(image, 2, rectangle.y + y + 2);
}
if (fIsRangeIndication)
{
FontMetrics fontMetrics = gc.getFontMetrics();
int delta = (fontMetrics.getHeight() - image.getBounds().height) / 2;
rectangle.y += delta;
rectangle.height -= delta;
drawRangeIndication(gc, canvas, rectangle);
}
}
}
/**
* @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer()
*/
public int getLayer()
{
return IAnnotationPresentation.DEFAULT_LAYER;
}
private Image getImage(Canvas canvas)
{
initializeImages(canvas);
return isCollapsed() ? fgCollapsedImage : fgExpandedImage;
}
/**
* Gets the collapse image descriptor
*
* @return - collapsed descriptor
*/
public ImageDescriptor getCollapsedImage()
{
return ImageDescriptor.createFromFile(UnifiedProjectionAnnotation.class, "images/collapsed.png"); //$NON-NLS-1$
}
/**
* Gets the expand image descriptor
*
* @return - expanded descriptor
*/
public ImageDescriptor getExpandedImage()
{
return ImageDescriptor.createFromFile(UnifiedProjectionAnnotation.class, "images/expanded.png"); //$NON-NLS-1$
}
private void initializeImages(Canvas canvas)
{
if (fgCollapsedImage == null)
{
ImageDescriptor descriptor = getCollapsedImage();
fgCollapsedImage = descriptor.createImage(canvas.getDisplay());
descriptor = getExpandedImage();
fgExpandedImage = descriptor.createImage(canvas.getDisplay());
canvas.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
if (fgCollapsedImage != null)
{
fgCollapsedImage.dispose();
fgCollapsedImage = null;
}
if (fgExpandedImage != null)
{
fgExpandedImage.dispose();
fgExpandedImage = null;
}
}
});
}
}
/**
* Returns the state of this annotation.
*
* @return <code>true</code> if collapsed
*/
public boolean isCollapsed()
{
return fIsCollapsed;
}
/**
* Marks this annotation as being collapsed.
*/
public void markCollapsed()
{
fIsCollapsed = true;
}
/**
* Marks this annotation as being unfolded.
*/
public void markExpanded()
{
fIsCollapsed = false;
}
/**
* Sets the color of this annotation
*
* @param color
*/
public void setColor(Color color)
{
this.color = color;
}
}