mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-31 20:40:47 +00:00
Make outline view DnD fully functioual.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@29083 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
b70463270b
commit
8d0b8c6fbc
2 changed files with 258 additions and 263 deletions
|
@ -1,3 +1,10 @@
|
|||
2009-11-30 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSOutlineView.m: Improve DnD allowing drop on items as well
|
||||
as inside them. Attempt to mimix OSX behavior. Simplify code.
|
||||
Use triangular images similar to OSX appearance.
|
||||
Doubtless needs more polishing.
|
||||
|
||||
2009-11-29 Wolfgang Lux <wolfgang.lux@gmail.com>
|
||||
|
||||
* Source/NSView.m (-dealloc): Fix bug where -dealloc could break
|
||||
|
|
|
@ -66,11 +66,11 @@ static int lastVerticalQuarterPosition;
|
|||
static int lastHorizontalHalfPosition;
|
||||
|
||||
static NSRect oldDraggingRect;
|
||||
static int oldDropRow;
|
||||
static int oldProposedDropRow;
|
||||
static int currentDropRow;
|
||||
static int oldDropLevel;
|
||||
static int currentDropLevel;
|
||||
static id oldDropItem;
|
||||
static id currentDropItem;
|
||||
static int oldDropIndex;
|
||||
static int currentDropIndex;
|
||||
|
||||
static NSMutableSet *autoExpanded = nil;
|
||||
static NSDate *lastDragUpdate = nil;
|
||||
static NSDate *lastDragChange = nil;
|
||||
|
@ -134,9 +134,18 @@ static NSImage *unexpandable = nil;
|
|||
{
|
||||
[self setVersion: current_version];
|
||||
nc = [NSNotificationCenter defaultCenter];
|
||||
#if 0
|
||||
/* Old Interface Builder style. */
|
||||
collapsed = [NSImage imageNamed: @"common_outlineCollapsed"];
|
||||
expanded = [NSImage imageNamed: @"common_outlineExpanded"];
|
||||
unexpandable = [NSImage imageNamed: @"common_outlineUnexpandable"];
|
||||
#else
|
||||
/* Current OSX style images. */
|
||||
// FIXME ... better ones?
|
||||
collapsed = [NSImage imageNamed: @"common_ArrowRightH"];
|
||||
expanded = [NSImage imageNamed: @"common_ArrowDownH"];
|
||||
unexpandable = [[NSImage alloc] initWithSize: [expanded size]];
|
||||
#endif
|
||||
autoExpanded = [NSMutableSet new];
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +288,7 @@ static NSImage *unexpandable = nil;
|
|||
* Expands the given item only. This is the equivalent of calling
|
||||
* [NSOutlineView-expandItem:expandChildren:] with NO.
|
||||
*/
|
||||
- (void)expandItem: (id)item
|
||||
- (void) expandItem: (id)item
|
||||
{
|
||||
[self expandItem: item expandChildren: NO];
|
||||
}
|
||||
|
@ -796,7 +805,7 @@ static NSImage *unexpandable = nil;
|
|||
/*
|
||||
* Drawing
|
||||
*/
|
||||
- (void)drawRow: (int)rowIndex clipRect: (NSRect)aRect
|
||||
- (void) drawRow: (int)rowIndex clipRect: (NSRect)aRect
|
||||
{
|
||||
int startingColumn;
|
||||
int endingColumn;
|
||||
|
@ -955,30 +964,21 @@ static NSImage *unexpandable = nil;
|
|||
[super drawRect: aRect];
|
||||
}
|
||||
|
||||
- (void) setDropItem: (id) item
|
||||
dropChildIndex: (int) childIndex
|
||||
- (void) setDropItem: (id)item
|
||||
dropChildIndex: (int)childIndex
|
||||
{
|
||||
int row = [_items indexOfObject: item];
|
||||
id itemAfter;
|
||||
|
||||
if (row == NSNotFound)
|
||||
if (item != nil && [_items indexOfObject: item] == NSNotFound)
|
||||
{
|
||||
/* FIXME raise an exception, or perhaps we should support
|
||||
* setting an item which is not visible (inside a collapsed
|
||||
* item presumably), or perhaps we should treat this as
|
||||
* cancelling the drop?
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (childIndex == NSOutlineViewDropOnItemIndex)
|
||||
{
|
||||
currentDropRow = row;
|
||||
currentDropLevel = NSOutlineViewDropOnItemIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemAfter = [_dataSource outlineView: self
|
||||
child: childIndex
|
||||
ofItem: item];
|
||||
currentDropRow = [_items indexOfObject: itemAfter];
|
||||
currentDropLevel = [self levelForItem: itemAfter];
|
||||
}
|
||||
currentDropItem = item;
|
||||
currentDropIndex = childIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -988,9 +988,8 @@ static NSImage *unexpandable = nil;
|
|||
- (NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
|
||||
{
|
||||
//NSLog(@"draggingEntered");
|
||||
currentDropRow = -1;
|
||||
// currentDropOperation = -1;
|
||||
oldDropRow = -1;
|
||||
oldDropItem = currentDropItem = nil;
|
||||
oldDropIndex = currentDropIndex = -1;
|
||||
lastVerticalQuarterPosition = -1;
|
||||
oldDraggingRect = NSMakeRect(0.,0., 0., 0.);
|
||||
return NSDragOperationCopy;
|
||||
|
@ -1013,10 +1012,10 @@ static NSImage *unexpandable = nil;
|
|||
int row;
|
||||
int verticalQuarterPosition;
|
||||
int horizontalHalfPosition;
|
||||
int positionInRow;
|
||||
int levelBefore;
|
||||
int levelAfter;
|
||||
int level;
|
||||
BOOL dropOn = NO;
|
||||
NSDragOperation dragOperation = [sender draggingSourceOperationMask];
|
||||
|
||||
ASSIGN(lastDragUpdate, [NSDate date]);
|
||||
|
@ -1028,23 +1027,13 @@ static NSImage *unexpandable = nil;
|
|||
horizontalHalfPosition =
|
||||
((p.x - _bounds.origin.y) / _indentationPerLevel) * 2.;
|
||||
|
||||
|
||||
row = verticalQuarterPosition;
|
||||
row = row % 4;
|
||||
if (row == 1 || row == 2) dropOn = YES;
|
||||
|
||||
if ((verticalQuarterPosition - oldProposedDropRow * 4 <= 2)
|
||||
&& (verticalQuarterPosition - oldProposedDropRow * 4 >= -3))
|
||||
{
|
||||
row = oldProposedDropRow;
|
||||
}
|
||||
else
|
||||
{
|
||||
row = (verticalQuarterPosition + 2) / 4;
|
||||
}
|
||||
|
||||
row = (verticalQuarterPosition + 1) / 4;
|
||||
positionInRow = verticalQuarterPosition % 4;
|
||||
if (row > _numberOfRows)
|
||||
row = _numberOfRows;
|
||||
{
|
||||
row = _numberOfRows; // beyond the last real row
|
||||
positionInRow = 1; // inside the root item
|
||||
}
|
||||
|
||||
//NSLog(@"horizontalHalfPosition = %d", horizontalHalfPosition);
|
||||
|
||||
|
@ -1079,22 +1068,30 @@ static NSImage *unexpandable = nil;
|
|||
{
|
||||
int childIndex;
|
||||
|
||||
/* Save positions to avoid executing this code when the general
|
||||
* position of the mouse is unchanged.
|
||||
*/
|
||||
lastVerticalQuarterPosition = verticalQuarterPosition;
|
||||
lastHorizontalHalfPosition = horizontalHalfPosition;
|
||||
|
||||
if (horizontalHalfPosition / 2 < levelAfter)
|
||||
horizontalHalfPosition = levelAfter * 2;
|
||||
else if (horizontalHalfPosition / 2 > levelBefore)
|
||||
horizontalHalfPosition = levelBefore * 2 + 1;
|
||||
level = horizontalHalfPosition / 2;
|
||||
|
||||
|
||||
lastVerticalQuarterPosition = verticalQuarterPosition;
|
||||
lastHorizontalHalfPosition = horizontalHalfPosition;
|
||||
|
||||
//NSLog(@"horizontalHalfPosition = %d", horizontalHalfPosition);
|
||||
//NSLog(@"verticalQuarterPosition = %d", verticalQuarterPosition);
|
||||
|
||||
currentDropRow = row;
|
||||
currentDropLevel = level;
|
||||
|
||||
if (positionInRow > 0 && positionInRow < 3)
|
||||
{
|
||||
/* We are directly over the middle of a row ... so the drop
|
||||
* should be directory on the item in that row.
|
||||
*/
|
||||
item = [self itemAtRow: row];
|
||||
childIndex = NSOutlineViewDropOnItemIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
int j = 0;
|
||||
|
@ -1120,12 +1117,9 @@ static NSImage *unexpandable = nil;
|
|||
childIndex = j;
|
||||
}
|
||||
|
||||
if (YES == dropOn)
|
||||
{
|
||||
childIndex = NSOutlineViewDropOnItemIndex;
|
||||
}
|
||||
currentDropItem = item;
|
||||
currentDropIndex = childIndex;
|
||||
|
||||
oldProposedDropRow = currentDropRow;
|
||||
if ([_dataSource respondsToSelector:
|
||||
@selector(outlineView:validateDrop:proposedItem:proposedChildIndex:)])
|
||||
{
|
||||
|
@ -1135,10 +1129,15 @@ static NSImage *unexpandable = nil;
|
|||
proposedChildIndex: childIndex];
|
||||
}
|
||||
|
||||
if ((currentDropRow != oldDropRow) || (currentDropLevel != oldDropLevel))
|
||||
//NSLog(@"Drop on %@ %d", currentDropItem, currentDropIndex);
|
||||
if ((currentDropItem != oldDropItem)
|
||||
|| (currentDropIndex != oldDropIndex))
|
||||
{
|
||||
NSBezierPath *path;
|
||||
|
||||
oldDropItem = currentDropItem;
|
||||
oldDropIndex = currentDropIndex;
|
||||
|
||||
ASSIGN(lastDragChange, lastDragUpdate);
|
||||
[self lockFocus];
|
||||
|
||||
|
@ -1147,34 +1146,69 @@ static NSImage *unexpandable = nil;
|
|||
|
||||
[[NSColor darkGrayColor] set];
|
||||
|
||||
//NSLog(@"currentDropLevel %d, currentDropRow %d",
|
||||
//currentDropLevel, currentDropRow);
|
||||
|
||||
if (currentDropLevel != NSOutlineViewDropOnItemIndex)
|
||||
if (currentDropIndex != NSOutlineViewDropOnItemIndex)
|
||||
{
|
||||
if (currentDropRow == 0)
|
||||
int numberOfChildren;
|
||||
|
||||
numberOfChildren = [_dataSource outlineView: self
|
||||
numberOfChildrenOfItem: currentDropItem];
|
||||
|
||||
if (currentDropIndex >= numberOfChildren)
|
||||
{
|
||||
/* The index lies beyond the last item,
|
||||
* so we get the last but one item and we
|
||||
* use the row after it. If there are no
|
||||
* children at all, we use the parent item row.
|
||||
*/
|
||||
if (numberOfChildren == 0)
|
||||
{
|
||||
row = [self rowForItem: currentDropItem];
|
||||
}
|
||||
else
|
||||
{
|
||||
item = [_dataSource outlineView: self
|
||||
child: numberOfChildren - 1
|
||||
ofItem: currentDropItem];
|
||||
|
||||
row = [self rowForItem: item] + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find the row for the item containing the child
|
||||
* we will be dropping on.
|
||||
*/
|
||||
item = [_dataSource outlineView: self
|
||||
child: currentDropIndex
|
||||
ofItem: currentDropItem];
|
||||
row = [self rowForItem: item];
|
||||
}
|
||||
|
||||
level = [self levelForItem: item];
|
||||
if (currentDropItem == nil && currentDropIndex == 0)
|
||||
{
|
||||
newRect = NSMakeRect([self visibleRect].origin.x,
|
||||
currentDropRow * _rowHeight,
|
||||
0,
|
||||
[self visibleRect].size.width,
|
||||
2);
|
||||
}
|
||||
else if (currentDropRow == _numberOfRows)
|
||||
else if (row == _numberOfRows)
|
||||
{
|
||||
newRect = NSMakeRect([self visibleRect].origin.x,
|
||||
currentDropRow * _rowHeight - 2,
|
||||
row * _rowHeight - 2,
|
||||
[self visibleRect].size.width,
|
||||
2);
|
||||
}
|
||||
else
|
||||
{
|
||||
newRect = NSMakeRect([self visibleRect].origin.x,
|
||||
currentDropRow * _rowHeight - 1,
|
||||
row * _rowHeight - 1,
|
||||
[self visibleRect].size.width,
|
||||
2);
|
||||
}
|
||||
newRect.origin.x += currentDropLevel * _indentationPerLevel;
|
||||
newRect.size.width -= currentDropLevel * _indentationPerLevel;
|
||||
level++;
|
||||
newRect.origin.x += level * _indentationPerLevel;
|
||||
newRect.size.width -= level * _indentationPerLevel;
|
||||
/* The rectangle is a line across the cell indicating the
|
||||
* insertion position. We adjust by enough pixels to allow for
|
||||
* a ring drawn on the left end.
|
||||
|
@ -1207,8 +1241,10 @@ static NSImage *unexpandable = nil;
|
|||
}
|
||||
else
|
||||
{
|
||||
row = [_items indexOfObject: currentDropItem];
|
||||
level = [self levelForItem: currentDropItem];
|
||||
newRect = [self frameOfCellAtColumn: 0
|
||||
row: currentDropRow];
|
||||
row: row];
|
||||
newRect.origin.x = _bounds.origin.x;
|
||||
newRect.size.width = _bounds.size.width + 2;
|
||||
newRect.origin.x -= _intercellSpacing.height / 2;
|
||||
|
@ -1233,8 +1269,8 @@ static NSImage *unexpandable = nil;
|
|||
{
|
||||
}
|
||||
|
||||
newRect.origin.x += currentDropLevel * _indentationPerLevel;
|
||||
newRect.size.width -= currentDropLevel * _indentationPerLevel;
|
||||
newRect.origin.x += level * _indentationPerLevel;
|
||||
newRect.size.width -= level * _indentationPerLevel;
|
||||
|
||||
NSFrameRectWithWidth(newRect, 2.0);
|
||||
// NSRectFill(newRect);
|
||||
|
@ -1244,23 +1280,6 @@ static NSImage *unexpandable = nil;
|
|||
|
||||
[self unlockFocus];
|
||||
|
||||
oldDropRow = currentDropRow;
|
||||
oldDropLevel = currentDropLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (YES == dropOn)
|
||||
{
|
||||
item = [_items objectAtIndex: currentDropRow];
|
||||
if ([self isExpandable: item] && ![self isItemExpanded: item])
|
||||
{
|
||||
[self expandItem: item expandChildren: NO];
|
||||
if ([self isItemExpanded: item])
|
||||
{
|
||||
[autoExpanded addObject: item];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1268,10 +1287,10 @@ static NSImage *unexpandable = nil;
|
|||
/* If we have been hovering over an item for more than half a second,
|
||||
* we should expand it.
|
||||
*/
|
||||
if (YES == dropOn
|
||||
if (positionInRow > 0 && positionInRow < 3
|
||||
&& [lastDragUpdate timeIntervalSinceDate: lastDragChange] >= 0.5)
|
||||
{
|
||||
item = [_items objectAtIndex: currentDropRow];
|
||||
item = [_items objectAtIndex: row];
|
||||
if ([self isExpandable: item] && ![self isItemExpanded: item])
|
||||
{
|
||||
[self expandItem: item expandChildren: NO];
|
||||
|
@ -1298,42 +1317,10 @@ static NSImage *unexpandable = nil;
|
|||
respondsToSelector:
|
||||
@selector(outlineView:acceptDrop:item:childIndex:)])
|
||||
{
|
||||
id item;
|
||||
int childIndex;
|
||||
|
||||
if (currentDropLevel == NSOutlineViewDropOnItemIndex)
|
||||
{
|
||||
item = [self itemAtRow: currentDropRow];
|
||||
childIndex = currentDropLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
int lvl, i, j = 0;
|
||||
|
||||
for (i = currentDropRow - 1; i >= 0; i--)
|
||||
{
|
||||
lvl = [self levelForRow: i];
|
||||
if (lvl == currentDropLevel - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (lvl == currentDropLevel)
|
||||
{
|
||||
j++;
|
||||
}
|
||||
}
|
||||
if (i == -1)
|
||||
item = nil;
|
||||
else
|
||||
item = [self itemAtRow: i];
|
||||
|
||||
childIndex = j;
|
||||
}
|
||||
|
||||
result = [_dataSource outlineView: self
|
||||
acceptDrop: sender
|
||||
item: item
|
||||
childIndex: childIndex];
|
||||
item: currentDropItem
|
||||
childIndex: currentDropIndex];
|
||||
}
|
||||
|
||||
[self _autoCollapse];
|
||||
|
@ -1469,7 +1456,8 @@ static NSImage *unexpandable = nil;
|
|||
|
||||
if (![self isExpandable: item])
|
||||
{
|
||||
image = unexpandable;
|
||||
// image = unexpandable;
|
||||
image = nil;
|
||||
}
|
||||
|
||||
level = [self levelForItem: item];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue