1 // Copyright (c) 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 "ash/launcher/overflow_button.h" 6 7 #include "ash/ash_switches.h" 8 #include "ash/shelf/shelf_layout_manager.h" 9 #include "ash/shelf/shelf_widget.h" 10 #include "grit/ash_resources.h" 11 #include "grit/ash_strings.h" 12 #include "third_party/skia/include/core/SkPaint.h" 13 #include "third_party/skia/include/core/SkPath.h" 14 #include "ui/base/animation/throb_animation.h" 15 #include "ui/base/l10n/l10n_util.h" 16 #include "ui/base/resource/resource_bundle.h" 17 #include "ui/gfx/canvas.h" 18 #include "ui/gfx/image/image_skia_operations.h" 19 #include "ui/gfx/skbitmap_operations.h" 20 #include "ui/gfx/skia_util.h" 21 #include "ui/gfx/transform.h" 22 #include "ui/views/widget/widget.h" 23 24 namespace ash { 25 namespace internal { 26 27 namespace { 28 29 const int kButtonHoverAlpha = 150; 30 31 const int kButtonCornerRadius = 2; 32 33 const int kButtonHoverSize = 28; 34 35 const int kBackgroundOffset = (48 - kButtonHoverSize) / 2; 36 37 // Padding from the inner edge of the shelf (towards center of display) to 38 // the edge of the background image of the overflow button. 39 const int kImagePaddingFromShelf = 5; 40 41 } // namesapce 42 43 OverflowButton::OverflowButton(views::ButtonListener* listener) 44 : CustomButton(listener), 45 bottom_image_(NULL) { 46 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 47 bottom_image_ = rb.GetImageNamed(IDR_AURA_LAUNCHER_OVERFLOW).ToImageSkia(); 48 49 50 set_accessibility_focusable(true); 51 SetAccessibleName(l10n_util::GetStringUTF16(IDS_ASH_SHELF_OVERFLOW_NAME)); 52 } 53 54 OverflowButton::~OverflowButton() {} 55 56 void OverflowButton::OnShelfAlignmentChanged() { 57 SchedulePaint(); 58 } 59 60 void OverflowButton::PaintBackground(gfx::Canvas* canvas, int alpha) { 61 gfx::Rect bounds(GetContentsBounds()); 62 gfx::Rect rect(0, 0, kButtonHoverSize, kButtonHoverSize); 63 ShelfLayoutManager* shelf = 64 ShelfLayoutManager::ForLauncher(GetWidget()->GetNativeView()); 65 66 // Nudge the background a little to line up right. 67 if (shelf->IsHorizontalAlignment()) { 68 rect.set_origin(gfx::Point( 69 bounds.x() + ((bounds.width() - kButtonHoverSize) / 2) - 1, 70 bounds.y() + kBackgroundOffset - 1)); 71 72 } else { 73 rect.set_origin(gfx::Point( 74 bounds.x() + kBackgroundOffset - 1, 75 bounds.y() + ((bounds.height() - kButtonHoverSize) / 2) - 1)); 76 } 77 78 SkPaint paint; 79 paint.setAntiAlias(true); 80 paint.setStyle(SkPaint::kFill_Style); 81 paint.setColor(SkColorSetARGB( 82 kButtonHoverAlpha * hover_animation_->GetCurrentValue(), 83 0, 0, 0)); 84 85 const SkScalar radius = SkIntToScalar(kButtonCornerRadius); 86 SkPath path; 87 path.addRoundRect(gfx::RectToSkRect(rect), radius, radius); 88 canvas->DrawPath(path, paint); 89 } 90 91 void OverflowButton::OnPaint(gfx::Canvas* canvas) { 92 ShelfLayoutManager* layout_manager = ShelfLayoutManager::ForLauncher( 93 GetWidget()->GetNativeView()); 94 ShelfAlignment alignment = layout_manager->GetAlignment(); 95 96 gfx::Rect bounds(GetContentsBounds()); 97 if (ash::switches::UseAlternateShelfLayout()) { 98 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 99 int background_image_id = 0; 100 if (layout_manager->shelf_widget()->launcher()->IsShowingOverflowBubble()) 101 background_image_id = IDR_AURA_NOTIFICATION_BACKGROUND_PRESSED; 102 else if(layout_manager->shelf_widget()->GetDimsShelf()) 103 background_image_id = IDR_AURA_NOTIFICATION_BACKGROUND_ON_BLACK; 104 else 105 background_image_id = IDR_AURA_NOTIFICATION_BACKGROUND_NORMAL; 106 107 const gfx::ImageSkia* background = 108 rb.GetImageNamed(background_image_id).ToImageSkia(); 109 if (alignment == SHELF_ALIGNMENT_LEFT) { 110 bounds = gfx::Rect( 111 bounds.right() - background->width() - kImagePaddingFromShelf, 112 bounds.y() + (bounds.height() - background->height()) / 2, 113 background->width(), background->height()); 114 } else if (alignment == SHELF_ALIGNMENT_RIGHT) { 115 bounds = gfx::Rect( 116 bounds.x() + kImagePaddingFromShelf, 117 bounds.y() + (bounds.height() - background->height()) / 2, 118 background->width(), background->height()); 119 } else { 120 bounds = gfx::Rect( 121 bounds.x() + (bounds.width() - background->width()) / 2, 122 bounds.y() + kImagePaddingFromShelf, 123 background->width(), background->height()); 124 } 125 canvas->DrawImageInt(*background, bounds.x(), bounds.y()); 126 } else { 127 if (alignment == SHELF_ALIGNMENT_BOTTOM) { 128 bounds = gfx::Rect( 129 bounds.x() + ((bounds.width() - kButtonHoverSize) / 2) - 1, 130 bounds.y() + kBackgroundOffset - 1, 131 kButtonHoverSize, kButtonHoverSize); 132 } else { 133 bounds = gfx::Rect( 134 bounds.x() + kBackgroundOffset -1, 135 bounds.y() + ((bounds.height() - kButtonHoverSize) / 2) -1, 136 kButtonHoverSize, kButtonHoverSize); 137 } 138 if (hover_animation_->is_animating()) { 139 PaintBackground( 140 canvas, 141 kButtonHoverAlpha * hover_animation_->GetCurrentValue()); 142 } else if (state() == STATE_HOVERED || state() == STATE_PRESSED) { 143 PaintBackground(canvas, kButtonHoverAlpha); 144 } 145 } 146 147 if (height() < kButtonHoverSize) 148 return; 149 150 const gfx::ImageSkia* image = NULL; 151 152 switch(alignment) { 153 case SHELF_ALIGNMENT_LEFT: 154 if (left_image_.isNull()) { 155 left_image_ = gfx::ImageSkiaOperations::CreateRotatedImage( 156 *bottom_image_, SkBitmapOperations::ROTATION_90_CW); 157 } 158 image = &left_image_; 159 break; 160 case SHELF_ALIGNMENT_RIGHT: 161 if (right_image_.isNull()) { 162 right_image_ = gfx::ImageSkiaOperations::CreateRotatedImage( 163 *bottom_image_, SkBitmapOperations::ROTATION_270_CW); 164 } 165 image = &right_image_; 166 break; 167 default: 168 image = bottom_image_; 169 break; 170 } 171 172 canvas->DrawImageInt(*image, 173 bounds.x() + ((bounds.width() - image->width()) / 2), 174 bounds.y() + ((bounds.height() - image->height()) / 2)); 175 } 176 177 } // namespace internal 178 } // namespace ash 179