diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index 765d5a51e9f7c2..c97ba686081321 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 00000000000000..f8e8dda2e0fd4d --- /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 ca60c8b27c3390..6e303363c1a04c 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 50b38029dc5fec..8b5d0c821cf12d 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 41826c6d4ca408..ef415975609287 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 8c2cfa6747aac9..e9e134ad86e603 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 e088ba5cfffcd3..15fbfe76ef7d91 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 ef1de5048308a9..e078c7deb2fd1d 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 78e34eb39d18b8..45bdaf3ff6984e 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 be648c87b369a4..de9a77d4dda7ff 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 33cc0924a2e8df..7126b35165c552 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 02687b8930103c..a3d477c7dd3e4a 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 e240fa2507382a..a9eb50d16a7409 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 edf75f837da2bc..303e255334a0eb 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 00000000000000..02b2d1b3d3fb13 --- /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 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 00000000000000..2d9aa67cb91b82 --- /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 00000000000000..29c2a0946d5755 Binary files /dev/null and b/ui/resources/aura/slab_close.png differ diff --git a/ui/resources/aura/slab_zoom.png b/ui/resources/aura/slab_zoom.png new file mode 100644 index 00000000000000..f0569bbc4cb7d7 Binary files /dev/null and b/ui/resources/aura/slab_zoom.png differ diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd index d6d8b412aaa1ce..3902ea3255d3a5 100644 --- a/ui/resources/ui_resources.grd +++ b/ui/resources/ui_resources.grd @@ -125,6 +125,8 @@ + +