Add -insertionPointRectForCharacterIndex:inTextContainer: method to NSLayoutManager and use it in NSTextView.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@15863 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Alexander Malmberg 2003-02-03 01:52:27 +00:00
parent c5227a8144
commit 20ab4fa2df
4 changed files with 142 additions and 130 deletions

View file

@ -38,6 +38,8 @@ points inside line frag rects.
http://wiki.gnustep.org/index.php/NominallySpacedGlyphs
*/
#include <math.h>
#include "AppKit/NSLayoutManager.h"
#include "AppKit/GSLayoutManager_internal.h"
@ -126,7 +128,9 @@ container? necessary? */
for (tc = textcontainers, i = 0; i < num_textcontainers; i++, tc++)
if (tc->textContainer == container)
break;
//printf("container %i %@, %i+%i\n",i,tc->textContainer,tc->pos,tc->length);
[self _doLayoutToGlyph: last - 1];
//printf(" now %i+%i\n",tc->pos,tc->length);
if (i == num_textcontainers ||
tc->pos + tc->length < last ||
tc->pos > glyphRange.location)
@ -173,9 +177,11 @@ container? necessary? */
{
if (!r->glyphs[i].isNotShown && r->glyphs[i].g &&
r->glyphs[i].g != NSControlGlyph)
x0 += [r->font advancementForGlyph: r->glyphs[i].g].width;
GLYPH_STEP_FORWARD(r, i, gpos, cpos)
{
x0 += [r->font advancementForGlyph: r->glyphs[i].g].width;
}
GLYPH_STEP_FORWARD(r, i, gpos, cpos)
}
}
else
x0 = NSMinX(lf->rect);
@ -202,9 +208,11 @@ container? necessary? */
{
if (!r->glyphs[i].isNotShown && r->glyphs[i].g &&
r->glyphs[i].g != NSControlGlyph)
x1 += [r->font advancementForGlyph: r->glyphs[i].g].width;
GLYPH_STEP_FORWARD(r, i, gpos, cpos)
{
x1 += [r->font advancementForGlyph: r->glyphs[i].g].width;
}
GLYPH_STEP_FORWARD(r, i, gpos, cpos)
}
}
else
x1 = NSMaxX(lf->rect);
@ -536,6 +544,106 @@ anything visible
}
}
-(NSRect) insertionPointRectForCharacterIndex: (unsigned int)cindex
inTextContainer: (NSTextContainer *)textContainer
{
int i;
textcontainer_t *tc;
linefrag_t *lf;
float x0, x1;
NSRect r;
unsigned int glyph_index;
float fraction_through;
if (cindex == [[_textStorage string] length])
{ /* TODO: use extra line frag, etc. */
if (!cindex)
{
return NSMakeRect(1,1,1,13); /* TODO! */
}
glyph_index = [self numberOfGlyphs] - 1;
fraction_through = 1.0;
}
else
{
NSRange glyphRange, charRange;
glyphRange = [self glyphRangeForCharacterRange: NSMakeRange(cindex, 1)
actualCharacterRange: &charRange];
/* Magic to deal with composite characters and ligatures. */
fraction_through = (cindex - charRange.location) / (float)charRange.length;
fraction_through *= glyphRange.length;
glyph_index = glyphRange.location + floor(fraction_through);
fraction_through -= floor(fraction_through);
}
for (tc = textcontainers, i = 0; i < num_textcontainers; i++, tc++)
if (tc->textContainer == textContainer)
break;
[self _doLayoutToGlyph: glyph_index - 1];
if (i == num_textcontainers)
{
NSLog(@"%s: invalid text container", __PRETTY_FUNCTION__);
return NSZeroRect;
}
if (glyph_index < tc->pos || glyph_index >= tc->pos + tc->length)
{
return NSZeroRect;
}
for (lf = tc->linefrags, i = 0; i < tc->num_linefrags; i++, lf++)
if (lf->pos + lf->length > glyph_index)
break;
{
int i, j;
linefrag_point_t *lp;
glyph_run_t *r;
unsigned int gpos, cpos;
for (j = 0, lp = lf->points; j < lf->num_points; j++)
if (lp->pos + lp->length > glyph_index)
break;
x0 = lp->p.x + lf->rect.origin.x;
r = run_for_glyph_index(lp->pos, glyphs, &gpos, &cpos);
i = lp->pos - gpos;
while (i + gpos < glyph_index)
{
if (!r->glyphs[i].isNotShown && r->glyphs[i].g &&
r->glyphs[i].g != NSControlGlyph)
{
x0 += [r->font advancementForGlyph: r->glyphs[i].g].width;
}
GLYPH_STEP_FORWARD(r, i, gpos, cpos)
}
x1 = x0;
if (!r->glyphs[i].isNotShown && r->glyphs[i].g &&
r->glyphs[i].g != NSControlGlyph)
{
x1 += [r->font advancementForGlyph: r->glyphs[i].g].width;
}
}
r = lf->rect;
r.origin.x = x0 + (x1 - x0) * fraction_through;
r.size.width = 1;
r.origin.y++;
r.size.height -= 2;
return r;
}
@end

