Mercurial > projects > dwt-addons
diff dwtx/draw2d/text/ParagraphTextLayout.d @ 98:95307ad235d9
Added Draw2d code, still work in progress
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 03 Aug 2008 00:52:14 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/draw2d/text/ParagraphTextLayout.d Sun Aug 03 00:52:14 2008 +0200 @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.draw2d.text.ParagraphTextLayout; + +import dwt.dwthelper.utils; +import dwtx.dwtxhelper.Collection; + +import dwt.graphics.Font; +import dwtx.draw2d.text.TextLayout; +import dwtx.draw2d.text.TextFlow; +import dwtx.draw2d.text.FlowUtilities; +import dwtx.draw2d.text.FlowContext; +import dwtx.draw2d.text.TextFragmentBox; +import dwtx.draw2d.text.FlowBorder; + +/** + * The layout for {@link TextFlow}. + * @author hudsonr + * @since 2.1 + */ +public class ParagraphTextLayout + : TextLayout +{ + +/** + * Wrapping will ONLY occur at valid line breaks + */ +public static const int WORD_WRAP_HARD = 0; + +/** + * Wrapping will always occur at the end of the available space, breaking in the middle of + * a word. + */ +public static const int WORD_WRAP_SOFT = 1; + +/** + * Wrapping will always occur at the end of available space, truncating a word if it + * doesn't fit. Note that truncation is not supported across multiple figures and + * with BiDi. Undesired effects may result if that is the case. + */ +public static const int WORD_WRAP_TRUNCATE = 2; + +private int wrappingStyle = WORD_WRAP_HARD; + +/** + * Constructs a new ParagraphTextLayout on the specified TextFlow. + * @param flow the TextFlow + */ +public this(TextFlow flow) { + super(flow); +} + +/** + * Constructs the layout with the specified TextFlow and wrapping style. The wrapping + * style must be one of: + * <UL> + * <LI>{@link #WORD_WRAP_HARD}</LI> + * <LI>{@link #WORD_WRAP_SOFT}</LI> + * <LI>{@link #WORD_WRAP_TRUNCATE}</LI> + * </UL> + * @param flow the textflow + * @param style the style of wrapping + */ +public this(TextFlow flow, int style) { + this(flow); + wrappingStyle = style; +} + +/** + * Given the Bidi levels of the given text, this method breaks the given text up by + * its level runs. + * @param text the String that needs to be broken up into its level runs + * @param levelInfo the Bidi levels + * @return the requested segment + */ +private String[] getSegments(String text, int levelInfo[]) { + if (levelInfo.length is 1) + return [text]; + + String result[] = new String[levelInfo.length / 2 + 1]; + + int i; + int endOffset; + int beginOffset = 0; + + for (i = 0; i < result.length - 1; i++) { + endOffset = levelInfo[i * 2 + 1]; + result[i] = text.substring(beginOffset, endOffset); + beginOffset = endOffset; + } + endOffset = text.length; + result[i] = text.substring(beginOffset, endOffset); + return result; +} + +class SegmentLookahead : /+FlowUtilities.+/LookAhead { + private int seg = -1; + private String segs[]; + private int[] width; + private final int trailingBorderSize; + this(String segs[], int trailingBorderSize) { + this.segs = segs; + this.trailingBorderSize = trailingBorderSize; + } + public int getWidth() { + if (width is null) { + width = new int[1]; + int startingIndex = seg + 1; + TextFlow textFlow = cast(TextFlow)getFlowFigure(); + + if (startingIndex is segs.length) { + width[0] += trailingBorderSize; + getContext().getWidthLookahead(textFlow, width); + } else { + String rest = segs[startingIndex]; + for (int k = startingIndex + 1; k < segs.length; k++) + rest ~= segs[k]; + if (!textFlow.addLeadingWordWidth(rest, width)) { + width[0] += trailingBorderSize; + getContext().getWidthLookahead(textFlow, width); + } + } + } + return width[0]; + } + public void setIndex(int value) { + this.seg = value; + width = null; + } +} + +/** + * @see dwtx.draw2d.text.FlowFigureLayout#layout() + */ +protected void layout() { + TextFlow textFlow = cast(TextFlow)getFlowFigure(); + int offset = 0; + + FlowContext context = getContext(); + List fragments = textFlow.getFragments(); + Font font = textFlow.getFont(); + int fragIndex = 0; + int advance = 0; + + TextFragmentBox fragment; + int levelInfo[] = (textFlow.getBidiInfo() is null) + ? [-1] + : textFlow.getBidiInfo().levelInfo; + + String segment; + String[] segments = getSegments(textFlow.getText(), levelInfo); + FlowBorder border = null; + if ( null !is cast(FlowBorder)textFlow.getBorder() ) + border = cast(FlowBorder)textFlow.getBorder(); + + SegmentLookahead lookahead = new SegmentLookahead(segments, border is null ? 0 : border.getRightMargin()); + int seg; + + if (border !is null) { + fragment = getFragment(fragIndex++, fragments); + fragment.setBidiLevel(levelInfo[0]); + fragment.setTruncated(false); + fragment.offset = fragment.length = -1; + fragment.setWidth(border.getLeftMargin() + border.getInsets(textFlow).left); + if (context.getRemainingLineWidth() + < fragment.getWidth() + lookahead.getWidth()) + context.endLine(); + context.addToCurrentLine(fragment); + } + + FlowUtilities flowUtilities = textFlow.getFlowUtilities_package(); + for (seg = 0; seg < segments.length; seg++) { + segment = segments[seg]; + lookahead.setIndex(seg); + + do { + fragment = getFragment(fragIndex++, fragments); + + fragment.offset = offset; + fragment.setBidiLevel(levelInfo[seg * 2]); + + advance = flowUtilities.wrapFragmentInContext_package(fragment, segment, + context, lookahead, font, wrappingStyle); + segment = segment.substring(advance); + offset += advance; + if ((segment.length > 0 + || fragment.length < advance) + || fragment.isTruncated()) + context.endLine(); + } while (segment.length > 0 + || (!fragment.isTruncated() && fragment.length < advance)); + } + + if (border !is null) { + fragment = getFragment(fragIndex++, fragments); + fragment.setBidiLevel(levelInfo[0]); + fragment.setTruncated(false); + fragment.offset = fragment.length = -1; + fragment.setWidth(border.getRightMargin() + border.getInsets(textFlow).right); + context.addToCurrentLine(fragment); + } + + //Remove the remaining unused fragments. + while (fragIndex < fragments.size()) + fragments.remove(fragments.size() - 1); +} + +}