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