blob: 3574f103cff0f771a91a2a169aa983ae03229a30 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2020 Dirk Fauth and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.nebula.widgets.nattable.painter.cell;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.resize.command.ColumnResizeCommand;
import org.eclipse.nebula.widgets.nattable.resize.command.RowResizeCommand;
import org.eclipse.nebula.widgets.nattable.style.CellStyleUtil;
import org.eclipse.nebula.widgets.nattable.style.IStyle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
/**
* TextPainter that draws text into a cell vertically. Can handle word wrapping
* and/or word cutting and/or automatic calculation and resizing of the cell
* width and height if the text does not fit into the cell.
* <p>
* <b>Note:</b><br>
* This is the old implementation that uses {@link GraphicsUtils} to create the
* counter-clockwise rotated vertical text. Internally it will render the text
* horizontal to a temporary image and rotate the image afterwards.<br>
* This implementation is kept in case the new {@link VerticalTextPainter} that
* uses {@link Transform} for rotations is not working as intended. A typical
* case for this could be wrong size calculations dependent on several fonts.
* </p>
*/
public class VerticalTextImagePainter extends AbstractTextPainter {
public VerticalTextImagePainter() {
this(false, true);
}
/**
* @param wrapText
* split text over multiple lines
* @param paintBg
* skips painting the background if is FALSE
*/
public VerticalTextImagePainter(boolean wrapText, boolean paintBg) {
this(wrapText, paintBg, 0);
}
/**
* @param wrapText
* split text over multiple lines
* @param paintBg
* skips painting the background if is FALSE
* @param spacing
* The space between text and cell border
*/
public VerticalTextImagePainter(boolean wrapText, boolean paintBg, int spacing) {
this(wrapText, paintBg, spacing, false);
}
/**
* @param wrapText
* split text over multiple lines
* @param paintBg
* skips painting the background if is FALSE
* @param calculate
* tells the text painter to calculate the cell borders regarding
* the content
*/
public VerticalTextImagePainter(boolean wrapText, boolean paintBg, boolean calculate) {
this(wrapText, paintBg, 0, calculate);
}
/**
* @param wrapText
* split text over multiple lines
* @param paintBg
* skips painting the background if is FALSE
* @param calculateByTextLength
* tells the text painter to calculate the cell border by
* containing text length. For horizontal text rendering, this
* means the width of the cell is calculated by content, for
* vertical text rendering the height is calculated
* @param calculateByTextHeight
* tells the text painter to calculate the cell border by
* containing text height. For horizontal text rendering, this
* means the height of the cell is calculated by content, for
* vertical text rendering the width is calculated
*/
public VerticalTextImagePainter(boolean wrapText, boolean paintBg,
boolean calculateByTextLength, boolean calculateByTextHeight) {
this(wrapText, paintBg, 0, calculateByTextLength, calculateByTextHeight);
}
/**
* @param wrapText
* split text over multiple lines
* @param paintBg
* skips painting the background if is FALSE
* @param spacing
* The space between text and cell border
* @param calculate
* tells the text painter to calculate the cell borders regarding
* the content
*/
public VerticalTextImagePainter(boolean wrapText, boolean paintBg, int spacing, boolean calculate) {
super(wrapText, paintBg, spacing, calculate);
}
/**
* @param wrapText
* split text over multiple lines
* @param paintBg
* skips painting the background if is FALSE
* @param spacing
* The space between text and cell border
* @param calculateByTextLength
* tells the text painter to calculate the cell border by
* containing text length. For horizontal text rendering, this
* means the width of the cell is calculated by content, for
* vertical text rendering the height is calculated
* @param calculateByTextHeight
* tells the text painter to calculate the cell border by
* containing text height. For horizontal text rendering, this
* means the height of the cell is calculated by content, for
* vertical text rendering the width is calculated
*/
public VerticalTextImagePainter(boolean wrapText, boolean paintBg, int spacing,
boolean calculateByTextLength, boolean calculateByTextHeight) {
super(wrapText, paintBg, spacing, calculateByTextLength, calculateByTextHeight);
}
@Override
public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
setupGCFromConfig(gc, CellStyleUtil.getCellStyle(cell, configRegistry));
String value = convertDataType(cell, configRegistry);
return gc.textExtent(value).y + (this.spacing * 2) + (getNumberOfNewLines(value) - 1) * this.lineSpacing;
}
@Override
public int getPreferredHeight(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
setupGCFromConfig(gc, CellStyleUtil.getCellStyle(cell, configRegistry));
return getLengthFromCache(gc, convertDataType(cell, configRegistry)) + (this.spacing * 2) + 1;
}
@Override
public void paintCell(ILayerCell cell, GC gc, Rectangle rectangle, IConfigRegistry configRegistry) {
if (this.paintBg) {
super.paintCell(cell, gc, rectangle, configRegistry);
}
Rectangle originalClipping = gc.getClipping();
gc.setClipping(rectangle.intersection(originalClipping));
IStyle cellStyle = CellStyleUtil.getCellStyle(cell, configRegistry);
setupGCFromConfig(gc, cellStyle);
boolean underline = renderUnderlined(cellStyle);
boolean strikethrough = renderStrikethrough(cellStyle);
String text = convertDataType(cell, configRegistry);
// calculate the text to display, adds dots if the text is longer than
// the available row height and adds new lines instead of spaces if word
// wrapping is enabled
text = getTextToDisplay(cell, gc, rectangle.height, text);
int numberOfNewLines = getNumberOfNewLines(text);
// if the content width is bigger than the available column width
// we're extending the column width (only if word wrapping is enabled)
int fontHeight = gc.getFontMetrics().getHeight();
int contentWidth = (fontHeight * numberOfNewLines) + (this.lineSpacing * (numberOfNewLines - 1)) + (this.spacing * 2);
int contentToCellDiff = (cell.getBounds().width - rectangle.width);
if ((contentWidth > rectangle.width) && this.calculateByTextHeight) {
ILayer layer = cell.getLayer();
layer.doCommand(
new ColumnResizeCommand(layer, cell.getColumnPosition(), contentWidth + contentToCellDiff, true));
}
if (text != null && text.length() > 0) {
if (numberOfNewLines == 1) {
int contentHeight = Math.min(getLengthFromCache(gc, text), rectangle.height);
GraphicsUtils.drawVerticalText(
text,
rectangle.x
+ CellStyleUtil.getHorizontalAlignmentPadding(cellStyle, rectangle, contentWidth)
+ this.spacing,
rectangle.y
+ CellStyleUtil.getVerticalAlignmentPadding(cellStyle, rectangle, contentHeight + this.spacing),
underline,
strikethrough, this.paintBg, gc, SWT.UP);
} else {
// draw every line by itself because of the alignment, otherwise
// the whole text is always aligned right
int xStartPos = rectangle.x
+ CellStyleUtil.getHorizontalAlignmentPadding(cellStyle, rectangle, contentWidth);
String[] lines = text.split("\n"); //$NON-NLS-1$
for (String line : lines) {
int lineContentWidth = Math.min(getLengthFromCache(gc, line), rectangle.height);
GraphicsUtils.drawVerticalText(
line,
xStartPos + this.spacing,
rectangle.y + CellStyleUtil.getVerticalAlignmentPadding(
cellStyle,
rectangle,
lineContentWidth + this.spacing),
underline, strikethrough, this.paintBg, gc,
SWT.UP);
// after every line calculate the x start pos new
xStartPos += fontHeight;
xStartPos += this.lineSpacing;
}
}
}
gc.setClipping(originalClipping);
}
@Override
protected void setNewMinLength(ILayerCell cell, int contentHeight) {
int cellLength = cell.getBounds().height;
if (cellLength < contentHeight) {
ILayer layer = cell.getLayer();
layer.doCommand(new RowResizeCommand(layer, cell.getRowPosition(), contentHeight, true));
}
}
@Override
protected int calculatePadding(ILayerCell cell, int availableLength) {
return cell.getBounds().height - availableLength;
}
}