/*******************************************************************************
* Copyright (c) 2015 ARM Ltd. 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:
* ARM Ltd and ARM Germany GmbH - Initial API and implementation
*******************************************************************************/
package com.arm.cmsis.pack.ui.tree;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
/**
* This is a generic class to support owner-draw cell label displayed in a
* TreeViewer
*/
public class AdvisedCellLabelProvider extends StyledCellLabelProvider {
protected static final int ALPHA = 160; // transparency value
protected static final int TEXTOFFSET = 4;
protected final IColumnAdvisor columnAdvisor; // column advisor necessary processing cell attributes e.g. image, check state
protected final int columnIndex; // column index of this cell
public AdvisedCellLabelProvider(IColumnAdvisor columnAdviser, int colIndex) {
this.columnAdvisor = columnAdviser;
this.columnIndex = colIndex;
}
@Override
public void initialize(ColumnViewer viewer, ViewerColumn column) {
super.initialize(viewer, column);
}
@Override
public void dispose() {
super.dispose();
}
@Override
protected void paint(Event event, Object element) {
drawBackground(event, element);
switch (columnAdvisor.getCellControlType(element, columnIndex)) {
case URL:
super.paint(event, element); // draw only URL text
drawUrl(event, element); // underline text
break;
case CHECK:
case INPLACE_CHECK:
super.paint(event, element);
drawCheckbox(event, element);
break;
case BUTTON:
super.paint(event, element);
drawButton(event, element);
break;
case INPLACE_SPIN:
super.paint(event, element);
drawSpinner(event, element);
break;
case SPIN:
case MENU:
case COMBO:
drawImage(event, element);
super.paint(event, element);
drawMark(event, element);
break;
default:
super.paint(event, element);
break;
}
if (columnAdvisor.hasSuffixButton(element, columnIndex)) {
Rectangle buttonBounds = columnAdvisor.getSuffixButtonBounds(
getCellBounds(event), element, columnIndex);
drawSuffixButton(event, element, buttonBounds);
}
}
protected void drawBackground(Event event, Object element) {
Rectangle cellBounds = getCellControlBounds(event);
Color clr = columnAdvisor.getBgColor(element, columnIndex);
if (clr != null) {
event.gc.setAlpha(ALPHA);
event.gc.setBackground(clr);
event.gc.fillRectangle(cellBounds);
event.gc.setAlpha(255);
}
}
protected void drawImage(Event event, Object element) {
Image image = columnAdvisor.getImage(element, columnIndex);
if (image != null) {
Rectangle cellBounds = getCellControlBounds(event);
Rectangle imageBounds = image.getBounds();
int dstX = (cellBounds.x + cellBounds.width) - imageBounds.width;
int yOff = (cellBounds.height - imageBounds.height)/2;
yOff = Math.max(2, yOff);
int dstY = cellBounds.y + yOff;
event.gc.setAlpha(ALPHA);
event.gc.drawImage(image, imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height,
dstX, dstY, imageBounds.width, imageBounds.height);
event.gc.setAlpha(255);
}
}
protected void drawMark(Event event, Object element) {
Rectangle cellBounds = getCellControlBounds(event);
int []ptArr = new int[6];
int offs = cellBounds.height/3;
ptArr[0] = cellBounds.x + cellBounds.width;
ptArr[1] = cellBounds.y + cellBounds.height - offs;
ptArr[2] = ptArr[0];
ptArr[3] = cellBounds.y + cellBounds.height;
ptArr[4] = ptArr[0] - offs;
ptArr[5] = ptArr[3];
event.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
event.gc.fillPolygon(ptArr);
}
/**
* Draw a check box
*
* @param event
* @param element tree item in the column zero
*/
protected void drawCheckbox(Event event, Object element) {
Rectangle cellBounds = getCellControlBounds(event);
Image image = columnAdvisor.getCheckboxImage(element, columnIndex);
if (image != null) {
Rectangle imageBounds;
imageBounds = image.getBounds();
event.gc.drawImage(image, imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height,
cellBounds.x + 1, cellBounds.y, imageBounds.width, imageBounds.height);
}
}
protected void drawSuffixButton(Event event, Object element, Rectangle buttonBounds) {
event.gc.setAntialias(SWT.ON);
int height = buttonBounds.height;
int width = buttonBounds.width - 2;
int x = buttonBounds.x + 1;
int y = buttonBounds.y;
if (!columnAdvisor.isSuffixButtonPressed(element, columnIndex)) {
event.gc.setForeground(ColorConstants.COLOR_SUFFICS_BUTTON_TOP);
event.gc.setBackground(ColorConstants.COLOR_SUFFICS_BUTTON_BOTTOM);
} else {
event.gc.setForeground(ColorConstants.COLOR_SUFFICS_BUTTON_BOTTOM);
event.gc.setBackground(ColorConstants.COLOR_SUFFICS_BUTTON_TOP);
}
event.gc.fillGradientRectangle(x, y, width, height, true);
drawButtonImage(columnAdvisor.getSuffixButtonImage(element, columnIndex), event.gc, buttonBounds);
event.gc.setForeground(ColorConstants.COLOR_BORDER);
event.gc.drawRectangle(x, y, width, height);
}
/**
* Get the cell bounds excluding the suffix button's bound if drawn
* @param event the drawing event
* @return cell bounds excluding the suffix button's bound if drawn
*/
protected Rectangle getCellControlBounds(Event event) {
Rectangle cellBounds = getCellBounds(event);
Object element = event.item.getData();
if (columnAdvisor.hasSuffixButton(element, columnIndex)) {
Rectangle buttonBounds = columnAdvisor.getSuffixButtonBounds(cellBounds, element, columnIndex);
if (buttonBounds.width == 0) {
return cellBounds;
}
//drawSuffixButton(event, element, buttonBounds);
cellBounds.width -= buttonBounds.width;
}
return cellBounds;
}
/**
* Draw a button
* @param event
* @param element
*/
protected void drawButton(Event event, Object element) {
if (columnAdvisor.isEmpty(element, columnIndex)) {
return;
}
Rectangle cellBounds = getCellControlBounds(event);
event.gc.setAntialias(SWT.ON);
if (!columnAdvisor.isButtonPressed(element, columnIndex)) {
event.gc.setForeground(ColorConstants.COLOR_BUTTON_TOP);
event.gc.setBackground(ColorConstants.COLOR_BUTTON_BOTTOM);
} else {
event.gc.setForeground(ColorConstants.COLOR_BUTTON_BOTTOM);
event.gc.setBackground(ColorConstants.COLOR_BUTTON_TOP);
}
event.gc.fillGradientRectangle(cellBounds.x + 1, cellBounds.y + 1,
cellBounds.width-1, cellBounds.height, true);
event.gc.setForeground(ColorConstants.COLOR_BORDER);
event.gc.drawRoundRectangle(cellBounds.x, cellBounds.y, cellBounds.width, cellBounds.height,
ColorConstants.ARC_WIDTH_HEIGHT, ColorConstants.ARC_WIDTH_HEIGHT);
int dstX = drawButtonImage(columnAdvisor.getImage(element, columnIndex), event.gc, cellBounds) + 8;
String text = columnAdvisor.getString(element, columnIndex);
Point extent = event.gc.textExtent(text);
//int dstX = (cellBounds.x + cellBounds.width / 2) - extent.x / 2;
int dstY = (cellBounds.y + cellBounds.height / 2) - extent.y / 2 + cellBounds.height % 2;
if (columnAdvisor.isEnabled(element, columnIndex)) {
event.gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
} else {
event.gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BORDER));
}
event.gc.drawString(text, dstX, dstY, true);
}
/**
* Draw the button image
* @param image {@link Image} to draw
* @param gc {@GC} to draw in
* @param bounds rectangle defining destination image position
* @return the right point of the image in the cell, can be used to
* calculate the starting position of the cell string
*/
protected int drawButtonImage(Image image, GC gc, Rectangle bounds) {
int dstX = bounds.x;
int dstY = bounds.y;
if (image != null) {
Rectangle imageBounds = image.getBounds();
//gc.setAlpha(ALPHA);
gc.drawImage(image, imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height,
dstX, dstY, imageBounds.width, imageBounds.height);
//gc.setAlpha(255);
return dstX + imageBounds.width;
}
return dstX;
}
/**
* Draw inplace spinner
* @param event the event
* @param element the cell's element
*/
protected void drawSpinner(Event event, Object element) {
Rectangle cellBounds = getCellControlBounds(event);
event.gc.setAntialias(SWT.ON);
int width = columnAdvisor.getSpinnerWidth(cellBounds, element, columnIndex);
int x = cellBounds.x + cellBounds.width - width;
int height = cellBounds.height / 2;
// draw the up spinner button
{
if (!columnAdvisor.isUpSpinnerPressed(element, columnIndex)) {
event.gc.setForeground(ColorConstants.COLOR_SPINNER_TOP);
event.gc.setBackground(ColorConstants.COLOR_SPINNER_BUTTON);
} else {
event.gc.setForeground(ColorConstants.COLOR_SPINNER_BUTTON);
event.gc.setBackground(ColorConstants.COLOR_SPINNER_TOP);
}
int y = cellBounds.y;
event.gc.fillGradientRectangle(x, y, width, height, true);
event.gc.setForeground(ColorConstants.COLOR_BORDER);
event.gc.drawRectangle(x, y, width, height);
event.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
int[] ptArr = new int[6];
ptArr[0] = x + width / 3 - 1;
ptArr[1] = y + 2 * height / 3;
ptArr[2] = x + width / 2;
ptArr[3] = y + height / 3;
ptArr[4] = x + 2 * width / 3 + 1;
ptArr[5] = ptArr[1];
event.gc.fillPolygon(ptArr);
}
// draw the down spinner button
{
if (!columnAdvisor.isDownSpinnerPressed(element, columnIndex)) {
event.gc.setForeground(ColorConstants.COLOR_SPINNER_TOP);
event.gc.setBackground(ColorConstants.COLOR_SPINNER_BUTTON);
} else {
event.gc.setForeground(ColorConstants.COLOR_SPINNER_BUTTON);
event.gc.setBackground(ColorConstants.COLOR_SPINNER_TOP);
}
int y = cellBounds.y + height;
event.gc.fillGradientRectangle(x, y, width, height, true);
event.gc.setForeground(ColorConstants.COLOR_BORDER);
event.gc.drawRectangle(x, y, width, height);
event.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
int[] ptArr = new int[6];
ptArr[0] = x + width / 3;
ptArr[1] = y + height / 3 + 1;
ptArr[2] = x + width / 2;
ptArr[3] = y + 2 * height / 3 + 1;
ptArr[4] = x + 2 * width / 3 + 1;
ptArr[5] = ptArr[1];
event.gc.fillPolygon(ptArr);
}
}
/**
* Draw an URL
* @param event the event
* @param element tree item in the column zero
*/
protected void drawUrl(Event event, Object element) {
Rectangle cellBounds = getCellControlBounds(event);
String text = columnAdvisor.getString(element, columnIndex);
if (text != null) {
int x = cellBounds.x + TEXTOFFSET;
int y = cellBounds.y;
Image img = columnAdvisor.getImage(element, columnIndex);
if(img != null){
x += img.getBounds().width;
y++;
}
Point extent = event.gc.textExtent(text);
event.gc.drawLine(x - 1, y + extent.y, x + extent.x - 1, y
+ extent.y);
}
}
/** Return the cell bounds
* @param event
* @return the cell bounds
*/
protected Rectangle getCellBounds(Event event) {
Widget item = event.item;
Rectangle cellBounds = new Rectangle(0, 0, 0, 0);
if (item instanceof TreeItem) {
TreeItem treeItem = (TreeItem) item;
cellBounds = treeItem.getBounds(event.index);
} else if (item instanceof TableItem) {
TableItem tableItem = (TableItem) item;
cellBounds = tableItem.getBounds(event.index);
}
return cellBounds;
}
/**
* @return the Display object
*/
public static Display getDisplay() {
Display display = Display.getCurrent();
// may be null if outside the UI thread
if (display == null) {
display = Display.getDefault();
}
return display;
}
@Override
public Image getToolTipImage(Object object) {
return super.getToolTipImage(object);
}
@Override
public void update(ViewerCell cell) {
Object element = cell.getElement();
int index = cell.getColumnIndex();
Color clr = columnAdvisor.getBgColor(element, index);
if(clr != null) {
cell.setBackground(clr);
} else {
cell.setBackground(null);
}
boolean enabled = columnAdvisor.isEnabled(element, index);
switch (columnAdvisor.getCellControlType(element, index)) {
case TEXT:
cell.setImage(columnAdvisor.getImage(element, index));
case SPIN:
case INPLACE_SPIN:
case MENU:
case COMBO:
String s = columnAdvisor.getString(element, index);
if(s != null && !s.isEmpty()) {
// workaround: append space to the text to avoid last character truncation the cells
s += ' ';
}
cell.setText(s);
if(!enabled) {
cell.setForeground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
} else {
cell.setForeground(null);
}
break;
case URL:
cell.setImage(columnAdvisor.getImage(element, index));
cell.setText(columnAdvisor.getString(element, index));
cell.setForeground(getDisplay().getSystemColor(SWT.COLOR_LINK_FOREGROUND));
break;
case BUTTON:
cell.setImage(columnAdvisor.getImage(element, index));
cell.setText(columnAdvisor.getString(element, index));
break;
default:
break;
}
super.update(cell);
}
@Override
public String getToolTipText(Object element) {
return columnAdvisor.getTooltipText(element, columnIndex);
}
}