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