Index: ui/views/bubble/bubble_border_2.cc |
diff --git a/ui/app_list/app_list_bubble_border.cc b/ui/views/bubble/bubble_border_2.cc |
similarity index 63% |
copy from ui/app_list/app_list_bubble_border.cc |
copy to ui/views/bubble/bubble_border_2.cc |
index 3af0263fd7930e4ff4e51acaf80323dc153b5886..b8fe8179eaed01fff9ce043825a8fadd9c3cbcd9 100644 |
--- a/ui/app_list/app_list_bubble_border.cc |
+++ b/ui/views/bubble/bubble_border_2.cc |
@@ -2,13 +2,15 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "ui/app_list/app_list_bubble_border.h" |
+#include "ui/views/bubble/bubble_border_2.h" |
-#include "third_party/skia/include/core/SkPath.h" |
-#include "third_party/skia/include/core/SkPaint.h" |
-#include "third_party/skia/include/effects/SkGradientShader.h" |
+#include <algorithm> // for std::max |
+ |
+#include "base/logging.h" |
#include "ui/gfx/canvas.h" |
#include "ui/gfx/path.h" |
+#include "ui/gfx/rect.h" |
+#include "ui/gfx/screen.h" |
#include "ui/gfx/skia_util.h" |
namespace { |
@@ -20,24 +22,25 @@ const int kCornerRadius = 2; |
const int kArrowHeight = 10; |
const int kArrowWidth = 20; |
-// Bubble border color and width. |
-const SkColor kBorderColor = SkColorSetARGB(0x26, 0, 0, 0); |
const int kBorderSize = 1; |
+const SkColor kBorderColor = SkColorSetARGB(0x26, 0, 0, 0); |
+const SkColor kBackgroundColor = SK_ColorWHITE; |
-const SkColor kSearchBoxBackground = SK_ColorWHITE; |
-const SkColor kContentsBackground = SkColorSetRGB(0xFC, 0xFC, 0xFC); |
- |
-// Colors and sizes of top separator between searchbox and grid view. |
-const SkColor kTopSeparatorColor = SkColorSetRGB(0xF0, 0xF0, 0xF0); |
-const int kTopSeparatorSize = 1; |
+const int kShadowOffsetX = 0; |
+const int kShadowOffsetY = 5; |
+const double kShadowBlur = 30; |
+const SkColor kShadowColor = SkColorSetARGB(0x72, 0, 0, 0); |
// Builds a bubble shape for given |bounds|. |
void BuildShape(const gfx::Rect& bounds, |
views::BubbleBorder::ArrowLocation arrow_location, |
SkScalar arrow_offset, |
SkScalar padding, |
- SkPath* path) { |
- const SkScalar corner_radius = SkIntToScalar(kCornerRadius); |
+ SkPath* path, |
+ int corner_radius_int, |
+ int arrow_height_int, |
+ int arrow_width_int) { |
+ const SkScalar corner_radius = SkIntToScalar(corner_radius_int); |
const SkScalar left = SkIntToScalar(bounds.x()) + padding; |
const SkScalar top = SkIntToScalar(bounds.y()) + padding; |
@@ -47,8 +50,9 @@ void BuildShape(const gfx::Rect& bounds, |
const SkScalar center_x = SkIntToScalar((bounds.x() + bounds.right()) / 2); |
const SkScalar center_y = SkIntToScalar((bounds.y() + bounds.bottom()) / 2); |
- const SkScalar half_arrow_width = (SkIntToScalar(kArrowWidth) - padding) / 2; |
- const SkScalar arrow_height = SkIntToScalar(kArrowHeight) - padding; |
+ const SkScalar half_arrow_width = |
+ (SkIntToScalar(arrow_width_int) - padding) / 2; |
+ const SkScalar arrow_height = SkIntToScalar(arrow_height_int) - padding; |
path->reset(); |
path->incReserve(12); |
@@ -116,40 +120,56 @@ void BuildShape(const gfx::Rect& bounds, |
} // namespace |
-namespace app_list { |
- |
-AppListBubbleBorder::AppListBubbleBorder(views::View* app_list_view, |
- views::View* search_box_view) |
- : views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT, |
- views::BubbleBorder::NO_SHADOW), |
- app_list_view_(app_list_view), |
- search_box_view_(search_box_view) { |
- const gfx::ShadowValue kShadows[] = { |
- // Offset (0, 5), blur=30, color=0.36 black |
- gfx::ShadowValue(gfx::Point(0, 5), 30, SkColorSetARGB(0x72, 0, 0, 0)), |
- }; |
- shadows_.assign(kShadows, kShadows + arraysize(kShadows)); |
+namespace views { |
+ |
+BubbleBorder2::BubbleBorder2(ArrowLocation arrow_location) |
+ : BubbleBorder(arrow_location, views::BubbleBorder::NO_SHADOW), |
+ corner_radius_(kCornerRadius), |
+ border_size_(kBorderSize), |
+ arrow_height_(kArrowHeight), |
+ arrow_width_(kArrowWidth), |
+ background_color_(kBackgroundColor), |
+ border_color_(kBorderColor) { |
+ SetShadow(gfx::ShadowValue(gfx::Point(kShadowOffsetX, kShadowOffsetY), |
+ kShadowBlur, kShadowColor)); |
} |
-AppListBubbleBorder::~AppListBubbleBorder() { |
-} |
+BubbleBorder2::~BubbleBorder2() {} |
+ |
+gfx::Rect BubbleBorder2::ComputeOffsetAndUpdateBubbleRect( |
+ gfx::Rect bubble_rect, |
+ const gfx::Rect& anchor_view_rect) { |
+ offset_ = gfx::Point(); |
+ |
+ gfx::Rect monitor_rect = gfx::Screen::GetDisplayNearestPoint( |
+ anchor_view_rect.CenterPoint()).bounds(); |
+ if (monitor_rect.IsEmpty() || monitor_rect.Contains(bubble_rect)) |
+ return bubble_rect; |
+ |
+ gfx::Point offset; |
+ |
+ if (has_arrow(arrow_location())) { |
+ if (is_arrow_on_horizontal(arrow_location())) { |
+ if (bubble_rect.x() < monitor_rect.x()) |
+ offset.set_x(monitor_rect.x() - bubble_rect.x()); |
+ else if (bubble_rect.right() > monitor_rect.right()) |
+ offset.set_x(monitor_rect.right() - bubble_rect.right()); |
+ } else { |
+ if (bubble_rect.y() < monitor_rect.y()) |
+ offset.set_y(monitor_rect.y() - bubble_rect.y()); |
+ else if (bubble_rect.bottom() > monitor_rect.bottom()) |
+ offset.set_y(monitor_rect.bottom() - bubble_rect.bottom()); |
+ } |
+ } |
-bool AppListBubbleBorder::ArrowAtTopOrBottom() const { |
- return arrow_location() == views::BubbleBorder::TOP_LEFT || |
- arrow_location() == views::BubbleBorder::TOP_RIGHT || |
- arrow_location() == views::BubbleBorder::BOTTOM_LEFT || |
- arrow_location() == views::BubbleBorder::BOTTOM_RIGHT; |
-} |
+ bubble_rect.Offset(offset); |
+ set_offset(offset); |
-bool AppListBubbleBorder::ArrowOnLeftOrRight() const { |
- return arrow_location() == views::BubbleBorder::LEFT_TOP || |
- arrow_location() == views::BubbleBorder::LEFT_BOTTOM || |
- arrow_location() == views::BubbleBorder::RIGHT_TOP || |
- arrow_location() == views::BubbleBorder::RIGHT_BOTTOM; |
+ return bubble_rect; |
} |
-void AppListBubbleBorder::GetMask(const gfx::Rect& bounds, |
- gfx::Path* mask) const { |
+void BubbleBorder2::GetMask(const gfx::Rect& bounds, |
+ gfx::Path* mask) const { |
gfx::Insets insets; |
GetInsets(&insets); |
@@ -160,60 +180,51 @@ void AppListBubbleBorder::GetMask(const gfx::Rect& bounds, |
arrow_location(), |
SkIntToScalar(GetArrowOffset()), |
SkIntToScalar(kBorderSize), |
- mask); |
+ mask, |
+ corner_radius_, |
+ arrow_height_, |
+ arrow_width_); |
} |
-int AppListBubbleBorder::GetArrowOffset() const { |
- if (ArrowAtTopOrBottom()) { |
- // Picks x offset and moves bubble arrow in the opposite direction. |
- // i.e. If bubble bounds is moved to right (positive offset), we need to |
- // move arrow to left so that it points to the same position. |
- return -offset_.x(); |
- } else if (ArrowOnLeftOrRight()) { |
- // Picks y offset and moves bubble arrow in the opposite direction. |
- return -offset_.y(); |
- } |
+void BubbleBorder2::SetShadow(gfx::ShadowValue shadow) { |
+ shadows_.clear(); |
+ shadows_.push_back(shadow); |
+} |
- // Other style does not have an arrow, so return 0. |
+int BubbleBorder2::GetBorderThickness() const { |
return 0; |
} |
-void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas, |
- const gfx::Rect& bounds) const { |
- const gfx::Rect search_box_view_bounds = |
- app_list_view_->ConvertRectToWidget(search_box_view_->bounds()); |
- gfx::Rect search_box_rect(bounds.x(), |
- bounds.y(), |
- bounds.width(), |
- search_box_view_bounds.bottom() - bounds.y()); |
+void BubbleBorder2::PaintBackground(gfx::Canvas* canvas, |
+ const gfx::Rect& bounds) const { |
+ canvas->FillRect(bounds, background_color_); |
+} |
- SkPaint paint; |
- paint.setStyle(SkPaint::kFill_Style); |
- paint.setColor(kSearchBoxBackground); |
- canvas->DrawRect(search_box_rect, paint); |
- |
- gfx::Rect seperator_rect(search_box_rect); |
- seperator_rect.set_y(seperator_rect.bottom()); |
- seperator_rect.set_height(kTopSeparatorSize); |
- canvas->FillRect(seperator_rect, kTopSeparatorColor); |
- |
- gfx::Rect contents_rect(bounds.x(), |
- seperator_rect.bottom(), |
- bounds.width(), |
- bounds.bottom() - seperator_rect.bottom()); |
- |
- paint.setColor(kContentsBackground); |
- canvas->DrawRect(contents_rect, paint); |
+int BubbleBorder2::GetArrowOffset() const { |
+ if (has_arrow(arrow_location())) { |
+ if (is_arrow_on_horizontal(arrow_location())) { |
+ // Picks x offset and moves bubble arrow in the opposite direction. |
+ // i.e. If bubble bounds is moved to right (positive offset), we need to |
+ // move arrow to left so that it points to the same position. |
+ return -offset_.x(); |
+ } else { |
+ // Picks y offset and moves bubble arrow in the opposite direction. |
+ return -offset_.y(); |
+ } |
+ } |
+ |
+ // Other style does not have an arrow, so return 0. |
+ return 0; |
} |
-void AppListBubbleBorder::GetInsets(gfx::Insets* insets) const { |
+void BubbleBorder2::GetInsets(gfx::Insets* insets) const { |
// Negate to change from outer margin to inner padding. |
gfx::Insets shadow_padding(-gfx::ShadowValue::GetMargin(shadows_)); |
if (arrow_location() == views::BubbleBorder::TOP_LEFT || |
arrow_location() == views::BubbleBorder::TOP_RIGHT) { |
// Arrow at top. |
- insets->Set(shadow_padding.top() + kArrowHeight, |
+ insets->Set(shadow_padding.top() + arrow_height_, |
shadow_padding.left(), |
shadow_padding.bottom(), |
shadow_padding.right()); |
@@ -222,13 +233,13 @@ void AppListBubbleBorder::GetInsets(gfx::Insets* insets) const { |
// Arrow at bottom. |
insets->Set(shadow_padding.top(), |
shadow_padding.left(), |
- shadow_padding.bottom() + kArrowHeight, |
+ shadow_padding.bottom() + arrow_height_, |
shadow_padding.right()); |
} else if (arrow_location() == views::BubbleBorder::LEFT_TOP || |
arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { |
// Arrow on left. |
insets->Set(shadow_padding.top(), |
- shadow_padding.left() + kArrowHeight, |
+ shadow_padding.left() + arrow_height_, |
shadow_padding.bottom(), |
shadow_padding.right()); |
} else if (arrow_location() == views::BubbleBorder::RIGHT_TOP || |
@@ -237,13 +248,12 @@ void AppListBubbleBorder::GetInsets(gfx::Insets* insets) const { |
insets->Set(shadow_padding.top(), |
shadow_padding.left(), |
shadow_padding.bottom(), |
- shadow_padding.right() + kArrowHeight); |
+ shadow_padding.right() + arrow_height_); |
} |
} |
-gfx::Rect AppListBubbleBorder::GetBounds( |
- const gfx::Rect& position_relative_to, |
- const gfx::Size& contents_size) const { |
+gfx::Rect BubbleBorder2::GetBounds(const gfx::Rect& position_relative_to, |
+ const gfx::Size& contents_size) const { |
gfx::Size border_size(contents_size); |
gfx::Insets insets; |
GetInsets(&insets); |
@@ -274,8 +284,7 @@ gfx::Rect AppListBubbleBorder::GetBounds( |
// Arrow at top. |
return gfx::Rect( |
gfx::Point(anchor_center_x - arrow_tip_x, |
- position_relative_to.bottom() - shadow_padding.top() - |
- kArrowHeight), |
+ position_relative_to.bottom() - shadow_padding.top()), |
border_size); |
} else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT || |
arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) { |
@@ -283,14 +292,13 @@ gfx::Rect AppListBubbleBorder::GetBounds( |
return gfx::Rect( |
gfx::Point(anchor_center_x - arrow_tip_x, |
position_relative_to.y() - border_size.height() + |
- shadow_padding.bottom() + kArrowHeight), |
+ shadow_padding.bottom()), |
border_size); |
} else if (arrow_location() == views::BubbleBorder::LEFT_TOP || |
arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { |
// Arrow on left. |
return gfx::Rect( |
- gfx::Point(position_relative_to.right() - shadow_padding.left() - |
- kArrowHeight, |
+ gfx::Point(position_relative_to.right() - shadow_padding.left(), |
anchor_center_y - arrow_tip_y), |
border_size); |
} else if (arrow_location() == views::BubbleBorder::RIGHT_TOP || |
@@ -298,7 +306,7 @@ gfx::Rect AppListBubbleBorder::GetBounds( |
// Arrow on right. |
return gfx::Rect( |
gfx::Point(position_relative_to.x() - border_size.width() + |
- shadow_padding.right() + kArrowHeight, |
+ shadow_padding.right(), |
anchor_center_y - arrow_tip_y), |
border_size); |
} |
@@ -307,8 +315,42 @@ gfx::Rect AppListBubbleBorder::GetBounds( |
return position_relative_to.Center(border_size); |
} |
-void AppListBubbleBorder::Paint(const views::View& view, |
- gfx::Canvas* canvas) const { |
+void BubbleBorder2::GetInsetsForArrowLocation(gfx::Insets* insets, |
+ ArrowLocation arrow_loc) const { |
+ int top = border_size_; |
+ int bottom = border_size_; |
+ int left = border_size_; |
+ int right = border_size_; |
+ switch (arrow_loc) { |
+ case TOP_LEFT: |
+ case TOP_RIGHT: |
+ top = std::max(top, arrow_height_); |
+ break; |
+ |
+ case BOTTOM_LEFT: |
+ case BOTTOM_RIGHT: |
+ bottom = std::max(bottom, arrow_height_); |
+ break; |
+ |
+ case LEFT_TOP: |
+ case LEFT_BOTTOM: |
+ left = std::max(left, arrow_height_); |
+ break; |
+ |
+ case RIGHT_TOP: |
+ case RIGHT_BOTTOM: |
+ right = std::max(right, arrow_height_); |
+ break; |
+ |
+ case NONE: |
+ case FLOAT: |
+ // Nothing to do. |
+ break; |
+ } |
+ insets->Set(top, left, bottom, right); |
+} |
+ |
+void BubbleBorder2::Paint(const views::View& view, gfx::Canvas* canvas) const { |
gfx::Insets insets; |
GetInsets(&insets); |
@@ -321,23 +363,29 @@ void AppListBubbleBorder::Paint(const views::View& view, |
arrow_location(), |
SkIntToScalar(GetArrowOffset()), |
SkDoubleToScalar(0.5), |
- &path); |
+ &path, |
+ corner_radius_, |
+ arrow_height_, |
+ arrow_width_); |
// Draw border and shadow. Note fill is needed to generate enough shadow. |
SkPaint paint; |
paint.setAntiAlias(true); |
paint.setStyle(SkPaint::kStrokeAndFill_Style); |
- paint.setStrokeWidth(SkIntToScalar(kBorderSize)); |
- paint.setColor(kBorderColor); |
+ paint.setStrokeWidth(SkIntToScalar(border_size_)); |
+ paint.setColor(border_color_); |
SkSafeUnref(paint.setLooper(gfx::CreateShadowDrawLooper(shadows_))); |
canvas->DrawPath(path, paint); |
- // Pads with kBoprderSize pixels to leave space for border lines. |
+ // Pads with |border_size_| pixels to leave space for border lines. |
BuildShape(content_bounds, |
arrow_location(), |
SkIntToScalar(GetArrowOffset()), |
- SkIntToScalar(kBorderSize), |
- &path); |
+ SkIntToScalar(border_size_), |
+ &path, |
+ corner_radius_, |
+ arrow_height_, |
+ arrow_width_); |
canvas->Save(); |
canvas->ClipPath(path); |
@@ -348,4 +396,4 @@ void AppListBubbleBorder::Paint(const views::View& view, |
canvas->Restore(); |
} |
-} // namespace app_list |
+} // namespace views |