mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-25 18:11:13 +00:00
Fix drag and drop of file objects - invoke cleanUpAfterDragOperation on lastDragView on NSWindow and add cleanup code to cleanUpAfterDragOperation in NSTextView
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/branches/gnustep_testplant_branch@35896 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
09efaeba41
commit
43a41c50fc
2 changed files with 147 additions and 114 deletions
|
@ -513,8 +513,7 @@ this happens when layout has been invalidated, and when we are resized.
|
||||||
[self sizeToFit];
|
[self sizeToFit];
|
||||||
/* TODO: we don't have to redisplay the entire view */
|
/* TODO: we don't have to redisplay the entire view */
|
||||||
[self setNeedsDisplay: YES];
|
[self setNeedsDisplay: YES];
|
||||||
[self updateInsertionPointStateAndRestartTimer:
|
[self updateInsertionPointStateAndRestartTimer: [self shouldDrawInsertionPoint]];
|
||||||
[self shouldDrawInsertionPoint]];
|
|
||||||
[self _updateInputMethodState];
|
[self _updateInputMethodState];
|
||||||
/* In case any sections of text with custom cursors were moved */
|
/* In case any sections of text with custom cursors were moved */
|
||||||
[[self window] invalidateCursorRectsForView: self];
|
[[self window] invalidateCursorRectsForView: self];
|
||||||
|
@ -4111,132 +4110,156 @@ Figure out how the additional layout stuff is supposed to work.
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) _stopInsertionTimer
|
||||||
|
{
|
||||||
|
if (_insertionPointTimer)
|
||||||
|
{
|
||||||
|
[_insertionPointTimer invalidate];
|
||||||
|
DESTROY(_insertionPointTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) _startInsertionTimer
|
||||||
|
{
|
||||||
|
if (_insertionPointTimer)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"Starting insertion timer with existing one running");
|
||||||
|
[self _stopInsertionTimer];
|
||||||
|
}
|
||||||
|
_insertionPointTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5
|
||||||
|
target: self
|
||||||
|
selector: @selector(_blink:)
|
||||||
|
userInfo: nil
|
||||||
|
repeats: YES];
|
||||||
|
RETAIN(_insertionPointTimer);
|
||||||
|
}
|
||||||
|
|
||||||
- (void) updateInsertionPointStateAndRestartTimer: (BOOL)restartFlag
|
- (void) updateInsertionPointStateAndRestartTimer: (BOOL)restartFlag
|
||||||
{
|
{
|
||||||
NSRect new;
|
NSRect new;
|
||||||
|
|
||||||
if (!_layoutManager)
|
if (!_layoutManager)
|
||||||
{
|
{
|
||||||
_insertionPointRect = NSZeroRect;
|
_insertionPointRect = NSZeroRect;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are in the middle of a dragging operation...
|
||||||
if (_dragTargetLocation != NSNotFound)
|
if (_dragTargetLocation != NSNotFound)
|
||||||
{
|
{
|
||||||
_tf.drag_target_hijacks_insertion_point = YES;
|
_tf.drag_target_hijacks_insertion_point = YES;
|
||||||
|
|
||||||
new = [_layoutManager
|
new = [_layoutManager
|
||||||
insertionPointRectForCharacterIndex: _dragTargetLocation
|
insertionPointRectForCharacterIndex: _dragTargetLocation
|
||||||
inTextContainer: _textContainer];
|
inTextContainer: _textContainer];
|
||||||
|
|
||||||
new.origin.x += _textContainerOrigin.x;
|
new.origin.x += _textContainerOrigin.x;
|
||||||
new.origin.y += _textContainerOrigin.y;
|
new.origin.y += _textContainerOrigin.y;
|
||||||
|
|
||||||
/* If the insertion would extend outside the view (e.g. because it's
|
/* If the insertion would extend outside the view (e.g. because it's
|
||||||
just to the right of a character on the far right edge of the view,
|
just to the right of a character on the far right edge of the view,
|
||||||
a common case for right-aligned text), we force it back in. */
|
a common case for right-aligned text), we force it back in. */
|
||||||
if (NSMaxX(new) > NSMaxX(_bounds))
|
if (NSMaxX(new) > NSMaxX(_bounds))
|
||||||
{
|
{
|
||||||
new.origin.x = NSMaxX(_bounds) - new.size.width;
|
new.origin.x = NSMaxX(_bounds) - new.size.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_layoutManager->_selected_range.length > 0 ||
|
else if (_layoutManager->_selected_range.length > 0 ||
|
||||||
_layoutManager->_selected_range.location == NSNotFound ||
|
_layoutManager->_selected_range.location == NSNotFound ||
|
||||||
!restartFlag)
|
!restartFlag)
|
||||||
{
|
{
|
||||||
new = NSZeroRect;
|
new = NSZeroRect;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new = [_layoutManager
|
new = [_layoutManager
|
||||||
insertionPointRectForCharacterIndex: _layoutManager->_selected_range.location
|
insertionPointRectForCharacterIndex: _layoutManager->_selected_range.location
|
||||||
inTextContainer: _textContainer];
|
inTextContainer: _textContainer];
|
||||||
|
|
||||||
new.origin.x += _textContainerOrigin.x;
|
new.origin.x += _textContainerOrigin.x;
|
||||||
new.origin.y += _textContainerOrigin.y;
|
new.origin.y += _textContainerOrigin.y;
|
||||||
|
|
||||||
/* If the insertion would extend outside the view (e.g. because it's
|
/* If the insertion would extend outside the view (e.g. because it's
|
||||||
just to the right of a character on the far right edge of the view,
|
just to the right of a character on the far right edge of the view,
|
||||||
a common case for right-aligned text), we force it back in. */
|
a common case for right-aligned text), we force it back in. */
|
||||||
if (NSMaxX(new) > NSMaxX(_bounds))
|
if (NSMaxX(new) > NSMaxX(_bounds))
|
||||||
{
|
{
|
||||||
new.origin.x = NSMaxX(_bounds) - new.size.width;
|
new.origin.x = NSMaxX(_bounds) - new.size.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle hijacked insertion point (either set above when entering this
|
/* Handle hijacked insertion point (either set above when entering this
|
||||||
method or during the previous call to this method) */
|
method or during the previous call to this method) */
|
||||||
if (_tf.drag_target_hijacks_insertion_point)
|
if (_tf.drag_target_hijacks_insertion_point)
|
||||||
{
|
{
|
||||||
|
// Erase previous insertion point line...
|
||||||
_drawInsertionPointNow = NO;
|
_drawInsertionPointNow = NO;
|
||||||
[self setNeedsDisplayInRect: _insertionPointRect
|
[self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
|
||||||
avoidAdditionalLayout: YES];
|
|
||||||
|
// Save new insertion point rectangle...
|
||||||
_insertionPointRect = new;
|
_insertionPointRect = new;
|
||||||
|
|
||||||
if (_dragTargetLocation != NSNotFound)
|
if (_dragTargetLocation != NSNotFound)
|
||||||
{
|
{
|
||||||
_insertionPointRect = new;
|
// Draw insertion point line in new location...
|
||||||
_drawInsertionPointNow = YES;
|
_drawInsertionPointNow = YES;
|
||||||
[self setNeedsDisplayInRect: _insertionPointRect
|
[self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
|
||||||
avoidAdditionalLayout: YES];
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
_tf.drag_target_hijacks_insertion_point = NO;
|
{
|
||||||
|
// Drag either completed or cancelled...
|
||||||
|
_tf.drag_target_hijacks_insertion_point = NO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, draw insertion point only if there is a need to do so */
|
/* Otherwise, draw insertion point only if there is a need to do so */
|
||||||
else if ([self shouldDrawInsertionPoint] || _drawInsertionPointNow)
|
else if ([self shouldDrawInsertionPoint] || _drawInsertionPointNow)
|
||||||
{
|
{
|
||||||
if (restartFlag)
|
if (restartFlag)
|
||||||
{
|
{
|
||||||
/* Start blinking timer if not yet started */
|
/* Start blinking timer if not yet started */
|
||||||
if (_insertionPointTimer == nil && [self shouldDrawInsertionPoint])
|
if (_insertionPointTimer == nil && [self shouldDrawInsertionPoint])
|
||||||
{
|
{
|
||||||
// NSLog(@"Start timer");
|
// Save new insertion point rectangle before starting the insertion timer...
|
||||||
_insertionPointRect = new;
|
_insertionPointRect = new;
|
||||||
_insertionPointTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5
|
[self _startInsertionTimer];
|
||||||
target: self
|
}
|
||||||
selector: @selector(_blink:)
|
else if (_insertionPointTimer != nil)
|
||||||
userInfo: nil
|
{
|
||||||
repeats: YES];
|
// Erase previous insertion point line...
|
||||||
RETAIN (_insertionPointTimer);
|
if (!NSEqualRects(new, _insertionPointRect))
|
||||||
}
|
{
|
||||||
else if (_insertionPointTimer != nil)
|
_drawInsertionPointNow = NO;
|
||||||
{
|
[self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
|
||||||
if (!NSEqualRects(new, _insertionPointRect))
|
|
||||||
{
|
// Save new insertion point rectangle...
|
||||||
_drawInsertionPointNow = NO;
|
_insertionPointRect = new;
|
||||||
[self setNeedsDisplayInRect: _insertionPointRect
|
}
|
||||||
avoidAdditionalLayout: YES];
|
}
|
||||||
_insertionPointRect = new;
|
|
||||||
}
|
/* Ok - blinking has just been turned on. Make sure we start
|
||||||
}
|
* the on/off/on/off blinking from the 'on', because in that way
|
||||||
|
* the user can see where the insertion point is as soon as
|
||||||
/* Ok - blinking has just been turned on. Make sure we start
|
* possible.
|
||||||
* the on/off/on/off blinking from the 'on', because in that way
|
*/
|
||||||
* the user can see where the insertion point is as soon as
|
_drawInsertionPointNow = YES;
|
||||||
* possible.
|
[self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
|
||||||
*/
|
}
|
||||||
_drawInsertionPointNow = YES;
|
|
||||||
[self setNeedsDisplayInRect: _insertionPointRect
|
|
||||||
avoidAdditionalLayout: YES];
|
|
||||||
}
|
|
||||||
else if ([self shouldDrawInsertionPoint] && (_insertionPointTimer != nil))
|
else if ([self shouldDrawInsertionPoint] && (_insertionPointTimer != nil))
|
||||||
{
|
{
|
||||||
// restartFlag is set to NO when control resigns first responder
|
// restartFlag is set to NO when control resigns first responder
|
||||||
// status or window resings key window status. So we invalidate
|
// status or window resings key window status. So we invalidate
|
||||||
// timer to avoid extra method calls
|
// timer to avoid extra method calls
|
||||||
// NSLog(@"Stop timer");
|
[self _stopInsertionTimer];
|
||||||
[_insertionPointTimer invalidate];
|
|
||||||
DESTROY (_insertionPointTimer);
|
// Erase previous insertion point line...
|
||||||
|
_drawInsertionPointNow = NO;
|
||||||
_drawInsertionPointNow = NO;
|
[self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
|
||||||
[self setNeedsDisplayInRect: _insertionPointRect
|
|
||||||
avoidAdditionalLayout: YES];
|
// Save new insertion point rectangle...
|
||||||
|
_insertionPointRect = new;
|
||||||
_insertionPointRect = new;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[self _updateInputMethodWithInsertionPoint: _insertionPointRect.origin];
|
[self _updateInputMethodWithInsertionPoint: _insertionPointRect.origin];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4268,16 +4291,16 @@ Figure out how the additional layout stuff is supposed to work.
|
||||||
effectiveRange: &lineFragGlyphRange];
|
effectiveRange: &lineFragGlyphRange];
|
||||||
|
|
||||||
if (NSMaxY(lineFragRect) <= NSMaxY(proposedPage))
|
if (NSMaxY(lineFragRect) <= NSMaxY(proposedPage))
|
||||||
{
|
{
|
||||||
actualTextBottom = NSMaxY(lineFragRect);
|
actualTextBottom = NSMaxY(lineFragRect);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We encountered a visible glyph fragment which extents below
|
// We encountered a visible glyph fragment which extents below
|
||||||
// the bottom of the page
|
// the bottom of the page
|
||||||
needsToMoveBottom = YES;
|
needsToMoveBottom = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = lineFragGlyphRange.location - 1;
|
i = lineFragGlyphRange.location - 1;
|
||||||
}
|
}
|
||||||
|
@ -5188,23 +5211,23 @@ other than copy/paste or dragging. */
|
||||||
{
|
{
|
||||||
NSPoint dragPoint;
|
NSPoint dragPoint;
|
||||||
unsigned dragIndex;
|
unsigned dragIndex;
|
||||||
|
|
||||||
dragPoint = [sender draggingLocation];
|
dragPoint = [sender draggingLocation];
|
||||||
dragPoint = [self convertPoint: dragPoint fromView: nil];
|
dragPoint = [self convertPoint: dragPoint fromView: nil];
|
||||||
dragIndex = [self _characterIndexForPoint: dragPoint
|
dragIndex = [self _characterIndexForPoint: dragPoint
|
||||||
respectFraction: YES];
|
respectFraction: YES];
|
||||||
|
|
||||||
if ([sender draggingSource] != self ||
|
if ([sender draggingSource] != self ||
|
||||||
dragIndex <= [self selectedRange].location ||
|
dragIndex <= [self selectedRange].location ||
|
||||||
dragIndex >= NSMaxRange([self selectedRange]))
|
dragIndex >= NSMaxRange([self selectedRange]))
|
||||||
{
|
{
|
||||||
_dragTargetLocation = dragIndex;
|
_dragTargetLocation = dragIndex;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dragTargetLocation = NSNotFound;
|
_dragTargetLocation = NSNotFound;
|
||||||
*flags = NSDragOperationNone;
|
*flags = NSDragOperationNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_dragTargetLocation != NSNotFound)
|
else if (_dragTargetLocation != NSNotFound)
|
||||||
{
|
{
|
||||||
|
@ -5335,11 +5358,11 @@ other than copy/paste or dragging. */
|
||||||
if ([self readSelectionFromPasteboard: pboard type: type])
|
if ([self readSelectionFromPasteboard: pboard type: type])
|
||||||
{
|
{
|
||||||
if (![type isEqual: NSColorPboardType])
|
if (![type isEqual: NSColorPboardType])
|
||||||
{
|
{
|
||||||
changeRange.length =
|
changeRange.length =
|
||||||
[self selectedRange].location - changeRange.location;
|
[self selectedRange].location - changeRange.location;
|
||||||
[self setSelectedRange: changeRange];
|
[self setSelectedRange: changeRange];
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
return NO;
|
return NO;
|
||||||
|
@ -5351,7 +5374,10 @@ other than copy/paste or dragging. */
|
||||||
|
|
||||||
- (void) cleanUpAfterDragOperation
|
- (void) cleanUpAfterDragOperation
|
||||||
{
|
{
|
||||||
// release drag information
|
// Cleanup information after dragging operation completes...
|
||||||
|
_dragTargetLocation = NSNotFound;
|
||||||
|
[self updateInsertionPointStateAndRestartTimer: NO];
|
||||||
|
[self displayIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (unsigned int) dragOperationForDraggingInfo: (id <NSDraggingInfo>)dragInfo
|
- (unsigned int) dragOperationForDraggingInfo: (id <NSDraggingInfo>)dragInfo
|
||||||
|
@ -6034,8 +6060,7 @@ or add guards
|
||||||
_drawInsertionPointNow = YES;
|
_drawInsertionPointNow = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setNeedsDisplayInRect: _insertionPointRect
|
[self setNeedsDisplayInRect: _insertionPointRect avoidAdditionalLayout: YES];
|
||||||
avoidAdditionalLayout: YES];
|
|
||||||
/* Because we are called by a timer which is independent of any
|
/* Because we are called by a timer which is independent of any
|
||||||
event processing in the gui runloop, we need to manually update
|
event processing in the gui runloop, we need to manually update
|
||||||
the window. */
|
the window. */
|
||||||
|
|
|
@ -4301,8 +4301,8 @@ resetCursorRectsForView(NSView *theView)
|
||||||
case GSAppKitDraggingDrop:
|
case GSAppKitDraggingDrop:
|
||||||
NSDebugLLog(@"NSDragging", @"GSAppKitDraggingDrop");
|
NSDebugLLog(@"NSDragging", @"GSAppKitDraggingDrop");
|
||||||
dragInfo = [GSServerForWindow(self) dragInfo];
|
dragInfo = [GSServerForWindow(self) dragInfo];
|
||||||
if (_lastDragView && _f.accepts_drag
|
if (_lastDragView && _f.accepts_drag &&
|
||||||
&& _lastDragOperationMask != NSDragOperationNone)
|
_lastDragOperationMask != NSDragOperationNone)
|
||||||
{
|
{
|
||||||
action = YES;
|
action = YES;
|
||||||
GSPerformDragSelector(_lastDragView,
|
GSPerformDragSelector(_lastDragView,
|
||||||
|
@ -4318,6 +4318,14 @@ resetCursorRectsForView(NSView *theView)
|
||||||
GSPerformVoidDragSelector(_lastDragView,
|
GSPerformVoidDragSelector(_lastDragView,
|
||||||
@selector(concludeDragOperation:), dragInfo);
|
@selector(concludeDragOperation:), dragInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for specific cleanup after drag methods...
|
||||||
|
if ([_lastDragView respondsToSelector: @selector(cleanUpAfterDragOperation)])
|
||||||
|
{
|
||||||
|
GSPerformVoidDragSelector(_lastDragView,
|
||||||
|
@selector(cleanUpAfterDragOperation),
|
||||||
|
dragInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_lastDragOperationMask = NSDragOperationNone;
|
_lastDragOperationMask = NSDragOperationNone;
|
||||||
DESTROY(_lastDragView);
|
DESTROY(_lastDragView);
|
||||||
|
|
Loading…
Reference in a new issue