| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/views/frame/app_non_client_frame_view_aura.h" | |
| 6 | |
| 7 #include "base/debug/stack_trace.h" | |
| 8 #include "chrome/browser/ui/views/frame/browser_frame.h" | |
| 9 #include "chrome/browser/ui/views/frame/browser_view.h" | |
| 10 #include "grit/ash_resources.h" | |
| 11 #include "grit/generated_resources.h" // Accessibility names | |
| 12 #include "grit/theme_resources.h" | |
| 13 #include "ui/aura/window.h" | |
| 14 #include "ui/base/hit_test.h" | |
| 15 #include "ui/base/l10n/l10n_util.h" | |
| 16 #include "ui/base/resource/resource_bundle.h" | |
| 17 #include "ui/base/theme_provider.h" | |
| 18 #include "ui/gfx/canvas.h" | |
| 19 #include "ui/gfx/image/image.h" | |
| 20 #include "ui/gfx/point.h" | |
| 21 #include "ui/gfx/rect.h" | |
| 22 #include "ui/gfx/size.h" | |
| 23 #include "ui/views/controls/button/image_button.h" | |
| 24 #include "ui/views/widget/widget.h" | |
| 25 #include "ui/views/window/non_client_view.h" | |
| 26 | |
| 27 #if defined(USE_ASH) | |
| 28 #include "ash/wm/workspace/frame_maximize_button.h" | |
| 29 #endif | |
| 30 | |
| 31 namespace { | |
| 32 // The number of pixels within the shadow to draw the buttons. | |
| 33 const int kShadowStart = 16; | |
| 34 // The size and close buttons are designed to overlap. | |
| 35 const int kButtonOverlap = 1; | |
| 36 | |
| 37 // TODO(pkotwicz): Remove these constants once the IDR_AURA_FULLSCREEN_SHADOW | |
| 38 // resource is updated. | |
| 39 const int kShadowHeightStretch = -1; | |
| 40 } | |
| 41 | |
| 42 class AppNonClientFrameViewAura::ControlView | |
| 43 : public views::View, public views::ButtonListener { | |
| 44 public: | |
| 45 explicit ControlView(AppNonClientFrameViewAura* owner) : | |
| 46 owner_(owner), | |
| 47 close_button_(new views::ImageButton(this)), | |
| 48 #if defined(USE_ASH) | |
| 49 restore_button_(new ash::FrameMaximizeButton(this, owner_)) | |
| 50 #else | |
| 51 restore_button_(new views::ImageButton(this)) | |
| 52 #endif | |
| 53 { | |
| 54 close_button_->SetAccessibleName( | |
| 55 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); | |
| 56 restore_button_->SetAccessibleName( | |
| 57 l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE)); | |
| 58 | |
| 59 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 60 | |
| 61 int control_base_resource_id = owner->browser_view()->IsOffTheRecord() ? | |
| 62 IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE : | |
| 63 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE; | |
| 64 control_base_ = rb.GetImageNamed(control_base_resource_id).ToImageSkia(); | |
| 65 shadow_ = rb.GetImageNamed(IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToImageSkia(); | |
| 66 | |
| 67 AddChildView(close_button_); | |
| 68 AddChildView(restore_button_); | |
| 69 } | |
| 70 | |
| 71 virtual ~ControlView() {} | |
| 72 | |
| 73 virtual void Layout() OVERRIDE { | |
| 74 restore_button_->SetPosition(gfx::Point(kShadowStart, 0)); | |
| 75 close_button_->SetPosition(gfx::Point(kShadowStart + | |
| 76 restore_button_->width() - kButtonOverlap, 0)); | |
| 77 } | |
| 78 | |
| 79 virtual void ViewHierarchyChanged(bool is_add, View* parent, | |
| 80 View* child) OVERRIDE { | |
| 81 if (is_add && child == this) { | |
| 82 SetButtonImages(restore_button_, | |
| 83 IDR_AURA_WINDOW_FULLSCREEN_RESTORE, | |
| 84 IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H, | |
| 85 IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P); | |
| 86 restore_button_->SizeToPreferredSize(); | |
| 87 | |
| 88 SetButtonImages(close_button_, | |
| 89 IDR_AURA_WINDOW_FULLSCREEN_CLOSE, | |
| 90 IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H, | |
| 91 IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P); | |
| 92 close_button_->SizeToPreferredSize(); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
| 97 return gfx::Size(shadow_->width(), | |
| 98 shadow_->height() + kShadowHeightStretch); | |
| 99 } | |
| 100 | |
| 101 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
| 102 canvas->TileImageInt(*control_base_, | |
| 103 restore_button_->x(), | |
| 104 restore_button_->y(), | |
| 105 restore_button_->width() - kButtonOverlap + close_button_->width(), | |
| 106 restore_button_->height()); | |
| 107 | |
| 108 views::View::OnPaint(canvas); | |
| 109 | |
| 110 canvas->DrawImageInt(*shadow_, 0, kShadowHeightStretch); | |
| 111 } | |
| 112 | |
| 113 virtual void ButtonPressed(views::Button* sender, | |
| 114 const ui::Event& event) OVERRIDE { | |
| 115 if (sender == close_button_) { | |
| 116 owner_->frame()->Close(); | |
| 117 } else if (sender == restore_button_) { | |
| 118 restore_button_->SetState(views::CustomButton::BS_NORMAL); | |
| 119 owner_->frame()->Restore(); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 private: | |
| 124 // Sets images whose ids are passed in for each of the respective states | |
| 125 // of |button|. | |
| 126 void SetButtonImages(views::ImageButton* button, int normal_image_id, | |
| 127 int hot_image_id, int pushed_image_id) { | |
| 128 ui::ThemeProvider* theme_provider = GetThemeProvider(); | |
| 129 button->SetImage(views::CustomButton::BS_NORMAL, | |
| 130 theme_provider->GetImageSkiaNamed(normal_image_id)); | |
| 131 button->SetImage(views::CustomButton::BS_HOT, | |
| 132 theme_provider->GetImageSkiaNamed(hot_image_id)); | |
| 133 button->SetImage(views::CustomButton::BS_PUSHED, | |
| 134 theme_provider->GetImageSkiaNamed(pushed_image_id)); | |
| 135 } | |
| 136 | |
| 137 AppNonClientFrameViewAura* owner_; | |
| 138 views::ImageButton* close_button_; | |
| 139 views::ImageButton* restore_button_; | |
| 140 const gfx::ImageSkia* control_base_; | |
| 141 const gfx::ImageSkia* shadow_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(ControlView); | |
| 144 }; | |
| 145 | |
| 146 // Observer to detect when the browser frame widget closes so we can clean | |
| 147 // up our ControlView. Because we can be closed via a keyboard shortcut we | |
| 148 // are not guaranteed to run AppNonClientFrameView's Close() or Restore(). | |
| 149 class AppNonClientFrameViewAura::FrameObserver : public views::WidgetObserver { | |
| 150 public: | |
| 151 explicit FrameObserver(AppNonClientFrameViewAura* owner) : owner_(owner) {} | |
| 152 virtual ~FrameObserver() {} | |
| 153 | |
| 154 // views::WidgetObserver: | |
| 155 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE { | |
| 156 owner_->CloseControlWidget(); | |
| 157 } | |
| 158 | |
| 159 private: | |
| 160 AppNonClientFrameViewAura* owner_; | |
| 161 | |
| 162 DISALLOW_COPY_AND_ASSIGN(FrameObserver); | |
| 163 }; | |
| 164 | |
| 165 // static | |
| 166 const char AppNonClientFrameViewAura::kViewClassName[] = | |
| 167 "AppNonClientFrameViewAura"; | |
| 168 // static | |
| 169 const char AppNonClientFrameViewAura::kControlWindowName[] = | |
| 170 "AppNonClientFrameViewAuraControls"; | |
| 171 | |
| 172 AppNonClientFrameViewAura::AppNonClientFrameViewAura( | |
| 173 BrowserFrame* frame, BrowserView* browser_view) | |
| 174 : BrowserNonClientFrameView(frame, browser_view), | |
| 175 control_view_(new ControlView(this)), | |
| 176 control_widget_(NULL), | |
| 177 frame_observer_(new FrameObserver(this)) { | |
| 178 // This FrameView is always maximized so we don't want the window to have | |
| 179 // resize borders. | |
| 180 frame->GetNativeView()->set_hit_test_bounds_override_inner(gfx::Insets()); | |
| 181 // Watch for frame close so we can clean up the control widget. | |
| 182 frame->AddObserver(frame_observer_.get()); | |
| 183 set_background(views::Background::CreateSolidBackground(SK_ColorBLACK)); | |
| 184 // Create the controls. | |
| 185 control_widget_ = new views::Widget; | |
| 186 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); | |
| 187 params.parent = browser_view->GetNativeWindow(); | |
| 188 params.transparent = true; | |
| 189 control_widget_->Init(params); | |
| 190 control_widget_->SetContentsView(control_view_); | |
| 191 aura::Window* window = control_widget_->GetNativeView(); | |
| 192 window->SetName(kControlWindowName); | |
| 193 gfx::Rect control_bounds = GetControlBounds(); | |
| 194 window->SetBounds(control_bounds); | |
| 195 control_widget_->Show(); | |
| 196 } | |
| 197 | |
| 198 AppNonClientFrameViewAura::~AppNonClientFrameViewAura() { | |
| 199 frame()->RemoveObserver(frame_observer_.get()); | |
| 200 // This frame view can be replaced (and deleted) if the window is restored | |
| 201 // via a keyboard shortcut like Alt-[. Ensure we close the control widget. | |
| 202 CloseControlWidget(); | |
| 203 } | |
| 204 | |
| 205 gfx::Rect AppNonClientFrameViewAura::GetBoundsForClientView() const { | |
| 206 return GetLocalBounds(); | |
| 207 } | |
| 208 | |
| 209 gfx::Rect AppNonClientFrameViewAura::GetWindowBoundsForClientBounds( | |
| 210 const gfx::Rect& client_bounds) const { | |
| 211 return client_bounds; | |
| 212 } | |
| 213 | |
| 214 int AppNonClientFrameViewAura::NonClientHitTest( | |
| 215 const gfx::Point& point) { | |
| 216 return HTNOWHERE; | |
| 217 } | |
| 218 | |
| 219 void AppNonClientFrameViewAura::GetWindowMask(const gfx::Size& size, | |
| 220 gfx::Path* window_mask) { | |
| 221 } | |
| 222 | |
| 223 void AppNonClientFrameViewAura::ResetWindowControls() { | |
| 224 } | |
| 225 | |
| 226 void AppNonClientFrameViewAura::UpdateWindowIcon() { | |
| 227 } | |
| 228 | |
| 229 void AppNonClientFrameViewAura::UpdateWindowTitle() { | |
| 230 } | |
| 231 | |
| 232 gfx::Rect AppNonClientFrameViewAura::GetBoundsForTabStrip( | |
| 233 views::View* tabstrip) const { | |
| 234 return gfx::Rect(); | |
| 235 } | |
| 236 | |
| 237 BrowserNonClientFrameView::TabStripInsets | |
| 238 AppNonClientFrameViewAura::GetTabStripInsets(bool restored) const { | |
| 239 return TabStripInsets(); | |
| 240 } | |
| 241 | |
| 242 int AppNonClientFrameViewAura::GetThemeBackgroundXInset() const { | |
| 243 return 0; | |
| 244 } | |
| 245 | |
| 246 void AppNonClientFrameViewAura::UpdateThrobber(bool running) { | |
| 247 } | |
| 248 | |
| 249 std::string AppNonClientFrameViewAura::GetClassName() const { | |
| 250 return kViewClassName; | |
| 251 } | |
| 252 | |
| 253 void AppNonClientFrameViewAura::OnBoundsChanged( | |
| 254 const gfx::Rect& previous_bounds) { | |
| 255 if (control_widget_) | |
| 256 control_widget_->GetNativeView()->SetBounds(GetControlBounds()); | |
| 257 } | |
| 258 | |
| 259 gfx::Rect AppNonClientFrameViewAura::GetControlBounds() const { | |
| 260 if (!control_view_) | |
| 261 return gfx::Rect(); | |
| 262 gfx::Size preferred = control_view_->GetPreferredSize(); | |
| 263 return gfx::Rect( | |
| 264 width() - preferred.width(), 0, | |
| 265 preferred.width(), preferred.height()); | |
| 266 } | |
| 267 | |
| 268 void AppNonClientFrameViewAura::CloseControlWidget() { | |
| 269 if (control_widget_) { | |
| 270 control_widget_->Close(); | |
| 271 control_widget_ = NULL; | |
| 272 } | |
| 273 } | |
| OLD | NEW |