OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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/views/sidebar/sidebar_tab.h" |
| 6 |
| 7 #include <limits> |
| 8 |
| 9 #include "chrome/browser/defaults.h" |
| 10 #include "chrome/browser/themes/browser_theme_provider.h" |
| 11 #include "chrome/common/extensions/extension.h" |
| 12 #include "gfx/canvas_skia.h" |
| 13 #include "gfx/path.h" |
| 14 #include "gfx/skbitmap_operations.h" |
| 15 #include "grit/app_resources.h" |
| 16 #include "grit/generated_resources.h" |
| 17 #include "grit/theme_resources.h" |
| 18 #include "ui/base/animation/slide_animation.h" |
| 19 #include "ui/base/animation/throb_animation.h" |
| 20 #include "ui/base/resource/resource_bundle.h" |
| 21 #include "views/widget/tooltip_manager.h" |
| 22 |
| 23 namespace { |
| 24 |
| 25 // Hit mask constants. |
| 26 const SkScalar kTabCapCurveWidth = 3; |
| 27 |
| 28 // Icon transparency constants. |
| 29 const int kOpaque = 255; |
| 30 const int kCollapsedOpacityPercents = 80; |
| 31 const int kExpandedActiveOpacityPercents = 100; |
| 32 const int kExpandedInactiveOpacityPercents = 60; |
| 33 |
| 34 // SidebarTab's background image cache helper. |
| 35 struct CachedImage { |
| 36 CachedImage() |
| 37 : image(NULL), |
| 38 width(0), |
| 39 height(0) { |
| 40 } |
| 41 // Loads an image with |resource_id| from resources. |
| 42 void Load(int resource_id); |
| 43 |
| 44 SkBitmap* image; |
| 45 int width; |
| 46 int height; |
| 47 }; |
| 48 |
| 49 void CachedImage::Load(int resource_id) { |
| 50 image = ResourceBundle::GetSharedInstance().GetBitmapNamed(resource_id); |
| 51 width = image->width(); |
| 52 height = image->height(); |
| 53 } |
| 54 |
| 55 } // namespace |
| 56 |
| 57 // static |
| 58 const char SidebarTab::kViewClassName[] = "browser/ui/views/sidebar/SidebarTab"; |
| 59 |
| 60 // SidebarTab, background images cache: |
| 61 |
| 62 // Caches tab's background image for the particular tab state (active/inactive). |
| 63 struct SidebarTab::TabImage { |
| 64 CachedImage tab; |
| 65 }; |
| 66 |
| 67 // Caches all background images. |
| 68 struct SidebarTab::TabImages { |
| 69 TabImages(); |
| 70 // Loads all images from resources. |
| 71 void Load(); |
| 72 |
| 73 TabImage active; |
| 74 TabImage inactive; |
| 75 }; |
| 76 |
| 77 SidebarTab::TabImages::TabImages() { |
| 78 Load(); |
| 79 } |
| 80 |
| 81 void SidebarTab::TabImages::Load() { |
| 82 active.tab.Load(IDR_SIDEBAR_TAB_ACTIVE); |
| 83 inactive.tab.Load(IDR_SIDEBAR_TAB_INACTIVE); |
| 84 } |
| 85 |
| 86 // SidebarTab, public: |
| 87 |
| 88 SidebarTab::SidebarTab(SidebarTabController* controller) |
| 89 : SidebarBaseTab(controller) { |
| 90 } |
| 91 |
| 92 SidebarTab::~SidebarTab() { |
| 93 } |
| 94 |
| 95 void SidebarTab::GetShape(gfx::Path* shape) const { |
| 96 SkScalar h = SkIntToScalar(height()); |
| 97 SkScalar w = SkIntToScalar(width()); |
| 98 |
| 99 // When there's not enough space for properly formed caps, use the simpler |
| 100 // tab shape (it happens during first frames of the insert tab animation). |
| 101 if (h <= kTabCapCurveWidth * 2) { |
| 102 shape->moveTo(w, 0); |
| 103 shape->lineTo(w, h); |
| 104 shape->lineTo(0, h); |
| 105 shape->close(); |
| 106 return; |
| 107 } |
| 108 |
| 109 // Foot of the tab. |
| 110 shape->moveTo(w, 0); |
| 111 shape->lineTo(w, h); |
| 112 // Bottom cap. |
| 113 shape->lineTo(kTabCapCurveWidth + 1, h); |
| 114 shape->lineTo(0, h - kTabCapCurveWidth - 1); |
| 115 // Connect to the top cap. |
| 116 shape->lineTo(0, kTabCapCurveWidth); |
| 117 // Top cap. |
| 118 shape->lineTo(kTabCapCurveWidth, 0); |
| 119 |
| 120 shape->close(); |
| 121 } |
| 122 |
| 123 // static |
| 124 gfx::Size SidebarTab::GetMinimumUnselectedSize() { |
| 125 gfx::Size minimum_size; |
| 126 // Since we use bitmap images, the real minimum width of the image is |
| 127 // defined most accurately by the width of the end cap images. |
| 128 return gfx::Size(tab_images().active.tab.width, |
| 129 tab_images().active.tab.height); |
| 130 } |
| 131 |
| 132 // static |
| 133 gfx::Size SidebarTab::GetMinimumSelectedSize() { |
| 134 gfx::Size minimum_size = GetMinimumUnselectedSize(); |
| 135 minimum_size.set_height(minimum_size.height()); |
| 136 return minimum_size; |
| 137 } |
| 138 |
| 139 // static |
| 140 gfx::Size SidebarTab::GetStandardSize() { |
| 141 return GetMinimumSelectedSize(); |
| 142 } |
| 143 |
| 144 // SidebarTab, SidebarBaseTab overrides, protected: |
| 145 |
| 146 void SidebarTab::DataChanged(const SidebarTabRendererData& old) { |
| 147 Layout(); |
| 148 } |
| 149 |
| 150 // SidebarTab, views::View overrides: |
| 151 |
| 152 void SidebarTab::Paint(gfx::Canvas* canvas) { |
| 153 PaintTabBackground(canvas); |
| 154 |
| 155 PaintIcon(canvas); |
| 156 |
| 157 PaintBadge(canvas); |
| 158 } |
| 159 |
| 160 void SidebarTab::Layout() { |
| 161 gfx::Rect local_bounds = GetLocalBounds(); |
| 162 if (local_bounds.IsEmpty()) |
| 163 return; |
| 164 |
| 165 // Position the icon. |
| 166 gfx::Size icon_size(!data().icon.empty() ? |
| 167 gfx::Size(data().icon.width(), data().icon.height()) : |
| 168 gfx::Size(Extension::kSidebarIconMaxSize, |
| 169 Extension::kSidebarIconMaxSize)); |
| 170 |
| 171 gfx::Point icon_origin( |
| 172 local_bounds.x() + (local_bounds.width() - icon_size.width()) / 2, |
| 173 local_bounds.y() + (local_bounds.height() - icon_size.height()) / 2); |
| 174 |
| 175 icon_bounds_ = gfx::Rect(icon_origin, icon_size); |
| 176 } |
| 177 |
| 178 void SidebarTab::OnThemeChanged() { |
| 179 tab_images().Load(); |
| 180 } |
| 181 |
| 182 bool SidebarTab::HasHitTestMask() const { |
| 183 return true; |
| 184 } |
| 185 |
| 186 void SidebarTab::GetHitTestMask(gfx::Path* path) const { |
| 187 GetShape(path); |
| 188 } |
| 189 |
| 190 bool SidebarTab::GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin) { |
| 191 origin->set_x(width() + views::TooltipManager::GetTooltipHeight()); |
| 192 origin->set_y(-views::TooltipManager::GetTooltipHeight()); |
| 193 return true; |
| 194 } |
| 195 |
| 196 // SidebarTab, private |
| 197 |
| 198 // static |
| 199 SidebarTab::TabImages& SidebarTab::tab_images() { |
| 200 static TabImages images; |
| 201 return images; |
| 202 } |
| 203 |
| 204 void SidebarTab::PaintTabBackground(gfx::Canvas* canvas) { |
| 205 if (IsSelected()) { |
| 206 PaintTabBackgroundImage(canvas, true); |
| 207 } else { |
| 208 PaintTabBackgroundImage(canvas, false); |
| 209 |
| 210 double throb_value = GetThrobValue(); |
| 211 if (throb_value > 0) { |
| 212 canvas->SaveLayerAlpha(static_cast<int>(throb_value * 0xff), |
| 213 gfx::Rect(width(), height())); |
| 214 canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255, |
| 215 SkXfermode::kClear_Mode); |
| 216 PaintTabBackgroundImage(canvas, true); |
| 217 canvas->Restore(); |
| 218 } |
| 219 } |
| 220 } |
| 221 |
| 222 void SidebarTab::PaintTabBackgroundImage(gfx::Canvas* canvas, |
| 223 bool as_active) { |
| 224 TabImage* tab_image = |
| 225 as_active ? &tab_images().active : &tab_images().inactive; |
| 226 |
| 227 canvas->DrawBitmapInt(*tab_image->tab.image, 0, 0); |
| 228 } |
| 229 |
| 230 void SidebarTab::PaintIcon(gfx::Canvas* canvas) { |
| 231 int alpha_percents = 100; |
| 232 if (!IsExpanded()) { |
| 233 alpha_percents = kCollapsedOpacityPercents; |
| 234 } else { |
| 235 if (IsSelected()) |
| 236 alpha_percents = kExpandedActiveOpacityPercents; |
| 237 else |
| 238 alpha_percents = kExpandedInactiveOpacityPercents; |
| 239 } |
| 240 SidebarBaseTab::PaintIcon(canvas, icon_bounds_.x(), icon_bounds_.y(), |
| 241 kOpaque * alpha_percents / 100); |
| 242 } |
| 243 |
| 244 void SidebarTab::PaintBadge(gfx::Canvas* canvas) { |
| 245 // TODO(alekseys): paint badge text. |
| 246 } |
| 247 |
OLD | NEW |