/******************************************************************************* * Copyright (c) 2012, 2015 Original authors 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: * Original authors and others - initial API and implementation * Loris Securo <lorissek@gmail.com> - Bug 499513 ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.painter.layer; import java.util.ArrayList; import java.util.List; import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; import org.eclipse.nebula.widgets.nattable.layer.ILayer; import org.eclipse.nebula.widgets.nattable.layer.LabelStack; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; import org.eclipse.nebula.widgets.nattable.util.GUIHelper; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Rectangle; public class GridLineCellLayerPainter extends CellLayerPainter { private final Color gridColor; /** * @since 1.5 */ protected boolean renderGridLines = true; /** * @since 1.4 */ protected Integer gridLineWidth = 1; /** * Create a GridLineCellLayerPainter that renders grid lines in the * specified color and uses the default clipping behaviour. * * @param gridColor * The color that should be used to render the grid lines. */ public GridLineCellLayerPainter(final Color gridColor) { this.gridColor = gridColor; } /** * Create a GridLineCellLayerPainter that renders gray grid lines and uses * the default clipping behaviour. */ public GridLineCellLayerPainter() { this.gridColor = GUIHelper.COLOR_GRAY; } /** * Create a GridLineCellLayerPainter that renders grid lines in the * specified color and uses the specified clipping behaviour. * * @param gridColor * The color that should be used to render the grid lines. * @param clipLeft * Configure the rendering behaviour when cells overlap. If set * to <code>true</code> the left cell will be clipped, if set to * <code>false</code> the right cell will be clipped. The default * value is <code>false</code>. * @param clipTop * Configure the rendering behaviour when cells overlap. If set * to <code>true</code> the top cell will be clipped, if set to * <code>false</code> the bottom cell will be clipped. The * default value is <code>false</code>. */ public GridLineCellLayerPainter(final Color gridColor, boolean clipLeft, boolean clipTop) { super(clipLeft, clipTop); this.gridColor = gridColor; } /** * Create a GridLineCellLayerPainter that renders gray grid lines and uses * the specified clipping behaviour. * * @param clipLeft * Configure the rendering behaviour when cells overlap. If set * to <code>true</code> the left cell will be clipped, if set to * <code>false</code> the right cell will be clipped. The default * value is <code>false</code>. * @param clipTop * Configure the rendering behaviour when cells overlap. If set * to <code>true</code> the top cell will be clipped, if set to * <code>false</code> the bottom cell will be clipped. The * default value is <code>false</code>. */ public GridLineCellLayerPainter(boolean clipLeft, boolean clipTop) { this(GUIHelper.COLOR_GRAY, clipLeft, clipTop); } /** * @return The local configured color that is used to render the grid lines. */ public Color getGridColor() { return this.gridColor; } @Override public void paintLayer(ILayer natLayer, GC gc, int xOffset, int yOffset, Rectangle rectangle, IConfigRegistry configRegistry) { Boolean renderConfig = null; LabelStack stack = natLayer.getRegionLabelsByXY(xOffset, yOffset); List<String> labels = new ArrayList<String>(); if (stack != null) { labels = stack.getLabels(); // check if there is a configuration telling to not rendering grid // lines renderConfig = configRegistry.getConfigAttribute( CellConfigAttributes.RENDER_GRID_LINES, DisplayMode.NORMAL, labels); } this.renderGridLines = (renderConfig != null) ? renderConfig : true; // Draw GridLines if (this.renderGridLines) { // check if there is a configuration for the grid line width Integer width = configRegistry.getConfigAttribute( CellConfigAttributes.GRID_LINE_WIDTH, DisplayMode.NORMAL, labels); this.gridLineWidth = (width != null) ? width : 1; int oldLineWidth = gc.getLineWidth(); gc.setLineWidth(this.gridLineWidth); drawGridLines(natLayer, gc, rectangle, configRegistry, labels); gc.setLineWidth(oldLineWidth); } super.paintLayer(natLayer, gc, xOffset, yOffset, rectangle, configRegistry); } @Override public Rectangle adjustCellBounds(int columnPosition, int rowPosition, Rectangle bounds) { Integer adjustment = this.renderGridLines ? this.gridLineWidth : 0; int startAdjustment = (adjustment == 1) ? 0 : Math.round(adjustment.floatValue() / 2); int sizeAdjustment = (adjustment == 1) ? 1 : Math.round(adjustment.floatValue() / 2); return new Rectangle( bounds.x - startAdjustment, bounds.y - startAdjustment, Math.max(bounds.width - sizeAdjustment, 0), Math.max(bounds.height - sizeAdjustment, 0)); } /** * @deprecated Use * {@link #drawGridLines(ILayer, GC, Rectangle, IConfigRegistry, List)} * with specifying the label stack */ @Deprecated protected void drawGridLines(ILayer natLayer, GC gc, Rectangle rectangle, IConfigRegistry configRegistry) { drawGridLines(natLayer, gc, rectangle, configRegistry, new ArrayList<String>()); } /** * @since 1.4 */ protected void drawGridLines(ILayer natLayer, GC gc, Rectangle rectangle, IConfigRegistry configRegistry, List<String> labels) { Color gColor = configRegistry.getConfigAttribute( CellConfigAttributes.GRID_LINE_COLOR, DisplayMode.NORMAL, labels); gc.setForeground(gColor != null ? gColor : this.gridColor); int adjustment = (this.gridLineWidth == 1) ? 1 : Math.round(this.gridLineWidth.floatValue() / 2); drawHorizontalLines(natLayer, gc, rectangle, adjustment); drawVerticalLines(natLayer, gc, rectangle, adjustment); } private void drawHorizontalLines(ILayer natLayer, GC gc, Rectangle rectangle, int adjustment) { int endX = rectangle.x + Math.min(natLayer.getWidth() - adjustment, rectangle.width); // this can happen on resizing if there is no CompositeLayer involved // without this check grid line fragments may be rendered below the last // column if (endX > natLayer.getWidth()) return; int rowPositionByY = natLayer.getRowPositionByY(rectangle.y + rectangle.height); int maxRowPosition = rowPositionByY > 0 ? Math.min(natLayer.getRowCount(), rowPositionByY) : natLayer.getRowCount(); for (int rowPosition = natLayer.getRowPositionByY(rectangle.y); rowPosition < maxRowPosition; rowPosition++) { final int size = natLayer.getRowHeightByPosition(rowPosition); if (size > 0) { int y = natLayer.getStartYOfRowPosition(rowPosition) + size - adjustment; gc.drawLine(rectangle.x, y, endX, y); } } } private void drawVerticalLines(ILayer natLayer, GC gc, Rectangle rectangle, int adjustment) { int endY = rectangle.y + Math.min(natLayer.getHeight() - adjustment, rectangle.height); // this can happen on resizing if there is no CompositeLayer involved // without this check grid line fragments may be rendered below the last // row if (endY > natLayer.getHeight()) return; int columnPositionByX = natLayer.getColumnPositionByX(rectangle.x + rectangle.width); int maxColumnPosition = columnPositionByX > 0 ? Math.min(natLayer.getColumnCount(), columnPositionByX) : natLayer.getColumnCount(); for (int columnPosition = natLayer.getColumnPositionByX(rectangle.x); columnPosition < maxColumnPosition; columnPosition++) { final int size = natLayer.getColumnWidthByPosition(columnPosition); if (size > 0) { int x = natLayer.getStartXOfColumnPosition(columnPosition) + size - adjustment; gc.drawLine(x, rectangle.y, x, endY); } } } }