aura: Fix launcher tooltips:

1. Refactor out app_list_bubble_border so that it can be used for launcher
tooltip border.
2. UI polish: increase padding, make tooltip single line, reduce maximum
tooltip width.

BUG=133292
TEST=manual

Review URL: https://chromiumcodereview.appspot.com/10834140

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149987 0039d316-1c4b-4281-b951-d872f2087c98
parent 92daaa43
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "ui/base/events.h" #include "ui/base/events.h"
#include "ui/gfx/insets.h" #include "ui/gfx/insets.h"
#include "ui/views/bubble/bubble_delegate.h" #include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/bubble/bubble_border_2.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
...@@ -25,12 +27,22 @@ ...@@ -25,12 +27,22 @@
namespace ash { namespace ash {
namespace internal { namespace internal {
namespace { namespace {
const int kTooltipMargin = 3; const int kTooltipTopBottomMargin = 3;
const int kTooltipLeftRightMargin = 10;
const int kTooltipAppearanceDelay = 200; // msec const int kTooltipAppearanceDelay = 200; // msec
const int kTooltipMinHeight = 29 - 2 * kTooltipTopBottomMargin;
const SkColor kTooltipTextColor = SkColorSetRGB(22, 22, 22);
// The maximum width of the tooltip bubble. Borrowed the value from // The maximum width of the tooltip bubble. Borrowed the value from
// ash/tooltip/tooltip_controller.cc // ash/tooltip/tooltip_controller.cc
const int kTooltipMaxWidth = 400; const int kTooltipMaxWidth = 250;
// Bubble border metrics
const int kArrowHeight = 7;
const int kArrowWidth = 15;
const int kShadowWidth = 8;
// The distance between the arrow tip and edge of the anchor view.
const int kArrowOffset = 10;
views::BubbleBorder::ArrowLocation GetArrowLocation(ShelfAlignment alignment) { views::BubbleBorder::ArrowLocation GetArrowLocation(ShelfAlignment alignment) {
switch (alignment) { switch (alignment) {
...@@ -58,11 +70,20 @@ class LauncherTooltipManager::LauncherTooltipBubble ...@@ -58,11 +70,20 @@ class LauncherTooltipManager::LauncherTooltipBubble
void Close(); void Close();
private: private:
// Overridden from views::BubbleDelegateView:
virtual gfx::Rect GetBubbleBounds() OVERRIDE;
// views::WidgetDelegate overrides: // views::WidgetDelegate overrides:
virtual void WindowClosing() OVERRIDE; virtual void WindowClosing() OVERRIDE;
// views::View overrides:
virtual gfx::Size GetPreferredSize() OVERRIDE;
LauncherTooltipManager* host_; LauncherTooltipManager* host_;
views::Label* label_; views::Label* label_;
views::BubbleBorder2* bubble_border_;
DISALLOW_COPY_AND_ASSIGN(LauncherTooltipBubble);
}; };
LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble( LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble(
...@@ -70,12 +91,13 @@ LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble( ...@@ -70,12 +91,13 @@ LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble(
views::BubbleBorder::ArrowLocation arrow_location, views::BubbleBorder::ArrowLocation arrow_location,
LauncherTooltipManager* host) LauncherTooltipManager* host)
: views::BubbleDelegateView(anchor, arrow_location), : views::BubbleDelegateView(anchor, arrow_location),
host_(host) { host_(host),
bubble_border_(NULL) {
set_close_on_esc(false); set_close_on_esc(false);
set_close_on_deactivate(false); set_close_on_deactivate(false);
set_use_focusless(true); set_use_focusless(true);
set_margins(gfx::Insets(kTooltipMargin, kTooltipMargin, kTooltipMargin, set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin,
kTooltipMargin)); kTooltipTopBottomMargin, kTooltipLeftRightMargin));
SetLayoutManager(new views::FillLayout()); SetLayoutManager(new views::FillLayout());
// The anchor may not have the widget in tests. // The anchor may not have the widget in tests.
if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) { if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) {
...@@ -86,14 +108,22 @@ LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble( ...@@ -86,14 +108,22 @@ LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble(
} }
label_ = new views::Label; label_ = new views::Label;
label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
label_->SetEnabledColor(kTooltipTextColor);
AddChildView(label_); AddChildView(label_);
views::BubbleDelegateView::CreateBubble(this);
bubble_border_ = new views::BubbleBorder2(views::BubbleBorder::BOTTOM_RIGHT);
bubble_border_->SetShadow(gfx::ShadowValue(
gfx::Point(0, 5), kShadowWidth, SkColorSetARGB(0x72, 0, 0, 0)));
bubble_border_->set_arrow_width(kArrowWidth);
bubble_border_->set_arrow_height(kArrowHeight);
set_anchor_insets(gfx::Insets(kArrowOffset, kArrowOffset, kArrowOffset,
kArrowOffset));
GetBubbleFrameView()->SetBubbleBorder(bubble_border_);
} }
void LauncherTooltipManager::LauncherTooltipBubble::SetText( void LauncherTooltipManager::LauncherTooltipBubble::SetText(
const string16& text) { const string16& text) {
label_->SetText(text); label_->SetText(text);
label_->SetMultiLine(true);
label_->SizeToFit(kTooltipMaxWidth);
SizeToContents(); SizeToContents();
} }
...@@ -104,12 +134,43 @@ void LauncherTooltipManager::LauncherTooltipBubble::Close() { ...@@ -104,12 +134,43 @@ void LauncherTooltipManager::LauncherTooltipBubble::Close() {
} }
} }
gfx::Rect LauncherTooltipManager::LauncherTooltipBubble::GetBubbleBounds() {
// This happens before replacing the default border.
if (!bubble_border_)
return views::BubbleDelegateView::GetBubbleBounds();
const gfx::Rect anchor_rect = GetAnchorRect();
gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds(
anchor_rect,
GetPreferredSize(),
false /* try_mirroring_arrow */);
const gfx::Point old_offset = bubble_border_->offset();
bubble_rect = bubble_border_->ComputeOffsetAndUpdateBubbleRect(bubble_rect,
anchor_rect);
// Repaints border if arrow offset is changed.
if (bubble_border_->offset() != old_offset)
GetBubbleFrameView()->SchedulePaint();
return bubble_rect;
}
void LauncherTooltipManager::LauncherTooltipBubble::WindowClosing() { void LauncherTooltipManager::LauncherTooltipBubble::WindowClosing() {
views::BubbleDelegateView::WindowClosing(); views::BubbleDelegateView::WindowClosing();
if (host_) if (host_)
host_->OnBubbleClosed(this); host_->OnBubbleClosed(this);
} }
gfx::Size LauncherTooltipManager::LauncherTooltipBubble::GetPreferredSize() {
gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize();
if (pref_size.height() < kTooltipMinHeight)
pref_size.set_height(kTooltipMinHeight);
if (pref_size.width() > kTooltipMaxWidth)
pref_size.set_width(kTooltipMaxWidth);
return pref_size;
}
LauncherTooltipManager::LauncherTooltipManager( LauncherTooltipManager::LauncherTooltipManager(
ShelfAlignment alignment, ShelfAlignment alignment,
ShelfLayoutManager* shelf_layout_manager, ShelfLayoutManager* shelf_layout_manager,
...@@ -339,7 +400,6 @@ void LauncherTooltipManager::CreateBubble(views::View* anchor, ...@@ -339,7 +400,6 @@ void LauncherTooltipManager::CreateBubble(views::View* anchor,
text_ = text; text_ = text;
view_ = new LauncherTooltipBubble( view_ = new LauncherTooltipBubble(
anchor, GetArrowLocation(alignment_), this); anchor, GetArrowLocation(alignment_), this);
views::BubbleDelegateView::CreateBubble(view_);
widget_ = view_->GetWidget(); widget_ = view_->GetWidget();
view_->SetText(text_); view_->SetText(text_);
......
...@@ -13,17 +13,6 @@ ...@@ -13,17 +13,6 @@
namespace { namespace {
// Bubble border corner radius.
const int kCornerRadius = 2;
// Arrow width and height.
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 kSearchBoxBackground = SK_ColorWHITE; const SkColor kSearchBoxBackground = SK_ColorWHITE;
const SkColor kContentsBackground = SkColorSetRGB(0xFC, 0xFC, 0xFC); const SkColor kContentsBackground = SkColorSetRGB(0xFC, 0xFC, 0xFC);
...@@ -31,153 +20,20 @@ const SkColor kContentsBackground = SkColorSetRGB(0xFC, 0xFC, 0xFC); ...@@ -31,153 +20,20 @@ const SkColor kContentsBackground = SkColorSetRGB(0xFC, 0xFC, 0xFC);
const SkColor kTopSeparatorColor = SkColorSetRGB(0xF0, 0xF0, 0xF0); const SkColor kTopSeparatorColor = SkColorSetRGB(0xF0, 0xF0, 0xF0);
const int kTopSeparatorSize = 1; const int kTopSeparatorSize = 1;
// 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);
const SkScalar left = SkIntToScalar(bounds.x()) + padding;
const SkScalar top = SkIntToScalar(bounds.y()) + padding;
const SkScalar right = SkIntToScalar(bounds.right()) - padding;
const SkScalar bottom = SkIntToScalar(bounds.bottom()) - padding;
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;
path->reset();
path->incReserve(12);
switch (arrow_location) {
case views::BubbleBorder::TOP_LEFT:
case views::BubbleBorder::TOP_RIGHT:
path->moveTo(center_x, bottom);
path->arcTo(right, bottom, right, center_y, corner_radius);
path->arcTo(right, top, center_x - half_arrow_width, top,
corner_radius);
path->lineTo(center_x + arrow_offset + half_arrow_width, top);
path->lineTo(center_x + arrow_offset, top - arrow_height);
path->lineTo(center_x + arrow_offset - half_arrow_width, top);
path->arcTo(left, top, left, center_y, corner_radius);
path->arcTo(left, bottom, center_x, bottom, corner_radius);
break;
case views::BubbleBorder::BOTTOM_LEFT:
case views::BubbleBorder::BOTTOM_RIGHT:
path->moveTo(center_x, top);
path->arcTo(left, top, left, center_y, corner_radius);
path->arcTo(left, bottom, center_x - half_arrow_width, bottom,
corner_radius);
path->lineTo(center_x + arrow_offset - half_arrow_width, bottom);
path->lineTo(center_x + arrow_offset, bottom + arrow_height);
path->lineTo(center_x + arrow_offset + half_arrow_width, bottom);
path->arcTo(right, bottom, right, center_y, corner_radius);
path->arcTo(right, top, center_x, top, corner_radius);
break;
case views::BubbleBorder::LEFT_TOP:
case views::BubbleBorder::LEFT_BOTTOM:
path->moveTo(right, center_y);
path->arcTo(right, top, center_x, top, corner_radius);
path->arcTo(left, top, left, center_y + arrow_offset - half_arrow_width,
corner_radius);
path->lineTo(left, center_y + arrow_offset - half_arrow_width);
path->lineTo(left - arrow_height, center_y + arrow_offset);
path->lineTo(left, center_y + arrow_offset + half_arrow_width);
path->arcTo(left, bottom, center_x, bottom, corner_radius);
path->arcTo(right, bottom, right, center_y, corner_radius);
break;
case views::BubbleBorder::RIGHT_TOP:
case views::BubbleBorder::RIGHT_BOTTOM:
path->moveTo(left, center_y);
path->arcTo(left, bottom, center_x, bottom, corner_radius);
path->arcTo(right, bottom,
right, center_y + arrow_offset + half_arrow_width,
corner_radius);
path->lineTo(right, center_y + arrow_offset + half_arrow_width);
path->lineTo(right + arrow_height, center_y + arrow_offset);
path->lineTo(right, center_y + arrow_offset - half_arrow_width);
path->arcTo(right, top, center_x, top, corner_radius);
path->arcTo(left, top, left, center_y, corner_radius);
break;
default:
// No arrows.
path->addRoundRect(gfx::RectToSkRect(bounds),
corner_radius,
corner_radius);
break;
}
path->close();
}
} // namespace } // namespace
namespace app_list { namespace app_list {
AppListBubbleBorder::AppListBubbleBorder(views::View* app_list_view, AppListBubbleBorder::AppListBubbleBorder(views::View* app_list_view,
views::View* search_box_view) views::View* search_box_view)
: views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT, : views::BubbleBorder2(views::BubbleBorder::BOTTOM_RIGHT),
views::BubbleBorder::NO_SHADOW),
app_list_view_(app_list_view), app_list_view_(app_list_view),
search_box_view_(search_box_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));
} }
AppListBubbleBorder::~AppListBubbleBorder() { AppListBubbleBorder::~AppListBubbleBorder() {
} }
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;
}
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;
}
void AppListBubbleBorder::GetMask(const gfx::Rect& bounds,
gfx::Path* mask) const {
gfx::Insets insets;
GetInsets(&insets);
gfx::Rect content_bounds(bounds);
content_bounds.Inset(insets);
BuildShape(content_bounds,
arrow_location(),
SkIntToScalar(GetArrowOffset()),
SkIntToScalar(kBorderSize),
mask);
}
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();
}
// Other style does not have an arrow, so return 0.
return 0;
}
void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas, void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas,
const gfx::Rect& bounds) const { const gfx::Rect& bounds) const {
const gfx::Rect search_box_view_bounds = const gfx::Rect search_box_view_bounds =
...@@ -206,146 +62,4 @@ void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas, ...@@ -206,146 +62,4 @@ void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas,
canvas->DrawRect(contents_rect, paint); canvas->DrawRect(contents_rect, paint);
} }
void AppListBubbleBorder::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,
shadow_padding.left(),
shadow_padding.bottom(),
shadow_padding.right());
} else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT ||
arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) {
// Arrow at bottom.
insets->Set(shadow_padding.top(),
shadow_padding.left(),
shadow_padding.bottom() + kArrowHeight,
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.bottom(),
shadow_padding.right());
} else if (arrow_location() == views::BubbleBorder::RIGHT_TOP ||
arrow_location() == views::BubbleBorder::RIGHT_BOTTOM) {
// Arrow on right.
insets->Set(shadow_padding.top(),
shadow_padding.left(),
shadow_padding.bottom(),
shadow_padding.right() + kArrowHeight);
}
}
gfx::Rect AppListBubbleBorder::GetBounds(
const gfx::Rect& position_relative_to,
const gfx::Size& contents_size) const {
gfx::Size border_size(contents_size);
gfx::Insets insets;
GetInsets(&insets);
border_size.Enlarge(insets.width(), insets.height());
// Negate to change from outer margin to inner padding.
gfx::Insets shadow_padding(-gfx::ShadowValue::GetMargin(shadows_));
// Anchor center that arrow aligns with.
const int anchor_center_x =
(position_relative_to.x() + position_relative_to.right()) / 2;
const int anchor_center_y =
(position_relative_to.y() + position_relative_to.bottom()) / 2;
// Arrow position relative to top-left of bubble. |arrow_tip_x| is used for
// arrow at the top or bottom and |arrow_tip_y| is used for arrow on left or
// right. The 1px offset for |arrow_tip_y| is needed because the app list grid
// icon start at a different position (1px earlier) compared with bottom
// launcher bar.
// TODO(xiyuan): Remove 1px offset when app list icon image asset is updated.
int arrow_tip_x = insets.left() + contents_size.width() / 2 +
GetArrowOffset();
int arrow_tip_y = insets.top() + contents_size.height() / 2 +
GetArrowOffset() + 1;
if (arrow_location() == views::BubbleBorder::TOP_LEFT ||
arrow_location() == views::BubbleBorder::TOP_RIGHT) {
// Arrow at top.
return gfx::Rect(
gfx::Point(anchor_center_x - arrow_tip_x,
position_relative_to.bottom() - shadow_padding.top() -
kArrowHeight),
border_size);
} else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT ||
arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) {
// Arrow at bottom.
return gfx::Rect(
gfx::Point(anchor_center_x - arrow_tip_x,
position_relative_to.y() - border_size.height() +
shadow_padding.bottom() + kArrowHeight),
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,
anchor_center_y - arrow_tip_y),
border_size);
} else if (arrow_location() == views::BubbleBorder::RIGHT_TOP ||
arrow_location() == views::BubbleBorder::RIGHT_BOTTOM) {
// Arrow on right.
return gfx::Rect(
gfx::Point(position_relative_to.x() - border_size.width() +
shadow_padding.right() + kArrowHeight,
anchor_center_y - arrow_tip_y),
border_size);
}
// No arrow bubble, center align with anchor.
return position_relative_to.Center(border_size);
}
void AppListBubbleBorder::Paint(const views::View& view,
gfx::Canvas* canvas) const {
gfx::Insets insets;
GetInsets(&insets);
gfx::Rect content_bounds = view.bounds();
content_bounds.Inset(insets);
SkPath path;
// Pads with 0.5 pixel since anti alias is used.
BuildShape(content_bounds,
arrow_location(),
SkIntToScalar(GetArrowOffset()),
SkDoubleToScalar(0.5),
&path);
// 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);
SkSafeUnref(paint.setLooper(gfx::CreateShadowDrawLooper(shadows_)));
canvas->DrawPath(path, paint);
// Pads with kBoprderSize pixels to leave space for border lines.
BuildShape(content_bounds,
arrow_location(),
SkIntToScalar(GetArrowOffset()),
SkIntToScalar(kBorderSize),
&path);
canvas->Save();
canvas->ClipPath(path);
// Use full bounds so that arrow is also painted.
const gfx::Rect& bounds = view.bounds();
PaintBackground(canvas, bounds);
canvas->Restore();
}
} // namespace app_list } // namespace app_list
...@@ -7,52 +7,28 @@ ...@@ -7,52 +7,28 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "ui/gfx/shadow_value.h" #include "ui/gfx/shadow_value.h"
#include "ui/views/bubble/bubble_border.h" #include "ui/views/bubble/bubble_border_2.h"
namespace app_list { namespace app_list {
// A class to paint bubble border and background. // A class to paint bubble border and background.
class AppListBubbleBorder : public views::BubbleBorder { class AppListBubbleBorder : public views::BubbleBorder2 {
public: public:
AppListBubbleBorder(views::View* app_list_view, AppListBubbleBorder(views::View* app_list_view,
views::View* search_box_view); views::View* search_box_view);
virtual ~AppListBubbleBorder(); virtual ~AppListBubbleBorder();
bool ArrowAtTopOrBottom() const;
bool ArrowOnLeftOrRight() const;
void GetMask(const gfx::Rect& bounds, gfx::Path* mask) const;
void set_offset(const gfx::Point& offset) { offset_ = offset; }
const gfx::Point& offset() const { return offset_; }
private: private:
// Gets arrow offset based on arrow location and |offset_|. // views::ImagelessBubbleBorder overrides:
int GetArrowOffset() const;
void PaintBackground(gfx::Canvas* canvas, void PaintBackground(gfx::Canvas* canvas,
const gfx::Rect& bounds) const; const gfx::Rect& bounds) const;
// views::BubbleBorder overrides:
virtual void GetInsets(gfx::Insets* insets) const OVERRIDE;
virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
const gfx::Size& contents_size) const OVERRIDE;
// views::Border overrides:
virtual void Paint(const views::View& view,
gfx::Canvas* canvas) const OVERRIDE;
// AppListView hosted inside this bubble. // AppListView hosted inside this bubble.
const views::View* app_list_view_; // Owned by views hierarchy. const views::View* app_list_view_; // Owned by views hierarchy.
// Children view of AppListView that needs to paint background. // Children view of AppListView that needs to paint background.
const views::View* search_box_view_; // Owned by views hierarchy. const views::View* search_box_view_; // Owned by views hierarchy.
// Offset in pixels relative the default middle position.
gfx::Point offset_;
gfx::ShadowValues shadows_;
DISALLOW_COPY_AND_ASSIGN(AppListBubbleBorder); DISALLOW_COPY_AND_ASSIGN(AppListBubbleBorder);
}; };
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "ui/app_list/search_box_model.h" #include "ui/app_list/search_box_model.h"
#include "ui/app_list/search_box_view.h" #include "ui/app_list/search_box_view.h"
#include "ui/gfx/insets.h" #include "ui/gfx/insets.h"
#include "ui/gfx/screen.h"
#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
...@@ -26,6 +25,9 @@ namespace { ...@@ -26,6 +25,9 @@ namespace {
// Inner padding space in pixels of bubble contents. // Inner padding space in pixels of bubble contents.
const int kInnerPadding = 1; const int kInnerPadding = 1;
// The distance between the arrow tip and edge of the anchor view.
const int kArrowOffset = 10;
} // namespace } // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -68,6 +70,8 @@ void AppListView::InitAsBubble( ...@@ -68,6 +70,8 @@ void AppListView::InitAsBubble(
set_move_with_anchor(true); set_move_with_anchor(true);
set_parent_window(parent); set_parent_window(parent);
set_close_on_deactivate(false); set_close_on_deactivate(false);
set_anchor_insets(gfx::Insets(kArrowOffset, kArrowOffset, kArrowOffset,
kArrowOffset));
views::BubbleDelegateView::CreateBubble(this); views::BubbleDelegateView::CreateBubble(this);
// Resets default background since AppListBubbleBorder paints background. // Resets default background since AppListBubbleBorder paints background.
...@@ -152,36 +156,15 @@ gfx::Rect AppListView::GetBubbleBounds() { ...@@ -152,36 +156,15 @@ gfx::Rect AppListView::GetBubbleBounds() {
if (!bubble_border_) if (!bubble_border_)
return views::BubbleDelegateView::GetBubbleBounds(); return views::BubbleDelegateView::GetBubbleBounds();
const gfx::Point old_offset = bubble_border_->offset();
const gfx::Rect anchor_rect = GetAnchorRect(); const gfx::Rect anchor_rect = GetAnchorRect();
bubble_border_->set_offset(gfx::Point());
gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds(
anchor_rect, anchor_rect,
GetPreferredSize(), GetPreferredSize(),
false /* try_mirroring_arrow */); false /* try_mirroring_arrow */);
gfx::Rect monitor_rect = gfx::Screen::GetDisplayNearestPoint( const gfx::Point old_offset = bubble_border_->offset();
anchor_rect.CenterPoint()).work_area(); bubble_rect = bubble_border_->ComputeOffsetAndUpdateBubbleRect(bubble_rect,
if (monitor_rect.IsEmpty() || monitor_rect.Contains(bubble_rect)) anchor_rect);
return bubble_rect;
gfx::Point offset;
if (bubble_border_->ArrowAtTopOrBottom()) {
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_border_->ArrowOnLeftOrRight()) {
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());
}
bubble_rect.Offset(offset);
bubble_border_->set_offset(offset);
// Repaints border if arrow offset is changed. // Repaints border if arrow offset is changed.
if (bubble_border_->offset() != old_offset) if (bubble_border_->offset() != old_offset)
......
...@@ -212,7 +212,7 @@ void BubbleBorder::GetInsetsForArrowLocation(gfx::Insets* insets, ...@@ -212,7 +212,7 @@ void BubbleBorder::GetInsetsForArrowLocation(gfx::Insets* insets,
insets->Set(top, left, bottom, right); insets->Set(top, left, bottom, right);
} }
int BubbleBorder::border_thickness() const { int BubbleBorder::GetBorderThickness() const {
return images_->border_thickness; return images_->border_thickness;
} }
...@@ -505,7 +505,7 @@ void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { ...@@ -505,7 +505,7 @@ void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
paint.setColor(border_->background_color()); paint.setColor(border_->background_color());
SkPath path; SkPath path;
gfx::Rect bounds(view->GetContentsBounds()); gfx::Rect bounds(view->GetContentsBounds());
bounds.Inset(-border_->border_thickness(), -border_->border_thickness()); bounds.Inset(-border_->GetBorderThickness(), -border_->GetBorderThickness());
SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius()); SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius);
canvas->DrawPath(path, paint); canvas->DrawPath(path, paint);
......
...@@ -118,7 +118,7 @@ class VIEWS_EXPORT BubbleBorder : public Border { ...@@ -118,7 +118,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
virtual void GetInsets(gfx::Insets* insets) const OVERRIDE; virtual void GetInsets(gfx::Insets* insets) const OVERRIDE;
// How many pixels the bubble border is from the edge of the images. // How many pixels the bubble border is from the edge of the images.
int border_thickness() const; virtual int GetBorderThickness() const;
protected: protected:
virtual ~BubbleBorder(); virtual ~BubbleBorder();
...@@ -126,7 +126,7 @@ class VIEWS_EXPORT BubbleBorder : public Border { ...@@ -126,7 +126,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// Calculates the insets for a specific arrow location. Normally called from // Calculates the insets for a specific arrow location. Normally called from
// GetInsets(arrow_location()), but may be called by specialized BubbleBorder // GetInsets(arrow_location()), but may be called by specialized BubbleBorder
// implementations. // implementations.
void GetInsetsForArrowLocation(gfx::Insets* insets, virtual void GetInsetsForArrowLocation(gfx::Insets* insets,
ArrowLocation arrow_loc) const; ArrowLocation arrow_loc) const;
private: private:
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/bubble/bubble_border_2.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 {
// Bubble border corner radius.
const int kCornerRadius = 2;
// Arrow width and height.
const int kArrowHeight = 10;
const int kArrowWidth = 20;
const int kBorderSize = 1;
const SkColor kBorderColor = SkColorSetARGB(0x26, 0, 0, 0);
const SkColor kBackgroundColor = SK_ColorWHITE;
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,
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;
const SkScalar right = SkIntToScalar(bounds.right()) - padding;
const SkScalar bottom = SkIntToScalar(bounds.bottom()) - padding;
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(arrow_width_int) - padding) / 2;
const SkScalar arrow_height = SkIntToScalar(arrow_height_int) - padding;
path->reset();
path->incReserve(12);
switch (arrow_location) {
case views::BubbleBorder::TOP_LEFT:
case views::BubbleBorder::TOP_RIGHT:
path->moveTo(center_x, bottom);
path->arcTo(right, bottom, right, center_y, corner_radius);
path->arcTo(right, top, center_x - half_arrow_width, top,
corner_radius);
path->lineTo(center_x + arrow_offset + half_arrow_width, top);
path->lineTo(center_x + arrow_offset, top - arrow_height);
path->lineTo(center_x + arrow_offset - half_arrow_width, top);
path->arcTo(left, top, left, center_y, corner_radius);
path->arcTo(left, bottom, center_x, bottom, corner_radius);
break;
case views::BubbleBorder::BOTTOM_LEFT:
case views::BubbleBorder::BOTTOM_RIGHT:
path->moveTo(center_x, top);
path->arcTo(left, top, left, center_y, corner_radius);
path->arcTo(left, bottom, center_x - half_arrow_width, bottom,
corner_radius);
path->lineTo(center_x + arrow_offset - half_arrow_width, bottom);
path->lineTo(center_x + arrow_offset, bottom + arrow_height);
path->lineTo(center_x + arrow_offset + half_arrow_width, bottom);
path->arcTo(right, bottom, right, center_y, corner_radius);
path->arcTo(right, top, center_x, top, corner_radius);
break;
case views::BubbleBorder::LEFT_TOP:
case views::BubbleBorder::LEFT_BOTTOM:
path->moveTo(right, center_y);
path->arcTo(right, top, center_x, top, corner_radius);
path->arcTo(left, top, left, center_y + arrow_offset - half_arrow_width,
corner_radius);
path->lineTo(left, center_y + arrow_offset - half_arrow_width);
path->lineTo(left - arrow_height, center_y + arrow_offset);
path->lineTo(left, center_y + arrow_offset + half_arrow_width);
path->arcTo(left, bottom, center_x, bottom, corner_radius);
path->arcTo(right, bottom, right, center_y, corner_radius);
break;
case views::BubbleBorder::RIGHT_TOP:
case views::BubbleBorder::RIGHT_BOTTOM:
path->moveTo(left, center_y);
path->arcTo(left, bottom, center_x, bottom, corner_radius);
path->arcTo(right, bottom,
right, center_y + arrow_offset + half_arrow_width,
corner_radius);
path->lineTo(right, center_y + arrow_offset + half_arrow_width);
path->lineTo(right + arrow_height, center_y + arrow_offset);
path->lineTo(right, center_y + arrow_offset - half_arrow_width);
path->arcTo(right, top, center_x, top, corner_radius);
path->arcTo(left, top, left, center_y, corner_radius);
break;
default:
// No arrows.
path->addRoundRect(gfx::RectToSkRect(bounds),
corner_radius,
corner_radius);
break;
}
path->close();
}
} // namespace
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));
}
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());
}
}
bubble_rect.Offset(offset);
set_offset(offset);
return bubble_rect;
}
void BubbleBorder2::GetMask(const gfx::Rect& bounds,
gfx::Path* mask) const {
gfx::Insets insets;
GetInsets(&insets);
gfx::Rect content_bounds(bounds);
content_bounds.Inset(insets);
BuildShape(content_bounds,
arrow_location(),
SkIntToScalar(GetArrowOffset()),
SkIntToScalar(kBorderSize),
mask,
corner_radius_,
arrow_height_,
arrow_width_);
}
void BubbleBorder2::SetShadow(gfx::ShadowValue shadow) {
shadows_.clear();
shadows_.push_back(shadow);
}
int BubbleBorder2::GetBorderThickness() const {
return 0;
}
void BubbleBorder2::PaintBackground(gfx::Canvas* canvas,
const gfx::Rect& bounds) const {
canvas->FillRect(bounds, background_color_);
}
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 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() + arrow_height_,
shadow_padding.left(),
shadow_padding.bottom(),
shadow_padding.right());
} else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT ||
arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) {
// Arrow at bottom.
insets->Set(shadow_padding.top(),
shadow_padding.left(),
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() + arrow_height_,
shadow_padding.bottom(),
shadow_padding.right());
} else if (arrow_location() == views::BubbleBorder::RIGHT_TOP ||
arrow_location() == views::BubbleBorder::RIGHT_BOTTOM) {
// Arrow on right.
insets->Set(shadow_padding.top(),
shadow_padding.left(),
shadow_padding.bottom(),
shadow_padding.right() + arrow_height_);
}
}
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);
border_size.Enlarge(insets.width(), insets.height());
// Negate to change from outer margin to inner padding.
gfx::Insets shadow_padding(-gfx::ShadowValue::GetMargin(shadows_));
// Anchor center that arrow aligns with.
const int anchor_center_x =
(position_relative_to.x() + position_relative_to.right()) / 2;
const int anchor_center_y =
(position_relative_to.y() + position_relative_to.bottom()) / 2;
// Arrow position relative to top-left of bubble. |arrow_tip_x| is used for
// arrow at the top or bottom and |arrow_tip_y| is used for arrow on left or
// right. The 1px offset for |arrow_tip_y| is needed because the app list grid
// icon start at a different position (1px earlier) compared with bottom
// launcher bar.
// TODO(xiyuan): Remove 1px offset when app list icon image asset is updated.
int arrow_tip_x = insets.left() + contents_size.width() / 2 +
GetArrowOffset();
int arrow_tip_y = insets.top() + contents_size.height() / 2 +
GetArrowOffset() + 1;
if (arrow_location() == views::BubbleBorder::TOP_LEFT ||
arrow_location() == views::BubbleBorder::TOP_RIGHT) {
// Arrow at top.
return gfx::Rect(
gfx::Point(anchor_center_x - arrow_tip_x,
position_relative_to.bottom() - shadow_padding.top()),
border_size);
} else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT ||
arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) {
// Arrow at bottom.
return gfx::Rect(
gfx::Point(anchor_center_x - arrow_tip_x,
position_relative_to.y() - border_size.height() +
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(),
anchor_center_y - arrow_tip_y),
border_size);
} else if (arrow_location() == views::BubbleBorder::RIGHT_TOP ||
arrow_location() == views::BubbleBorder::RIGHT_BOTTOM) {
// Arrow on right.
return gfx::Rect(
gfx::Point(position_relative_to.x() - border_size.width() +
shadow_padding.right(),
anchor_center_y - arrow_tip_y),
border_size);
}
// No arrow bubble, center align with anchor.
return position_relative_to.Center(border_size);
}
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);
gfx::Rect content_bounds = view.bounds();
content_bounds.Inset(insets);
SkPath path;
// Pads with 0.5 pixel since anti alias is used.
BuildShape(content_bounds,
arrow_location(),
SkIntToScalar(GetArrowOffset()),
SkDoubleToScalar(0.5),
&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(border_size_));
paint.setColor(border_color_);
SkSafeUnref(paint.setLooper(gfx::CreateShadowDrawLooper(shadows_)));
canvas->DrawPath(path, paint);
// Pads with |border_size_| pixels to leave space for border lines.
BuildShape(content_bounds,
arrow_location(),
SkIntToScalar(GetArrowOffset()),
SkIntToScalar(border_size_),
&path,
corner_radius_,
arrow_height_,
arrow_width_);
canvas->Save();
canvas->ClipPath(path);
// Use full bounds so that arrow is also painted.
const gfx::Rect& bounds = view.bounds();
PaintBackground(canvas, bounds);
canvas->Restore();
}
} // namespace views
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_BUBBLE_BUBBLE_BORDER_2_H_
#define UI_VIEWS_BUBBLE_BUBBLE_BORDER_2_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "ui/gfx/shadow_value.h"
#include "ui/views/bubble/bubble_border.h"
namespace views {
// A BubbleBorder rendered with Skia drawing commands instead of images.
class VIEWS_EXPORT BubbleBorder2 : public BubbleBorder {
public:
explicit BubbleBorder2(ArrowLocation arrow_location);
virtual ~BubbleBorder2();
// Given the |bubble_rect| that this border encloses, and the bounds of the
// anchor view |anchor_view_rect|, compute the right offset to place the
// arrow at shifting the |bubble_rect| to fit inside the display area if
// needed. Returns the shifted |bubble_rect|.
gfx::Rect ComputeOffsetAndUpdateBubbleRect(gfx::Rect bubble_rect,
const gfx::Rect& anchor_view_rect);
// Returns the path in |mask| that would be created if this border were to be
// applied to the rect specified by |bounds|.
void GetMask(const gfx::Rect& bounds, gfx::Path* mask) const;
void set_offset(const gfx::Point& offset) { offset_ = offset; }
const gfx::Point& offset() const { return offset_; }
void set_corner_radius(int corner_radius) { corner_radius_ = corner_radius; }
int corner_radius() const { return corner_radius_; }
void set_border_size(int border_size) { border_size_ = border_size; }
int border_size() const { return border_size_; }
void set_arrow_height(int arrow_height) { arrow_height_ = arrow_height; }
int arrow_height() const { return arrow_height_; }
void set_arrow_width(int arrow_width) { arrow_width_ = arrow_width; }
int arrow_width() const { return arrow_width_; }
void SetShadow(gfx::ShadowValue shadow);
// views::BubbleBorder overrides:
int GetBorderThickness() const OVERRIDE;
protected:
void PaintBackground(gfx::Canvas* canvas,
const gfx::Rect& bounds) const;
private:
// Gets arrow offset based on arrow location and |offset_|.
int GetArrowOffset() const;
// views::BubbleBorder overrides:
virtual void GetInsets(gfx::Insets* insets) const OVERRIDE;
virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
const gfx::Size& contents_size) const OVERRIDE;
void GetInsetsForArrowLocation(gfx::Insets* insets,
ArrowLocation arrow_loc) const OVERRIDE;
// views::Border overrides:
virtual void Paint(const View& view,
gfx::Canvas* canvas) const OVERRIDE;
int corner_radius_;
int border_size_;
int arrow_height_;
int arrow_width_;
SkColor background_color_;
SkColor border_color_;
// Offset in pixels by which the arrow is shifted relative the default middle
// position. If the arrow is placed horizontally (at top or bottom), the |x_|
// component of |offset_| specifies the offset, else, the |y_| component.
gfx::Point offset_;
gfx::ShadowValues shadows_;
DISALLOW_COPY_AND_ASSIGN(BubbleBorder2);
};
} // namespace views
#endif // UI_VIEWS_BUBBLE_BUBBLE_BORDER_2_H_
...@@ -230,7 +230,11 @@ void BubbleDelegateView::OnWidgetMoved(Widget* widget) { ...@@ -230,7 +230,11 @@ void BubbleDelegateView::OnWidgetMoved(Widget* widget) {
} }
gfx::Rect BubbleDelegateView::GetAnchorRect() { gfx::Rect BubbleDelegateView::GetAnchorRect() {
return anchor_view() ? anchor_view()->GetBoundsInScreen() : gfx::Rect(); if (!anchor_view())
return gfx::Rect();
gfx::Rect anchor_bounds = anchor_view()->GetBoundsInScreen();
anchor_bounds.Inset(anchor_insets_);
return anchor_bounds;
} }
void BubbleDelegateView::Show() { void BubbleDelegateView::Show() {
......
...@@ -72,6 +72,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, ...@@ -72,6 +72,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
const gfx::Insets& margins() const { return margins_; } const gfx::Insets& margins() const { return margins_; }
void set_margins(const gfx::Insets& margins) { margins_ = margins; } void set_margins(const gfx::Insets& margins) { margins_ = margins; }
void set_anchor_insets(const gfx::Insets& insets) { anchor_insets_ = insets; }
const gfx::Insets& anchor_insets() const { return anchor_insets_; }
gfx::NativeView parent_window() const { return parent_window_; } gfx::NativeView parent_window() const { return parent_window_; }
void set_parent_window(gfx::NativeView window) { parent_window_ = window; } void set_parent_window(gfx::NativeView window) { parent_window_ = window; }
...@@ -157,6 +160,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, ...@@ -157,6 +160,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView,
// The margins between the content and the inside of the border. // The margins between the content and the inside of the border.
gfx::Insets margins_; gfx::Insets margins_;
// Insets applied to the |anchor_view_| bounds.
gfx::Insets anchor_insets_;
// Original opacity of the bubble. // Original opacity of the bubble.
int original_opacity_; int original_opacity_;
......
...@@ -91,6 +91,9 @@ gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect, ...@@ -91,6 +91,9 @@ gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect,
void BubbleFrameView::SetBubbleBorder(BubbleBorder* border) { void BubbleFrameView::SetBubbleBorder(BubbleBorder* border) {
bubble_border_ = border; bubble_border_ = border;
set_border(bubble_border_); set_border(bubble_border_);
// Update the background, which relies on the border.
set_background(new views::BubbleBackground(border));
} }
gfx::Rect BubbleFrameView::GetMonitorBounds(const gfx::Rect& rect) { gfx::Rect BubbleFrameView::GetMonitorBounds(const gfx::Rect& rect) {
......
...@@ -62,6 +62,8 @@ ...@@ -62,6 +62,8 @@
'bubble/bubble_delegate.h', 'bubble/bubble_delegate.h',
'bubble/bubble_frame_view.cc', 'bubble/bubble_frame_view.cc',
'bubble/bubble_frame_view.h', 'bubble/bubble_frame_view.h',
'bubble/bubble_border_2.cc',
'bubble/bubble_border_2.h',
'button_drag_utils.cc', 'button_drag_utils.cc',
'button_drag_utils.h', 'button_drag_utils.h',
'color_chooser/color_chooser_listener.h', 'color_chooser/color_chooser_listener.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment