summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authortfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-13 11:59:47 +0000
committertfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-13 11:59:47 +0000
commitad678cf424e5c9c0d956deb94d0777d475e8fdd2 (patch)
treea6a55eb374813d142fe1429e824e2c8e16e38ac7 /ui
parentfc29f183706373091bf980160e3d26835b264f9c (diff)
downloadchromium_src-ad678cf424e5c9c0d956deb94d0777d475e8fdd2.zip
chromium_src-ad678cf424e5c9c0d956deb94d0777d475e8fdd2.tar.gz
chromium_src-ad678cf424e5c9c0d956deb94d0777d475e8fdd2.tar.bz2
views: Move views/window/ to ui/views/window directory.
Left stub files that will be removed in a follow up patch after updating the files to point to the new location. BUG=104039 R=ben@chromium.org Review URL: http://codereview.chromium.org/8552005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109827 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/views/window/client_view.cc88
-rw-r--r--ui/views/window/client_view.h89
-rw-r--r--ui/views/window/custom_frame_view.cc594
-rw-r--r--ui/views/window/custom_frame_view.h127
-rw-r--r--ui/views/window/dialog_client_view.cc591
-rw-r--r--ui/views/window/dialog_client_view.h170
-rw-r--r--ui/views/window/dialog_delegate.cc121
-rw-r--r--ui/views/window/dialog_delegate.h128
-rw-r--r--ui/views/window/native_frame_view.cc74
-rw-r--r--ui/views/window/native_frame_view.h48
-rw-r--r--ui/views/window/non_client_view.cc276
-rw-r--r--ui/views/window/non_client_view.h240
-rw-r--r--ui/views/window/window_resources.h32
-rw-r--r--ui/views/window/window_shape.cc46
-rw-r--r--ui/views/window/window_shape.h25
15 files changed, 2649 insertions, 0 deletions
diff --git a/ui/views/window/client_view.cc b/ui/views/window/client_view.cc
new file mode 100644
index 0000000..560983b
--- /dev/null
+++ b/ui/views/window/client_view.cc
@@ -0,0 +1,88 @@
+// 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 "views/window/client_view.h"
+
+#include "base/logging.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/hit_test.h"
+#include "views/widget/widget.h"
+#include "views/widget/widget_delegate.h"
+
+namespace views {
+
+// static
+const char ClientView::kViewClassName[] =
+ "views/window/ClientView";
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientView, public:
+
+ClientView::ClientView(Widget* widget, View* contents_view)
+ : widget_(widget),
+ contents_view_(contents_view) {
+}
+
+int ClientView::NonClientHitTest(const gfx::Point& point) {
+ return bounds().Contains(point) ? HTCLIENT : HTNOWHERE;
+}
+
+DialogClientView* ClientView::AsDialogClientView() {
+ return NULL;
+}
+
+const DialogClientView* ClientView::AsDialogClientView() const {
+ return NULL;
+}
+
+bool ClientView::CanClose() {
+ return true;
+}
+
+void ClientView::WidgetClosing() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientView, View overrides:
+
+gfx::Size ClientView::GetPreferredSize() {
+ // |contents_view_| is allowed to be NULL up until the point where this view
+ // is attached to a Container.
+ if (contents_view_)
+ return contents_view_->GetPreferredSize();
+ return gfx::Size();
+}
+
+void ClientView::Layout() {
+ // |contents_view_| is allowed to be NULL up until the point where this view
+ // is attached to a Container.
+ if (contents_view_)
+ contents_view_->SetBounds(0, 0, width(), height());
+}
+
+std::string ClientView::GetClassName() const {
+ return kViewClassName;
+}
+
+void ClientView::GetAccessibleState(ui::AccessibleViewState* state) {
+ state->role = ui::AccessibilityTypes::ROLE_CLIENT;
+}
+
+void ClientView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ // Overridden to do nothing. The NonClientView manually calls Layout on the
+ // ClientView when it is itself laid out, see comment in
+ // NonClientView::Layout.
+}
+
+void ClientView::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+ if (is_add && child == this) {
+ DCHECK(GetWidget());
+ DCHECK(contents_view_); // |contents_view_| must be valid now!
+ // Insert |contents_view_| at index 0 so it is first in the focus chain.
+ // (the OK/Cancel buttons are inserted before contents_view_)
+ AddChildViewAt(contents_view_, 0);
+ }
+}
+
+} // namespace views
diff --git a/ui/views/window/client_view.h b/ui/views/window/client_view.h
new file mode 100644
index 0000000..4b809f2
--- /dev/null
+++ b/ui/views/window/client_view.h
@@ -0,0 +1,89 @@
+// 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_VIEWS_WINDOW_CLIENT_VIEW_H_
+#define UI_VIEWS_WINDOW_CLIENT_VIEW_H_
+#pragma once
+
+#include "views/view.h"
+
+namespace views {
+
+class DialogClientView;
+class Widget;
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientView
+//
+// A ClientView is a View subclass that is used to occupy the "client area"
+// of a widget. It provides basic information to the widget that contains it
+// such as non-client hit testing information, sizing etc. Sub-classes of
+// ClientView are used to create more elaborate contents, e.g.
+// "DialogClientView".
+class VIEWS_EXPORT ClientView : public View {
+ public:
+ // Internal class name
+ static const char kViewClassName[];
+
+ // Constructs a ClientView object for the specified widget with the specified
+ // contents. Since this object is created during the process of creating
+ // |widget|, |contents_view| must be valid if you want the initial size of
+ // the widget to be based on |contents_view|'s preferred size.
+ ClientView(Widget* widget, View* contents_view);
+ virtual ~ClientView() {}
+
+ // Manual RTTI ftw.
+ virtual DialogClientView* AsDialogClientView();
+ virtual const DialogClientView* AsDialogClientView() const;
+
+ // Returns true to signal that the Widget can be closed. Specialized
+ // ClientView subclasses can override this default behavior to allow the
+ // close to be blocked until the user corrects mistakes, accepts a warning
+ // dialog, etc.
+ virtual bool CanClose();
+
+ // Notification that the widget is closing.
+ virtual void WidgetClosing();
+
+ // Tests to see if the specified point (in view coordinates) is within the
+ // bounds of this view. If so, it returns HTCLIENT in this default
+ // implementation. If it is outside the bounds of this view, this must return
+ // HTNOWHERE to tell the caller to do further processing to determine where
+ // in the non-client area it is (if it is).
+ // Subclasses of ClientView can extend this logic by overriding this method
+ // to detect if regions within the client area count as parts of the "non-
+ // client" area. A good example of this is the size box at the bottom right
+ // corner of resizable dialog boxes.
+ virtual int NonClientHitTest(const gfx::Point& point);
+
+ // Overridden from View:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual void Layout() OVERRIDE;
+ virtual std::string GetClassName() const OVERRIDE;
+
+ protected:
+ // Overridden from View:
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
+ virtual void ViewHierarchyChanged(bool is_add,
+ View* parent,
+ View* child) OVERRIDE;
+
+ // Accessors for private data members.
+ View* contents_view() const { return contents_view_; }
+ void set_contents_view(View* contents_view) {
+ contents_view_ = contents_view;
+ }
+
+ private:
+ // The Widget that hosts this ClientView.
+ Widget* widget_;
+
+ // The View that this ClientView contains.
+ View* contents_view_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_CLIENT_VIEW_H_
diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc
new file mode 100644
index 0000000..989f3c55
--- /dev/null
+++ b/ui/views/window/custom_frame_view.cc
@@ -0,0 +1,594 @@
+// 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 "views/window/custom_frame_view.h"
+
+#include <algorithm>
+
+#include "base/utf_string_conversions.h"
+#include "grit/ui_resources.h"
+#include "grit/ui_strings.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/path.h"
+#include "views/widget/widget_delegate.h"
+#include "views/window/client_view.h"
+#include "views/window/window_resources.h"
+#include "views/window/window_shape.h"
+
+#if defined(USE_AURA)
+#include "views/widget/native_widget_aura.h"
+#elif defined(OS_WIN)
+#include "views/widget/native_widget_win.h"
+#endif
+
+namespace views {
+
+// static
+gfx::Font* CustomFrameView::title_font_ = NULL;
+
+namespace {
+// The frame border is only visible in restored mode and is hardcoded to 4 px on
+// each side regardless of the system window border size.
+const int kFrameBorderThickness = 4;
+// Various edges of the frame border have a 1 px shadow along their edges; in a
+// few cases we shift elements based on this amount for visual appeal.
+const int kFrameShadowThickness = 1;
+// While resize areas on Windows are normally the same size as the window
+// borders, our top area is shrunk by 1 px to make it easier to move the window
+// around with our thinner top grabbable strip. (Incidentally, our side and
+// bottom resize areas don't match the frame border thickness either -- they
+// span the whole nonclient area, so there's no "dead zone" for the mouse.)
+const int kTopResizeAdjust = 1;
+// 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;
+// The titlebar never shrinks too short to show the caption button plus some
+// padding below it.
+const int kCaptionButtonHeightWithPadding = 19;
+// The titlebar has a 2 px 3D edge along the top and bottom.
+const int kTitlebarTopAndBottomEdgeThickness = 2;
+// The icon is inset 2 px from the left frame border.
+const int kIconLeftSpacing = 2;
+// The icon never shrinks below 16 px on a side.
+const int kIconMinimumSize = 16;
+// There is a 4 px gap between the icon and the title text.
+const int kIconTitleSpacing = 4;
+// There is a 5 px gap between the title text and the caption buttons.
+const int kTitleCaptionSpacing = 5;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, public:
+
+CustomFrameView::CustomFrameView(Widget* frame)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(close_button_(new ImageButton(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(restore_button_(new ImageButton(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(maximize_button_(new ImageButton(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(minimize_button_(new ImageButton(this))),
+ window_icon_(NULL),
+ should_show_minmax_buttons_(false),
+ should_show_client_edge_(false),
+ frame_(frame) {
+ InitClass();
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ close_button_->SetAccessibleName(
+ l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
+
+ // Close button images will be set in LayoutWindowControls().
+ AddChildView(close_button_);
+
+ restore_button_->SetAccessibleName(
+ l10n_util::GetStringUTF16(IDS_APP_ACCNAME_RESTORE));
+ restore_button_->SetImage(CustomButton::BS_NORMAL,
+ rb.GetBitmapNamed(IDR_RESTORE));
+ restore_button_->SetImage(CustomButton::BS_HOT,
+ rb.GetBitmapNamed(IDR_RESTORE_H));
+ restore_button_->SetImage(CustomButton::BS_PUSHED,
+ rb.GetBitmapNamed(IDR_RESTORE_P));
+ AddChildView(restore_button_);
+
+ maximize_button_->SetAccessibleName(
+ l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
+ maximize_button_->SetImage(CustomButton::BS_NORMAL,
+ rb.GetBitmapNamed(IDR_MAXIMIZE));
+ maximize_button_->SetImage(CustomButton::BS_HOT,
+ rb.GetBitmapNamed(IDR_MAXIMIZE_H));
+ maximize_button_->SetImage(CustomButton::BS_PUSHED,
+ rb.GetBitmapNamed(IDR_MAXIMIZE_P));
+ AddChildView(maximize_button_);
+
+ minimize_button_->SetAccessibleName(
+ l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE));
+ minimize_button_->SetImage(CustomButton::BS_NORMAL,
+ rb.GetBitmapNamed(IDR_MINIMIZE));
+ minimize_button_->SetImage(CustomButton::BS_HOT,
+ rb.GetBitmapNamed(IDR_MINIMIZE_H));
+ minimize_button_->SetImage(CustomButton::BS_PUSHED,
+ rb.GetBitmapNamed(IDR_MINIMIZE_P));
+ AddChildView(minimize_button_);
+
+ should_show_minmax_buttons_ = frame_->widget_delegate()->CanMaximize();
+ should_show_client_edge_ = frame_->widget_delegate()->ShouldShowClientEdge();
+
+ if (frame_->widget_delegate()->ShouldShowWindowIcon()) {
+ window_icon_ = new ImageButton(this);
+ AddChildView(window_icon_);
+ }
+}
+
+CustomFrameView::~CustomFrameView() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, NonClientFrameView implementation:
+
+gfx::Rect CustomFrameView::GetBoundsForClientView() const {
+ return client_view_bounds_;
+}
+
+gfx::Rect CustomFrameView::GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const {
+ int top_height = NonClientTopBorderHeight();
+ int border_thickness = NonClientBorderThickness();
+ return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
+ std::max(0, client_bounds.y() - top_height),
+ client_bounds.width() + (2 * border_thickness),
+ client_bounds.height() + top_height + border_thickness);
+}
+
+int CustomFrameView::NonClientHitTest(const gfx::Point& point) {
+ // Sanity check.
+ if (!bounds().Contains(point))
+ return HTNOWHERE;
+
+ int frame_component = frame_->client_view()->NonClientHitTest(point);
+
+ // See if we're in the sysmenu region. (We check the ClientView first to be
+ // consistent with OpaqueBrowserFrameView; it's not really necessary here.)
+ gfx::Rect sysmenu_rect(IconBounds());
+ // In maximized mode we extend the rect to the screen corner to take advantage
+ // of Fitts' Law.
+ if (frame_->IsMaximized())
+ sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom());
+ sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect));
+ if (sysmenu_rect.Contains(point))
+ return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;
+
+ if (frame_component != HTNOWHERE)
+ return frame_component;
+
+ // Then see if the point is within any of the window controls.
+ if (close_button_->GetMirroredBounds().Contains(point))
+ return HTCLOSE;
+ if (restore_button_->GetMirroredBounds().Contains(point))
+ return HTMAXBUTTON;
+ if (maximize_button_->GetMirroredBounds().Contains(point))
+ return HTMAXBUTTON;
+ if (minimize_button_->GetMirroredBounds().Contains(point))
+ return HTMINBUTTON;
+ if (window_icon_ && window_icon_->GetMirroredBounds().Contains(point))
+ return HTSYSMENU;
+
+ int window_component = GetHTComponentForFrame(point, FrameBorderThickness(),
+ NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize,
+ frame_->widget_delegate()->CanResize());
+ // Fall back to the caption if no other component matches.
+ return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
+}
+
+void CustomFrameView::GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) {
+ DCHECK(window_mask);
+ if (frame_->IsMaximized())
+ return;
+
+ views::GetDefaultWindowMask(size, window_mask);
+}
+
+void CustomFrameView::EnableClose(bool enable) {
+ close_button_->SetEnabled(enable);
+}
+
+void CustomFrameView::ResetWindowControls() {
+ restore_button_->SetState(CustomButton::BS_NORMAL);
+ minimize_button_->SetState(CustomButton::BS_NORMAL);
+ maximize_button_->SetState(CustomButton::BS_NORMAL);
+ // The close button isn't affected by this constraint.
+}
+
+void CustomFrameView::UpdateWindowIcon() {
+ window_icon_->SchedulePaint();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, View overrides:
+
+void CustomFrameView::OnPaint(gfx::Canvas* canvas) {
+ if (frame_->IsMaximized())
+ PaintMaximizedFrameBorder(canvas);
+ else
+ PaintRestoredFrameBorder(canvas);
+ PaintTitleBar(canvas);
+ if (ShouldShowClientEdge())
+ PaintRestoredClientEdge(canvas);
+}
+
+void CustomFrameView::Layout() {
+ LayoutWindowControls();
+ LayoutTitleBar();
+ LayoutClientView();
+}
+
+gfx::Size CustomFrameView::GetPreferredSize() {
+ gfx::Size pref = frame_->client_view()->GetPreferredSize();
+ gfx::Rect bounds(0, 0, pref.width(), pref.height());
+ return frame_->non_client_view()->GetWindowBoundsForClientBounds(
+ bounds).size();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, ButtonListener implementation:
+
+void CustomFrameView::ButtonPressed(Button* sender, const views::Event& event) {
+ if (sender == close_button_)
+ frame_->Close();
+ else if (sender == minimize_button_)
+ frame_->Minimize();
+ else if (sender == maximize_button_)
+ frame_->Maximize();
+ else if (sender == restore_button_)
+ frame_->Restore();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, private:
+
+int CustomFrameView::FrameBorderThickness() const {
+ return frame_->IsMaximized() ? 0 : kFrameBorderThickness;
+}
+
+int CustomFrameView::NonClientBorderThickness() const {
+ // In maximized mode, we don't show a client edge.
+ return FrameBorderThickness() +
+ (ShouldShowClientEdge() ? kClientEdgeThickness : 0);
+}
+
+int CustomFrameView::NonClientTopBorderHeight() const {
+ return std::max(FrameBorderThickness() + IconSize(),
+ CaptionButtonY() + kCaptionButtonHeightWithPadding) +
+ TitlebarBottomThickness();
+}
+
+int CustomFrameView::CaptionButtonY() const {
+ // Maximized buttons start at window top so that even if their images aren't
+ // drawn flush with the screen edge, they still obey Fitts' Law.
+ return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness;
+}
+
+int CustomFrameView::TitlebarBottomThickness() const {
+ return kTitlebarTopAndBottomEdgeThickness +
+ (ShouldShowClientEdge() ? kClientEdgeThickness : 0);
+}
+
+int CustomFrameView::IconSize() const {
+#if defined(OS_WIN)
+ // This metric scales up if either the titlebar height or the titlebar font
+ // size are increased.
+ return GetSystemMetrics(SM_CYSMICON);
+#else
+ return std::max(title_font_->GetHeight(), kIconMinimumSize);
+#endif
+}
+
+bool CustomFrameView::ShouldShowClientEdge() const {
+ return should_show_client_edge_ && !frame_->IsMaximized();
+}
+
+gfx::Rect CustomFrameView::IconBounds() const {
+ int size = IconSize();
+ int frame_thickness = FrameBorderThickness();
+ // Our frame border has a different "3D look" than Windows'. Theirs has a
+ // more complex gradient on the top that they push their icon/title below;
+ // then the maximized window cuts this off and the icon/title are centered
+ // in the remaining space. Because the apparent shape of our border is
+ // simpler, using the same positioning makes things look slightly uncentered
+ // with restored windows, so when the window is restored, instead of
+ // calculating the remaining space from below the frame border, we calculate
+ // from below the 3D edge.
+ int unavailable_px_at_top = frame_->IsMaximized() ?
+ frame_thickness : kTitlebarTopAndBottomEdgeThickness;
+ // When the icon is shorter than the minimum space we reserve for the caption
+ // button, we vertically center it. We want to bias rounding to put extra
+ // space above the icon, since the 3D edge (+ client edge, for restored
+ // windows) below looks (to the eye) more like additional space than does the
+ // 3D edge (or nothing at all, for maximized windows) above; hence the +1.
+ int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
+ unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
+ return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
+}
+
+void CustomFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
+ // Window frame mode.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ SkBitmap* frame_image;
+ SkColor frame_color;
+ if (frame_->IsActive()) {
+ frame_image = rb.GetBitmapNamed(IDR_FRAME);
+ frame_color = ResourceBundle::frame_color;
+ } else {
+ frame_image = rb.GetBitmapNamed(IDR_FRAME_INACTIVE);
+ frame_color = ResourceBundle::frame_color_inactive;
+ }
+
+ SkBitmap* top_left_corner = rb.GetBitmapNamed(IDR_WINDOW_TOP_LEFT_CORNER);
+ SkBitmap* top_right_corner =
+ rb.GetBitmapNamed(IDR_WINDOW_TOP_RIGHT_CORNER);
+ SkBitmap* top_edge = rb.GetBitmapNamed(IDR_WINDOW_TOP_CENTER);
+ SkBitmap* right_edge = rb.GetBitmapNamed(IDR_WINDOW_RIGHT_SIDE);
+ SkBitmap* left_edge = rb.GetBitmapNamed(IDR_WINDOW_LEFT_SIDE);
+ SkBitmap* bottom_left_corner =
+ rb.GetBitmapNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER);
+ SkBitmap* bottom_right_corner =
+ rb.GetBitmapNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER);
+ SkBitmap* bottom_edge = rb.GetBitmapNamed(IDR_WINDOW_BOTTOM_CENTER);
+
+ // Fill with the frame color first so we have a constant background for
+ // areas not covered by the theme image.
+ canvas->FillRect(frame_color,
+ gfx::Rect(0, 0, width(), frame_image->height()));
+
+ int remaining_height = height() - frame_image->height();
+ if (remaining_height > 0) {
+ // Now fill down the sides.
+ canvas->FillRect(frame_color,
+ gfx::Rect(0, frame_image->height(), left_edge->width(),
+ remaining_height));
+ canvas->FillRect(frame_color,
+ gfx::Rect(width() - right_edge->width(),
+ frame_image->height(), right_edge->width(),
+ remaining_height));
+ int center_width = width() - left_edge->width() - right_edge->width();
+ if (center_width > 0) {
+ // Now fill the bottom area.
+ canvas->FillRect(frame_color,
+ gfx::Rect(left_edge->width(),
+ height() - bottom_edge->height(),
+ center_width, bottom_edge->height()));
+ }
+ }
+
+ // Draw the theme frame.
+ canvas->TileImageInt(*frame_image, 0, 0, width(), frame_image->height());
+
+ // Top.
+ canvas->DrawBitmapInt(*top_left_corner, 0, 0);
+ canvas->TileImageInt(*top_edge, top_left_corner->width(), 0,
+ width() - top_right_corner->width(), top_edge->height());
+ canvas->DrawBitmapInt(*top_right_corner,
+ width() - top_right_corner->width(), 0);
+
+ // Right.
+ canvas->TileImageInt(*right_edge, width() - right_edge->width(),
+ top_right_corner->height(), right_edge->width(),
+ height() - top_right_corner->height() - bottom_right_corner->height());
+
+ // Bottom.
+ canvas->DrawBitmapInt(*bottom_right_corner,
+ width() - bottom_right_corner->width(),
+ height() - bottom_right_corner->height());
+ canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(),
+ height() - bottom_edge->height(),
+ width() - bottom_left_corner->width() - bottom_right_corner->width(),
+ bottom_edge->height());
+ canvas->DrawBitmapInt(*bottom_left_corner, 0,
+ height() - bottom_left_corner->height());
+
+ // Left.
+ canvas->TileImageInt(*left_edge, 0, top_left_corner->height(),
+ left_edge->width(),
+ height() - top_left_corner->height() - bottom_left_corner->height());
+}
+
+void CustomFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ SkBitmap* frame_image = rb.GetBitmapNamed(frame_->IsActive() ?
+ IDR_FRAME : IDR_FRAME_INACTIVE);
+ canvas->TileImageInt(*frame_image, 0, FrameBorderThickness(), width(),
+ frame_image->height());
+
+ // The bottom of the titlebar actually comes from the top of the Client Edge
+ // graphic, with the actual client edge clipped off the bottom.
+ SkBitmap* titlebar_bottom = rb.GetBitmapNamed(IDR_APP_TOP_CENTER);
+ int edge_height = titlebar_bottom->height() -
+ (ShouldShowClientEdge() ? kClientEdgeThickness : 0);
+ canvas->TileImageInt(*titlebar_bottom, 0,
+ frame_->client_view()->y() - edge_height, width(), edge_height);
+}
+
+void CustomFrameView::PaintTitleBar(gfx::Canvas* canvas) {
+ WidgetDelegate* d = frame_->widget_delegate();
+
+ // It seems like in some conditions we can be asked to paint after the window
+ // that contains us is WM_DESTROYed. At this point, our delegate is NULL. The
+ // correct long term fix may be to shut down the RootView in WM_DESTROY.
+ if (!d)
+ return;
+
+ canvas->DrawStringInt(d->GetWindowTitle(), *title_font_,
+ SK_ColorWHITE, GetMirroredXForRect(title_bounds_),
+ title_bounds_.y(), title_bounds_.width(),
+ title_bounds_.height());
+}
+
+void CustomFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
+ gfx::Rect client_area_bounds = frame_->client_view()->bounds();
+ int client_area_top = client_area_bounds.y();
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SkBitmap* top_left = rb.GetBitmapNamed(IDR_APP_TOP_LEFT);
+ SkBitmap* top = rb.GetBitmapNamed(IDR_APP_TOP_CENTER);
+ SkBitmap* top_right = rb.GetBitmapNamed(IDR_APP_TOP_RIGHT);
+ SkBitmap* right = rb.GetBitmapNamed(IDR_CONTENT_RIGHT_SIDE);
+ SkBitmap* bottom_right =
+ rb.GetBitmapNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER);
+ SkBitmap* bottom = rb.GetBitmapNamed(IDR_CONTENT_BOTTOM_CENTER);
+ SkBitmap* bottom_left =
+ rb.GetBitmapNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
+ SkBitmap* left = rb.GetBitmapNamed(IDR_CONTENT_LEFT_SIDE);
+
+ // Top.
+ int top_edge_y = client_area_top - top->height();
+ canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(),
+ top_edge_y);
+ canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y,
+ client_area_bounds.width(), top->height());
+ canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y);
+
+ // Right.
+ int client_area_bottom =
+ std::max(client_area_top, client_area_bounds.bottom());
+ int client_area_height = client_area_bottom - client_area_top;
+ canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
+ right->width(), client_area_height);
+
+ // Bottom.
+ canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(),
+ client_area_bottom);
+ canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom,
+ client_area_bounds.width(), bottom_right->height());
+ canvas->DrawBitmapInt(*bottom_left,
+ client_area_bounds.x() - bottom_left->width(), client_area_bottom);
+
+ // Left.
+ canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
+ client_area_top, left->width(), client_area_height);
+
+ // Draw the toolbar color to fill in the edges.
+ canvas->DrawRectInt(ResourceBundle::toolbar_color,
+ client_area_bounds.x() - 1, client_area_top - 1,
+ client_area_bounds.width() + 1, client_area_bottom - client_area_top + 1);
+}
+
+void CustomFrameView::LayoutWindowControls() {
+ close_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
+ ImageButton::ALIGN_BOTTOM);
+ int caption_y = CaptionButtonY();
+ bool is_maximized = frame_->IsMaximized();
+ // There should always be the same number of non-shadow pixels visible to the
+ // side of the caption buttons. In maximized mode we extend the rightmost
+ // button to the screen corner to obey Fitts' Law.
+ int right_extra_width = is_maximized ?
+ (kFrameBorderThickness - kFrameShadowThickness) : 0;
+ gfx::Size close_button_size = close_button_->GetPreferredSize();
+ close_button_->SetBounds(width() - FrameBorderThickness() -
+ right_extra_width - close_button_size.width(), caption_y,
+ close_button_size.width() + right_extra_width,
+ close_button_size.height());
+
+ // When the window is restored, we show a maximized button; otherwise, we show
+ // a restore button.
+ bool is_restored = !is_maximized && !frame_->IsMinimized();
+ views::ImageButton* invisible_button = is_restored ?
+ restore_button_ : maximize_button_;
+ invisible_button->SetVisible(false);
+
+ views::ImageButton* visible_button = is_restored ?
+ maximize_button_ : restore_button_;
+ FramePartBitmap normal_part, hot_part, pushed_part;
+ if (should_show_minmax_buttons_) {
+ visible_button->SetVisible(true);
+ visible_button->SetImageAlignment(ImageButton::ALIGN_LEFT,
+ ImageButton::ALIGN_BOTTOM);
+ gfx::Size visible_button_size = visible_button->GetPreferredSize();
+ visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
+ caption_y, visible_button_size.width(),
+ visible_button_size.height());
+
+ minimize_button_->SetVisible(true);
+ minimize_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
+ ImageButton::ALIGN_BOTTOM);
+ gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
+ minimize_button_->SetBounds(
+ visible_button->x() - minimize_button_size.width(), caption_y,
+ minimize_button_size.width(),
+ minimize_button_size.height());
+
+ normal_part = IDR_CLOSE;
+ hot_part = IDR_CLOSE_H;
+ pushed_part = IDR_CLOSE_P;
+ } else {
+ visible_button->SetVisible(false);
+ minimize_button_->SetVisible(false);
+
+ normal_part = IDR_CLOSE_SA;
+ hot_part = IDR_CLOSE_SA_H;
+ pushed_part = IDR_CLOSE_SA_P;
+ }
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ close_button_->SetImage(CustomButton::BS_NORMAL,
+ rb.GetBitmapNamed(normal_part));
+ close_button_->SetImage(CustomButton::BS_HOT,
+ rb.GetBitmapNamed(hot_part));
+ close_button_->SetImage(CustomButton::BS_PUSHED,
+ rb.GetBitmapNamed(pushed_part));
+}
+
+void CustomFrameView::LayoutTitleBar() {
+ // The window title is based on the calculated icon position, even when there
+ // is no icon.
+ gfx::Rect icon_bounds(IconBounds());
+ if (frame_->widget_delegate()->ShouldShowWindowIcon())
+ window_icon_->SetBoundsRect(icon_bounds);
+
+ // Size the title.
+ int title_x = frame_->widget_delegate()->ShouldShowWindowIcon() ?
+ icon_bounds.right() + kIconTitleSpacing : icon_bounds.x();
+ int title_height = title_font_->GetHeight();
+ // We bias the title position so that when the difference between the icon and
+ // title heights is odd, the extra pixel of the title is above the vertical
+ // midline rather than below. This compensates for how the icon is already
+ // biased downwards (see IconBounds()) and helps prevent descenders on the
+ // title from overlapping the 3D edge at the bottom of the titlebar.
+ title_bounds_.SetRect(title_x,
+ icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
+ std::max(0, (should_show_minmax_buttons_ ?
+ minimize_button_->x() : close_button_->x()) - kTitleCaptionSpacing -
+ title_x), title_height);
+}
+
+void CustomFrameView::LayoutClientView() {
+ int top_height = NonClientTopBorderHeight();
+ int border_thickness = NonClientBorderThickness();
+ client_view_bounds_.SetRect(border_thickness, top_height,
+ std::max(0, width() - (2 * border_thickness)),
+ std::max(0, height() - top_height - border_thickness));
+}
+
+// static
+void CustomFrameView::InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+#if defined(USE_AURA)
+ title_font_ = new gfx::Font(NativeWidgetAura::GetWindowTitleFont());
+#elif defined(OS_WIN)
+ title_font_ = new gfx::Font(NativeWidgetWin::GetWindowTitleFont());
+#elif defined(OS_LINUX)
+ // TODO(ben): need to resolve what font this is.
+ title_font_ = new gfx::Font();
+#endif
+ initialized = true;
+ }
+}
+
+} // namespace views
diff --git a/ui/views/window/custom_frame_view.h b/ui/views/window/custom_frame_view.h
new file mode 100644
index 0000000..8a04dd4
--- /dev/null
+++ b/ui/views/window/custom_frame_view.h
@@ -0,0 +1,127 @@
+// 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_VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_
+#define UI_VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_
+#pragma once
+
+#include "views/controls/button/image_button.h"
+#include "views/widget/widget.h"
+#include "views/window/non_client_view.h"
+
+namespace gfx {
+class Canvas;
+class Font;
+class Size;
+class Path;
+class Point;
+}
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CustomFrameView
+//
+// A ChromeView that provides the non client frame for Windows. This means
+// rendering the non-standard window caption, border, and controls.
+//
+////////////////////////////////////////////////////////////////////////////////
+class CustomFrameView : public NonClientFrameView,
+ public ButtonListener {
+ public:
+ explicit CustomFrameView(Widget* frame);
+ virtual ~CustomFrameView();
+
+ // Overridden from 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;
+
+ // View overrides:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void Layout() OVERRIDE;
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ // ButtonListener implementation:
+ virtual void ButtonPressed(Button* sender, const views::Event& event)
+ OVERRIDE;
+
+ private:
+ // Returns the thickness of the border that makes up the window frame edges.
+ // This does not include any client edge.
+ int FrameBorderThickness() const;
+
+ // Returns the thickness of the entire nonclient left, right, and bottom
+ // borders, including both the window frame and any client edge.
+ int NonClientBorderThickness() const;
+
+ // Returns the height of the entire nonclient top border, including the window
+ // frame, any title area, and any connected client edge.
+ int NonClientTopBorderHeight() const;
+
+ // Returns the y-coordinate of the caption buttons.
+ int CaptionButtonY() const;
+
+ // Returns the thickness of the nonclient portion of the 3D edge along the
+ // bottom of the titlebar.
+ int TitlebarBottomThickness() const;
+
+ // Returns the size of the titlebar icon. This is used even when the icon is
+ // not shown, e.g. to set the titlebar height.
+ int IconSize() const;
+
+ // Returns the bounds of the titlebar icon (or where the icon would be if
+ // there was one).
+ gfx::Rect IconBounds() const;
+
+ // Returns true if the client edge should be drawn. This is true if
+ // the window delegate wants a client edge and we are not maxmized.
+ bool ShouldShowClientEdge() const;
+
+ // Paint various sub-components of this view.
+ void PaintRestoredFrameBorder(gfx::Canvas* canvas);
+ void PaintMaximizedFrameBorder(gfx::Canvas* canvas);
+ void PaintTitleBar(gfx::Canvas* canvas);
+ void PaintRestoredClientEdge(gfx::Canvas* canvas);
+
+ // Layout various sub-components of this view.
+ void LayoutWindowControls();
+ void LayoutTitleBar();
+ void LayoutClientView();
+
+ // The bounds of the client view, in this view's coordinates.
+ gfx::Rect client_view_bounds_;
+
+ // The layout rect of the title, if visible.
+ gfx::Rect title_bounds_;
+
+ // Window controls.
+ ImageButton* close_button_;
+ ImageButton* restore_button_;
+ ImageButton* maximize_button_;
+ ImageButton* minimize_button_;
+ ImageButton* window_icon_;
+ bool should_show_minmax_buttons_;
+ bool should_show_client_edge_;
+
+ // The window that owns this view.
+ Widget* frame_;
+
+ // Initialize various static resources.
+ static void InitClass();
+ static gfx::Font* title_font_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomFrameView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc
new file mode 100644
index 0000000..f0abe6f
--- /dev/null
+++ b/ui/views/window/dialog_client_view.cc
@@ -0,0 +1,591 @@
+// 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 "views/window/dialog_client_view.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <uxtheme.h>
+#include <vsstyle.h>
+#elif defined(TOOLKIT_USES_GTK)
+#include <gtk/gtk.h>
+#endif
+
+#include <algorithm>
+
+#include "base/utf_string_conversions.h"
+#include "grit/ui_strings.h"
+#include "ui/base/hit_test.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/font.h"
+#include "views/controls/button/text_button.h"
+#include "views/layout/layout_constants.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+#include "views/window/dialog_delegate.h"
+
+#if defined(OS_WIN)
+#include "ui/gfx/native_theme.h"
+#else
+#include "ui/gfx/skia_utils_gtk.h"
+#endif
+
+namespace views {
+namespace {
+
+// Updates any of the standard buttons according to the delegate.
+void UpdateButtonHelper(NativeTextButton* button_view,
+ DialogDelegate* delegate,
+ ui::DialogButton button) {
+ string16 label = delegate->GetDialogButtonLabel(button);
+ if (!label.empty())
+ button_view->SetText(label);
+ button_view->SetEnabled(delegate->IsDialogButtonEnabled(button));
+ button_view->SetVisible(delegate->IsDialogButtonVisible(button));
+}
+
+#if defined(OS_WIN)
+void FillViewWithSysColor(gfx::Canvas* canvas, View* view, COLORREF color) {
+ SkColor sk_color =
+ SkColorSetRGB(GetRValue(color), GetGValue(color), GetBValue(color));
+ canvas->FillRect(sk_color, view->GetLocalBounds());
+}
+#endif
+
+// DialogButton ----------------------------------------------------------------
+
+// DialogButtons is used for the ok/cancel buttons of the window. DialogButton
+// forwards AcceleratorPressed to the delegate.
+
+class DialogButton : public NativeTextButton {
+ public:
+ DialogButton(ButtonListener* listener,
+ Widget* owner,
+ ui::DialogButton type,
+ const string16& title,
+ bool is_default)
+ : NativeTextButton(listener, title),
+ owner_(owner),
+ type_(type) {
+ SetIsDefault(is_default);
+ }
+
+ // Overridden to forward to the delegate.
+ virtual bool AcceleratorPressed(const Accelerator& accelerator) {
+ if (!owner_->widget_delegate()->AsDialogDelegate()->
+ AreAcceleratorsEnabled(type_)) {
+ return false;
+ }
+ return NativeTextButton::AcceleratorPressed(accelerator);
+ }
+
+ private:
+ Widget* owner_;
+ const ui::DialogButton type_;
+
+ DISALLOW_COPY_AND_ASSIGN(DialogButton);
+};
+
+} // namespace
+
+// static
+gfx::Font* DialogClientView::dialog_button_font_ = NULL;
+static const int kDialogMinButtonWidth = 75;
+static const int kDialogButtonLabelSpacing = 16;
+static const int kDialogButtonContentSpacing = 5;
+
+// The group used by the buttons. This name is chosen voluntarily big not to
+// conflict with other groups that could be in the dialog content.
+static const int kButtonGroup = 6666;
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView, public:
+
+DialogClientView::DialogClientView(Widget* owner, View* contents_view)
+ : ClientView(owner, contents_view),
+ ok_button_(NULL),
+ cancel_button_(NULL),
+ default_button_(NULL),
+ extra_view_(NULL),
+ size_extra_view_height_to_buttons_(false),
+ notified_delegate_(false),
+ listening_to_focus_(false),
+ saved_focus_manager_(NULL),
+ bottom_view_(NULL) {
+ InitClass();
+}
+
+DialogClientView::~DialogClientView() {
+}
+
+void DialogClientView::ShowDialogButtons() {
+ DialogDelegate* dd = GetDialogDelegate();
+ int buttons = dd->GetDialogButtons();
+ if (buttons & ui::DIALOG_BUTTON_OK && !ok_button_) {
+ string16 label = dd->GetDialogButtonLabel(ui::DIALOG_BUTTON_OK);
+ if (label.empty())
+ label = l10n_util::GetStringUTF16(IDS_APP_OK);
+ bool is_default_button =
+ (dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_OK) != 0;
+ ok_button_ = new DialogButton(this,
+ GetWidget(),
+ ui::DIALOG_BUTTON_OK,
+ label,
+ is_default_button);
+ ok_button_->SetGroup(kButtonGroup);
+ if (is_default_button)
+ default_button_ = ok_button_;
+ if (!(buttons & ui::DIALOG_BUTTON_CANCEL))
+ ok_button_->AddAccelerator(Accelerator(ui::VKEY_ESCAPE,
+ false, false, false));
+ AddChildView(ok_button_);
+ }
+ if (buttons & ui::DIALOG_BUTTON_CANCEL && !cancel_button_) {
+ string16 label =
+ dd->GetDialogButtonLabel(ui::DIALOG_BUTTON_CANCEL);
+ if (label.empty()) {
+ if (buttons & ui::DIALOG_BUTTON_OK) {
+ label = l10n_util::GetStringUTF16(IDS_APP_CANCEL);
+ } else {
+ label = l10n_util::GetStringUTF16(IDS_APP_CLOSE);
+ }
+ }
+ bool is_default_button =
+ (dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_CANCEL)
+ != 0;
+ cancel_button_ = new DialogButton(this,
+ GetWidget(),
+ ui::DIALOG_BUTTON_CANCEL,
+ label,
+ is_default_button);
+ cancel_button_->SetGroup(kButtonGroup);
+ cancel_button_->AddAccelerator(Accelerator(ui::VKEY_ESCAPE,
+ false, false, false));
+ if (is_default_button)
+ default_button_ = ok_button_;
+ AddChildView(cancel_button_);
+ }
+ if (!buttons) {
+ // Register the escape key as an accelerator which will close the window
+ // if there are no dialog buttons.
+ AddAccelerator(Accelerator(ui::VKEY_ESCAPE, false, false, false));
+ }
+}
+
+void DialogClientView::SetDefaultButton(NativeTextButton* new_default_button) {
+ if (default_button_ && default_button_ != new_default_button) {
+ default_button_->SetIsDefault(false);
+ default_button_ = NULL;
+ }
+
+ if (new_default_button) {
+ default_button_ = new_default_button;
+ default_button_->SetIsDefault(true);
+ }
+}
+
+void DialogClientView::OnWillChangeFocus(View* focused_before,
+ View* focused_now) {
+ NativeTextButton* new_default_button = NULL;
+ if (focused_now &&
+ focused_now->GetClassName() == NativeTextButton::kViewClassName) {
+ new_default_button = static_cast<NativeTextButton*>(focused_now);
+ } else {
+ // The focused view is not a button, get the default button from the
+ // delegate.
+ DialogDelegate* dd = GetDialogDelegate();
+ if ((dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_OK) != 0)
+ new_default_button = ok_button_;
+ if ((dd->GetDefaultDialogButton() & ui::DIALOG_BUTTON_CANCEL)
+ != 0)
+ new_default_button = cancel_button_;
+ }
+ SetDefaultButton(new_default_button);
+}
+
+void DialogClientView::OnDidChangeFocus(View* focused_before,
+ View* focused_now) {
+}
+
+// Changing dialog labels will change button widths.
+void DialogClientView::UpdateDialogButtons() {
+ DialogDelegate* dd = GetDialogDelegate();
+ int buttons = dd->GetDialogButtons();
+
+ if (buttons & ui::DIALOG_BUTTON_OK)
+ UpdateButtonHelper(ok_button_, dd, ui::DIALOG_BUTTON_OK);
+
+ if (buttons & ui::DIALOG_BUTTON_CANCEL) {
+ UpdateButtonHelper(cancel_button_, dd, ui::DIALOG_BUTTON_CANCEL);
+ }
+
+ LayoutDialogButtons();
+ SchedulePaint();
+}
+
+void DialogClientView::AcceptWindow() {
+ if (notified_delegate_) {
+ // Only notify the delegate once. See comment in header above
+ // notified_delegate_ for details.
+ return;
+ }
+ if (GetDialogDelegate()->Accept(false)) {
+ notified_delegate_ = true;
+ Close();
+ }
+}
+
+void DialogClientView::CancelWindow() {
+ // Call the standard Close handler, which checks with the delegate before
+ // proceeding. This checking _isn't_ done here, but in the WM_CLOSE handler,
+ // so that the close box on the window also shares this code path.
+ Close();
+}
+
+void DialogClientView::SetBottomView(View* bottom_view) {
+ if (bottom_view_) {
+ RemoveChildView(bottom_view_);
+ delete bottom_view_;
+ }
+ bottom_view_ = bottom_view;
+ if (bottom_view_)
+ AddChildView(bottom_view_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView, View overrides:
+
+void DialogClientView::NativeViewHierarchyChanged(
+ bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view) {
+ if (attached) {
+ UpdateFocusListener();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView, ClientView overrides:
+
+bool DialogClientView::CanClose() {
+ if (notified_delegate_)
+ return true;
+
+ DialogDelegate* dd = GetDialogDelegate();
+ int buttons = dd->GetDialogButtons();
+ bool close = true;
+ if (buttons & ui::DIALOG_BUTTON_CANCEL)
+ close = dd->Cancel();
+ else if (buttons & ui::DIALOG_BUTTON_OK)
+ close = dd->Accept(true);
+ notified_delegate_ = close;
+ return close;
+}
+
+void DialogClientView::WidgetClosing() {
+ if (listening_to_focus_) {
+ DCHECK(saved_focus_manager_);
+ if (saved_focus_manager_)
+ saved_focus_manager_->RemoveFocusChangeListener(this);
+ }
+}
+
+int DialogClientView::NonClientHitTest(const gfx::Point& point) {
+ if (size_box_bounds_.Contains(point.x() - x(), point.y() - y()))
+ return HTBOTTOMRIGHT;
+ return ClientView::NonClientHitTest(point);
+}
+
+DialogClientView* DialogClientView::AsDialogClientView() {
+ return this;
+}
+
+const DialogClientView* DialogClientView::AsDialogClientView() const {
+ return this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogClientView, View overrides:
+
+void DialogClientView::OnPaint(gfx::Canvas* canvas) {
+#if defined(OS_WIN)
+ FillViewWithSysColor(canvas, this, GetSysColor(COLOR_3DFACE));
+#elif defined(USE_WAYLAND) || defined(USE_AURA)
+ SkColor sk_color = SkColorSetARGB(200, 255, 255, 255);
+ canvas->FillRect(sk_color, GetLocalBounds());
+#else
+ GtkWidget* widget = GetWidget()->GetNativeView();
+ if (GTK_IS_WINDOW(widget)) {
+ GtkStyle* window_style = gtk_widget_get_style(widget);
+ canvas->FillRect(gfx::GdkColorToSkColor(window_style->bg[GTK_STATE_NORMAL]),
+ GetLocalBounds());
+ }
+#endif
+}
+
+void DialogClientView::PaintChildren(gfx::Canvas* canvas) {
+ View::PaintChildren(canvas);
+ if (!GetWidget()->IsMaximized() && !GetWidget()->IsMinimized())
+ PaintSizeBox(canvas);
+}
+
+void DialogClientView::Layout() {
+ if (has_dialog_buttons())
+ LayoutDialogButtons();
+ if (bottom_view_) {
+ gfx::Rect bounds = GetContentsBounds();
+ gfx::Size pref = bottom_view_->GetPreferredSize();
+ bottom_view_->SetBounds(bounds.x(),
+ bounds.bottom() - pref.height() - kButtonVEdgeMargin,
+ bounds.width(), pref.height());
+ }
+ LayoutContentsView();
+}
+
+void DialogClientView::ViewHierarchyChanged(bool is_add, View* parent,
+ View* child) {
+ if (is_add && child == this) {
+ // Can only add and update the dialog buttons _after_ they are added to the
+ // view hierarchy since they are native controls and require the
+ // Container's HWND.
+ ShowDialogButtons();
+ ClientView::ViewHierarchyChanged(is_add, parent, child);
+
+ UpdateFocusListener();
+
+ // The "extra view" must be created and installed after the contents view
+ // has been inserted into the view hierarchy.
+ CreateExtraView();
+ UpdateDialogButtons();
+ Layout();
+ }
+}
+
+gfx::Size DialogClientView::GetPreferredSize() {
+ gfx::Size prefsize = contents_view()->GetPreferredSize();
+ int button_height = 0;
+ if (has_dialog_buttons()) {
+ if (cancel_button_)
+ button_height = cancel_button_->height();
+ else
+ button_height = ok_button_->height();
+ // Account for padding above and below the button.
+ button_height += kDialogButtonContentSpacing + kButtonVEdgeMargin;
+
+ // Make sure the view is sized to the buttons's width if they are wider than
+ // the contents.
+ int width = 0;
+ if (cancel_button_)
+ width += GetButtonWidth(ui::DIALOG_BUTTON_CANCEL);
+ if (ok_button_) {
+ width += GetButtonWidth(ui::DIALOG_BUTTON_OK);
+ if (cancel_button_)
+ width += kRelatedButtonHSpacing;
+ }
+ if (extra_view_) {
+ width += extra_view_->GetPreferredSize().width();
+ if (cancel_button_ || ok_button_)
+ width += kRelatedButtonHSpacing;
+ }
+ if (width > 0) {
+ width += 2 * kButtonHEdgeMargin;
+ prefsize.set_width(std::max(prefsize.width(), width));
+ }
+ }
+ if (bottom_view_) {
+ gfx::Size bottom_pref = bottom_view_->GetPreferredSize();
+ prefsize.Enlarge(0, bottom_pref.height() + kButtonVEdgeMargin);
+ }
+ prefsize.Enlarge(0, button_height);
+ return prefsize;
+}
+
+bool DialogClientView::AcceleratorPressed(const Accelerator& accelerator) {
+ // We only expect Escape key.
+ DCHECK(accelerator.key_code() == ui::VKEY_ESCAPE);
+ Close();
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogClientView, ButtonListener implementation:
+
+void DialogClientView::ButtonPressed(
+ Button* sender, const views::Event& event) {
+ // We NULL check the delegate here since the buttons can receive WM_COMMAND
+ // messages even after they (and the window containing us) are destroyed.
+ if (!GetDialogDelegate())
+ return;
+
+ if (sender == ok_button_) {
+ AcceptWindow();
+ } else if (sender == cancel_button_) {
+ CancelWindow();
+ } else {
+ NOTREACHED();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogClientView, private:
+
+void DialogClientView::PaintSizeBox(gfx::Canvas* canvas) {
+ if (GetWidget()->widget_delegate()->CanResize() ||
+ GetWidget()->widget_delegate()->CanMaximize()) {
+#if defined(OS_WIN)
+ gfx::NativeTheme::ExtraParams extra;
+ gfx::Size gripper_size = gfx::NativeTheme::instance()->GetPartSize(
+ gfx::NativeTheme::kWindowResizeGripper, gfx::NativeTheme::kNormal,
+ extra);
+
+ // TODO(beng): (http://b/1085509) In "classic" rendering mode, there isn't
+ // a theme-supplied gripper. We should probably improvise
+ // something, which would also require changing |gripper_size|
+ // to have different default values, too...
+ size_box_bounds_ = GetContentsBounds();
+ size_box_bounds_.set_x(size_box_bounds_.right() - gripper_size.width());
+ size_box_bounds_.set_y(size_box_bounds_.bottom() - gripper_size.height());
+
+ gfx::NativeTheme::instance()->Paint(canvas->GetSkCanvas(),
+ gfx::NativeTheme::kWindowResizeGripper,
+ gfx::NativeTheme::kNormal,
+ size_box_bounds_,
+ extra);
+#else
+ NOTIMPLEMENTED();
+ // TODO(port): paint size box
+#endif
+ }
+}
+
+int DialogClientView::GetButtonWidth(int button) const {
+ DialogDelegate* dd = GetDialogDelegate();
+ string16 button_label = dd->GetDialogButtonLabel(
+ static_cast<ui::DialogButton>(button));
+ int string_width = dialog_button_font_->GetStringWidth(button_label);
+ return std::max(string_width + kDialogButtonLabelSpacing,
+ kDialogMinButtonWidth);
+}
+
+int DialogClientView::GetButtonsHeight() const {
+ if (has_dialog_buttons()) {
+ if (cancel_button_)
+ return cancel_button_->height() + kDialogButtonContentSpacing;
+ return ok_button_->height() + kDialogButtonContentSpacing;
+ }
+ return 0;
+}
+
+void DialogClientView::LayoutDialogButtons() {
+ gfx::Rect lb = GetContentsBounds();
+ gfx::Rect extra_bounds;
+ int bottom_y = lb.bottom() - kButtonVEdgeMargin;
+ int button_height = 0;
+ if (bottom_view_) {
+ gfx::Size bottom_pref = bottom_view_->GetPreferredSize();
+ bottom_y -= bottom_pref.height() + kButtonVEdgeMargin + kButtonVEdgeMargin;
+ }
+ if (cancel_button_) {
+ gfx::Size ps = cancel_button_->GetPreferredSize();
+ int button_width = std::max(
+ GetButtonWidth(ui::DIALOG_BUTTON_CANCEL), ps.width());
+ int button_x = lb.right() - button_width - kButtonHEdgeMargin;
+ int button_y = bottom_y - ps.height();
+ cancel_button_->SetBounds(button_x, button_y, button_width, ps.height());
+ // The extra view bounds are dependent on this button.
+ extra_bounds.set_width(std::max(0, cancel_button_->x()));
+ extra_bounds.set_y(cancel_button_->y());
+ button_height = std::max(button_height, ps.height());
+ }
+ if (ok_button_) {
+ gfx::Size ps = ok_button_->GetPreferredSize();
+ int button_width = std::max(
+ GetButtonWidth(ui::DIALOG_BUTTON_OK), ps.width());
+ int ok_button_right = lb.right() - kButtonHEdgeMargin;
+ if (cancel_button_)
+ ok_button_right = cancel_button_->x() - kRelatedButtonHSpacing;
+ int button_x = ok_button_right - button_width;
+ int button_y = bottom_y - ps.height();
+ ok_button_->SetBounds(button_x, button_y, ok_button_right - button_x,
+ ps.height());
+ // The extra view bounds are dependent on this button.
+ extra_bounds.set_width(std::max(0, ok_button_->x()));
+ extra_bounds.set_y(ok_button_->y());
+ button_height = std::max(button_height, ps.height());
+ }
+ if (extra_view_) {
+ gfx::Size ps = extra_view_->GetPreferredSize();
+ extra_bounds.set_x(lb.x() + kButtonHEdgeMargin);
+ int height = size_extra_view_height_to_buttons_ ?
+ std::max(ps.height(), button_height) : ps.height();
+ extra_bounds.set_height(height);
+ extra_view_->SetBoundsRect(extra_bounds);
+ }
+}
+
+void DialogClientView::LayoutContentsView() {
+ gfx::Rect lb = GetContentsBounds();
+ lb.set_height(std::max(0, lb.height() - GetButtonsHeight()));
+ contents_view()->SetBoundsRect(lb);
+ contents_view()->Layout();
+}
+
+void DialogClientView::CreateExtraView() {
+ View* extra_view = GetDialogDelegate()->GetExtraView();
+ if (extra_view && !extra_view_) {
+ extra_view_ = extra_view;
+ extra_view_->SetGroup(kButtonGroup);
+ AddChildView(extra_view_);
+ size_extra_view_height_to_buttons_ =
+ GetDialogDelegate()->GetSizeExtraViewHeightToButtons();
+ }
+}
+
+DialogDelegate* DialogClientView::GetDialogDelegate() const {
+ return GetWidget()->widget_delegate()->AsDialogDelegate();
+}
+
+void DialogClientView::Close() {
+ GetWidget()->Close();
+ GetDialogDelegate()->OnClose();
+}
+
+void DialogClientView::UpdateFocusListener() {
+ FocusManager* focus_manager = GetFocusManager();
+ // Listen for focus change events so we can update the default button.
+ // focus_manager can be NULL when the dialog is created on un-shown view.
+ // We start listening for focus changes when the page is visible.
+ // Focus manager could also change if window host changes a parent.
+ if (listening_to_focus_) {
+ if (saved_focus_manager_ == focus_manager)
+ return;
+ DCHECK(saved_focus_manager_);
+ if (saved_focus_manager_)
+ saved_focus_manager_->RemoveFocusChangeListener(this);
+ listening_to_focus_ = false;
+ }
+ saved_focus_manager_ = focus_manager;
+ // Listen for focus change events so we can update the default button.
+ if (focus_manager) {
+ focus_manager->AddFocusChangeListener(this);
+ listening_to_focus_ = true;
+ }
+}
+
+// static
+void DialogClientView::InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ dialog_button_font_ = new gfx::Font(rb.GetFont(ResourceBundle::BaseFont));
+ initialized = true;
+ }
+}
+
+} // namespace views
diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h
new file mode 100644
index 0000000..093815b
--- /dev/null
+++ b/ui/views/window/dialog_client_view.h
@@ -0,0 +1,170 @@
+// 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_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
+#define UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
+#pragma once
+
+#include "ui/gfx/font.h"
+#include "views/focus/focus_manager.h"
+#include "views/controls/button/button.h"
+#include "views/window/client_view.h"
+
+namespace views {
+
+class DialogDelegate;
+class NativeTextButton;
+class Widget;
+namespace internal {
+class RootView;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView
+//
+// This ClientView subclass provides the content of a typical dialog box,
+// including a strip of buttons at the bottom right of the window, default
+// accelerator handlers for accept and cancel, and the ability for the
+// embedded contents view to provide extra UI to be shown in the row of
+// buttons.
+//
+// DialogClientView also provides the ability to set an arbitrary view that is
+// positioned beneath the buttons.
+//
+class VIEWS_EXPORT DialogClientView : public ClientView,
+ public ButtonListener,
+ public FocusChangeListener {
+ public:
+ DialogClientView(Widget* widget, View* contents_view);
+ virtual ~DialogClientView();
+
+ // Adds the dialog buttons required by the supplied DialogDelegate to the
+ // view.
+ void ShowDialogButtons();
+
+ // Updates the enabled state and label of the buttons required by the
+ // supplied DialogDelegate
+ void UpdateDialogButtons();
+
+ // Accept the changes made in the window that contains this ClientView.
+ void AcceptWindow();
+
+ // Cancel the changes made in the window that contains this ClientView.
+ void CancelWindow();
+
+ // Accessors in case the user wishes to adjust these buttons.
+ NativeTextButton* ok_button() const { return ok_button_; }
+ NativeTextButton* cancel_button() const { return cancel_button_; }
+
+ // Sets the view that is positioned along the bottom of the buttons. The
+ // bottom view is positioned beneath the buttons at the full width of the
+ // dialog. If there is an existing bottom view it is removed and deleted.
+ void SetBottomView(View* bottom_view);
+
+ // Overridden from View:
+ virtual void NativeViewHierarchyChanged(
+ bool attached,
+ gfx::NativeView native_view,
+ internal::RootView* root_view) OVERRIDE;
+
+ // Overridden from ClientView:
+ virtual bool CanClose() OVERRIDE;
+ virtual void WidgetClosing() OVERRIDE;
+ virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
+ virtual DialogClientView* AsDialogClientView() OVERRIDE;
+ virtual const DialogClientView* AsDialogClientView() const OVERRIDE;
+
+ // FocusChangeListener implementation:
+ virtual void OnWillChangeFocus(View* focused_before,
+ View* focused_now) OVERRIDE;
+ virtual void OnDidChangeFocus(View* focused_before,
+ View* focused_now) OVERRIDE;
+
+ protected:
+ // View overrides:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual void PaintChildren(gfx::Canvas* canvas) OVERRIDE;
+ virtual void Layout() OVERRIDE;
+ virtual void ViewHierarchyChanged(bool is_add, View* parent,
+ View* child) OVERRIDE;
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual bool AcceleratorPressed(const Accelerator& accelerator) OVERRIDE;
+
+ // ButtonListener implementation:
+ virtual void ButtonPressed(Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ private:
+ // Paint the size box in the bottom right corner of the window if it is
+ // resizable.
+ void PaintSizeBox(gfx::Canvas* canvas);
+
+ // Returns the width of the specified dialog button using the correct font.
+ int GetButtonWidth(int button) const;
+ int GetButtonsHeight() const;
+
+ // Position and size various sub-views.
+ void LayoutDialogButtons();
+ void LayoutContentsView();
+
+ // Makes the specified button the default button.
+ void SetDefaultButton(NativeTextButton* button);
+
+ bool has_dialog_buttons() const { return ok_button_ || cancel_button_; }
+
+ // Create and add the extra view, if supplied by the delegate.
+ void CreateExtraView();
+
+ // Returns the DialogDelegate for the window.
+ DialogDelegate* GetDialogDelegate() const;
+
+ // Closes the widget.
+ void Close();
+
+ // Updates focus listener.
+ void UpdateFocusListener();
+
+ static void InitClass();
+
+ // The dialog buttons.
+ NativeTextButton* ok_button_;
+ NativeTextButton* cancel_button_;
+
+ // The button that is currently the default button if any.
+ NativeTextButton* default_button_;
+
+ // The button-level extra view, NULL unless the dialog delegate supplies one.
+ View* extra_view_;
+
+ // See description of DialogDelegate::GetSizeExtraViewHeightToButtons for
+ // details on this.
+ bool size_extra_view_height_to_buttons_;
+
+ // The layout rect of the size box, when visible.
+ gfx::Rect size_box_bounds_;
+
+ // True if we've notified the delegate the window is closing and the delegate
+ // allosed the close. In some situations it's possible to get two closes (see
+ // http://crbug.com/71940). This is used to avoid notifying the delegate
+ // twice, which can have bad consequences.
+ bool notified_delegate_;
+
+ // true if focus listener is added.
+ bool listening_to_focus_;
+
+ // When ancestor gets changed focus manager gets changed as well.
+ FocusManager* saved_focus_manager_;
+
+ // View positioned along the bottom, beneath the buttons.
+ View* bottom_view_;
+
+ // Static resource initialization
+ static gfx::Font* dialog_button_font_;
+
+ DISALLOW_COPY_AND_ASSIGN(DialogClientView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
new file mode 100644
index 0000000..fc24f90
--- /dev/null
+++ b/ui/views/window/dialog_delegate.cc
@@ -0,0 +1,121 @@
+// 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 "views/window/dialog_delegate.h"
+
+#include "base/logging.h"
+#include "views/controls/button/text_button.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogDelegate:
+
+DialogDelegate* DialogDelegate::AsDialogDelegate() { return this; }
+
+int DialogDelegate::GetDialogButtons() const {
+ return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
+}
+
+int DialogDelegate::GetDefaultDialogButton() const {
+ if (GetDialogButtons() & ui::DIALOG_BUTTON_OK)
+ return ui::DIALOG_BUTTON_OK;
+ if (GetDialogButtons() & ui::DIALOG_BUTTON_CANCEL)
+ return ui::DIALOG_BUTTON_CANCEL;
+ return ui::DIALOG_BUTTON_NONE;
+}
+
+string16 DialogDelegate::GetDialogButtonLabel(ui::DialogButton button) const {
+ // Empty string results in defaults for
+ // ui::DIALOG_BUTTON_OK or ui::DIALOG_BUTTON_CANCEL.
+ return string16();
+}
+
+bool DialogDelegate::IsDialogButtonEnabled(ui::DialogButton button) const {
+ return true;
+}
+
+bool DialogDelegate::IsDialogButtonVisible(ui::DialogButton button) const {
+ return true;
+}
+
+bool DialogDelegate::AreAcceleratorsEnabled(ui::DialogButton button) {
+ return true;
+}
+
+View* DialogDelegate::GetExtraView() {
+ return NULL;
+}
+
+bool DialogDelegate::GetSizeExtraViewHeightToButtons() {
+ return false;
+}
+
+bool DialogDelegate::Cancel() {
+ return true;
+}
+
+bool DialogDelegate::Accept(bool window_closiang) {
+ return Accept();
+}
+
+bool DialogDelegate::Accept() {
+ return true;
+}
+
+View* DialogDelegate::GetInitiallyFocusedView() {
+ // Focus the default button if any.
+ const DialogClientView* dcv = GetDialogClientView();
+ int default_button = GetDefaultDialogButton();
+ if (default_button == ui::DIALOG_BUTTON_NONE)
+ return NULL;
+
+ if ((default_button & GetDialogButtons()) == 0) {
+ // The default button is a button we don't have.
+ NOTREACHED();
+ return NULL;
+ }
+
+ if (default_button & ui::DIALOG_BUTTON_OK)
+ return dcv->ok_button();
+ if (default_button & ui::DIALOG_BUTTON_CANCEL)
+ return dcv->cancel_button();
+ return NULL;
+}
+
+ClientView* DialogDelegate::CreateClientView(Widget* widget) {
+ return new DialogClientView(widget, GetContentsView());
+}
+
+const DialogClientView* DialogDelegate::GetDialogClientView() const {
+ return GetWidget()->client_view()->AsDialogClientView();
+}
+
+DialogClientView* DialogDelegate::GetDialogClientView() {
+ return GetWidget()->client_view()->AsDialogClientView();
+}
+
+ui::AccessibilityTypes::Role DialogDelegate::GetAccessibleWindowRole() const {
+ return ui::AccessibilityTypes::ROLE_DIALOG;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogDelegateView:
+
+DialogDelegateView::DialogDelegateView() {
+}
+
+DialogDelegateView::~DialogDelegateView() {
+}
+
+Widget* DialogDelegateView::GetWidget() {
+ return View::GetWidget();
+}
+
+const Widget* DialogDelegateView::GetWidget() const {
+ return View::GetWidget();
+}
+
+} // namespace views
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
new file mode 100644
index 0000000..75b9d5f
--- /dev/null
+++ b/ui/views/window/dialog_delegate.h
@@ -0,0 +1,128 @@
+// 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_VIEWS_WINDOW_DIALOG_DELEGATE_H_
+#define UI_VIEWS_WINDOW_DIALOG_DELEGATE_H_
+#pragma once
+
+#include "base/string16.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/ui_base_types.h"
+#include "views/widget/widget_delegate.h"
+#include "views/window/dialog_client_view.h"
+
+namespace views {
+
+class View;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DialogDelegate
+//
+// DialogDelegate is an interface implemented by objects that wish to show a
+// dialog box Window. The window that is displayed uses this interface to
+// determine how it should be displayed and notify the delegate object of
+// certain events.
+//
+///////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
+ public:
+ virtual DialogDelegate* AsDialogDelegate();
+
+ // Returns a mask specifying which of the available DialogButtons are visible
+ // for the dialog. Note: If an OK button is provided, you should provide a
+ // CANCEL button. A dialog box with just an OK button is frowned upon and
+ // considered a very special case, so if you're planning on including one,
+ // you should reconsider, or beng says there will be stabbings.
+ //
+ // To use the extra button you need to override GetDialogButtons()
+ virtual int GetDialogButtons() const;
+
+ // Returns the default dialog button. This should not be a mask as only
+ // one button should ever be the default button. Return
+ // ui::DIALOG_BUTTON_NONE if there is no default. Default
+ // behavior is to return ui::DIALOG_BUTTON_OK or
+ // ui::DIALOG_BUTTON_CANCEL (in that order) if they are
+ // present, ui::DIALOG_BUTTON_NONE otherwise.
+ virtual int GetDefaultDialogButton() const;
+
+ // Returns the label of the specified dialog button.
+ virtual string16 GetDialogButtonLabel(ui::DialogButton button) const;
+
+ // Returns whether the specified dialog button is enabled.
+ virtual bool IsDialogButtonEnabled(ui::DialogButton button) const;
+
+ // Returns whether the specified dialog button is visible.
+ virtual bool IsDialogButtonVisible(ui::DialogButton button) const;
+
+ // Returns whether accelerators are enabled on the button. This is invoked
+ // when an accelerator is pressed, not at construction time. This
+ // returns true.
+ virtual bool AreAcceleratorsEnabled(ui::DialogButton button);
+
+ // Override this function if with a view which will be shown in the same
+ // row as the OK and CANCEL buttons but flush to the left and extending
+ // up to the buttons.
+ virtual View* GetExtraView();
+
+ // Returns whether the height of the extra view should be at least as tall as
+ // the buttons. The default (false) is to give the extra view it's preferred
+ // height. By returning true the height becomes
+ // max(extra_view preferred height, buttons preferred height).
+ virtual bool GetSizeExtraViewHeightToButtons();
+
+ // For Dialog boxes, if there is a "Cancel" button, this is called when the
+ // user presses the "Cancel" button or the Close button on the window or
+ // in the system menu, or presses the Esc key. This function should return
+ // true if the window can be closed after it returns, or false if it must
+ // remain open.
+ virtual bool Cancel();
+
+ // For Dialog boxes, this is called when the user presses the "OK" button,
+ // or the Enter key. Can also be called on Esc key or close button
+ // presses if there is no "Cancel" button. This function should return
+ // true if the window can be closed after it returns, or false if it must
+ // remain open. If |window_closing| is true, it means that this handler is
+ // being called because the window is being closed (e.g. by Window::Close)
+ // and there is no Cancel handler, so Accept is being called instead.
+ virtual bool Accept(bool window_closing);
+ virtual bool Accept();
+
+ // Overridden from WindowDelegate:
+ virtual View* GetInitiallyFocusedView() OVERRIDE;
+ virtual ClientView* CreateClientView(Widget* widget) OVERRIDE;
+
+ // Called when the window has been closed.
+ virtual void OnClose() {}
+
+ // A helper for accessing the DialogClientView object contained by this
+ // delegate's Window.
+ const DialogClientView* GetDialogClientView() const;
+ DialogClientView* GetDialogClientView();
+
+ protected:
+ // Overridden from WindowDelegate:
+ virtual ui::AccessibilityTypes::Role GetAccessibleWindowRole() const OVERRIDE;
+};
+
+// A DialogDelegate implementation that is-a View. Used to override GetWidget()
+// to call View's GetWidget() for the common case where a DialogDelegate
+// implementation is-a View.
+class VIEWS_EXPORT DialogDelegateView : public DialogDelegate,
+ public View {
+ public:
+ DialogDelegateView();
+ virtual ~DialogDelegateView();
+
+ // Overridden from DialogDelegate:
+ virtual Widget* GetWidget() OVERRIDE;
+ virtual const Widget* GetWidget() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DialogDelegateView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_DIALOG_DELEGATE_H_
diff --git a/ui/views/window/native_frame_view.cc b/ui/views/window/native_frame_view.cc
new file mode 100644
index 0000000..8cb7dfd
--- /dev/null
+++ b/ui/views/window/native_frame_view.cc
@@ -0,0 +1,74 @@
+// 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 "views/window/native_frame_view.h"
+
+#include "views/widget/native_widget.h"
+#include "views/widget/widget.h"
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+#include "views/widget/native_widget_win.h"
+#endif
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeFrameView, public:
+
+NativeFrameView::NativeFrameView(Widget* frame)
+ : NonClientFrameView(),
+ frame_(frame) {
+}
+
+NativeFrameView::~NativeFrameView() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeFrameView, NonClientFrameView overrides:
+
+gfx::Rect NativeFrameView::GetBoundsForClientView() const {
+ return gfx::Rect(0, 0, width(), height());
+}
+
+gfx::Rect NativeFrameView::GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const {
+#if defined(OS_WIN) && !defined(USE_AURA)
+ RECT rect = client_bounds.ToRECT();
+ NativeWidgetWin* widget_win =
+ static_cast<NativeWidgetWin*>(frame_->native_widget());
+ AdjustWindowRectEx(&rect, widget_win->window_style(), FALSE,
+ widget_win->window_ex_style());
+ return gfx::Rect(rect);
+#else
+ // TODO(sad):
+ return client_bounds;
+#endif
+}
+
+int NativeFrameView::NonClientHitTest(const gfx::Point& point) {
+ return frame_->client_view()->NonClientHitTest(point);
+}
+
+void NativeFrameView::GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) {
+ // Nothing to do, we use the default window mask.
+}
+
+void NativeFrameView::EnableClose(bool enable) {
+ // Nothing to do, handled automatically by Window.
+}
+
+void NativeFrameView::ResetWindowControls() {
+ // Nothing to do.
+}
+
+void NativeFrameView::UpdateWindowIcon() {
+ // Nothing to do.
+}
+
+gfx::Size NativeFrameView::GetPreferredSize() {
+ return frame_->client_view()->GetPreferredSize();
+}
+
+} // namespace views
diff --git a/ui/views/window/native_frame_view.h b/ui/views/window/native_frame_view.h
new file mode 100644
index 0000000..de7f8ae
--- /dev/null
+++ b/ui/views/window/native_frame_view.h
@@ -0,0 +1,48 @@
+// 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_VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
+#define UI_VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
+#pragma once
+
+#include "views/window/non_client_view.h"
+
+namespace views {
+
+class Widget;
+
+class VIEWS_EXPORT NativeFrameView : public NonClientFrameView {
+ public:
+ explicit NativeFrameView(Widget* frame);
+ virtual ~NativeFrameView();
+
+ // NonClientFrameView overrides:
+ 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;
+
+ // View overrides:
+
+ // Returns the client size. On Windows, this is the expected behavior for
+ // native frames (see |NativeWidgetWin::WidgetSizeIsClientSize()|), while
+ // other platforms currently always return client bounds from
+ // |GetWindowBoundsForClientBounds()|.
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ private:
+ // Our containing frame.
+ Widget* frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
diff --git a/ui/views/window/non_client_view.cc b/ui/views/window/non_client_view.cc
new file mode 100644
index 0000000..be1cdac
--- /dev/null
+++ b/ui/views/window/non_client_view.cc
@@ -0,0 +1,276 @@
+// 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 "views/window/non_client_view.h"
+
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/hit_test.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+#include "views/window/client_view.h"
+
+namespace views {
+
+// static
+const int NonClientFrameView::kFrameShadowThickness = 1;
+const int NonClientFrameView::kClientEdgeThickness = 1;
+const char NonClientFrameView::kViewClassName[] =
+ "views/window/NonClientFrameView";
+
+const char NonClientView::kViewClassName[] =
+ "views/window/NonClientView";
+
+// The frame view and the client view are always at these specific indices,
+// because the RootView message dispatch sends messages to items higher in the
+// z-order first and we always want the client view to have first crack at
+// handling mouse messages.
+static const int kFrameViewIndex = 0;
+static const int kClientViewIndex = 1;
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientView, public:
+
+NonClientView::NonClientView()
+ : client_view_(NULL) {
+}
+
+NonClientView::~NonClientView() {
+ // This value may have been reset before the window hierarchy shuts down,
+ // so we need to manually remove it.
+ RemoveChildView(frame_view_.get());
+}
+
+void NonClientView::SetFrameView(NonClientFrameView* frame_view) {
+ // See comment in header about ownership.
+ frame_view->set_parent_owned(false);
+ if (frame_view_.get())
+ RemoveChildView(frame_view_.get());
+ frame_view_.reset(frame_view);
+ if (parent())
+ AddChildViewAt(frame_view_.get(), kFrameViewIndex);
+}
+
+bool NonClientView::CanClose() {
+ return client_view_->CanClose();
+}
+
+void NonClientView::WindowClosing() {
+ client_view_->WidgetClosing();
+}
+
+void NonClientView::UpdateFrame() {
+ Widget* widget = GetWidget();
+ SetFrameView(widget->CreateNonClientFrameView());
+ widget->ThemeChanged();
+ Layout();
+ SchedulePaint();
+ widget->UpdateFrameAfterFrameChange();
+}
+
+void NonClientView::SetInactiveRenderingDisabled(bool disable) {
+ frame_view_->SetInactiveRenderingDisabled(disable);
+}
+
+gfx::Rect NonClientView::GetWindowBoundsForClientBounds(
+ const gfx::Rect client_bounds) const {
+ return frame_view_->GetWindowBoundsForClientBounds(client_bounds);
+}
+
+int NonClientView::NonClientHitTest(const gfx::Point& point) {
+ // The NonClientFrameView is responsible for also asking the ClientView.
+ return frame_view_->NonClientHitTest(point);
+}
+
+void NonClientView::GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) {
+ frame_view_->GetWindowMask(size, window_mask);
+}
+
+void NonClientView::EnableClose(bool enable) {
+ frame_view_->EnableClose(enable);
+}
+
+void NonClientView::ResetWindowControls() {
+ frame_view_->ResetWindowControls();
+}
+
+void NonClientView::UpdateWindowIcon() {
+ frame_view_->UpdateWindowIcon();
+}
+
+void NonClientView::LayoutFrameView() {
+ // First layout the NonClientFrameView, which determines the size of the
+ // ClientView...
+ frame_view_->SetBounds(0, 0, width(), height());
+
+ // We need to manually call Layout here because layout for the frame view can
+ // change independently of the bounds changing - e.g. after the initial
+ // display of the window the metrics of the native window controls can change,
+ // which does not change the bounds of the window but requires a re-layout to
+ // trigger a repaint. We override OnBoundsChanged() for the NonClientFrameView
+ // to do nothing so that SetBounds above doesn't cause Layout to be called
+ // twice.
+ frame_view_->Layout();
+}
+
+void NonClientView::SetAccessibleName(const string16& name) {
+ accessible_name_ = name;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientView, View overrides:
+
+gfx::Size NonClientView::GetPreferredSize() {
+ // TODO(pkasting): This should probably be made to look similar to
+ // GetMinimumSize() below. This will require implementing GetPreferredSize()
+ // better in the various frame views.
+ gfx::Rect client_bounds(gfx::Point(), client_view_->GetPreferredSize());
+ return GetWindowBoundsForClientBounds(client_bounds).size();
+}
+
+gfx::Size NonClientView::GetMinimumSize() {
+ return frame_view_->GetMinimumSize();
+}
+
+void NonClientView::Layout() {
+ LayoutFrameView();
+
+ // Then layout the ClientView, using those bounds.
+ client_view_->SetBoundsRect(frame_view_->GetBoundsForClientView());
+
+ // We need to manually call Layout on the ClientView as well for the same
+ // reason as above.
+ client_view_->Layout();
+}
+
+void NonClientView::ViewHierarchyChanged(bool is_add, View* parent,
+ View* child) {
+ // Add our two child views here as we are added to the Widget so that if we
+ // are subsequently resized all the parent-child relationships are
+ // established.
+ if (is_add && GetWidget() && child == this) {
+ AddChildViewAt(frame_view_.get(), kFrameViewIndex);
+ AddChildViewAt(client_view_, kClientViewIndex);
+ }
+}
+
+void NonClientView::GetAccessibleState(ui::AccessibleViewState* state) {
+ state->role = ui::AccessibilityTypes::ROLE_WINDOW;
+ state->name = accessible_name_;
+}
+
+std::string NonClientView::GetClassName() const {
+ return kViewClassName;
+}
+
+views::View* NonClientView::GetEventHandlerForPoint(const gfx::Point& point) {
+ // Because of the z-ordering of our child views (the client view is positioned
+ // over the non-client frame view, if the client view ever overlaps the frame
+ // view visually (as it does for the browser window), then it will eat mouse
+ // events for the window controls. We override this method here so that we can
+ // detect this condition and re-route the events to the non-client frame view.
+ // The assumption is that the frame view's implementation of HitTest will only
+ // return true for area not occupied by the client view.
+ gfx::Point point_in_child_coords(point);
+ View::ConvertPointToView(this, frame_view_.get(), &point_in_child_coords);
+ if (frame_view_->HitTest(point_in_child_coords))
+ return frame_view_->GetEventHandlerForPoint(point_in_child_coords);
+
+ return View::GetEventHandlerForPoint(point);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView, public:
+
+void NonClientFrameView::SetInactiveRenderingDisabled(bool disable) {
+ // See comment in Widget::SetInactiveRenderingDisabled as to why we don't
+ // conditionally invoke ShouldPaintAsActiveChanged.
+ paint_as_active_ = disable;
+ ShouldPaintAsActiveChanged();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView, View overrides:
+
+bool NonClientFrameView::HitTest(const gfx::Point& l) const {
+ // For the default case, we assume the non-client frame view never overlaps
+ // the client view.
+ return !GetWidget()->client_view()->bounds().Contains(l);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView, protected:
+
+int NonClientFrameView::GetHTComponentForFrame(const gfx::Point& point,
+ int top_resize_border_height,
+ int resize_border_thickness,
+ int top_resize_corner_height,
+ int resize_corner_width,
+ bool can_resize) {
+ // Tricky: In XP, native behavior is to return HTTOPLEFT and HTTOPRIGHT for
+ // a |resize_corner_size|-length strip of both the side and top borders, but
+ // only to return HTBOTTOMLEFT/HTBOTTOMRIGHT along the bottom border + corner
+ // (not the side border). Vista goes further and doesn't return these on any
+ // of the side borders. We allow callers to match either behavior.
+ int component;
+ if (point.x() < resize_border_thickness) {
+ if (point.y() < top_resize_corner_height)
+ component = HTTOPLEFT;
+ else if (point.y() >= (height() - resize_border_thickness))
+ component = HTBOTTOMLEFT;
+ else
+ component = HTLEFT;
+ } else if (point.x() >= (width() - resize_border_thickness)) {
+ if (point.y() < top_resize_corner_height)
+ component = HTTOPRIGHT;
+ else if (point.y() >= (height() - resize_border_thickness))
+ component = HTBOTTOMRIGHT;
+ else
+ component = HTRIGHT;
+ } else if (point.y() < top_resize_border_height) {
+ if (point.x() < resize_corner_width)
+ component = HTTOPLEFT;
+ else if (point.x() >= (width() - resize_corner_width))
+ component = HTTOPRIGHT;
+ else
+ component = HTTOP;
+ } else if (point.y() >= (height() - resize_border_thickness)) {
+ if (point.x() < resize_corner_width)
+ component = HTBOTTOMLEFT;
+ else if (point.x() >= (width() - resize_corner_width))
+ component = HTBOTTOMRIGHT;
+ else
+ component = HTBOTTOM;
+ } else {
+ return HTNOWHERE;
+ }
+
+ // If the window can't be resized, there are no resize boundaries, just
+ // window borders.
+ return can_resize ? component : HTBORDER;
+}
+
+bool NonClientFrameView::ShouldPaintAsActive() const {
+ return GetWidget()->IsActive() || paint_as_active_;
+}
+
+void NonClientFrameView::ShouldPaintAsActiveChanged() {
+ if (!paint_as_active_)
+ SchedulePaint();
+}
+
+void NonClientFrameView::GetAccessibleState(ui::AccessibleViewState* state) {
+ state->role = ui::AccessibilityTypes::ROLE_WINDOW;
+}
+
+std::string NonClientFrameView::GetClassName() const {
+ return kViewClassName;
+}
+
+void NonClientFrameView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ // Overridden to do nothing. The NonClientView manually calls Layout on the
+ // FrameView when it is itself laid out, see comment in NonClientView::Layout.
+}
+
+} // namespace views
diff --git a/ui/views/window/non_client_view.h b/ui/views/window/non_client_view.h
new file mode 100644
index 0000000..db2ab9b
--- /dev/null
+++ b/ui/views/window/non_client_view.h
@@ -0,0 +1,240 @@
+// 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_VIEWS_WINDOW_NON_CLIENT_VIEW_H_
+#define UI_VIEWS_WINDOW_NON_CLIENT_VIEW_H_
+#pragma once
+
+#include "views/view.h"
+#include "views/window/client_view.h"
+
+namespace gfx {
+class Path;
+}
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView
+//
+// An object that subclasses NonClientFrameView is a View that renders and
+// responds to events within the frame portions of the non-client area of a
+// window. This view does _not_ contain the ClientView, but rather is a sibling
+// of it.
+class VIEWS_EXPORT NonClientFrameView : public View {
+ public:
+ // Internal class name.
+ static const char kViewClassName[];
+ // Various edges of the frame border have a 1 px shadow along their edges; in
+ // a few cases we shift elements based on this amount for visual appeal.
+ static const int kFrameShadowThickness;
+ // In restored mode, we draw a 1 px edge around the content area inside the
+ // frame border.
+ static const int kClientEdgeThickness;
+
+ // Sets whether the window should be rendered as active regardless of the
+ // actual active state. Used when bubbles become active to make their parent
+ // appear active. A value of true makes the window render as active always,
+ // false gives normal behavior.
+ void SetInactiveRenderingDisabled(bool disable);
+
+ // Returns the bounds (in this View's parent's coordinates) that the client
+ // view should be laid out within.
+ virtual gfx::Rect GetBoundsForClientView() const = 0;
+
+ virtual gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const = 0;
+
+ // This function must ask the ClientView to do a hittest. We don't do this in
+ // the parent NonClientView because that makes it more difficult to calculate
+ // hittests for regions that are partially obscured by the ClientView, e.g.
+ // HTSYSMENU.
+ virtual int NonClientHitTest(const gfx::Point& point) = 0;
+ virtual void GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) = 0;
+ virtual void EnableClose(bool enable) = 0;
+ virtual void ResetWindowControls() = 0;
+ virtual void UpdateWindowIcon() = 0;
+
+ // Overridden from View:
+ virtual bool HitTest(const gfx::Point& l) const OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual std::string GetClassName() const OVERRIDE;
+
+ protected:
+ virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
+
+ NonClientFrameView() : paint_as_active_(false) {}
+
+ // Helper for non-client view implementations to determine which area of the
+ // window border the specified |point| falls within. The other parameters are
+ // the size of the sizing edges, and whether or not the window can be
+ // resized.
+ int GetHTComponentForFrame(const gfx::Point& point,
+ int top_resize_border_height,
+ int resize_border_thickness,
+ int top_resize_corner_height,
+ int resize_corner_width,
+ bool can_resize);
+
+ // Used to determine if the frame should be painted as active. Keyed off the
+ // window's actual active state and the override, see
+ // SetInactiveRenderingDisabled() above.
+ bool ShouldPaintAsActive() const;
+
+ // Invoked from SetInactiveRenderingDisabled(). This implementation invokes
+ // SchedulesPaint as necessary.
+ virtual void ShouldPaintAsActiveChanged();
+
+ private:
+ // True when the non-client view should always be rendered as if the window
+ // were active, regardless of whether or not the top level window actually
+ // is active.
+ bool paint_as_active_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientView
+//
+// The NonClientView is the logical root of all Views contained within a
+// Window, except for the RootView which is its parent and of which it is the
+// sole child. The NonClientView has two children, the NonClientFrameView which
+// is responsible for painting and responding to events from the non-client
+// portions of the window, and the ClientView, which is responsible for the
+// same for the client area of the window:
+//
+// +- views::Window ------------------------------------+
+// | +- views::RootView ------------------------------+ |
+// | | +- views::NonClientView ---------------------+ | |
+// | | | +- views::NonClientFrameView subclas ---+ | | |
+// | | | | | | | |
+// | | | | << all painting and event receiving >> | | | |
+// | | | | << of the non-client areas of a >> | | | |
+// | | | | << views::Window. >> | | | |
+// | | | | | | | |
+// | | | +----------------------------------------+ | | |
+// | | | +- views::ClientView or subclass --------+ | | |
+// | | | | | | | |
+// | | | | << all painting and event receiving >> | | | |
+// | | | | << of the client areas of a >> | | | |
+// | | | | << views::Window. >> | | | |
+// | | | | | | | |
+// | | | +----------------------------------------+ | | |
+// | | +--------------------------------------------+ | |
+// | +------------------------------------------------+ |
+// +----------------------------------------------------+
+//
+// The NonClientFrameView and ClientView are siblings because due to theme
+// changes the NonClientFrameView may be replaced with different
+// implementations (e.g. during the switch from DWM/Aero-Glass to Vista Basic/
+// Classic rendering).
+//
+class VIEWS_EXPORT NonClientView : public View {
+ public:
+ // Internal class name.
+ static const char kViewClassName[];
+
+ NonClientView();
+ virtual ~NonClientView();
+
+ // Returns the current NonClientFrameView instance, or NULL if
+ // it does not exist.
+ NonClientFrameView* frame_view() const { return frame_view_.get(); }
+
+ // Replaces the current NonClientFrameView (if any) with the specified one.
+ void SetFrameView(NonClientFrameView* frame_view);
+
+ // Returns true if the ClientView determines that the containing window can be
+ // closed, false otherwise.
+ bool CanClose();
+
+ // Called by the containing Window when it is closed.
+ void WindowClosing();
+
+ // Changes the frame from native to custom depending on the value of
+ // |use_native_frame|.
+ void UpdateFrame();
+
+ // Prevents the window from being rendered as deactivated when |disable| is
+ // true, until called with |disable| false. Used when a sub-window is to be
+ // shown that shouldn't visually de-activate the window.
+ // Subclasses can override this to perform additional actions when this value
+ // changes.
+ void SetInactiveRenderingDisabled(bool disable);
+
+ // Returns the bounds of the window required to display the content area at
+ // the specified bounds.
+ gfx::Rect GetWindowBoundsForClientBounds(const gfx::Rect client_bounds) const;
+
+ // Determines the windows HT* code when the mouse cursor is at the
+ // specified point, in window coordinates.
+ int NonClientHitTest(const gfx::Point& point);
+
+ // Returns a mask to be used to clip the top level window for the given
+ // size. This is used to create the non-rectangular window shape.
+ void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask);
+
+ // Toggles the enable state for the Close button (and the Close menu item in
+ // the system menu).
+ void EnableClose(bool enable);
+
+ // Tells the window controls as rendered by the NonClientView to reset
+ // themselves to a normal state. This happens in situations where the
+ // containing window does not receive a normal sequences of messages that
+ // would lead to the controls returning to this normal state naturally, e.g.
+ // when the window is maximized, minimized or restored.
+ void ResetWindowControls();
+
+ // Tells the NonClientView to invalidate the NonClientFrameView's window icon.
+ void UpdateWindowIcon();
+
+ // Get/Set client_view property.
+ ClientView* client_view() const { return client_view_; }
+ void set_client_view(ClientView* client_view) {
+ client_view_ = client_view;
+ }
+
+ // Layout just the frame view. This is necessary on Windows when non-client
+ // metrics such as the position of the window controls changes independently
+ // of a window resize message.
+ void LayoutFrameView();
+
+ // Set the accessible name of this view.
+ void SetAccessibleName(const string16& name);
+
+ // NonClientView, View overrides:
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+ virtual gfx::Size GetMinimumSize() OVERRIDE;
+ virtual void Layout() OVERRIDE;
+ virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+ virtual std::string GetClassName() const OVERRIDE;
+
+ virtual views::View* GetEventHandlerForPoint(const gfx::Point& point)
+ OVERRIDE;
+
+ protected:
+ // NonClientView, View overrides:
+ virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child)
+ OVERRIDE;
+
+ private:
+ // A ClientView object or subclass, responsible for sizing the contents view
+ // of the window, hit testing and perhaps other tasks depending on the
+ // implementation.
+ ClientView* client_view_;
+
+ // The NonClientFrameView that renders the non-client portions of the window.
+ // This object is not owned by the view hierarchy because it can be replaced
+ // dynamically as the system settings change.
+ scoped_ptr<NonClientFrameView> frame_view_;
+
+ // The accessible name of this view.
+ string16 accessible_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(NonClientView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_NON_CLIENT_VIEW_H_
diff --git a/ui/views/window/window_resources.h b/ui/views/window/window_resources.h
new file mode 100644
index 0000000..14afc43
--- /dev/null
+++ b/ui/views/window/window_resources.h
@@ -0,0 +1,32 @@
+// 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_VIEWS_WINDOW_WINDOW_RESOURCES_H_
+#define UI_VIEWS_WINDOW_WINDOW_RESOURCES_H_
+#pragma once
+
+class SkBitmap;
+
+namespace views {
+
+typedef int FramePartBitmap;
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowResources
+//
+// An interface implemented by an object providing bitmaps to render the
+// contents of a window frame. The Window may swap in different
+// implementations of this interface to render different modes. The definition
+// of FramePartBitmap depends on the implementation.
+//
+class WindowResources {
+ public:
+ virtual ~WindowResources() {}
+
+ virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_WINDOW_RESOURCES_H_
diff --git a/ui/views/window/window_shape.cc b/ui/views/window/window_shape.cc
new file mode 100644
index 0000000..869ec21
--- /dev/null
+++ b/ui/views/window/window_shape.cc
@@ -0,0 +1,46 @@
+// 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 "views/window/window_shape.h"
+
+#include "ui/gfx/path.h"
+#include "ui/gfx/size.h"
+
+namespace views {
+
+void GetDefaultWindowMask(const gfx::Size &size, gfx::Path *window_mask) {
+ // Redefine the window visible region for the new size.
+ window_mask->moveTo(0, 3);
+ window_mask->lineTo(1, 2);
+ window_mask->lineTo(1, 1);
+ window_mask->lineTo(2, 1);
+ window_mask->lineTo(3, 0);
+
+ window_mask->lineTo(SkIntToScalar(size.width() - 3), 0);
+ window_mask->lineTo(SkIntToScalar(size.width() - 2), 1);
+ window_mask->lineTo(SkIntToScalar(size.width() - 1), 1);
+ window_mask->lineTo(SkIntToScalar(size.width() - 1), 2);
+ window_mask->lineTo(SkIntToScalar(size.width()), 3);
+
+ window_mask->lineTo(SkIntToScalar(size.width()),
+ SkIntToScalar(size.height() - 3));
+ window_mask->lineTo(SkIntToScalar(size.width() - 1),
+ SkIntToScalar(size.height() - 3));
+ window_mask->lineTo(SkIntToScalar(size.width() - 1),
+ SkIntToScalar(size.height() - 1));
+ window_mask->lineTo(SkIntToScalar(size.width() - 3),
+ SkIntToScalar(size.height() - 2));
+ window_mask->lineTo(SkIntToScalar(size.width() - 3),
+ SkIntToScalar(size.height()));
+
+ window_mask->lineTo(3, SkIntToScalar(size.height()));
+ window_mask->lineTo(2, SkIntToScalar(size.height() - 2));
+ window_mask->lineTo(1, SkIntToScalar(size.height() - 1));
+ window_mask->lineTo(1, SkIntToScalar(size.height() - 3));
+ window_mask->lineTo(0, SkIntToScalar(size.height() - 3));
+
+ window_mask->close();
+}
+
+} // namespace views
diff --git a/ui/views/window/window_shape.h b/ui/views/window/window_shape.h
new file mode 100644
index 0000000..6db3add
--- /dev/null
+++ b/ui/views/window/window_shape.h
@@ -0,0 +1,25 @@
+// 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_VIEWS_WINDOW_WINDOW_SHAPE_H_
+#define UI_VIEWS_WINDOW_WINDOW_SHAPE_H_
+#pragma once
+
+#include "views/views_export.h"
+
+namespace gfx {
+class Size;
+class Path;
+}
+
+namespace views {
+
+// Sets the window mask to a style that most likely matches
+// ui/resources/window_*
+VIEWS_EXPORT void GetDefaultWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask);
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_WINDOW_SHAPE_H_