| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/views/info_bubble.h" | 5 #include "chrome/browser/views/info_bubble.h" |
| 6 | 6 |
| 7 #include "app/gfx/canvas.h" | 7 #include "app/gfx/canvas.h" |
| 8 #include "app/gfx/color_utils.h" | 8 #include "app/gfx/color_utils.h" |
| 9 #include "app/gfx/path.h" | 9 #include "app/gfx/path.h" |
| 10 #include "base/keyboard_codes.h" | 10 #include "base/keyboard_codes.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 | 28 |
| 29 // This is used to paint the border of the InfoBubble. Windows uses this via | 29 // This is used to paint the border of the InfoBubble. Windows uses this via |
| 30 // BorderWidget (see below), while others can use it directly in the bubble. | 30 // BorderWidget (see below), while others can use it directly in the bubble. |
| 31 class BorderContents : public views::View { | 31 class BorderContents : public views::View { |
| 32 public: | 32 public: |
| 33 BorderContents() { } | 33 BorderContents() { } |
| 34 | 34 |
| 35 // Given the size of the contents and the rect to point at, initializes the | 35 // Given the size of the contents and the rect to point at, initializes the |
| 36 // bubble and returns the bounds of both the border | 36 // bubble and returns the bounds of both the border |
| 37 // and the contents inside the bubble. | 37 // and the contents inside the bubble. |
| 38 // |is_rtl| is true if the UI is RTL and thus the arrow should default to the | 38 // |prefer_arrow_on_right| specifies the preferred location for the arrow |
| 39 // right side of the bubble; otherwise it defaults to the left top corner, and | 39 // anchor. If the bubble does not fit on the monitor, the arrow location may |
| 40 // then is moved as necessary to try and fit the whole bubble on the same | 40 // changed so it can. |
| 41 // monitor as the rect being pointed to. | |
| 42 // | 41 // |
| 43 // TODO(pkasting): Maybe this should use mirroring transformations instead, | 42 // TODO(pkasting): Maybe this should use mirroring transformations instead, |
| 44 // which would hopefully simplify this code. | 43 // which would hopefully simplify this code. |
| 45 void InitAndGetBounds( | 44 void InitAndGetBounds( |
| 46 const gfx::Rect& position_relative_to, // In screen coordinates | 45 const gfx::Rect& position_relative_to, // In screen coordinates |
| 47 const gfx::Size& contents_size, | 46 const gfx::Size& contents_size, |
| 48 bool is_rtl, | 47 bool prefer_arrow_on_right, |
| 49 gfx::Rect* contents_bounds, // Returned in window coordinates | 48 gfx::Rect* contents_bounds, // Returned in window coordinates |
| 50 gfx::Rect* window_bounds); // Returned in screen coordinates | 49 gfx::Rect* window_bounds); // Returned in screen coordinates |
| 51 | 50 |
| 52 private: | 51 private: |
| 53 virtual ~BorderContents() { } | 52 virtual ~BorderContents() { } |
| 54 | 53 |
| 55 // Overridden from View: | 54 // Overridden from View: |
| 56 virtual void Paint(gfx::Canvas* canvas); | 55 virtual void Paint(gfx::Canvas* canvas); |
| 57 | 56 |
| 58 DISALLOW_COPY_AND_ASSIGN(BorderContents); | 57 DISALLOW_COPY_AND_ASSIGN(BorderContents); |
| 59 }; | 58 }; |
| 60 | 59 |
| 61 void BorderContents::InitAndGetBounds( | 60 void BorderContents::InitAndGetBounds( |
| 62 const gfx::Rect& position_relative_to, | 61 const gfx::Rect& position_relative_to, |
| 63 const gfx::Size& contents_size, | 62 const gfx::Size& contents_size, |
| 64 bool is_rtl, | 63 bool prefer_arrow_on_right, |
| 65 gfx::Rect* contents_bounds, | 64 gfx::Rect* contents_bounds, |
| 66 gfx::Rect* window_bounds) { | 65 gfx::Rect* window_bounds) { |
| 67 // Margins between the contents and the inside of the border, in pixels. | 66 // Margins between the contents and the inside of the border, in pixels. |
| 68 const int kLeftMargin = 6; | 67 const int kLeftMargin = 6; |
| 69 const int kTopMargin = 6; | 68 const int kTopMargin = 6; |
| 70 const int kRightMargin = 6; | 69 const int kRightMargin = 6; |
| 71 const int kBottomMargin = 9; | 70 const int kBottomMargin = 9; |
| 72 | 71 |
| 73 // Set the border. | 72 // Set the border. |
| 74 BubbleBorder* bubble_border = new BubbleBorder; | 73 BubbleBorder* bubble_border = new BubbleBorder; |
| 75 set_border(bubble_border); | 74 set_border(bubble_border); |
| 76 bubble_border->set_background_color(InfoBubble::kBackgroundColor); | 75 bubble_border->set_background_color(InfoBubble::kBackgroundColor); |
| 77 | 76 |
| 78 // Give the contents a margin. | 77 // Give the contents a margin. |
| 79 gfx::Size local_contents_size(contents_size); | 78 gfx::Size local_contents_size(contents_size); |
| 80 local_contents_size.Enlarge(kLeftMargin + kRightMargin, | 79 local_contents_size.Enlarge(kLeftMargin + kRightMargin, |
| 81 kTopMargin + kBottomMargin); | 80 kTopMargin + kBottomMargin); |
| 82 | 81 |
| 83 // Try putting the arrow in its default location, and calculating the bounds. | 82 // Try putting the arrow in its initial location, and calculating the |
| 84 BubbleBorder::ArrowLocation arrow_location(is_rtl ? | 83 // bounds. |
| 84 BubbleBorder::ArrowLocation arrow_location(prefer_arrow_on_right ? |
| 85 BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT); | 85 BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT); |
| 86 bubble_border->set_arrow_location(arrow_location); | 86 bubble_border->set_arrow_location(arrow_location); |
| 87 *window_bounds = | 87 *window_bounds = |
| 88 bubble_border->GetBounds(position_relative_to, local_contents_size); | 88 bubble_border->GetBounds(position_relative_to, local_contents_size); |
| 89 | 89 |
| 90 // See if those bounds will fit on the monitor. | 90 // See if those bounds will fit on the monitor. |
| 91 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( | 91 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( |
| 92 WindowSizer::CreateDefaultMonitorInfoProvider()); | 92 WindowSizer::CreateDefaultMonitorInfoProvider()); |
| 93 gfx::Rect monitor_bounds( | 93 gfx::Rect monitor_bounds( |
| 94 monitor_provider->GetMonitorWorkAreaMatching(position_relative_to)); | 94 monitor_provider->GetMonitorWorkAreaMatching(position_relative_to)); |
| 95 if (!monitor_bounds.IsEmpty() && !monitor_bounds.Contains(*window_bounds)) { | 95 if (!monitor_bounds.IsEmpty() && !monitor_bounds.Contains(*window_bounds)) { |
| 96 // The bounds don't fit. Move the arrow to try and improve things. | 96 // The bounds don't fit. Move the arrow to try and improve things. |
| 97 bool arrow_on_left = | 97 bool arrow_on_left = prefer_arrow_on_right ? |
| 98 (is_rtl ? (window_bounds->x() < monitor_bounds.x()) : | 98 (window_bounds->x() < monitor_bounds.x()) : |
| 99 (window_bounds->right() <= monitor_bounds.right())); | 99 (window_bounds->right() <= monitor_bounds.right()); |
| 100 if (window_bounds->bottom() > monitor_bounds.bottom()) { | 100 if (window_bounds->bottom() > monitor_bounds.bottom()) { |
| 101 arrow_location = arrow_on_left ? | 101 arrow_location = arrow_on_left ? |
| 102 BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT; | 102 BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT; |
| 103 } else { | 103 } else { |
| 104 arrow_location = arrow_on_left ? | 104 arrow_location = arrow_on_left ? |
| 105 BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; | 105 BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT; |
| 106 } | 106 } |
| 107 bubble_border->set_arrow_location(arrow_location); | 107 bubble_border->set_arrow_location(arrow_location); |
| 108 | 108 |
| 109 // Now get the recalculated bounds. | 109 // Now get the recalculated bounds. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 BorderWidget::BorderWidget() { | 148 BorderWidget::BorderWidget() { |
| 149 set_delete_on_destroy(false); // Our owner will free us manually. | 149 set_delete_on_destroy(false); // Our owner will free us manually. |
| 150 set_window_style(WS_POPUP); | 150 set_window_style(WS_POPUP); |
| 151 set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED); | 151 set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED); |
| 152 } | 152 } |
| 153 | 153 |
| 154 gfx::Rect BorderWidget::InitAndGetBounds( | 154 gfx::Rect BorderWidget::InitAndGetBounds( |
| 155 HWND owner, | 155 HWND owner, |
| 156 const gfx::Rect& position_relative_to, | 156 const gfx::Rect& position_relative_to, |
| 157 const gfx::Size& contents_size, | 157 const gfx::Size& contents_size, |
| 158 bool is_rtl) { | 158 bool prefer_arrow_on_right) { |
| 159 // Set up the border view and ask it to calculate our bounds (and our | 159 // Set up the border view and ask it to calculate our bounds (and our |
| 160 // contents'). | 160 // contents'). |
| 161 BorderContents* border_contents = new BorderContents; | 161 BorderContents* border_contents = new BorderContents; |
| 162 gfx::Rect contents_bounds, window_bounds; | 162 gfx::Rect contents_bounds, window_bounds; |
| 163 border_contents->InitAndGetBounds(position_relative_to, contents_size, is_rtl, | 163 border_contents->InitAndGetBounds(position_relative_to, contents_size, |
| 164 &contents_bounds, &window_bounds); | 164 prefer_arrow_on_right, &contents_bounds, |
| 165 &window_bounds); |
| 165 | 166 |
| 166 // Initialize ourselves. | 167 // Initialize ourselves. |
| 167 WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds); | 168 WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds); |
| 168 SetContentsView(border_contents); | 169 SetContentsView(border_contents); |
| 169 SetWindowPos(owner, 0, 0, 0, 0, | 170 SetWindowPos(owner, 0, 0, 0, 0, |
| 170 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW); | 171 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW); |
| 171 | 172 |
| 172 // Chop a hole out of our region to show the contents through. | 173 // Chop a hole out of our region to show the contents through. |
| 173 // CreateRectRgn() expects (left, top, right, bottom) in window coordinates. | 174 // CreateRectRgn() expects (left, top, right, bottom) in window coordinates. |
| 174 HRGN contents_region = CreateRectRgn(contents_bounds.x(), contents_bounds.y(), | 175 HRGN contents_region = CreateRectRgn(contents_bounds.x(), contents_bounds.y(), |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 // Create a View to hold the contents of the main window. | 241 // Create a View to hold the contents of the main window. |
| 241 views::View* contents_view = new views::View; | 242 views::View* contents_view = new views::View; |
| 242 // Adding |contents| as a child has to be done before we call | 243 // Adding |contents| as a child has to be done before we call |
| 243 // contents->GetPreferredSize() below, since some supplied views don't | 244 // contents->GetPreferredSize() below, since some supplied views don't |
| 244 // actually initialize themselves until they're added to a hierarchy. | 245 // actually initialize themselves until they're added to a hierarchy. |
| 245 contents_view->AddChildView(contents); | 246 contents_view->AddChildView(contents); |
| 246 SetContentsView(contents_view); | 247 SetContentsView(contents_view); |
| 247 | 248 |
| 248 // Calculate and set the bounds for all windows and views. | 249 // Calculate and set the bounds for all windows and views. |
| 249 gfx::Rect window_bounds; | 250 gfx::Rect window_bounds; |
| 251 |
| 252 bool prefer_arrow_on_right = |
| 253 (contents->UILayoutIsRightToLeft() == delegate->PreferOriginSideAnchor()); |
| 254 |
| 250 #if defined(OS_WIN) | 255 #if defined(OS_WIN) |
| 251 border_.reset(new BorderWidget); | 256 border_.reset(new BorderWidget); |
| 252 // Initialize and position the border window. | 257 // Initialize and position the border window. |
| 253 window_bounds = border_->InitAndGetBounds(GetNativeView(), | 258 window_bounds = border_->InitAndGetBounds(GetNativeView(), |
| 254 position_relative_to, contents->GetPreferredSize(), | 259 position_relative_to, contents->GetPreferredSize(), |
| 255 contents->UILayoutIsRightToLeft()); | 260 prefer_arrow_on_right); |
| 256 | 261 |
| 257 // Make |contents| take up the entire contents view. | 262 // Make |contents| take up the entire contents view. |
| 258 contents_view->SetLayoutManager(new views::FillLayout); | 263 contents_view->SetLayoutManager(new views::FillLayout); |
| 259 | 264 |
| 260 // Paint the background color behind the contents. | 265 // Paint the background color behind the contents. |
| 261 contents_view->set_background( | 266 contents_view->set_background( |
| 262 views::Background::CreateSolidBackground(kBackgroundColor)); | 267 views::Background::CreateSolidBackground(kBackgroundColor)); |
| 263 #else | 268 #else |
| 264 // Create a view to paint the border and background. | 269 // Create a view to paint the border and background. |
| 265 BorderContents* border_contents = new BorderContents; | 270 BorderContents* border_contents = new BorderContents; |
| 266 gfx::Rect contents_bounds; | 271 gfx::Rect contents_bounds; |
| 267 border_contents->InitAndGetBounds(position_relative_to, | 272 border_contents->InitAndGetBounds(position_relative_to, |
| 268 contents->GetPreferredSize(), contents->UILayoutIsRightToLeft(), | 273 contents->GetPreferredSize(), prefer_arrow_on_right, |
| 269 &contents_bounds, &window_bounds); | 274 &contents_bounds, &window_bounds); |
| 270 // This new view must be added before |contents| so it will paint under it. | 275 // This new view must be added before |contents| so it will paint under it. |
| 271 contents_view->AddChildView(0, border_contents); | 276 contents_view->AddChildView(0, border_contents); |
| 272 | 277 |
| 273 // |contents_view| has no layout manager, so we have to explicitly position | 278 // |contents_view| has no layout manager, so we have to explicitly position |
| 274 // its children. | 279 // its children. |
| 275 border_contents->SetBounds(gfx::Rect(gfx::Point(), window_bounds.size())); | 280 border_contents->SetBounds(gfx::Rect(gfx::Point(), window_bounds.size())); |
| 276 contents->SetBounds(contents_bounds); | 281 contents->SetBounds(contents_bounds); |
| 277 #endif | 282 #endif |
| 278 SetBounds(window_bounds); | 283 SetBounds(window_bounds); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 #endif | 332 #endif |
| 328 } | 333 } |
| 329 | 334 |
| 330 bool InfoBubble::AcceleratorPressed(const views::Accelerator& accelerator) { | 335 bool InfoBubble::AcceleratorPressed(const views::Accelerator& accelerator) { |
| 331 if (!delegate_ || delegate_->CloseOnEscape()) { | 336 if (!delegate_ || delegate_->CloseOnEscape()) { |
| 332 Close(true); | 337 Close(true); |
| 333 return true; | 338 return true; |
| 334 } | 339 } |
| 335 return false; | 340 return false; |
| 336 } | 341 } |
| OLD | NEW |