summaryrefslogtreecommitdiffstats
path: root/ui/aura_shell/toplevel_frame_view.cc
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-22 18:15:58 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-22 18:15:58 +0000
commit70ccf7061242e1b405f58fb423dab470d9ec69ab (patch)
treecf8a1e58792098286aa4ce6e2a4859449aa77fe5 /ui/aura_shell/toplevel_frame_view.cc
parentc7f2ef7cee78dffc7fceea096ea482750b31fad1 (diff)
downloadchromium_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.cc383
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