[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Doubleclicking NSTextView
From: |
Wolfgang Lux |
Subject: |
Re: Doubleclicking NSTextView |
Date: |
Sun, 2 Sep 2007 17:40:46 +0200 |
Andreas Höschler wrote:
- (void)mouseDown:(NSEvent *)theEvent
{
...
+ if (startIndex != (unsigned)-1 && startIndex > 0)
+ {
+ NSString *string = [self string];
+ if ([string characterAtIndex:startIndex - 1] == '\n')
startIndex--;
+ }
...
}
Unfortunately, this change is not correct (if you double click on the
beginning of a line the previous line will be selected). In fact, it
merely tries to work around the problem that -characterIndexForPoint:
returns a wrong result in the first place. A better fix for the whole
problem is below.
- (NSRange)selectionRangeForProposedRange:(NSRange)
proposedCharRange granularity:(NSSelectionGranularity)gr
{
...
+ switch (gr)
+ {
+ case NSSelectByCharacter:
+ break;
+ default:
+ return [string lineRangeForRange:proposedCharRange];
+ break;
+ }
...
)
I do not really understand this change and could not find an example
where it makes a difference.
Okay, now for a better solution of the problem. First of all,
NSLayoutManager's -
glyphIndexForPoint:inTextContainer:fractionOfDistanceThroughGlyph: is
returning wrong information here because it ignores characters which
are not shown and control characters when computing the position even
though such characters are relevant for layout. In particular, if you
click after the last character of a line, the method returns the
index of the last character in the line and fraction 1 rather than
the index of the newline character (and fraction 1). The following
patch corrects this. Incidentally, the same applies to tab
characters. Without this fix, if you click in the space of a tab
character, the method returns the index of the character *before* the
tab character (unless it is the first character in the line) and not
that of the tab character.
--- Source/NSLayoutManager.m (Revision 25440)
+++ Source/NSLayoutManager.m (Arbeitskopie)
@@ -696,11 +696,10 @@
last_visible = lf->pos;
for (j = lp->pos - glyph_pos; j + glyph_pos < lp->pos + lp-
>length;)
{
- if (r->glyphs[j].isNotShown || r->glyphs[j].g == NSControlGlyph ||
- !r->glyphs[j].g)
+ if (!r->glyphs[j].g)
{
GLYPH_STEP_FORWARD(r, j, glyph_pos, char_pos)
- continue;
+ continue;
}
last_visible = j + glyph_pos;
The other part of the problem is that we do not want NSTextView's -
characterIndexForPoint: method to increment the position even if
fraction is greater than 0.5 if the new position is in the next line.
This is fixed by the patch below. In addition, -
characterIndexForPoint: is not correct according to the Mac OS X
documentation (and the implementation) because -
characterIndexForPoint: expects a point in screen coordinates rather
than view coordinates. Therefore, I have take the liberty to
introduce a new private method
_characterIndexForPoint:respectFraction: to compute the index in view
coordinates. Unless respectFraction is NO, the index is incremented
to match the closest character on the same line. Note that -
characterIndexForPoint: passes NO for this parameter, which is
compatible with the Mac OS X implementation of this method.
--- NSSource/NSTextView.m (Revision 25440)
+++ NSSource/NSTextView.m (Arbeitskopie)
@@ -1793,7 +1793,8 @@
TODO: make sure this is only called when _layoutManager is known non-
nil,
or add guards
*/
-- (unsigned int) characterIndexForPoint: (NSPoint)point
+- (unsigned int) _characterIndexForPoint: (NSPoint)point
+ respectFraction: (BOOL)respectFraction
{
unsigned index;
float fraction;
@@ -1808,13 +1809,21 @@
return (unsigned int)-1;
index = [_layoutManager characterIndexForGlyphAtIndex: index];
- if (fraction > 0.5 && index < [_textStorage length])
+ if (respectFraction && fraction > 0.5 && index < [_textStorage
length] &&
+ [[_textStorage string] characterAtIndex:index] != '\n')
{
index++;
}
return index;
}
+- (unsigned int) characterIndexForPoint: (NSPoint)point
+{
+ point = [[self window] convertScreenToBase:point];
+ point = [self convertPoint:point fromView:nil];
+ return [self _characterIndexForPoint:point respectFraction:NO];
+}
+
- (NSRange) markedRange
{
return NSMakeRange(NSNotFound, 0);
@@ -4267,7 +4276,8 @@
dragPoint = [sender draggingLocation];
dragPoint = [self convertPoint: dragPoint fromView: nil];
- dragIndex = [self characterIndexForPoint: dragPoint];
+ dragIndex = [self _characterIndexForPoint: dragPoint
+ respectFraction: YES];
dragRange = NSMakeRange (dragIndex, 0);
range = [self selectionRangeForProposedRange: dragRange
@@ -4302,7 +4312,8 @@
dragPoint = [sender draggingLocation];
dragPoint = [self convertPoint: dragPoint fromView: nil];
- dragIndex = [self characterIndexForPoint: dragPoint];
+ dragIndex = [self _characterIndexForPoint: dragPoint
+ respectFraction: YES];
dragRange = NSMakeRange (dragIndex, 0);
range = [self selectionRangeForProposedRange: dragRange
@@ -4416,7 +4427,8 @@
possible) */
startPoint = [self convertPoint: [theEvent locationInWindow]
fromView: nil];
- startIndex = [self characterIndexForPoint: startPoint];
+ startIndex = [self _characterIndexForPoint: startPoint
+ respectFraction: [theEvent clickCount] == 1];
if (startIndex == (unsigned int)-1)
{
@@ -4620,7 +4632,8 @@
point = [self convertPoint: [lastEvent locationInWindow]
fromView: nil];
- proposedRange = MakeRangeFromAbs([self characterIndexForPoint: point],
+ proposedRange = MakeRangeFromAbs([self _characterIndexForPoint: point
+ respectFraction: YES],
startIndex);
chosenRange = [self selectionRangeForProposedRange: proposedRange
granularity: granularity];
Regards
Wolfgang
- Re: Doubleclicking NSTextView,
Wolfgang Lux <=