diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-22 18:15:58 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-22 18:15:58 +0000 |
commit | 70ccf7061242e1b405f58fb423dab470d9ec69ab (patch) | |
tree | cf8a1e58792098286aa4ce6e2a4859449aa77fe5 /ui/aura_shell/toplevel_frame_view.cc | |
parent | c7f2ef7cee78dffc7fceea096ea482750b31fad1 (diff) | |
download | chromium_src-70ccf7061242e1b405f58fb423dab470d9ec69ab.zip chromium_src-70ccf7061242e1b405f58fb423dab470d9ec69ab.tar.gz chromium_src-70ccf7061242e1b405f58fb423dab470d9ec69ab.tar.bz2 |
Adds a NonClientFrameView for generic toplevel windows.Also adds a feeble (but better than what there was) attempt at sometimes updating the cursor. Will have to be replaced by a better system, but it's a start.http://crbug.com/97247TEST=none
Review URL: http://codereview.chromium.org/7977012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102312 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/aura_shell/toplevel_frame_view.cc')
-rw-r--r-- | ui/aura_shell/toplevel_frame_view.cc | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/ui/aura_shell/toplevel_frame_view.cc b/ui/aura_shell/toplevel_frame_view.cc new file mode 100644 index 0000000..02b2d1b --- /dev/null +++ b/ui/aura_shell/toplevel_frame_view.cc @@ -0,0 +1,383 @@ +// Copyright (c) 2011 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/aura_shell/toplevel_frame_view.h" + +#include "grit/ui_resources.h" +#include "ui/base/animation/throb_animation.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "views/controls/button/custom_button.h" +#include "views/widget/widget.h" +#include "views/widget/widget_delegate.h" + +#if !defined(OS_WIN) +#include "views/window/hit_test.h" +#endif + +namespace aura_shell { +namespace internal { + +namespace { +// The thickness of the left, right and bottom edges of the frame. +const int kFrameBorderThickness = 8; +const int kFrameOpacity = 50; +// The color used to fill the frame. +const SkColor kFrameColor = SkColorSetARGB(kFrameOpacity, 0, 0, 0); +const int kFrameBorderHiddenOpacity = 0; +const int kFrameBorderVisibleOpacity = kFrameOpacity; +// How long the hover animation takes if uninterrupted. +const int kHoverFadeDurationMs = 250; +} // namespace + +// Buttons for window controls - close, zoom, etc. +class WindowControlButton : public views::CustomButton { + public: + WindowControlButton(views::ButtonListener* listener, + SkColor color, + const SkBitmap& icon) + : views::CustomButton(listener), + color_(color), + icon_(icon) { + } + virtual ~WindowControlButton() {} + + // Overridden from views::View: + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + canvas->FillRectInt(GetBackgroundColor(), 0, 0, width(), height()); + canvas->DrawBitmapInt(icon_, 0, 0); + } + virtual gfx::Size GetPreferredSize() OVERRIDE { + gfx::Size size(icon_.width(), icon_.height()); + size.Enlarge(3, 2); + return size; + } + + private: + SkColor GetBackgroundColor() { + return SkColorSetARGB(hover_animation_->CurrentValueBetween(0, 150), + SkColorGetR(color_), + SkColorGetG(color_), + SkColorGetB(color_)); + } + + SkColor color_; + SkBitmap icon_; + + DISALLOW_COPY_AND_ASSIGN(WindowControlButton); +}; + +class SizingBorder : public views::View, + public ui::AnimationDelegate { + public: + SizingBorder() + : ALLOW_THIS_IN_INITIALIZER_LIST( + animation_(new ui::SlideAnimation(this))) { + animation_->SetSlideDuration(kHoverFadeDurationMs); + } + virtual ~SizingBorder() {} + + void Configure(const gfx::Rect& hidden_bounds, + const gfx::Rect& visible_bounds) { + hidden_bounds_ = hidden_bounds; + visible_bounds_ = visible_bounds; + SetBoundsRect(hidden_bounds_); + } + + void Show() { + animation_->Show(); + } + + void Hide() { + animation_->Hide(); + } + + bool IsShowing() const { + return animation_->IsShowing(); + } + + bool IsHiding() const { + return animation_->IsClosing(); + } + + private: + // Overridden from views::View: + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + // Fill with current opacity value. + int opacity = animation_->CurrentValueBetween(kFrameBorderHiddenOpacity, + kFrameBorderVisibleOpacity); + canvas->FillRectInt(SkColorSetARGB(opacity, + SkColorGetR(kFrameColor), + SkColorGetG(kFrameColor), + SkColorGetB(kFrameColor)), + 0, 0, width(), height()); + } + + // Overridden from ui::AnimationDelegate: + void AnimationProgressed(const ui::Animation* animation) OVERRIDE { + // TODO: update bounds. + gfx::Rect current_bounds = animation_->CurrentValueBetween(hidden_bounds_, + visible_bounds_); + SetBoundsRect(current_bounds); + SchedulePaint(); + } + + // Each of these represents the hidden/visible states of the sizing border. + // When the view is shown or hidden it animates between them. + gfx::Rect hidden_bounds_; + gfx::Rect visible_bounds_; + + scoped_ptr<ui::SlideAnimation> animation_; + + DISALLOW_COPY_AND_ASSIGN(SizingBorder); +}; + +//////////////////////////////////////////////////////////////////////////////// +// ToplevelFrameView, public: + +ToplevelFrameView::ToplevelFrameView() + : current_hittest_code_(HTNOWHERE), + left_edge_(new SizingBorder), + right_edge_(new SizingBorder), + bottom_edge_(new SizingBorder) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + close_button_ = + new WindowControlButton(this, SK_ColorRED, + *rb.GetBitmapNamed(IDR_AURA_WINDOW_CLOSE_ICON)); + zoom_button_ = + new WindowControlButton(this, SK_ColorGREEN, + *rb.GetBitmapNamed(IDR_AURA_WINDOW_ZOOM_ICON)); + AddChildView(close_button_); + AddChildView(zoom_button_); + + AddChildView(left_edge_); + AddChildView(right_edge_); + AddChildView(bottom_edge_); +} + +ToplevelFrameView::~ToplevelFrameView() { +} + +//////////////////////////////////////////////////////////////////////////////// +// ToplevelFrameView, private: + +int ToplevelFrameView::NonClientBorderThickness() const { + return kFrameBorderThickness; +} + +int ToplevelFrameView::NonClientTopBorderHeight() const { + return close_button_->GetPreferredSize().height(); +} + +int ToplevelFrameView::NonClientHitTestImpl(const gfx::Point& point) { + // Sanity check. + if (!GetLocalBounds().Contains(point)) + return HTNOWHERE; + + // The client view gets first crack at claiming the point. + int frame_component = GetWidget()->client_view()->NonClientHitTest(point); + if (frame_component != HTNOWHERE) + return frame_component; + + // The window controls come second. + if (close_button_->GetMirroredBounds().Contains(point)) + return HTCLOSE; + else if (zoom_button_->GetMirroredBounds().Contains(point)) + return HTMAXBUTTON; + + // Finally other portions of the frame/sizing border. + frame_component = + GetHTComponentForFrame(point, + NonClientBorderThickness(), + NonClientBorderThickness(), + NonClientBorderThickness(), + NonClientBorderThickness(), + GetWidget()->widget_delegate()->CanResize()); + + // Coerce HTCAPTION as a fallback. + return frame_component == HTNOWHERE ? HTCAPTION : frame_component; +} + +void ToplevelFrameView::ShowSizingBorder(SizingBorder* sizing_border) { + if (sizing_border && !sizing_border->IsShowing()) + sizing_border->Show(); + if (left_edge_ != sizing_border && !left_edge_->IsHiding()) + left_edge_->Hide(); + if (right_edge_ != sizing_border && !right_edge_->IsHiding()) + right_edge_->Hide(); + if (bottom_edge_ != sizing_border && !bottom_edge_->IsHiding()) + bottom_edge_->Hide(); +} + +bool ToplevelFrameView::PointIsInChildView(views::View* child, + const gfx::Point& point) const { + gfx::Point child_point(point); + ConvertPointToView(this, child, &child_point); + return child->HitTest(child_point); +} + +gfx::Rect ToplevelFrameView::GetHiddenBoundsForSizingBorder( + int frame_component) const { + int border_size = NonClientBorderThickness(); + int caption_height = NonClientTopBorderHeight(); + switch (frame_component) { + case HTLEFT: + return gfx::Rect(border_size, caption_height, border_size, + height() - border_size - caption_height); + case HTBOTTOM: + return gfx::Rect(border_size, height() - 2 * border_size, + width() - 2 * border_size, border_size); + case HTRIGHT: + return gfx::Rect(width() - 2 * border_size, caption_height, border_size, + height() - border_size - caption_height); + default: + break; + } + return gfx::Rect(); +} + +gfx::Rect ToplevelFrameView::GetVisibleBoundsForSizingBorder( + int frame_component) const { + int border_size = NonClientBorderThickness(); + int caption_height = NonClientTopBorderHeight(); + switch (frame_component) { + case HTLEFT: + return gfx::Rect(0, caption_height, border_size, + height() - border_size - caption_height); + case HTBOTTOM: + return gfx::Rect(border_size, height() - border_size, + width() - 2 * border_size, border_size); + case HTRIGHT: + return gfx::Rect(width() - border_size, caption_height, border_size, + height() - border_size - caption_height); + default: + break; + } + return gfx::Rect(); +} + +//////////////////////////////////////////////////////////////////////////////// +// ToplevelFrameView, views::NonClientFrameView overrides: + +gfx::Rect ToplevelFrameView::GetBoundsForClientView() const { + return client_view_bounds_; +} + +gfx::Rect ToplevelFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + gfx::Rect window_bounds = client_bounds; + window_bounds.Inset(-NonClientBorderThickness(), + -NonClientTopBorderHeight(), + -NonClientBorderThickness(), + -NonClientBorderThickness()); + return window_bounds; +} + +int ToplevelFrameView::NonClientHitTest(const gfx::Point& point) { + int old_hittest_code = current_hittest_code_; + current_hittest_code_ = NonClientHitTestImpl(point); + return current_hittest_code_; +} + +void ToplevelFrameView::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { + // Nothing. +} + +void ToplevelFrameView::EnableClose(bool enable) { + close_button_->SetEnabled(enable); +} + +void ToplevelFrameView::ResetWindowControls() { + NOTIMPLEMENTED(); +} + +void ToplevelFrameView::UpdateWindowIcon() { + NOTIMPLEMENTED(); +} + +//////////////////////////////////////////////////////////////////////////////// +// ToplevelFrameView, views::View overrides: + +void ToplevelFrameView::Layout() { + client_view_bounds_ = GetLocalBounds(); + client_view_bounds_.Inset(NonClientBorderThickness(), + NonClientTopBorderHeight(), + NonClientBorderThickness(), + NonClientBorderThickness()); + + gfx::Size close_button_ps = close_button_->GetPreferredSize(); + close_button_->SetBoundsRect( + gfx::Rect(width() - close_button_ps.width() - NonClientBorderThickness(), + 0, close_button_ps.width(), close_button_ps.height())); + + gfx::Size zoom_button_ps = zoom_button_->GetPreferredSize(); + zoom_button_->SetBoundsRect( + gfx::Rect(close_button_->x() - zoom_button_ps.width(), 0, + zoom_button_ps.width(), zoom_button_ps.height())); + + left_edge_->Configure(GetHiddenBoundsForSizingBorder(HTLEFT), + GetVisibleBoundsForSizingBorder(HTLEFT)); + right_edge_->Configure(GetHiddenBoundsForSizingBorder(HTRIGHT), + GetVisibleBoundsForSizingBorder(HTRIGHT)); + bottom_edge_->Configure(GetHiddenBoundsForSizingBorder(HTBOTTOM), + GetVisibleBoundsForSizingBorder(HTBOTTOM)); +} + +void ToplevelFrameView::OnPaint(gfx::Canvas* canvas) { + gfx::Rect caption_rect(NonClientBorderThickness(), 0, + width() - 2 * NonClientBorderThickness(), + NonClientTopBorderHeight()); + canvas->FillRectInt(kFrameColor, caption_rect.x(), caption_rect.y(), + caption_rect.width(), caption_rect.height()); +} + +void ToplevelFrameView::OnMouseMoved(const views::MouseEvent& event) { + switch (current_hittest_code_) { + case HTLEFT: + ShowSizingBorder(left_edge_); + break; + case HTRIGHT: + ShowSizingBorder(right_edge_); + break; + case HTBOTTOM: + ShowSizingBorder(bottom_edge_); + break; + default: + break; + } +} + +void ToplevelFrameView::OnMouseExited(const views::MouseEvent& event) { + ShowSizingBorder(NULL); +} + +views::View* ToplevelFrameView::GetEventHandlerForPoint( + const gfx::Point& point) { + if (PointIsInChildView(left_edge_, point) || + PointIsInChildView(right_edge_, point) || + PointIsInChildView(bottom_edge_, point)) { + return this; + } + return View::GetEventHandlerForPoint(point); +} + + +//////////////////////////////////////////////////////////////////////////////// +// ToplevelFrameView, views::ButtonListener implementation: + +void ToplevelFrameView::ButtonPressed(views::Button* sender, + const views::Event& event) { + if (sender == close_button_) { + GetWidget()->Close(); + } else if (sender == zoom_button_) { + if (GetWidget()->IsMaximized()) + GetWidget()->Restore(); + else + GetWidget()->Maximize(); + } +} + +} // namespace internal +} // namespace aura_shell |