|
Lines 1-5
Link Here
|
| 1 |
/******************************************************************************* |
1 |
/******************************************************************************* |
| 2 |
* Copyright (c) 2000, 2010 IBM Corporation and others. |
2 |
* Copyright (c) 2000, 2011 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 |
|
Lines 39-44
Link Here
|
| 39 |
import org.eclipse.swt.widgets.Composite; |
39 |
import org.eclipse.swt.widgets.Composite; |
| 40 |
import org.eclipse.swt.widgets.Control; |
40 |
import org.eclipse.swt.widgets.Control; |
| 41 |
import org.eclipse.swt.widgets.Display; |
41 |
import org.eclipse.swt.widgets.Display; |
|
|
42 |
import org.eclipse.swt.widgets.ScrollBar; |
| 42 |
|
43 |
|
| 43 |
import org.eclipse.jface.util.Util; |
44 |
import org.eclipse.jface.util.Util; |
| 44 |
|
45 |
|
|
Lines 308-313
Link Here
|
| 308 |
} |
309 |
} |
| 309 |
|
310 |
|
| 310 |
/** |
311 |
/** |
|
|
312 |
* Container for cached widget infos. |
| 313 |
* |
| 314 |
* @since 3.7 |
| 315 |
*/ |
| 316 |
static class WidgetInfos { |
| 317 |
/** |
| 318 |
* the text widget line count |
| 319 |
*/ |
| 320 |
int maxLines; |
| 321 |
/** |
| 322 |
* the height of the vertical scrollbar thumb |
| 323 |
*/ |
| 324 |
int thumbHeight; |
| 325 |
/** |
| 326 |
* the visible lines of the text widget |
| 327 |
*/ |
| 328 |
double visibleLines; |
| 329 |
/** |
| 330 |
* the invisible lines of the text widget |
| 331 |
*/ |
| 332 |
double invisibleLines; |
| 333 |
/** |
| 334 |
* the bounds of {@link OverviewRuler#fCanvas} |
| 335 |
*/ |
| 336 |
Rectangle bounds; |
| 337 |
/** |
| 338 |
* the writable area in the text widget (height of all lines in pixels) |
| 339 |
*/ |
| 340 |
int writable; |
| 341 |
|
| 342 |
/** |
| 343 |
* Initializes the widget infos. |
| 344 |
* |
| 345 |
* @param textWidget the text widget |
| 346 |
* @param canvas the overview ruler canvas |
| 347 |
*/ |
| 348 |
public WidgetInfos(StyledText textWidget, Canvas canvas) { |
| 349 |
maxLines= textWidget.getLineCount(); |
| 350 |
bounds= canvas.getBounds(); |
| 351 |
writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); |
| 352 |
|
| 353 |
ScrollBar verticalBar= textWidget.getVerticalBar(); |
| 354 |
thumbHeight= verticalBar != null ? Math.max(Math.min(bounds.height, verticalBar.getThumbBounds().height), 0) : 0; |
| 355 |
|
| 356 |
int partialTopIndex= JFaceTextUtil.getPartialTopIndex(textWidget); |
| 357 |
int topLineHeight= textWidget.getLineHeight(textWidget.getOffsetAtLine(partialTopIndex)); |
| 358 |
int topLinePixel= textWidget.getLinePixel(partialTopIndex); |
| 359 |
double topIndex= partialTopIndex - (double) topLinePixel / topLineHeight; |
| 360 |
|
| 361 |
int partialBottomIndex= JFaceTextUtil.getPartialBottomIndex(textWidget); |
| 362 |
int bottomLineHeight= textWidget.getLineHeight(textWidget.getOffsetAtLine(partialBottomIndex)); |
| 363 |
int bottomLinePixel= textWidget.getLinePixel(partialBottomIndex); |
| 364 |
double bottomIndex= partialBottomIndex - ((double) bottomLinePixel - textWidget.getClientArea().height) / bottomLineHeight; |
| 365 |
|
| 366 |
visibleLines= bottomIndex - topIndex; |
| 367 |
invisibleLines= maxLines - visibleLines; |
| 368 |
} |
| 369 |
} |
| 370 |
|
| 371 |
private static final boolean DEBUG_DRAW= false; |
| 372 |
private static final boolean DEBUG_COMPUTE_Y= false; |
| 373 |
private static final boolean DEBUG_TO_DOCUMENT_LINE_NUMBER= false; |
| 374 |
|
| 375 |
/** |
| 311 |
* <code>true</code> if we're on a Mac, where "new GC(canvas)" is expensive. |
376 |
* <code>true</code> if we're on a Mac, where "new GC(canvas)" is expensive. |
| 312 |
* @see <a href="https://bugs.eclipse.org/298936">bug 298936</a> |
377 |
* @see <a href="https://bugs.eclipse.org/298936">bug 298936</a> |
| 313 |
* @since 3.6 |
378 |
* @since 3.6 |
|
Lines 647-658
Link Here
|
| 647 |
else |
712 |
else |
| 648 |
visible= fTextViewer.getVisibleRegion(); // legacy support |
713 |
visible= fTextViewer.getVisibleRegion(); // legacy support |
| 649 |
|
714 |
|
| 650 |
int maxLines= textWidget.getLineCount(); |
715 |
WidgetInfos infos= null; |
| 651 |
Point size= fCanvas.getSize(); |
716 |
|
| 652 |
int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); |
|
|
| 653 |
if (size.y > writable) |
| 654 |
size.y= Math.max(writable - fHeader.getSize().y, 0); |
| 655 |
|
| 656 |
for (Iterator iterator= fAnnotationsSortedByLayer.iterator(); iterator.hasNext();) { |
717 |
for (Iterator iterator= fAnnotationsSortedByLayer.iterator(); iterator.hasNext();) { |
| 657 |
Object annotationType= iterator.next(); |
718 |
Object annotationType= iterator.next(); |
| 658 |
|
719 |
|
|
Lines 688-713
Link Here
|
| 688 |
continue; |
749 |
continue; |
| 689 |
} |
750 |
} |
| 690 |
|
751 |
|
|
|
752 |
if (infos == null) { |
| 753 |
infos= new WidgetInfos(textWidget, fCanvas); |
| 754 |
r.x= INSET; |
| 755 |
r.width= infos.bounds.width - (2 * INSET); |
| 756 |
} |
| 691 |
|
757 |
|
| 692 |
try { |
758 |
try { |
|
|
759 |
int startOffset= visible != null ? annotationOffset - visible.getOffset() : widgetRegion.getOffset(); |
| 760 |
int startLine= textWidget.getLineAtOffset(startOffset); |
| 761 |
|
| 762 |
yy= computeY(startLine, infos); |
| 763 |
|
| 693 |
if (ANNOTATION_HEIGHT_SCALABLE) { |
764 |
if (ANNOTATION_HEIGHT_SCALABLE) { |
| 694 |
int numbersOfLines= document.getNumberOfLines(annotationOffset, annotationLength); |
765 |
int numbersOfLines= document.getNumberOfLines(annotationOffset, annotationLength); |
| 695 |
// don't count empty trailing lines |
766 |
// don't count empty trailing lines |
| 696 |
IRegion lastLine= document.getLineInformationOfOffset(annotationOffset + annotationLength); |
767 |
IRegion lastLine= document.getLineInformationOfOffset(annotationOffset + annotationLength); |
| 697 |
if (lastLine.getOffset() == annotationOffset + annotationLength) { |
768 |
if (lastLine.getOffset() == annotationOffset + annotationLength) { |
| 698 |
numbersOfLines -= 2; |
769 |
numbersOfLines -= 2; |
| 699 |
hh= (numbersOfLines * size.y) / maxLines + ANNOTATION_HEIGHT; |
770 |
int yy2= computeY(startLine + numbersOfLines, infos); |
| 700 |
if (hh < ANNOTATION_HEIGHT) |
771 |
hh= Math.max(yy2 - yy, ANNOTATION_HEIGHT); |
| 701 |
hh= ANNOTATION_HEIGHT; |
|
|
| 702 |
} else |
772 |
} else |
| 703 |
hh= ANNOTATION_HEIGHT; |
773 |
hh= ANNOTATION_HEIGHT; |
| 704 |
} |
774 |
} |
| 705 |
fAnnotationHeight= hh; |
775 |
fAnnotationHeight= hh; |
| 706 |
|
776 |
|
| 707 |
int startOffset= visible != null ? annotationOffset - visible.getOffset() : widgetRegion.getOffset(); |
|
|
| 708 |
int startLine= textWidget.getLineAtOffset(startOffset); |
| 709 |
yy= Math.min((startLine * size.y) / maxLines, size.y - hh); |
| 710 |
|
| 711 |
if (!areColorsComputed) { |
777 |
if (!areColorsComputed) { |
| 712 |
fill= getFillColor(annotationType, style[t] == FilterIterator.TEMPORARY); |
778 |
fill= getFillColor(annotationType, style[t] == FilterIterator.TEMPORARY); |
| 713 |
stroke= getStrokeColor(annotationType, style[t] == FilterIterator.TEMPORARY); |
779 |
stroke= getStrokeColor(annotationType, style[t] == FilterIterator.TEMPORARY); |
|
Lines 716-731
Link Here
|
| 716 |
|
782 |
|
| 717 |
if (fill != null) { |
783 |
if (fill != null) { |
| 718 |
gc.setBackground(fill); |
784 |
gc.setBackground(fill); |
| 719 |
gc.fillRectangle(INSET, yy, size.x-(2*INSET), hh); |
785 |
gc.fillRectangle(INSET, yy, infos.bounds.x-(2*INSET), hh); |
| 720 |
} |
786 |
} |
| 721 |
|
787 |
|
| 722 |
if (stroke != null) { |
788 |
if (stroke != null) { |
| 723 |
gc.setForeground(stroke); |
789 |
gc.setForeground(stroke); |
| 724 |
r.x= INSET; |
|
|
| 725 |
r.y= yy; |
790 |
r.y= yy; |
| 726 |
if (yy + hh == size.y) |
791 |
if (yy + hh == infos.bounds.height) |
| 727 |
r.y--; |
792 |
r.y--; |
| 728 |
r.width= size.x - (2 * INSET); |
|
|
| 729 |
r.height= hh; |
793 |
r.height= hh; |
| 730 |
gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance |
794 |
gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance |
| 731 |
gc.drawRectangle(r); |
795 |
gc.drawRectangle(r); |
|
Lines 735-740
Link Here
|
| 735 |
} |
799 |
} |
| 736 |
} |
800 |
} |
| 737 |
} |
801 |
} |
|
|
802 |
|
| 803 |
if (DEBUG_DRAW) { |
| 804 |
// draw debugging guides (boundaries): |
| 805 |
if (infos == null) |
| 806 |
infos= new WidgetInfos(textWidget, fCanvas); |
| 807 |
gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_DARK_MAGENTA)); |
| 808 |
yy= infos.thumbHeight / 2; |
| 809 |
gc.drawLine(0, yy, infos.bounds.x/2, yy); |
| 810 |
yy= infos.bounds.height - infos.thumbHeight / 2; |
| 811 |
gc.drawLine(0, yy, infos.bounds.x/2, yy); |
| 812 |
|
| 813 |
gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_BLUE)); |
| 814 |
yy= 0; |
| 815 |
gc.drawLine(0, yy, infos.bounds.x/2, yy); |
| 816 |
yy= infos.bounds.height - 1; |
| 817 |
gc.drawLine(0, yy, infos.bounds.x/2, yy); |
| 818 |
} |
| 819 |
} |
| 820 |
|
| 821 |
/** |
| 822 |
* Computes and returns the y location of the given startLine. |
| 823 |
* |
| 824 |
* @param startLine the start line |
| 825 |
* @param infos the cached widget infos |
| 826 |
* @return the vertical position of the given startLine in the overview ruler |
| 827 |
* @since 3.7 |
| 828 |
*/ |
| 829 |
private int computeY(int startLine, WidgetInfos infos) { |
| 830 |
// this is the inverse of #toLineNumbers(int) |
| 831 |
|
| 832 |
int yy; |
| 833 |
if (infos.bounds.height > infos.writable || infos.invisibleLines <= 0) { // too few lines for relative positions: align annotations with textWidget lines |
| 834 |
yy = Math.max(0, (2 * startLine + 1) * infos.writable / (infos.maxLines * 2) - infos.bounds.y); |
| 835 |
if (DEBUG_COMPUTE_Y) |
| 836 |
System.out.println("static: " + yy); //$NON-NLS-1$ |
| 837 |
|
| 838 |
} else if (startLine + 1 < infos.visibleLines / 2) { // before middle of first page: map to area from 0 to thumbHeight/2 |
| 839 |
yy= (int) (startLine * infos.thumbHeight / infos.visibleLines); // == startLine * (thumbHeight / 2) / (visibleLines / 2); |
| 840 |
if (DEBUG_COMPUTE_Y) |
| 841 |
System.out.println("start: " + yy); //$NON-NLS-1$ |
| 842 |
|
| 843 |
} else if (infos.maxLines - infos.visibleLines / 2 <= startLine) { // after middle of last page: map to area from canvasHeight-1 - thumbHeight/2 to canvasHeight-1 |
| 844 |
yy= (int) (infos.bounds.height-1 - (double)infos.thumbHeight / 2 + (startLine - (infos.maxLines - infos.visibleLines / 2) + 1) * infos.thumbHeight / infos.visibleLines); |
| 845 |
if (DEBUG_COMPUTE_Y) |
| 846 |
System.out.println("end: " + yy); //$NON-NLS-1$ |
| 847 |
|
| 848 |
} else { |
| 849 |
yy= (int) ((double)infos.thumbHeight/2 + (startLine + 1 - infos.visibleLines / 2) * (infos.bounds.height - infos.thumbHeight) / infos.invisibleLines); |
| 850 |
if (DEBUG_COMPUTE_Y) |
| 851 |
System.out.println("middle: " + yy); //$NON-NLS-1$ |
| 852 |
} |
| 853 |
// center of rectangle should be at the calculated position: |
| 854 |
yy-= ANNOTATION_HEIGHT / 2; |
| 855 |
// cap at start/end: |
| 856 |
yy= Math.max(0, Math.min(yy, infos.bounds.height-1 - ANNOTATION_HEIGHT)); |
| 857 |
return yy; |
| 738 |
} |
858 |
} |
| 739 |
|
859 |
|
| 740 |
/* |
860 |
/* |
|
Lines 783-810
Link Here
|
| 783 |
* @return the corresponding document lines |
903 |
* @return the corresponding document lines |
| 784 |
*/ |
904 |
*/ |
| 785 |
private int[] toLineNumbers(int y_coordinate) { |
905 |
private int[] toLineNumbers(int y_coordinate) { |
| 786 |
|
906 |
// this is the inverse of #computeY(int, WidgetInfos) |
| 787 |
StyledText textWidget= fTextViewer.getTextWidget(); |
907 |
|
| 788 |
int maxLines= textWidget.getContent().getLineCount(); |
908 |
WidgetInfos infos= new WidgetInfos(fTextViewer.getTextWidget(), fCanvas); |
| 789 |
|
909 |
|
| 790 |
int rulerLength= fCanvas.getSize().y; |
910 |
if (y_coordinate >= infos.writable || y_coordinate >= infos.bounds.height || y_coordinate < 0) |
| 791 |
int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); |
|
|
| 792 |
|
| 793 |
if (rulerLength > writable) |
| 794 |
rulerLength= Math.max(writable - fHeader.getSize().y, 0); |
| 795 |
|
| 796 |
if (y_coordinate >= writable || y_coordinate >= rulerLength) |
| 797 |
return new int[] {-1, -1}; |
911 |
return new int[] {-1, -1}; |
| 798 |
|
912 |
|
| 799 |
int[] lines= new int[2]; |
913 |
int[] lines= new int[2]; |
| 800 |
|
914 |
|
| 801 |
int pixel0= Math.max(y_coordinate - 1, 0); |
915 |
// the "+ 1" below accounts for the offset of the hot spot in typical mouse cursors |
| 802 |
int pixel1= Math.min(rulerLength, y_coordinate + 1); |
916 |
int pixel0= Math.max(y_coordinate - ANNOTATION_HEIGHT / 2 + 1, 0); |
| 803 |
rulerLength= Math.max(rulerLength, 1); |
917 |
int pixel1= Math.min(infos.bounds.height, y_coordinate + ANNOTATION_HEIGHT / 2 + 1); |
| 804 |
|
918 |
|
| 805 |
lines[0]= (pixel0 * maxLines) / rulerLength; |
919 |
if (infos.bounds.height > infos.writable || infos.invisibleLines <= 0) { // too few lines for relative positions: align annotations with textWidget lines |
| 806 |
lines[1]= (pixel1 * maxLines) / rulerLength; |
920 |
// yy = Math.max(0, (2 * startLine + 1) * infos.writable / (infos.maxLines * 2) - infos.bounds.y); |
| 807 |
|
921 |
lines[0]= (int) ((pixel0 + infos.bounds.y) * infos.maxLines / (double)infos.writable); |
|
|
922 |
lines[1]= (int) ((pixel1 + infos.bounds.y) * infos.maxLines / (double)infos.writable); |
| 923 |
if (DEBUG_TO_DOCUMENT_LINE_NUMBER) |
| 924 |
System.out.println("static y: " + y_coordinate + " => [" + lines[0] + ", " + lines[1] + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| 925 |
|
| 926 |
} else if (y_coordinate < infos.thumbHeight / 2) { // before middle of first page: map to area from 0 to thumbHeight/2 |
| 927 |
// yy= (int) (startLine * infos.thumbHeight / infos.visibleLines); |
| 928 |
lines[0] = (int) (pixel0 * infos.visibleLines / infos.thumbHeight); |
| 929 |
lines[1] = (int) (pixel1 * infos.visibleLines / infos.thumbHeight); |
| 930 |
if (DEBUG_TO_DOCUMENT_LINE_NUMBER) |
| 931 |
System.out.println("start y: " + y_coordinate + " => [" + lines[0] + ", " + lines[1] + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| 932 |
|
| 933 |
} else if (infos.bounds.height - 1 - infos.thumbHeight / 2 < y_coordinate) { // after middle of last page: map to area from canvasHeight-1 - thumbHeight/2 to canvasHeight-1 |
| 934 |
// yy= (int) (infos.bounds.height-1 - (double)infos.thumbHeight / 2 + (startLine - (infos.maxLines - infos.visibleLines / 2) + 1) * infos.thumbHeight / infos.visibleLines); |
| 935 |
lines[0] = (int) ((pixel0 - (infos.bounds.height-1) + (double)infos.thumbHeight / 2) * infos.visibleLines / infos.thumbHeight - 1 + (infos.maxLines - infos.visibleLines / 2)); |
| 936 |
lines[1] = (int) ((pixel1 - (infos.bounds.height-1) + (double)infos.thumbHeight / 2) * infos.visibleLines / infos.thumbHeight - 1 + (infos.maxLines - infos.visibleLines / 2)); |
| 937 |
if (DEBUG_TO_DOCUMENT_LINE_NUMBER) |
| 938 |
System.out.println("end y: " + y_coordinate + " => [" + lines[0] + ", " + lines[1] + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| 939 |
|
| 940 |
} else { |
| 941 |
// yy= (int) ((double)infos.thumbHeight/2 + (startLine + 1 - infos.visibleLines / 2) * (infos.bounds.height - infos.thumbHeight) / infos.invisibleLines); |
| 942 |
lines[0]= (int) ((pixel0 - (double)infos.thumbHeight/2) * infos.invisibleLines / (infos.bounds.height - infos.thumbHeight) - 1 + infos.visibleLines / 2); |
| 943 |
lines[1]= (int) ((pixel1 - (double)infos.thumbHeight/2) * infos.invisibleLines / (infos.bounds.height - infos.thumbHeight) - 1 + infos.visibleLines / 2); |
| 944 |
if (DEBUG_TO_DOCUMENT_LINE_NUMBER) |
| 945 |
System.out.println("middle y: " + y_coordinate + " => [" + lines[0] + ", " + lines[1] + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| 946 |
} |
| 947 |
|
| 808 |
if (fTextViewer instanceof ITextViewerExtension5) { |
948 |
if (fTextViewer instanceof ITextViewerExtension5) { |
| 809 |
ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; |
949 |
ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; |
| 810 |
lines[0]= extension.widgetLine2ModelLine(lines[0]); |
950 |
lines[0]= extension.widgetLine2ModelLine(lines[0]); |
|
Lines 818-824
Link Here
|
| 818 |
} catch (BadLocationException x) { |
958 |
} catch (BadLocationException x) { |
| 819 |
} |
959 |
} |
| 820 |
} |
960 |
} |
|
|
961 |
|
| 962 |
if (y_coordinate < ANNOTATION_HEIGHT && y_coordinate < infos.bounds.y) |
| 963 |
lines[0]= 0; |
| 964 |
|
| 965 |
if (lines[0] < 0) |
| 966 |
lines[0]= 0; |
| 967 |
if (lines[1] > infos.maxLines) |
| 968 |
lines[1]= infos.maxLines; |
| 821 |
|
969 |
|
|
|
970 |
if (DEBUG_TO_DOCUMENT_LINE_NUMBER) |
| 971 |
System.out.println("result: [" + lines[0] + ", " + lines[1] + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 822 |
return lines; |
972 |
return lines; |
| 823 |
} |
973 |
} |
| 824 |
|
974 |
|