Mercurial > projects > dwt-mac
comparison dwt/graphics/TextLayout.d @ 45:d8635bb48c7c
Merge with SWT 3.5
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 01 Dec 2008 17:07:00 +0100 |
parents | 642f460a0908 |
children | cfa563df4fdd |
comparison
equal
deleted
inserted
replaced
44:ca5e494f2bbf | 45:d8635bb48c7c |
---|---|
1 /******************************************************************************* | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 IBM Corporation and others. | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
3 * All rights reserved. This program and the accompanying materials | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | 4 * are made available under the terms of the Eclipse Public License v1.0 |
5 * which accompanies this distribution, and is available at | 5 * which accompanies this distribution, and is available at |
6 * http://www.eclipse.org/legal/epl-v10.html | 6 * http://www.eclipse.org/legal/epl-v10.html |
7 * | 7 * |
8 * Contributors: | 8 * Contributors: |
9 * IBM Corporation - initial API and implementation | 9 * IBM Corporation - initial API and implementation |
10 * | 10 * |
11 * Port to the D programming language: | 11 * Port to the D programming language: |
12 * Jacob Carlborg <jacob.carlborg@gmail.com> | 12 * Jacob Carlborg <doob@me.com> |
13 *******************************************************************************/ | 13 *******************************************************************************/ |
14 module dwt.graphics.TextLayout; | 14 module dwt.graphics.TextLayout; |
15 | 15 |
16 import dwt.DWT; | 16 import dwt.DWT; |
17 import dwt.DWTException; | 17 import dwt.DWTException; |
18 import dwt.internal.Compatibility; | |
19 import dwt.internal.cocoa.NSArray; | |
20 import dwt.internal.cocoa.NSAutoreleasePool; | |
21 import dwt.internal.cocoa.NSBezierPath; | |
18 import dwt.internal.cocoa.NSColor; | 22 import dwt.internal.cocoa.NSColor; |
19 import dwt.internal.cocoa.NSFont; | 23 import dwt.internal.cocoa.NSFont; |
20 import dwt.internal.cocoa.NSLayoutManager; | 24 import dwt.internal.cocoa.NSLayoutManager; |
21 import dwt.internal.cocoa.NSMutableParagraphStyle; | 25 import dwt.internal.cocoa.NSMutableParagraphStyle; |
22 import dwt.internal.cocoa.NSNumber; | 26 import dwt.internal.cocoa.NSNumber; |
25 import dwt.internal.cocoa.NSRect; | 29 import dwt.internal.cocoa.NSRect; |
26 import dwt.internal.cocoa.NSSize; | 30 import dwt.internal.cocoa.NSSize; |
27 import dwt.internal.cocoa.NSString; | 31 import dwt.internal.cocoa.NSString; |
28 import dwt.internal.cocoa.NSTextContainer; | 32 import dwt.internal.cocoa.NSTextContainer; |
29 import dwt.internal.cocoa.NSTextStorage; | 33 import dwt.internal.cocoa.NSTextStorage; |
34 import dwt.internal.cocoa.NSTextTab; | |
35 import dwt.internal.cocoa.NSThread; | |
30 import dwt.internal.cocoa.OS; | 36 import dwt.internal.cocoa.OS; |
31 | 37 |
32 import tango.text.convert.Format; | 38 import tango.text.convert.Format; |
33 | 39 |
34 import dwt.dwthelper.utils; | 40 import dwt.dwthelper.utils; |
59 * Application code must explicitly invoke the <code>TextLayout#dispose()</code> | 65 * Application code must explicitly invoke the <code>TextLayout#dispose()</code> |
60 * method to release the operating system resources managed by each instance | 66 * method to release the operating system resources managed by each instance |
61 * when those instances are no longer required. | 67 * when those instances are no longer required. |
62 * </p> | 68 * </p> |
63 * | 69 * |
64 * @since 3.0 | 70 * @see <a href="http://www.eclipse.org/swt/snippets/#textlayout">TextLayout, TextStyle snippets</a> |
71 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample, StyledText tab</a> | |
72 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
73 * | |
74 * @since 3.0 | |
65 */ | 75 */ |
66 public final class TextLayout : Resource { | 76 public final class TextLayout : Resource { |
67 | 77 |
68 alias Resource.init_ init_; | 78 alias Resource.init_ init_; |
69 | 79 |
81 int wrapWidth; | 91 int wrapWidth; |
82 int orientation; | 92 int orientation; |
83 | 93 |
84 int[] lineOffsets; | 94 int[] lineOffsets; |
85 NSRect[] lineBounds; | 95 NSRect[] lineBounds; |
96 | |
97 static final int UNDERLINE_THICK = 1 << 16; | |
86 | 98 |
87 static class StyleItem { | 99 static class StyleItem { |
88 TextStyle style; | 100 TextStyle style; |
89 int start; | 101 int start; |
90 | 102 |
128 | 140 |
129 void checkLayout() { | 141 void checkLayout() { |
130 if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); | 142 if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); |
131 } | 143 } |
132 | 144 |
145 float[] computePolyline(int left, int top, int right, int bottom) { | |
146 int height = bottom - top; // can be any number | |
147 int width = 2 * height; // must be even | |
148 int peaks = Compatibility.ceil(right - left, width); | |
149 if (peaks is 0 && right - left > 2) { | |
150 peaks = 1; | |
151 } | |
152 int length = ((2 * peaks) + 1) * 2; | |
153 if (length < 0) return new float[0]; | |
154 | |
155 float[] coordinates = new float[length]; | |
156 for (int i = 0; i < peaks; i++) { | |
157 int index = 4 * i; | |
158 coordinates[index] = left + (width * i); | |
159 coordinates[index+1] = bottom; | |
160 coordinates[index+2] = coordinates[index] + width / 2; | |
161 coordinates[index+3] = top; | |
162 } | |
163 coordinates[length-2] = left + (width * peaks); | |
164 coordinates[length-1] = bottom; | |
165 return coordinates; | |
166 } | |
167 | |
133 void computeRuns() { | 168 void computeRuns() { |
134 if (textStorage !is null) return; | 169 if (textStorage !is null) return; |
135 NSString str = NSString.stringWith(text); | 170 NSString str = NSString.stringWith(text); |
136 textStorage = (cast(NSTextStorage)(new NSTextStorage()).alloc()); | 171 textStorage = (cast(NSTextStorage)(new NSTextStorage()).alloc()); |
137 textStorage.initWithString_(str); | 172 textStorage.initWithString(str); |
138 layoutManager = cast(NSLayoutManager)(new NSLayoutManager()).alloc().init(); | 173 layoutManager = cast(NSLayoutManager)(new NSLayoutManager()).alloc().init(); |
139 textContainer = cast(NSTextContainer)(new NSTextContainer()).alloc(); | 174 textContainer = cast(NSTextContainer)(new NSTextContainer()).alloc(); |
140 NSSize size = NSSize(); | 175 NSSize size = NSSize(); |
141 size.width = wrapWidth !is -1 ? wrapWidth : Float.MAX_VALUE; | 176 size.width = wrapWidth !is -1 ? wrapWidth : Float.MAX_VALUE; |
142 size.height = Float.MAX_VALUE; | 177 size.height = Float.MAX_VALUE; |
146 | 181 |
147 textStorage.beginEditing(); | 182 textStorage.beginEditing(); |
148 Font defaultFont = font !is null ? font : device.systemFont; | 183 Font defaultFont = font !is null ? font : device.systemFont; |
149 NSRange range = NSRange(); | 184 NSRange range = NSRange(); |
150 range.length = str.length(); | 185 range.length = str.length(); |
151 textStorage.addAttribute(OS.NSFontAttributeName(), defaultFont.handle, range); | 186 textStorage.addAttribute(OS.NSFontAttributeName, defaultFont.handle, range); |
152 | 187 |
153 NSMutableParagraphStyle paragraph = cast(NSMutableParagraphStyle)(new NSMutableParagraphStyle()).alloc().init(); | 188 NSMutableParagraphStyle paragraph = cast(NSMutableParagraphStyle)(new NSMutableParagraphStyle()).alloc().init(); |
154 NSTextAlignment align_ = NSLeftTextAlignment; | 189 NSTextAlignment align_ = NSLeftTextAlignment; |
155 if (justify) { | 190 if (justify) { |
156 align_ = NSJustifiedTextAlignment; | 191 align_ = NSJustifiedTextAlignment; |
164 } | 199 } |
165 } | 200 } |
166 paragraph.setAlignment(align_); | 201 paragraph.setAlignment(align_); |
167 paragraph.setLineSpacing(spacing); | 202 paragraph.setLineSpacing(spacing); |
168 paragraph.setFirstLineHeadIndent(indent); | 203 paragraph.setFirstLineHeadIndent(indent); |
204 paragraph.setLineBreakMode(wrapWidth !is -1 ? OS.NSLineBreakByWordWrapping : OS.NSLineBreakByClipping); | |
205 paragraph.setTabStops(NSArray.array()); | |
206 if (tabs !is null) { | |
207 int count = tabs.length; | |
208 for (int i = 0, pos = 0; i < count; i++) { | |
209 pos += tabs[i]; | |
210 NSTextTab tab = (NSTextTab)new NSTextTab().alloc(); | |
211 tab = tab.initWithType(OS.NSLeftTabStopType, pos); | |
212 paragraph.addTabStop(tab); | |
213 tab.release(); | |
214 } | |
215 int width = count - 2 >= 0 ? tabs[count - 1] - tabs[count - 2] : tabs[count - 1]; | |
216 paragraph.setDefaultTabInterval(width); | |
217 } | |
169 | 218 |
170 //TODO tabs ascend descent wrap | 219 //TODO ascend descent wrap |
171 | 220 |
172 textStorage.addAttribute(OS.NSParagraphStyleAttributeName(), paragraph, range); | 221 textStorage.addAttribute(OS.NSParagraphStyleAttributeName, paragraph, range); |
173 paragraph.release(); | 222 paragraph.release(); |
174 | 223 |
175 int textLength = str.length(); | 224 int /*long*/ textLength = str.length(); |
176 for (int i = 0; i < styles.length - 1; i++) { | 225 for (int i = 0; i < styles.length - 1; i++) { |
177 StyleItem run = styles[i]; | 226 StyleItem run = styles[i]; |
178 if (run.style is null) continue; | 227 if (run.style is null) continue; |
179 TextStyle style = run.style; | 228 TextStyle style = run.style; |
180 range.location = textLength !is 0 ? translateOffset(run.start) : 0; | 229 range.location = textLength !is 0 ? translateOffset(run.start) : 0; |
181 range.length = translateOffset(styles[i + 1].start) - range.location; | 230 range.length = translateOffset(styles[i + 1].start) - range.location; |
182 Font font = style.font; | 231 Font font = style.font; |
183 if (font !is null) { | 232 if (font !is null) { |
184 textStorage.addAttribute(OS.NSFontAttributeName(), font.handle, range); | 233 textStorage.addAttribute(OS.NSFontAttributeName, font.handle, range); |
185 } | 234 } |
186 Color foreground = style.foreground; | 235 Color foreground = style.foreground; |
187 if (foreground !is null) { | 236 if (foreground !is null) { |
188 NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1); | 237 NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1); |
189 textStorage.addAttribute(OS.NSForegroundColorAttributeName(), color, range); | 238 textStorage.addAttribute(OS.NSForegroundColorAttributeName, color, range); |
190 } | 239 } |
191 Color background = style.background; | 240 Color background = style.background; |
192 if (background !is null) { | 241 if (background !is null) { |
193 NSColor color = NSColor.colorWithDeviceRed(background.handle[0], background.handle[1], background.handle[2], 1); | 242 NSColor color = NSColor.colorWithDeviceRed(background.handle[0], background.handle[1], background.handle[2], 1); |
194 textStorage.addAttribute(OS.NSBackgroundColorAttributeName, color, range); | 243 textStorage.addAttribute(OS.NSBackgroundColorAttributeName, color, range); |
195 } | 244 } |
196 if (style.strikeout) { | 245 if (style.strikeout) { |
197 textStorage.addAttribute(OS.NSStrikethroughStyleAttributeName(), NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range); | 246 textStorage.addAttribute(OS.NSStrikethroughStyleAttributeName, NSNumber.numberWithInt(OS.NSUnderlineStyleSingle), range); |
198 Color strikeColor = style.strikeoutColor; | 247 Color strikeColor = style.strikeoutColor; |
199 if (strikeColor !is null) { | 248 if (strikeColor !is null) { |
200 NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1); | 249 NSColor color = NSColor.colorWithDeviceRed(strikeColor.handle[0], strikeColor.handle[1], strikeColor.handle[2], 1); |
201 textStorage.addAttribute(OS.NSStrikethroughColorAttributeName(), color, range); | 250 textStorage.addAttribute(OS.NSStrikethroughColorAttributeName, color, range); |
202 } | 251 } |
203 } | 252 } |
204 if (style.underline) { | 253 if (style.underline) { |
205 //TODO - IME - thick | |
206 int underlineStyle = 0; | 254 int underlineStyle = 0; |
207 switch (style.underlineStyle) { | 255 switch (style.underlineStyle) { |
208 case DWT.UNDERLINE_SINGLE: | 256 case DWT.UNDERLINE_SINGLE: |
209 underlineStyle = OS.NSUnderlineStyleSingle; | 257 underlineStyle = OS.NSUnderlineStyleSingle; |
210 break; | 258 break; |
211 case DWT.UNDERLINE_DOUBLE: | 259 case DWT.UNDERLINE_DOUBLE: |
212 underlineStyle = OS.NSUnderlineStyleDouble; | 260 underlineStyle = OS.NSUnderlineStyleDouble; |
213 break; | 261 break; |
262 case UNDERLINE_THICK: | |
263 underlineStyle = OS.NSUnderlineStyleThick; | |
264 break; | |
214 } | 265 } |
215 if (underlineStyle !is 0) { | 266 if (underlineStyle !is 0) { |
216 textStorage.addAttribute(OS.NSUnderlineStyleAttributeName(), NSNumber.numberWithInt(underlineStyle), range); | 267 textStorage.addAttribute(OS.NSUnderlineStyleAttributeName, NSNumber.numberWithInt(underlineStyle), range); |
217 Color underlineColor = style.underlineColor; | 268 Color underlineColor = style.underlineColor; |
218 if (underlineColor !is null) { | 269 if (underlineColor !is null) { |
219 NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1); | 270 NSColor color = NSColor.colorWithDeviceRed(underlineColor.handle[0], underlineColor.handle[1], underlineColor.handle[2], 1); |
220 textStorage.addAttribute(OS.NSUnderlineColorAttributeName(), color, range); | 271 textStorage.addAttribute(OS.NSUnderlineColorAttributeName, color, range); |
221 } | 272 } |
222 } | 273 } |
223 } | 274 } |
224 if (style.rise !is 0) { | 275 if (style.rise !is 0) { |
225 textStorage.addAttribute(OS.NSBaselineOffsetAttributeName(), NSNumber.numberWithInt(style.rise), range); | 276 textStorage.addAttribute(OS.NSBaselineOffsetAttributeName, NSNumber.numberWithInt(style.rise), range); |
226 } | 277 } |
227 if (style.metrics !is null) { | 278 if (style.metrics !is null) { |
228 //TODO | 279 //TODO |
229 } | 280 } |
230 } | 281 } |
231 textStorage.endEditing(); | 282 textStorage.endEditing(); |
232 | 283 |
233 textContainer.setLineFragmentPadding(0); | 284 textContainer.setLineFragmentPadding(0); |
234 layoutManager.glyphRangeForTextContainer(textContainer); | 285 layoutManager.glyphRangeForTextContainer(textContainer); |
235 | 286 |
236 int numberOfLines, index, numberOfGlyphs = layoutManager.numberOfGlyphs(); | 287 int numberOfLines; |
288 NSUInteger numberOfGlyphs = layoutManager.numberOfGlyphs(), index; | |
237 NSRangePointer rangePtr = cast(NSRangePointer) OS.malloc(NSRange.sizeof); | 289 NSRangePointer rangePtr = cast(NSRangePointer) OS.malloc(NSRange.sizeof); |
238 NSRange lineRange = NSRange(); | |
239 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ | 290 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ |
240 layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_withoutAdditionalLayout_(index, rangePtr, true); | 291 layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true); |
241 OS.memmove(&lineRange, rangePtr, NSRange.sizeof); | 292 OS.memmove(&lineRange, rangePtr, NSRange.sizeof); |
242 index = lineRange.location + lineRange.length; | 293 index = lineRange.location + lineRange.length; |
243 } | 294 } |
244 if (numberOfLines is 0) numberOfLines++; | 295 if (numberOfLines is 0) numberOfLines++; |
245 int[] offsets = new int[numberOfLines + 1]; | 296 int[] offsets = new int[numberOfLines + 1]; |
246 NSRect[] bounds = new NSRect[numberOfLines]; | 297 NSRect[] bounds = new NSRect[numberOfLines]; |
247 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ | 298 for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ |
248 bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_withoutAdditionalLayout_(index, rangePtr, true); | 299 bounds[numberOfLines] = layoutManager.lineFragmentUsedRectForGlyphAtIndex(index, rangePtr, true); |
300 if (numberOfLines < bounds.length - 1) bounds[numberOfLines].height -= spacing; | |
249 OS.memmove(&lineRange, rangePtr, NSRange.sizeof); | 301 OS.memmove(&lineRange, rangePtr, NSRange.sizeof); |
250 offsets[numberOfLines] = lineRange.location; | 302 offsets[numberOfLines] = (int)/*64*/lineRange.location; |
251 index = lineRange.location + lineRange.length; | 303 index = lineRange.location + lineRange.length; |
252 } | 304 } |
253 if (numberOfLines is 0) { | 305 if (numberOfLines is 0) { |
254 Font font = this.font !is null ? this.font : device.systemFont; | 306 Font font = this.font !is null ? this.font : device.systemFont; |
255 NSFont nsFont = font.handle; | 307 NSFont nsFont = font.handle; |
256 bounds[0] = NSRect(); | 308 bounds[0] = NSRect(); |
257 bounds[0].height = Math.max(layoutManager.defaultLineHeightForFont(nsFont), ascent + descent); | 309 bounds[0].height = Math.max(layoutManager.defaultLineHeightForFont(nsFont), ascent + descent); |
258 } | 310 } |
259 OS.free(rangePtr); | 311 OS.free(rangePtr); |
260 offsets[numberOfLines] = textStorage.length(); | 312 offsets[numberOfLines] = (int)/*64*/textStorage.length(); |
261 this.lineOffsets = offsets; | 313 this.lineOffsets = offsets; |
262 this.lineBounds = bounds; | 314 this.lineBounds = bounds; |
263 } | 315 } |
264 | 316 |
265 void destroy() { | 317 void destroy() { |
343 computeRuns(); | 395 computeRuns(); |
344 if (gc is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); | 396 if (gc is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); |
345 if (gc.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 397 if (gc.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
346 if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 398 if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
347 if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 399 if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
348 gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND); | 400 int length = translateOffset(text.length()); |
349 // float[] foreground = gc.data.foreground; | 401 if (length is 0 && flags is 0) return; |
350 // NSColor color = NSColor.colorWithDeviceRed(foreground[0], foreground[1], foreground[2], foreground[3]); | 402 NSAutoreleasePool pool = gc.checkGC(GC.CLIPPING | GC.TRANSFORM | GC.FOREGROUND); |
351 // textStorage.setForegroundColor(color); | 403 try { |
352 NSPoint pt = NSPoint(); | 404 gc.handle.saveGraphicsState(); |
353 pt.x = x; | 405 float[] fg = gc.data.foreground; |
354 pt.y = y; | 406 NSColor foreground = NSColor.colorWithDeviceRed(fg[0], fg[1], fg[2], fg[3]); |
355 NSRange range = NSRange(); | 407 NSPoint pt = NSPoint(); |
356 range.length = layoutManager.numberOfGlyphs(); | 408 pt.x = x; |
357 bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1; | 409 pt.y = y; |
410 bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1; | |
358 NSRange* selectionRange = null; | 411 NSRange* selectionRange = null; |
359 if (hasSelection) { | 412 NSColor selectionColor = null; |
360 selectionRange = new NSRange(); | 413 if (hasSelection || (flags & DWT.LAST_LINE_SELECTION) !is 0) { |
361 selectionRange.location = selectionStart; | 414 if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION); |
362 selectionRange.length = selectionEnd - selectionStart + 1; | 415 selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]); |
363 if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION); | 416 } |
364 NSColor selectionColor = NSColor.colorWithDeviceRed(selectionBackground.handle[0], selectionBackground.handle[1], selectionBackground.handle[2], selectionBackground.handle[3]); | 417 if (hasSelection) { |
418 selectionRange = new NSRange(); | |
419 selectionRange.location = selectionStart; | |
420 selectionRange.length = selectionEnd - selectionStart + 1; | |
365 layoutManager.addTemporaryAttribute(OS.NSBackgroundColorAttributeName, selectionColor, *selectionRange); | 421 layoutManager.addTemporaryAttribute(OS.NSBackgroundColorAttributeName, selectionColor, *selectionRange); |
366 } | 422 } |
367 //TODO draw selection for flags (LAST_LINE_SELECTION and FULL_SELECTION) | 423 //TODO draw selection for flags (DELIMITER_SELECTION) |
368 if (range.length > 0) { | 424 int numberOfGlyphs = layoutManager.numberOfGlyphs(); |
369 layoutManager.drawBackgroundForGlyphRange(range, pt); | 425 if (numberOfGlyphs > 0) { |
370 layoutManager.drawGlyphsForGlyphRange(range, pt); | 426 NSRange range = new NSRange(); |
371 } | 427 for (int i = 0; i < styles.length - 1; i++) { |
372 if (selectionRange !is null) { | 428 StyleItem run = styles[i]; |
429 if (run.style !is null && run.style.foreground !is null) continue; | |
430 range.location = length !is 0 ? translateOffset(run.start) : 0; | |
431 range.length = translateOffset(styles[i + 1].start) - range.location; | |
432 layoutManager.addTemporaryAttribute(OS.NSForegroundColorAttributeName, foreground, range); | |
433 } | |
434 range.location = 0; | |
435 range.length = numberOfGlyphs; | |
436 layoutManager.drawBackgroundForGlyphRange(range, pt); | |
437 layoutManager.drawGlyphsForGlyphRange(range, pt); | |
438 range.length = length; | |
439 layoutManager.removeTemporaryAttribute(OS.NSForegroundColorAttributeName, range); | |
440 NSPoint point = new NSPoint(); | |
441 for (int j = 0; j < styles.length; j++) { | |
442 StyleItem run = styles[j]; | |
443 TextStyle style = run.style; | |
444 if (style is null) continue; | |
445 bool drawUnderline = style.underline && style.underlineStyle !is DWT.UNDERLINE_SINGLE && style.underlineStyle !is DWT.UNDERLINE_DOUBLE; | |
446 drawUnderline = drawUnderline && (j + 1 is styles.length || !style.isAdherentUnderline(styles[j + 1].style)); | |
447 bool drawBorder = style.borderStyle !is DWT.NONE; | |
448 drawBorder = drawBorder && (j + 1 is styles.length || !style.isAdherentBorder(styles[j + 1].style)); | |
449 if (!drawUnderline && !drawBorder) continue; | |
450 int end = j + 1 < styles.length ? translateOffset(styles[j + 1].start - 1) : length; | |
451 for (int i = 0; i < lineOffsets.length - 1; i++) { | |
452 int lineStart = untranslateOffset(lineOffsets[i]); | |
453 int lineEnd = untranslateOffset(lineOffsets[i + 1] - 1); | |
454 if (drawUnderline) { | |
455 int start = run.start; | |
456 for (int k = j; k > 0 && style.isAdherentUnderline(styles[k - 1].style); k--) { | |
457 start = styles[k - 1].start; | |
458 } | |
459 start = translateOffset(start); | |
460 if (!(start > lineEnd || end < lineStart)) { | |
461 range.location = layoutManager.glyphIndexForCharacterAtIndex(Math.max(lineStart, start)); | |
462 range.length = layoutManager.glyphIndexForCharacterAtIndex(Math.min(lineEnd, end) + 1) - range.location; | |
463 if (range.length > 0) { | |
464 gc.handle.saveGraphicsState(); | |
465 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer); | |
466 float baseline = layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, lineStart); | |
467 float underlineX = pt.x + rect.x; | |
468 float underlineY = pt.y + rect.y + rect.height - baseline; | |
469 float[] color = null; | |
470 if (style.underlineColor !is null) color = style.underlineColor.handle; | |
471 if (color is null && style.foreground !is null) color = style.foreground.handle; | |
472 if (color !is null) { | |
473 NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke(); | |
474 } | |
475 NSBezierPath path = NSBezierPath.bezierPath(); | |
476 switch (style.underlineStyle) { | |
477 case DWT.UNDERLINE_ERROR: { | |
478 path.setLineWidth(2f); | |
479 path.setLineCapStyle(OS.NSRoundLineCapStyle); | |
480 path.setLineJoinStyle(OS.NSRoundLineJoinStyle); | |
481 path.setLineDash(new float[]{1, 3f}, 2, 0); | |
482 point.x = underlineX; | |
483 point.y = underlineY + 0.5f; | |
484 path.moveToPoint(point); | |
485 point.x = underlineX + rect.width; | |
486 point.y = underlineY + 0.5f; | |
487 path.lineToPoint(point); | |
488 break; | |
489 } | |
490 case DWT.UNDERLINE_SQUIGGLE: { | |
491 gc.handle.setShouldAntialias(false); | |
492 path.setLineWidth(1.0f); | |
493 path.setLineCapStyle(OS.NSButtLineCapStyle); | |
494 path.setLineJoinStyle(OS.NSMiterLineJoinStyle); | |
495 float lineBottom = pt.y + rect.y + rect.height; | |
496 float squigglyThickness = 1; | |
497 float squigglyHeight = 2 * squigglyThickness; | |
498 float squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1); | |
499 float[] points = computePolyline((int)underlineX, (int)squigglyY, (int)(underlineX + rect.width), (int)(squigglyY + squigglyHeight)); | |
500 point.x = points[0] + 0.5f; | |
501 point.y = points[1] + 0.5f; | |
502 path.moveToPoint(point); | |
503 for (int p = 2; p < points.length; p+=2) { | |
504 point.x = points[p] + 0.5f; | |
505 point.y = points[p+1] + 0.5f; | |
506 path.lineToPoint(point); | |
507 } | |
508 break; | |
509 } | |
510 } | |
511 path.stroke(); | |
512 gc.handle.restoreGraphicsState(); | |
513 } | |
514 } | |
515 } | |
516 if (drawBorder) { | |
517 int start = run.start; | |
518 for (int k = j; k > 0 && style.isAdherentBorder(styles[k - 1].style); k--) { | |
519 start = styles[k - 1].start; | |
520 } | |
521 start = translateOffset(start); | |
522 if (!(start > lineEnd || end < lineStart)) { | |
523 range.location = layoutManager.glyphIndexForCharacterAtIndex(Math.max(lineStart, start)); | |
524 range.length = layoutManager.glyphIndexForCharacterAtIndex(Math.min(lineEnd, end) + 1) - range.location; | |
525 if (range.length > 0) { | |
526 gc.handle.saveGraphicsState(); | |
527 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer); | |
528 rect.x += pt.x + 0.5f; | |
529 rect.y += pt.y + 0.5f; | |
530 rect.width -= 0.5f; | |
531 rect.height -= 0.5f; | |
532 float[] color = null; | |
533 if (style.borderColor !is null) color = style.borderColor.handle; | |
534 if (color is null && style.foreground !is null) color = style.foreground.handle; | |
535 if (color !is null) { | |
536 NSColor.colorWithDeviceRed(color[0], color[1], color[2], color[3]).setStroke(); | |
537 } | |
538 int width = 1; | |
539 float[] dashes = null; | |
540 switch (style.borderStyle) { | |
541 case DWT.BORDER_SOLID: break; | |
542 case DWT.BORDER_DASH: dashes = width !is 0 ? GC.LINE_DASH : GC.LINE_DASH_ZERO; break; | |
543 case DWT.BORDER_DOT: dashes = width !is 0 ? GC.LINE_DOT : GC.LINE_DOT_ZERO; break; | |
544 } | |
545 NSBezierPath path = NSBezierPath.bezierPath(); | |
546 path.setLineDash(dashes, dashes !is null ? dashes.length : 0, 0); | |
547 path.appendBezierPathWithRect(rect); | |
548 path.stroke(); | |
549 gc.handle.restoreGraphicsState(); | |
550 } | |
551 } | |
552 } | |
553 } | |
554 | |
555 } | |
556 } | |
557 if ((flags & DWT.LAST_LINE_SELECTION) !is 0) { | |
558 NSRect bounds = lineBounds[lineBounds.length - 1]; | |
559 NSRect rect = new NSRect(); | |
560 rect.x = pt.x + bounds.x + bounds.width; | |
561 rect.y = y + bounds.y; | |
562 rect.width = (flags & DWT.FULL_SELECTION) !is 0 ? 0x7fffffff : bounds.height / 3; | |
563 rect.height = bounds.height; | |
564 selectionColor.setFill(); | |
565 NSBezierPath path = NSBezierPath.bezierPath(); | |
566 path.appendBezierPathWithRect(rect); | |
567 path.fill(); | |
568 } | |
569 if (selectionRange !is null) { | |
373 layoutManager.removeTemporaryAttribute(OS.NSBackgroundColorAttributeName, *selectionRange); | 570 layoutManager.removeTemporaryAttribute(OS.NSBackgroundColorAttributeName, *selectionRange); |
571 } | |
572 gc.handle.restoreGraphicsState(); | |
573 } finally { | |
574 gc.uncheckGC(pool); | |
374 } | 575 } |
375 } | 576 } |
376 | 577 |
377 void freeRuns() { | 578 void freeRuns() { |
378 if (textStorage is null) return; | 579 if (textStorage is null) return; |
424 checkLayout(); | 625 checkLayout(); |
425 return ascent; | 626 return ascent; |
426 } | 627 } |
427 | 628 |
428 /** | 629 /** |
429 * Returns the bounds of the receiver. | 630 * Returns the bounds of the receiver. The width returned is either the |
631 * width of the longest line or the width set using {@link TextLayout#setWidth(int)}. | |
632 * To obtain the text bounds of a line use {@link TextLayout#getLineBounds(int)}. | |
430 * | 633 * |
431 * @return the bounds of the receiver | 634 * @return the bounds of the receiver |
432 * | 635 * |
433 * @exception DWTException <ul> | 636 * @exception DWTException <ul> |
434 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 637 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
435 * </ul> | 638 * </ul> |
639 * | |
640 * @see #setWidth(int) | |
641 * @see #getLineBounds(int) | |
436 */ | 642 */ |
437 public Rectangle getBounds() { | 643 public Rectangle getBounds() { |
438 checkLayout(); | 644 checkLayout(); |
439 computeRuns(); | 645 NSAutoreleasePool pool = null; |
440 NSRect rect = layoutManager.usedRectForTextContainer(textContainer); | 646 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
441 if (wrapWidth !is -1) rect.width = wrapWidth; | 647 try { |
442 if (text.length() is 0) { | 648 computeRuns(); |
443 Font font = this.font !is null ? this.font : device.systemFont; | 649 NSRect rect = layoutManager.usedRectForTextContainer(textContainer); |
444 NSFont nsFont = font.handle; | 650 if (wrapWidth !is -1) rect.width = wrapWidth; |
445 rect.height = Math.max(rect.height, layoutManager.defaultLineHeightForFont(nsFont)); | 651 if (text.length() is 0) { |
446 } | 652 Font font = this.font !is null ? this.font : device.systemFont; |
447 rect.height = Math.max(rect.height, ascent + descent); | 653 NSFont nsFont = font.handle; |
654 rect.height = Math.max(rect.height, layoutManager.defaultLineHeightForFont(nsFont)); | |
655 } | |
656 rect.height = Math.max(rect.height, ascent + descent) + spacing; | |
448 return new Rectangle(0, 0, cast(int)rect.width, cast(int)rect.height); | 657 return new Rectangle(0, 0, cast(int)rect.width, cast(int)rect.height); |
658 } finally { | |
659 if (pool !is null) pool.release(); | |
660 } | |
449 } | 661 } |
450 | 662 |
451 /** | 663 /** |
452 * Returns the bounds for the specified range of characters. The | 664 * Returns the bounds for the specified range of characters. The |
453 * bounds is the smallest rectangle that encompasses all characters | 665 * bounds is the smallest rectangle that encompasses all characters |
462 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 674 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
463 * </ul> | 675 * </ul> |
464 */ | 676 */ |
465 public Rectangle getBounds(int start, int end) { | 677 public Rectangle getBounds(int start, int end) { |
466 checkLayout(); | 678 checkLayout(); |
467 computeRuns(); | 679 NSAutoreleasePool pool = null; |
468 int length = text.length(); | 680 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
469 if (length is 0) return new Rectangle(0, 0, 0, 0); | 681 try { |
470 if (start > end) return new Rectangle(0, 0, 0, 0); | 682 computeRuns(); |
471 start = Math.min(Math.max(0, start), length - 1); | 683 int length = text.length(); |
472 end = Math.min(Math.max(0, end), length - 1); | 684 if (length is 0) return new Rectangle(0, 0, 0, 0); |
473 start = translateOffset(start); | 685 if (start > end) return new Rectangle(0, 0, 0, 0); |
474 end = translateOffset(end); | 686 start = Math.min(Math.max(0, start), length - 1); |
687 end = Math.min(Math.max(0, end), length - 1); | |
688 start = translateOffset(start); | |
689 end = translateOffset(end); | |
475 NSRange range = NSRange(); | 690 NSRange range = NSRange(); |
476 range.location = layoutManager.glyphIndexForCharacterAtIndex(start); | 691 range.location = layoutManager.glyphIndexForCharacterAtIndex(start); |
477 range.length = layoutManager.glyphIndexForCharacterAtIndex(end + 1) - range.location; | 692 range.length = layoutManager.glyphIndexForCharacterAtIndex(end + 1) - range.location; |
478 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer); | 693 NSRect rect = layoutManager.boundingRectForGlyphRange(range, textContainer); |
479 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)Math.ceil(rect.width), cast(int)Math.ceil(rect.height)); | 694 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)Math.ceil(rect.width), cast(int)Math.ceil(rect.height)); |
695 } finally { | |
696 if (pool !is null) pool.release(); | |
697 } | |
480 } | 698 } |
481 | 699 |
482 /** | 700 /** |
483 * Returns the descent of the receiver. | 701 * Returns the descent of the receiver. |
484 * | 702 * |
559 * @exception DWTException <ul> | 777 * @exception DWTException <ul> |
560 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 778 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
561 */ | 779 */ |
562 public int getLevel(int offset) { | 780 public int getLevel(int offset) { |
563 checkLayout(); | 781 checkLayout(); |
564 computeRuns(); | 782 NSAutoreleasePool pool = null; |
565 int length = text.length(); | 783 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
566 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); | 784 try { |
567 offset = translateOffset(offset); | 785 computeRuns(); |
568 int level = 0; | 786 int length = text.length(); |
569 //TODO | 787 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); |
570 return level; | 788 offset = translateOffset(offset); |
789 int level = 0; | |
790 //TODO | |
791 return level; | |
792 } finally { | |
793 if (pool !is null) pool.release(); | |
794 } | |
571 } | 795 } |
572 | 796 |
573 /** | 797 /** |
574 * Returns the line offsets. Each value in the array is the | 798 * Returns the line offsets. Each value in the array is the |
575 * offset for the first character in a line except for the last | 799 * offset for the first character in a line except for the last |
581 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 805 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
582 * </ul> | 806 * </ul> |
583 */ | 807 */ |
584 public int[] getLineOffsets() { | 808 public int[] getLineOffsets() { |
585 checkLayout (); | 809 checkLayout (); |
586 computeRuns(); | 810 NSAutoreleasePool pool = null; |
587 int[] offsets = new int[lineOffsets.length]; | 811 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
588 for (int i = 0; i < offsets.length; i++) { | 812 try { |
589 offsets[i] = untranslateOffset(lineOffsets[i]); | 813 computeRuns(); |
590 } | 814 int[] offsets = new int[lineOffsets.length]; |
591 return offsets; | 815 for (int i = 0; i < offsets.length; i++) { |
816 offsets[i] = untranslateOffset(lineOffsets[i]); | |
817 } | |
818 return offsets; | |
819 } finally { | |
820 if (pool !is null) pool.release(); | |
821 } | |
592 } | 822 } |
593 | 823 |
594 /** | 824 /** |
595 * Returns the index of the line that contains the specified | 825 * Returns the index of the line that contains the specified |
596 * character offset. | 826 * character offset. |
605 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 835 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
606 * </ul> | 836 * </ul> |
607 */ | 837 */ |
608 public int getLineIndex(int offset) { | 838 public int getLineIndex(int offset) { |
609 checkLayout (); | 839 checkLayout (); |
610 computeRuns(); | 840 NSAutoreleasePool pool = null; |
611 int length = text.length(); | 841 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
612 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); | 842 try { |
613 offset = translateOffset(offset); | 843 computeRuns(); |
614 for (int line=0; line<lineOffsets.length - 1; line++) { | 844 int length = text.length(); |
615 if (lineOffsets[line + 1] > offset) { | 845 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); |
616 return line; | 846 offset = translateOffset(offset); |
617 } | 847 for (int line=0; line<lineOffsets.length - 1; line++) { |
618 } | 848 if (lineOffsets[line + 1] > offset) { |
619 return lineBounds.length - 1; | 849 return line; |
850 } | |
851 } | |
852 return lineBounds.length - 1; | |
853 } finally { | |
854 if (pool !is null) pool.release(); | |
855 } | |
620 } | 856 } |
621 | 857 |
622 /** | 858 /** |
623 * Returns the bounds of the line for the specified line index. | 859 * Returns the bounds of the line for the specified line index. |
624 * | 860 * |
632 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 868 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
633 * </ul> | 869 * </ul> |
634 */ | 870 */ |
635 public Rectangle getLineBounds(int lineIndex) { | 871 public Rectangle getLineBounds(int lineIndex) { |
636 checkLayout(); | 872 checkLayout(); |
637 computeRuns(); | 873 NSAutoreleasePool pool = null; |
638 if (!(0 <= lineIndex && lineIndex < lineBounds.length)) DWT.error(DWT.ERROR_INVALID_RANGE); | 874 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
639 NSRect rect = lineBounds[lineIndex]; | 875 try { |
876 computeRuns(); | |
877 if (!(0 <= lineIndex && lineIndex < lineBounds.length)) DWT.error(DWT.ERROR_INVALID_RANGE); | |
878 NSRect rect = lineBounds[lineIndex]; | |
640 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)rect.width, cast(int)rect.height); | 879 return new Rectangle(cast(int)rect.x, cast(int)rect.y, cast(int)rect.width, cast(int)rect.height); |
880 } finally { | |
881 if (pool !is null) pool.release(); | |
882 } | |
641 } | 883 } |
642 | 884 |
643 /** | 885 /** |
644 * Returns the receiver's line count. This includes lines caused | 886 * Returns the receiver's line count. This includes lines caused |
645 * by wrapping. | 887 * by wrapping. |
650 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 892 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
651 * </ul> | 893 * </ul> |
652 */ | 894 */ |
653 public int getLineCount() { | 895 public int getLineCount() { |
654 checkLayout (); | 896 checkLayout (); |
655 computeRuns(); | 897 NSAutoreleasePool pool = null; |
656 return lineOffsets.length - 1; | 898 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
899 try { | |
900 computeRuns(); | |
901 return lineOffsets.length - 1; | |
902 } finally { | |
903 if (pool !is null) pool.release(); | |
904 } | |
657 } | 905 } |
658 | 906 |
659 /** | 907 /** |
660 * Returns the font metrics for the specified line index. | 908 * Returns the font metrics for the specified line index. |
661 * | 909 * |
669 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 917 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
670 * </ul> | 918 * </ul> |
671 */ | 919 */ |
672 public FontMetrics getLineMetrics (int lineIndex) { | 920 public FontMetrics getLineMetrics (int lineIndex) { |
673 checkLayout (); | 921 checkLayout (); |
674 computeRuns(); | 922 NSAutoreleasePool pool = null; |
675 int lineCount = getLineCount(); | 923 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
676 if (!(0 <= lineIndex && lineIndex < lineCount)) DWT.error(DWT.ERROR_INVALID_RANGE); | 924 try { |
677 int length = text.length(); | 925 computeRuns(); |
678 if (length is 0) { | 926 int lineCount = getLineCount(); |
679 Font font = this.font !is null ? this.font : device.systemFont; | 927 if (!(0 <= lineIndex && lineIndex < lineCount)) DWT.error(DWT.ERROR_INVALID_RANGE); |
680 NSFont nsFont = font.handle; | 928 int length = text.length(); |
929 if (length is 0) { | |
930 Font font = this.font !is null ? this.font : device.systemFont; | |
931 NSFont nsFont = font.handle; | |
681 int ascent = cast(int)(0.5f + nsFont.ascender()); | 932 int ascent = cast(int)(0.5f + nsFont.ascender()); |
682 int descent = cast(int)(0.5f + (-nsFont.descender() + nsFont.leading())); | 933 int descent = cast(int)(0.5f + (-nsFont.descender() + nsFont.leading())); |
683 ascent = Math.max(ascent, this.ascent); | 934 ascent = Math.max(ascent, this.ascent); |
684 descent = Math.max(descent, this.descent); | 935 descent = Math.max(descent, this.descent); |
685 return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent); | 936 return FontMetrics.cocoa_new(ascent, descent, 0, 0, ascent + descent); |
686 } | 937 } |
687 Rectangle rect = getLineBounds(lineIndex); | 938 Rectangle rect = getLineBounds(lineIndex); |
688 int baseline = cast(int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]); | 939 int baseline = cast(int)layoutManager.typesetter().baselineOffsetInLayoutManager(layoutManager, getLineOffsets()[lineIndex]); |
689 return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height); | 940 return FontMetrics.cocoa_new(rect.height - baseline, baseline, 0, 0, rect.height); |
941 } finally { | |
942 if (pool !is null) pool.release(); | |
943 } | |
690 } | 944 } |
691 | 945 |
692 /** | 946 /** |
693 * Returns the location for the specified character offset. The | 947 * Returns the location for the specified character offset. The |
694 * <code>trailing</code> argument indicates whether the offset | 948 * <code>trailing</code> argument indicates whether the offset |
705 * @see #getOffset(Point, int[]) | 959 * @see #getOffset(Point, int[]) |
706 * @see #getOffset(int, int, int[]) | 960 * @see #getOffset(int, int, int[]) |
707 */ | 961 */ |
708 public Point getLocation(int offset, bool trailing) { | 962 public Point getLocation(int offset, bool trailing) { |
709 checkLayout(); | 963 checkLayout(); |
710 computeRuns(); | 964 NSAutoreleasePool pool = null; |
711 int length = text.length(); | 965 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
712 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); | 966 try { |
713 if (length is 0) return new Point(0, 0); | 967 computeRuns(); |
714 offset = translateOffset(offset); | 968 int length = text.length(); |
969 if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE); | |
970 if (length is 0) return new Point(0, 0); | |
971 offset = translateOffset(offset); | |
715 NSUInteger glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(offset); | 972 NSUInteger glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(offset); |
716 NSRect rect = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_(glyphIndex, null); | 973 NSRect rect = layoutManager.lineFragmentUsedRectForGlyphAtIndex_effectiveRange_(glyphIndex, null); |
717 NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex); | 974 NSPoint point = layoutManager.locationForGlyphAtIndex(glyphIndex); |
718 if (trailing) { | 975 if (trailing) { |
719 NSRange range = NSRange(); | 976 NSRange range = NSRange(); |
720 range.location = glyphIndex; | 977 range.location = glyphIndex; |
721 range.length = 1; | 978 range.length = 1; |
722 NSRect bounds = layoutManager.boundingRectForGlyphRange(range, textContainer); | 979 NSRect bounds = layoutManager.boundingRectForGlyphRange(range, textContainer); |
723 point.x += bounds.width; | 980 point.x += bounds.width; |
724 } | 981 } |
725 return new Point(cast(int)point.x, cast(int)rect.y); | 982 return new Point(cast(int)point.x, cast(int)rect.y); |
983 } finally { | |
984 if (pool !is null) pool.release(); | |
985 } | |
726 } | 986 } |
727 | 987 |
728 /** | 988 /** |
729 * Returns the next offset for the specified offset and movement | 989 * Returns the next offset for the specified offset and movement |
730 * type. The movement is one of <code>DWT.MOVEMENT_CHAR</code>, | 990 * type. The movement is one of <code>DWT.MOVEMENT_CHAR</code>, |
743 * </ul> | 1003 * </ul> |
744 * | 1004 * |
745 * @see #getPreviousOffset(int, int) | 1005 * @see #getPreviousOffset(int, int) |
746 */ | 1006 */ |
747 public int getNextOffset (int offset, int movement) { | 1007 public int getNextOffset (int offset, int movement) { |
748 return _getOffset(offset, movement, true); | 1008 NSAutoreleasePool pool = null; |
1009 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); | |
1010 try { | |
1011 return _getOffset(offset, movement, true); | |
1012 } finally { | |
1013 if (pool !is null) pool.release(); | |
1014 } | |
749 } | 1015 } |
750 | 1016 |
751 int _getOffset (int offset, int movement, bool forward) { | 1017 int _getOffset (int offset, int movement, bool forward) { |
752 checkLayout(); | 1018 checkLayout(); |
753 computeRuns(); | 1019 computeRuns(); |
761 if (forward) { | 1027 if (forward) { |
762 offset++; | 1028 offset++; |
763 } else { | 1029 } else { |
764 offset--; | 1030 offset--; |
765 } | 1031 } |
766 return untranslateOffset(offset); | 1032 return Math.max(0, Math.min(length, untranslateOffset(offset))); |
767 } | 1033 } |
768 case DWT.MOVEMENT_WORD: { | 1034 case DWT.MOVEMENT_WORD: { |
769 return untranslateOffset(textStorage.nextWordFromIndex(offset, forward)); | 1035 return untranslateOffset((int)/*64*/textStorage.nextWordFromIndex(offset, forward)); |
770 } | 1036 } |
771 case DWT.MOVEMENT_WORD_END: { | 1037 case DWT.MOVEMENT_WORD_END: { |
772 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset); | 1038 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset); |
773 return untranslateOffset(range.location + range.length); | 1039 return untranslateOffset((int)/*64*/(range.location + range.length)); |
774 } | 1040 } |
775 case DWT.MOVEMENT_WORD_START: { | 1041 case DWT.MOVEMENT_WORD_START: { |
776 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset); | 1042 NSRange range = textStorage.doubleClickAtIndex(length is offset ? length - 1 : offset); |
777 return untranslateOffset(range.location); | 1043 return untranslateOffset((int)/*64*/range.location); |
778 } | 1044 } |
779 default: | 1045 default: |
780 break; | 1046 break; |
781 } | 1047 } |
782 return -1; | 1048 return -1; |
805 * | 1071 * |
806 * @see #getLocation(int, bool) | 1072 * @see #getLocation(int, bool) |
807 */ | 1073 */ |
808 public int getOffset(Point point, int[] trailing) { | 1074 public int getOffset(Point point, int[] trailing) { |
809 checkLayout(); | 1075 checkLayout(); |
810 computeRuns(); | 1076 NSAutoreleasePool pool = null; |
811 if (point is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); | 1077 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
812 return getOffset(point.x, point.y, trailing); | 1078 try { |
1079 computeRuns(); | |
1080 if (point is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); | |
1081 return getOffset(point.x, point.y, trailing); | |
1082 } finally { | |
1083 if (pool !is null) pool.release(); | |
1084 } | |
813 } | 1085 } |
814 | 1086 |
815 /** | 1087 /** |
816 * Returns the character offset for the specified point. | 1088 * Returns the character offset for the specified point. |
817 * For a typical character, the trailing argument will be filled in to | 1089 * For a typical character, the trailing argument will be filled in to |
835 * | 1107 * |
836 * @see #getLocation(int, bool) | 1108 * @see #getLocation(int, bool) |
837 */ | 1109 */ |
838 public int getOffset(int x, int y, int[] trailing) { | 1110 public int getOffset(int x, int y, int[] trailing) { |
839 checkLayout(); | 1111 checkLayout(); |
840 computeRuns(); | 1112 NSAutoreleasePool pool = null; |
841 if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 1113 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
842 int length = text.length(); | 1114 try { |
843 if (length is 0) return 0; | 1115 computeRuns(); |
1116 if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | |
1117 int length = text.length(); | |
1118 if (length is 0) return 0; | |
844 NSPoint pt = NSPoint(); | 1119 NSPoint pt = NSPoint(); |
845 pt.x = x; | 1120 pt.x = x; |
846 pt.y = y; | 1121 pt.y = y; |
847 CGFloat partialFration; | 1122 CGFloat partialFration; |
848 NSUInteger glyphIndex = layoutManager.glyphIndexForPoint_inTextContainer_fractionOfDistanceThroughGlyph_(pt, textContainer, &partialFration); | 1123 NSUInteger glyphIndex = layoutManager.glyphIndexForPoint(pt, textContainer, &partialFration); |
849 int offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex); | 1124 int /*long*/ offset = layoutManager.characterIndexForGlyphAtIndex(glyphIndex); |
850 if (trailing !is null) trailing[0] = cast(int) Math.round(partialFration); | 1125 if (trailing !is null) trailing[0] = cast(int) Math.round(partialFration); |
851 return Math.min(untranslateOffset(offset), length - 1); | 1126 return Math.min(untranslateOffset((int)/*64*/offset), length - 1); |
1127 } finally { | |
1128 if (pool !is null) pool.release(); | |
1129 } | |
852 } | 1130 } |
853 | 1131 |
854 /** | 1132 /** |
855 * Returns the orientation of the receiver. | 1133 * Returns the orientation of the receiver. |
856 * | 1134 * |
883 * </ul> | 1161 * </ul> |
884 * | 1162 * |
885 * @see #getNextOffset(int, int) | 1163 * @see #getNextOffset(int, int) |
886 */ | 1164 */ |
887 public int getPreviousOffset (int index, int movement) { | 1165 public int getPreviousOffset (int index, int movement) { |
888 return _getOffset(index, movement, false); | 1166 NSAutoreleasePool pool = null; |
1167 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); | |
1168 try { | |
1169 return _getOffset(index, movement, false); | |
1170 } finally { | |
1171 if (pool !is null) pool.release(); | |
1172 } | |
889 } | 1173 } |
890 | 1174 |
891 /** | 1175 /** |
892 * Gets the ranges of text that are associated with a <code>TextStyle</code>. | 1176 * Gets the ranges of text that are associated with a <code>TextStyle</code>. |
893 * | 1177 * |
1086 alignment &= mask; | 1370 alignment &= mask; |
1087 if (alignment is 0) return; | 1371 if (alignment is 0) return; |
1088 if ((alignment & DWT.LEFT) !is 0) alignment = DWT.LEFT; | 1372 if ((alignment & DWT.LEFT) !is 0) alignment = DWT.LEFT; |
1089 if ((alignment & DWT.RIGHT) !is 0) alignment = DWT.RIGHT; | 1373 if ((alignment & DWT.RIGHT) !is 0) alignment = DWT.RIGHT; |
1090 if (this.alignment is alignment) return; | 1374 if (this.alignment is alignment) return; |
1091 freeRuns(); | 1375 NSAutoreleasePool pool = null; |
1092 this.alignment = alignment; | 1376 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1377 try { | |
1378 freeRuns(); | |
1379 this.alignment = alignment; | |
1380 } finally { | |
1381 if (pool !is null) pool.release(); | |
1382 } | |
1093 } | 1383 } |
1094 | 1384 |
1095 /** | 1385 /** |
1096 * Sets the ascent of the receiver. The ascent is distance in pixels | 1386 * Sets the ascent of the receiver. The ascent is distance in pixels |
1097 * from the baseline to the top of the line and it is applied to all | 1387 * from the baseline to the top of the line and it is applied to all |
1112 */ | 1402 */ |
1113 public void setAscent (int ascent) { | 1403 public void setAscent (int ascent) { |
1114 checkLayout (); | 1404 checkLayout (); |
1115 if (ascent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 1405 if (ascent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
1116 if (this.ascent is ascent) return; | 1406 if (this.ascent is ascent) return; |
1117 freeRuns(); | 1407 NSAutoreleasePool pool = null; |
1118 this.ascent = ascent; | 1408 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1409 try { | |
1410 freeRuns(); | |
1411 this.ascent = ascent; | |
1412 } finally { | |
1413 if (pool !is null) pool.release(); | |
1414 } | |
1119 } | 1415 } |
1120 | 1416 |
1121 /** | 1417 /** |
1122 * Sets the descent of the receiver. The descent is distance in pixels | 1418 * Sets the descent of the receiver. The descent is distance in pixels |
1123 * from the baseline to the bottom of the line and it is applied to all | 1419 * from the baseline to the bottom of the line and it is applied to all |
1138 */ | 1434 */ |
1139 public void setDescent (int descent) { | 1435 public void setDescent (int descent) { |
1140 checkLayout (); | 1436 checkLayout (); |
1141 if (descent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 1437 if (descent < -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
1142 if (this.descent is descent) return; | 1438 if (this.descent is descent) return; |
1143 freeRuns(); | 1439 NSAutoreleasePool pool = null; |
1144 this.descent = descent; | 1440 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1441 try { | |
1442 freeRuns(); | |
1443 this.descent = descent; | |
1444 } finally { | |
1445 if (pool !is null) pool.release(); | |
1446 } | |
1145 } | 1447 } |
1146 | 1448 |
1147 /** | 1449 /** |
1148 * Sets the default font which will be used by the receiver | 1450 * Sets the default font which will be used by the receiver |
1149 * to draw and measure text. If the | 1451 * to draw and measure text. If the |
1165 if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 1467 if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
1166 Font oldFont = this.font; | 1468 Font oldFont = this.font; |
1167 if (oldFont is font) return; | 1469 if (oldFont is font) return; |
1168 this.font = font; | 1470 this.font = font; |
1169 if (oldFont !is null && oldFont.equals(font)) return; | 1471 if (oldFont !is null && oldFont.equals(font)) return; |
1170 freeRuns(); | 1472 NSAutoreleasePool pool = null; |
1473 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); | |
1474 try { | |
1475 freeRuns(); | |
1476 } finally { | |
1477 if (pool !is null) pool.release(); | |
1478 } | |
1171 } | 1479 } |
1172 | 1480 |
1173 /** | 1481 /** |
1174 * Sets the indent of the receiver. This indent it applied of the first line of | 1482 * Sets the indent of the receiver. This indent it applied of the first line of |
1175 * each paragraph. | 1483 * each paragraph. |
1184 */ | 1492 */ |
1185 public void setIndent (int indent) { | 1493 public void setIndent (int indent) { |
1186 checkLayout (); | 1494 checkLayout (); |
1187 if (indent < 0) return; | 1495 if (indent < 0) return; |
1188 if (this.indent is indent) return; | 1496 if (this.indent is indent) return; |
1189 freeRuns(); | 1497 NSAutoreleasePool pool = null; |
1190 this.indent = indent; | 1498 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1499 try { | |
1500 freeRuns(); | |
1501 this.indent = indent; | |
1502 } finally { | |
1503 if (pool !is null) pool.release(); | |
1504 } | |
1191 } | 1505 } |
1192 | 1506 |
1193 /** | 1507 /** |
1194 * Sets the justification of the receiver. Note that the receiver's | 1508 * Sets the justification of the receiver. Note that the receiver's |
1195 * width must be set in order to use justification. | 1509 * width must be set in order to use justification. |
1203 * @since 3.2 | 1517 * @since 3.2 |
1204 */ | 1518 */ |
1205 public void setJustify (bool justify) { | 1519 public void setJustify (bool justify) { |
1206 checkLayout (); | 1520 checkLayout (); |
1207 if (justify is this.justify) return; | 1521 if (justify is this.justify) return; |
1208 freeRuns(); | 1522 NSAutoreleasePool pool = null; |
1209 this.justify = justify; | 1523 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1524 try { | |
1525 freeRuns(); | |
1526 this.justify = justify; | |
1527 } finally { | |
1528 if (pool !is null) pool.release(); | |
1529 } | |
1210 } | 1530 } |
1211 | 1531 |
1212 /** | 1532 /** |
1213 * Sets the orientation of the receiver, which must be one | 1533 * Sets the orientation of the receiver, which must be one |
1214 * of <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>. | 1534 * of <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>. |
1225 orientation &= mask; | 1545 orientation &= mask; |
1226 if (orientation is 0) return; | 1546 if (orientation is 0) return; |
1227 if ((orientation & DWT.LEFT_TO_RIGHT) !is 0) orientation = DWT.LEFT_TO_RIGHT; | 1547 if ((orientation & DWT.LEFT_TO_RIGHT) !is 0) orientation = DWT.LEFT_TO_RIGHT; |
1228 if (this.orientation is orientation) return; | 1548 if (this.orientation is orientation) return; |
1229 this.orientation = orientation; | 1549 this.orientation = orientation; |
1230 freeRuns(); | 1550 NSAutoreleasePool pool = null; |
1551 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); | |
1552 try { | |
1553 freeRuns(); | |
1554 } finally { | |
1555 if (pool !is null) pool.release(); | |
1556 } | |
1231 } | 1557 } |
1232 | 1558 |
1233 /** | 1559 /** |
1234 * Sets the offsets of the receiver's text segments. Text segments are used to | 1560 * Sets the offsets of the receiver's text segments. Text segments are used to |
1235 * override the default behaviour of the bidirectional algorithm. | 1561 * override the default behaviour of the bidirectional algorithm. |
1258 if (this.segments[i] !is segments[i]) break; | 1584 if (this.segments[i] !is segments[i]) break; |
1259 } | 1585 } |
1260 if (i is segments.length) return; | 1586 if (i is segments.length) return; |
1261 } | 1587 } |
1262 } | 1588 } |
1263 freeRuns(); | 1589 NSAutoreleasePool pool = null; |
1264 this.segments = segments; | 1590 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1591 try { | |
1592 freeRuns(); | |
1593 this.segments = segments; | |
1594 } finally { | |
1595 if (pool !is null) pool.release(); | |
1596 } | |
1265 } | 1597 } |
1266 | 1598 |
1267 /** | 1599 /** |
1268 * Sets the line spacing of the receiver. The line spacing | 1600 * Sets the line spacing of the receiver. The line spacing |
1269 * is the space left between lines. | 1601 * is the space left between lines. |
1279 */ | 1611 */ |
1280 public void setSpacing (int spacing) { | 1612 public void setSpacing (int spacing) { |
1281 checkLayout(); | 1613 checkLayout(); |
1282 if (spacing < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 1614 if (spacing < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
1283 if (this.spacing is spacing) return; | 1615 if (this.spacing is spacing) return; |
1284 freeRuns(); | 1616 NSAutoreleasePool pool = null; |
1285 this.spacing = spacing; | 1617 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1618 try { | |
1619 freeRuns(); | |
1620 this.spacing = spacing; | |
1621 } finally { | |
1622 if (pool !is null) pool.release(); | |
1623 } | |
1286 } | 1624 } |
1287 | 1625 |
1288 /** | 1626 /** |
1289 * Sets the style of the receiver for the specified range. Styles previously | 1627 * Sets the style of the receiver for the specified range. Styles previously |
1290 * set for that range will be overwritten. The start and end offsets are | 1628 * set for that range will be overwritten. The start and end offsets are |
1298 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | 1636 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> |
1299 * </ul> | 1637 * </ul> |
1300 */ | 1638 */ |
1301 public void setStyle (TextStyle style, int start, int end) { | 1639 public void setStyle (TextStyle style, int start, int end) { |
1302 checkLayout(); | 1640 checkLayout(); |
1303 int length = text.length(); | 1641 NSAutoreleasePool pool = null; |
1304 if (length is 0) return; | 1642 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1305 if (start > end) return; | 1643 try { |
1306 start = Math.min(Math.max(0, start), length - 1); | 1644 int length = text.length(); |
1307 end = Math.min(Math.max(0, end), length - 1); | 1645 if (length is 0) return; |
1308 int low = -1; | 1646 if (start > end) return; |
1309 int high = styles.length; | 1647 start = Math.min(Math.max(0, start), length - 1); |
1310 while (high - low > 1) { | 1648 end = Math.min(Math.max(0, end), length - 1); |
1311 int index = (high + low) / 2; | 1649 int low = -1; |
1312 if (styles[index + 1].start > start) { | 1650 int high = styles.length; |
1313 high = index; | 1651 while (high - low > 1) { |
1314 } else { | 1652 int index = (high + low) / 2; |
1315 low = index; | 1653 if (styles[index + 1].start > start) { |
1316 } | 1654 high = index; |
1317 } | |
1318 if (0 <= high && high < styles.length) { | |
1319 StyleItem item = styles[high]; | |
1320 if (item.start is start && styles[high + 1].start - 1 is end) { | |
1321 if (style is null) { | |
1322 if (item.style is null) return; | |
1323 } else { | 1655 } else { |
1324 if (style.equals(item.style)) return; | 1656 low = index; |
1325 } | 1657 } |
1326 } | 1658 } |
1327 } | 1659 if (0 <= high && high < styles.length) { |
1328 freeRuns(); | 1660 StyleItem item = styles[high]; |
1329 int modifyStart = high; | 1661 if (item.start is start && styles[high + 1].start - 1 is end) { |
1330 int modifyEnd = modifyStart; | 1662 if (style is null) { |
1331 while (modifyEnd < styles.length) { | 1663 if (item.style is null) return; |
1332 if (styles[modifyEnd + 1].start > end) break; | 1664 } else { |
1333 modifyEnd++; | 1665 if (style.equals(item.style)) return; |
1334 } | 1666 } |
1335 if (modifyStart is modifyEnd) { | 1667 } |
1336 int styleStart = styles[modifyStart].start; | 1668 } |
1337 int styleEnd = styles[modifyEnd + 1].start - 1; | 1669 freeRuns(); |
1338 if (styleStart is start && styleEnd is end) { | 1670 int modifyStart = high; |
1339 styles[modifyStart].style = style; | 1671 int modifyEnd = modifyStart; |
1340 return; | 1672 while (modifyEnd < styles.length) { |
1341 } | 1673 if (styles[modifyEnd + 1].start > end) break; |
1342 if (styleStart !is start && styleEnd !is end) { | 1674 modifyEnd++; |
1343 StyleItem[] newStyles = new StyleItem[styles.length + 2]; | 1675 } |
1344 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); | 1676 if (modifyStart is modifyEnd) { |
1345 StyleItem item = new StyleItem(); | 1677 int styleStart = styles[modifyStart].start; |
1346 item.start = start; | 1678 int styleEnd = styles[modifyEnd + 1].start - 1; |
1347 item.style = style; | 1679 if (styleStart is start && styleEnd is end) { |
1348 newStyles[modifyStart + 1] = item; | 1680 styles[modifyStart].style = style; |
1349 item = new StyleItem(); | 1681 return; |
1350 item.start = end + 1; | 1682 } |
1351 item.style = styles[modifyStart].style; | 1683 if (styleStart !is start && styleEnd !is end) { |
1352 newStyles[modifyStart + 2] = item; | 1684 StyleItem[] newStyles = new StyleItem[styles.length + 2]; |
1353 System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1); | 1685 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); |
1354 styles = newStyles; | 1686 StyleItem item = new StyleItem(); |
1355 return; | 1687 item.start = start; |
1356 } | 1688 item.style = style; |
1357 } | 1689 newStyles[modifyStart + 1] = item; |
1358 if (start is styles[modifyStart].start) modifyStart--; | 1690 item = new StyleItem(); |
1359 if (end is styles[modifyEnd + 1].start - 1) modifyEnd++; | 1691 item.start = end + 1; |
1360 int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1); | 1692 item.style = styles[modifyStart].style; |
1361 StyleItem[] newStyles = new StyleItem[newLength]; | 1693 newStyles[modifyStart + 2] = item; |
1362 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); | 1694 System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1); |
1363 StyleItem item = new StyleItem(); | 1695 styles = newStyles; |
1364 item.start = start; | 1696 return; |
1365 item.style = style; | 1697 } |
1366 newStyles[modifyStart + 1] = item; | 1698 } |
1367 styles[modifyEnd].start = end + 1; | 1699 if (start is styles[modifyStart].start) modifyStart--; |
1368 System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd); | 1700 if (end is styles[modifyEnd + 1].start - 1) modifyEnd++; |
1369 styles = newStyles; | 1701 int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1); |
1702 StyleItem[] newStyles = new StyleItem[newLength]; | |
1703 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); | |
1704 StyleItem item = new StyleItem(); | |
1705 item.start = start; | |
1706 item.style = style; | |
1707 newStyles[modifyStart + 1] = item; | |
1708 styles[modifyEnd].start = end + 1; | |
1709 System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd); | |
1710 styles = newStyles; | |
1711 } finally { | |
1712 if (pool !is null) pool.release(); | |
1713 } | |
1370 } | 1714 } |
1371 | 1715 |
1372 /** | 1716 /** |
1373 * Sets the receiver's tab list. Each value in the tab list specifies | 1717 * Sets the receiver's tab list. Each value in the tab list specifies |
1374 * the space in pixels from the origin of the text layout to the respective | 1718 * the space in pixels from the origin of the text layout to the respective |
1390 if (this.tabs[i] !is tabs[i]) break; | 1734 if (this.tabs[i] !is tabs[i]) break; |
1391 } | 1735 } |
1392 if (i is tabs.length) return; | 1736 if (i is tabs.length) return; |
1393 } | 1737 } |
1394 } | 1738 } |
1395 freeRuns(); | 1739 NSAutoreleasePool pool = null; |
1396 this.tabs = tabs; | 1740 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1741 try { | |
1742 freeRuns(); | |
1743 this.tabs = tabs; | |
1744 } finally { | |
1745 if (pool !is null) pool.release(); | |
1746 } | |
1397 } | 1747 } |
1398 | 1748 |
1399 /** | 1749 /** |
1400 * Sets the receiver's text. | 1750 * Sets the receiver's text. |
1401 * | 1751 * |
1410 */ | 1760 */ |
1411 public void setText (String text) { | 1761 public void setText (String text) { |
1412 checkLayout (); | 1762 checkLayout (); |
1413 if (text is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); | 1763 if (text is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); |
1414 if (text.equals(this.text)) return; | 1764 if (text.equals(this.text)) return; |
1415 freeRuns(); | 1765 NSAutoreleasePool pool = null; |
1416 this.text = text; | 1766 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1417 styles = new StyleItem[2]; | 1767 try { |
1418 styles[0] = new StyleItem(); | 1768 freeRuns(); |
1419 styles[1] = new StyleItem(); | 1769 this.text = text; |
1420 styles[styles.length - 1].start = text.length(); | 1770 styles = new StyleItem[2]; |
1771 styles[0] = new StyleItem(); | |
1772 styles[1] = new StyleItem(); | |
1773 styles[styles.length - 1].start = text.length(); | |
1774 } finally { | |
1775 if (pool !is null) pool.release(); | |
1776 } | |
1421 } | 1777 } |
1422 | 1778 |
1423 /** | 1779 /** |
1424 * Sets the line width of the receiver, which determines how | 1780 * Sets the line width of the receiver, which determines how |
1425 * text should be wrapped and aligned. The default value is | 1781 * text should be wrapped and aligned. The default value is |
1438 */ | 1794 */ |
1439 public void setWidth (int width) { | 1795 public void setWidth (int width) { |
1440 checkLayout(); | 1796 checkLayout(); |
1441 if (width < -1 || width is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); | 1797 if (width < -1 || width is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
1442 if (this.wrapWidth is width) return; | 1798 if (this.wrapWidth is width) return; |
1443 freeRuns(); | 1799 NSAutoreleasePool pool = null; |
1444 this.wrapWidth = width; | 1800 if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); |
1801 try { | |
1802 freeRuns(); | |
1803 this.wrapWidth = width; | |
1804 } finally { | |
1805 if (pool !is null) pool.release(); | |
1806 } | |
1445 } | 1807 } |
1446 | 1808 |
1447 /** | 1809 /** |
1448 * Returns a string containing a concise, human-readable | 1810 * Returns a string containing a concise, human-readable |
1449 * description of the receiver. | 1811 * description of the receiver. |