#include "ui/gfx/path.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
+#include "ui/native_theme/native_theme.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/widget/widget.h"
const int kTitleLeftInset = 19;
const int kTitleBottomInset = 12;
-// Get the |vertical| or horizontal screen overflow of the |window_bounds|.
-int GetOffScreenLength(const gfx::Rect& monitor_bounds,
+// Get the |vertical| or horizontal amount that |available_bounds| overflows
+// |window_bounds|.
+int GetOffScreenLength(const gfx::Rect& available_bounds,
const gfx::Rect& window_bounds,
bool vertical) {
- if (monitor_bounds.IsEmpty() || monitor_bounds.Contains(window_bounds))
+ if (available_bounds.IsEmpty() || available_bounds.Contains(window_bounds))
return 0;
// window_bounds
- // +-------------------------------+
- // | top |
- // | +----------------+ |
- // | left | monitor_bounds | right |
- // | +----------------+ |
- // | bottom |
- // +-------------------------------+
+ // +---------------------------------+
+ // | top |
+ // | +------------------+ |
+ // | left | available_bounds | right |
+ // | +------------------+ |
+ // | bottom |
+ // +---------------------------------+
if (vertical)
- return std::max(0, monitor_bounds.y() - window_bounds.y()) +
- std::max(0, window_bounds.bottom() - monitor_bounds.bottom());
- return std::max(0, monitor_bounds.x() - window_bounds.x()) +
- std::max(0, window_bounds.right() - monitor_bounds.right());
+ return std::max(0, available_bounds.y() - window_bounds.y()) +
+ std::max(0, window_bounds.bottom() - available_bounds.bottom());
+ return std::max(0, available_bounds.x() - window_bounds.x()) +
+ std::max(0, window_bounds.right() - available_bounds.right());
}
} // namespace
close_(NULL),
titlebar_extra_view_(NULL) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- title_ = new Label(string16(), rb.GetFont(ui::ResourceBundle::MediumFont));
+ title_ = new Label(base::string16(),
+ rb.GetFontList(ui::ResourceBundle::MediumFont));
title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
AddChildView(title_);
- close_ = new LabelButton(this, string16());
+ close_ = new LabelButton(this, base::string16());
close_->SetImage(CustomButton::STATE_NORMAL,
*rb.GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
close_->SetImage(CustomButton::STATE_HOVERED,
close_->SetImage(CustomButton::STATE_PRESSED,
*rb.GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
close_->SetSize(close_->GetPreferredSize());
- close_->set_border(NULL);
+ close_->SetBorder(scoped_ptr<Border>());
close_->SetVisible(false);
AddChildView(close_);
}
void BubbleFrameView::UpdateWindowTitle() {
title_->SetText(GetWidget()->widget_delegate()->ShouldShowWindowTitle() ?
- GetWidget()->widget_delegate()->GetWindowTitle() : string16());
+ GetWidget()->widget_delegate()->GetWindowTitle() : base::string16());
// Update the close button visibility too, otherwise it's not intialized.
ResetWindowControls();
}
}
void BubbleFrameView::Layout() {
- gfx::Rect bounds(GetLocalBounds());
- bounds.Inset(border()->GetInsets());
+ gfx::Rect bounds(GetContentsBounds());
+ if (bounds.IsEmpty())
+ return;
+
// Small additional insets yield the desired 10px visual close button insets.
bounds.Inset(0, 0, close_->width() + 1, 0);
close_->SetPosition(gfx::Point(bounds.right(), bounds.y() + 2));
UpdateWindowIcon();
}
+void BubbleFrameView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ if (bubble_border_ && bubble_border_->use_theme_background_color()) {
+ bubble_border_->set_background_color(GetNativeTheme()->
+ GetSystemColor(ui::NativeTheme::kColorId_DialogBackground));
+ SchedulePaint();
+ }
+}
+
void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == close_)
GetWidget()->Close();
}
-void BubbleFrameView::SetBubbleBorder(BubbleBorder* border) {
- bubble_border_ = border;
- set_border(bubble_border_);
+void BubbleFrameView::SetBubbleBorder(scoped_ptr<BubbleBorder> border) {
+ bubble_border_ = border.get();
+ SetBorder(border.PassAs<Border>());
// Update the background, which relies on the border.
- set_background(new views::BubbleBackground(border));
+ set_background(new views::BubbleBackground(bubble_border_));
}
void BubbleFrameView::SetTitlebarExtraView(View* view) {
gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect,
gfx::Size client_size,
bool adjust_if_offscreen) {
- gfx::Insets insets(GetInsets());
- client_size.Enlarge(insets.width(), insets.height());
+ gfx::Size size(GetSizeForClientSize(client_size));
const BubbleBorder::Arrow arrow = bubble_border_->arrow();
if (adjust_if_offscreen && BubbleBorder::has_arrow(arrow)) {
+ // Try to mirror the anchoring if the bubble does not fit on the screen.
if (!bubble_border_->is_arrow_at_center(arrow)) {
- // Try to mirror the anchoring if the bubble does not fit on the screen.
- MirrorArrowIfOffScreen(true, anchor_rect, client_size);
- MirrorArrowIfOffScreen(false, anchor_rect, client_size);
+ MirrorArrowIfOffScreen(true, anchor_rect, size);
+ MirrorArrowIfOffScreen(false, anchor_rect, size);
} else {
- // Mirror as needed vertically if the arrow is on a horizontal edge and
- // vice-versa.
- MirrorArrowIfOffScreen(BubbleBorder::is_arrow_on_horizontal(arrow),
- anchor_rect,
- client_size);
- OffsetArrowIfOffScreen(anchor_rect, client_size);
+ const bool mirror_vertical = BubbleBorder::is_arrow_on_horizontal(arrow);
+ MirrorArrowIfOffScreen(mirror_vertical, anchor_rect, size);
+ OffsetArrowIfOffScreen(anchor_rect, size);
}
}
// Calculate the bounds with the arrow in its updated location and offset.
- return bubble_border_->GetBounds(anchor_rect, client_size);
+ return bubble_border_->GetBounds(anchor_rect, size);
}
-gfx::Rect BubbleFrameView::GetMonitorBounds(const gfx::Rect& rect) {
+gfx::Rect BubbleFrameView::GetAvailableScreenBounds(const gfx::Rect& rect) {
+ // The bubble attempts to fit within the current screen bounds.
// TODO(scottmg): Native is wrong. http://crbug.com/133312
return gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(
rect.CenterPoint()).work_area();
const gfx::Rect& anchor_rect,
const gfx::Size& client_size) {
// Check if the bounds don't fit on screen.
- gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect));
+ gfx::Rect available_bounds(GetAvailableScreenBounds(anchor_rect));
gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size));
- if (GetOffScreenLength(monitor_rect, window_bounds, vertical) > 0) {
+ if (GetOffScreenLength(available_bounds, window_bounds, vertical) > 0) {
BubbleBorder::Arrow arrow = bubble_border()->arrow();
// Mirror the arrow and get the new bounds.
bubble_border_->set_arrow(
gfx::Rect mirror_bounds =
bubble_border_->GetBounds(anchor_rect, client_size);
// Restore the original arrow if mirroring doesn't show more of the bubble.
- if (GetOffScreenLength(monitor_rect, mirror_bounds, vertical) >=
- GetOffScreenLength(monitor_rect, window_bounds, vertical))
+ // Otherwise it should invoke parent's Layout() to layout the content based
+ // on the new bubble border.
+ if (GetOffScreenLength(available_bounds, mirror_bounds, vertical) >=
+ GetOffScreenLength(available_bounds, window_bounds, vertical))
bubble_border_->set_arrow(arrow);
- else
- SchedulePaint();
+ else if (parent())
+ parent()->Layout();
}
}
bubble_border_->set_arrow_offset(0);
gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size));
- gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect));
- if (monitor_rect.IsEmpty() || monitor_rect.Contains(window_bounds))
+ gfx::Rect available_bounds(GetAvailableScreenBounds(anchor_rect));
+ if (available_bounds.IsEmpty() || available_bounds.Contains(window_bounds))
return;
// Calculate off-screen adjustment.
const bool is_horizontal = BubbleBorder::is_arrow_on_horizontal(arrow);
int offscreen_adjust = 0;
if (is_horizontal) {
- if (window_bounds.x() < monitor_rect.x())
- offscreen_adjust = monitor_rect.x() - window_bounds.x();
- else if (window_bounds.right() > monitor_rect.right())
- offscreen_adjust = monitor_rect.right() - window_bounds.right();
+ if (window_bounds.x() < available_bounds.x())
+ offscreen_adjust = available_bounds.x() - window_bounds.x();
+ else if (window_bounds.right() > available_bounds.right())
+ offscreen_adjust = available_bounds.right() - window_bounds.right();
} else {
- if (window_bounds.y() < monitor_rect.y())
- offscreen_adjust = monitor_rect.y() - window_bounds.y();
- else if (window_bounds.bottom() > monitor_rect.bottom())
- offscreen_adjust = monitor_rect.bottom() - window_bounds.bottom();
+ if (window_bounds.y() < available_bounds.y())
+ offscreen_adjust = available_bounds.y() - window_bounds.y();
+ else if (window_bounds.bottom() > available_bounds.bottom())
+ offscreen_adjust = available_bounds.bottom() - window_bounds.bottom();
}
// For center arrows, arrows are moved in the opposite direction of
}
gfx::Size BubbleFrameView::GetSizeForClientSize(const gfx::Size& client_size) {
- gfx::Size size(
- GetUpdatedWindowBounds(gfx::Rect(), client_size, false).size());
// Accommodate the width of the title bar elements.
int title_bar_width = GetInsets().width() + border()->GetInsets().width();
if (!title_->text().empty())
title_bar_width += close_->width() + 1;
if (titlebar_extra_view_ != NULL)
title_bar_width += titlebar_extra_view_->GetPreferredSize().width();
+ gfx::Size size(client_size);
size.SetToMax(gfx::Size(title_bar_width, 0));
+ const gfx::Insets insets(GetInsets());
+ size.Enlarge(insets.width(), insets.height());
return size;
}