Chromium Code Reviews| Index: chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm |
| diff --git a/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm b/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm |
| index ba6990f50c09c09857a3e7404e918c992c21d06d..3b29638665693dedf8f1b91a076511d27b8bcb69 100644 |
| --- a/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm |
| +++ b/chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm |
| @@ -12,10 +12,15 @@ |
| #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" |
| #include "chrome/browser/ui/cocoa/spinner_view.h" |
| #include "chrome/grit/generated_resources.h" |
| +#include "skia/ext/skia_utils_mac.h" |
| #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
| #import "ui/base/cocoa/controls/hyperlink_button_cell.h" |
| #include "ui/base/l10n/l10n_util_mac.h" |
| #include "ui/base/resource/resource_bundle.h" |
| +#include "ui/gfx/color_palette.h" |
| +#include "ui/gfx/image/image_skia_util_mac.h" |
| +#include "ui/gfx/paint_vector_icon.h" |
| +#include "ui/gfx/vector_icons_public.h" |
| #include "ui/resources/grit/ui_resources.h" |
| namespace { |
| @@ -26,11 +31,12 @@ const CGFloat kChooserWidth = 350.0f; |
| // Chooser height. |
| const CGFloat kChooserHeight = 300.0f; |
| -// Signal strength level image size. |
| -const CGFloat kSignalStrengthLevelImageSize = 20.0f; |
| +// Row view image size. |
| +const CGFloat kRowViewImageSize = 20.0f; |
| // Table row view height. |
| -const CGFloat kTableRowViewHeight = 23.0f; |
| +const CGFloat kTableRowViewOneLineHeight = 23.0f; |
| +const CGFloat kTableRowViewTwoLinesHeight = 39.0f; |
| // Spinner size. |
| const CGFloat kSpinnerSize = 24.0f; |
| @@ -50,11 +56,29 @@ const CGFloat kSeparatorAlphaValue = 0.6f; |
| // Separator height. |
| const CGFloat kSeparatorHeight = 1.0f; |
| +// Distance between two views inside the table row view. |
| +const CGFloat kTableRowViewHorizontalPadding = 5.0f; |
| +const CGFloat kTableRowViewVerticalPadding = 1.0f; |
| + |
| // The lookup table for signal strength level image. |
| const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR, |
| IDR_SIGNAL_2_BAR, IDR_SIGNAL_3_BAR, |
| IDR_SIGNAL_4_BAR}; |
| +// Creates a label with |text|. |
| +base::scoped_nsobject<NSTextField> CreateLabel(NSString* text) { |
| + base::scoped_nsobject<NSTextField> label( |
| + [[NSTextField alloc] initWithFrame:NSZeroRect]); |
| + [label setDrawsBackground:NO]; |
| + [label setBezeled:NO]; |
| + [label setEditable:NO]; |
| + [label setSelectable:NO]; |
| + [label setStringValue:text]; |
| + [label setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; |
| + [label sizeToFit]; |
| + return label; |
| +} |
| + |
| } // namespace |
| // A table row view that contains one line of text, and optionally contains an |
| @@ -63,11 +87,18 @@ const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR, |
| @private |
| base::scoped_nsobject<NSImageView> image_; |
| base::scoped_nsobject<NSTextField> text_; |
| + base::scoped_nsobject<NSTextField> pairedStatus_; |
| } |
| -// Designated initializer. |
| +// This initializer is used when the chooser needs to show no devices found |
| +// message. |
| +- (instancetype)initWithText:(NSString*)text; |
| + |
| - (instancetype)initWithText:(NSString*)text |
| - signalStrengthLevel:(NSInteger)level; |
| + signalStrengthLevel:(NSInteger)level |
| + isConnected:(bool)isConnected |
| + isPaired:(bool)isPaired |
| + rowHeight:(CGFloat)rowHeight; |
| // Gets the image in front of the text. |
| - (NSImageView*)image; |
| @@ -75,46 +106,100 @@ const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR, |
| // Gets the text. |
| - (NSTextField*)text; |
| +// Gets the paired status. |
| +- (NSTextField*)pairedStatus; |
| + |
| @end |
| @implementation ChooserContentTableRowView |
| +- (instancetype)initWithText:(NSString*)text { |
| + if ((self = [super initWithFrame:NSZeroRect])) { |
| + text_ = CreateLabel(text); |
| + CGFloat textHeight = NSHeight([text_ frame]); |
| + CGFloat textOriginX = kTableRowViewHorizontalPadding; |
| + CGFloat textOriginY = (kTableRowViewOneLineHeight - textHeight) / 2; |
| + [text_ setFrameOrigin:NSMakePoint(textOriginX, textOriginY)]; |
| + [self addSubview:text_]; |
| + } |
| + |
| + return self; |
| +} |
| + |
| - (instancetype)initWithText:(NSString*)text |
| - signalStrengthLevel:(NSInteger)level { |
| + signalStrengthLevel:(NSInteger)level |
| + isConnected:(bool)isConnected |
| + isPaired:(bool)isPaired |
| + rowHeight:(CGFloat)rowHeight { |
| if ((self = [super initWithFrame:NSZeroRect])) { |
| - if (level != -1) { |
| + // Create the views. |
| + // Image. |
| + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| + NSImage* image = nullptr; |
| + if (isConnected) { |
| + image = gfx::NSImageFromImageSkia(gfx::CreateVectorIcon( |
| + gfx::VectorIconId::BLUETOOTH_CONNECTED, gfx::kChromeIconGrey)); |
| + } else if (level != -1) { |
| DCHECK_GE(level, 0); |
| DCHECK_LT(level, base::checked_cast<NSInteger>( |
| arraysize(kSignalStrengthLevelImageIds))); |
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| - NSImage* signalStrengthLevelImage = |
| - rb.GetNativeImageNamed(kSignalStrengthLevelImageIds[level]) |
| - .ToNSImage(); |
| + image = rb.GetNativeImageNamed(kSignalStrengthLevelImageIds[level]) |
| + .ToNSImage(); |
| + } |
| + CGFloat imageOriginX = kTableRowViewHorizontalPadding; |
| + CGFloat imageOriginY = (rowHeight - kRowViewImageSize) / 2; |
| + if (image) { |
| image_.reset([[NSImageView alloc] |
| - initWithFrame:NSMakeRect(0, (kTableRowViewHeight - |
| - kSignalStrengthLevelImageSize) / |
| - 2, |
| - kSignalStrengthLevelImageSize, |
| - kSignalStrengthLevelImageSize)]); |
| - [image_ setImage:signalStrengthLevelImage]; |
| + initWithFrame:NSMakeRect(imageOriginX, imageOriginY, |
| + kRowViewImageSize, kRowViewImageSize)]); |
| + [image_ setImage:image]; |
| [self addSubview:image_]; |
| } |
| - text_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); |
| - [text_ setDrawsBackground:NO]; |
| - [text_ setBezeled:NO]; |
| - [text_ setEditable:NO]; |
| - [text_ setSelectable:NO]; |
| - [text_ setStringValue:text]; |
| - [text_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; |
| - [text_ sizeToFit]; |
| + // Text. |
| + text_ = CreateLabel(text); |
| CGFloat textHeight = NSHeight([text_ frame]); |
| - [text_ setFrameOrigin:NSMakePoint( |
| - level == -1 ? 0 : kSignalStrengthLevelImageSize + |
| - kHorizontalPadding, |
| - (kTableRowViewHeight - textHeight) / 2)]; |
| + |
| + // Paired status. |
| + CGFloat pairedStatusHeight = 0.0f; |
| + if (isPaired) { |
| + pairedStatus_ = CreateLabel( |
| + l10n_util::GetNSString(IDS_DEVICE_CHOOSER_PAIRED_STATUS_TEXT)); |
| + [pairedStatus_ |
| + setTextColor:skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700)]; |
| + pairedStatusHeight = NSHeight([pairedStatus_ frame]); |
| + } |
| + |
| + // Lay out the views. |
| + // Text. |
| + CGFloat textOriginX = |
| + imageOriginX + kRowViewImageSize + kTableRowViewHorizontalPadding; |
| + CGFloat textOriginY; |
| + if (isPaired) { |
| + textOriginY = pairedStatusHeight + |
| + (rowHeight - textHeight - pairedStatusHeight - |
| + kTableRowViewVerticalPadding) / |
| + 2 + |
| + kTableRowViewVerticalPadding; |
| + } else { |
| + textOriginY = (rowHeight - textHeight) / 2; |
| + } |
| + |
| + [text_ setFrameOrigin:NSMakePoint(textOriginX, textOriginY)]; |
| [self addSubview:text_]; |
| + |
| + // Paired status. |
| + if (isPaired) { |
| + CGFloat pairedStatusOriginX = textOriginX; |
| + CGFloat pairedStatusOriginY = |
| + (rowHeight - textHeight - pairedStatusHeight - |
| + kTableRowViewVerticalPadding) / |
| + 2; |
| + [pairedStatus_ |
| + setFrameOrigin:NSMakePoint(pairedStatusOriginX, pairedStatusOriginY)]; |
| + [self addSubview:pairedStatus_]; |
| + } |
| } |
| return self; |
| @@ -128,6 +213,10 @@ const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR, |
| return text_.get(); |
| } |
| +- (NSTextField*)pairedStatus { |
| + return pairedStatus_.get(); |
| +} |
| + |
| @end |
| class ChooserContentViewController : public ChooserController::View { |
| @@ -310,8 +399,8 @@ void ChooserContentViewController::UpdateTableView() { |
| titleHeight_ = NSHeight([titleView_ frame]); |
| // Status. |
| - status_ = [self createTextField:l10n_util::GetNSString( |
| - IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING)]; |
| + status_ = CreateLabel( |
| + l10n_util::GetNSString(IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING)); |
| CGFloat statusWidth = kChooserWidth / 2 - kMarginX; |
| // The height is arbitrary as it will be adjusted later. |
| [status_ setFrameSize:NSMakeSize(statusWidth, 0.0f)]; |
| @@ -341,9 +430,8 @@ void ChooserContentViewController::UpdateTableView() { |
| separator_ = [self createSeparator]; |
| // Message. |
| - message_ = [self createTextField:l10n_util::GetNSStringF( |
| - IDS_DEVICE_CHOOSER_FOOTNOTE_TEXT, |
| - base::string16())]; |
| + message_ = CreateLabel(l10n_util::GetNSStringF( |
| + IDS_DEVICE_CHOOSER_FOOTNOTE_TEXT, base::string16())); |
| CGFloat messageWidth = NSWidth([message_ frame]); |
| messageHeight_ = NSHeight([message_ frame]); |
| @@ -489,25 +577,51 @@ void ChooserContentViewController::UpdateTableView() { |
| return titleView; |
| } |
| -- (base::scoped_nsobject<NSView>)createTableRowView:(NSInteger)rowIndex { |
| +- (base::scoped_nsobject<NSView>)createTableRowView:(NSInteger)row { |
| NSInteger level = -1; |
| + bool isConnected = false; |
| + bool isPaired = false; |
| size_t numOptions = chooserController_->NumOptions(); |
| - if (chooserController_->ShouldShowIconBeforeText() && numOptions > 0) { |
| - DCHECK_GE(rowIndex, 0); |
| - DCHECK_LT(rowIndex, base::checked_cast<NSInteger>(numOptions)); |
| - level = base::checked_cast<NSInteger>( |
| - chooserController_->GetSignalStrengthLevel( |
| - base::checked_cast<size_t>(rowIndex))); |
| + base::scoped_nsobject<NSView> tableRowView; |
| + if (numOptions == 0) { |
| + DCHECK_EQ(0, row); |
| + tableRowView.reset([[ChooserContentTableRowView alloc] |
| + initWithText:[self optionAtIndex:row]]); |
| + } else { |
| + DCHECK_GE(row, 0); |
| + DCHECK_LT(row, base::checked_cast<NSInteger>(numOptions)); |
| + size_t rowIndex = base::checked_cast<size_t>(row); |
| + if (chooserController_->ShouldShowIconBeforeText()) { |
| + level = base::checked_cast<NSInteger>( |
| + chooserController_->GetSignalStrengthLevel(rowIndex)); |
| + } |
| + isConnected = chooserController_->IsConnected(rowIndex); |
| + isPaired = chooserController_->IsPaired(rowIndex); |
| + tableRowView.reset([[ChooserContentTableRowView alloc] |
| + initWithText:[self optionAtIndex:row] |
| + signalStrengthLevel:level |
| + isConnected:isConnected |
| + isPaired:isPaired |
| + rowHeight:[self tableRowViewHeight:row]]); |
| } |
| - base::scoped_nsobject<NSView> tableRowView([[ChooserContentTableRowView alloc] |
| - initWithText:[self optionAtIndex:rowIndex] |
| - signalStrengthLevel:level]); |
| return tableRowView; |
| } |
| - (CGFloat)tableRowViewHeight:(NSInteger)row { |
| - return kTableRowViewHeight; |
| + size_t numOptions = chooserController_->NumOptions(); |
| + if (numOptions == 0) { |
| + DCHECK_EQ(0, row); |
| + return kTableRowViewOneLineHeight; |
| + } |
| + |
| + DCHECK_GE(row, 0); |
| + DCHECK_LT(row, base::checked_cast<NSInteger>(numOptions)); |
| + size_t rowIndex = base::checked_cast<size_t>(row); |
| + if (chooserController_->IsPaired(rowIndex)) |
| + return kTableRowViewTwoLinesHeight; |
| + else |
| + return kTableRowViewOneLineHeight; |
|
Evan Stade
2016/09/09 20:44:47
nit: no else after return (I'd replace this with a
juncai
2016/09/12 20:37:12
Done.
|
| } |
| - (base::scoped_nsobject<NSButton>)createButtonWithTitle:(NSString*)title { |
| @@ -540,19 +654,6 @@ void ChooserContentViewController::UpdateTableView() { |
| return spacer; |
| } |
| -- (base::scoped_nsobject<NSTextField>)createTextField:(NSString*)text { |
| - base::scoped_nsobject<NSTextField> textField( |
| - [[NSTextField alloc] initWithFrame:NSZeroRect]); |
| - [textField setDrawsBackground:NO]; |
| - [textField setBezeled:NO]; |
| - [textField setEditable:NO]; |
| - [textField setSelectable:NO]; |
| - [textField setStringValue:text]; |
| - [textField setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; |
| - [textField sizeToFit]; |
| - return textField; |
| -} |
| - |
| - (base::scoped_nsobject<NSButton>)createHyperlinkButtonWithText: |
| (NSString*)text { |
| base::scoped_nsobject<NSButton> button( |
| @@ -704,4 +805,10 @@ void ChooserContentViewController::UpdateTableView() { |
| return [tableRowView text]; |
| } |
| +- (NSTextField*)tableRowViewPairedStatus:(NSInteger)row { |
| + ChooserContentTableRowView* tableRowView = |
| + [tableView_ viewAtColumn:0 row:row makeIfNecessary:YES]; |
| + return [tableRowView pairedStatus]; |
| +} |
| + |
| @end |