diff options
author | beng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-31 00:42:17 +0000 |
---|---|---|
committer | beng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-31 00:42:17 +0000 |
commit | b2a4b9f96997dc3b929b5b9930325a030a8294e3 (patch) | |
tree | 3b18dd4002b9f6b681dd8256783f9d308591568f /chrome | |
parent | cd5241ff75071da8e4345e81ebc220e17505a306 (diff) | |
download | chromium_src-b2a4b9f96997dc3b929b5b9930325a030a8294e3.zip chromium_src-b2a4b9f96997dc3b929b5b9930325a030a8294e3.tar.gz chromium_src-b2a4b9f96997dc3b929b5b9930325a030a8294e3.tar.bz2 |
Move dialog-specific aspects of ClientView into a new subclass DialogClientView.
ClientView becomes a generic representation of the View that occupies the "client area" of a window. All Windows now require a Client View (though they can use the default).
Adjust WindowDelegate to provide a method for constructing the ClientView for a Window. The DialogDelegate overrides this to construct the DialogClientView. In the future, other specialized delegates will construct ClientViews specific to them, e.g. WizardDelegate would construct WizardClientView.
Adjust the Window Init method to set up this new required Client View, and make some tweaks to CustomFrameWindow to make all this work.
Remove all traces of dialog specific handling in Window into DialogClientView.
B=1280060
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@153 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/views/about_chrome_view.cc | 2 | ||||
-rw-r--r-- | chrome/browser/views/bookmark_editor_view.cc | 2 | ||||
-rw-r--r-- | chrome/browser/views/bug_report_view.cc | 2 | ||||
-rw-r--r-- | chrome/browser/views/clear_browsing_data.cc | 4 | ||||
-rw-r--r-- | chrome/browser/views/constrained_window_impl.cc | 56 | ||||
-rw-r--r-- | chrome/browser/views/constrained_window_impl.h | 9 | ||||
-rw-r--r-- | chrome/browser/views/edit_keyword_controller.cc | 4 | ||||
-rw-r--r-- | chrome/browser/views/first_run_view_base.cc | 9 | ||||
-rw-r--r-- | chrome/browser/views/input_window.cc | 4 | ||||
-rw-r--r-- | chrome/browser/views/shelf_item_dialog.cc | 4 | ||||
-rw-r--r-- | chrome/views/custom_frame_window.cc | 105 | ||||
-rw-r--r-- | chrome/views/dialog_client_view.cc | 410 | ||||
-rw-r--r-- | chrome/views/dialog_client_view.h | 133 | ||||
-rw-r--r-- | chrome/views/dialog_delegate.h | 26 | ||||
-rw-r--r-- | chrome/views/views.vcproj | 8 | ||||
-rw-r--r-- | chrome/views/window.cc | 103 | ||||
-rw-r--r-- | chrome/views/window.h | 48 | ||||
-rw-r--r-- | chrome/views/window_delegate.h | 7 |
18 files changed, 714 insertions, 222 deletions
diff --git a/chrome/browser/views/about_chrome_view.cc b/chrome/browser/views/about_chrome_view.cc index 4ad5908..bc632cd 100644 --- a/chrome/browser/views/about_chrome_view.cc +++ b/chrome/browser/views/about_chrome_view.cc @@ -489,5 +489,5 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result, // Check button may have appeared/disappeared. We cannot call this during // ViewHierarchyChanged because the |window()| pointer hasn't been set yet. if (window()) - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } diff --git a/chrome/browser/views/bookmark_editor_view.cc b/chrome/browser/views/bookmark_editor_view.cc index da5a92d..8f6ae2c 100644 --- a/chrome/browser/views/bookmark_editor_view.cc +++ b/chrome/browser/views/bookmark_editor_view.cc @@ -391,7 +391,7 @@ void BookmarkEditorView::UserInputChanged() { url_tf_.SetBackgroundColor(kErrorColor); else url_tf_.SetDefaultBackgroundColor(); - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } void BookmarkEditorView::NewGroup() { diff --git a/chrome/browser/views/bug_report_view.cc b/chrome/browser/views/bug_report_view.cc index 45023e5..b46235f 100644 --- a/chrome/browser/views/bug_report_view.cc +++ b/chrome/browser/views/bug_report_view.cc @@ -278,7 +278,7 @@ void BugReportView::ItemChanged(ChromeViews::ComboBox* combo_box, include_page_image_checkbox_->SetEnabled(!is_phishing_report); include_page_image_checkbox_->SetIsSelected(!is_phishing_report); - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } void BugReportView::ContentsChanged(ChromeViews::TextField* sender, diff --git a/chrome/browser/views/clear_browsing_data.cc b/chrome/browser/views/clear_browsing_data.cc index b3721ab..2526182 100644 --- a/chrome/browser/views/clear_browsing_data.cc +++ b/chrome/browser/views/clear_browsing_data.cc @@ -322,7 +322,7 @@ std::wstring ClearBrowsingDataView::GetItemAt(ChromeViews::ComboBox* source, void ClearBrowsingDataView::ButtonPressed(ChromeViews::NativeButton* sender) { // When no checkbox is checked we should not have the action button enabled. // This forces the button to evaluate what state they should be in. - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } //////////////////////////////////////////////////////////////////////////////// @@ -355,7 +355,7 @@ void ClearBrowsingDataView::UpdateControlEnabledState() { throbber_->Stop(); // Make sure to update the state for OK and Cancel buttons. - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } // Convenience method that returns true if the supplied checkbox is selected diff --git a/chrome/browser/views/constrained_window_impl.cc b/chrome/browser/views/constrained_window_impl.cc index f666b50..96a63588 100644 --- a/chrome/browser/views/constrained_window_impl.cc +++ b/chrome/browser/views/constrained_window_impl.cc @@ -256,7 +256,6 @@ class ConstrainedWindowNonClientView void SetShowThrobber(bool show_throbber); // Overridden from ChromeViews::NonClientView: - virtual void Init(ChromeViews::ClientView* client_view); virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; virtual gfx::Size CalculateWindowSizeForClientSize(int width, int height) const; @@ -300,11 +299,6 @@ class ConstrainedWindowNonClientView void UpdateLocationBar(); bool ShouldDisplayURLField() const; - // The View that provides the background for the window, and optionally - // dialog buttons. Note: the non-client view does _not_ own this view, the - // container does. - ChromeViews::ClientView* client_view_; - ConstrainedWindowImpl* container_; ChromeViews::WindowDelegate* window_delegate_; @@ -540,12 +534,6 @@ void ConstrainedWindowNonClientView::Run() { //////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowNonClientView, ChromeViews::NonClientView implementation: -void ConstrainedWindowNonClientView::Init( - ChromeViews::ClientView* client_view) { - client_view_ = client_view; - AddChildView(client_view_); -} - gfx::Rect ConstrainedWindowNonClientView::CalculateClientAreaBounds( int width, int height) const { @@ -578,15 +566,9 @@ int ConstrainedWindowNonClientView::NonClientHitTest(const gfx::Point& point) { // First see if it's within the grow box area, since that overlaps the client // bounds. - if (client_view_->PointIsInSizeBox(point)) - return HTBOTTOMRIGHT; - - // Then see if it's within the client area. - if (client_view_) { - client_view_->GetBounds(&bounds); - if (bounds.PtInRect(test_point)) - return HTCLIENT; - } + int component = container_->client_view()->NonClientHitTest(point); + if (component != HTNOWHERE) + return component; // Then see if the point is within any of the window controls. close_button_->GetBounds(&bounds); @@ -596,10 +578,10 @@ int ConstrainedWindowNonClientView::NonClientHitTest(const gfx::Point& point) { if (bounds.PtInRect(test_point)) return HTSYSMENU; - int component = GetHTComponentForFrame(point, kResizeAreaSize, - kResizeAreaCornerSize, - kResizeAreaNorthSize, - window_delegate_->CanResize()); + component = GetHTComponentForFrame(point, kResizeAreaSize, + kResizeAreaCornerSize, + kResizeAreaNorthSize, + window_delegate_->CanResize()); if (component == HTNOWHERE) { // Finally fall back to the caption. GetBounds(&bounds, APPLY_MIRRORING_TRANSFORMATION); @@ -692,26 +674,28 @@ void ConstrainedWindowNonClientView::Layout() { location_bar_height); location_bar_->Layout(); } - if (client_view_) - client_view_->SetBounds(client_bounds_.ToRECT()); + container_->client_view()->SetBounds(client_bounds_.ToRECT()); } void ConstrainedWindowNonClientView::GetPreferredSize(CSize* out) { DCHECK(out); - if (client_view_) { - client_view_->GetPreferredSize(out); - out->cx += 2 * kWindowHorizontalBorderSize; - out->cy += CalculateNonClientHeight(ShouldDisplayURLField()) + - kWindowVerticalBorderSize; - } + container_->client_view()->GetPreferredSize(out); + out->cx += 2 * kWindowHorizontalBorderSize; + out->cy += CalculateNonClientHeight(ShouldDisplayURLField()) + + kWindowVerticalBorderSize; } void ConstrainedWindowNonClientView::ViewHierarchyChanged(bool is_add, View *parent, View *child) { - if (is_add && location_bar_ && GetViewContainer() && - !(location_bar_->IsInitialized())) { - location_bar_->Init(); + if (is_add && GetViewContainer()) { + // Add our Client View as we are added to the ViewContainer so that if we + // are subsequently resized all the parent-child relationships are + // established. + if (is_add && GetViewContainer() && child == this) + AddChildView(container_->client_view()); + if (location_bar_ && !location_bar_->IsInitialized()) + location_bar_->Init(); } } diff --git a/chrome/browser/views/constrained_window_impl.h b/chrome/browser/views/constrained_window_impl.h index 9e8c0b3..31a6d04 100644 --- a/chrome/browser/views/constrained_window_impl.h +++ b/chrome/browser/views/constrained_window_impl.h @@ -32,12 +32,15 @@ #include "chrome/browser/constrained_window.h" #include "chrome/browser/tab_contents_delegate.h" -#include "chrome/views/client_view.h" #include "chrome/views/custom_frame_window.h" class ConstrainedTabContentsWindowDelegate; class ConstrainedWindowAnimation; class ConstrainedWindowNonClientView; +namespace ChromeViews { +class HWNDView; +class WindowDelegate; +} /////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowImpl @@ -123,6 +126,8 @@ class ConstrainedWindowImpl : public ConstrainedWindow, virtual void OnWindowPosChanged(WINDOWPOS* window_pos); private: + friend class ConstrainedWindow; + // Use the static factory methods on ConstrainedWindow to construct a // ConstrainedWindow. ConstrainedWindowImpl(TabContents* owner, @@ -132,8 +137,6 @@ class ConstrainedWindowImpl : public ConstrainedWindow, ChromeViews::WindowDelegate* window_delegate); void Init(TabContents* owner); - friend class ConstrainedWindow; - // Called after changing either the anchor point or titlebar // visibility of a suppressed popup. This does the actual resizing. // diff --git a/chrome/browser/views/edit_keyword_controller.cc b/chrome/browser/views/edit_keyword_controller.cc index 8fe9b00..982b6d2 100644 --- a/chrome/browser/views/edit_keyword_controller.cc +++ b/chrome/browser/views/edit_keyword_controller.cc @@ -81,7 +81,7 @@ void EditKeywordController::Show() { ChromeViews::Window::CreateChromeWindow(::IsWindow(parent_) ? parent_ : NULL, gfx::Rect(), this); window()->Show(); - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); title_tf_->SelectAll(); title_tf_->RequestFocus(); } @@ -183,7 +183,7 @@ ChromeViews::View* EditKeywordController::GetContentsView() { void EditKeywordController::ContentsChanged(TextField* sender, const std::wstring& new_contents) { - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); UpdateImageViews(); } diff --git a/chrome/browser/views/first_run_view_base.cc b/chrome/browser/views/first_run_view_base.cc index 4ee8aceb..9f8044c 100644 --- a/chrome/browser/views/first_run_view_base.cc +++ b/chrome/browser/views/first_run_view_base.cc @@ -180,12 +180,9 @@ int FirstRunViewBase::GetDefaultImportItems() const { void FirstRunViewBase::DisableButtons() { window()->EnableClose(false); - ChromeViews::ClientView* cv = - reinterpret_cast<ChromeViews::ClientView*>(GetParent()); - if (cv) { - cv->ok_button()->SetEnabled(false); - cv->cancel_button()->SetEnabled(false); - } + ChromeViews::DialogClientView* dcv = GetDialogClientView(); + dcv->ok_button()->SetEnabled(false); + dcv->cancel_button()->SetEnabled(false); } bool FirstRunViewBase::CreateDesktopShortcut() { diff --git a/chrome/browser/views/input_window.cc b/chrome/browser/views/input_window.cc index f4c560e..2576139 100644 --- a/chrome/browser/views/input_window.cc +++ b/chrome/browser/views/input_window.cc @@ -131,7 +131,7 @@ ChromeViews::View* ContentView::GetContentsView() { void ContentView::ContentsChanged(ChromeViews::TextField* sender, const std::wstring& new_contents) { - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } /////////////////////////////////////////////////////////////////////////////// @@ -187,6 +187,6 @@ ChromeViews::Window* CreateInputWindow(HWND parent_hwnd, ChromeViews::Window* window = ChromeViews::Window::CreateChromeWindow(parent_hwnd, gfx::Rect(), new ContentView(delegate)); - window->UpdateDialogButtons(); + window->client_view()->AsDialogClientView()->UpdateDialogButtons(); return window; } diff --git a/chrome/browser/views/shelf_item_dialog.cc b/chrome/browser/views/shelf_item_dialog.cc index 670453a..2c3de48 100644 --- a/chrome/browser/views/shelf_item_dialog.cc +++ b/chrome/browser/views/shelf_item_dialog.cc @@ -413,7 +413,7 @@ void ShelfItemDialog::ContentsChanged(ChromeViews::TextField* sender, // so we reset the expected handle to an impossible value. if (sender == title_field_) expected_title_handle_ = 0; - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } bool ShelfItemDialog::Accept() { @@ -493,7 +493,7 @@ void ShelfItemDialog::OnSelectionChanged() { UTF8ToWide(url_table_model_->GetURL(selection).spec())); if (title_field_) title_field_->SetText(url_table_model_->GetTitle(selection)); - window()->UpdateDialogButtons(); + GetDialogClientView()->UpdateDialogButtons(); } } diff --git a/chrome/views/custom_frame_window.cc b/chrome/views/custom_frame_window.cc index 8c6bf98..28146b6 100644 --- a/chrome/views/custom_frame_window.cc +++ b/chrome/views/custom_frame_window.cc @@ -49,7 +49,7 @@ namespace ChromeViews { HCURSOR CustomFrameWindow::resize_cursors_[6]; -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // WindowResources // // An enumeration of bitmap resources used by this window. @@ -222,7 +222,7 @@ SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[]; ChromeFont InactiveWindowResources::title_font_; -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // // DefaultNonClientView // @@ -237,7 +237,6 @@ class DefaultNonClientView : public NonClientView, virtual ~DefaultNonClientView(); // Overridden from CustomFrameWindow::NonClientView: - virtual void Init(ClientView* client_view); virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; virtual gfx::Size CalculateWindowSizeForClientSize(int width, int height) const; @@ -250,6 +249,7 @@ class DefaultNonClientView : public NonClientView, virtual void Paint(ChromeCanvas* canvas); virtual void Layout(); virtual void GetPreferredSize(CSize* out); + virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); // BaseButton::ButtonListener implementation: virtual void ButtonPressed(BaseButton* sender); @@ -327,7 +327,7 @@ static const int kResizeAreaCornerSize = 16; static const int kWindowHorizontalBorderSize = 4; static const int kWindowVerticalBorderSize = 4; -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, public: DefaultNonClientView::DefaultNonClientView( @@ -385,19 +385,9 @@ DefaultNonClientView::DefaultNonClientView( DefaultNonClientView::~DefaultNonClientView() { } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, CustomFrameWindow::NonClientView implementation: -void DefaultNonClientView::Init(ClientView* client_view) { - client_view_ = client_view; - AddChildView(client_view_); - // TODO(beng): (Cleanup) this should mostly move down to Window, because - // it'll be needed for that version too, but with a virtual - // override here to update the NC view. - SetWindowIcon(container_->window_delegate()->GetWindowIcon()); -} - - gfx::Rect DefaultNonClientView::CalculateClientAreaBounds( int width, int height) const { int top_margin = CalculateContentsTop(); @@ -440,15 +430,9 @@ int DefaultNonClientView::NonClientHitTest(const gfx::Point& point) { // First see if it's within the grow box area, since that overlaps the client // bounds. - if (client_view_->PointIsInSizeBox(point)) - return HTBOTTOMRIGHT; - - // Then see if it's within the client area. - if (client_view_) { - client_view_->GetBounds(&bounds, APPLY_MIRRORING_TRANSFORMATION); - if (bounds.PtInRect(test_point)) - return HTCLIENT; - } + int component = container_->client_view()->NonClientHitTest(point); + if (component != HTNOWHERE) + return component; // Then see if the point is within any of the window controls. close_button_->GetBounds(&bounds, APPLY_MIRRORING_TRANSFORMATION); @@ -467,7 +451,7 @@ int DefaultNonClientView::NonClientHitTest(const gfx::Point& point) { if (bounds.PtInRect(test_point)) return HTSYSMENU; - int component = GetHTComponentForFrame( + component = GetHTComponentForFrame( point, kResizeAreaSize, kResizeAreaCornerSize, @@ -507,7 +491,7 @@ void DefaultNonClientView::EnableClose(bool enable) { close_button_->SetEnabled(enable); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, View overrides: void DefaultNonClientView::Paint(ChromeCanvas* canvas) { @@ -537,14 +521,21 @@ void DefaultNonClientView::Layout() { void DefaultNonClientView::GetPreferredSize(CSize* out) { DCHECK(out); - if (client_view_) { - client_view_->GetPreferredSize(out); - out->cx += 2 * kWindowHorizontalBorderSize; - out->cy += CalculateContentsTop() + kWindowVerticalBorderSize; - } + container_->client_view()->GetPreferredSize(out); + out->cx += 2 * kWindowHorizontalBorderSize; + out->cy += CalculateContentsTop() + kWindowVerticalBorderSize; } -//////////////////////////////////////////////////////////////////////////////// +void DefaultNonClientView::ViewHierarchyChanged(bool is_add, + View* parent, + View* child) { + // Add our Client View as we are added to the ViewContainer so that if we are + // subsequently resized all the parent-child relationships are established. + if (is_add && GetViewContainer() && child == this) + AddChildView(container_->client_view()); +} + +/////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, BaseButton::ButtonListener implementation: void DefaultNonClientView::ButtonPressed(BaseButton* sender) { @@ -559,7 +550,7 @@ void DefaultNonClientView::ButtonPressed(BaseButton* sender) { } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, private: void DefaultNonClientView::SetWindowIcon(SkBitmap window_icon) { @@ -650,7 +641,7 @@ void DefaultNonClientView::PaintClientEdge(ChromeCanvas* canvas) { SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); CRect client_area_bounds; - client_view_->GetBounds(&client_area_bounds); + container_->client_view()->GetBounds(&client_area_bounds); canvas->DrawBitmapInt(*top_left, client_area_bounds.left - top_left->width(), client_area_bounds.top - top->height()); @@ -822,11 +813,9 @@ void DefaultNonClientView::LayoutTitleBar() { } void DefaultNonClientView::LayoutClientView() { - if (client_view_) { - gfx::Rect client_bounds( - CalculateClientAreaBounds(GetWidth(), GetHeight())); - client_view_->SetBounds(client_bounds.ToRECT()); - } + gfx::Rect client_bounds( + CalculateClientAreaBounds(GetWidth(), GetHeight())); + container_->client_view()->SetBounds(client_bounds.ToRECT()); } // static @@ -839,7 +828,7 @@ void DefaultNonClientView::InitClass() { } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // CustomFrameWindow, public: CustomFrameWindow::CustomFrameWindow(WindowDelegate* window_delegate) @@ -859,25 +848,33 @@ CustomFrameWindow::CustomFrameWindow(WindowDelegate* window_delegate, CustomFrameWindow::~CustomFrameWindow() { } -void CustomFrameWindow::Init(HWND owner, const gfx::Rect& bounds) { - Window::Init(owner, bounds); - // We need to re-parent the client view to the non-client view. - GetRootView()->RemoveChildView(client_view_); - GetRootView()->AddChildView(non_client_view_); - non_client_view_->Init(client_view_); - GetRootView()->Layout(); - - ResetWindowRegion(); -} - void CustomFrameWindow::ExecuteSystemMenuCommand(int command) { if (command) SendMessage(GetHWND(), WM_SYSCOMMAND, command, 0); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // CustomFrameWindow, Window overrides: +void CustomFrameWindow::Init(HWND parent, const gfx::Rect& bounds) { + // TODO(beng): (Cleanup) Right now, the only way to specify a different + // non-client view is to subclass this object and provide one + // by setting this member before calling Init. + if (!non_client_view_) + non_client_view_ = new DefaultNonClientView(this); + Window::Init(parent, bounds); + ResetWindowRegion(); +} + +void CustomFrameWindow::SetClientView(ClientView* client_view) { + DCHECK(client_view && !client_view_ && GetHWND()); + client_view_ = client_view; + // For a CustomFrameWindow, the non-client view is the root. + HWNDViewContainer::SetContentsView(non_client_view_); + // When the non client view is added to the view hierarchy, it will cause the + // client view to be added as well. +} + gfx::Size CustomFrameWindow::CalculateWindowSizeForClientSize( const gfx::Size& client_size) const { return non_client_view_->CalculateWindowSizeForClientSize( @@ -906,7 +903,7 @@ void CustomFrameWindow::SizeWindowToDefault() { window_size.ToSIZE(), false); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // CustomFrameWindow, HWNDViewContainer overrides: static void EnableMenuItem(HMENU menu, UINT command, bool enabled) { @@ -1161,7 +1158,7 @@ void CustomFrameWindow::OnSize(UINT param, const CSize& size) { ResetWindowRegion(); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // CustomFrameWindow, private: void CustomFrameWindow::RunSystemMenu(const CPoint& point) { diff --git a/chrome/views/dialog_client_view.cc b/chrome/views/dialog_client_view.cc new file mode 100644 index 0000000..0ce9293 --- /dev/null +++ b/chrome/views/dialog_client_view.cc @@ -0,0 +1,410 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <windows.h> +#include <uxtheme.h> +#include <vsstyle.h> + +#include "chrome/views/dialog_client_view.h" + +#include "base/gfx/native_theme.h" +#include "chrome/browser/standard_layout.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/chrome_font.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/win_util.h" +#include "chrome/views/dialog_delegate.h" +#include "chrome/views/window.h" +#include "generated_resources.h" + +namespace ChromeViews { + +namespace { + +// Updates any of the standard buttons according to the delegate. +void UpdateButtonHelper(ChromeViews::NativeButton* button_view, + ChromeViews::DialogDelegate* delegate, + ChromeViews::DialogDelegate::DialogButton button) { + std::wstring label = delegate->GetDialogButtonLabel(button); + if (!label.empty()) + button_view->SetLabel(label); + button_view->SetEnabled(delegate->IsDialogButtonEnabled(button)); + button_view->SetVisible(delegate->IsDialogButtonVisible(button)); +} + +void FillViewWithSysColor(ChromeCanvas* canvas, View* view, COLORREF color) { + SkColor sk_color = + SkColorSetRGB(GetRValue(color), GetGValue(color), GetBValue(color)); + canvas->FillRectInt(sk_color, 0, 0, view->GetWidth(), view->GetHeight()); +} + +// DialogButton ---------------------------------------------------------------- + +// DialogButtons is used for the ok/cancel buttons of the window. DialogButton +// forwrds AcceleratorPressed to the delegate. + +class DialogButton : public NativeButton { + public: + DialogButton(Window* owner, + DialogDelegate::DialogButton type, + const std::wstring& title, + bool is_default) + : NativeButton(title, is_default), owner_(owner), type_(type) { + } + + // Overridden to forward to the delegate. + virtual bool AcceleratorPressed(const Accelerator& accelerator) { + if (!owner_->window_delegate()->AsDialogDelegate()-> + AreAcceleratorsEnabled(type_)) { + return false; + } + return NativeButton::AcceleratorPressed(accelerator); + } + + private: + Window* owner_; + const DialogDelegate::DialogButton type_; + + DISALLOW_EVIL_CONSTRUCTORS(DialogButton); +}; + +} // namespace + +// static +ChromeFont DialogClientView::dialog_button_font_; +static const int kDialogMinButtonWidth = 75; +static const int kDialogButtonLabelSpacing = 16; +static const int kDialogButtonContentSpacing = 0; + +// 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(Window* owner, View* contents_view) + : ClientView(owner, contents_view), + ok_button_(NULL), + cancel_button_(NULL), + extra_view_(NULL), + accepted_(false) { + InitClass(); +} + +DialogClientView::~DialogClientView() { +} + +void DialogClientView::ShowDialogButtons() { + DialogDelegate* dd = GetDialogDelegate(); + int buttons = dd->GetDialogButtons(); + if (buttons & DialogDelegate::DIALOGBUTTON_OK && !ok_button_) { + std::wstring label = + dd->GetDialogButtonLabel(DialogDelegate::DIALOGBUTTON_OK); + if (label.empty()) + label = l10n_util::GetString(IDS_OK); + ok_button_ = new DialogButton( + window(), DialogDelegate::DIALOGBUTTON_OK, + label, + (dd->GetDefaultDialogButton() & DialogDelegate::DIALOGBUTTON_OK) != 0); + ok_button_->SetListener(this); + ok_button_->SetGroup(kButtonGroup); + if (!cancel_button_) + ok_button_->AddAccelerator(Accelerator(VK_ESCAPE, false, false, false)); + AddChildView(ok_button_); + } + if (buttons & DialogDelegate::DIALOGBUTTON_CANCEL && !cancel_button_) { + std::wstring label = + dd->GetDialogButtonLabel(DialogDelegate::DIALOGBUTTON_CANCEL); + if (label.empty()) { + if (buttons & DialogDelegate::DIALOGBUTTON_OK) { + label = l10n_util::GetString(IDS_CANCEL); + } else { + label = l10n_util::GetString(IDS_CLOSE); + } + } + cancel_button_ = new DialogButton( + window(), DialogDelegate::DIALOGBUTTON_CANCEL, + label, + (dd->GetDefaultDialogButton() & DialogDelegate::DIALOGBUTTON_CANCEL) + != 0); + cancel_button_->SetListener(this); + cancel_button_->SetGroup(kButtonGroup); + cancel_button_->AddAccelerator(Accelerator(VK_ESCAPE, false, false, false)); + AddChildView(cancel_button_); + } + + ChromeViews::View* extra_view = dd->GetExtraView(); + if (extra_view && !extra_view_) { + extra_view_ = extra_view; + extra_view_->SetGroup(kButtonGroup); + AddChildView(extra_view_); + } + if (!buttons) { + // Register the escape key as an accelerator which will close the window + // if there are no dialog buttons. + AddAccelerator(Accelerator(VK_ESCAPE, false, false, false)); + } +} + +// Changing dialog labels will change button widths. +void DialogClientView::UpdateDialogButtons() { + DialogDelegate* dd = GetDialogDelegate(); + int buttons = dd->GetDialogButtons(); + + if (buttons & DialogDelegate::DIALOGBUTTON_OK) + UpdateButtonHelper(ok_button_, dd, DialogDelegate::DIALOGBUTTON_OK); + + if (buttons & DialogDelegate::DIALOGBUTTON_CANCEL) + UpdateButtonHelper(cancel_button_, dd, DialogDelegate::DIALOGBUTTON_CANCEL); + + LayoutDialogButtons(); + SchedulePaint(); +} + +void DialogClientView::AcceptWindow() { + accepted_ = true; + if (GetDialogDelegate()->Accept(false)) + window()->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. + window()->Close(); +} + +/////////////////////////////////////////////////////////////////////////////// +// DialogClientView, ClientView overrides: + +bool DialogClientView::CanClose() const { + DialogDelegate* dd = GetDialogDelegate(); + int buttons = dd->GetDialogButtons(); + if (buttons & DialogDelegate::DIALOGBUTTON_CANCEL) + return dd->Cancel(); + if (buttons & DialogDelegate::DIALOGBUTTON_OK) + return dd->Accept(true); + return true; +} + +int DialogClientView::NonClientHitTest(const gfx::Point& point) { + if (size_box_bounds_.Contains(point.x() - GetX(), point.y() - GetY())) + return HTBOTTOMRIGHT; + return ClientView::NonClientHitTest(point); +} + +//////////////////////////////////////////////////////////////////////////////// +// DialogClientView, View overrides: + +void DialogClientView::Paint(ChromeCanvas* canvas) { + FillViewWithSysColor(canvas, this, GetSysColor(COLOR_3DFACE)); +} + +void DialogClientView::PaintChildren(ChromeCanvas* canvas) { + View::PaintChildren(canvas); + if (!window()->IsMaximized() && !window()->IsMinimized()) + PaintSizeBox(canvas); +} + +void DialogClientView::Layout() { + if (has_dialog_buttons()) + LayoutDialogButtons(); + 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 + // ViewContainer's HWND. + ShowDialogButtons(); + ClientView::ViewHierarchyChanged(is_add, parent, child); + UpdateDialogButtons(); + Layout(); + } +} + +void DialogClientView::DidChangeBounds(const CRect& prev, const CRect& next) { + Layout(); +} + +void DialogClientView::GetPreferredSize(CSize* out) { + DCHECK(out); + contents_view()->GetPreferredSize(out); + int button_height = 0; + if (has_dialog_buttons()) { + if (cancel_button_) + button_height = cancel_button_->GetHeight(); + else + button_height = ok_button_->GetHeight(); + // Account for padding above and below the button. + button_height += kDialogButtonContentSpacing + kButtonVEdgeMargin; + } + out->cy += button_height; +} + +bool DialogClientView::AcceleratorPressed(const Accelerator& accelerator) { + DCHECK(accelerator.GetKeyCode() == VK_ESCAPE); // We only expect Escape key. + window()->Close(); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// DialogClientView, NativeButton::Listener implementation: + +void DialogClientView::ButtonPressed(NativeButton* sender) { + if (sender == ok_button_) { + AcceptWindow(); + } else if (sender == cancel_button_) { + CancelWindow(); + } else { + NOTREACHED(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// DialogClientView, private: + +void DialogClientView::PaintSizeBox(ChromeCanvas* canvas) { + if (window()->window_delegate()->CanResize() || + window()->window_delegate()->CanMaximize()) { + HDC dc = canvas->beginPlatformPaint(); + SIZE gripper_size = { 0, 0 }; + gfx::NativeTheme::instance()->GetThemePartSize( + gfx::NativeTheme::STATUS, dc, SP_GRIPPER, 1, NULL, TS_TRUE, + &gripper_size); + + // 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... + CRect gripper_bounds; + GetLocalBounds(&gripper_bounds, false); + gripper_bounds.left = gripper_bounds.right - gripper_size.cx; + gripper_bounds.top = gripper_bounds.bottom - gripper_size.cy; + size_box_bounds_ = gripper_bounds; + gfx::NativeTheme::instance()->PaintStatusGripper( + dc, SP_PANE, 1, 0, gripper_bounds); + canvas->endPlatformPaint(); + } +} + +int DialogClientView::GetButtonWidth(int button) const { + DialogDelegate* dd = GetDialogDelegate(); + std::wstring button_label = dd->GetDialogButtonLabel( + static_cast<DialogDelegate::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_->GetHeight() + kDialogButtonContentSpacing; + return ok_button_->GetHeight() + kDialogButtonContentSpacing; + } + return 0; +} + +void DialogClientView::LayoutDialogButtons() { + CRect extra_bounds; + if (cancel_button_) { + CSize ps; + cancel_button_->GetPreferredSize(&ps); + CRect lb; + GetLocalBounds(&lb, false); + int button_width = GetButtonWidth(DialogDelegate::DIALOGBUTTON_CANCEL); + CRect bounds; + bounds.left = lb.right - button_width - kButtonHEdgeMargin; + bounds.top = lb.bottom - ps.cy - kButtonVEdgeMargin; + bounds.right = bounds.left + button_width; + bounds.bottom = bounds.top + ps.cy; + cancel_button_->SetBounds(bounds); + // The extra view bounds are dependent on this button. + extra_bounds.right = bounds.left; + extra_bounds.top = bounds.top; + } + if (ok_button_) { + CSize ps; + ok_button_->GetPreferredSize(&ps); + CRect lb; + GetLocalBounds(&lb, false); + int button_width = GetButtonWidth(DialogDelegate::DIALOGBUTTON_OK); + int ok_button_right = lb.right - kButtonHEdgeMargin; + if (cancel_button_) + ok_button_right = cancel_button_->GetX() - kRelatedButtonHSpacing; + CRect bounds; + bounds.left = ok_button_right - button_width; + bounds.top = lb.bottom - ps.cy - kButtonVEdgeMargin; + bounds.right = ok_button_right; + bounds.bottom = bounds.top + ps.cy; + ok_button_->SetBounds(bounds); + // The extra view bounds are dependent on this button. + extra_bounds.right = bounds.left; + extra_bounds.top = bounds.top; + } + if (extra_view_) { + CSize ps; + extra_view_->GetPreferredSize(&ps); + CRect lb; + GetLocalBounds(&lb, false); + extra_bounds.left = lb.left + kButtonHEdgeMargin; + extra_bounds.bottom = extra_bounds.top + ps.cy; + extra_view_->SetBounds(extra_bounds); + } +} + +void DialogClientView::LayoutContentsView() { + CRect lb; + GetLocalBounds(&lb, false); + lb.bottom = std::max(0, static_cast<int>(lb.bottom - GetButtonsHeight())); + contents_view()->SetBounds(lb); + contents_view()->Layout(); +} + +DialogDelegate* DialogClientView::GetDialogDelegate() const { + DialogDelegate* dd = window()->window_delegate()->AsDialogDelegate(); + DCHECK(dd); + return dd; +} + +// static +void DialogClientView::InitClass() { + static bool initialized = false; + if (!initialized) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + dialog_button_font_ = rb.GetFont(ResourceBundle::BaseFont); + initialized = true; + } +} + +} diff --git a/chrome/views/dialog_client_view.h b/chrome/views/dialog_client_view.h new file mode 100644 index 0000000..b2b7c6c --- /dev/null +++ b/chrome/views/dialog_client_view.h @@ -0,0 +1,133 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CHROME_VIEWS_DIALOG_CLIENT_VIEW_H_ +#define CHROME_VIEWS_DIALOG_CLIENT_VIEW_H_ + +#include "chrome/common/gfx/chrome_font.h" +#include "chrome/views/client_view.h" +#include "chrome/views/native_button.h" + +namespace ChromeViews { + +class DialogDelegate; +class Window; + +/////////////////////////////////////////////////////////////////////////////// +// 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. +// +class DialogClientView : public ClientView, + public NativeButton::Listener { + public: + DialogClientView(Window* window, View* contents_view); + virtual ~DialogClientView(); + + // Adds the dialog buttons required by the supplied WindowDelegate to the + // view. + void ShowDialogButtons(); + + // Updates the enabled state and label of the buttons required by the + // supplied WindowDelegate + 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. + NativeButton* ok_button() const { return ok_button_; } + NativeButton* cancel_button() const { return cancel_button_; } + + // Overridden from ClientView: + virtual bool CanClose() const; + virtual int NonClientHitTest(const gfx::Point& point); + virtual DialogClientView* AsDialogClientView() { return this; } + + protected: + // View overrides: + virtual void Paint(ChromeCanvas* canvas); + virtual void PaintChildren(ChromeCanvas* canvas); + virtual void Layout(); + virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); + virtual void DidChangeBounds(const CRect& prev, const CRect& next); + virtual void GetPreferredSize(CSize* out); + virtual bool AcceleratorPressed(const Accelerator& accelerator); + + // NativeButton::Listener implementation: + virtual void ButtonPressed(NativeButton* sender); + + private: + // Paint the size box in the bottom right corner of the window if it is + // resizable. + void PaintSizeBox(ChromeCanvas* canvas); + + // Returns the width of the specified dialog button using the correct font. + int GetButtonWidth(int button) const; + int DialogClientView::GetButtonsHeight() const; + + // Position and size various sub-views. + void LayoutDialogButtons(); + void LayoutContentsView(); + + bool has_dialog_buttons() const { return ok_button_ || cancel_button_; } + + // Returns the DialogDelegate for the window. + DialogDelegate* GetDialogDelegate() const; + + // The dialog buttons. + NativeButton* ok_button_; + NativeButton* cancel_button_; + + // The button-level extra view, NULL unless the dialog delegate supplies one. + View* extra_view_; + + // The layout rect of the size box, when visible. + gfx::Rect size_box_bounds_; + + // True if the window was Accepted by the user using the OK button. + bool accepted_; + + // Static resource initialization + static void InitClass(); + static ChromeFont dialog_button_font_; + + DISALLOW_EVIL_CONSTRUCTORS(DialogClientView); +}; + +} + +#endif // #ifndef CHROME_VIEWS_DIALOG_CLIENT_VIEW_H_ diff --git a/chrome/views/dialog_delegate.h b/chrome/views/dialog_delegate.h index 2dc48e6..9ca4ade 100644 --- a/chrome/views/dialog_delegate.h +++ b/chrome/views/dialog_delegate.h @@ -30,6 +30,7 @@ #ifndef CHROME_VIEWS_DIALOG_DELEGATE_H__ #define CHROME_VIEWS_DIALOG_DELEGATE_H__ +#include "chrome/views/dialog_client_view.h" #include "chrome/views/window_delegate.h" namespace ChromeViews { @@ -119,6 +120,31 @@ class DialogDelegate : public WindowDelegate { // instead. virtual bool Accept(bool window_closing) { return Accept(); } virtual bool Accept() { return true; } + + // Overridden from WindowDelegate: + virtual View* GetInitiallyFocusedView() const { + // Try to focus the OK then the Cancel button if present. + DialogClientView* dcv = GetDialogClientView(); + if (GetDialogButtons() & DIALOGBUTTON_OK) + return dcv->ok_button(); + if (GetDialogButtons() & DIALOGBUTTON_CANCEL) + return dcv->cancel_button(); + return NULL; + } + + // Overridden from WindowDelegate: + virtual ClientView* CreateClientView(Window* window) { + return new DialogClientView(window, GetContentsView()); + } + + // A helper for accessing the DialogClientView object contained by this + // delegate's Window. + DialogClientView* GetDialogClientView() const { + ClientView* client_view = window()->client_view(); + DialogClientView* dialog_client_view = client_view->AsDialogClientView(); + DCHECK(dialog_client_view); + return dialog_client_view; + } }; } // namespace ChromeViews diff --git a/chrome/views/views.vcproj b/chrome/views/views.vcproj index 928ae37..4baf1be 100644 --- a/chrome/views/views.vcproj +++ b/chrome/views/views.vcproj @@ -278,6 +278,14 @@ > </File> <File + RelativePath=".\dialog_client_view.cc" + > + </File> + <File + RelativePath=".\dialog_client_view.h" + > + </File> + <File RelativePath=".\dialog_delegate.h" > </File> diff --git a/chrome/views/window.cc b/chrome/views/window.cc index 042968b..4243994 100644 --- a/chrome/views/window.cc +++ b/chrome/views/window.cc @@ -36,7 +36,6 @@ #include "chrome/common/pref_service.h" #include "chrome/common/resource_bundle.h" #include "chrome/common/win_util.h" -#include "chrome/views/client_view.h" #include "chrome/views/custom_frame_window.h" #include "chrome/views/window_delegate.h" @@ -65,8 +64,6 @@ Window::Window(WindowDelegate* window_delegate) is_modal_(false), restored_enabled_(false), is_always_on_top_(false), - use_client_view_(true), - accepted_(false), window_closed_(false) { InitClass(); DCHECK(window_delegate_); @@ -112,33 +109,25 @@ void Window::Init(HWND parent, const gfx::Rect& bounds) { if (window_ex_style() == 0) set_window_ex_style(CalculateWindowExStyle()); - // A child window never owns its own focus manager, it uses the one - // associated with the root of the window tree... - if (use_client_view_) { - View* contents_view = window_delegate_->GetContentsView(); - DCHECK(contents_view); - client_view_ = new ClientView(this, contents_view); - // A Window almost always owns its own focus manager, even if it's a child - // window. File a bug if you find a circumstance where this isn't the case - // and we can adjust this API. Note that if this is not the case, you'll - // also have to change SetInitialFocus() as it relies on the window's focus - // manager. - HWNDViewContainer::Init(parent, bounds, true); - SetContentsView(client_view_); - } else { - HWNDViewContainer::Init(parent, bounds, true); - SetContentsView(window_delegate_->GetContentsView()); - } + HWNDViewContainer::Init(parent, bounds, true); win_util::SetWindowUserData(GetHWND(), this); std::wstring window_title = window_delegate_->GetWindowTitle(); SetWindowText(GetHWND(), window_title.c_str()); + + SetClientView(window_delegate_->CreateClientView(this)); SetInitialBounds(bounds); if (window_delegate_->HasAlwaysOnTopMenu()) AddAlwaysOnTopSystemMenuItem(); } +void Window::SetClientView(ClientView* client_view) { + DCHECK(client_view && !client_view_ && GetHWND()); + client_view_ = client_view; + HWNDViewContainer::SetContentsView(client_view_); +} + gfx::Size Window::CalculateWindowSizeForClientSize( const gfx::Size& client_size) const { RECT r = { 0, 0, client_size.width(), client_size.height() }; @@ -197,24 +186,7 @@ void Window::Close() { return; } - bool can_close = true; - // Ask the delegate if we're allowed to close. The user may not have left the - // window in a state where this is allowable (e.g. unsaved work). Also, don't - // call Cancel on the delegate if we've already been accepted and are in the - // process of being closed. Furthermore, if we have only an OK button, but no - // Cancel button, and we're closing without being accepted, call Accept to - // see if we should close. - if (!accepted_) { - DialogDelegate* dd = window_delegate_->AsDialogDelegate(); - if (dd) { - int buttons = dd->GetDialogButtons(); - if (buttons & DialogDelegate::DIALOGBUTTON_CANCEL) - can_close = dd->Cancel(); - else if (buttons & DialogDelegate::DIALOGBUTTON_OK) - can_close = dd->Accept(true); - } - } - if (can_close) { + if (client_view_->CanClose()) { SaveWindowPosition(); RestoreEnabledIfNecessary(); HWNDViewContainer::Close(); @@ -256,27 +228,6 @@ void Window::EnableClose(bool enable) { SWP_NOZORDER); } -void Window::UpdateDialogButtons() { - if (client_view_) - client_view_->UpdateDialogButtons(); -} - -void Window::AcceptWindow() { - accepted_ = true; - DialogDelegate* dd = window_delegate_->AsDialogDelegate(); - if (dd) - accepted_ = dd->Accept(false); - if (accepted_) - Close(); -} - -void Window::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 Window::UpdateWindowTitle() { std::wstring window_title = window_delegate_->GetWindowTitle(); SetWindowText(GetHWND(), window_title.c_str()); @@ -349,21 +300,19 @@ gfx::Size Window::GetLocalizedContentsSize(int col_resource_id, return gfx::Size(width, height); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // Window, protected: void Window::SizeWindowToDefault() { - if (client_view_) { - CSize pref(0, 0); - client_view_->GetPreferredSize(&pref); - DCHECK(pref.cx > 0 && pref.cy > 0); - // CenterAndSizeWindow adjusts the window size to accommodate the non-client - // area. - win_util::CenterAndSizeWindow(owning_window(), GetHWND(), pref, true); - } + CSize pref(0, 0); + client_view_->GetPreferredSize(&pref); + DCHECK(pref.cx > 0 && pref.cy > 0); + // CenterAndSizeWindow adjusts the window size to accommodate the non-client + // area. + win_util::CenterAndSizeWindow(owning_window(), GetHWND(), pref, true); } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // Window, HWNDViewContainer overrides: void Window::OnActivate(UINT action, BOOL minimized, HWND window) { @@ -390,12 +339,13 @@ LRESULT Window::OnEraseBkgnd(HDC dc) { } LRESULT Window::OnNCHitTest(const CPoint& point) { - // We paint the size box over the content area sometimes... check to see if - // the mouse is over it... + // First, give the ClientView a chance to test the point to see if it is part + // of the non-client area. CPoint temp = point; MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1); - if (client_view_ && client_view_->PointIsInSizeBox(gfx::Point(temp))) - return HTBOTTOMRIGHT; + int component = client_view_->NonClientHitTest(gfx::Point(temp)); + if (component != HTNOWHERE) + return component; // Otherwise, we let Windows do all the native frame non-client handling for // us. @@ -472,13 +422,6 @@ void Window::SetInitialFocus() { bool focus_set = false; ChromeViews::View* v = window_delegate_->GetInitiallyFocusedView(); - // For dialogs, try to focus either the OK or Cancel buttons if any. - if (!v && window_delegate_->AsDialogDelegate() && client_view_) { - if (client_view_->ok_button()) - v = client_view_->ok_button(); - else if (client_view_->cancel_button()) - v = client_view_->cancel_button(); - } if (v) { focus_set = true; // In order to make that view the initially focused one, we make it the diff --git a/chrome/views/window.h b/chrome/views/window.h index d6bb48e..534634c 100644 --- a/chrome/views/window.h +++ b/chrome/views/window.h @@ -114,35 +114,19 @@ class Window : public HWNDViewContainer { virtual void EnableClose(bool enable); WindowDelegate* window_delegate() const { return window_delegate_; } - void set_window_delegate(WindowDelegate* delegate) { - window_delegate_ = delegate; - } - // Set whether or not we should insert a client view. See comment below. - void set_use_client_view(bool use_client_view) { - use_client_view_ = use_client_view; - } + // Returns the ClientView object used by this Window. + ClientView* client_view() const { return client_view_; } void set_focus_on_creation(bool focus_on_creation) { focus_on_creation_ = focus_on_creation; } - // Updates the enabled state and label of the dialog buttons visible in this - // window. - void UpdateDialogButtons(); - - // Called when the window should be canceled or accepted, if it is a dialog - // box. - void AcceptWindow(); - void CancelWindow(); - // Tell the window to update its title from the delegate. virtual void UpdateWindowTitle(); // The parent of this window. - HWND owning_window() const { - return owning_hwnd_; - } + HWND owning_window() const { return owning_hwnd_; } // Convenience methods for storing/retrieving window location information // to/from a PrefService using the specified |entry| name. @@ -171,6 +155,16 @@ class Window : public HWNDViewContainer { int row_resource_id); protected: + // Sets the specified view as the ClientView of this Window. The ClientView + // is responsible for laying out the Window's contents view, as well as + // performing basic hit-testing, and perhaps other responsibilities depending + // on the implementation. The Window's view hierarchy takes ownership of the + // ClientView unless the ClientView specifies otherwise. This must be called + // only once, and after the native window has been created. + // This is called by Init. |client_view| cannot be NULL. + virtual void SetClientView(ClientView* client_view); + + // Sizes the window to the default size specified by its ClientView. virtual void SizeWindowToDefault(); // Overridden from HWNDViewContainer: @@ -183,8 +177,9 @@ class Window : public HWNDViewContainer { virtual void OnSize(UINT size_param, const CSize& new_size); virtual void OnSysCommand(UINT notification_code, CPoint click); - // The client view object that contains the client area of the window, - // including optional dialog buttons. + // 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_; // Our window delegate (see Init method for documentation). @@ -249,17 +244,6 @@ class Window : public HWNDViewContainer { // We need to own the text of the menu, the Windows API does not copy it. std::wstring always_on_top_menu_text_; - // Whether or not the client view should be inserted into the Window's view - // hierarchy. - // TODO(beng): (Cleanup) This is probably a short term measure until I figure - // out a way to make other Window subclasses (e.g. - // ConstrainedWindowImpl) and their users jive with the new - // dialog framework. - bool use_client_view_; - - // True if the window was Accepted by the user using the OK button. - bool accepted_; - // Set to true if the window is in the process of closing . bool window_closed_; diff --git a/chrome/views/window_delegate.h b/chrome/views/window_delegate.h index 8f506d2..67990a0 100644 --- a/chrome/views/window_delegate.h +++ b/chrome/views/window_delegate.h @@ -35,6 +35,7 @@ #include <atlmisc.h> #include <string> +#include "chrome/views/client_view.h" #include "chrome/views/window.h" #include "skia/include/SkBitmap.h" @@ -139,6 +140,12 @@ class WindowDelegate { return NULL; } + // Called by the Window to create the Client View used to host the contents + // of the window. + virtual ClientView* CreateClientView(Window* window) { + return new ClientView(window, GetContentsView()); + } + // An accessor to the Window this delegate is bound to. Window* window() const { return window_.get(); } |