blob: 8ef06827f65d4d13cbd2698e6fd63983de75d7d7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/bookmark_button.h"
NSString* kBookmarkButtonDragType = @"ChromiumBookmarkButtonDragType";
// http://codereview.chromium.org/180036/diff/3001/3004
namespace {
const CGFloat kWebDragStartHysteresisX = 5.0;
const CGFloat kWebDragStartHysteresisY = 5.0;
}
@implementation BookmarkButton
@synthesize draggable = draggable_;
- (id)initWithFrame:(NSRect)frame {
if ((self = [super initWithFrame:frame])) {
draggable_ = YES;
}
return self;
}
// By default, NSButton ignores middle-clicks.
- (void)otherMouseUp:(NSEvent*)event {
[self performClick:self];
}
- (void)beginDrag:(NSEvent*)event {
NSSize dragOffset = NSMakeSize(0.0, 0.0);
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]
owner:self];
// This NSData is no longer referenced once the function ends so
// there is no need to retain/release when placing in here as an
// opaque pointer.
[pboard setData:[NSData dataWithBytes:&self length:sizeof(self)]
forType:kBookmarkButtonDragType];
// This won't work if the source view is clipped. Fortunately, we
// don't display clipped bookmark buttons.
[[self superview] lockFocus];
scoped_nsobject<NSBitmapImageRep>
bitmapImage([[NSBitmapImageRep alloc]
initWithFocusedViewRect:[self frame]]);
[[self superview] unlockFocus];
scoped_nsobject<NSImage> imageDrag([[NSImage alloc]
initWithSize:[bitmapImage size]]);
[imageDrag addRepresentation:bitmapImage];
// At the moment, moving bookmarks causes their buttons (like me!)
// to be destroyed and rebuilt. Make sure we don't go away while on
// the stack.
[self retain];
CGFloat yAt = [self bounds].size.height;
[self dragImage:imageDrag at:NSMakePoint(0, yAt) offset:dragOffset
event:event pasteboard:pboard source:self slideBack:YES];
// And we're done.
[self autorelease];
}
- (void)draggedImage:(NSImage*)anImage
endedAt:(NSPoint)aPoint
operation:(NSDragOperation)operation {
beingDragged_ = NO;
[[self cell] setHighlighted:NO];
}
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
return isLocal ? NSDragOperationMove : NSDragOperationNone;
}
- (void)mouseUp:(NSEvent*)theEvent {
// This conditional is never true (DnD loops in Cocoa eat the mouse
// up) but I added it in case future versions of Cocoa do unexpected
// things.
if (beingDragged_)
return [super mouseUp:theEvent];
// There are non-drag cases where a mouseUp: may happen
// (e.g. mouse-down, cmd-tab to another application, move mouse,
// mouse-up). So we check.
NSPoint viewLocal = [self convertPoint:[theEvent locationInWindow]
fromView:[[self window] contentView]];
if (NSPointInRect(viewLocal, [self bounds])) {
[self performClick:self];
} else {
[[self cell] setHighlighted:NO];
}
}
// Mimic "begin a click" operation visually. Do NOT follow through
// with normal button event handling.
- (void)mouseDown:(NSEvent*)theEvent {
[[self cell] setHighlighted:YES];
initialMouseDownLocation_ = [theEvent locationInWindow];
}
// Return YES if we have crossed a threshold of movement after
// mouse-down when we should begin a drag. Else NO.
- (BOOL)hasCrossedDragThreshold:(NSEvent*)theEvent {
NSPoint currentLocation = [theEvent locationInWindow];
if ((abs(currentLocation.x - initialMouseDownLocation_.x) >
kWebDragStartHysteresisX) ||
(abs(currentLocation.y - initialMouseDownLocation_.y) >
kWebDragStartHysteresisY)) {
return YES;
} else {
return NO;
}
}
- (void)mouseDragged:(NSEvent*)theEvent {
if (beingDragged_)
[super mouseDragged:theEvent];
else {
if (draggable_ && [self hasCrossedDragThreshold:theEvent]) {
[self beginDrag:theEvent];
}
}
}
@end
|