summaryrefslogtreecommitdiffstats
path: root/ui
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
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')
-rw-r--r--ui/aura/aura.gyp1
-rw-r--r--ui/aura/cursor.h23
-rw-r--r--ui/aura/demo/demo_main.cc5
-rw-r--r--ui/aura/desktop.cc4
-rw-r--r--ui/aura/desktop.h6
-rw-r--r--ui/aura/desktop_host.h4
-rw-r--r--ui/aura/desktop_host_linux.cc5
-rw-r--r--ui/aura/desktop_host_win.cc22
-rw-r--r--ui/aura/desktop_host_win.h1
-rw-r--r--ui/aura/toplevel_window_event_filter.cc22
-rw-r--r--ui/aura/toplevel_window_event_filter.h2
-rw-r--r--ui/aura_shell/aura_shell.gyp2
-rw-r--r--ui/aura_shell/examples/window_type_launcher.cc9
-rw-r--r--ui/aura_shell/examples/window_type_launcher.h2
-rw-r--r--ui/aura_shell/toplevel_frame_view.cc383
-rw-r--r--ui/aura_shell/toplevel_frame_view.h96
-rw-r--r--ui/resources/aura/slab_close.pngbin0 -> 1468 bytes
-rw-r--r--ui/resources/aura/slab_zoom.pngbin0 -> 1353 bytes
-rw-r--r--ui/resources/ui_resources.grd2
19 files changed, 583 insertions, 6 deletions
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp
index 765d5a5..c97ba686 100644
--- a/ui/aura/aura.gyp
+++ b/ui/aura/aura.gyp
@@ -23,6 +23,7 @@
'AURA_IMPLEMENTATION',
],
'sources': [
+ 'cursor.h',
'desktop_host.h',
'desktop_host_linux.cc',
'desktop_host_win.cc',
diff --git a/ui/aura/cursor.h b/ui/aura/cursor.h
new file mode 100644
index 0000000..f8e8dda
--- /dev/null
+++ b/ui/aura/cursor.h
@@ -0,0 +1,23 @@
+// 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.
+
+#ifndef UI_AURA_CURSOR_H_
+#define UI_AURA_CURSOR_H_
+#pragma once
+
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+
+enum AURA_EXPORT CursorType {
+ CURSOR_POINTER,
+ CURSOR_LINK,
+ CURSOR_WAIT,
+ CURSOR_SIZE_HORIZONTAL,
+ CURSOR_SIZE_VERTICAL
+};
+
+} // namespace aura
+
+#endif // UI_AURA_CURSOR_H_
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc
index ca60c8b..6e30336 100644
--- a/ui/aura/demo/demo_main.cc
+++ b/ui/aura/demo/demo_main.cc
@@ -37,19 +37,16 @@ class DemoWindowDelegate : public aura::WindowDelegate {
virtual bool OnKeyEvent(aura::KeyEvent* event) OVERRIDE {
return false;
}
-
virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
return HTCAPTION;
}
-
virtual bool OnMouseEvent(aura::MouseEvent* event) OVERRIDE {
return true;
}
-
+ virtual void OnCaptureLost() OVERRIDE {}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
canvas->AsCanvasSkia()->drawColor(color_, SkXfermode::kSrc_Mode);
}
-
virtual void OnWindowDestroying() OVERRIDE {}
virtual void OnWindowDestroyed() OVERRIDE {}
diff --git a/ui/aura/desktop.cc b/ui/aura/desktop.cc
index 50b3802..8b5d0c8 100644
--- a/ui/aura/desktop.cc
+++ b/ui/aura/desktop.cc
@@ -57,6 +57,10 @@ void Desktop::SetSize(const gfx::Size& size) {
host_->SetSize(size);
}
+void Desktop::SetCursor(CursorType cursor_type) {
+ host_->SetCursor(cursor_type);
+}
+
void Desktop::Run() {
Show();
MessageLoopForUI::current()->Run(host_.get());
diff --git a/ui/aura/desktop.h b/ui/aura/desktop.h
index 41826c6d..ef41597 100644
--- a/ui/aura/desktop.h
+++ b/ui/aura/desktop.h
@@ -9,8 +9,9 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/task.h"
-#include "ui/aura/root_window.h"
#include "ui/aura/aura_export.h"
+#include "ui/aura/cursor.h"
+#include "ui/aura/root_window.h"
#include "ui/gfx/compositor/compositor.h"
#include "ui/gfx/native_widget_types.h"
@@ -38,6 +39,9 @@ class AURA_EXPORT Desktop : public ui::CompositorDelegate {
// Sets the size of the desktop.
void SetSize(const gfx::Size& size);
+ // Shows the specified cursor.
+ void SetCursor(CursorType cursor_type);
+
// Shows the desktop host and runs an event loop for it.
void Run();
diff --git a/ui/aura/desktop_host.h b/ui/aura/desktop_host.h
index 8c2cfa6..e9e134a 100644
--- a/ui/aura/desktop_host.h
+++ b/ui/aura/desktop_host.h
@@ -7,6 +7,7 @@
#pragma once
#include "base/message_loop.h"
+#include "ui/aura/cursor.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
@@ -40,6 +41,9 @@ class DesktopHost : public MessageLoop::Dispatcher {
// Gets/Sets the size of the DesktopHost.
virtual gfx::Size GetSize() = 0;
virtual void SetSize(const gfx::Size& size) = 0;
+
+ // Sets the currently displayed cursor.
+ virtual void SetCursor(CursorType cursor_type) = 0;
};
} // namespace aura
diff --git a/ui/aura/desktop_host_linux.cc b/ui/aura/desktop_host_linux.cc
index e088ba5..15fbfe7 100644
--- a/ui/aura/desktop_host_linux.cc
+++ b/ui/aura/desktop_host_linux.cc
@@ -30,6 +30,7 @@ class DesktopHostLinux : public DesktopHost {
virtual void Show() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void SetCursor(CursorType cursor_type) OVERRIDE;
Desktop* desktop_;
@@ -113,6 +114,10 @@ void DesktopHostLinux::SetSize(const gfx::Size& size) {
XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
}
+void DesktopHostLinux::SetCursor(CursorType cursor_type) {
+ NOTIMPLEMENTED();
+}
+
} // namespace
// static
diff --git a/ui/aura/desktop_host_win.cc b/ui/aura/desktop_host_win.cc
index ef1de50..e078c7d 100644
--- a/ui/aura/desktop_host_win.cc
+++ b/ui/aura/desktop_host_win.cc
@@ -58,6 +58,28 @@ void DesktopHostWin::SetSize(const gfx::Size& size) {
SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOREPOSITION);
}
+void DesktopHostWin::SetCursor(CursorType cursor_type) {
+ switch (cursor_type) {
+ case CURSOR_POINTER:
+ ::SetCursor(LoadCursor(NULL, IDC_ARROW));
+ break;
+ case CURSOR_LINK:
+ ::SetCursor(LoadCursor(NULL, IDC_HAND));
+ break;
+ case CURSOR_WAIT:
+ ::SetCursor(LoadCursor(NULL, IDC_WAIT));
+ break;
+ case CURSOR_SIZE_HORIZONTAL:
+ ::SetCursor(LoadCursor(NULL, IDC_SIZEWE));
+ break;
+ case CURSOR_SIZE_VERTICAL:
+ ::SetCursor(LoadCursor(NULL, IDC_SIZENS));
+ break;
+ default:
+ break;
+ }
+}
+
void DesktopHostWin::OnClose() {
// TODO: this obviously shouldn't be here.
MessageLoopForUI::current()->Quit();
diff --git a/ui/aura/desktop_host_win.h b/ui/aura/desktop_host_win.h
index 78e34eb..45bdaf3 100644
--- a/ui/aura/desktop_host_win.h
+++ b/ui/aura/desktop_host_win.h
@@ -26,6 +26,7 @@ class DesktopHostWin : public DesktopHost, public ui::WindowImpl {
virtual void Show() OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;
virtual void SetSize(const gfx::Size& size) OVERRIDE;
+ virtual void SetCursor(CursorType cursor_type) OVERRIDE;
private:
BEGIN_MSG_MAP_EX(DesktopHostWin)
diff --git a/ui/aura/toplevel_window_event_filter.cc b/ui/aura/toplevel_window_event_filter.cc
index be648c8..de9a77d4 100644
--- a/ui/aura/toplevel_window_event_filter.cc
+++ b/ui/aura/toplevel_window_event_filter.cc
@@ -4,6 +4,8 @@
#include "ui/aura/toplevel_window_event_filter.h"
+#include "ui/aura/cursor.h"
+#include "ui/aura/desktop.h"
#include "ui/aura/event.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
@@ -25,9 +27,12 @@ ToplevelWindowEventFilter::~ToplevelWindowEventFilter() {
bool ToplevelWindowEventFilter::OnMouseEvent(Window* target,
MouseEvent* event) {
switch (event->type()) {
- case ui::ET_MOUSE_PRESSED:
+ case ui::ET_MOUSE_MOVED:
window_component_ =
target->delegate()->GetNonClientComponent(event->location());
+ UpdateCursorForWindowComponent();
+ break;
+ case ui::ET_MOUSE_PRESSED:
MoveWindowToFront(target);
mouse_down_offset_ = event->location();
window_location_ = target->bounds().origin();
@@ -64,4 +69,19 @@ void ToplevelWindowEventFilter::MoveWindowToFront(Window* target) {
}
}
+void ToplevelWindowEventFilter::UpdateCursorForWindowComponent() {
+ switch (window_component_) {
+ case HTLEFT:
+ case HTRIGHT:
+ Desktop::GetInstance()->SetCursor(CURSOR_SIZE_HORIZONTAL);
+ break;
+ case HTBOTTOM:
+ Desktop::GetInstance()->SetCursor(CURSOR_SIZE_VERTICAL);
+ break;
+ default:
+ Desktop::GetInstance()->SetCursor(CURSOR_POINTER);
+ break;
+ }
+}
+
} // namespace aura
diff --git a/ui/aura/toplevel_window_event_filter.h b/ui/aura/toplevel_window_event_filter.h
index 33cc092..7126b35 100644
--- a/ui/aura/toplevel_window_event_filter.h
+++ b/ui/aura/toplevel_window_event_filter.h
@@ -28,6 +28,8 @@ class ToplevelWindowEventFilter : public EventFilter {
// respective z-orders.
void MoveWindowToFront(Window* target);
+ void UpdateCursorForWindowComponent();
+
gfx::Point mouse_down_offset_;
gfx::Point window_location_;
int window_component_;
diff --git a/ui/aura_shell/aura_shell.gyp b/ui/aura_shell/aura_shell.gyp
index 02687b8..a3d477c 100644
--- a/ui/aura_shell/aura_shell.gyp
+++ b/ui/aura_shell/aura_shell.gyp
@@ -42,6 +42,8 @@
'shell_factory.h',
'status_area_view.cc',
'status_area_view.h',
+ 'toplevel_frame_view.cc',
+ 'toplevel_frame_view.h',
],
},
{
diff --git a/ui/aura_shell/examples/window_type_launcher.cc b/ui/aura_shell/examples/window_type_launcher.cc
index e240fa2..a9eb50d 100644
--- a/ui/aura_shell/examples/window_type_launcher.cc
+++ b/ui/aura_shell/examples/window_type_launcher.cc
@@ -8,6 +8,7 @@
#include "ui/aura/window.h"
#include "ui/aura_shell/examples/example_factory.h"
#include "ui/aura_shell/examples/toplevel_window.h"
+#include "ui/aura_shell/toplevel_frame_view.h"
#include "ui/gfx/canvas.h"
#include "views/controls/button/text_button.h"
#include "views/controls/menu/menu_item_view.h"
@@ -71,10 +72,18 @@ views::View* WindowTypeLauncher::GetContentsView() {
return this;
}
+bool WindowTypeLauncher::CanResize() const {
+ return true;
+}
+
std::wstring WindowTypeLauncher::GetWindowTitle() const {
return L"Examples: Window Builder";
}
+views::NonClientFrameView* WindowTypeLauncher::CreateNonClientFrameView() {
+ return new aura_shell::internal::ToplevelFrameView;
+}
+
void WindowTypeLauncher::ButtonPressed(views::Button* sender,
const views::Event& event) {
if (sender == create_button_) {
diff --git a/ui/aura_shell/examples/window_type_launcher.h b/ui/aura_shell/examples/window_type_launcher.h
index edf75f8..303e255 100644
--- a/ui/aura_shell/examples/window_type_launcher.h
+++ b/ui/aura_shell/examples/window_type_launcher.h
@@ -42,7 +42,9 @@ class WindowTypeLauncher : public views::WidgetDelegateView,
// Overridden from views::WidgetDelegate:
virtual views::View* GetContentsView() OVERRIDE;
+ virtual bool CanResize() const OVERRIDE;
virtual std::wstring GetWindowTitle() const OVERRIDE;
+ virtual views::NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
// Overridden from views::ButtonListener:
virtual void ButtonPressed(views::Button* sender,
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
diff --git a/ui/aura_shell/toplevel_frame_view.h b/ui/aura_shell/toplevel_frame_view.h
new file mode 100644
index 0000000..2d9aa67
--- /dev/null
+++ b/ui/aura_shell/toplevel_frame_view.h
@@ -0,0 +1,96 @@
+// 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.
+
+#ifndef UI_AURA_SHELL_TOPLEVEL_FRAME_VIEW_H_
+#define UI_AURA_SHELL_TOPLEVEL_FRAME_VIEW_H_
+#pragma once
+
+#include "ui/aura_shell/aura_shell_export.h"
+#include "ui/base/animation/animation_delegate.h"
+#include "views/controls/button/button.h"
+#include "views/window/non_client_view.h"
+
+namespace ui {
+class SlideAnimation;
+}
+
+namespace aura_shell {
+namespace internal {
+
+class SizingBorder;
+
+// A NonClientFrameView implementation for generic top-level windows in Aura.
+// TODO(beng): Find a way to automatically this for all top-level windows in
+// Aura. Right now windows have to override CreateNonClientFrameView
+// on WidgetDelegate to specify this.
+class AURA_SHELL_EXPORT ToplevelFrameView : public views::NonClientFrameView,
+ public views::ButtonListener {
+ public:
+ ToplevelFrameView();
+ virtual ~ToplevelFrameView();
+
+ private:
+ // Returns the height of the side/bottom non-client edges.
+ int NonClientBorderThickness() const;
+
+ // Returns the height of the top non-client edge - the caption.
+ int NonClientTopBorderHeight() const;
+
+ // Implementation of NonClientHitTest().
+ int NonClientHitTestImpl(const gfx::Point& point);
+
+ // Shows the specified |sizing_border|, hiding all others.
+ // If |sizing_border| is NULL, all other sizing borders are hidden.
+ void ShowSizingBorder(SizingBorder* sizing_border);
+
+ // Returns true if the specified point (in FrameView coordinates) hit-tests
+ // against the specified child.
+ bool PointIsInChildView(views::View* child, const gfx::Point& point) const;
+
+ // Returns the bounds of the specified sizing border for its visible and
+ // hidden states.
+ gfx::Rect GetHiddenBoundsForSizingBorder(int frame_component) const;
+ gfx::Rect GetVisibleBoundsForSizingBorder(int frame_component) const;
+
+ // Overridden from views::NonClientFrameView:
+ virtual gfx::Rect GetBoundsForClientView() const OVERRIDE;
+ virtual gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const OVERRIDE;
+ virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
+ virtual void GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) OVERRIDE;
+ virtual void EnableClose(bool enable) OVERRIDE;
+ virtual void ResetWindowControls() OVERRIDE;
+ virtual void UpdateWindowIcon() OVERRIDE;
+
+ // Overridden from views::View:
+ virtual void Layout() OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void OnMouseMoved(const views::MouseEvent& event) OVERRIDE;
+ virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE;
+ virtual views::View* GetEventHandlerForPoint(
+ const gfx::Point& point) OVERRIDE;
+
+ // Overridden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ gfx::Rect client_view_bounds_;
+
+ views::Button* close_button_;
+ views::Button* zoom_button_;
+
+ int current_hittest_code_;
+
+ SizingBorder* left_edge_;
+ SizingBorder* right_edge_;
+ SizingBorder* bottom_edge_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToplevelFrameView);
+};
+
+} // namespace internal
+} // namespace aura_shell
+
+#endif // #ifndef UI_AURA_SHELL_TOPLEVEL_FRAME_VIEW_H_
diff --git a/ui/resources/aura/slab_close.png b/ui/resources/aura/slab_close.png
new file mode 100644
index 0000000..29c2a09
--- /dev/null
+++ b/ui/resources/aura/slab_close.png
Binary files differ
diff --git a/ui/resources/aura/slab_zoom.png b/ui/resources/aura/slab_zoom.png
new file mode 100644
index 0000000..f0569bb
--- /dev/null
+++ b/ui/resources/aura/slab_zoom.png
Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index d6d8b41..3902ea3 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -125,6 +125,8 @@
<include name="IDR_AURA_LAUNCHER_ICON_APPLIST" file="aura/applist.png" type="BINDATA" />
<include name="IDR_AURA_STATUS_MOCK" file="aura/statusbar.png" type="BINDATA" />
<include name="IDR_AURA_WALLPAPER" file="aura/damask.png" type="BINDATA" />
+ <include name="IDR_AURA_WINDOW_CLOSE_ICON" file="aura/slab_close.png" type="BINDATA" />
+ <include name="IDR_AURA_WINDOW_ZOOM_ICON" file="aura/slab_zoom.png" type="BINDATA" />
</if>
</includes>
</release>