views:

21

answers:

0

Hello,

I'm trying to subclass NSCollectionView in order to add item padding and eventually work on drag and drop (10.5). I've managed to add the padding but at the loss of the default selection functionality. I've gotten a selection box drawing in the NSCollectionView but I'm having trouble with selecting the items inside the selection box. Currently the code used to generate the selection box is inside a class used to perform actions when the user clicks outside of an NSCollectionViewItem's proper view (i.e. not the padding). It looks like this:

-(void)mouseDown:(NSEvent *)event {
    NSPoint originalClickLocation, finalClickLocation;
    originalClickLocation = [event locationInWindow];
    originalClickLocation.x -= originX;
    originalClickLocation.y -= originY;

    NSRect libraryViewBounds = [cv frame];  
    NSRect selectBox;

    if(NSPointInRect(originalClickLocation, libraryViewBounds)) { //hold on folks, we might dragging something here!        
        while(1) {
            event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | NSLeftMouseUpMask) untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES]; //get the lastest mouse dragged or up event from the window
            finalClickLocation = [event locationInWindow]; //new point of mouse     
            finalClickLocation.x -= originX;
            finalClickLocation.y -= originY;    

            selectBox.origin.y = (originalClickLocation.y < finalClickLocation.y ? originalClickLocation.y : finalClickLocation.y) + originY;
            selectBox.origin.x = (originalClickLocation.x > finalClickLocation.x ? finalClickLocation.x : originalClickLocation.x) + originX;
            selectBox.size.width = originalClickLocation.x > finalClickLocation.x ? originalClickLocation.x - finalClickLocation.x : finalClickLocation.x - originalClickLocation.x;
            selectBox.size.height = originalClickLocation.y > finalClickLocation.y ? originalClickLocation.y - finalClickLocation.y : finalClickLocation.y - originalClickLocation.y;
            selectBox = [cv convertRect:selectBox fromView:nil];

            if([event type] == NSLeftMouseUp)
                break; //finished dragging
            else if(event != nil) {
                [cv setHighlightBox:selectBox];
                //[cv selectItemsInRect:selectBox];
                [cv setNeedsDisplay:YES];               
            }           

    }
        if(!NSEqualPoints(originalClickLocation, finalClickLocation)) {
            NSLog(@"%f,%f to %f,%f",originalClickLocation.x,originalClickLocation.y,finalClickLocation.x,finalClickLocation.y);
            [cv selectItemsInRect:selectBox];
            [cv setNeedsDisplay:YES];
        }
    }
}

The originX/Y variables are simply the distance from the window to the start of the NSCollectionView. cv is a link back to the actual NSCollectionView. Setting the highlightBox for cv means that when told to redraw it draws a red box for the NSRect. It currently does this correctly.

The selectItemsInRect method is a bit of a mess simply because I've been trying many things to get it to work, all to no avail. The problem seems to be the coordinate system. The NSRect created in the mouseDown method has an origin from the bottom, left corner of the NSCollectionView. Before it gets passed to the NSCollectionView to draw it is converted (fromView:nil) and the origin is now from the top, left of the NSCollectionView. Now from what I can tell, the items in the NSCollectionView have origins from the bottom, left of the lowest item in that column (so if there are two rows in column A and one in column B, items on the first row will have different origin.y values).

This has left me all very confused, and when I try to use NSIntersectsRect to work out if the selection box includes an item it often selects the vertically flipped opposite item (two items in a column, drag the select box over the top one, the bottom is selected).

I've been looking at this for a good while now and trying various things and all I've managed to do is become utterly confused. I'm hoping this is something that gets messed around with a fair bit and that someone has a simple explanation of how I'm going wrong.

I'm happy to post more code if I've missed something important out.

Thanks.