/***************************************************************************** * Copyright (c) 2015 CEA LIST. * * 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: * Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation * *****************************************************************************/ package org.eclipse.nebula.widgets.richtext.painter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.nebula.widgets.richtext.painter.instructions.FontMetricsProvider; import org.eclipse.nebula.widgets.richtext.painter.instructions.PaintInstruction; import org.eclipse.nebula.widgets.richtext.painter.instructions.TextPaintInstruction; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Rectangle; public class LinePainter { private Collection<PaintInstruction> instructions = new ArrayList<>(); private FontMetrics biggestMetrics = null; private int contentWidth = 0; private int trimmedContentWidth = 0; private int justifySpace = 0; private int roundingPixels = 0; private List<String> words = new ArrayList<>(); public void paint(GC gc, Rectangle area) { // calculate maximum line height Font beforeFont = gc.getFont(); FontMetrics biggestMetrics = gc.getFontMetrics(); for (PaintInstruction instruction : instructions) { if (instruction instanceof FontMetricsProvider) { FontMetrics metrics = ((FontMetricsProvider) instruction).getFontMetrics(gc); if (metrics.getHeight() > biggestMetrics.getHeight()) { biggestMetrics = metrics; } } // collect all words in a line if (instruction instanceof TextPaintInstruction) { words.addAll(((TextPaintInstruction) instruction).getWords()); } } // calculate the justify space int wordCount = (this.words.size() > 1) ? (this.words.size() - 1) : 1; justifySpace = (area.width - getTrimmedContentWidth()) / wordCount; roundingPixels = area.width - (getTrimmedContentWidth() + (justifySpace * wordCount)); // reset the font after size calculations gc.setFont(beforeFont); // remember the biggest metrics for base line calculation this.biggestMetrics = biggestMetrics; // after the parsing is done, execute the painting operations for (PaintInstruction instruction : instructions) { instruction.paint(gc, area); } } public void addInstruction(PaintInstruction instruction) { this.instructions.add(instruction); } public FontMetrics getBiggestMetrics() { return this.biggestMetrics; } public int getLineHeight() { return this.biggestMetrics.getHeight(); } /** * @return The static content width taking spaces into account. */ public int getContentWidth() { return this.contentWidth; } /** * Increase the static content with with spaces. * * @param width * The width that should be added to the static content width. */ public void increaseContentWidth(int width) { this.contentWidth += width; } /** * @return The static content width without spaces. */ public int getTrimmedContentWidth() { return this.trimmedContentWidth; } /** * Increase the static content with without spaces. * * @param width * The width that should be added to the static content width. */ public void increaseTrimmedContentWidth(int width) { this.trimmedContentWidth += width; } /** * * @return The number of pixels that need to be added to render a text justified. */ public int getNextJustifySpace() { int result = this.justifySpace; if (roundingPixels > 0) { result += roundingPixels--; } return result; } }