comparison 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
comparison
equal deleted inserted replaced
96:b492ba44e44d 98:95307ad235d9
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.draw2d.text.ParagraphTextLayout;
14
15 import dwt.dwthelper.utils;
16 import dwtx.dwtxhelper.Collection;
17
18 import dwt.graphics.Font;
19 import dwtx.draw2d.text.TextLayout;
20 import dwtx.draw2d.text.TextFlow;
21 import dwtx.draw2d.text.FlowUtilities;
22 import dwtx.draw2d.text.FlowContext;
23 import dwtx.draw2d.text.TextFragmentBox;
24 import dwtx.draw2d.text.FlowBorder;
25
26 /**
27 * The layout for {@link TextFlow}.
28 * @author hudsonr
29 * @since 2.1
30 */
31 public class ParagraphTextLayout
32 : TextLayout
33 {
34
35 /**
36 * Wrapping will ONLY occur at valid line breaks
37 */
38 public static const int WORD_WRAP_HARD = 0;
39
40 /**
41 * Wrapping will always occur at the end of the available space, breaking in the middle of
42 * a word.
43 */
44 public static const int WORD_WRAP_SOFT = 1;
45
46 /**
47 * Wrapping will always occur at the end of available space, truncating a word if it
48 * doesn't fit. Note that truncation is not supported across multiple figures and
49 * with BiDi. Undesired effects may result if that is the case.
50 */
51 public static const int WORD_WRAP_TRUNCATE = 2;
52
53 private int wrappingStyle = WORD_WRAP_HARD;
54
55 /**
56 * Constructs a new ParagraphTextLayout on the specified TextFlow.
57 * @param flow the TextFlow
58 */
59 public this(TextFlow flow) {
60 super(flow);
61 }
62
63 /**
64 * Constructs the layout with the specified TextFlow and wrapping style. The wrapping
65 * style must be one of:
66 * <UL>
67 * <LI>{@link #WORD_WRAP_HARD}</LI>
68 * <LI>{@link #WORD_WRAP_SOFT}</LI>
69 * <LI>{@link #WORD_WRAP_TRUNCATE}</LI>
70 * </UL>
71 * @param flow the textflow
72 * @param style the style of wrapping
73 */
74 public this(TextFlow flow, int style) {
75 this(flow);
76 wrappingStyle = style;
77 }
78
79 /**
80 * Given the Bidi levels of the given text, this method breaks the given text up by
81 * its level runs.
82 * @param text the String that needs to be broken up into its level runs
83 * @param levelInfo the Bidi levels
84 * @return the requested segment
85 */
86 private String[] getSegments(String text, int levelInfo[]) {
87 if (levelInfo.length is 1)
88 return [text];
89
90 String result[] = new String[levelInfo.length / 2 + 1];
91
92 int i;
93 int endOffset;
94 int beginOffset = 0;
95
96 for (i = 0; i < result.length - 1; i++) {
97 endOffset = levelInfo[i * 2 + 1];
98 result[i] = text.substring(beginOffset, endOffset);
99 beginOffset = endOffset;
100 }
101 endOffset = text.length;
102 result[i] = text.substring(beginOffset, endOffset);
103 return result;
104 }
105
106 class SegmentLookahead : /+FlowUtilities.+/LookAhead {
107 private int seg = -1;
108 private String segs[];
109 private int[] width;
110 private final int trailingBorderSize;
111 this(String segs[], int trailingBorderSize) {
112 this.segs = segs;
113 this.trailingBorderSize = trailingBorderSize;
114 }
115 public int getWidth() {
116 if (width is null) {
117 width = new int[1];
118 int startingIndex = seg + 1;
119 TextFlow textFlow = cast(TextFlow)getFlowFigure();
120
121 if (startingIndex is segs.length) {
122 width[0] += trailingBorderSize;
123 getContext().getWidthLookahead(textFlow, width);
124 } else {
125 String rest = segs[startingIndex];
126 for (int k = startingIndex + 1; k < segs.length; k++)
127 rest ~= segs[k];
128 if (!textFlow.addLeadingWordWidth(rest, width)) {
129 width[0] += trailingBorderSize;
130 getContext().getWidthLookahead(textFlow, width);
131 }
132 }
133 }
134 return width[0];
135 }
136 public void setIndex(int value) {
137 this.seg = value;
138 width = null;
139 }
140 }
141
142 /**
143 * @see dwtx.draw2d.text.FlowFigureLayout#layout()
144 */
145 protected void layout() {
146 TextFlow textFlow = cast(TextFlow)getFlowFigure();
147 int offset = 0;
148
149 FlowContext context = getContext();
150 List fragments = textFlow.getFragments();
151 Font font = textFlow.getFont();
152 int fragIndex = 0;
153 int advance = 0;
154
155 TextFragmentBox fragment;
156 int levelInfo[] = (textFlow.getBidiInfo() is null)
157 ? [-1]
158 : textFlow.getBidiInfo().levelInfo;
159
160 String segment;
161 String[] segments = getSegments(textFlow.getText(), levelInfo);
162 FlowBorder border = null;
163 if ( null !is cast(FlowBorder)textFlow.getBorder() )
164 border = cast(FlowBorder)textFlow.getBorder();
165
166 SegmentLookahead lookahead = new SegmentLookahead(segments, border is null ? 0 : border.getRightMargin());
167 int seg;
168
169 if (border !is null) {
170 fragment = getFragment(fragIndex++, fragments);
171 fragment.setBidiLevel(levelInfo[0]);
172 fragment.setTruncated(false);
173 fragment.offset = fragment.length = -1;
174 fragment.setWidth(border.getLeftMargin() + border.getInsets(textFlow).left);
175 if (context.getRemainingLineWidth()
176 < fragment.getWidth() + lookahead.getWidth())
177 context.endLine();
178 context.addToCurrentLine(fragment);
179 }
180
181 FlowUtilities flowUtilities = textFlow.getFlowUtilities_package();
182 for (seg = 0; seg < segments.length; seg++) {
183 segment = segments[seg];
184 lookahead.setIndex(seg);
185
186 do {
187 fragment = getFragment(fragIndex++, fragments);
188
189 fragment.offset = offset;
190 fragment.setBidiLevel(levelInfo[seg * 2]);
191
192 advance = flowUtilities.wrapFragmentInContext_package(fragment, segment,
193 context, lookahead, font, wrappingStyle);
194 segment = segment.substring(advance);
195 offset += advance;
196 if ((segment.length > 0
197 || fragment.length < advance)
198 || fragment.isTruncated())
199 context.endLine();
200 } while (segment.length > 0
201 || (!fragment.isTruncated() && fragment.length < advance));
202 }
203
204 if (border !is null) {
205 fragment = getFragment(fragIndex++, fragments);
206 fragment.setBidiLevel(levelInfo[0]);
207 fragment.setTruncated(false);
208 fragment.offset = fragment.length = -1;
209 fragment.setWidth(border.getRightMargin() + border.getInsets(textFlow).right);
210 context.addToCurrentLine(fragment);
211 }
212
213 //Remove the remaining unused fragments.
214 while (fragIndex < fragments.size())
215 fragments.remove(fragments.size() - 1);
216 }
217
218 }