Mercurial > projects > dwt-addons
annotate dwtx/ui/internal/forms/widgets/TextSegment.d @ 90:7ffeace6c47f
Update 3.4M7 to 3.4
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 06 Jul 2008 23:30:07 +0200 |
parents | 26c6c9dfd13c |
children | 11e8159caf7a |
rev | line source |
---|---|
75 | 1 /******************************************************************************* |
90 | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
75 | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.ui.internal.forms.widgets.TextSegment; | |
14 | |
15 import dwtx.ui.internal.forms.widgets.ParagraphSegment; | |
16 import dwtx.ui.internal.forms.widgets.Locator; | |
17 import dwtx.ui.internal.forms.widgets.SelectionData; | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
18 import dwtx.ui.internal.forms.widgets.FormTextModel; |
75 | 19 |
90 | 20 // import com.ibm.icu.text.BreakIterator; |
21 | |
75 | 22 import dwt.DWT; |
23 import dwt.graphics.Color; | |
24 import dwt.graphics.Font; | |
25 import dwt.graphics.FontMetrics; | |
26 import dwt.graphics.GC; | |
27 import dwt.graphics.Point; | |
28 import dwt.graphics.Rectangle; | |
29 | |
30 import dwt.dwthelper.utils; | |
90 | 31 // import mango.icu.ULocale; |
32 // import mango.icu.UString; | |
33 // import mango.icu.UBreakIterator; | |
34 import dwtx.dwtxhelper.BreakIterator; | |
75 | 35 import tango.util.collection.ArraySeq; |
36 | |
37 /** | |
38 * @version 1.0 | |
39 * @author | |
40 */ | |
41 public class TextSegment : ParagraphSegment { | |
42 | |
43 private String colorId; | |
44 | |
45 private String fontId; | |
46 | |
47 private String text; | |
48 | |
49 protected bool underline; | |
50 | |
51 private bool wrapAllowed = true; | |
52 | |
53 protected ArraySeq!(Object) areaRectangles; | |
54 | |
55 private TextFragment[] textFragments; | |
56 | |
57 class AreaRectangle { | |
58 Rectangle rect; | |
59 | |
60 int from, to; | |
61 | |
62 public this(Rectangle rect, int from, int to) { | |
63 this.rect = rect; | |
64 this.from = from; | |
65 this.to = to; | |
66 } | |
67 | |
68 public bool contains(int x, int y) { | |
69 return rect.contains(x, y); | |
70 } | |
71 | |
72 public bool intersects(Rectangle region) { | |
73 return rect.intersects(region); | |
74 } | |
75 | |
76 public String getText() { | |
77 if (from is 0 && to is -1) | |
78 return this.outer.getText(); | |
79 if (from > 0 && to is -1) | |
80 return this.outer.getText().substring(from); | |
81 return this.outer.getText().substring(from, to); | |
82 } | |
83 } | |
84 | |
85 static class SelectionRange { | |
86 public int start; | |
87 | |
88 public int stop; | |
89 | |
90 public this() { | |
91 reset(); | |
92 } | |
93 | |
94 public void reset() { | |
95 start = -1; | |
96 stop = -1; | |
97 } | |
98 } | |
99 | |
100 static class TextFragment { | |
101 short index; | |
102 | |
103 short length; | |
104 | |
105 public this(short index, short length) { | |
106 this.index = index; | |
107 this.length = length; | |
108 } | |
109 } | |
110 | |
111 public this(String text, String fontId) { | |
112 this(text, fontId, null, true); | |
113 } | |
114 | |
115 public this(String text, String fontId, String colorId) { | |
116 this(text, fontId, colorId, true); | |
117 } | |
118 | |
119 public this(String text, String fontId, String colorId, bool wrapAllowed) { | |
120 areaRectangles = new ArraySeq!(Object); | |
121 this.text = cleanup(text); | |
122 this.fontId = fontId; | |
123 this.colorId = colorId; | |
124 this.wrapAllowed = wrapAllowed; | |
125 } | |
126 | |
127 private String cleanup(String text) { | |
128 StringBuffer buf = new StringBuffer(); | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
129 for (int i = 0; i < text.length; i++) { |
75 | 130 char c = text.charAt(i); |
131 if (c is '\n' || c is '\r' || c is '\f') { | |
132 if (i > 0) | |
133 buf.append(' '); | |
134 } else | |
135 buf.append(c); | |
136 } | |
137 return buf.toString(); | |
138 } | |
139 | |
140 public void setWordWrapAllowed(bool value) { | |
141 wrapAllowed = value; | |
142 } | |
143 | |
144 public bool isWordWrapAllowed() { | |
145 return wrapAllowed; | |
146 } | |
147 | |
148 public bool isSelectable() { | |
149 return false; | |
150 } | |
151 | |
152 public String getColorId() { | |
153 return colorId; | |
154 } | |
155 | |
156 public String getText() { | |
157 return text; | |
158 } | |
159 | |
160 void setText(String text) { | |
161 this.text = cleanup(text); | |
162 textFragments = null; | |
163 } | |
164 | |
165 void setColorId(String colorId) { | |
166 this.colorId = colorId; | |
167 } | |
168 | |
169 void setFontId(String fontId) { | |
170 this.fontId = fontId; | |
171 textFragments = null; | |
172 } | |
173 | |
174 public bool contains(int x, int y) { | |
175 for (int i = 0; i < areaRectangles.size(); i++) { | |
176 AreaRectangle ar = cast(AreaRectangle) areaRectangles.get(i); | |
177 if (ar.contains(x, y)) | |
178 return true; | |
179 if (i<areaRectangles.size()-1) { | |
180 // test the gap | |
181 Rectangle top = ar.rect; | |
182 Rectangle bot = (cast(AreaRectangle)areaRectangles.get(i+1)).rect; | |
183 if (y >= top.y+top.height && y < bot.y) { | |
184 // in the gap | |
185 int left = Math.max(top.x, bot.x); | |
186 int right = Math.min(top.x+top.width, bot.x+bot.width); | |
187 if (x>=left && x<=right) { | |
188 return true; | |
189 } | |
190 } | |
191 } | |
192 } | |
193 return false; | |
194 } | |
195 | |
196 public bool intersects(Rectangle rect) { | |
197 for (int i = 0; i < areaRectangles.size(); i++) { | |
198 AreaRectangle ar = cast(AreaRectangle) areaRectangles.get(i); | |
199 if (ar.intersects(rect)) | |
200 return true; | |
201 if (i<areaRectangles.size()-1) { | |
202 // test the gap | |
203 Rectangle top = ar.rect; | |
204 Rectangle bot = (cast(AreaRectangle)areaRectangles.get(i+1)).rect; | |
205 if (top.y+top.height < bot.y) { | |
206 int y = top.y+top.height; | |
207 int height = bot.y-y; | |
208 int left = Math.max(top.x, bot.x); | |
209 int right = Math.min(top.x+top.width, bot.x+bot.width); | |
210 Rectangle gap = new Rectangle(left, y, right-left, height); | |
211 if (gap.intersects(rect)) | |
212 return true; | |
213 } | |
214 } | |
215 } | |
216 return false; | |
217 } | |
218 | |
219 public Rectangle getBounds() { | |
220 int x = 0, y = 0; | |
221 int width = 0, height = 0; | |
222 | |
223 for (int i = 0; i < areaRectangles.size(); i++) { | |
224 AreaRectangle ar = cast(AreaRectangle) areaRectangles.get(i); | |
225 if (i is 0) { | |
226 x = ar.rect.x; | |
227 y = ar.rect.y; | |
228 } else | |
229 x = Math.min(ar.rect.x, x); | |
230 width = Math.max(ar.rect.width, width); | |
231 height += ar.rect.height; | |
232 } | |
233 return new Rectangle(x, y, width, height); | |
234 } | |
235 | |
236 public bool advanceLocator(GC gc, int wHint, Locator locator, | |
237 Hashtable objectTable, bool computeHeightOnly) { | |
238 Font oldFont = null; | |
239 if (fontId !is null) { | |
240 oldFont = gc.getFont(); | |
241 Font newFont = cast(Font) objectTable.get(fontId); | |
242 if (newFont !is null) | |
243 gc.setFont(newFont); | |
244 } | |
245 FontMetrics fm = gc.getFontMetrics(); | |
246 int lineHeight = fm.getHeight(); | |
247 bool newLine = false; | |
248 | |
249 if (wHint is DWT.DEFAULT || !wrapAllowed) { | |
250 Point extent = gc.textExtent(text); | |
251 int totalExtent = locator.x+extent.x; | |
252 if (isSelectable()) | |
253 totalExtent+=1; | |
254 | |
255 if (wHint !is DWT.DEFAULT && totalExtent > wHint) { | |
256 // new line | |
257 locator.x = locator.indent; | |
258 locator.y += locator.rowHeight; | |
259 if (computeHeightOnly) | |
260 locator.collectHeights(); | |
261 locator.rowHeight = 0; | |
262 locator.leading = 0; | |
263 newLine = true; | |
264 } | |
265 int width = extent.x; | |
266 if (isSelectable()) | |
267 width += 1; | |
268 locator.x += width; | |
269 locator.width = locator.indent + width; | |
270 locator.rowHeight = Math.max(locator.rowHeight, extent.y); | |
271 locator.leading = Math.max(locator.leading, fm.getLeading()); | |
272 return newLine; | |
273 } | |
274 | |
275 computeTextFragments(gc); | |
276 | |
277 int width = 0; | |
278 Point lineExtent = new Point(0, 0); | |
279 | |
280 for (int i = 0; i < textFragments.length; i++) { | |
281 TextFragment textFragment = textFragments[i]; | |
282 int currentExtent = locator.x + lineExtent.x; | |
283 | |
284 if (isSelectable()) | |
285 currentExtent += 1; | |
286 | |
90 | 287 // i !is 0 || locator.x > locator.getStartX() + (isSelectable() ? 1 : 0) means: |
288 // only wrap on the first fragment if we are not at the start of a line | |
289 if ((i !is 0 || locator.x > locator.getStartX() + (isSelectable() ? 1 : 0)) && currentExtent + textFragment.length > wHint) { | |
75 | 290 // overflow |
291 int lineWidth = currentExtent; | |
292 locator.rowHeight = Math.max(locator.rowHeight, lineExtent.y); | |
293 locator.leading = Math.max(locator.leading, fm.getLeading()); | |
294 if (computeHeightOnly) | |
295 locator.collectHeights(); | |
296 locator.x = locator.indent; | |
297 locator.y += locator.rowHeight; | |
298 locator.rowHeight = 0; | |
299 locator.leading = 0; | |
300 lineExtent.x = 0; | |
301 lineExtent.y = 0; | |
302 width = Math.max(width, lineWidth); | |
303 newLine = true; | |
304 } | |
305 lineExtent.x += textFragment.length; | |
306 lineExtent.y = Math.max(lineHeight, lineExtent.y); | |
307 } | |
308 int lineWidth = lineExtent.x; | |
309 if (isSelectable()) | |
310 lineWidth += 1; | |
311 locator.x += lineWidth; | |
312 locator.width = width; | |
313 locator.rowHeight = Math.max(locator.rowHeight, lineExtent.y); | |
314 locator.leading = Math.max(locator.leading, fm.getLeading()); | |
315 if (oldFont !is null) { | |
316 gc.setFont(oldFont); | |
317 } | |
318 return newLine; | |
319 } | |
320 | |
321 /** | |
322 * @param gc | |
323 * @param width | |
324 * @param locator | |
325 * @param selected | |
326 * @param selData | |
327 * @param color | |
328 * @param fm | |
329 * @param lineHeight | |
330 * @param descent | |
331 */ | |
332 private void layoutWithoutWrapping(GC gc, int width, Locator locator, | |
333 bool selected, FontMetrics fm, int lineHeight, int descent) { | |
334 Point extent = gc.textExtent(text); | |
335 int ewidth = extent.x; | |
336 if (isSelectable()) | |
337 ewidth += 1; | |
338 if (locator.x + ewidth > width-locator.marginWidth) { | |
339 // new line | |
340 locator.resetCaret(); | |
341 locator.y += locator.rowHeight; | |
342 locator.rowHeight = 0; | |
343 locator.rowCounter++; | |
344 } | |
345 int ly = locator.getBaseline(fm.getHeight() - fm.getLeading()); | |
346 //int lineY = ly + lineHeight - descent + 1; | |
347 Rectangle br = new Rectangle(locator.x, ly, ewidth, | |
348 lineHeight - descent + 3); | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
349 areaRectangles.append(new AreaRectangle(br, 0, -1)); |
75 | 350 locator.x += ewidth; |
351 locator.width = ewidth; | |
352 locator.rowHeight = Math.max(locator.rowHeight, extent.y); | |
353 } | |
354 | |
355 protected int convertOffsetToStringIndex(GC gc, String s, int x, | |
356 int swidth, int selOffset) { | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
357 int index = s.length; |
75 | 358 while (index > 0 && x + swidth > selOffset) { |
359 index--; | |
360 String ss = s.substring(0, index); | |
361 swidth = gc.textExtent(ss).x; | |
362 } | |
363 return index; | |
364 } | |
365 | |
366 public void paintFocus(GC gc, Color bg, Color fg, bool selected, | |
367 Rectangle repaintRegion) { | |
368 if (areaRectangles is null) | |
369 return; | |
370 for (int i = 0; i < areaRectangles.size(); i++) { | |
371 AreaRectangle areaRectangle = cast(AreaRectangle) areaRectangles.get(i); | |
372 Rectangle br = areaRectangle.rect; | |
373 int bx = br.x; | |
374 int by = br.y; | |
375 if (repaintRegion !is null) { | |
376 bx -= repaintRegion.x; | |
377 by -= repaintRegion.y; | |
378 } | |
379 if (selected) { | |
380 gc.setBackground(bg); | |
381 gc.setForeground(fg); | |
382 gc.drawFocus(bx, by, br.width, br.height); | |
383 } else { | |
384 gc.setForeground(bg); | |
385 gc.drawRectangle(bx, by, br.width - 1, br.height - 1); | |
386 } | |
387 } | |
388 } | |
389 | |
390 public void paint(GC gc, bool hover, Hashtable resourceTable, | |
391 bool selected, SelectionData selData, Rectangle repaintRegion) { | |
392 this.paint(gc, hover, resourceTable, selected, false, selData, | |
393 repaintRegion); | |
394 } | |
395 | |
396 protected void paint(GC gc, bool hover, Hashtable resourceTable, | |
397 bool selected, bool rollover, SelectionData selData, | |
398 Rectangle repaintRegion) { | |
399 Font oldFont = null; | |
400 Color oldColor = null; | |
401 Color oldBg = null; | |
402 | |
403 // apply segment-specific font, color and background | |
404 if (fontId !is null) { | |
405 oldFont = gc.getFont(); | |
406 Font newFont = cast(Font) resourceTable.get(fontId); | |
407 if (newFont !is null) | |
408 gc.setFont(newFont); | |
409 } | |
410 if (!hover && colorId !is null) { | |
411 oldColor = gc.getForeground(); | |
412 Color newColor = cast(Color) resourceTable.get(colorId); | |
413 if (newColor !is null) | |
414 gc.setForeground(newColor); | |
415 } | |
416 oldBg = gc.getBackground(); | |
417 | |
418 FontMetrics fm = gc.getFontMetrics(); | |
419 int lineHeight = fm.getHeight(); | |
420 int descent = fm.getDescent(); | |
421 | |
422 // paint area rectangles of the segment | |
423 for (int i = 0; i < areaRectangles.size(); i++) { | |
424 AreaRectangle areaRectangle = cast(AreaRectangle) areaRectangles.get(i); | |
425 Rectangle rect = areaRectangle.rect; | |
426 String text = areaRectangle.getText(); | |
427 Point extent = gc.textExtent(text); | |
428 int textX = rect.x + (isSelectable()?1:0); | |
429 int lineY = rect.y + lineHeight - descent + 1; | |
430 paintString(gc, text, extent.x, textX, rect.y, lineY, selData, | |
431 rect, hover, rollover, repaintRegion); | |
432 if (selected) { | |
433 int fx = rect.x; | |
434 int fy = rect.y; | |
435 if (repaintRegion !is null) { | |
436 fx -= repaintRegion.x; | |
437 fy -= repaintRegion.y; | |
438 } | |
439 //To avoid partially cancelling the focus by painting over | |
440 //X-ORed pixels, first cancel it yourself | |
441 Color fg = gc.getForeground(); | |
442 gc.setForeground(oldBg); | |
443 gc.drawRectangle(fx, fy, rect.width - 1, rect.height - 1); | |
444 gc.setForeground(fg); | |
445 gc.drawFocus(fx, fy, rect.width, rect.height); | |
446 } | |
447 } | |
448 // restore GC resources | |
449 if (oldFont !is null) { | |
450 gc.setFont(oldFont); | |
451 } | |
452 if (oldColor !is null) { | |
453 gc.setForeground(oldColor); | |
454 } | |
455 if (oldBg !is null) { | |
456 gc.setBackground(oldBg); | |
457 } | |
458 } | |
459 | |
460 public void computeSelection(GC gc, Hashtable resourceTable, SelectionData selData) { | |
461 Font oldFont = null; | |
462 | |
463 if (fontId !is null) { | |
464 oldFont = gc.getFont(); | |
465 Font newFont = cast(Font) resourceTable.get(fontId); | |
466 if (newFont !is null) | |
467 gc.setFont(newFont); | |
468 } | |
469 | |
470 for (int i = 0; i < areaRectangles.size(); i++) { | |
471 AreaRectangle areaRectangle = cast(AreaRectangle) areaRectangles.get(i); | |
472 Rectangle rect = areaRectangle.rect; | |
473 String text = areaRectangle.getText(); | |
474 Point extent = gc.textExtent(text); | |
475 computeSelection(gc, text, extent.x, selData, | |
476 rect); | |
477 } | |
478 // restore GC resources | |
479 if (oldFont !is null) { | |
480 gc.setFont(oldFont); | |
481 } | |
482 } | |
483 | |
484 private void paintString(GC gc, String s, int swidth, int x, int y, | |
485 int lineY, SelectionData selData, Rectangle bounds, bool hover, | |
486 bool rolloverMode, Rectangle repaintRegion) { | |
487 // repaints one area rectangle | |
488 if (selData !is null && selData.isEnclosed()) { | |
489 Color savedBg = gc.getBackground(); | |
490 Color savedFg = gc.getForeground(); | |
491 int leftOffset = selData.getLeftOffset(bounds.height); | |
492 int rightOffset = selData.getRightOffset(bounds.height); | |
493 bool firstRow = selData.isFirstSelectionRow(bounds.y, | |
494 bounds.height); | |
495 bool lastRow = selData.isLastSelectionRow(bounds.y, | |
496 bounds.height); | |
497 bool selectedRow = selData | |
498 .isSelectedRow(bounds.y, bounds.height); | |
499 | |
500 int sstart = -1; | |
501 int sstop = -1; | |
502 | |
503 if ((firstRow && x + swidth < leftOffset) | |
504 || (lastRow && x > rightOffset)) { | |
505 paintStringSegment(gc, s, gc.textExtent(s).x, x, y, lineY, | |
506 hover, rolloverMode, repaintRegion); | |
507 return; | |
508 } | |
509 | |
510 if (firstRow && bounds.x + swidth > leftOffset) { | |
511 sstart = convertOffsetToStringIndex(gc, s, bounds.x, swidth, | |
512 leftOffset); | |
513 } | |
514 if (lastRow && bounds.x + swidth > rightOffset) { | |
515 sstop = convertOffsetToStringIndex(gc, s, bounds.x, swidth, | |
516 rightOffset); | |
517 } | |
518 | |
519 if (firstRow && sstart !is -1) { | |
520 String left = s.substring(0, sstart); | |
521 int width = gc.textExtent(left).x; | |
522 paintStringSegment(gc, left, width, x, y, lineY, hover, | |
523 rolloverMode, repaintRegion); | |
524 x += width; | |
525 } | |
526 if (selectedRow) { | |
527 int lindex = sstart !is -1 ? sstart : 0; | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
528 int rindex = sstop !is -1 ? sstop : s.length; |
75 | 529 String mid = s.substring(lindex, rindex); |
530 Point extent = gc.textExtent(mid); | |
531 gc.setForeground(selData.fg); | |
532 gc.setBackground(selData.bg); | |
533 gc.fillRectangle(x, y, extent.x, extent.y); | |
534 paintStringSegment(gc, mid, extent.x, x, y, lineY, hover, | |
535 rolloverMode, repaintRegion); | |
536 x += extent.x; | |
537 gc.setForeground(savedFg); | |
538 gc.setBackground(savedBg); | |
539 } else { | |
540 paintStringSegment(gc, s, gc.textExtent(s).x, x, y, lineY, | |
541 hover, rolloverMode, repaintRegion); | |
542 } | |
543 if (lastRow && sstop !is -1) { | |
544 String right = s.substring(sstop); | |
545 paintStringSegment(gc, right, gc.textExtent(right).x, x, y, | |
546 lineY, hover, rolloverMode, repaintRegion); | |
547 } | |
548 } else { | |
549 paintStringSegment(gc, s, gc.textExtent(s).x, x, y, lineY, hover, | |
550 rolloverMode, repaintRegion); | |
551 } | |
552 } | |
553 | |
554 private void computeSelection(GC gc, String s, int swidth, SelectionData selData, Rectangle bounds) { | |
555 int leftOffset = selData.getLeftOffset(bounds.height); | |
556 int rightOffset = selData.getRightOffset(bounds.height); | |
557 bool firstRow = selData.isFirstSelectionRow(bounds.y, bounds.height); | |
558 bool lastRow = selData.isLastSelectionRow(bounds.y, bounds.height); | |
559 bool selectedRow = selData.isSelectedRow(bounds.y, bounds.height); | |
560 | |
561 int sstart = -1; | |
562 int sstop = -1; | |
563 | |
564 if (firstRow && bounds.x + swidth > leftOffset) { | |
565 sstart = convertOffsetToStringIndex(gc, s, bounds.x, swidth, | |
566 leftOffset); | |
567 } | |
568 if (lastRow && bounds.x + swidth > rightOffset) { | |
569 sstop = convertOffsetToStringIndex(gc, s, bounds.x, swidth, | |
570 rightOffset); | |
571 } | |
572 | |
573 if (selectedRow) { | |
574 int lindex = sstart !is -1 ? sstart : 0; | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
575 int rindex = sstop !is -1 ? sstop : s.length; |
75 | 576 String mid = s.substring(lindex, rindex); |
577 selData.addSegment(mid); | |
578 } | |
579 } | |
580 | |
581 /** | |
582 * @param gc | |
583 * @param s | |
584 * @param x | |
585 * @param y | |
586 * @param lineY | |
587 * @param hover | |
588 * @param rolloverMode | |
589 */ | |
590 private void paintStringSegment(GC gc, String s, int swidth, int x, int y, | |
591 int lineY, bool hover, bool rolloverMode, | |
592 Rectangle repaintRegion) { | |
593 bool reverse = false; | |
594 int clipX = x; | |
595 int clipY = y; | |
596 int clipLineY = lineY; | |
597 if (repaintRegion !is null) { | |
598 clipX -= repaintRegion.x; | |
599 clipY -= repaintRegion.y; | |
600 clipLineY -= repaintRegion.y; | |
601 } | |
602 if (underline || hover || rolloverMode) { | |
603 if (rolloverMode && !hover) | |
604 reverse = true; | |
605 } | |
606 if (reverse) { | |
607 drawUnderline(gc, swidth, clipX, clipLineY, hover, rolloverMode); | |
90 | 608 drawString(gc, s, clipX, clipY); |
75 | 609 } else { |
90 | 610 drawString(gc, s, clipX, clipY); |
75 | 611 drawUnderline(gc, swidth, clipX, clipLineY, hover, rolloverMode); |
612 } | |
613 } | |
614 | |
90 | 615 protected void drawString(GC gc, String s, int clipX, int clipY) { |
616 gc.drawString(s, clipX, clipY, true); | |
617 } | |
618 | |
75 | 619 private void drawUnderline(GC gc, int swidth, int x, int y, bool hover, |
620 bool rolloverMode) { | |
621 if (underline || hover || rolloverMode) { | |
622 Color saved = null; | |
623 if (rolloverMode && !hover) { | |
624 saved = gc.getForeground(); | |
625 gc.setForeground(gc.getBackground()); | |
626 } | |
627 gc.drawLine(x, y, x + swidth-1, y); | |
628 if (saved !is null) | |
629 gc.setForeground(saved); | |
630 } | |
631 } | |
632 | |
633 /* | |
634 * (non-Javadoc) | |
635 * | |
636 * @see dwtx.ui.internal.forms.widgets.ParagraphSegment#layout(dwt.graphics.GC, | |
637 * int, dwtx.ui.internal.forms.widgets.Locator, | |
638 * java.util.Hashtable, bool, | |
639 * dwtx.ui.internal.forms.widgets.SelectionData) | |
640 */ | |
641 public void layout(GC gc, int width, Locator locator, | |
642 Hashtable resourceTable, bool selected) { | |
643 Font oldFont = null; | |
644 | |
645 areaRectangles.clear(); | |
646 | |
647 if (fontId !is null) { | |
648 oldFont = gc.getFont(); | |
649 Font newFont = cast(Font) resourceTable.get(fontId); | |
650 if (newFont !is null) | |
651 gc.setFont(newFont); | |
652 } | |
653 FontMetrics fm = gc.getFontMetrics(); | |
654 int lineHeight = fm.getHeight(); | |
655 int descent = fm.getDescent(); | |
656 | |
657 if (!wrapAllowed) { | |
658 layoutWithoutWrapping(gc, width, locator, selected, fm, lineHeight, | |
659 descent); | |
660 } else { | |
661 int lineStart = 0; | |
662 int lastLoc = 0; | |
663 Point lineExtent = new Point(0, 0); | |
664 computeTextFragments(gc); | |
665 int rightEdge = width-locator.marginWidth; | |
666 for (int i = 0; i < textFragments.length; i++) { | |
667 TextFragment fragment = textFragments[i]; | |
668 int breakLoc = fragment.index; | |
669 if (breakLoc is 0) | |
670 continue; | |
90 | 671 // (i !is 0 || locator.x > locator.getStartX() + (isSelectable() ? 1 : 0)) means: |
672 // only wrap on the first fragment if we are not at the start of a line | |
673 if ((i !is 0 || locator.x > locator.getStartX() + (isSelectable() ? 1 : 0)) && locator.x + lineExtent.x + fragment.length > rightEdge) { | |
75 | 674 // overflow |
675 int lineWidth = locator.x + lineExtent.x; | |
676 if (isSelectable()) | |
677 lineWidth += 1; | |
678 int ly = locator.getBaseline(lineHeight - fm.getLeading()); | |
679 Rectangle br = new Rectangle(isSelectable()? | |
680 locator.x - 1:locator.x, ly, | |
681 isSelectable()?lineExtent.x + 1:lineExtent.x, lineHeight - descent + 3); | |
682 areaRectangles | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
683 .append(new AreaRectangle(br, lineStart, lastLoc)); |
75 | 684 |
685 locator.rowHeight = Math.max(locator.rowHeight, | |
686 lineExtent.y); | |
687 locator.resetCaret(); | |
688 if (isSelectable()) | |
689 locator.x += 1; | |
690 locator.y += locator.rowHeight; | |
691 locator.rowCounter++; | |
692 locator.rowHeight = 0; | |
693 lineStart = lastLoc; | |
694 lineExtent.x = 0; | |
695 lineExtent.y = 0; | |
696 } | |
697 lastLoc = breakLoc; | |
698 lineExtent.x += fragment.length; | |
699 lineExtent.y = Math.max(lineHeight, lineExtent.y); | |
700 } | |
701 //String lastLine = text.substring(lineStart, lastLoc); | |
702 int ly = locator.getBaseline(lineHeight - fm.getLeading()); | |
703 int lastWidth = lineExtent.x; | |
704 if (isSelectable()) | |
705 lastWidth += 1; | |
706 Rectangle br = new Rectangle(isSelectable()?locator.x - 1:locator.x, ly, | |
707 isSelectable()?lineExtent.x + 1:lineExtent.x, | |
708 lineHeight - descent + 3); | |
709 //int lineY = ly + lineHeight - descent + 1; | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
710 areaRectangles.append(new AreaRectangle(br, lineStart, lastLoc)); |
75 | 711 locator.x += lastWidth; |
712 locator.rowHeight = Math.max(locator.rowHeight, lineExtent.y); | |
713 } | |
714 if (oldFont !is null) { | |
715 gc.setFont(oldFont); | |
716 } | |
717 } | |
718 | |
719 private void computeTextFragments(GC gc) { | |
720 if (textFragments !is null) | |
721 return; | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
722 ArraySeq!(Object) list = new ArraySeq!(Object); |
90 | 723 auto wb = UBreakIterator.openLineIterator( ULocale.Default, getText() ); |
724 scope(exit) wb.close(); | |
75 | 725 int cursor = 0; |
90 | 726 for (int loc = wb.first(); loc !is UBreakIterator.DONE; loc = wb.next()) { |
75 | 727 if (loc is 0) |
728 continue; | |
729 String word = text.substring(cursor, loc); | |
730 Point extent = gc.textExtent(word); | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
731 list.append(new TextFragment(cast(short) loc, cast(short) extent.x)); |
75 | 732 cursor = loc; |
733 } | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
734 textFragments = arraycast!(TextFragment)(list.toArray()); |
75 | 735 } |
736 | |
737 public void clearCache(String fontId) { | |
77
26c6c9dfd13c
ui.forms compile, just FormTextModel with xml reimpl left todo
Frank Benoit <benoit@tionex.de>
parents:
75
diff
changeset
|
738 if (fontId is null && (this.fontId is null||this.fontId.equals(FormTextModel.BOLD_FONT_ID))) |
75 | 739 textFragments = null; |
740 else if (fontId !is null && this.fontId !is null && fontId.equals(this.fontId)) | |
741 textFragments = null; | |
742 } | |
743 } |