Changeset 213:36f5cb12e1a2 for dwt/custom/StyledText.d
- Timestamp:
- 05/17/08 11:34:28 (8 months ago)
- Files:
-
- dwt/custom/StyledText.d (modified) (43 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
dwt/custom/StyledText.d
r212 r213 57 57 import dwt.widgets.Display; 58 58 import dwt.widgets.Event; 59 import dwt.widgets.IME; 59 60 import dwt.widgets.Label; 60 61 import dwt.widgets.Listener; … … 197 198 bool editable = true; 198 199 bool wordWrap = false; 199 bool doubleClickEnabled = true; // see getDoubleClickEnabled200 bool overwrite = false; // insert/overwrite edit mode200 bool doubleClickEnabled = true; // see getDoubleClickEnabled 201 bool overwrite = false; // insert/overwrite edit mode 201 202 int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default. 202 203 int[int] keyActionMap; … … 214 215 int lastLineBottom; // the bottom pixel of the last line been replaced 215 216 bool isMirrored_; 216 bool bidiColoring = false; // apply the BIDI algorithm on text segments of the same color217 bool bidiColoring = false; // apply the BIDI algorithm on text segments of the same color 217 218 Image leftCaretBitmap = null; 218 219 Image rightCaretBitmap = null; 219 220 int caretDirection = DWT.NULL; 221 int caretWidth = 0; 220 222 Caret defaultCaret = null; 221 223 bool updateCaretDirection = true; 222 224 bool fixedLineHeight; 223 225 bool dragDetect_ = true; 226 IME ime; 224 227 225 228 int alignment; … … 261 264 int startLine; // first (wrapped) line to print 262 265 int endLine; // last (wrapped) line to print 263 bool singleLine; // widget single line mode266 bool singleLine; // widget single line mode 264 267 Point selection = null; // selected text 265 bool mirrored; // indicates the printing gc should be mirrored268 bool mirrored; // indicates the printing gc should be mirrored 266 269 int lineSpacing; 267 270 int printMargin; … … 527 530 } 528 531 if (printOptions.printLineNumbers) { 532 int numberingWidth = 0; 529 533 int count = endLine - startLine + 1; 530 StringBuffer buffer = new StringBuffer("0"); 531 while ((count /= 10) > 0) buffer.append("0"); 532 printLayout.setText(buffer.toString()); 533 int numberingWidth = printLayout.getBounds().width + printMargin; 534 String[] lineLabels = printOptions.lineLabels; 535 if (lineLabels !is null) { 536 for (int i = startLine; i < Math.min(count, lineLabels.length); i++) { 537 if (lineLabels[i] !is null) { 538 printLayout.setText(lineLabels[i]); 539 int lineWidth = printLayout.getBounds().width; 540 numberingWidth = Math.max(numberingWidth, lineWidth); 541 } 542 } 543 } else { 544 StringBuffer buffer = new StringBuffer("0"); 545 while ((count /= 10) > 0) buffer.append("0"); 546 printLayout.setText(buffer.toString()); 547 numberingWidth = printLayout.getBounds().width; 548 } 549 numberingWidth += printMargin; 534 550 if (numberingWidth > width) numberingWidth = width; 535 551 paintX += numberingWidth; … … 569 585 //draw paragraph top in the current page and paragraph bottom in the next 570 586 int height = paragraphBottom - paintY; 571 gc.setClipping( paintX, paintY,width, height);587 gc.setClipping(clientArea.x, paintY, clientArea.width, height); 572 588 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i); 589 gc.setClipping(cast(Rectangle)null); 573 590 printDecoration(page, false, printLayout); 574 591 printer.endPage(); … … 579 596 paintY = clientArea.y - height; 580 597 int layoutHeight = layout.getBounds().height; 581 gc.setClipping( paintX, clientArea.y,width, layoutHeight - height);598 gc.setClipping(clientArea.x, clientArea.y, clientArea.width, layoutHeight - height); 582 599 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i); 600 gc.setClipping(cast(Rectangle)null); 583 601 paintY += layoutHeight; 584 602 } 585 gc.setClipping(cast(Rectangle)null);586 603 } 587 604 } 588 605 printerRenderer.disposeTextLayout(layout); 589 606 } 590 if (pa intY > clientArea.y) {607 if (page <= endPage && paintY > clientArea.y) { 591 608 // close partial page 592 609 printDecoration(page, false, printLayout); … … 675 692 if (printOptions.printLineNumbers) { 676 693 FontMetrics metrics = layout.getLineMetrics(0); 677 printLayout.setAscent(metrics.getAscent() + metrics.get Descent());694 printLayout.setAscent(metrics.getAscent() + metrics.getLeading()); 678 695 printLayout.setDescent(metrics.getDescent()); 679 printLayout.setText( to!(String)(index) ); 696 String[] lineLabels = printOptions.lineLabels; 697 if (lineLabels !is null) { 698 if (0 <= index && index < lineLabels.length && lineLabels[index] !is null) { 699 printLayout.setText(lineLabels[index]); 700 } else { 701 printLayout.setText(""); 702 } 703 } else { 704 printLayout.setText( to!(String)(index) ); 705 } 680 706 int paintX = x - printMargin - printLayout.getBounds().width; 681 707 printLayout.draw(gc, paintX, y); … … 1313 1339 renderer.setContent(content); 1314 1340 renderer.setFont(getFont(), tabLength); 1315 defaultCaret = new Caret(this, DWT.NULL); 1341 ime = new IME(this, DWT.NONE); 1342 defaultCaret = new Caret(this, DWT.NONE); 1316 1343 if ((style & DWT.WRAP) !is 0) { 1317 1344 setWordWrap(true); … … 1328 1355 } 1329 1356 }; 1330 BidiUtil.addLanguageListener( handle, runnable);1357 BidiUtil.addLanguageListener(this, runnable); 1331 1358 } 1332 1359 setCaret(defaultCaret); … … 1752 1779 for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) { 1753 1780 TextLayout layout = renderer.getTextLayout(lineIndex); 1781 int wrapWidth = layout.getWidth(); 1754 1782 if (wordWrap) layout.setWidth(wHint is 0 ? 1 : wHint); 1755 1783 Rectangle rect = layout.getBounds(); 1756 1784 height += rect.height; 1757 1785 width = Math.max(width, rect.width); 1786 layout.setWidth(wrapWidth); 1758 1787 renderer.disposeTextLayout(layout); 1759 1788 if (isFixedLineHeight() && height > maxHeight) break; … … 1944 1973 } 1945 1974 if (selection.x is selection.y) return false; 1946 int offset = getOffsetAtPoint(event.x, event.y );1947 if ( offset > selection.x&& offset < selection.y) {1975 int offset = getOffsetAtPoint(event.x, event.y, null, true); 1976 if (selection.x <= offset && offset < selection.y) { 1948 1977 return dragDetect(event); 1949 1978 } … … 2237 2266 */ 2238 2267 void doContent(char key) { 2239 if (textLimit > 0 &&2240 content.getCharCount() - (selection.y - selection.x) >= textLimit) {2241 return;2242 }2243 2268 Event event = new Event(); 2244 2269 event.start = selection.x; … … 2267 2292 } 2268 2293 if (event.text !is null) { 2294 if (textLimit > 0 && content.getCharCount() - (event.end - event.start) >= textLimit) { 2295 return; 2296 } 2269 2297 sendKeyEvent(event); 2270 2298 } … … 2531 2559 int newCaretOffset = getOffsetAtPoint(x, y); 2532 2560 2533 if (clickCount > 1) { 2534 // double click word select the previous/next word. fixes bug 15610 2561 if (doubleClickEnabled && clickCount > 1) { 2535 2562 newCaretOffset = doMouseWordSelect(x, newCaretOffset, line); 2536 2563 } … … 3247 3274 Rectangle getBoundsAtOffset(int offset) { 3248 3275 int lineIndex = content.getLineAtOffset(offset); 3276 int lineOffset = content.getOffsetAtLine(lineIndex); 3249 3277 String line = content.getLine(lineIndex); 3250 3278 Rectangle bounds; 3251 3279 if (line.length !is 0) { 3252 int offsetInLine = offset - content.getOffsetAtLine(lineIndex);3280 int offsetInLine = offset - lineOffset; 3253 3281 TextLayout layout = renderer.getTextLayout(lineIndex); 3254 3282 bounds = layout.getBounds(offsetInLine, offsetInLine); … … 3257 3285 bounds = new Rectangle (0, 0, 0, renderer.getLineHeight()); 3258 3286 } 3287 if (offset is caretOffset) { 3288 int lineEnd = lineOffset + line.length; 3289 if (offset is lineEnd && caretAlignment is PREVIOUS_OFFSET_TRAILING) { 3290 bounds.width += getCaretWidth(); 3291 } 3292 } 3259 3293 bounds.x += leftMargin - horizontalScrollOffset; 3260 3294 bounds.y += getLinePixel(lineIndex); 3261 3295 return bounds; 3262 3296 } 3263 3264 3297 /** 3265 3298 * Returns the caret position relative to the start of the text. … … 3308 3341 } 3309 3342 /** 3310 * Returns the content implementation that is used for text storage 3311 * or null if no user defined content implementation has been set.3312 * 3313 * @return content implementation that is used for text storage or null3314 * if no user definedcontent implementation has been set.3343 * Returns the content implementation that is used for text storage. 3344 * 3345 * @return content the user defined content implementation that is used for 3346 * text storage or the default content implementation if no user defined 3347 * content implementation has been set. 3315 3348 * @exception DWTException <ul> 3316 3349 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> … … 3467 3500 checkWidget(); 3468 3501 return content.getCharCount(); 3502 } 3503 /** 3504 * Returns the line at the given line index without delimiters. 3505 * Index 0 is the first line of the content. When there are not 3506 * any lines, getLine(0) is a valid call that answers an empty string. 3507 * <p> 3508 * 3509 * @param lineIndex index of the line to return. 3510 * @return the line text without delimiters 3511 * 3512 * @exception DWTException <ul> 3513 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3514 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3515 * </ul> 3516 * @exception IllegalArgumentException <ul> 3517 * <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li> 3518 * </ul> 3519 * @since 3.4 3520 */ 3521 public String getLine(int lineIndex) { 3522 checkWidget(); 3523 if (lineIndex < 0 || 3524 (lineIndex > 0 && lineIndex >= content.getLineCount())) { 3525 DWT.error(DWT.ERROR_INVALID_RANGE); 3526 } 3527 return content.getLine(lineIndex); 3469 3528 } 3470 3529 /** … … 3860 3919 * </ul> 3861 3920 * @exception IllegalArgumentException <ul> 3862 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>3921 * <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li> 3863 3922 * </ul> 3864 3923 * @since 2.0 … … 3900 3959 DWT.error(DWT.ERROR_NULL_ARGUMENT); 3901 3960 } 3902 // is y above first line or is x before first column? 3903 if (point.y + getVerticalScrollOffset() < 0 || point.x + horizontalScrollOffset < 0) { 3961 int[] trailing = new int[1]; 3962 int offset = getOffsetAtPoint(point.x, point.y, trailing, true); 3963 if (offset is -1) { 3904 3964 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 3905 3965 } 3906 int bottomIndex = getLineIndex(clientAreaHeight); 3907 int height = getLinePixel(bottomIndex) + renderer.getLineHeight(bottomIndex); 3908 if (point.y > height) { 3909 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 3910 } 3911 int lineIndex = getLineIndex(point.y); 3912 int lineOffset = content.getOffsetAtLine(lineIndex); 3913 TextLayout layout = renderer.getTextLayout(lineIndex); 3914 int[] trailing = new int[1]; 3915 int x = point.x + horizontalScrollOffset - leftMargin ; 3916 int y = point.y - getLinePixel(lineIndex); 3917 int offsetInLine = layout.getOffset(x, y, trailing); 3918 String line = content.getLine(lineIndex); 3919 if (offsetInLine !is line.length - 1) { 3920 offsetInLine = Math.min(line.length, offsetInLine + trailing[0]); 3921 } 3922 Rectangle rect = layout.getLineBounds(layout.getLineIndex(offsetInLine)); 3923 renderer.disposeTextLayout(layout); 3924 if (x > rect.x + rect.width) { 3925 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 3926 } 3927 return lineOffset + offsetInLine; 3966 return offset + trailing[0]; 3928 3967 } 3929 3968 int getOffsetAtPoint(int x, int y) { … … 3948 3987 if (trailing[0] !is 0) { 3949 3988 int lineInParagraph = layout.getLineIndex(offsetInLine + trailing[0]); 3950 //TODO handle bidi text3951 3989 int lineStart = layout.getLineOffsets()[lineInParagraph]; 3952 3990 if (offsetInLine + trailing[0] is lineStart) { … … 3975 4013 return offsetInLine + content.getOffsetAtLine(lineIndex); 3976 4014 } 4015 int getOffsetAtPoint(int x, int y, int[] trailing, bool inTextOnly) { 4016 if (inTextOnly && y + getVerticalScrollOffset() < 0 || x + horizontalScrollOffset < 0) { 4017 return -1; 4018 } 4019 int bottomIndex = getPartialBottomIndex(); 4020 int height = getLinePixel(bottomIndex + 1); 4021 if (inTextOnly && y > height) { 4022 return -1; 4023 } 4024 int lineIndex = getLineIndex(y); 4025 int lineOffset = content.getOffsetAtLine(lineIndex); 4026 TextLayout layout = renderer.getTextLayout(lineIndex); 4027 x += horizontalScrollOffset - leftMargin ; 4028 y -= getLinePixel(lineIndex); 4029 int offset = layout.getOffset(x, y, trailing); 4030 Rectangle rect = layout.getLineBounds(layout.getLineIndex(offset)); 4031 renderer.disposeTextLayout(layout); 4032 if (inTextOnly && !(rect.x <= x && x <= rect.x + rect.width)) { 4033 return -1; 4034 } 4035 return offset + lineOffset; 4036 } 3977 4037 /** 3978 4038 * Returns the orientation of the receiver. … … 4000 4060 int lineHeight = renderer.getLineHeight(); 4001 4061 int partialLineCount = Compatibility.ceil(clientAreaHeight, lineHeight); 4002 return Math.m in(content.getLineCount(), topIndex + partialLineCount) - 1;4062 return Math.max(0, Math.min(content.getLineCount(), topIndex + partialLineCount) - 1); 4003 4063 } 4004 4064 return getLineIndex(clientAreaHeight - bottomMargin); … … 4597 4657 int lineOffset = content.getOffsetAtLine(i); 4598 4658 TextLayout layout = renderer.getTextLayout(i); 4599 if (layout.getText().length > 0) { 4600 if (i is lineStart && i is lineEnd) { 4601 rect = layout.getBounds(start - lineOffset, end - lineOffset); 4602 } else if (i is lineStart) { 4603 String line = content.getLine(i); 4604 rect = layout.getBounds(start - lineOffset, line.length); 4659 int length = layout.getText().length; 4660 if (length > 0) { 4661 if (i is lineStart) { 4662 if (i is lineEnd) { 4663 rect = layout.getBounds(start - lineOffset, end - lineOffset); 4664 } else { 4665 rect = layout.getBounds(start - lineOffset, length); 4666 } 4667 y += rect.y; 4605 4668 } else if (i is lineEnd) { 4606 4669 rect = layout.getBounds(0, end - lineOffset); … … 4727 4790 int getCaretDirection() { 4728 4791 if (!isBidiCaret()) return DWT.DEFAULT; 4792 if (ime.getCompositionOffset() !is -1) return DWT.DEFAULT; 4729 4793 if (!updateCaretDirection && caretDirection !is DWT.NULL) return caretDirection; 4730 4794 updateCaretDirection = false; … … 4754 4818 int getWrapWidth () { 4755 4819 if (wordWrap && !isSingleLine()) { 4756 int width = clientAreaWidth - leftMargin - rightMargin ;4820 int width = clientAreaWidth - leftMargin - rightMargin - getCaretWidth(); 4757 4821 return width > 0 ? width : 1; 4758 4822 } … … 4935 4999 addListener(DWT.Resize, listener); 4936 5000 addListener(DWT.Traverse, listener); 5001 ime.addListener(DWT.ImeComposition, new class () Listener { 5002 public void handleEvent(Event event) { 5003 switch (event.detail) { 5004 case DWT.COMPOSITION_SELECTION: handleCompositionSelection(event); break; 5005 case DWT.COMPOSITION_CHANGED: handleCompositionChanged(event); break; 5006 case DWT.COMPOSITION_OFFSET: handleCompositionOffset(event); break; 5007 } 5008 } 5009 }); 4937 5010 if (verticalBar !is null) { 4938 5011 verticalBar.addListener(DWT.Selection, new class() Listener { … … 5038 5111 } 5039 5112 } 5113 void handleCompositionOffset (Event event) { 5114 int[] trailing = new int [1]; 5115 event.index = getOffsetAtPoint(event.x, event.y, trailing, true); 5116 event.count = trailing[0]; 5117 } 5118 void handleCompositionSelection (Event event) { 5119 event.start = selection.x; 5120 event.end = selection.y; 5121 event.text = getSelectionText(); 5122 } 5123 void handleCompositionChanged(Event event) { 5124 String text = event.text; 5125 int start = event.start; 5126 int end = event.end; 5127 int length = text.length; 5128 if (length is ime.getCommitCount()) { 5129 content.replaceTextRange(start, end - start, ""); 5130 caretOffset = start; 5131 caretWidth = 0; 5132 caretDirection = DWT.NULL; 5133 } else { 5134 content.replaceTextRange(start, end - start, text); 5135 caretOffset = ime.getCaretOffset(); 5136 if (ime.getWideCaret()) { 5137 int lineIndex = getCaretLine(); 5138 int lineOffset = content.getOffsetAtLine(lineIndex); 5139 TextLayout layout = renderer.getTextLayout(lineIndex); 5140 caretWidth = layout.getBounds(start - lineOffset, start + length - 1 - lineOffset).width; 5141 renderer.disposeTextLayout(layout); 5142 } 5143 } 5144 showCaret(); 5145 } 5040 5146 /** 5041 5147 * Frees resources. … … 5068 5174 } 5069 5175 if (isBidiCaret()) { 5070 BidiUtil.removeLanguageListener( handle);5176 BidiUtil.removeLanguageListener(this); 5071 5177 } 5072 5178 selectionBackground = null; … … 5250 5356 end = lineEnd; 5251 5357 } 5252 selection.x = selection.y= start;5253 selectionAnchor = -1;5358 caretOffset = start; 5359 resetSelection(); 5254 5360 caretOffset = end; 5255 5361 showCaret(); … … 5396 5502 */ 5397 5503 void handleTextChanged(TextChangedEvent event) { 5504 int offset = ime.getCompositionOffset(); 5505 if (offset !is -1 && lastTextChangeStart < offset) { 5506 ime.setCompositionOffset(offset + lastTextChangeNewCharCount - lastTextChangeReplaceCharCount); 5507 } 5398 5508 int firstLine = content.getLineAtOffset(lastTextChangeStart); 5399 5509 resetCache(firstLine, 0); … … 5786 5896 */ 5787 5897 bool isBidi() { 5788 return IS_GTK || BidiUtil.isBidiPlatform() || isMirrored_;5898 return IS_GTK || IS_CARBON || BidiUtil.isBidiPlatform() || isMirrored_; 5789 5899 } 5790 5900 bool isBidiCaret() { … … 6513 6623 } 6514 6624 horizontalScrollOffset += pixels; 6515 int oldColumnX = columnX;6516 6625 setCaretLocation(); 6517 columnX = oldColumnX;6518 6626 return true; 6519 6627 } … … 6568 6676 super.redraw(); 6569 6677 } 6570 int oldColumnX = columnX;6571 6678 setCaretLocation(); 6572 columnX = oldColumnX;6573 6679 return true; 6574 6680 } … … 6705 6811 * Sets the alignment of the widget. The argument should be one of <code>DWT.LEFT</code>, 6706 6812 * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. The alignment applies for all lines. 6813 * </p><p> 6814 * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set 6815 * in order to stabilize the right edge before setting alignment. 6816 * </p> 6707 6817 * 6708 6818 * @param alignment the new alignment … … 6732 6842 checkWidget(); 6733 6843 background = color; 6844 super.setBackground(color); 6734 6845 super.redraw(); 6735 6846 } … … 6801 6912 } 6802 6913 if (isDefaultCaret) { 6803 caret.setBounds(location.x, location.y, 0, caretHeight);6914 caret.setBounds(location.x, location.y, caretWidth, caretHeight); 6804 6915 } else { 6805 6916 caret.setLocation(location); … … 6855 6966 caretOffset = offset; 6856 6967 } 6968 caretAlignment = PREVIOUS_OFFSET_TRAILING; 6857 6969 // clear the selection if the caret is moved. 6858 6970 // don't notify listeners about the selection change. … … 7184 7296 * Sets the alignment of the specified lines. The argument should be one of <code>DWT.LEFT</code>, 7185 7297 * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. 7186 * <p> 7298 * <p><p> 7299 * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set 7300 * in order to stabilize the right edge before setting alignment. 7301 * </p> 7187 7302 * Should not be called if a LineStyleListener has been set since the listener 7188 7303 * maintains the line attributes. … … 7490 7605 return; 7491 7606 } 7492 if (!BidiUtil.setOrientation( handle, orientation)) {7607 if (!BidiUtil.setOrientation(this, orientation)) { 7493 7608 return; 7494 7609 } … … 7706 7821 caretOffset = selection.y = end; 7707 7822 } 7823 caretAlignment = PREVIOUS_OFFSET_TRAILING; 7708 7824 internalRedrawRange(selection.x, selection.y - selection.x); 7709 7825 } … … 8005 8121 tabLength = tabs; 8006 8122 renderer.setFont(null, tabs); 8007 if (caretOffset > 0) {8008 caretOffset = 0;8009 showCaret();8010 clearSelection(false);8011 }8012 8123 resetCache(0, content.getLineCount()); 8124 setCaretLocation(); 8013 8125 super.redraw(); 8014 8126 }
