Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Unified Diff: chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.cc

Issue 9580001: Aura: Update window frames, allow resize from outside window (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix caption for maximized windows, new resize cursor tweak Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.cc
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.cc
index b44cba650fe1996c94ddb147a4f2ac8b52d8f522..f47526ccd6bb5a1521c0aeaeea7208958035149a 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_aura.cc
@@ -6,377 +6,161 @@
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h" // Accessibility names
+#include "grit/theme_resources.h"
+#include "grit/theme_resources_standard.h"
#include "grit/ui_resources.h"
#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
-#include "ui/aura/cursor.h"
-#include "ui/base/animation/throb_animation.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkShader.h"
+#include "ui/aura/window.h"
+#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/theme_provider.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/compositor/layer.h"
-#include "ui/views/controls/button/custom_button.h"
+#include "ui/gfx/font.h"
+#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace {
-// Our window is larger than it appears, as it includes space around the edges
-// where resize handles can appear.
-const int kResizeBorderThickness = 8;
-// The top edge is a little thinner, as it is not draggable for resize.
-const int kTopBorderThickness = 4;
-// Offset between top of non-client frame and top edge of opaque frame
-// background at start of slide-in animation.
-const int kFrameBackgroundTopOffset = 25;
-
-// Width of a persistent border that we show around the window (using
-// FrameBackground) even when the resize border isn't visible.
-const int kPersistentBorderThickness = 2;
-
-// The color used to fill the frame. Opacity is handled in the layer.
-const SkColor kFrameColor = SK_ColorBLACK;
-// Radius of rounded rectangle corners.
-const int kRoundedRectRadius = 3;
-// Frame border fades in over this range of opacity.
-const double kFrameBorderStartOpacity = 0.2;
-const double kFrameBorderEndOpacity = 0.3;
-// How long the hover animation takes if uninterrupted.
-const int kHoverFadeDurationMs = 250;
-
-// Color shown when window control is hovered.
-const SkColor kMaximizeButtonBackgroundColor = SkColorSetRGB(0, 255, 0);
-const SkColor kCloseButtonBackgroundColor = SkColorSetRGB(255, 0, 0);
-
-bool HitVisibleView(views::View* view, gfx::Point point) {
- return view->visible() && view->GetMirroredBounds().Contains(point);
+
+// Size of border along top edge, used for resize handle computations.
+const int kTopThickness = 1;
+// TODO(jamescook): Border is specified to be a single pixel overlapping
+// the web content and may need to be built into the shadow layers instead.
+const int kBorderThickness = 0;
+// Number of pixels outside the window frame to look for resize events.
+const int kResizeAreaOutsideBounds = 6;
+// In the window corners, the resize areas don't actually expand bigger, but the
+// 16 px at the end of each edge triggers diagonal resizing.
+const int kResizeAreaCornerSize = 16;
+// Space between left edge of window and popup window icon.
+const int kIconOffsetX = 4;
+// Space between top of window and popup window icon.
+const int kIconOffsetY = 4;
+// Height and width of window icon.
+const int kIconSize = 16;
+// Space between the title text and the caption buttons.
+const int kTitleLogoSpacing = 5;
+// Space between title text and icon.
+const int kTitleOffsetX = 4;
+// Space between title text and top of window.
+const int kTitleOffsetY = 6;
+// Space between close button and right edge of window.
+const int kCloseButtonOffsetX = 0;
+// Space between close button and top edge of window.
+const int kCloseButtonOffsetY = 0;
+// Space between left edge of window and tabstrip.
+const int kTabstripLeftSpacing = 4;
+// Space between right edge of tabstrip and maximize button.
+const int kTabstripRightSpacing = 10;
+// Space between top of window and top of tabstrip for restored windows.
+const int kTabstripTopSpacingRestored = 10;
+// Space between top of window and top of tabstrip for maximized windows.
+const int kTabstripTopSpacingMaximized = 1;
+
+// Tiles an image into an area, rounding the top corners.
+void TileRoundRect(gfx::Canvas* canvas,
+ int x, int y, int w, int h,
+ const SkBitmap& bitmap,
+ int corner_radius) {
+ SkRect rect;
+ rect.iset(x, y, x + w, y + h);
+ const SkScalar kRadius = SkIntToScalar(corner_radius);
+ SkScalar radii[8] = {
+ kRadius, kRadius, // top-left
+ kRadius, kRadius, // top-right
+ 0, 0, // bottom-right
+ 0, 0}; // bottom-left
+ SkPath path;
+ path.addRoundRect(rect, radii, SkPath::kCW_Direction);
+
+ SkPaint paint;
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint.setShader(shader);
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ // CreateBitmapShader returns a Shader with a reference count of one, we
+ // need to unref after paint takes ownership of the shader.
+ shader->unref();
+ canvas->GetSkCanvas()->drawPath(path, paint);
}
} // namespace
-// Buttons for window controls - close, zoom, etc.
-// Note that views::CustomButton is already a ui::AnimationDelegate.
-class WindowControlButton : public views::CustomButton {
- public:
- WindowControlButton(BrowserNonClientFrameViewAura* owner,
- SkColor color,
- const SkBitmap& icon)
- : views::CustomButton(owner),
- owner_(owner),
- color_(color),
- icon_(icon),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- show_animation_(new ui::SlideAnimation(this))) {
- show_animation_->SetSlideDuration(kHoverFadeDurationMs);
- SetPaintToLayer(true);
- layer()->SetFillsBoundsOpaquely(false);
- layer()->SetOpacity(0.f);
- }
- virtual ~WindowControlButton() {}
-
- void Show() {
- show_animation_->Show();
- }
- void Hide() {
- show_animation_->Hide();
- }
-
- // Overridden from views::View:
- virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE {
- // Ensure the caption/frame background shows when we hover this button.
- owner_->ShowFrameBackground();
- views::CustomButton::OnMouseEntered(event);
- }
- virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE {
- owner_->HideFrameBackground();
- views::CustomButton::OnMouseExited(event);
- }
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- canvas->FillRect(GetLocalBounds(), GetBackgroundColor());
- canvas->DrawBitmapInt(icon_, 0, 0);
- }
- virtual gfx::Size GetPreferredSize() OVERRIDE {
- return gfx::Size(icon_.width(), icon_.height());
- }
-
- // Overridden from ui::AnimationDelegate:
- virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
- if (animation == show_animation_.get()) {
- double opacity = show_animation_->GetCurrentValue();
- layer()->SetOpacity(static_cast<float>(opacity));
- return;
- }
- views::CustomButton::AnimationProgressed(animation);
- }
-
- private:
- SkColor GetBackgroundColor() {
- // Background animates in separately, so handle opacity manually.
- return SkColorSetARGB(hover_animation_->CurrentValueBetween(0, 150),
- SkColorGetR(color_),
- SkColorGetG(color_),
- SkColorGetB(color_));
- }
-
- BrowserNonClientFrameViewAura* owner_;
- SkColor color_;
- SkBitmap icon_;
- scoped_ptr<ui::SlideAnimation> show_animation_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowControlButton);
-};
-
-// Layer that visually sits "behind" the window contents and expands out to
-// provide visual resize handles on the sides. Hit testing and resize handling
-// is in the parent NonClientFrameView.
-class FrameBackgroundView : public views::View,
- public ui::AnimationDelegate {
- public:
- FrameBackgroundView()
- : ALLOW_THIS_IN_INITIALIZER_LIST(
- size_animation_(new ui::SlideAnimation(this))),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- color_animation_(new ui::SlideAnimation(this))) {
- size_animation_->SetSlideDuration(kHoverFadeDurationMs);
- color_animation_->SetSlideDuration(kHoverFadeDurationMs);
- SetPaintToLayer(true);
- UpdateOpacity();
- }
- virtual ~FrameBackgroundView() {
- }
-
- void Configure(const gfx::Rect& start_bounds, const gfx::Rect& end_bounds) {
- start_bounds_ = start_bounds;
- end_bounds_ = end_bounds;
- UpdateBounds();
- }
- void SetEndBounds(const gfx::Rect& end_bounds) {
- end_bounds_ = end_bounds;
- UpdateBounds();
- }
- void Show() {
- size_animation_->Show();
- color_animation_->Show();
- }
- void Hide() {
- size_animation_->Hide();
- color_animation_->Hide();
- }
-
- protected:
- // Overridden from views::View:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
- SkRect rect = { SkIntToScalar(0), SkIntToScalar(0),
- SkIntToScalar(width()), SkIntToScalar(height()) };
- SkScalar radius = SkIntToScalar(kRoundedRectRadius);
- SkPaint paint;
- // Animation handles setting the opacity for the whole layer.
- paint.setColor(kFrameColor);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->GetSkCanvas()->drawRoundRect(rect, radius, radius, paint);
- }
-
- // Overridden from ui::AnimationDelegate:
- virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE {
- if (animation == color_animation_.get()) {
- UpdateOpacity();
- } else if (animation == size_animation_.get()) {
- UpdateBounds();
- }
- }
-
- private:
- void UpdateOpacity() {
- double opacity = color_animation_->CurrentValueBetween(
- kFrameBorderStartOpacity, kFrameBorderEndOpacity);
- layer()->SetOpacity(static_cast<float>(opacity));
- }
-
- void UpdateBounds() {
- gfx::Rect current_bounds =
- size_animation_->CurrentValueBetween(start_bounds_, end_bounds_);
- SetBoundsRect(current_bounds);
- SchedulePaint();
- }
-
- scoped_ptr<ui::SlideAnimation> size_animation_;
- scoped_ptr<ui::SlideAnimation> color_animation_;
- // Default "hidden" rectangle.
- gfx::Rect default_bounds_;
- // When moving mouse from one target to another (e.g. from edge to corner)
- // the size animation start point may not be the default size.
- gfx::Rect start_bounds_;
- // Expanded bounds, with edges visible from behind the client area.
- gfx::Rect end_bounds_;
-
- DISALLOW_COPY_AND_ASSIGN(FrameBackgroundView);
-};
-
///////////////////////////////////////////////////////////////////////////////
// BrowserNonClientFrameViewAura, public:
BrowserNonClientFrameViewAura::BrowserNonClientFrameViewAura(
BrowserFrame* frame, BrowserView* browser_view)
: BrowserNonClientFrameView(frame, browser_view),
- last_hittest_code_(HTNOWHERE) {
- frame_background_ = new FrameBackgroundView();
- AddChildView(frame_background_);
-
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- maximize_button_ =
- new WindowControlButton(this,
- kMaximizeButtonBackgroundColor,
- *rb.GetBitmapNamed(IDR_AURA_WINDOW_ZOOM_ICON));
+ maximize_button_(NULL),
+ close_button_(NULL),
+ window_icon_(NULL),
+ button_separator_(NULL),
+ top_left_corner_(NULL),
+ top_edge_(NULL),
+ top_right_corner_(NULL),
+ header_left_edge_(NULL),
+ header_right_edge_(NULL) {
+}
+
+BrowserNonClientFrameViewAura::~BrowserNonClientFrameViewAura() {
+}
+
+void BrowserNonClientFrameViewAura::Init() {
+ // Ensure we get resize cursors for a few pixels outside our bounds.
+ frame()->GetNativeWindow()->set_hit_test_bounds_inset(
+ -kResizeAreaOutsideBounds);
+
+ // Caption buttons.
+ maximize_button_ = new views::ImageButton(this);
+ SetButtonImages(maximize_button_,
+ IDR_AURA_WINDOW_MAXIMIZE,
+ IDR_AURA_WINDOW_MAXIMIZE_H,
+ IDR_AURA_WINDOW_MAXIMIZE_P);
maximize_button_->SetAccessibleName(
l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE));
AddChildView(maximize_button_);
-
- close_button_ =
- new WindowControlButton(this,
- kCloseButtonBackgroundColor,
- *rb.GetBitmapNamed(IDR_AURA_WINDOW_CLOSE_ICON));
+ close_button_ = new views::ImageButton(this);
+ SetButtonImages(close_button_,
+ IDR_AURA_WINDOW_CLOSE,
+ IDR_AURA_WINDOW_CLOSE_H,
+ IDR_AURA_WINDOW_CLOSE_P);
close_button_->SetAccessibleName(
l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
AddChildView(close_button_);
- // The BrowserFrame will become our owning window/widget.
- frame->AsWidget()->AddObserver(this);
- // Associate our WindowFrame interface with our owning window/widget so
- // we get callbacks from aura_shell.
- frame->AsWidget()->GetNativeWindow()->SetProperty(
- ash::kWindowFrameKey,
- static_cast<ash::WindowFrame*>(this));
-}
-
-BrowserNonClientFrameViewAura::~BrowserNonClientFrameViewAura() {
- // Don't need to remove the Widget observer, the window is deleted before us.
-}
-
-void BrowserNonClientFrameViewAura::ShowFrameBackground() {
- UpdateFrameBackground(ShouldPaintAsActive());
- frame_background_->Show();
-}
-
-void BrowserNonClientFrameViewAura::HideFrameBackground() {
- frame_background_->Hide();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BrowserNonClientFrameViewAura, private:
-
-int BrowserNonClientFrameViewAura::NonClientHitTestImpl(
- const gfx::Point& point) {
- if (!GetLocalBounds().Contains(point))
- return HTNOWHERE;
-
- // Window controls get first try because they overlap the client area.
- if (HitVisibleView(maximize_button_, point))
- return HTMAXBUTTON;
- if (HitVisibleView(close_button_, point))
- return HTCLOSE;
-
- int frame_component = GetWidget()->client_view()->NonClientHitTest(point);
- if (frame_component != HTNOWHERE)
- return frame_component;
-
- // Test window resize components.
- bool can_resize = GetWidget()->widget_delegate()->CanResize();
- // TODO(derat): Disallow resizing via the top border in the Aura shell
- // instead of enforcing it here. See http://crbug.com/101830.
- frame_component = GetHTComponentForFrame(point,
- 0,
- kResizeBorderThickness,
- kResizeBorderThickness,
- kResizeBorderThickness,
- can_resize);
- if (frame_component != HTNOWHERE)
- return frame_component;
- // Use HTCAPTION as a final fallback.
- return HTCAPTION;
-}
-
-// Pass |active_window| explicitly because deactivating a window causes
-// OnWidgetActivationChanged() to be called before GetWidget()->IsActive()
-// changes state.
-gfx::Rect BrowserNonClientFrameViewAura::GetFrameBackgroundBounds(
- int hittest_code,
- bool active_window) {
- bool show_left = false;
- bool show_top = false;
- bool show_right = false;
- bool show_bottom = false;
- switch (hittest_code) {
- case HTBOTTOM:
- show_bottom = true;
- break;
- case HTBOTTOMLEFT:
- show_bottom = true;
- show_left = true;
- break;
- case HTBOTTOMRIGHT:
- show_bottom = true;
- show_right = true;
- break;
- case HTCAPTION:
- show_top = true;
- break;
- case HTCLOSE:
- show_top = true;
- break;
- case HTLEFT:
- show_left = true;
- break;
- case HTMAXBUTTON:
- show_top = true;
- break;
- case HTRIGHT:
- show_right = true;
- break;
- case HTTOP:
- show_top = true;
- break;
- case HTTOPLEFT:
- show_top = true;
- show_left = true;
- break;
- case HTTOPRIGHT:
- show_top = true;
- show_right = true;
- break;
- default:
- break;
+ // Window frame image parts.
+ ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
+ button_separator_ =
+ bundle.GetBitmapNamed(IDR_AURA_WINDOW_BUTTON_SEPARATOR);
+ top_left_corner_ =
+ bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_TOP_LEFT);
+ top_edge_ =
+ bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_TOP);
+ top_right_corner_ =
+ bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_TOP_RIGHT);
+ header_left_edge_ =
+ bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_LEFT);
+ header_right_edge_ =
+ bundle.GetBitmapNamed(IDR_AURA_WINDOW_HEADER_SHADE_RIGHT);
+ // TODO(jamescook): Should we paint the header bottom edge here, or keep
+ // it in BrowserFrameAura::ToolbarBackground as we do now?
+
+ // Initializing the TabIconView is expensive, so only do it if we need to.
+ if (browser_view()->ShouldShowWindowIcon()) {
+ window_icon_ = new TabIconView(this);
+ window_icon_->set_is_light(true);
+ AddChildView(window_icon_);
+ window_icon_->Update();
}
- // Always show top edge for the active window so that you can tell which
- // window has focus.
- if (active_window)
- show_top = true;
- gfx::Rect target = bounds();
- // Inset the sides that are not showing.
- target.Inset(
- (show_left ? 0 : kResizeBorderThickness - kPersistentBorderThickness),
- (show_top ? 0 : kTopBorderThickness + kFrameBackgroundTopOffset),
- (show_right ? 0 : kResizeBorderThickness - kPersistentBorderThickness),
- (show_bottom ? 0 : kResizeBorderThickness - kPersistentBorderThickness));
- return target;
-}
-
-void BrowserNonClientFrameViewAura::UpdateFrameBackground(bool active_window) {
- gfx::Rect start_bounds = GetFrameBackgroundBounds(HTNOWHERE, active_window);
- gfx::Rect end_bounds =
- GetFrameBackgroundBounds(last_hittest_code_, active_window);
- frame_background_->Configure(start_bounds, end_bounds);
-}
-
-void BrowserNonClientFrameViewAura::ActiveStateChanged() {
- bool active = ShouldPaintAsActive();
- // Active windows have different background bounds.
- UpdateFrameBackground(active);
- if (active)
- frame_background_->Show();
- else
- frame_background_->Hide();
}
///////////////////////////////////////////////////////////////////////////////
@@ -386,56 +170,83 @@ gfx::Rect BrowserNonClientFrameViewAura::GetBoundsForTabStrip(
views::View* tabstrip) const {
if (!tabstrip)
return gfx::Rect();
- // TODO(jamescook): Avatar icon support.
- // Reserve space on the right for close/maximize buttons.
- int tabstrip_x = kResizeBorderThickness;
- int tabstrip_width = maximize_button_->x() - tabstrip_x;
- return gfx::Rect(tabstrip_x,
- GetHorizontalTabStripVerticalOffset(false),
- tabstrip_width,
+ bool restored = !frame()->IsMaximized();
+ return gfx::Rect(kTabstripLeftSpacing,
+ GetHorizontalTabStripVerticalOffset(restored),
+ maximize_button_->x() - kTabstripRightSpacing,
tabstrip->GetPreferredSize().height());
-
}
int BrowserNonClientFrameViewAura::GetHorizontalTabStripVerticalOffset(
bool restored) const {
- return kTopBorderThickness;
+ return NonClientTopBorderHeight(restored);
}
void BrowserNonClientFrameViewAura::UpdateThrobber(bool running) {
- // TODO(jamescook): Do we need this?
+ if (window_icon_)
+ window_icon_->Update();
}
///////////////////////////////////////////////////////////////////////////////
// views::NonClientFrameView overrides:
gfx::Rect BrowserNonClientFrameViewAura::GetBoundsForClientView() const {
- gfx::Rect bounds = GetLocalBounds();
- bounds.Inset(kResizeBorderThickness,
- kTopBorderThickness,
- kResizeBorderThickness,
- kResizeBorderThickness);
- return bounds;
+ int top_height = NonClientTopBorderHeight(false);
+ return gfx::Rect(kBorderThickness,
+ top_height,
+ std::max(0, width() - (2 * kBorderThickness)),
+ std::max(0, height() - top_height - kBorderThickness));
}
gfx::Rect BrowserNonClientFrameViewAura::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const {
- gfx::Rect bounds = client_bounds;
- bounds.Inset(-kResizeBorderThickness,
- -kTopBorderThickness,
- -kResizeBorderThickness,
- -kResizeBorderThickness);
- return bounds;
+ int top_height = NonClientTopBorderHeight(false);
+ return gfx::Rect(std::max(0, client_bounds.x() - kBorderThickness),
+ std::max(0, client_bounds.y() - top_height),
+ client_bounds.width() + (2 * kBorderThickness),
+ client_bounds.height() + top_height + kBorderThickness);
}
int BrowserNonClientFrameViewAura::NonClientHitTest(const gfx::Point& point) {
- last_hittest_code_ = NonClientHitTestImpl(point);
- return last_hittest_code_;
+ gfx::Rect expanded_bounds = bounds();
+ expanded_bounds.Inset(-kResizeAreaOutsideBounds, -kResizeAreaOutsideBounds);
+ if (!expanded_bounds.Contains(point))
+ return HTNOWHERE;
+
+ // No avatar button for Chrome OS.
+
+ // Check the client view first, as it overlaps the window caption area.
+ int client_component = frame()->client_view()->NonClientHitTest(point);
+ if (client_component != HTNOWHERE)
+ return client_component;
+
+ // Then see if the point is within any of the window controls.
+ if (close_button_->visible() &&
+ close_button_->GetMirroredBounds().Contains(point))
+ return HTCLOSE;
+ if (maximize_button_->visible() &&
+ maximize_button_->GetMirroredBounds().Contains(point))
+ return HTMAXBUTTON;
+
+ bool can_resize = frame()->widget_delegate() ?
+ frame()->widget_delegate()->CanResize() :
+ false;
+ int frame_component = GetHTComponentForFrame(point,
+ kTopThickness,
+ kBorderThickness,
+ kResizeAreaCornerSize,
+ kResizeAreaCornerSize,
+ can_resize);
+ if (frame_component != HTNOWHERE)
+ return frame_component;
+
+ // Caption is a safe default.
+ return HTCAPTION;
}
void BrowserNonClientFrameViewAura::GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) {
- // Nothing.
+ // Aura does not use window masks.
}
void BrowserNonClientFrameViewAura::ResetWindowControls() {
@@ -444,104 +255,92 @@ void BrowserNonClientFrameViewAura::ResetWindowControls() {
}
void BrowserNonClientFrameViewAura::UpdateWindowIcon() {
- // TODO(jamescook): We will need this for app frames.
-}
-
-void BrowserNonClientFrameViewAura::ShouldPaintAsActiveChanged() {
- ActiveStateChanged();
+ if (window_icon_)
+ window_icon_->SchedulePaint();
}
///////////////////////////////////////////////////////////////////////////////
// views::View overrides:
-void BrowserNonClientFrameViewAura::Layout() {
- // Layout window buttons from right to left.
- int right = width() - kResizeBorderThickness;
- gfx::Size preferred = close_button_->GetPreferredSize();
- close_button_->SetBounds(right - preferred.width(), kTopBorderThickness,
- preferred.width(), preferred.height());
- right -= preferred.width(); // No padding.
- preferred = maximize_button_->GetPreferredSize();
- maximize_button_->SetBounds(right - preferred.width(), kTopBorderThickness,
- preferred.width(), preferred.height());
- UpdateFrameBackground(ShouldPaintAsActive());
+void BrowserNonClientFrameViewAura::OnPaint(gfx::Canvas* canvas) {
+ if (frame()->IsFullscreen())
+ return; // Nothing visible, don't paint.
+ PaintHeader(canvas);
+ PaintTitleBar(canvas);
+ // Paint the view hierarchy, which draws the caption buttons.
+ BrowserNonClientFrameView::OnPaint(canvas);
}
-views::View* BrowserNonClientFrameViewAura::GetEventHandlerForPoint(
- const gfx::Point& point) {
- // Mouse hovers near the resizing edges result in the animation starting and
- // stopping as the frame background changes size. Just ignore events
- // destined for the frame background and handle them at this level.
- views::View* view = View::GetEventHandlerForPoint(point);
- if (view == frame_background_)
- return this;
- return view;
+void BrowserNonClientFrameViewAura::Layout() {
+ // Maximized windows and app/popup windows use shorter buttons.
+ if (frame()->IsMaximized() ||
+ !browser_view()->IsBrowserTypeNormal()) {
+ SetButtonImages(close_button_,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H,
+ IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P);
+ SetButtonImages(maximize_button_,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H,
+ IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P);
+ } else {
+ SetButtonImages(close_button_,
+ IDR_AURA_WINDOW_CLOSE,
+ IDR_AURA_WINDOW_CLOSE_H,
+ IDR_AURA_WINDOW_CLOSE_P);
+ SetButtonImages(maximize_button_,
+ IDR_AURA_WINDOW_MAXIMIZE,
+ IDR_AURA_WINDOW_MAXIMIZE_H,
+ IDR_AURA_WINDOW_MAXIMIZE_P);
+ }
+
+ gfx::Size close_size = close_button_->GetPreferredSize();
+ close_button_->SetBounds(
+ width() - close_size.width() - kCloseButtonOffsetX,
+ kCloseButtonOffsetY,
+ close_size.width(),
+ close_size.height());
+
+ gfx::Size maximize_size = maximize_button_->GetPreferredSize();
+ maximize_button_->SetBounds(
+ close_button_->x() - button_separator_->width() - maximize_size.width(),
+ close_button_->y(),
+ maximize_size.width(),
+ maximize_size.height());
+
+ if (window_icon_)
+ window_icon_->SetBoundsRect(
+ gfx::Rect(kIconOffsetX, kIconOffsetY, kIconSize, kIconSize));
+
+ BrowserNonClientFrameView::Layout();
}
-bool BrowserNonClientFrameViewAura::HitTest(const gfx::Point& p) const {
- // Claim all events outside the client area.
- bool in_client = GetWidget()->client_view()->bounds().Contains(p);
- if (!in_client)
- return true;
- // Window controls overlap the client area, so explicitly check for points
- // inside of them.
- if (close_button_->bounds().Contains(p) ||
- maximize_button_->bounds().Contains(p))
+bool BrowserNonClientFrameViewAura::HitTest(const gfx::Point& l) const {
+ // If the point is outside the bounds of the client area, claim it.
+ if (NonClientFrameView::HitTest(l))
return true;
+
// Otherwise claim it only if it's in a non-tab portion of the tabstrip.
if (!browser_view()->tabstrip())
return false;
gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
gfx::Point tabstrip_origin(tabstrip_bounds.origin());
- View::ConvertPointToView(
- frame()->client_view(), this, &tabstrip_origin);
+ View::ConvertPointToView(frame()->client_view(), this, &tabstrip_origin);
tabstrip_bounds.set_origin(tabstrip_origin);
- if (p.y() > tabstrip_bounds.bottom())
+ if (l.y() > tabstrip_bounds.bottom())
return false;
// We convert from our parent's coordinates since we assume we fill its bounds
// completely. We need to do this since we're not a parent of the tabstrip,
// meaning ConvertPointToView would otherwise return something bogus.
- gfx::Point browser_view_point(p);
+ gfx::Point browser_view_point(l);
View::ConvertPointToView(parent(), browser_view(), &browser_view_point);
return browser_view()->IsPositionInWindowCaption(browser_view_point);
}
-void BrowserNonClientFrameViewAura::OnMouseMoved(
- const views::MouseEvent& event) {
- // We may be hovering over the resize edge.
- ShowFrameBackground();
-}
-
-void BrowserNonClientFrameViewAura::OnMouseExited(
- const views::MouseEvent& event) {
- // We hovered away from the resize edge.
- HideFrameBackground();
-}
-
-gfx::NativeCursor BrowserNonClientFrameViewAura::GetCursor(
- const views::MouseEvent& event) {
- switch (last_hittest_code_) {
- case HTBOTTOM:
- return aura::kCursorSouthResize;
- case HTBOTTOMLEFT:
- return aura::kCursorSouthWestResize;
- case HTBOTTOMRIGHT:
- return aura::kCursorSouthEastResize;
- case HTLEFT:
- return aura::kCursorWestResize;
- case HTRIGHT:
- return aura::kCursorEastResize;
- case HTTOP:
- // Resizing from the top edge is not allowed.
- return aura::kCursorNull;
- case HTTOPLEFT:
- return aura::kCursorWestResize;
- case HTTOPRIGHT:
- return aura::kCursorEastResize;
- default:
- return aura::kCursorNull;
- }
+void BrowserNonClientFrameViewAura::GetAccessibleState(
+ ui::AccessibleViewState* state) {
+ state->role = ui::AccessibilityTypes::ROLE_TITLEBAR;
}
///////////////////////////////////////////////////////////////////////////////
@@ -549,34 +348,191 @@ gfx::NativeCursor BrowserNonClientFrameViewAura::GetCursor(
void BrowserNonClientFrameViewAura::ButtonPressed(views::Button* sender,
const views::Event& event) {
- if (sender == close_button_) {
- frame()->Close();
- } else if (sender == maximize_button_) {
+ if (sender == maximize_button_) {
if (frame()->IsMaximized())
frame()->Restore();
else
frame()->Maximize();
+ // The maximize button may have moved out from under the cursor.
+ ResetWindowControls();
+ } else if (sender == close_button_) {
+ frame()->Close();
}
}
///////////////////////////////////////////////////////////////////////////////
-// views::Widget::Observer overrides:
+// TabIconView::TabIconViewModel overrides:
+
+bool BrowserNonClientFrameViewAura::ShouldTabIconViewAnimate() const {
+ // This function is queried during the creation of the window as the
+ // TabIconView we host is initialized, so we need to NULL check the selected
+ // WebContents because in this condition there is not yet a selected tab.
+ content::WebContents* current_tab = browser_view()->GetSelectedWebContents();
+ return current_tab ? current_tab->IsLoading() : false;
+}
-void BrowserNonClientFrameViewAura::OnWidgetActivationChanged(
- views::Widget* widget,
- bool active) {
- ActiveStateChanged();
+SkBitmap BrowserNonClientFrameViewAura::GetFaviconForTabIconView() {
+ views::WidgetDelegate* delegate = frame()->widget_delegate();
+ if (!delegate)
+ return SkBitmap();
+ return delegate->GetWindowIcon();
}
///////////////////////////////////////////////////////////////////////////////
-// ash::WindowFrame overrides:
+// BrowserNonClientFrameViewAura, private:
+
+void BrowserNonClientFrameViewAura::SetButtonImages(views::ImageButton* button,
+ int normal_bitmap_id,
+ int hot_bitmap_id,
+ int pushed_bitmap_id) {
+ ui::ThemeProvider* tp = frame()->GetThemeProvider();
+ button->SetImage(views::CustomButton::BS_NORMAL,
+ tp->GetBitmapNamed(normal_bitmap_id));
+ button->SetImage(views::CustomButton::BS_HOT,
+ tp->GetBitmapNamed(hot_bitmap_id));
+ button->SetImage(views::CustomButton::BS_PUSHED,
+ tp->GetBitmapNamed(pushed_bitmap_id));
+}
-void BrowserNonClientFrameViewAura::OnWindowHoverChanged(bool hovered) {
- if (hovered) {
- maximize_button_->Show();
- close_button_->Show();
+int BrowserNonClientFrameViewAura::NonClientTopBorderHeight(
+ bool restored) const {
+ if (frame()->widget_delegate() &&
+ frame()->widget_delegate()->ShouldShowWindowTitle()) {
+ // For popups ensure we have enough space to see the full window buttons.
+ return kCloseButtonOffsetY + close_button_->height();
+ }
+ if (restored)
+ return kTabstripTopSpacingRestored;
+ return kTabstripTopSpacingMaximized;
+}
+
+void BrowserNonClientFrameViewAura::PaintHeader(gfx::Canvas* canvas) {
+ // The primary header image changes based on window activation state and
+ // theme, so we look it up for each paint.
+ SkBitmap* theme_frame = GetThemeFrameBitmap();
+ SkBitmap* theme_frame_overlay = GetThemeFrameOverlayBitmap();
+
+ // Draw the header background, clipping the corners to be rounded.
+ const int kCornerRadius = 2;
+ TileRoundRect(canvas,
+ 0, 0, width(), theme_frame->height(),
+ *theme_frame,
+ kCornerRadius);
+
+ // Draw the theme frame overlay, if available.
+ if (theme_frame_overlay)
+ canvas->DrawBitmapInt(*theme_frame_overlay, 0, 0);
+
+ // Separator between the maximize and close buttons.
+ canvas->DrawBitmapInt(*button_separator_,
+ close_button_->x() - button_separator_->width(),
+ close_button_->y());
+
+ // Draw the top corners and edge.
+ int top_left_height = top_left_corner_->height();
+ canvas->DrawBitmapInt(*top_left_corner_,
+ 0, 0, top_left_corner_->width(), top_left_height,
+ 0, 0, top_left_corner_->width(), top_left_height,
+ false);
+ canvas->TileImageInt(*top_edge_,
+ top_left_corner_->width(),
+ 0,
+ width() - top_left_corner_->width() - top_right_corner_->width(),
+ top_edge_->height());
+ int top_right_height = top_right_corner_->height();
+ canvas->DrawBitmapInt(*top_right_corner_,
+ 0, 0,
+ top_right_corner_->width(), top_right_height,
+ width() - top_right_corner_->width(), 0,
+ top_right_corner_->width(), top_right_height,
+ false);
+
+ // Header left edge.
+ int header_left_height = theme_frame->height() - top_left_height;
+ canvas->TileImageInt(*header_left_edge_,
+ 0, top_left_height,
+ header_left_edge_->width(), header_left_height);
+
+ // Header right edge.
+ int header_right_height = theme_frame->height() - top_right_height;
+ canvas->TileImageInt(*header_right_edge_,
+ width() - header_right_edge_->width(), top_right_height,
+ header_right_edge_->width(), header_right_height);
+
+ // We don't draw edges around the content area. Web content goes flush
+ // to the edge of the window.
+}
+
+void BrowserNonClientFrameViewAura::PaintTitleBar(gfx::Canvas* canvas) {
+ // The window icon is painted by the TabIconView.
+ views::WidgetDelegate* delegate = frame()->widget_delegate();
+ if (delegate && delegate->ShouldShowWindowTitle()) {
+ int icon_right = window_icon_ ? window_icon_->bounds().right() : 0;
+ gfx::Rect title_bounds(
+ icon_right + kTitleOffsetX,
+ kTitleOffsetY,
+ std::max(0, maximize_button_->x() - kTitleLogoSpacing - icon_right),
+ BrowserFrame::GetTitleFont().GetHeight());
+ canvas->DrawStringInt(delegate->GetWindowTitle(),
+ BrowserFrame::GetTitleFont(),
+ SK_ColorWHITE,
+ GetMirroredXForRect(title_bounds),
+ title_bounds.y(),
+ title_bounds.width(),
+ title_bounds.height());
+ }
+}
+
+SkBitmap* BrowserNonClientFrameViewAura::GetThemeFrameBitmap() const {
+ bool is_incognito = browser_view()->IsOffTheRecord();
+ int resource_id;
+ if (browser_view()->IsBrowserTypeNormal()) {
+ if (ShouldPaintAsActive()) {
+ // Use the standard resource ids to allow users to theme the frames.
+ // TODO(jamescook): If this becomes the only frame we use on Aura, define
+ // the resources to use the standard ids like IDR_THEME_FRAME, etc.
+ if (is_incognito) {
+ return GetCustomBitmap(IDR_THEME_FRAME_INCOGNITO,
+ IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE);
+ }
+ return GetCustomBitmap(IDR_THEME_FRAME,
+ IDR_AURA_WINDOW_HEADER_BASE_ACTIVE);
+ }
+ if (is_incognito) {
+ return GetCustomBitmap(IDR_THEME_FRAME_INCOGNITO_INACTIVE,
+ IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_INACTIVE);
+ }
+ return GetCustomBitmap(IDR_THEME_FRAME_INACTIVE,
+ IDR_AURA_WINDOW_HEADER_BASE_INACTIVE);
+ }
+ // Never theme app and popup windows.
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ if (ShouldPaintAsActive()) {
+ resource_id = is_incognito ?
+ IDR_THEME_FRAME_INCOGNITO : IDR_FRAME;
} else {
- maximize_button_->Hide();
- close_button_->Hide();
+ resource_id = is_incognito ?
+ IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE;
}
+ return rb.GetBitmapNamed(resource_id);
+}
+
+SkBitmap* BrowserNonClientFrameViewAura::GetThemeFrameOverlayBitmap() const {
+ ui::ThemeProvider* tp = GetThemeProvider();
+ if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
+ browser_view()->IsBrowserTypeNormal() &&
+ !browser_view()->IsOffTheRecord()) {
+ return tp->GetBitmapNamed(ShouldPaintAsActive() ?
+ IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE);
+ }
+ return NULL;
+}
+
+SkBitmap* BrowserNonClientFrameViewAura::GetCustomBitmap(
+ int bitmap_id,
+ int fallback_bitmap_id) const {
+ ui::ThemeProvider* tp = GetThemeProvider();
+ if (tp->HasCustomImage(bitmap_id))
+ return tp->GetBitmapNamed(bitmap_id);
+ return tp->GetBitmapNamed(fallback_bitmap_id);
}

Powered by Google App Engine
This is Rietveld 408576698