Permalink
Browse files

Merge pull request #2487 from daboe01/fixed--CPTextView-did-not-suppo…

…rt-dragging-the-selection

Fixed: CPTextView did not support dragging the selection
  • Loading branch information...
2 parents c2b7cc7 + 9d041c4 commit 65f701d459b115c7540bedc312685fe54da3a3a0 @mrcarlberg mrcarlberg committed on GitHub Oct 13, 2016
Showing with 124 additions and 42 deletions.
  1. +2 −2 AppKit/CPTextView/CPLayoutManager.j
  2. +118 −39 AppKit/CPTextView/CPTextView.j
  3. +4 −1 AppKit/CPTextView/_CPRTFParser.j
@@ -164,7 +164,7 @@ _oncontextmenuhandler = function () { return false; };
if (![self numberOfGlyphs])
return CGRectMake(0, 0, 1, 12); // crude hack to give a cursor in an empty doc.
- if (CPMaxRange(aRange) >= [self numberOfGlyphs])
+ if (CPMaxRange(aRange) > [self numberOfGlyphs])
aRange = CPMakeRange([self numberOfGlyphs] - 1, 1);
var fragments = _objectsInRange(_lineFragments, aRange),
@@ -1370,4 +1370,4 @@ var _objectsInRange = function(aList, aRange)
"\n\t_attributes="+[_attributes description];
}
-@end
+@end
@@ -153,6 +153,7 @@ var kDelegateRespondsTo_textShouldBeginEditing
CPTimer _scrollingTimer;
BOOL _scrollingDownward;
+ CPRange _movingSelection;
int _stickyXLocation;
@@ -203,7 +204,7 @@ var kDelegateRespondsTo_textShouldBeginEditing
_typingAttributes = [[CPDictionary alloc] initWithObjects:[_font, _textColor] forKeys:[CPFontAttributeName, CPForegroundColorAttributeName]];
}
- [self registerForDraggedTypes:[CPColorDragType]];
+ [self registerForDraggedTypes:[CPColorDragType, CPRTFPboardType]];
return self;
}
@@ -899,35 +900,82 @@ var kDelegateRespondsTo_textShouldBeginEditing
}, 500);
}
+- (CGPoint)_characterIndexFromRawPoint:(CGPoint)point
+{
+ var fraction = [],
+ point = [self convertPoint:point fromView:nil];
+
+ // convert to container coordinate
+ point.x -= _textContainerOrigin.x;
+ point.y -= _textContainerOrigin.y;
+
+ var index = [_layoutManager glyphIndexForPoint:point inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction];
+
+ if (index === CPNotFound)
+ index = [_layoutManager numberOfCharacters];
+ else if (fraction[0] > 0.5)
+ index++;
+
+ return index;
+}
+- (CGPoint)_characterIndexFromEvent:(CPEvent)event
+{
+ return [self _characterIndexFromRawPoint:[event locationInWindow]];
+}
#pragma mark -
#pragma mark Mouse Events
- (void)mouseDown:(CPEvent)event
{
[_CPNativeInputManager cancelCurrentInputSessionIfNeeded];
-
- var fraction = [],
- point = [self convertPoint:[event locationInWindow] fromView:nil],
- granularities = [CPNotFound, CPSelectByCharacter, CPSelectByWord, CPSelectByParagraph];
-
[_caret setVisibility:NO];
-
- // convert to container coordinate
- point.x -= _textContainerOrigin.x;
- point.y -= _textContainerOrigin.y;
-
- _startTrackingLocation = [_layoutManager glyphIndexForPoint:point inTextContainer:_textContainer fractionOfDistanceThroughGlyph:fraction];
-
- if (_startTrackingLocation === CPNotFound)
- _startTrackingLocation = [_layoutManager numberOfCharacters];
- else if (fraction[0] > 0.5)
- _startTrackingLocation++;
-
+
+ _startTrackingLocation = [self _characterIndexFromEvent:event];
+
+ var granularities = [CPNotFound, CPSelectByCharacter, CPSelectByWord, CPSelectByParagraph];
[self setSelectionGranularity:granularities[[event clickCount]]];
-
+
+ if ([self selectionGranularity] == CPSelectByCharacter && CPLocationInRange(_startTrackingLocation, _selectionRange))
+ {
+ var lineBeginningIndex = [_layoutManager _firstLineFragmentForLineFromLocation:_selectionRange.location]._range.location,
+ placeholderRange = _MakeRangeFromAbs(lineBeginningIndex, CPMaxRange(_selectionRange)),
+ placeholderString = [_textStorage attributedSubstringFromRange:placeholderRange],
+ placeholderFrame = CGRectIntersection([_layoutManager boundingRectForGlyphRange:placeholderRange inTextContainer:_textContainer], _frame),
+ rangeToHide = CPMakeRange(0, _selectionRange.location - lineBeginningIndex),
+ dragPlaceholder;
+
+ // hide the left part of the first line of the selection that is not included
+ [placeholderString addAttribute:CPForegroundColorAttributeName
+ value:[CPColor colorWithRed:1 green:1 blue:1 alpha:0]
+ range:rangeToHide];
+
+ _movingSelection = CPMakeRange(_startTrackingLocation, 0);
+
+ dragPlaceholder = [[CPTextView alloc] initWithFrame:placeholderFrame];
+ [dragPlaceholder insertText:placeholderString];
+ [dragPlaceholder setBackgroundColor:[CPColor colorWithRed:1 green:1 blue:1 alpha:0]];
+ [dragPlaceholder setAlphaValue:0.5];
+
+ var stringForPasting = [_textStorage attributedSubstringFromRange:CPMakeRangeCopy(_selectionRange)],
+ richData = [_CPRTFProducer produceRTF:stringForPasting documentAttributes:@{}],
+ draggingPasteboard = [CPPasteboard pasteboardWithName:CPDragPboard];
+ [draggingPasteboard declareTypes:[CPRTFPboardType] owner:nil];
+ [draggingPasteboard setString:richData forType:CPRTFPboardType];
+
+ [self dragView:dragPlaceholder
+ at:placeholderFrame.origin
+ offset:nil
+ event:event
+ pasteboard:draggingPasteboard
+ source:self
+ slideBack:YES];
+
+ return;
+ }
+
var setRange = CPMakeRange(_startTrackingLocation, 0);
-
+
if ([event modifierFlags] & CPShiftKeyMask)
setRange = _MakeRangeFromAbs(_startTrackingLocation < _MidRange(_selectionRange) ? CPMaxRange(_selectionRange) : _selectionRange.location, _startTrackingLocation);
else
@@ -943,22 +991,11 @@ var kDelegateRespondsTo_textShouldBeginEditing
- (void)mouseDragged:(CPEvent)event
{
- var fraction = [],
- point = [self convertPoint:[event locationInWindow] fromView:nil];
-
- // convert to container coordinate
- point.x -= _textContainerOrigin.x;
- point.y -= _textContainerOrigin.y;
-
+ if (_movingSelection)
+ return;
+
var oldRange = [self selectedRange],
- index = [_layoutManager glyphIndexForPoint:point
- inTextContainer:_textContainer
- fractionOfDistanceThroughGlyph:fraction];
-
- if (index === CPNotFound)
- index = _scrollingDownward ? CPMaxRange(oldRange) : oldRange.location;
- else if (fraction[0] > 0.5)
- index++;
+ index = [self _characterIndexFromEvent:event];
if (index > oldRange.location)
_scrollingDownward = YES;
@@ -977,7 +1014,9 @@ var kDelegateRespondsTo_textShouldBeginEditing
- (void)mouseUp:(CPEvent)event
{
- /* will post CPTextViewDidChangeSelectionNotification */
+ _movingSelection = nil;
+
+ // will post CPTextViewDidChangeSelectionNotification
_previousSelectionGranularity = [self selectionGranularity];
[self setSelectionGranularity:CPSelectByCharacter];
[self setSelectedRange:[self selectedRange] affinity:0 stillSelecting:NO];
@@ -1965,6 +2004,15 @@ var kDelegateRespondsTo_textShouldBeginEditing
[_caret startBlinking];
}
+- (void)draggingUpdated:(CPDraggingInfo)info
+{
+ var point = [info draggingLocation],
+ location = [self _characterIndexFromRawPoint:point];
+
+ _movingSelection = CPMakeRange(location, 0);
+ [_caret _drawCaretAtLocation:_movingSelection.location];
+ [_caret setVisibility:YES];
+}
#pragma mark -
#pragma mark Dragging operation
@@ -1973,11 +2021,33 @@ var kDelegateRespondsTo_textShouldBeginEditing
{
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard];
+
+ if ([pasteboard availableTypeFromArray:[CPRTFPboardType]])
+ {
+ [_caret setVisibility:NO];
+
+ if (CPLocationInRange(_movingSelection.location, _selectionRange))
+ {
+ [self setSelectedRange:_movingSelection];
+ _movingSelection = nil;
+ return;
+ }
- if (![pasteboard availableTypeFromArray:[CPColorDragType]])
- return NO;
+ if (_movingSelection.location > CPMaxRange(_selectionRange))
+ _movingSelection.location -= _selectionRange.length;
+
+ [self _deleteForRange:_selectionRange];
+ [self setSelectedRange:_movingSelection];
- [self setTextColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] range:_selectionRange];
+ var dataForPasting = [pasteboard stringForType:CPRTFPboardType];
+ // setTimeout is to a work around a transaction issue with the undomanager
+ setTimeout(function(){
+ [self insertText:[[_CPRTFParser new] parseRTF:dataForPasting]];
+ }, 0);
+ }
+
+ if ([pasteboard availableTypeFromArray:[CPColorDragType]])
+ [self setTextColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] range:_selectionRange];
}
@end
@@ -2254,6 +2324,12 @@ var CPTextViewAllowsUndoKey = @"CPTextViewAllowsUndoKey",
_caretTimer = nil;
}
}
+
+- (void)_drawCaretAtLocation:(int)aLoc
+{
+ var rect = [_textView._layoutManager boundingRectForGlyphRange:CPMakeRange(aLoc, 1) inTextContainer:_textView._textContainer];
+ [self setRect:rect];
+}
@end
@@ -2639,6 +2715,7 @@ var _CPCopyPlaceholder = '-';
-(void) _setRegularExpression:(JSObject)re toFontTrait:(CPFontTrait)aTrait
{
+ var match;
while (match = re.exec(_string))
{
var attribs = [[self attributesAtIndex:match.index effectiveRange:nil] copy],
@@ -2650,6 +2727,7 @@ var _CPCopyPlaceholder = '-';
-(void) _replaceEveryOccurenceOfRegularExpression:(JSObject)re withString:(CPString)aString
{
+ var match;
while (match = re.exec(_string))
[self replaceCharactersInRange:CPMakeRange(match.index, match[0].length) withString:aString];
}
@@ -2663,6 +2741,7 @@ var _CPCopyPlaceholder = '-';
[self _replaceEveryOccurenceOfRegularExpression:/&lt;/i withString:'<'];
[self _replaceEveryOccurenceOfRegularExpression:/&gt;/i withString:'>'];
[self _replaceEveryOccurenceOfRegularExpression:/&amp;/i withString:'&'];
+ [self _replaceEveryOccurenceOfRegularExpression:/&nbsp;/i withString:' '];
return self;
}
@@ -514,6 +514,9 @@ var kRgsymRtf = {
return [self _applyPropChange:sym parameter:param];
case kRTFParserType_char:
+ if((param + '') !== 'NaN' && (param + '').length)
+ _currentParseIndex -= (param + '').length;
+
return [self _checkChar:sym parameter:param];
case kRTFParserType_dest:
@@ -785,4 +788,4 @@ var kRgsymRtf = {
return _result;
}
-@end
+@end

0 comments on commit 65f701d

Please sign in to comment.