View file

@ -2856,9 +2856,6 @@ Figure out how the additional layout stuff is supposed to work.
/* TODO: this is a basic stopgap implementation; should work fine, but no
blinking. need to do a proper one once I know how */
unsigned int l;
BOOL after;
NSRange gr;
NSRect new;
if (!_layoutManager)
@ -2870,47 +2867,17 @@ Figure out how the additional layout stuff is supposed to work.
if (_layoutManager->_selected_range.length > 0 ||
_layoutManager->_selected_range.location == NSNotFound)
{
[self setNeedsDisplayInRect: _insertionPointRect];
_insertionPointRect = NSZeroRect;
return;
}
l = _layoutManager->_selected_range.location;
if (l == [self textLength])
{
if (l == 0)
{
/* TODO */
new = NSZeroRect;
new.size.width = 1;
new.size.height = 14;
new.origin.y = 0;
goto adjust;
}
l--;
after = YES;
new = NSZeroRect;
}
else
after = NO;
gr = [_layoutManager glyphRangeForCharacterRange: NSMakeRange(l,1)
actualCharacterRange: NULL];
new = [_layoutManager boundingRectForGlyphRange: gr
inTextContainer: _textContainer];
if (after)
{
new.origin.x += new.size.width - 1;
new = [_layoutManager
insertionPointRectForCharacterIndex: _layoutManager->_selected_range.location
inTextContainer: _textContainer];
new.origin.x += _textContainerOrigin.x;
new.origin.y += _textContainerOrigin.y;
}
new.size.width = 1;
adjust:
new.origin.y++;
new.size.height -= 2;
new.origin.x += _textContainerOrigin.x;
new.origin.y += _textContainerOrigin.y;
if (!NSEqualRects(new, _insertionPointRect))
{
@ -2919,92 +2886,7 @@ adjust:
[self setNeedsDisplayInRect: _insertionPointRect];
}
#if 0 /* TODO */
/* Update insertion point rect */
NSRange charRange;
NSRange glyphRange;
unsigned glyphIndex;
NSRect rect;
NSRect oldInsertionPointRect;
/* Simple case - no insertion point */
if ((_layoutManager->_selected_range.length > 0) || _layoutManager->_selected_range.location == NSNotFound)
{
if (_insertionPointTimer != nil)
{
[_insertionPointTimer invalidate];
DESTROY (_insertionPointTimer);
}
/* TODO: horizontal position of insertion point */
// _originalInsertPoint = 0; TODO
return;
}
if (_layoutManager->_selected_range.location == [[[_layoutManager textStorage] string] length])
{
rect = NSZeroRect;
goto ugly_hack_done;
}
charRange = NSMakeRange (_layoutManager->_selected_range.location, 0);
glyphRange = [_layoutManager glyphRangeForCharacterRange: charRange
actualCharacterRange: NULL];
glyphIndex = glyphRange.location;
rect = [_layoutManager lineFragmentUsedRectForGlyphAtIndex: glyphIndex
effectiveRange: NULL];
rect.origin.x += _textContainerOrigin.x;
rect.origin.y += _textContainerOrigin.y;
if ([self selectionAffinity] != NSSelectionAffinityUpstream)
{
/* Standard case - draw the insertion point just before the
associated glyph index */
NSPoint loc = [_layoutManager locationForGlyphAtIndex: glyphIndex];
rect.origin.x += loc.x;
}
else /* _affinity == NSSelectionAffinityUpstream - non standard */
{
/* TODO - THIS DOES NOT WORK - as a consequence,
NSSelectionAffinityUpstream DOES NOT WORK */
/* Check - if the previous glyph is on another line */
/* TODO: Don't know how to do this check, this is a hack and
DOES NOT WORK - clearly this code should be inside the layout
manager anyway */
NSRect rect2;
rect2 = [_layoutManager lineFragmentRectForGlyphAtIndex: glyphIndex - 1
effectiveRange: NULL];
if (NSMinY (rect2) < NSMinY (rect))
{
/* Then we need to draw the insertion point just after the
previous glyph - DOES NOT WORK */
glyphRange = NSMakeRange (glyphIndex - 1, 1);
rect = [_layoutManager boundingRectForGlyphRange: glyphRange
inTextContainer:_textContainer];
rect.origin.x = NSMaxX (rect) - 1;
}
else /* Else, standard case again */
{
NSPoint loc = [_layoutManager locationForGlyphAtIndex: glyphIndex];
rect.origin.x += loc.x;
}
}
ugly_hack_done:
rect.size.width = 1;
oldInsertionPointRect = _insertionPointRect;
_insertionPointRect = rect;
/* Remember horizontal position of insertion point */
// _originalInsertPoint = _insertionPointRect.origin.x; TODO
#if 0 /* TODO: old code for insertion point blinking. might be useful */
if (restartFlag)
{
/* Start blinking timer if not yet started */