Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_drag_drop.h" | |
| 6 | |
| 7 #import <Cocoa/Cocoa.h> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/scoped_nsobject.h" | |
| 11 #include "base/message_loop.h" | |
| 12 #include "base/string16.h" | |
| 13 #include "base/sys_string_conversions.h" | |
| 14 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
| 15 #include "chrome/browser/bookmarks/bookmark_model.h" | |
| 16 #include "chrome/browser/bookmarks/bookmark_node_data.h" | |
| 17 #include "chrome/browser/bookmarks/bookmark_utils.h" | |
| 18 #include "chrome/browser/profiles/profile.h" | |
| 19 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h" | |
| 20 #include "ui/base/resource/resource_bundle.h" | |
| 21 #include "ui/gfx/mac/nsimage_cache.h" | |
| 22 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" | |
| 23 | |
| 24 namespace chrome { | |
|
sail
2012/12/04 16:34:13
can this be moved below the "} // namespace" line
tfarina
2012/12/04 16:39:48
I did this way so I don't have to chrome::DragImag
sail
2012/12/04 16:41:50
Ahh, makes sense. Never mind then.
| |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 // Make a drag image from the drop data. | |
| 29 NSImage* MakeDragImage(BookmarkModel* model, | |
| 30 const std::vector<const BookmarkNode*>& nodes) { | |
| 31 if (nodes.size() == 1) { | |
| 32 const BookmarkNode* node = nodes[0]; | |
| 33 const gfx::Image& favicon = model->GetFavicon(node); | |
| 34 return DragImageForBookmark( | |
| 35 favicon.IsEmpty() ? nil : favicon.ToNSImage(), node->GetTitle()); | |
| 36 } else { | |
| 37 // TODO(feldstein): Do something better than this. Should have badging | |
| 38 // and a single drag image. | |
| 39 // http://crbug.com/37264 | |
| 40 return [NSImage imageNamed:NSImageNameMultipleDocuments]; | |
| 41 } | |
| 42 } | |
| 43 | |
| 44 // Draws string |title| within box |frame|, positioning it at the origin. | |
| 45 // Truncates text with fading if it is too long to fit horizontally. | |
| 46 // Based on code from GradientButtonCell but simplified where possible. | |
| 47 void DrawTruncatedTitle(NSAttributedString* title, NSRect frame) { | |
| 48 NSSize size = [title size]; | |
| 49 if (std::floor(size.width) <= NSWidth(frame)) { | |
| 50 [title drawAtPoint:frame.origin]; | |
| 51 return; | |
| 52 } | |
| 53 | |
| 54 // Gradient is about twice our line height long. | |
| 55 CGFloat gradient_width = std::min(size.height * 2, NSWidth(frame) / 4); | |
| 56 NSRect solid_part, gradient_part; | |
| 57 NSDivideRect(frame, &gradient_part, &solid_part, gradient_width, NSMaxXEdge); | |
| 58 CGContextRef context = static_cast<CGContextRef>( | |
| 59 [[NSGraphicsContext currentContext] graphicsPort]); | |
| 60 CGContextBeginTransparencyLayerWithRect(context, NSRectToCGRect(frame), 0); | |
| 61 { // Draw text clipped to frame. | |
| 62 gfx::ScopedNSGraphicsContextSaveGState scoped_state; | |
| 63 [NSBezierPath clipRect:frame]; | |
| 64 [title drawAtPoint:frame.origin]; | |
| 65 } | |
| 66 | |
| 67 NSColor* color = [NSColor blackColor]; | |
| 68 NSColor* alpha_color = [color colorWithAlphaComponent:0.0]; | |
| 69 scoped_nsobject<NSGradient> mask( | |
| 70 [[NSGradient alloc] initWithStartingColor:color | |
| 71 endingColor:alpha_color]); | |
| 72 // Draw the gradient mask. | |
| 73 CGContextSetBlendMode(context, kCGBlendModeDestinationIn); | |
| 74 [mask drawFromPoint:NSMakePoint(NSMaxX(frame) - gradient_width, | |
| 75 NSMinY(frame)) | |
| 76 toPoint:NSMakePoint(NSMaxX(frame), | |
| 77 NSMinY(frame)) | |
| 78 options:NSGradientDrawsBeforeStartingLocation]; | |
| 79 CGContextEndTransparencyLayer(context); | |
| 80 } | |
| 81 | |
| 82 } // namespace | |
| 83 | |
| 84 NSImage* DragImageForBookmark(NSImage* favicon, const string16& title) { | |
| 85 // If no favicon, use a default. | |
| 86 if (!favicon) { | |
| 87 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 88 favicon = rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToNSImage(); | |
| 89 } | |
| 90 | |
| 91 // If no title, just use icon. | |
| 92 if (title.empty()) | |
| 93 return favicon; | |
| 94 NSString* ns_title = base::SysUTF16ToNSString(title); | |
| 95 | |
| 96 // Set the look of the title. | |
| 97 NSDictionary* attrs = | |
| 98 [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize: | |
| 99 [NSFont smallSystemFontSize]] | |
| 100 forKey:NSFontAttributeName]; | |
| 101 scoped_nsobject<NSAttributedString> rich_title( | |
| 102 [[NSAttributedString alloc] initWithString:ns_title | |
| 103 attributes:attrs]); | |
| 104 | |
| 105 // Set up sizes and locations for rendering. | |
| 106 const CGFloat kIconMargin = 2.0; // Gap between icon and text. | |
| 107 CGFloat text_left = [favicon size].width + kIconMargin; | |
| 108 NSSize drag_image_size = [favicon size]; | |
| 109 NSSize text_size = [rich_title size]; | |
| 110 CGFloat max_text_width = bookmarks::kDefaultBookmarkWidth - text_left; | |
| 111 text_size.width = std::min(text_size.width, max_text_width); | |
| 112 drag_image_size.width = text_left + text_size.width; | |
| 113 | |
| 114 // Render the drag image. | |
| 115 NSImage* drag_image = | |
| 116 [[[NSImage alloc] initWithSize:drag_image_size] autorelease]; | |
| 117 [drag_image lockFocus]; | |
| 118 [favicon drawAtPoint:NSMakePoint(0, 0) | |
| 119 fromRect:NSZeroRect | |
| 120 operation:NSCompositeSourceOver | |
| 121 fraction:0.7]; | |
| 122 NSRect target_text_rect = NSMakeRect(text_left, 0, | |
| 123 text_size.width, drag_image_size.height); | |
| 124 DrawTruncatedTitle(rich_title, target_text_rect); | |
| 125 [drag_image unlockFocus]; | |
| 126 | |
| 127 return drag_image; | |
| 128 } | |
| 129 | |
| 130 } // namespace chrome | |
| 131 | |
| 132 namespace bookmark_utils { | |
| 133 | |
| 134 void DragBookmarks(Profile* profile, | |
| 135 const std::vector<const BookmarkNode*>& nodes, | |
| 136 gfx::NativeView view) { | |
| 137 DCHECK(!nodes.empty()); | |
| 138 | |
| 139 // Allow nested message loop so we get DnD events as we drag this around. | |
| 140 bool was_nested = MessageLoop::current()->IsNested(); | |
| 141 MessageLoop::current()->SetNestableTasksAllowed(true); | |
| 142 | |
| 143 std::vector<BookmarkNodeData::Element> elements; | |
|
tfarina
2012/12/04 16:15:53
I fold the StartDrag(...) function directly here.
| |
| 144 for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin(); | |
| 145 it != nodes.end(); ++it) { | |
| 146 elements.push_back(BookmarkNodeData::Element(*it)); | |
| 147 } | |
| 148 | |
| 149 WriteToPasteboard(kDragPasteboard, elements, profile->GetPath().value()); | |
| 150 | |
| 151 // Synthesize an event for dragging, since we can't be sure that | |
| 152 // [NSApp currentEvent] will return a valid dragging event. | |
| 153 NSWindow* window = [view window]; | |
| 154 NSPoint position = [window mouseLocationOutsideOfEventStream]; | |
| 155 NSTimeInterval event_time = [[NSApp currentEvent] timestamp]; | |
| 156 NSEvent* drag_event = [NSEvent mouseEventWithType:NSLeftMouseDragged | |
| 157 location:position | |
| 158 modifierFlags:NSLeftMouseDraggedMask | |
| 159 timestamp:event_time | |
| 160 windowNumber:[window windowNumber] | |
| 161 context:nil | |
| 162 eventNumber:0 | |
| 163 clickCount:1 | |
| 164 pressure:1.0]; | |
| 165 | |
| 166 // TODO(avi): Do better than this offset. | |
| 167 NSImage* drag_image = | |
| 168 MakeDragImage(BookmarkModelFactory::GetForProfile(profile), nodes); | |
| 169 NSSize image_size = [drag_image size]; | |
| 170 position.x -= std::floor(image_size.width / 2); | |
| 171 position.y -= std::floor(image_size.height / 5); | |
| 172 [window dragImage:drag_image | |
| 173 at:position | |
| 174 offset:NSZeroSize | |
| 175 event:drag_event | |
| 176 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] | |
| 177 source:nil | |
| 178 slideBack:YES]; | |
| 179 | |
| 180 MessageLoop::current()->SetNestableTasksAllowed(was_nested); | |
| 181 } | |
| 182 | |
| 183 } // namespace bookmark_utils | |
| OLD | NEW |