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