Mercurial > projects > dwt2
annotate org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/custom/StyledTextRenderer.d @ 120:536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
===D2===
* added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements
used these templates to work with strict type storage rules of dmd-2.053
* com.ibm.icu now also compilable with D2, but not tested yet
* small fixes
Snippet288 - shared data is in TLS
===Phobos===
* fixed critical bugs in Phobos implemention
completely incorrect segfault prone fromStringz (Linux's port ruthless killer)
terrible, incorrect StringBuffer realization (StyledText killer)
* fixed small bugs as well
Snippet72 - misprint in the snippet
* implemented missed functionality for Phobos
ByteArrayOutputStream implemented (image loading available)
formatting correctly works for all DWT's cases
As a result, folowing snippets now works with Phobos (Snippet### - what is fixed):
Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting
Snippet48, 282 - crash on image loading
Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText
Snippet244 - hang-up
===Tango===
* few changes for the latest Tango trunc-r5661
* few small performance improvments
===General===
* implMissing-s for only one version changed to implMissingInTango/InPhobos
* incorrect calls to Format in toString-s fixed
* fixed loading \uXXXX characters in ResourceBundle
* added good UTF-8 support for StyledText, TextLayout (Win32) and friends
UTF functions revised and tested. It is now in java.nonstandard.*Utf modules
StyledText and TextLayout (Win32) modules revised for UTF-8 support
* removed small diferences in most identical files in *.swt.* folders
*.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32
now 179 of 576 (~31%) files in *.swt.* folders are fully identical
* Win32: snippets now have right subsystem, pretty icons and native system style controls
* small fixes in snippets
Snippet44 - it's not Snippet44
Snippet212 - functions work with different images and offsets arrays
Win32: Snippet282 - crash on close if the button has an image
Snippet293 - setGrayed is commented
and others
Win32: As a result, folowing snippets now works
Snippet68 - color doesn't change
Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above)
Snippet193 - no tabel headers
author | Denis Shelomovskij <verylonglogin.reg@gmail.com> |
---|---|
date | Sat, 09 Jul 2011 15:50:20 +0300 |
parents | c01d033c633a |
children |
rev | line source |
---|---|
25 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2008 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 org.eclipse.swt.custom.StyledTextRenderer; | |
14 | |
15 | |
16 | |
17 import org.eclipse.swt.SWT; | |
18 import org.eclipse.swt.graphics.Color; | |
19 import org.eclipse.swt.graphics.Device; | |
20 import org.eclipse.swt.graphics.Font; | |
21 import org.eclipse.swt.graphics.FontData; | |
22 import org.eclipse.swt.graphics.FontMetrics; | |
23 import org.eclipse.swt.graphics.GC; | |
24 import org.eclipse.swt.graphics.GlyphMetrics; | |
25 import org.eclipse.swt.graphics.Point; | |
26 import org.eclipse.swt.graphics.Rectangle; | |
27 import org.eclipse.swt.graphics.TextLayout; | |
28 import org.eclipse.swt.graphics.TextStyle; | |
29 import org.eclipse.swt.widgets.Display; | |
30 import org.eclipse.swt.widgets.IME; | |
31 import org.eclipse.swt.widgets.ScrollBar; | |
32 import org.eclipse.swt.custom.StyledText; | |
33 import org.eclipse.swt.custom.Bullet; | |
34 import org.eclipse.swt.custom.StyleRange; | |
35 import org.eclipse.swt.custom.StyledText; | |
36 import org.eclipse.swt.custom.StyledTextContent; | |
37 import org.eclipse.swt.custom.TextChangingEvent; | |
38 import org.eclipse.swt.custom.ST; | |
39 import org.eclipse.swt.custom.StyledTextEvent; | |
40 | |
41 import java.lang.all; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
42 import java.nonstandard.UnsafeUtf; |
25 | 43 |
44 /** | |
45 * A StyledTextRenderer renders the content of a StyledText widget. | |
46 * This class can be used to render to the display or to a printer. | |
47 */ | |
48 class StyledTextRenderer { | |
49 Device device; | |
50 StyledText styledText; | |
51 StyledTextContent content; | |
52 | |
53 /* Font info */ | |
54 Font regularFont, boldFont, italicFont, boldItalicFont; | |
55 int tabWidth; | |
56 int ascent, descent; | |
57 int averageCharWidth; | |
58 | |
59 /* Line data */ | |
60 int topIndex = -1; | |
61 TextLayout[] layouts; | |
62 int lineCount; | |
63 int[] lineWidth; | |
64 int[] lineHeight; | |
65 LineInfo[] lines; | |
66 int maxWidth; | |
67 int maxWidthLineIndex; | |
68 bool idleRunning; | |
69 | |
70 /* Bullet */ | |
71 Bullet[] bullets; | |
72 int[] bulletsIndices; | |
73 int[] redrawLines; | |
74 | |
75 /* Style data */ | |
76 int[] ranges; | |
77 int styleCount; | |
78 StyleRange[] styles; | |
79 StyleRange[] stylesSet; | |
80 int stylesSetCount = 0; | |
49
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
81 const static int BULLET_MARGIN = 8; |
25 | 82 |
49
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
83 const static bool COMPACT_STYLES = true; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
84 const static bool MERGE_STYLES = true; |
25 | 85 |
49
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
86 const static int GROW = 32; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
87 const static int IDLE_TIME = 50; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
88 const static int CACHE_SIZE = 128; |
25 | 89 |
49
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
90 const static int BACKGROUND = 1 << 0; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
91 const static int ALIGNMENT = 1 << 1; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
92 const static int INDENT = 1 << 2; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
93 const static int JUSTIFY = 1 << 3; |
7a2dd761a8b2
more work until dmd 2.026 linux segfaults.
Frank Benoit <benoit@tionex.de>
parents:
48
diff
changeset
|
94 const static int SEGMENTS = 1 << 5; |
25 | 95 |
96 static class LineInfo { | |
97 int flags; | |
98 Color background; | |
99 int alignment; | |
100 int indent; | |
101 bool justify; | |
102 int[] segments; | |
103 | |
104 public this() { | |
105 } | |
106 public this(LineInfo info) { | |
107 if (info !is null) { | |
108 flags = info.flags; | |
109 background = info.background; | |
110 alignment = info.alignment; | |
111 indent = info.indent; | |
112 justify = info.justify; | |
113 segments = info.segments; | |
114 } | |
115 } | |
116 } | |
117 | |
118 this(Device device, StyledText styledText) { | |
119 this.device = device; | |
120 this.styledText = styledText; | |
121 } | |
122 int addMerge(int[] mergeRanges, StyleRange[] mergeStyles, int mergeCount, int modifyStart, int modifyEnd) { | |
123 int rangeCount = styleCount << 1; | |
124 StyleRange endStyle = null; | |
125 int endStart = 0, endLength = 0; | |
126 if (modifyEnd < rangeCount) { | |
127 endStyle = styles[modifyEnd >> 1]; | |
128 endStart = ranges[modifyEnd]; | |
129 endLength = ranges[modifyEnd + 1]; | |
130 } | |
131 int grow = mergeCount - (modifyEnd - modifyStart); | |
132 if (rangeCount + grow >= ranges.length) { | |
133 int[] tmpRanges = new int[ranges.length + grow + (GROW << 1)]; | |
134 System.arraycopy(ranges, 0, tmpRanges, 0, modifyStart); | |
135 StyleRange[] tmpStyles = new StyleRange[styles.length + (grow >> 1) + GROW]; | |
136 System.arraycopy(styles, 0, tmpStyles, 0, modifyStart >> 1); | |
137 if (rangeCount > modifyEnd) { | |
138 System.arraycopy(ranges, modifyEnd, tmpRanges, modifyStart + mergeCount, rangeCount - modifyEnd); | |
139 System.arraycopy(styles, modifyEnd >> 1, tmpStyles, (modifyStart + mergeCount) >> 1, styleCount - (modifyEnd >> 1)); | |
140 } | |
141 ranges = tmpRanges; | |
142 styles = tmpStyles; | |
143 } else { | |
144 if (rangeCount > modifyEnd) { | |
145 System.arraycopy(ranges, modifyEnd, ranges, modifyStart + mergeCount, rangeCount - modifyEnd); | |
146 System.arraycopy(styles, modifyEnd >> 1, styles, (modifyStart + mergeCount) >> 1, styleCount - (modifyEnd >> 1)); | |
147 } | |
148 } | |
149 if (MERGE_STYLES) { | |
150 int j = modifyStart; | |
151 for (int i = 0; i < mergeCount; i += 2) { | |
152 if (j > 0 && ranges[j - 2] + ranges[j - 1] is mergeRanges[i] && mergeStyles[i >> 1].similarTo(styles[(j - 2) >> 1])) { | |
153 ranges[j - 1] += mergeRanges[i + 1]; | |
154 } else { | |
155 styles[j >> 1] = mergeStyles[i >> 1]; | |
156 ranges[j++] = mergeRanges[i]; | |
157 ranges[j++] = mergeRanges[i + 1]; | |
158 } | |
159 } | |
160 if (endStyle !is null && ranges[j - 2] + ranges[j - 1] is endStart && endStyle.similarTo(styles[(j - 2) >> 1])) { | |
161 ranges[j - 1] += endLength; | |
162 modifyEnd += 2; | |
163 mergeCount += 2; | |
164 } | |
165 if (rangeCount > modifyEnd) { | |
166 System.arraycopy(ranges, modifyStart + mergeCount, ranges, j, rangeCount - modifyEnd); | |
167 System.arraycopy(styles, (modifyStart + mergeCount) >> 1, styles, j >> 1, styleCount - (modifyEnd >> 1)); | |
168 } | |
169 grow = (j - modifyStart) - (modifyEnd - modifyStart); | |
170 } else { | |
171 System.arraycopy(mergeRanges, 0, ranges, modifyStart, mergeCount); | |
172 System.arraycopy(mergeStyles, 0, styles, modifyStart >> 1, mergeCount >> 1); | |
173 } | |
174 styleCount += grow >> 1; | |
175 return grow; | |
176 } | |
177 int addMerge(StyleRange[] mergeStyles, int mergeCount, int modifyStart, int modifyEnd) { | |
178 int grow = mergeCount - (modifyEnd - modifyStart); | |
179 StyleRange endStyle = null; | |
180 if (modifyEnd < styleCount) endStyle = styles[modifyEnd]; | |
181 if (styleCount + grow >= styles.length) { | |
182 StyleRange[] tmpStyles = new StyleRange[styles.length + grow + GROW]; | |
183 System.arraycopy(styles, 0, tmpStyles, 0, modifyStart); | |
184 if (styleCount > modifyEnd) { | |
185 System.arraycopy(styles, modifyEnd, tmpStyles, modifyStart + mergeCount, styleCount - modifyEnd); | |
186 } | |
187 styles = tmpStyles; | |
188 } else { | |
189 if (styleCount > modifyEnd) { | |
190 System.arraycopy(styles, modifyEnd, styles, modifyStart + mergeCount, styleCount - modifyEnd); | |
191 } | |
192 } | |
193 if (MERGE_STYLES) { | |
194 int j = modifyStart; | |
195 for (int i = 0; i < mergeCount; i++) { | |
196 StyleRange newStyle = mergeStyles[i], style; | |
197 if (j > 0 && (style = styles[j - 1]).start + style.length is newStyle.start && newStyle.similarTo(style)) { | |
198 style.length += newStyle.length; | |
199 } else { | |
200 styles[j++] = newStyle; | |
201 } | |
202 } | |
203 StyleRange style = styles[j - 1]; | |
204 if (endStyle !is null && style.start + style.length is endStyle.start && endStyle.similarTo(style)) { | |
205 style.length += endStyle.length; | |
206 modifyEnd++; | |
207 mergeCount++; | |
208 } | |
209 if (styleCount > modifyEnd) { | |
210 System.arraycopy(styles, modifyStart + mergeCount, styles, j, styleCount - modifyEnd); | |
211 } | |
212 grow = (j - modifyStart) - (modifyEnd - modifyStart); | |
213 } else { | |
214 System.arraycopy(mergeStyles, 0, styles, modifyStart, mergeCount); | |
215 } | |
216 styleCount += grow; | |
217 return grow; | |
218 } | |
219 void calculate(int startLine, int lineCount) { | |
220 int endLine = startLine + lineCount; | |
221 if (startLine < 0 || endLine > lineWidth.length) { | |
222 return; | |
223 } | |
224 int hTrim = styledText.leftMargin + styledText.rightMargin + styledText.getCaretWidth(); | |
225 for (int i = startLine; i < endLine; i++) { | |
226 if (lineWidth[i] is -1 || lineHeight[i] is -1) { | |
227 TextLayout layout = getTextLayout(i); | |
228 Rectangle rect = layout.getBounds(); | |
229 lineWidth[i] = rect.width + hTrim; | |
230 lineHeight[i] = rect.height; | |
231 disposeTextLayout(layout); | |
232 } | |
233 if (lineWidth[i] > maxWidth) { | |
234 maxWidth = lineWidth[i]; | |
235 maxWidthLineIndex = i; | |
236 } | |
237 } | |
238 } | |
239 void calculateClientArea () { | |
240 int index = styledText.getTopIndex(); | |
241 int lineCount = content.getLineCount(); | |
242 int height = styledText.getClientArea().height; | |
243 int y = 0; | |
244 while (height > y && lineCount > index) { | |
245 calculate(index, 1); | |
246 y += lineHeight[index++]; | |
247 } | |
248 } | |
249 void calculateIdle () { | |
250 if (idleRunning) return; | |
251 Runnable runnable = new class() Runnable { | |
252 public void run() { | |
253 if (styledText is null) return; | |
254 int i; | |
255 long start = System.currentTimeMillis(); | |
256 for (i = 0; i < lineCount; i++) { | |
257 if (lineHeight[i] is -1 || lineWidth[i] is -1) { | |
258 calculate(i, 1); | |
259 if (System.currentTimeMillis() - start > IDLE_TIME) break; | |
260 } | |
261 } | |
262 if (i < lineCount) { | |
263 Display display = styledText.getDisplay(); | |
264 display.asyncExec(this); | |
265 } else { | |
266 idleRunning = false; | |
267 styledText.setScrollBars(true); | |
268 ScrollBar bar = styledText.getVerticalBar(); | |
269 if (bar !is null) { | |
270 bar.setSelection(styledText.getVerticalScrollOffset()); | |
271 } | |
272 } | |
273 } | |
274 }; | |
275 Display display = styledText.getDisplay(); | |
276 display.asyncExec(runnable); | |
277 idleRunning = true; | |
278 } | |
279 void clearLineBackground(int startLine, int count) { | |
280 if (lines is null) return; | |
281 for (int i = startLine; i < startLine + count; i++) { | |
282 LineInfo info = lines[i]; | |
283 if (info !is null) { | |
284 info.flags &= ~BACKGROUND; | |
285 info.background = null; | |
286 if (info.flags is 0) lines[i] = null; | |
287 } | |
288 } | |
289 } | |
290 void clearLineStyle(int startLine, int count) { | |
291 if (lines is null) return; | |
292 for (int i = startLine; i < startLine + count; i++) { | |
293 LineInfo info = lines[i]; | |
294 if (info !is null) { | |
295 info.flags &= ~(ALIGNMENT | INDENT | JUSTIFY); | |
296 if (info.flags is 0) lines[i] = null; | |
297 } | |
298 } | |
299 } | |
300 void copyInto(StyledTextRenderer renderer) { | |
301 if (ranges !is null) { | |
302 int[] newRanges = renderer.ranges = new int[styleCount << 1]; | |
303 System.arraycopy(ranges, 0, newRanges, 0, newRanges.length); | |
304 } | |
305 if (styles !is null) { | |
306 StyleRange[] newStyles = renderer.styles = new StyleRange[styleCount]; | |
307 for (int i = 0; i < newStyles.length; i++) { | |
308 newStyles[i] = cast(StyleRange)styles[i].clone(); | |
309 } | |
310 renderer.styleCount = styleCount; | |
311 } | |
312 if (lines !is null) { | |
313 LineInfo[] newLines = renderer.lines = new LineInfo[lineCount]; | |
314 for (int i = 0; i < newLines.length; i++) { | |
315 newLines[i] = new LineInfo(lines[i]); | |
316 } | |
317 renderer.lineCount = lineCount; | |
318 } | |
319 } | |
320 void dispose() { | |
321 if (boldFont !is null) boldFont.dispose(); | |
322 if (italicFont !is null) italicFont.dispose(); | |
323 if (boldItalicFont !is null) boldItalicFont.dispose(); | |
324 boldFont = italicFont = boldItalicFont = null; | |
325 reset(); | |
326 content = null; | |
327 device = null; | |
328 styledText = null; | |
329 } | |
330 void disposeTextLayout (TextLayout layout) { | |
331 if (layouts !is null) { | |
332 for (int i = 0; i < layouts.length; i++) { | |
333 if (layouts[i] is layout) return; | |
334 } | |
335 } | |
336 layout.dispose(); | |
337 } | |
338 void drawBullet(Bullet bullet, GC gc, int paintX, int paintY, int index, int lineAscent, int lineDescent) { | |
339 StyleRange style = bullet.style; | |
340 GlyphMetrics metrics = style.metrics; | |
341 Color color = style.foreground; | |
342 if (color !is null) gc.setForeground(color); | |
343 if ((bullet.type & ST.BULLET_DOT) !is 0 && StyledText.IS_MOTIF) { | |
344 int size = Math.max(4, (lineAscent + lineDescent) / 4); | |
345 if ((size & 1) is 0) size++; | |
346 if (color is null) { | |
347 Display display = styledText.getDisplay(); | |
348 color = display.getSystemColor(SWT.COLOR_BLACK); | |
349 } | |
350 gc.setBackground(color); | |
351 int x = paintX + Math.max(0, metrics.width - size - BULLET_MARGIN); | |
352 gc.fillArc(x, paintY + size, size + 1, size + 1, 0, 360); | |
353 return; | |
354 } | |
355 Font font = style.font; | |
356 if (font !is null) gc.setFont(font); | |
357 String string = ""; | |
358 int type = bullet.type & (ST.BULLET_DOT|ST.BULLET_NUMBER|ST.BULLET_LETTER_LOWER|ST.BULLET_LETTER_UPPER); | |
359 switch (type) { | |
360 case ST.BULLET_DOT: string = "\u2022"; break; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
361 case ST.BULLET_NUMBER: string = String_valueOf(index); break; |
25 | 362 case ST.BULLET_LETTER_LOWER: string = [cast(char) (index % 26 + 97)]; break; |
363 case ST.BULLET_LETTER_UPPER: string = [cast(char) (index % 26 + 65)]; break; | |
364 default: | |
365 } | |
366 if ((bullet.type & ST.BULLET_TEXT) !is 0) string ~= bullet.text; | |
367 Display display = styledText.getDisplay(); | |
368 TextLayout layout = new TextLayout(display); | |
369 layout.setText(string); | |
370 layout.setAscent(lineAscent); | |
371 layout.setDescent(lineDescent); | |
372 style = cast(StyleRange)style.clone(); | |
373 style.metrics = null; | |
374 if (style.font is null) style.font = getFont(style.fontStyle); | |
375 layout.setStyle(style, 0, string.length); | |
376 int x = paintX + Math.max(0, metrics.width - layout.getBounds().width - BULLET_MARGIN); | |
377 layout.draw(gc, x, paintY); | |
378 layout.dispose(); | |
379 } | |
380 int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackground, Color widgetForeground) { | |
381 TextLayout layout = getTextLayout(lineIndex); | |
382 String line = content.getLine(lineIndex); | |
383 int lineOffset = content.getOffsetAtLine(lineIndex); | |
384 int lineLength = line.length; | |
385 Point selection = styledText.getSelection(); | |
386 int selectionStart = selection.x - lineOffset; | |
387 int selectionEnd = selection.y - lineOffset; | |
388 Rectangle client = styledText.getClientArea(); | |
389 Color lineBackground = getLineBackground(lineIndex, null); | |
390 StyledTextEvent event = styledText.getLineBackgroundData(lineOffset, line); | |
391 if (event !is null && event.lineBackground !is null) lineBackground = event.lineBackground; | |
392 | |
393 int height = layout.getBounds().height; | |
394 if (lineBackground !is null) { | |
395 gc.setBackground(lineBackground); | |
396 gc.fillRectangle(client.x, paintY, client.width, height); | |
397 } else { | |
398 gc.setBackground(widgetBackground); | |
399 styledText.drawBackground(gc, client.x, paintY, client.width, height); | |
400 } | |
401 gc.setForeground(widgetForeground); | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
402 if (selectionStart is selectionEnd || (selectionEnd <= 0 && selectionStart >= lineLength)) { |
25 | 403 layout.draw(gc, paintX, paintY); |
404 } else { | |
405 int start = Math.max(0, selectionStart); | |
406 int end = Math.min(lineLength, selectionEnd); | |
407 Color selectionFg = styledText.getSelectionForeground(); | |
408 Color selectionBg = styledText.getSelectionBackground(); | |
409 int flags; | |
410 if ((styledText.getStyle() & SWT.FULL_SELECTION) !is 0) { | |
411 flags = SWT.FULL_SELECTION; | |
412 } else { | |
413 flags = SWT.DELIMITER_SELECTION; | |
414 } | |
415 if (selectionStart <= lineLength && lineLength < selectionEnd ) { | |
416 flags |= SWT.LAST_LINE_SELECTION; | |
417 } | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
418 layout.draw(gc, paintX, paintY, start, end > 0 ? line.offsetBefore(end) : end - 1, selectionFg, selectionBg, flags); |
25 | 419 } |
420 | |
421 // draw objects | |
422 Bullet bullet = null; | |
423 int bulletIndex = -1; | |
424 if (bullets !is null) { | |
425 if (bulletsIndices !is null) { | |
426 int index = lineIndex - topIndex; | |
427 if (0 <= index && index < CACHE_SIZE) { | |
428 bullet = bullets[index]; | |
429 bulletIndex = bulletsIndices[index]; | |
430 } | |
431 } else { | |
432 for (int i = 0; i < bullets.length; i++) { | |
433 bullet = bullets[i]; | |
434 bulletIndex = bullet.indexOf(lineIndex); | |
435 if (bulletIndex !is -1) break; | |
436 } | |
437 } | |
438 } | |
439 if (bulletIndex !is -1 && bullet !is null) { | |
440 FontMetrics metrics = layout.getLineMetrics(0); | |
441 int lineAscent = metrics.getAscent() + metrics.getLeading(); | |
442 if (bullet.type is ST.BULLET_CUSTOM) { | |
443 bullet.style.start = lineOffset; | |
444 styledText.paintObject(gc, paintX, paintY, lineAscent, metrics.getDescent(), bullet.style, bullet, bulletIndex); | |
445 } else { | |
446 drawBullet(bullet, gc, paintX, paintY, bulletIndex, lineAscent, metrics.getDescent()); | |
447 } | |
448 } | |
449 TextStyle[] styles = layout.getStyles(); | |
450 int[] ranges = null; | |
451 for (int i = 0; i < styles.length; i++) { | |
452 if (styles[i].metrics !is null) { | |
453 if (ranges is null) ranges = layout.getRanges(); | |
454 int start = ranges[i << 1]; | |
455 int length = ranges[(i << 1) + 1] - start; | |
456 Point point = layout.getLocation(start, false); | |
457 FontMetrics metrics = layout.getLineMetrics(layout.getLineIndex(start)); | |
458 StyleRange style = cast(StyleRange)(cast(StyleRange)styles[i]).clone(); | |
459 style.start = start + lineOffset; | |
460 style.length = length; | |
461 int lineAscent = metrics.getAscent() + metrics.getLeading(); | |
462 styledText.paintObject(gc, point.x + paintX, point.y + paintY, lineAscent, metrics.getDescent(), style, null, 0); | |
463 } | |
464 } | |
465 disposeTextLayout(layout); | |
466 return height; | |
467 } | |
468 int getBaseline() { | |
469 return ascent; | |
470 } | |
471 Font getFont(int style) { | |
472 switch (style) { | |
473 case SWT.BOLD: | |
474 if (boldFont !is null) return boldFont; | |
475 return boldFont = new Font(device, getFontData(style)); | |
476 case SWT.ITALIC: | |
477 if (italicFont !is null) return italicFont; | |
478 return italicFont = new Font(device, getFontData(style)); | |
479 case SWT.BOLD | SWT.ITALIC: | |
480 if (boldItalicFont !is null) return boldItalicFont; | |
481 return boldItalicFont = new Font(device, getFontData(style)); | |
482 default: | |
483 return regularFont; | |
484 } | |
485 } | |
486 FontData[] getFontData(int style) { | |
487 FontData[] fontDatas = regularFont.getFontData(); | |
488 for (int i = 0; i < fontDatas.length; i++) { | |
489 fontDatas[i].setStyle(style); | |
490 } | |
491 return fontDatas; | |
492 } | |
493 int getHeight () { | |
494 int defaultLineHeight = getLineHeight(); | |
495 if (styledText.isFixedLineHeight()) { | |
496 return lineCount * defaultLineHeight; | |
497 } | |
498 int totalHeight = 0; | |
499 int width = styledText.getWrapWidth(); | |
500 for (int i = 0; i < lineCount; i++) { | |
501 int height = lineHeight[i]; | |
502 if (height is -1) { | |
503 if (width > 0) { | |
504 int length = content.getLine(i).length; | |
505 height = ((length * averageCharWidth / width) + 1) * defaultLineHeight; | |
506 } else { | |
507 height = defaultLineHeight; | |
508 } | |
509 } | |
510 totalHeight += height; | |
511 } | |
512 return totalHeight + styledText.topMargin + styledText.bottomMargin; | |
513 } | |
514 int getLineAlignment(int index, int defaultAlignment) { | |
515 if (lines is null) return defaultAlignment; | |
516 LineInfo info = lines[index]; | |
517 if (info !is null && (info.flags & ALIGNMENT) !is 0) { | |
518 return info.alignment; | |
519 } | |
520 return defaultAlignment; | |
521 } | |
522 Color getLineBackground(int index, Color defaultBackground) { | |
523 if (lines is null) return defaultBackground; | |
524 LineInfo info = lines[index]; | |
525 if (info !is null && (info.flags & BACKGROUND) !is 0) { | |
526 return info.background; | |
527 } | |
528 return defaultBackground; | |
529 } | |
530 Bullet getLineBullet (int index, Bullet defaultBullet) { | |
531 if (bullets is null) return defaultBullet; | |
532 if (bulletsIndices !is null) return defaultBullet; | |
533 for (int i = 0; i < bullets.length; i++) { | |
534 Bullet bullet = bullets[i]; | |
535 if (bullet.indexOf(index) !is -1) return bullet; | |
536 } | |
537 return defaultBullet; | |
538 } | |
539 int getLineHeight() { | |
540 return ascent + descent; | |
541 } | |
542 int getLineHeight(int lineIndex) { | |
543 if (lineHeight[lineIndex] is -1) { | |
544 calculate(lineIndex, 1); | |
545 } | |
546 return lineHeight[lineIndex]; | |
547 } | |
548 int getLineIndent(int index, int defaultIndent) { | |
549 if (lines is null) return defaultIndent; | |
550 LineInfo info = lines[index]; | |
551 if (info !is null && (info.flags & INDENT) !is 0) { | |
552 return info.indent; | |
553 } | |
554 return defaultIndent; | |
555 } | |
556 bool getLineJustify(int index, bool defaultJustify) { | |
557 if (lines is null) return defaultJustify; | |
558 LineInfo info = lines[index]; | |
559 if (info !is null && (info.flags & JUSTIFY) !is 0) { | |
560 return info.justify; | |
561 } | |
562 return defaultJustify; | |
563 } | |
564 int[] getLineSegments(int index, int[] defaultSegments) { | |
565 if (lines is null) return defaultSegments; | |
566 LineInfo info = lines[index]; | |
567 if (info !is null && (info.flags & SEGMENTS) !is 0) { | |
568 return info.segments; | |
569 } | |
570 return defaultSegments; | |
571 } | |
572 int getRangeIndex(int offset, int low, int high) { | |
573 if (styleCount is 0) return 0; | |
574 if (ranges !is null) { | |
575 while (high - low > 2) { | |
576 int index = ((high + low) / 2) / 2 * 2; | |
577 int end = ranges[index] + ranges[index + 1]; | |
578 if (end > offset) { | |
579 high = index; | |
580 } else { | |
581 low = index; | |
582 } | |
583 } | |
584 } else { | |
585 while (high - low > 1) { | |
586 int index = ((high + low) / 2); | |
587 int end = styles[index].start + styles[index].length; | |
588 if (end > offset) { | |
589 high = index; | |
590 } else { | |
591 low = index; | |
592 } | |
593 } | |
594 } | |
595 return high; | |
596 } | |
597 int[] getRanges(int start, int length) { | |
598 int[] newRanges; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
599 int end = start + length - 1; //not a valid index, but OK |
25 | 600 if (ranges !is null) { |
601 int rangeCount = styleCount << 1; | |
602 int rangeStart = getRangeIndex(start, -1, rangeCount); | |
603 if (rangeStart >= rangeCount) return null; | |
604 if (ranges[rangeStart] > end) return null; | |
605 int rangeEnd = Math.min(rangeCount - 2, getRangeIndex(end, rangeStart - 1, rangeCount) + 1); | |
606 newRanges = new int[rangeEnd - rangeStart + 2]; | |
607 System.arraycopy(ranges, rangeStart, newRanges, 0, newRanges.length); | |
608 } else { | |
609 int rangeStart = getRangeIndex(start, -1, styleCount); | |
610 if (rangeStart >= styleCount) return null; | |
611 if (styles[rangeStart].start > end) return null; | |
612 int rangeEnd = Math.min(styleCount - 1, getRangeIndex(end, rangeStart - 1, styleCount)); | |
613 newRanges = new int[(rangeEnd - rangeStart + 1) << 1]; | |
614 for (int i = rangeStart, j = 0; i <= rangeEnd; i++, j += 2) { | |
615 StyleRange style = styles[i]; | |
616 newRanges[j] = style.start; | |
617 newRanges[j + 1] = style.length; | |
618 } | |
619 } | |
620 if (start > newRanges[0]) { | |
621 newRanges[1] = newRanges[0] + newRanges[1] - start; | |
622 newRanges[0] = start; | |
623 } | |
624 if (end < newRanges[newRanges.length - 2] + newRanges[newRanges.length - 1] - 1) { | |
625 newRanges[newRanges.length - 1] = end - newRanges[newRanges.length - 2] + 1; | |
626 } | |
627 return newRanges; | |
628 } | |
629 StyleRange[] getStyleRanges(int start, int length, bool includeRanges) { | |
630 StyleRange[] newStyles; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
631 int end = start + length - 1; //not a valid index, but OK |
25 | 632 if (ranges !is null) { |
633 int rangeCount = styleCount << 1; | |
634 int rangeStart = getRangeIndex(start, -1, rangeCount); | |
635 if (rangeStart >= rangeCount) return null; | |
636 if (ranges[rangeStart] > end) return null; | |
637 int rangeEnd = Math.min(rangeCount - 2, getRangeIndex(end, rangeStart - 1, rangeCount) + 1); | |
638 newStyles = new StyleRange[((rangeEnd - rangeStart) >> 1) + 1]; | |
639 if (includeRanges) { | |
640 for (int i = rangeStart, j = 0; i <= rangeEnd; i += 2, j++) { | |
641 newStyles[j] = cast(StyleRange)styles[i >> 1].clone(); | |
642 newStyles[j].start = ranges[i]; | |
643 newStyles[j].length = ranges[i + 1]; | |
644 } | |
645 } else { | |
646 System.arraycopy(styles, rangeStart >> 1, newStyles, 0, newStyles.length); | |
647 } | |
648 } else { | |
649 int rangeStart = getRangeIndex(start, -1, styleCount); | |
650 if (rangeStart >= styleCount) return null; | |
651 if (styles[rangeStart].start > end) return null; | |
652 int rangeEnd = Math.min(styleCount - 1, getRangeIndex(end, rangeStart - 1, styleCount)); | |
653 newStyles = new StyleRange[rangeEnd - rangeStart + 1]; | |
654 System.arraycopy(styles, rangeStart, newStyles, 0, newStyles.length); | |
655 } | |
656 StyleRange style = newStyles[0]; | |
657 if (start > style.start) { | |
658 if (!includeRanges || ranges is null) newStyles[0] = style = cast(StyleRange)style.clone(); | |
659 style.length = style.start + style.length - start; | |
660 style.start = start; | |
661 } | |
662 style = newStyles[newStyles.length - 1]; | |
663 if (end < style.start + style.length - 1) { | |
664 if (end < style.start) { | |
665 StyleRange[] tmp = new StyleRange[newStyles.length - 1]; | |
666 System.arraycopy(newStyles, 0, tmp, 0, newStyles.length - 1); | |
667 newStyles = tmp; | |
668 } else { | |
669 if (!includeRanges || ranges is null) newStyles[newStyles.length - 1] = style = cast(StyleRange)style.clone(); | |
670 style.length = end - style.start + 1; | |
671 } | |
672 } | |
673 return newStyles; | |
674 } | |
675 StyleRange getStyleRange(StyleRange style) { | |
676 if (style.start is 0 && style.length is 0 && style.fontStyle is SWT.NORMAL) return style; | |
677 StyleRange clone = cast(StyleRange)style.clone(); | |
678 clone.start = clone.length = 0; | |
679 clone.fontStyle = SWT.NORMAL; | |
680 if (clone.font is null) clone.font = getFont(style.fontStyle); | |
681 return clone; | |
682 } | |
683 TextLayout getTextLayout(int lineIndex) { | |
684 return getTextLayout(lineIndex, styledText.getOrientation(), styledText.getWrapWidth(), styledText.lineSpacing); | |
685 } | |
686 TextLayout getTextLayout(int lineIndex, int orientation, int width, int lineSpacing) { | |
687 TextLayout layout = null; | |
688 if (styledText !is null) { | |
689 int topIndex = styledText.topIndex > 0 ? styledText.topIndex - 1 : 0; | |
690 if (layouts is null || topIndex !is this.topIndex) { | |
691 TextLayout[] newLayouts = new TextLayout[CACHE_SIZE]; | |
692 if (layouts !is null) { | |
693 for (int i = 0; i < layouts.length; i++) { | |
694 if (layouts[i] !is null) { | |
695 int layoutIndex = (i + this.topIndex) - topIndex; | |
696 if (0 <= layoutIndex && layoutIndex < newLayouts.length) { | |
697 newLayouts[layoutIndex] = layouts[i]; | |
698 } else { | |
699 layouts[i].dispose(); | |
700 } | |
701 } | |
702 } | |
703 } | |
704 if (bullets !is null && bulletsIndices !is null && topIndex !is this.topIndex) { | |
705 int delta = topIndex - this.topIndex; | |
706 if (delta > 0) { | |
707 if (delta < bullets.length) { | |
708 System.arraycopy(bullets, delta, bullets, 0, bullets.length - delta); | |
709 System.arraycopy(bulletsIndices, delta, bulletsIndices, 0, bulletsIndices.length - delta); | |
710 } | |
711 int startIndex = Math.max(0, bullets.length - delta); | |
712 for (int i = startIndex; i < bullets.length; i++) bullets[i] = null; | |
713 } else { | |
714 if (-delta < bullets.length) { | |
715 System.arraycopy(bullets, 0, bullets, -delta, bullets.length + delta); | |
716 System.arraycopy(bulletsIndices, 0, bulletsIndices, -delta, bulletsIndices.length + delta); | |
717 } | |
718 int endIndex = Math.min(bullets.length, -delta); | |
719 for (int i = 0; i < endIndex; i++) bullets[i] = null; | |
720 } | |
721 } | |
722 this.topIndex = topIndex; | |
723 layouts = newLayouts; | |
724 } | |
725 if (layouts !is null) { | |
726 int layoutIndex = lineIndex - topIndex; | |
727 if (0 <= layoutIndex && layoutIndex < layouts.length) { | |
728 layout = layouts[layoutIndex]; | |
729 if (layout !is null) { | |
730 if (lineWidth[lineIndex] !is -1) return layout; | |
731 } else { | |
732 layout = layouts[layoutIndex] = new TextLayout(device); | |
733 } | |
734 } | |
735 } | |
736 } | |
737 if (layout is null) layout = new TextLayout(device); | |
738 String line = content.getLine(lineIndex); | |
739 int lineOffset = content.getOffsetAtLine(lineIndex); | |
740 int[] segments = null; | |
741 int indent = 0; | |
742 int alignment = SWT.LEFT; | |
743 bool justify = false; | |
744 Bullet bullet = null; | |
745 int[] ranges = null; | |
746 StyleRange[] styles = null; | |
747 int rangeStart = 0, styleCount = 0; | |
748 StyledTextEvent event = null; | |
749 if (styledText !is null) { | |
750 event = styledText.getLineStyleData(lineOffset, line); | |
751 segments = styledText.getBidiSegments(lineOffset, line); | |
752 indent = styledText.indent; | |
753 alignment = styledText.alignment; | |
754 justify = styledText.justify; | |
755 } | |
756 if (event !is null) { | |
757 indent = event.indent; | |
758 alignment = event.alignment; | |
759 justify = event.justify; | |
760 bullet = event.bullet; | |
761 ranges = event.ranges; | |
762 styles = event.styles; | |
763 if (styles !is null) { | |
764 styleCount = styles.length; | |
765 if (styledText.isFixedLineHeight()) { | |
766 for (int i = 0; i < styleCount; i++) { | |
767 if (styles[i].isVariableHeight()) { | |
768 styledText.verticalScrollOffset = -1; | |
769 styledText.setVariableLineHeight(); | |
770 styledText.redraw(); | |
771 break; | |
772 } | |
773 } | |
774 } | |
775 } | |
776 if (bullets is null || bulletsIndices is null) { | |
777 bullets = new Bullet[CACHE_SIZE]; | |
778 bulletsIndices = new int[CACHE_SIZE]; | |
779 } | |
780 int index = lineIndex - topIndex; | |
781 if (0 <= index && index < CACHE_SIZE) { | |
782 bullets[index] = bullet; | |
783 bulletsIndices[index] = event.bulletIndex; | |
784 } | |
785 } else { | |
786 if (lines !is null) { | |
787 LineInfo info = lines[lineIndex]; | |
788 if (info !is null) { | |
789 if ((info.flags & INDENT) !is 0) indent = info.indent; | |
790 if ((info.flags & ALIGNMENT) !is 0) alignment = info.alignment; | |
791 if ((info.flags & JUSTIFY) !is 0) justify = info.justify; | |
792 if ((info.flags & SEGMENTS) !is 0) segments = info.segments; | |
793 } | |
794 } | |
795 if (bulletsIndices !is null) { | |
796 bullets = null; | |
797 bulletsIndices = null; | |
798 } | |
799 if (bullets !is null) { | |
800 for (int i = 0; i < bullets.length; i++) { | |
801 if (bullets[i].indexOf(lineIndex) !is -1) { | |
802 bullet = bullets[i]; | |
803 break; | |
804 } | |
805 } | |
806 } | |
807 ranges = this.ranges; | |
808 styles = this.styles; | |
809 styleCount = this.styleCount; | |
810 if (ranges !is null) { | |
811 rangeStart = getRangeIndex(lineOffset, -1, styleCount << 1); | |
812 } else { | |
813 rangeStart = getRangeIndex(lineOffset, -1, styleCount); | |
814 } | |
815 } | |
816 if (bullet !is null) { | |
817 StyleRange style = bullet.style; | |
818 GlyphMetrics metrics = style.metrics; | |
819 indent += metrics.width; | |
820 } | |
821 layout.setFont(regularFont); | |
822 layout.setAscent(ascent); | |
823 layout.setDescent(descent); | |
824 layout.setText(line); | |
825 layout.setOrientation(orientation); | |
826 layout.setSegments(segments); | |
827 layout.setWidth(width); | |
828 layout.setSpacing(lineSpacing); | |
829 layout.setTabs([tabWidth]); | |
830 layout.setIndent(indent); | |
831 layout.setAlignment(alignment); | |
832 layout.setJustify(justify); | |
833 | |
834 int lastOffset = 0; | |
835 int length = line.length; | |
836 if (styles !is null) { | |
837 if (ranges !is null) { | |
838 int rangeCount = styleCount << 1; | |
839 for (int i = rangeStart; i < rangeCount; i += 2) { | |
840 int start, end; | |
841 if (lineOffset > ranges[i]) { | |
842 start = 0; | |
843 end = Math.min (length, ranges[i + 1] - lineOffset + ranges[i]); | |
844 } else { | |
845 start = ranges[i] - lineOffset; | |
846 end = Math.min(length, start + ranges[i + 1]); | |
847 } | |
848 if (start >= length) break; | |
849 if (lastOffset < start) { | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
850 layout.setStyle(null, lastOffset, line.offsetBefore(start)); |
25 | 851 } |
852 layout.setStyle(getStyleRange(styles[i >> 1]), start, end); | |
853 lastOffset = Math.max(lastOffset, end); | |
854 } | |
855 } else { | |
856 for (int i = rangeStart; i < styleCount; i++) { | |
857 int start, end; | |
858 if (lineOffset > styles[i].start) { | |
859 start = 0; | |
860 end = Math.min (length, styles[i].length - lineOffset + styles[i].start); | |
861 } else { | |
862 start = styles[i].start - lineOffset; | |
863 end = Math.min(length, start + styles[i].length); | |
864 } | |
865 if (start >= length) break; | |
866 if (lastOffset < start) { | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
867 layout.setStyle(null, lastOffset, line.offsetBefore(start)); |
25 | 868 } |
869 layout.setStyle(getStyleRange(styles[i]), start, end); | |
870 lastOffset = Math.max(lastOffset, end); | |
871 } | |
872 } | |
873 } | |
874 if (lastOffset < length) layout.setStyle(null, lastOffset, length); | |
875 if (styledText !is null && styledText.ime !is null) { | |
876 IME ime = styledText.ime; | |
877 int compositionOffset = ime.getCompositionOffset(); | |
878 if (compositionOffset !is -1) { | |
879 int commitCount = ime.getCommitCount(); | |
880 int compositionLength = ime.getText().length; | |
881 if (compositionLength !is commitCount) { | |
882 int compositionLine = content.getLineAtOffset(compositionOffset); | |
883 if (compositionLine is lineIndex) { | |
884 int[] imeRanges = ime.getRanges(); | |
885 TextStyle[] imeStyles = ime.getStyles(); | |
886 if (imeRanges.length > 0) { | |
887 for (int i = 0; i < imeStyles.length; i++) { | |
888 int start = imeRanges[i*2] - lineOffset; | |
889 int end = imeRanges[i*2+1] - lineOffset; | |
890 TextStyle imeStyle = imeStyles[i], userStyle; | |
891 for (int j = start; j <= end; j++) { | |
892 userStyle = layout.getStyle(j); | |
893 if (userStyle is null && j > 0) userStyle = layout.getStyle(j - 1); | |
894 if (userStyle is null && j + 1 < length) userStyle = layout.getStyle(j + 1); | |
895 if (userStyle is null) { | |
896 layout.setStyle(imeStyle, j, j); | |
897 } else { | |
898 TextStyle newStyle = new TextStyle(imeStyle); | |
899 if (newStyle.font is null) newStyle.font = userStyle.font; | |
900 if (newStyle.foreground is null) newStyle.foreground = userStyle.foreground; | |
901 if (newStyle.background is null) newStyle.background = userStyle.background; | |
902 layout.setStyle(newStyle, j, j); | |
903 } | |
904 } | |
905 } | |
906 } else { | |
907 int start = compositionOffset - lineOffset; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
908 int end = line.offsetBefore(start + compositionLength); |
25 | 909 TextStyle userStyle = layout.getStyle(start); |
910 if (userStyle is null) { | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
911 if (start > 0) userStyle = layout.getStyle(line.offsetBefore(start)); |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
912 if (userStyle is null && line.offsetAfter(end) < length) userStyle = layout.getStyle(line.offsetAfter(end)); |
25 | 913 if (userStyle !is null) { |
914 TextStyle newStyle = new TextStyle(); | |
915 newStyle.font = userStyle.font; | |
916 newStyle.foreground = userStyle.foreground; | |
917 newStyle.background = userStyle.background; | |
918 layout.setStyle(newStyle, start, end); | |
919 } | |
920 } | |
921 } | |
922 } | |
923 } | |
924 } | |
925 } | |
926 | |
927 if (styledText !is null && styledText.isFixedLineHeight()) { | |
928 int index = -1; | |
929 int lineCount = layout.getLineCount(); | |
930 int height = getLineHeight(); | |
931 for (int i = 0; i < lineCount; i++) { | |
932 int lineHeight = layout.getLineBounds(i).height; | |
933 if (lineHeight > height) { | |
934 height = lineHeight; | |
935 index = i; | |
936 } | |
937 } | |
938 if (index !is -1) { | |
939 FontMetrics metrics = layout.getLineMetrics(index); | |
940 ascent = metrics.getAscent() + metrics.getLeading(); | |
941 descent = metrics.getDescent(); | |
942 if (layouts !is null) { | |
943 for (int i = 0; i < layouts.length; i++) { | |
944 if (layouts[i] !is null && layouts[i] !is layout) { | |
945 layouts[i].setAscent(ascent); | |
946 layouts[i].setDescent(descent); | |
947 } | |
948 } | |
949 } | |
950 if (styledText.verticalScrollOffset !is 0) { | |
951 int topIndex = styledText.topIndex; | |
952 int topIndexY = styledText.topIndexY; | |
953 int lineHeight = getLineHeight(); | |
954 if (topIndexY >= 0) { | |
955 styledText.verticalScrollOffset = (topIndex - 1) * lineHeight + lineHeight - topIndexY; | |
956 } else { | |
957 styledText.verticalScrollOffset = topIndex * lineHeight - topIndexY; | |
958 } | |
959 } | |
960 styledText.calculateScrollBars(); | |
961 if (styledText.isBidiCaret()) styledText.createCaretBitmaps(); | |
962 styledText.caretDirection = SWT.NULL; | |
963 styledText.setCaretLocation(); | |
964 styledText.redraw(); | |
965 } | |
966 } | |
967 return layout; | |
968 } | |
969 int getWidth() { | |
970 return maxWidth; | |
971 } | |
972 void reset() { | |
973 if (layouts !is null) { | |
974 for (int i = 0; i < layouts.length; i++) { | |
975 TextLayout layout = layouts[i]; | |
976 if (layout !is null) layout.dispose(); | |
977 } | |
978 layouts = null; | |
979 } | |
980 topIndex = -1; | |
981 stylesSetCount = styleCount = lineCount = 0; | |
982 ranges = null; | |
983 styles = null; | |
984 stylesSet = null; | |
985 lines = null; | |
986 lineWidth = null; | |
987 lineHeight = null; | |
988 bullets = null; | |
989 bulletsIndices = null; | |
990 redrawLines = null; | |
991 } | |
992 void reset(int startLine, int lineCount) { | |
993 int endLine = startLine + lineCount; | |
994 if (startLine < 0 || endLine > lineWidth.length) return; | |
995 for (int i = startLine; i < endLine; i++) { | |
996 lineWidth[i] = -1; | |
997 lineHeight[i] = -1; | |
998 } | |
999 if (startLine <= maxWidthLineIndex && maxWidthLineIndex < endLine) { | |
1000 maxWidth = 0; | |
1001 maxWidthLineIndex = -1; | |
1002 if (lineCount !is this.lineCount) { | |
1003 for (int i = 0; i < this.lineCount; i++) { | |
1004 if (lineWidth[i] > maxWidth) { | |
1005 maxWidth = lineWidth[i]; | |
1006 maxWidthLineIndex = i; | |
1007 } | |
1008 } | |
1009 } | |
1010 } | |
1011 } | |
1012 void setContent(StyledTextContent content) { | |
1013 reset(); | |
1014 this.content = content; | |
1015 lineCount = content.getLineCount(); | |
1016 lineWidth = new int[lineCount]; | |
1017 lineHeight = new int[lineCount]; | |
1018 reset(0, lineCount); | |
1019 } | |
1020 void setFont(Font font, int tabs) { | |
1021 TextLayout layout = new TextLayout(device); | |
1022 layout.setFont(regularFont); | |
1023 if (font !is null) { | |
1024 if (boldFont !is null) boldFont.dispose(); | |
1025 if (italicFont !is null) italicFont.dispose(); | |
1026 if (boldItalicFont !is null) boldItalicFont.dispose(); | |
1027 boldFont = italicFont = boldItalicFont = null; | |
1028 regularFont = font; | |
1029 layout.setText(" "); | |
1030 layout.setFont(font); | |
1031 layout.setStyle(new TextStyle(getFont(SWT.NORMAL), null, null), 0, 0); | |
1032 layout.setStyle(new TextStyle(getFont(SWT.BOLD), null, null), 1, 1); | |
1033 layout.setStyle(new TextStyle(getFont(SWT.ITALIC), null, null), 2, 2); | |
1034 layout.setStyle(new TextStyle(getFont(SWT.BOLD | SWT.ITALIC), null, null), 3, 3); | |
1035 FontMetrics metrics = layout.getLineMetrics(0); | |
1036 ascent = metrics.getAscent() + metrics.getLeading(); | |
1037 descent = metrics.getDescent(); | |
1038 boldFont.dispose(); | |
1039 italicFont.dispose(); | |
1040 boldItalicFont.dispose(); | |
1041 boldFont = italicFont = boldItalicFont = null; | |
1042 } | |
1043 layout.dispose(); | |
1044 layout = new TextLayout(device); | |
1045 layout.setFont(regularFont); | |
1046 StringBuffer tabBuffer = new StringBuffer(tabs); | |
1047 for (int i = 0; i < tabs; i++) { | |
1048 tabBuffer.append(' '); | |
1049 } | |
1050 layout.setText(tabBuffer.toString()); | |
1051 tabWidth = layout.getBounds().width; | |
1052 layout.dispose(); | |
1053 if (styledText !is null) { | |
1054 GC gc = new GC(styledText); | |
1055 averageCharWidth = gc.getFontMetrics().getAverageCharWidth(); | |
1056 gc.dispose(); | |
1057 } | |
1058 } | |
1059 void setLineAlignment(int startLine, int count, int alignment) { | |
1060 if (lines is null) lines = new LineInfo[lineCount]; | |
1061 for (int i = startLine; i < startLine + count; i++) { | |
1062 if (lines[i] is null) { | |
1063 lines[i] = new LineInfo(); | |
1064 } | |
1065 lines[i].flags |= ALIGNMENT; | |
1066 lines[i].alignment = alignment; | |
1067 } | |
1068 } | |
1069 void setLineBackground(int startLine, int count, Color background) { | |
1070 if (lines is null) lines = new LineInfo[lineCount]; | |
1071 for (int i = startLine; i < startLine + count; i++) { | |
1072 if (lines[i] is null) { | |
1073 lines[i] = new LineInfo(); | |
1074 } | |
1075 lines[i].flags |= BACKGROUND; | |
1076 lines[i].background = background; | |
1077 } | |
1078 } | |
1079 void setLineBullet(int startLine, int count, Bullet bullet) { | |
1080 if (bulletsIndices !is null) { | |
1081 bulletsIndices = null; | |
1082 bullets = null; | |
1083 } | |
1084 if (bullets is null) { | |
1085 if (bullet is null) return; | |
1086 bullets = new Bullet[1]; | |
1087 bullets[0] = bullet; | |
1088 } | |
1089 int index = 0; | |
1090 while (index < bullets.length) { | |
1091 if (bullet is bullets[index]) break; | |
1092 index++; | |
1093 } | |
1094 if (bullet !is null) { | |
1095 if (index is bullets.length) { | |
1096 Bullet[] newBulletsList = new Bullet[bullets.length + 1]; | |
1097 System.arraycopy(bullets, 0, newBulletsList, 0, bullets.length); | |
1098 newBulletsList[index] = bullet; | |
1099 bullets = newBulletsList; | |
1100 } | |
1101 bullet.addIndices(startLine, count); | |
1102 } else { | |
1103 updateBullets(startLine, count, 0, false); | |
1104 styledText.redrawLinesBullet(redrawLines); | |
1105 redrawLines = null; | |
1106 } | |
1107 } | |
1108 void setLineIndent(int startLine, int count, int indent) { | |
1109 if (lines is null) lines = new LineInfo[lineCount]; | |
1110 for (int i = startLine; i < startLine + count; i++) { | |
1111 if (lines[i] is null) { | |
1112 lines[i] = new LineInfo(); | |
1113 } | |
1114 lines[i].flags |= INDENT; | |
1115 lines[i].indent = indent; | |
1116 } | |
1117 } | |
1118 void setLineJustify(int startLine, int count, bool justify) { | |
1119 if (lines is null) lines = new LineInfo[lineCount]; | |
1120 for (int i = startLine; i < startLine + count; i++) { | |
1121 if (lines[i] is null) { | |
1122 lines[i] = new LineInfo(); | |
1123 } | |
1124 lines[i].flags |= JUSTIFY; | |
1125 lines[i].justify = justify; | |
1126 } | |
1127 } | |
1128 void setLineSegments(int startLine, int count, int[] segments) { | |
1129 if (lines is null) lines = new LineInfo[lineCount]; | |
1130 for (int i = startLine; i < startLine + count; i++) { | |
1131 if (lines[i] is null) { | |
1132 lines[i] = new LineInfo(); | |
1133 } | |
1134 lines[i].flags |= SEGMENTS; | |
1135 lines[i].segments = segments; | |
1136 } | |
1137 } | |
1138 void setStyleRanges (int[] newRanges, StyleRange[] newStyles) { | |
1139 if (newStyles is null) { | |
1140 stylesSetCount = styleCount = 0; | |
1141 ranges = null; | |
1142 styles = null; | |
1143 stylesSet = null; | |
1144 return; | |
1145 } | |
1146 if (newRanges is null && COMPACT_STYLES) { | |
1147 newRanges = new int[newStyles.length << 1]; | |
1148 StyleRange[] tmpStyles = new StyleRange[newStyles.length]; | |
1149 if (stylesSet is null) stylesSet = new StyleRange[4]; | |
1150 for (int i = 0, j = 0; i < newStyles.length; i++) { | |
1151 StyleRange newStyle = newStyles[i]; | |
1152 newRanges[j++] = newStyle.start; | |
1153 newRanges[j++] = newStyle.length; | |
1154 int index = 0; | |
1155 while (index < stylesSetCount) { | |
1156 if (stylesSet[index].similarTo(newStyle)) break; | |
1157 index++; | |
1158 } | |
1159 if (index is stylesSetCount) { | |
1160 if (stylesSetCount is stylesSet.length) { | |
1161 StyleRange[] tmpStylesSet = new StyleRange[stylesSetCount + 4]; | |
1162 System.arraycopy(stylesSet, 0, tmpStylesSet, 0, stylesSetCount); | |
1163 stylesSet = tmpStylesSet; | |
1164 } | |
1165 stylesSet[stylesSetCount++] = newStyle; | |
1166 } | |
1167 tmpStyles[i] = stylesSet[index]; | |
1168 } | |
1169 newStyles = tmpStyles; | |
1170 } | |
1171 | |
1172 if (styleCount is 0) { | |
1173 if (newRanges !is null) { | |
1174 ranges = new int[newRanges.length]; | |
1175 System.arraycopy(newRanges, 0, ranges, 0, ranges.length); | |
1176 } | |
1177 styles = new StyleRange[newStyles.length]; | |
1178 System.arraycopy(newStyles, 0, styles, 0, styles.length); | |
1179 styleCount = newStyles.length; | |
1180 return; | |
1181 } | |
1182 if (newRanges !is null && ranges is null) { | |
1183 ranges = new int[styles.length << 1]; | |
1184 for (int i = 0, j = 0; i < styleCount; i++) { | |
1185 ranges[j++] = styles[i].start; | |
1186 ranges[j++] = styles[i].length; | |
1187 } | |
1188 } | |
1189 if (newRanges is null && ranges !is null) { | |
1190 newRanges = new int[newStyles.length << 1]; | |
1191 for (int i = 0, j = 0; i < newStyles.length; i++) { | |
1192 newRanges[j++] = newStyles[i].start; | |
1193 newRanges[j++] = newStyles[i].length; | |
1194 } | |
1195 } | |
1196 if (ranges !is null) { | |
1197 int rangeCount = styleCount << 1; | |
1198 int start = newRanges[0]; | |
1199 int modifyStart = getRangeIndex(start, -1, rangeCount), modifyEnd; | |
1200 bool insert = modifyStart is rangeCount; | |
1201 if (!insert) { | |
1202 int end = newRanges[newRanges.length - 2] + newRanges[newRanges.length - 1]; | |
1203 modifyEnd = getRangeIndex(end, modifyStart - 1, rangeCount); | |
1204 insert = modifyStart is modifyEnd && ranges[modifyStart] >= end; | |
1205 } | |
1206 if (insert) { | |
1207 addMerge(newRanges, newStyles, newRanges.length, modifyStart, modifyStart); | |
1208 return; | |
1209 } | |
1210 modifyEnd = modifyStart; | |
1211 int[] mergeRanges = new int[6]; | |
1212 StyleRange[] mergeStyles = new StyleRange[3]; | |
1213 for (int i = 0; i < newRanges.length; i += 2) { | |
1214 int newStart = newRanges[i]; | |
1215 int newEnd = newStart + newRanges[i + 1]; | |
1216 if (newStart is newEnd) continue; | |
1217 int modifyLast = 0, mergeCount = 0; | |
1218 while (modifyEnd < rangeCount) { | |
1219 if (newStart >= ranges[modifyStart] + ranges[modifyStart + 1]) modifyStart += 2; | |
1220 if (ranges[modifyEnd] + ranges[modifyEnd + 1] > newEnd) break; | |
1221 modifyEnd += 2; | |
1222 } | |
1223 if (ranges[modifyStart] < newStart && newStart < ranges[modifyStart] + ranges[modifyStart + 1]) { | |
1224 mergeStyles[mergeCount >> 1] = styles[modifyStart >> 1]; | |
1225 mergeRanges[mergeCount] = ranges[modifyStart]; | |
1226 mergeRanges[mergeCount + 1] = newStart - ranges[modifyStart]; | |
1227 mergeCount += 2; | |
1228 } | |
1229 mergeStyles[mergeCount >> 1] = newStyles[i >> 1]; | |
1230 mergeRanges[mergeCount] = newStart; | |
1231 mergeRanges[mergeCount + 1] = newRanges[i + 1]; | |
1232 mergeCount += 2; | |
1233 if (modifyEnd < rangeCount && ranges[modifyEnd] < newEnd && newEnd < ranges[modifyEnd] + ranges[modifyEnd + 1]) { | |
1234 mergeStyles[mergeCount >> 1] = styles[modifyEnd >> 1]; | |
1235 mergeRanges[mergeCount] = newEnd; | |
1236 mergeRanges[mergeCount + 1] = ranges[modifyEnd] + ranges[modifyEnd + 1] - newEnd; | |
1237 mergeCount += 2; | |
1238 modifyLast = 2; | |
1239 } | |
1240 int grow = addMerge(mergeRanges, mergeStyles, mergeCount, modifyStart, modifyEnd + modifyLast); | |
1241 rangeCount += grow; | |
1242 modifyStart = modifyEnd += grow; | |
1243 } | |
1244 } else { | |
1245 int start = newStyles[0].start; | |
1246 int modifyStart = getRangeIndex(start, -1, styleCount), modifyEnd; | |
1247 bool insert = modifyStart is styleCount; | |
1248 if (!insert) { | |
1249 int end = newStyles[newStyles.length - 1].start + newStyles[newStyles.length - 1].length; | |
1250 modifyEnd = getRangeIndex(end, modifyStart - 1, styleCount); | |
1251 insert = modifyStart is modifyEnd && styles[modifyStart].start >= end; | |
1252 } | |
1253 if (insert) { | |
1254 addMerge(newStyles, newStyles.length, modifyStart, modifyStart); | |
1255 return; | |
1256 } | |
1257 modifyEnd = modifyStart; | |
1258 StyleRange[] mergeStyles = new StyleRange[3]; | |
1259 for (int i = 0; i < newStyles.length; i++) { | |
1260 StyleRange newStyle = newStyles[i], style; | |
1261 int newStart = newStyle.start; | |
1262 int newEnd = newStart + newStyle.length; | |
1263 if (newStart is newEnd) continue; | |
1264 int modifyLast = 0, mergeCount = 0; | |
1265 while (modifyEnd < styleCount) { | |
1266 if (newStart >= styles[modifyStart].start + styles[modifyStart].length) modifyStart++; | |
1267 if (styles[modifyEnd].start + styles[modifyEnd].length > newEnd) break; | |
1268 modifyEnd++; | |
1269 } | |
1270 style = styles[modifyStart]; | |
1271 if (style.start < newStart && newStart < style.start + style.length) { | |
1272 style = mergeStyles[mergeCount++] = cast(StyleRange)style.clone(); | |
1273 style.length = newStart - style.start; | |
1274 } | |
1275 mergeStyles[mergeCount++] = newStyle; | |
1276 if (modifyEnd < styleCount) { | |
1277 style = styles[modifyEnd]; | |
1278 if (style.start < newEnd && newEnd < style.start + style.length) { | |
1279 style = mergeStyles[mergeCount++] = cast(StyleRange)style.clone(); | |
1280 style.length += style.start - newEnd; | |
1281 style.start = newEnd; | |
1282 modifyLast = 1; | |
1283 } | |
1284 } | |
1285 int grow = addMerge(mergeStyles, mergeCount, modifyStart, modifyEnd + modifyLast); | |
1286 modifyStart = modifyEnd += grow; | |
1287 } | |
1288 } | |
1289 } | |
1290 void textChanging(TextChangingEvent event) { | |
1291 int start = event.start; | |
1292 int newCharCount = event.newCharCount, replaceCharCount = event.replaceCharCount; | |
1293 int newLineCount = event.newLineCount, replaceLineCount = event.replaceLineCount; | |
1294 | |
1295 updateRanges(start, replaceCharCount, newCharCount); | |
1296 | |
1297 int startLine = content.getLineAtOffset(start); | |
1298 if (replaceCharCount is content.getCharCount()) lines = null; | |
1299 if (replaceLineCount is lineCount) { | |
1300 lineCount = newLineCount; | |
1301 lineWidth = new int[lineCount]; | |
1302 lineHeight = new int[lineCount]; | |
1303 reset(0, lineCount); | |
1304 } else { | |
1305 int delta = newLineCount - replaceLineCount; | |
1306 if (lineCount + delta > lineWidth.length) { | |
1307 int[] newWidths = new int[lineCount + delta + GROW]; | |
1308 System.arraycopy(lineWidth, 0, newWidths, 0, lineCount); | |
1309 lineWidth = newWidths; | |
1310 int[] newHeights = new int[lineCount + delta + GROW]; | |
1311 System.arraycopy(lineHeight, 0, newHeights, 0, lineCount); | |
1312 lineHeight = newHeights; | |
1313 } | |
1314 if (lines !is null) { | |
1315 if (lineCount + delta > lines.length) { | |
1316 LineInfo[] newLines = new LineInfo[lineCount + delta + GROW]; | |
1317 System.arraycopy(lines, 0, newLines, 0, lineCount); | |
1318 lines = newLines; | |
1319 } | |
1320 } | |
1321 int startIndex = startLine + replaceLineCount + 1; | |
1322 int endIndex = startLine + newLineCount + 1; | |
1323 System.arraycopy(lineWidth, startIndex, lineWidth, endIndex, lineCount - startIndex); | |
1324 System.arraycopy(lineHeight, startIndex, lineHeight, endIndex, lineCount - startIndex); | |
1325 for (int i = startLine; i < endIndex; i++) { | |
1326 lineWidth[i] = lineHeight[i] = -1; | |
1327 } | |
1328 for (int i = lineCount + delta; i < lineCount; i++) { | |
1329 lineWidth[i] = lineHeight[i] = -1; | |
1330 } | |
1331 if (layouts !is null) { | |
1332 int layoutStartLine = startLine - topIndex; | |
1333 int layoutEndLine = layoutStartLine + replaceLineCount + 1; | |
1334 for (int i = layoutStartLine; i < layoutEndLine; i++) { | |
1335 if (0 <= i && i < layouts.length) { | |
1336 if (layouts[i] !is null) layouts[i].dispose(); | |
1337 layouts[i] = null; | |
1338 if (bullets !is null && bulletsIndices !is null) bullets[i] = null; | |
1339 } | |
1340 } | |
1341 if (delta > 0) { | |
1342 for (int i = layouts.length - 1; i >= layoutEndLine; i--) { | |
1343 if (0 <= i && i < layouts.length) { | |
1344 endIndex = i + delta; | |
1345 if (0 <= endIndex && endIndex < layouts.length) { | |
1346 layouts[endIndex] = layouts[i]; | |
1347 layouts[i] = null; | |
1348 if (bullets !is null && bulletsIndices !is null) { | |
1349 bullets[endIndex] = bullets[i]; | |
1350 bulletsIndices[endIndex] = bulletsIndices[i]; | |
1351 bullets[i] = null; | |
1352 } | |
1353 } else { | |
1354 if (layouts[i] !is null) layouts[i].dispose(); | |
1355 layouts[i] = null; | |
1356 if (bullets !is null && bulletsIndices !is null) bullets[i] = null; | |
1357 } | |
1358 } | |
1359 } | |
1360 } else if (delta < 0) { | |
1361 for (int i = layoutEndLine; i < layouts.length; i++) { | |
1362 if (0 <= i && i < layouts.length) { | |
1363 endIndex = i + delta; | |
1364 if (0 <= endIndex && endIndex < layouts.length) { | |
1365 layouts[endIndex] = layouts[i]; | |
1366 layouts[i] = null; | |
1367 if (bullets !is null && bulletsIndices !is null) { | |
1368 bullets[endIndex] = bullets[i]; | |
1369 bulletsIndices[endIndex] = bulletsIndices[i]; | |
1370 bullets[i] = null; | |
1371 } | |
1372 } else { | |
1373 if (layouts[i] !is null) layouts[i].dispose(); | |
1374 layouts[i] = null; | |
1375 if (bullets !is null && bulletsIndices !is null) bullets[i] = null; | |
1376 } | |
1377 } | |
1378 } | |
1379 } | |
1380 } | |
1381 if (replaceLineCount !is 0 || newLineCount !is 0) { | |
1382 int startLineOffset = content.getOffsetAtLine(startLine); | |
1383 if (startLineOffset !is start) startLine++; | |
1384 updateBullets(startLine, replaceLineCount, newLineCount, true); | |
1385 if (lines !is null) { | |
1386 startIndex = startLine + replaceLineCount; | |
1387 endIndex = startLine + newLineCount; | |
1388 System.arraycopy(lines, startIndex, lines, endIndex, lineCount - startIndex); | |
1389 for (int i = startLine; i < endIndex; i++) { | |
1390 lines[i] = null; | |
1391 } | |
1392 for (int i = lineCount + delta; i < lineCount; i++) { | |
1393 lines[i] = null; | |
1394 } | |
1395 } | |
1396 } | |
1397 lineCount += delta; | |
1398 if (maxWidthLineIndex !is -1 && startLine <= maxWidthLineIndex && maxWidthLineIndex <= startLine + replaceLineCount) { | |
1399 maxWidth = 0; | |
1400 maxWidthLineIndex = -1; | |
1401 for (int i = 0; i < lineCount; i++) { | |
1402 if (lineWidth[i] > maxWidth) { | |
1403 maxWidth = lineWidth[i]; | |
1404 maxWidthLineIndex = i; | |
1405 } | |
1406 } | |
1407 } | |
1408 } | |
1409 } | |
1410 void updateBullets(int startLine, int replaceLineCount, int newLineCount, bool update) { | |
1411 if (bullets is null) return; | |
1412 if (bulletsIndices !is null) return; | |
1413 for (int i = 0; i < bullets.length; i++) { | |
1414 Bullet bullet = bullets[i]; | |
1415 int[] lines = bullet.removeIndices(startLine, replaceLineCount, newLineCount, update); | |
1416 if (lines !is null) { | |
1417 if (redrawLines is null) { | |
1418 redrawLines = lines; | |
1419 } else { | |
1420 int[] newRedrawBullets = new int[redrawLines.length + lines.length]; | |
1421 System.arraycopy(redrawLines, 0, newRedrawBullets, 0, redrawLines.length); | |
1422 System.arraycopy(lines, 0, newRedrawBullets, redrawLines.length, lines.length); | |
1423 redrawLines = newRedrawBullets; | |
1424 } | |
1425 } | |
1426 } | |
1427 int removed = 0; | |
1428 for (int i = 0; i < bullets.length; i++) { | |
1429 if (bullets[i].size() is 0) removed++; | |
1430 } | |
1431 if (removed > 0) { | |
1432 if (removed is bullets.length) { | |
1433 bullets = null; | |
1434 } else { | |
1435 Bullet[] newBulletsList = new Bullet[bullets.length - removed]; | |
1436 for (int i = 0, j = 0; i < bullets.length; i++) { | |
1437 Bullet bullet = bullets[i]; | |
1438 if (bullet.size() > 0) newBulletsList[j++] = bullet; | |
1439 } | |
1440 bullets = newBulletsList; | |
1441 } | |
1442 } | |
1443 } | |
1444 void updateRanges(int start, int replaceCharCount, int newCharCount) { | |
1445 if (styleCount is 0 || (replaceCharCount is 0 && newCharCount is 0)) return; | |
1446 if (ranges !is null) { | |
1447 int rangeCount = styleCount << 1; | |
1448 int modifyStart = getRangeIndex(start, -1, rangeCount); | |
1449 if (modifyStart is rangeCount) return; | |
1450 int end = start + replaceCharCount; | |
1451 int modifyEnd = getRangeIndex(end, modifyStart - 1, rangeCount); | |
1452 int offset = newCharCount - replaceCharCount; | |
1453 if (modifyStart is modifyEnd && ranges[modifyStart] < start && end < ranges[modifyEnd] + ranges[modifyEnd + 1]) { | |
1454 if (newCharCount is 0) { | |
1455 ranges[modifyStart + 1] -= replaceCharCount; | |
1456 modifyEnd += 2; | |
1457 } else { | |
1458 if (rangeCount + 2 > ranges.length) { | |
1459 int[] newRanges = new int[ranges.length + (GROW << 1)]; | |
1460 System.arraycopy(ranges, 0, newRanges, 0, rangeCount); | |
1461 ranges = newRanges; | |
1462 StyleRange[] newStyles = new StyleRange[styles.length + GROW]; | |
1463 System.arraycopy(styles, 0, newStyles, 0, styleCount); | |
1464 styles = newStyles; | |
1465 } | |
1466 System.arraycopy(ranges, modifyStart + 2, ranges, modifyStart + 4, rangeCount - (modifyStart + 2)); | |
1467 System.arraycopy(styles, (modifyStart + 2) >> 1, styles, (modifyStart + 4) >> 1, styleCount - ((modifyStart + 2) >> 1)); | |
1468 ranges[modifyStart + 3] = ranges[modifyStart] + ranges[modifyStart + 1] - end; | |
1469 ranges[modifyStart + 2] = start + newCharCount; | |
1470 ranges[modifyStart + 1] = start - ranges[modifyStart]; | |
1471 styles[(modifyStart >> 1) + 1] = styles[modifyStart >> 1]; | |
1472 rangeCount += 2; | |
1473 styleCount++; | |
1474 modifyEnd += 4; | |
1475 } | |
1476 if (offset !is 0) { | |
1477 for (int i = modifyEnd; i < rangeCount; i += 2) { | |
1478 ranges[i] += offset; | |
1479 } | |
1480 } | |
1481 } else { | |
1482 if (ranges[modifyStart] < start && start < ranges[modifyStart] + ranges[modifyStart + 1]) { | |
1483 ranges[modifyStart + 1] = start - ranges[modifyStart]; | |
1484 modifyStart += 2; | |
1485 } | |
1486 if (modifyEnd < rangeCount && ranges[modifyEnd] < end && end < ranges[modifyEnd] + ranges[modifyEnd + 1]) { | |
1487 ranges[modifyEnd + 1] = ranges[modifyEnd] + ranges[modifyEnd + 1] - end; | |
1488 ranges[modifyEnd] = end; | |
1489 } | |
1490 if (offset !is 0) { | |
1491 for (int i = modifyEnd; i < rangeCount; i += 2) { | |
1492 ranges[i] += offset; | |
1493 } | |
1494 } | |
1495 System.arraycopy(ranges, modifyEnd, ranges, modifyStart, rangeCount - modifyEnd); | |
1496 System.arraycopy(styles, modifyEnd >> 1, styles, modifyStart >> 1, styleCount - (modifyEnd >> 1)); | |
1497 styleCount -= (modifyEnd - modifyStart) >> 1; | |
1498 } | |
1499 } else { | |
1500 int modifyStart = getRangeIndex(start, -1, styleCount); | |
1501 if (modifyStart is styleCount) return; | |
1502 int end = start + replaceCharCount; | |
1503 int modifyEnd = getRangeIndex(end, modifyStart - 1, styleCount); | |
1504 int offset = newCharCount - replaceCharCount; | |
1505 if (modifyStart is modifyEnd && styles[modifyStart].start < start && end < styles[modifyEnd].start + styles[modifyEnd].length) { | |
1506 if (newCharCount is 0) { | |
1507 styles[modifyStart].length -= replaceCharCount; | |
1508 modifyEnd++; | |
1509 } else { | |
1510 if (styleCount + 1 > styles.length) { | |
1511 StyleRange[] newStyles = new StyleRange[styles.length + GROW]; | |
1512 System.arraycopy(styles, 0, newStyles, 0, styleCount); | |
1513 styles = newStyles; | |
1514 } | |
1515 System.arraycopy(styles, modifyStart + 1, styles, modifyStart + 2, styleCount - (modifyStart + 1)); | |
1516 styles[modifyStart + 1] = cast(StyleRange)styles[modifyStart].clone(); | |
1517 styles[modifyStart + 1].length = styles[modifyStart].start + styles[modifyStart].length - end; | |
1518 styles[modifyStart + 1].start = start + newCharCount; | |
1519 styles[modifyStart].length = start - styles[modifyStart].start; | |
1520 styleCount++; | |
1521 modifyEnd += 2; | |
1522 } | |
1523 if (offset !is 0) { | |
1524 for (int i = modifyEnd; i < styleCount; i++) { | |
1525 styles[i].start += offset; | |
1526 } | |
1527 } | |
1528 } else { | |
1529 if (styles[modifyStart].start < start && start < styles[modifyStart].start + styles[modifyStart].length) { | |
1530 styles[modifyStart].length = start - styles[modifyStart].start; | |
1531 modifyStart++; | |
1532 } | |
1533 if (modifyEnd < styleCount && styles[modifyEnd].start < end && end < styles[modifyEnd].start + styles[modifyEnd].length) { | |
1534 styles[modifyEnd].length = styles[modifyEnd].start + styles[modifyEnd].length - end; | |
1535 styles[modifyEnd].start = end; | |
1536 } | |
1537 if (offset !is 0) { | |
1538 for (int i = modifyEnd; i < styleCount; i++) { | |
1539 styles[i].start += offset; | |
1540 } | |
1541 } | |
1542 System.arraycopy(styles, modifyEnd, styles, modifyStart, styleCount - modifyEnd); | |
1543 styleCount -= modifyEnd - modifyStart; | |
1544 } | |
1545 } | |
1546 } | |
1547 } |