mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 07:00:46 +00:00
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:
parent
c5227a8144
commit
20ab4fa2df
4 changed files with 142 additions and 130 deletions
|
@ -1,3 +1,11 @@
|
|||
2003-02-03 02:49 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Headers/gnustep/gui/NSLayoutManager.h, Source/NSLayoutManager.m:
|
||||
Add -insertionPointRectForCharacterIndex:inTextContainer: method.
|
||||
|
||||
* Source/NSTextView.m (-updateInsertionPointStateAndRestartTimer:):
|
||||
Use it.
|
||||
|
||||
2003-02-02 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSTextField.m
|
||||
|
|
|
@ -110,6 +110,20 @@
|
|||
fractionOfDistanceThroughGlyph: (float *)partialFraction;
|
||||
|
||||
|
||||
/*
|
||||
Returns a rectangle suitable for drawing an insertion point in if the
|
||||
insertion point is placed before the given character. The character index
|
||||
may be any character in the text (it will handle positions "inside" a
|
||||
ligature), and (unlike other methods) it may be one past the end of the
|
||||
text (ie. cindex==[[_textStorage string] length]).
|
||||
|
||||
If the character isn't in the text container, returns NSZeroRect.
|
||||
|
||||
GNUstep extension.
|
||||
*/
|
||||
-(NSRect) insertionPointRectForCharacterIndex: (unsigned int)cindex
|
||||
inTextContainer: (NSTextContainer *)textContainer;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue