Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1820)

Unified Diff: ui/app_list/cocoa/app_list_view_controller.mm

Issue 1802473002: Add deprecation warning banner to App Launcher on Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@20170310-MacViews-ViewsUnittests
Patch Set: Separate function Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/app_list/cocoa/app_list_view_controller.h ('k') | ui/app_list/cocoa/apps_grid_controller.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/app_list/cocoa/app_list_view_controller.mm
diff --git a/ui/app_list/cocoa/app_list_view_controller.mm b/ui/app_list/cocoa/app_list_view_controller.mm
index 6862aec488c98e153e7c1ec7d93c1e28281073e8..568acc72a08b53408e9fa48fc1839271607baa86 100644
--- a/ui/app_list/cocoa/app_list_view_controller.mm
+++ b/ui/app_list/cocoa/app_list_view_controller.mm
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_model.h"
@@ -20,6 +21,7 @@
#import "ui/app_list/cocoa/apps_grid_controller.h"
#include "ui/app_list/search_box_model.h"
#import "ui/base/cocoa/flipped_view.h"
+#import "ui/gfx/image/image_skia_util_mac.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
namespace {
@@ -45,6 +47,15 @@ const CGFloat kMaxSegmentWidth = 80;
// Duration of the animation for sliding in and out search results.
const NSTimeInterval kResultsAnimationDuration = 0.2;
+// Properties of the message rectangle, if it is shown.
+const NSRect kMessageRect = {{12, 12}, {370, 91}};
+const CGFloat kMessageCornerRadius = 2;
+const CGFloat kSpacingBelowMessageTitle = 6;
+const SkColor kMessageBackgroundColor = SkColorSetRGB(0xFF, 0xFD, 0xE7);
+const SkColor kMessageStrokeColor = SkColorSetARGB(0x3d, 0x00, 0x00, 0x00);
+// The inset should be 16px, but NSTextView has its own inset of 3.
+const CGFloat kMessageTextInset = 13;
+
} // namespace
@interface BackgroundView : FlippedView;
@@ -74,8 +85,33 @@ const NSTimeInterval kResultsAnimationDuration = 0.2;
@end
+@interface MessageBackgroundView : FlippedView
+@end
+
+@implementation MessageBackgroundView
+
+- (void)drawRect:(NSRect)dirtyRect {
+ NSRect boundsRect = [self bounds];
+ gfx::ScopedNSGraphicsContextSaveGState context;
+ [[NSBezierPath bezierPathWithRoundedRect:boundsRect
+ xRadius:kMessageCornerRadius
+ yRadius:kMessageCornerRadius] addClip];
+
+ [skia::SkColorToSRGBNSColor(kMessageStrokeColor) set];
+ NSRectFill(boundsRect);
+
+ [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(boundsRect, 1, 1)
+ xRadius:kMessageCornerRadius
+ yRadius:kMessageCornerRadius] addClip];
+ [skia::SkColorToSRGBNSColor(kMessageBackgroundColor) set];
+ NSRectFill(boundsRect);
+}
+
+@end
+
@interface AppListViewController ()
+- (void)updateMessage;
- (void)loadAndSetView;
- (void)revealSearchResults:(BOOL)show;
@@ -176,6 +212,7 @@ void AppListModelObserverBridge::OnShutdown() {
[appsSearchResultsController_ setDelegate:nil];
[appsSearchBoxController_ setDelegate:nil];
[appsGridController_ setDelegate:nil];
+ [messageText_ setDelegate:nil];
}
delegate_ = newDelegate;
if (delegate_) {
@@ -191,17 +228,179 @@ void AppListModelObserverBridge::OnShutdown() {
app_list_model_observer_bridge_.reset(
new app_list::AppListModelObserverBridge(self));
[self onProfilesChanged];
+ [self updateMessage];
}
--(void)loadAndSetView {
+- (void)updateMessage {
+ if (![AppsGridController hasFewerRows])
+ return;
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSFont* messageFont = rb.GetFontWithDelta(0).GetNativeFont();
+ NSFont* titleFont = rb.GetFontWithDelta(2).GetNativeFont();
+
+ base::string16 title = delegate_->GetMessageTitle();
+ size_t messageBreak;
+ base::string16 messageFull = delegate_->GetMessageText(&messageBreak);
+ base::string16 shortcutName = delegate_->GetAppsShortcutName();
+ base::string16 learnMore = delegate_->GetLearnMoreText();
+ base::string16 learnMoreUrl = delegate_->GetLearnMoreLink();
+
+ base::string16 messagePre = messageFull.substr(0, messageBreak);
+ base::string16 messagePost = messageFull.substr(messageBreak);
+
+ NSURL* linkURL = [NSURL URLWithString:base::SysUTF16ToNSString(learnMoreUrl)];
+ gfx::ImageSkia* icon = delegate_->GetAppsIcon();
+
+ // Shift the baseline up so that the graphics align centered. 4 looks nice. It
+ // happens to be the image size minus the font size, but that's a coincidence.
+ const CGFloat kBaselineShift = 4;
+ base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+ [[NSMutableParagraphStyle alloc] init]);
+ [paragraphStyle setLineSpacing:kSpacingBelowMessageTitle + kBaselineShift];
+
+ NSNumber* baselineOffset = [NSNumber numberWithFloat:kBaselineShift];
+ base::scoped_nsobject<NSMutableAttributedString> text(
+ [[NSMutableAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(title)
+ attributes:@{
+ NSParagraphStyleAttributeName : paragraphStyle,
+ NSFontAttributeName : titleFont
+ }]);
+
+ NSDictionary* defaultAttributes = @{
+ NSFontAttributeName : messageFont,
+ NSBaselineOffsetAttributeName : baselineOffset
+ };
+
+ base::scoped_nsobject<NSAttributedString> lineBreak(
+ [[NSAttributedString alloc] initWithString:@"\n"
+ attributes:defaultAttributes]);
+ base::scoped_nsobject<NSAttributedString> space([[NSAttributedString alloc]
+ initWithString:@" "
+ attributes:defaultAttributes]);
+ base::scoped_nsobject<NSAttributedString> messagePreString(
+ [[NSAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(messagePre)
+ attributes:defaultAttributes]);
+ base::scoped_nsobject<NSAttributedString> messagePostString(
+ [[NSAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(messagePost)
+ attributes:defaultAttributes]);
+
+ // NSNoUnderlineStyle is broken.
+ base::scoped_nsobject<NSAttributedString> learnMoreString(
+ [[NSAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(learnMore)
+ attributes:@{
+ NSParagraphStyleAttributeName : paragraphStyle,
+ NSFontAttributeName : messageFont,
+ NSLinkAttributeName : linkURL,
+ NSBaselineOffsetAttributeName : baselineOffset,
+ NSUnderlineStyleAttributeName :
+ [NSNumber numberWithInt:NSNoUnderlineStyle]
+ }]);
+ base::scoped_nsobject<NSAttributedString> shortcutStringText(
+ [[NSAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(shortcutName)
+ attributes:defaultAttributes]);
+ base::scoped_nsobject<NSMutableAttributedString> shortcutString(
+ [[NSMutableAttributedString alloc] init]);
+ if (icon) {
+ NSImage* image = gfx::NSImageFromImageSkia(*icon);
+ // The image has a bunch of representations. Ensure the smallest is used.
+ // (Going smaller would make pixels all manky, so don't do that).
+ [image setSize:NSMakeSize(16, 16)];
+
+ base::scoped_nsobject<NSTextAttachmentCell> attachmentCell(
+ [[NSTextAttachmentCell alloc] initImageCell:image]);
+ base::scoped_nsobject<NSTextAttachment> attachment(
+ [[NSTextAttachment alloc] init]);
+ [attachment setAttachmentCell:attachmentCell];
+ [shortcutString
+ appendAttributedString:[NSAttributedString
+ attributedStringWithAttachment:attachment]];
+ [shortcutString appendAttributedString:space];
+ }
+ [shortcutString appendAttributedString:shortcutStringText];
+
+ [text appendAttributedString:lineBreak];
+ [text appendAttributedString:messagePreString];
+ [text appendAttributedString:shortcutString];
+ [text appendAttributedString:messagePostString];
+ [text appendAttributedString:space];
+ [text appendAttributedString:learnMoreString];
+
+ [[messageText_ textStorage] setAttributedString:text];
+ [messageText_ sizeToFit];
+
+ // If the user scroller preference is to always show scrollbars, and the
+ // translated message is long, the scroll track may be present. This means
+ // text will be under the scroller. We only want vertical scrolling, but
+ // reducing the width puts the scroll track in a weird spot. So, increase the
+ // width of the scroll view to move the track into the padding towards the
+ // message background border, then reduce the width of the text view. The
+ // non-overlay scroller still looks kinda weird but hopefully not many will
+ // actually see it.
+ CGFloat overlap =
+ NSWidth([messageText_ bounds]) - [messageScrollView_ contentSize].width;
+ if (overlap > 0) {
+ NSRect rect = [messageScrollView_ frame];
+ rect.size.width += kMessageTextInset - 2;
+ [messageScrollView_ setFrame:rect];
+ overlap -= kMessageTextInset - 2;
+ DCHECK_GT(overlap, 0);
+ rect = [messageText_ frame];
+ rect.size.width -= overlap;
+ [messageText_ setFrame:rect];
+ [messageText_ sizeToFit];
+
+ // And after doing all that for some reason Cocoa scrolls to the bottom. So
+ // fix that.
+ [[messageScrollView_ documentView] scrollPoint:NSMakePoint(0, 0)];
+ }
+
+ [messageText_ setDelegate:self];
+}
+
+- (void)loadAndSetView {
pagerControl_.reset([[AppListPagerView alloc] init]);
[pagerControl_ setTarget:appsGridController_];
[pagerControl_ setAction:@selector(onPagerClicked:)];
NSRect gridFrame = [[appsGridController_ view] frame];
- NSRect contentsRect = NSMakeRect(0, kSearchInputHeight + kTopSeparatorSize,
- NSWidth(gridFrame), NSHeight(gridFrame) + kPagerPreferredHeight -
- [AppsGridController scrollerPadding]);
+
+ base::scoped_nsobject<NSView> messageTextBackground;
+ if ([AppsGridController hasFewerRows]) {
+ messageTextBackground.reset(
+ [[MessageBackgroundView alloc] initWithFrame:kMessageRect]);
+ NSRect frameRect =
+ NSInsetRect(kMessageRect, kMessageTextInset, kMessageTextInset);
+ messageText_.reset([[NSTextView alloc] initWithFrame:frameRect]);
+ // Provide a solid background here (as well as the background) so that
+ // subpixel AA works.
+ [messageText_
+ setBackgroundColor:skia::SkColorToSRGBNSColor(kMessageBackgroundColor)];
+ [messageText_ setDrawsBackground:YES];
+ [messageText_ setEditable:NO];
+ // Ideally setSelectable:NO would also be set here, but that disables mouse
+ // events completely, breaking the "Learn more" link. Instead, selection is
+ // "disabled" via a delegate method which Apple's documentation suggests. In
+ // reality, selection still happens, it just disappears once the mouse is
+ // released. To avoid the selection appearing, also set selected text to
+ // have no special attributes. Sadly, the mouse cursor still displays an
+ // I-beam, but hacking cursor rectangles on the view so that the "Learn
+ // More" link is still correctly handled is too hard.
+ [messageText_ setSelectedTextAttributes:@{}];
+ gridFrame.origin.y += NSMaxY([messageTextBackground frame]);
+ }
+
+ [[appsGridController_ view] setFrame:gridFrame];
+
+ NSRect contentsRect =
+ NSMakeRect(0, kSearchInputHeight + kTopSeparatorSize, NSWidth(gridFrame),
+ NSMaxY(gridFrame) + kPagerPreferredHeight -
+ [AppsGridController scrollerPadding]);
contentsView_.reset([[FlippedView alloc] initWithFrame:contentsRect]);
@@ -236,6 +435,28 @@ void AppListModelObserverBridge::OnShutdown() {
[loadingIndicator_ setDisplayedWhenStopped:NO];
[loadingIndicator_ startAnimation:self];
+ if (messageText_) {
+ [contentsView_ addSubview:messageTextBackground];
+
+ // Add a scroll view in case the translation is long and doesn't fit. Mac
+ // likes to hide scrollbars, so add to the height so the user can see part
+ // of the next line of text: just extend out into the padding towards the
+ // text background's border. Subtract at least 2: one for the border stroke
+ // and one for a bit of padding.
+ NSRect frameRect = [messageText_ frame];
+ frameRect.size.height += kMessageTextInset - 2;
+ messageScrollView_.reset([[NSScrollView alloc] initWithFrame:frameRect]);
+ [messageScrollView_ setHasVerticalScroller:YES];
+ [messageScrollView_ setAutohidesScrollers:YES];
+
+ // Now the message is going into an NSScrollView, origin should be 0, 0.
+ frameRect = [messageText_ frame];
+ frameRect.origin = NSMakePoint(0, 0);
+ [messageText_ setFrame:frameRect];
+
+ [messageScrollView_ setDocumentView:messageText_];
+ [contentsView_ addSubview:messageScrollView_];
+ }
[contentsView_ addSubview:[appsGridController_ view]];
[contentsView_ addSubview:pagerControl_];
[contentsView_ addSubview:loadingIndicator_];
@@ -368,4 +589,20 @@ void AppListModelObserverBridge::OnShutdown() {
[appsSearchBoxController_ rebuildMenu];
}
+// NSTextViewDelegate implementation.
+
+- (BOOL)textView:(NSTextView*)textView
+ clickedOnLink:(id)link
+ atIndex:(NSUInteger)charIndex {
+ DCHECK(delegate_);
+ delegate_->OpenLearnMoreLink();
+ return YES;
+}
+
+- (NSArray*)textView:(NSTextView*)aTextView
+ willChangeSelectionFromCharacterRanges:(NSArray*)oldSelectedCharRanges
+ toCharacterRanges:(NSArray*)newSelectedCharRanges {
+ return oldSelectedCharRanges;
+}
+
@end
« no previous file with comments | « ui/app_list/cocoa/app_list_view_controller.h ('k') | ui/app_list/cocoa/apps_grid_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698