Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Side by Side Diff: chrome/browser/views/info_bubble.cc

Issue 195099: Convert InfoBubble to using BubbleBorder. This also replaces the border grap... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/views/info_bubble.h ('k') | chrome/browser/views/location_bar_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "app/resource_bundle.h"
11 #include "chrome/browser/window_sizer.h" 10 #include "chrome/browser/window_sizer.h"
12 #include "chrome/common/notification_service.h" 11 #include "chrome/common/notification_service.h"
13 #include "grit/theme_resources.h" 12 #include "third_party/Skia/include/core/SkPaint.h"
13 #include "views/fill_layout.h"
14 #include "views/widget/root_view.h" 14 #include "views/widget/root_view.h"
15 #include "views/window/window.h" 15 #include "views/window/window.h"
16 16
17 #if defined(OS_WIN)
18 #include "base/win_util.h"
19 #endif
20
21 using views::View;
22
23 namespace { 17 namespace {
24 18
25 // All sizes are in pixels.
26
27 // Size of the border, along each edge.
28 const int kBorderSize = 1;
29
30 // Size of the arrow.
31 const int kArrowSize = 5;
32
33 // Number of pixels to the start of the arrow from the edge of the window.
34 const int kArrowXOffset = 13;
35
36 // Number of pixels between the tip of the arrow and the region we're
37 // pointing to.
38 const int kArrowToContentPadding = -4;
39
40 // Background color of the bubble. 19 // Background color of the bubble.
41 #if defined(OS_WIN) 20 #if defined(OS_WIN)
42 const SkColor kBackgroundColor = color_utils::GetSysSkColor(COLOR_WINDOW); 21 const SkColor kBackgroundColor = color_utils::GetSysSkColor(COLOR_WINDOW);
43 #else 22 #else
44 // TODO(beng): source from theme provider. 23 // TODO(beng): source from theme provider.
45 const SkColor kBackgroundColor = SK_ColorWHITE; 24 const SkColor kBackgroundColor = SK_ColorWHITE;
46 #endif 25 #endif
47 26
48 // Color of the border and arrow. 27 }
49 const SkColor kBorderColor1 = SkColorSetRGB(99, 99, 99);
50 // Border shadow color.
51 const SkColor kBorderColor2 = SkColorSetRGB(160, 160, 160);
52 28
53 // Intended dimensions of the bubble's corner images. If you update these, 29 #if defined(OS_WIN)
54 // make sure that the OnSize code works. 30 // BorderContents -------------------------------------------------------------
55 const int kInfoBubbleCornerWidth = 3;
56 const int kInfoBubbleCornerHeight = 3;
57 31
58 // Bubble corner images. 32 // This is used to paint the border; see comments on BorderWidget below.
59 const SkBitmap* kInfoBubbleCornerTopLeft = NULL; 33 class BorderContents : public views::View {
60 const SkBitmap* kInfoBubbleCornerTopRight = NULL; 34 public:
61 const SkBitmap* kInfoBubbleCornerBottomLeft = NULL; 35 BorderContents() { }
62 const SkBitmap* kInfoBubbleCornerBottomRight = NULL;
63 36
64 // Margins around the content. 37 // Given the size of the contents and the rect (in screen coordinates) to
65 const int kInfoBubbleViewTopMargin = 6; 38 // point at, initializes the bubble and returns the bounds (in screen
66 const int kInfoBubbleViewBottomMargin = 9; 39 // coordinates) of both the border and the contents inside the bubble.
67 const int kInfoBubbleViewLeftMargin = 6; 40 // |is_rtl| is true if the UI is RTL and thus the arrow should default to the
68 const int kInfoBubbleViewRightMargin = 6; 41 // right side of the bubble; otherwise it defaults to the left top corner, and
42 // then is moved as necessary to try and fit the whole bubble on the same
43 // monitor as the rect being pointed to.
44 //
45 // TODO(pkasting): Maybe this should use mirroring transformations instead,
46 // which would hopefully simplify this code.
47 void InitAndGetBounds(const gfx::Rect& position_relative_to,
48 const gfx::Size& contents_size,
49 bool is_rtl,
50 gfx::Rect* inner_bounds,
51 gfx::Rect* outer_bounds);
69 52
70 } // namespace 53 private:
54 virtual ~BorderContents() { }
55
56 // Overridden from View:
57 virtual void Paint(gfx::Canvas* canvas);
58
59 DISALLOW_COPY_AND_ASSIGN(BorderContents);
60 };
61
62 void BorderContents::InitAndGetBounds(
63 const gfx::Rect& position_relative_to,
64 const gfx::Size& contents_size,
65 bool is_rtl,
66 gfx::Rect* inner_bounds,
67 gfx::Rect* outer_bounds) {
68 // Set the border.
69 BubbleBorder* bubble_border = new BubbleBorder;
70 set_border(bubble_border);
71 bubble_border->set_background_color(kBackgroundColor);
72
73 // Try putting the arrow in its default location, and calculating the bounds.
74 BubbleBorder::ArrowLocation arrow_location(is_rtl ?
75 BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT);
76 bubble_border->set_arrow_location(arrow_location);
77 *outer_bounds = bubble_border->GetBounds(position_relative_to, contents_size);
78
79 // See if those bounds will fit on the monitor.
80 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider(
81 WindowSizer::CreateDefaultMonitorInfoProvider());
82 gfx::Rect monitor_bounds(
83 monitor_provider->GetMonitorWorkAreaMatching(position_relative_to));
84 if (!monitor_bounds.IsEmpty() && !monitor_bounds.Contains(*outer_bounds)) {
85 // The bounds don't fit. Move the arrow to try and improve things.
86 bool arrow_on_left =
87 (is_rtl ? (outer_bounds->x() < monitor_bounds.x()) :
88 (outer_bounds->right() <= monitor_bounds.right()));
89 if (outer_bounds->bottom() > monitor_bounds.bottom()) {
90 arrow_location = arrow_on_left ?
91 BubbleBorder::BOTTOM_LEFT : BubbleBorder::BOTTOM_RIGHT;
92 } else {
93 arrow_location = arrow_on_left ?
94 BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
95 }
96 bubble_border->set_arrow_location(arrow_location);
97
98 // Now get the recalculated bounds.
99 *outer_bounds = bubble_border->GetBounds(position_relative_to,
100 contents_size);
101 }
102
103 // Calculate the bounds of the contained contents by subtracting the border
104 // dimensions.
105 *inner_bounds = *outer_bounds;
106 gfx::Insets insets;
107 bubble_border->GetInsets(&insets);
108 inner_bounds->Inset(insets.left(), insets.top(), insets.right(),
109 insets.bottom());
110 }
111
112 void BorderContents::Paint(gfx::Canvas* canvas) {
113 // The border of this view creates an anti-aliased round-rect region for the
114 // contents, which we need to fill with the background color.
115 SkPaint paint;
116 paint.setAntiAlias(true);
117 paint.setStyle(SkPaint::kFill_Style);
118 paint.setColor(kBackgroundColor);
119 gfx::Path path;
120 gfx::Rect bounds(GetLocalBounds(false));
121 SkRect rect;
122 rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()),
123 SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom()));
124 SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
125 path.addRoundRect(rect, radius, radius);
126 canvas->drawPath(path, paint);
127
128 // Now we paint the border, so it will be alpha-blended atop the contents.
129 // This looks slightly better in the corners than drawing the contents atop
130 // the border.
131 PaintBorder(canvas);
132 }
133
134 // BorderWidget ---------------------------------------------------------------
135
136 BorderWidget::BorderWidget() {
137 set_delete_on_destroy(false); // Our owner will free us manually.
138 set_window_style(WS_POPUP);
139 set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
140 }
141
142 gfx::Rect BorderWidget::InitAndGetBounds(
143 HWND owner,
144 const gfx::Rect& position_relative_to,
145 const gfx::Size& contents_size,
146 bool is_rtl) {
147 // Margins around the contents.
148 const int kLeftMargin = 6;
149 const int kTopMargin = 6;
150 const int kRightMargin = 6;
151 const int kBottomMargin = 9;
152
153 // Set up the border view and ask it to calculate our bounds (and our
154 // contents').
155 gfx::Size local_contents_size(contents_size);
156 local_contents_size.Enlarge(kLeftMargin + kRightMargin,
157 kTopMargin + kBottomMargin);
158 BorderContents* border_contents = new BorderContents;
159 gfx::Rect inner_bounds, outer_bounds;
160 border_contents->InitAndGetBounds(position_relative_to, local_contents_size,
161 is_rtl, &inner_bounds, &outer_bounds);
162
163 // Initialize ourselves.
164 WidgetWin::Init(GetAncestor(owner, GA_ROOT), outer_bounds);
165 SetContentsView(border_contents);
166 SetWindowPos(owner, 0, 0, 0, 0,
167 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW);
168
169 // Chop a hole out of our region to show the contents through.
170 // CreateRectRgn() expects (left, top, right, bottom) in window coordinates.
171 inner_bounds.Inset(kLeftMargin, kTopMargin, kRightMargin, kBottomMargin);
172 gfx::Rect region_bounds(inner_bounds);
173 region_bounds.Offset(-outer_bounds.x(), -outer_bounds.y());
174 HRGN inner_region = CreateRectRgn(region_bounds.x(), region_bounds.y(),
175 region_bounds.right(), region_bounds.bottom());
176 HRGN outer_region = CreateRectRgn(0, 0,
177 outer_bounds.right(), outer_bounds.bottom());
178 CombineRgn(outer_region, outer_region, inner_region, RGN_XOR);
179 DeleteObject(inner_region);
180 SetWindowRgn(outer_region, true);
181
182 return inner_bounds;
183 }
184
185 LRESULT BorderWidget::OnMouseActivate(HWND window,
186 UINT hit_test,
187 UINT mouse_message) {
188 // Never activate.
189 return MA_NOACTIVATE;
190 }
191 #endif
71 192
72 // InfoBubble ----------------------------------------------------------------- 193 // InfoBubble -----------------------------------------------------------------
73 194
74 // static 195 // static
75 InfoBubble* InfoBubble::Show(views::Window* parent, 196 InfoBubble* InfoBubble::Show(views::Window* parent,
76 const gfx::Rect& position_relative_to, 197 const gfx::Rect& position_relative_to,
77 views::View* contents, 198 views::View* contents,
78 InfoBubbleDelegate* delegate) { 199 InfoBubbleDelegate* delegate) {
79 InfoBubble* window = new InfoBubble(); 200 InfoBubble* window = new InfoBubble;
80 window->Init(parent, position_relative_to, contents, delegate); 201 window->Init(parent, position_relative_to, contents, delegate);
81 return window; 202 return window;
82 } 203 }
83 204
84 void InfoBubble::Close() { 205 void InfoBubble::Close() {
85 Close(false); 206 Close(false);
86 } 207 }
87 208
88 InfoBubble::InfoBubble() 209 InfoBubble::InfoBubble()
89 : 210 :
90 #if defined(OS_LINUX) 211 #if defined(OS_LINUX)
91 WidgetGtk(TYPE_POPUP), 212 WidgetGtk(TYPE_POPUP),
92 #endif 213 #endif
93 delegate_(NULL), 214 delegate_(NULL),
94 parent_(NULL), 215 parent_(NULL),
95 content_view_(NULL),
96 closed_(false) { 216 closed_(false) {
97 } 217 }
98 218
99 void InfoBubble::Init(views::Window* parent, 219 void InfoBubble::Init(views::Window* parent,
100 const gfx::Rect& position_relative_to, 220 const gfx::Rect& position_relative_to,
101 views::View* contents, 221 views::View* contents,
102 InfoBubbleDelegate* delegate) { 222 InfoBubbleDelegate* delegate) {
103 parent_ = parent; 223 parent_ = parent;
104 parent_->DisableInactiveRendering(); 224 parent_->DisableInactiveRendering();
105 225
106 delegate_ = delegate; 226 delegate_ = delegate;
107 227
108 if (kInfoBubbleCornerTopLeft == NULL) {
109 kInfoBubbleCornerTopLeft = ResourceBundle::GetSharedInstance()
110 .GetBitmapNamed(IDR_INFO_BUBBLE_CORNER_TOP_LEFT);
111 kInfoBubbleCornerTopRight = ResourceBundle::GetSharedInstance()
112 .GetBitmapNamed(IDR_INFO_BUBBLE_CORNER_TOP_RIGHT);
113 kInfoBubbleCornerBottomLeft = ResourceBundle::GetSharedInstance()
114 .GetBitmapNamed(IDR_INFO_BUBBLE_CORNER_BOTTOM_LEFT);
115 kInfoBubbleCornerBottomRight = ResourceBundle::GetSharedInstance()
116 .GetBitmapNamed(IDR_INFO_BUBBLE_CORNER_BOTTOM_RIGHT);
117 }
118 #if defined(OS_WIN) 228 #if defined(OS_WIN)
119 set_window_style(WS_POPUP | WS_CLIPCHILDREN); 229 set_window_style(WS_POPUP | WS_CLIPCHILDREN);
120 set_window_ex_style(WS_EX_TOOLWINDOW); 230 set_window_ex_style(WS_EX_TOOLWINDOW);
121 set_initial_class_style( 231 border_.reset(new BorderWidget);
122 (win_util::GetWinVersion() < win_util::WINVERSION_XP) ?
123 0 : CS_DROPSHADOW);
124 #endif 232 #endif
125 content_view_ = CreateContentView(contents);
126 233
127 #if defined(OS_WIN) 234 #if defined(OS_WIN)
128 WidgetWin::Init(parent->GetNativeWindow(), gfx::Rect()); 235 WidgetWin::Init(parent->GetNativeWindow(), gfx::Rect());
129 #else 236 #else
130 WidgetGtk::Init(GTK_WIDGET(parent->GetNativeWindow()), gfx::Rect()); 237 WidgetGtk::Init(GTK_WIDGET(parent->GetNativeWindow()), gfx::Rect());
131 #endif 238 #endif
132 239
133 SetContentsView(content_view_); 240 views::View* contents_view = new views::View;
134 // The preferred size may differ when parented. Ask for the bounds again 241 contents_view->set_background(
135 // and if they differ reset the bounds. 242 views::Background::CreateSolidBackground(kBackgroundColor));
136 gfx::Rect parented_bounds = 243 contents_view->SetLayoutManager(new views::FillLayout);
137 content_view_->CalculateWindowBoundsAndAjust(position_relative_to); 244 // Adding |contents| as a child has to be done before we call
138 SetBounds(parented_bounds); 245 // contents->GetPreferredSize() below, since some supplied views don't
246 // actually set themselves up until they're added to a hierarchy.
247 contents_view->AddChildView(contents);
248 SetContentsView(contents_view);
139 249
250 gfx::Rect bounds;
140 #if defined(OS_WIN) 251 #if defined(OS_WIN)
252 bounds = border_->InitAndGetBounds(GetNativeView(),
253 position_relative_to,
254 contents_view->GetPreferredSize(),
255 contents->UILayoutIsRightToLeft());
256
141 // Register the Escape accelerator for closing. 257 // Register the Escape accelerator for closing.
142 GetFocusManager()->RegisterAccelerator( 258 GetFocusManager()->RegisterAccelerator(
143 views::Accelerator(VK_ESCAPE, false, false, false), this); 259 views::Accelerator(VK_ESCAPE, false, false, false), this);
144 #endif 260 #endif
261 SetBounds(bounds);
145 262
146 NotificationService::current()->Notify(NotificationType::INFO_BUBBLE_CREATED, 263 NotificationService::current()->Notify(NotificationType::INFO_BUBBLE_CREATED,
147 Source<InfoBubble>(this), 264 Source<InfoBubble>(this),
148 NotificationService::NoDetails()); 265 NotificationService::NoDetails());
149 266
150 // Show the window. 267 // Show the window.
151 #if defined(OS_WIN) 268 #if defined(OS_WIN)
269 border_->ShowWindow(SW_SHOW);
152 ShowWindow(SW_SHOW); 270 ShowWindow(SW_SHOW);
153 #else 271 #else
154 views::WidgetGtk::Show(); 272 views::WidgetGtk::Show();
155 #endif 273 #endif
156 } 274 }
157 275
158 InfoBubble::ContentView* InfoBubble::CreateContentView(View* content) {
159 return new ContentView(content, this);
160 }
161
162 #if defined(OS_WIN) 276 #if defined(OS_WIN)
163 void InfoBubble::OnActivate(UINT action, BOOL minimized, HWND window) { 277 void InfoBubble::OnActivate(UINT action, BOOL minimized, HWND window) {
164 // The popup should close when it is deactivated. 278 // The popup should close when it is deactivated.
165 if (action == WA_INACTIVE && !closed_) { 279 if (action == WA_INACTIVE && !closed_) {
166 Close(); 280 Close();
167 } else if (action == WA_ACTIVE) { 281 } else if (action == WA_ACTIVE) {
168 DCHECK(GetRootView()->GetChildViewCount() > 0); 282 DCHECK(GetRootView()->GetChildViewCount() > 0);
169 GetRootView()->GetChildViewAt(0)->RequestFocus(); 283 GetRootView()->GetChildViewAt(0)->RequestFocus();
170 } 284 }
171 } 285 }
172
173 void InfoBubble::OnSize(UINT param, const CSize& size) {
174 // See OnSizeAllocate for the Linux version.
175 gfx::Path path;
176 content_view_->GetMask(gfx::Size(size.cx, size.cy), &path);
177 SetWindowRgn(path.CreateHRGN(), TRUE);
178 WidgetWin::OnSize(param, size);
179 }
180 #elif defined(OS_LINUX)
181 void InfoBubble::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {
182 gfx::Path path;
183 content_view_->GetMask(gfx::Size(allocation->width, allocation->height),
184 &path);
185 SetShape(path);
186 WidgetGtk::OnSizeAllocate(widget, allocation);
187 }
188 #endif 286 #endif
189 287
190 void InfoBubble::Close(bool closed_by_escape) { 288 void InfoBubble::Close(bool closed_by_escape) {
191 if (closed_) 289 if (closed_)
192 return; 290 return;
193 291
194 if (delegate_) 292 if (delegate_)
195 delegate_->InfoBubbleClosing(this, closed_by_escape); 293 delegate_->InfoBubbleClosing(this, closed_by_escape);
196 closed_ = true; 294 closed_ = true;
197 #if defined(OS_WIN) 295 #if defined(OS_WIN)
296 border_->Close();
198 WidgetWin::Close(); 297 WidgetWin::Close();
199 #else 298 #else
200 WidgetGtk::Close(); 299 WidgetGtk::Close();
201 #endif 300 #endif
202 } 301 }
203 302
204 bool InfoBubble::AcceleratorPressed(const views::Accelerator& accelerator) { 303 bool InfoBubble::AcceleratorPressed(const views::Accelerator& accelerator) {
205 if (!delegate_ || delegate_->CloseOnEscape()) { 304 if (!delegate_ || delegate_->CloseOnEscape()) {
206 Close(true); 305 Close(true);
207 return true; 306 return true;
208 } 307 }
209 return false; 308 return false;
210 } 309 }
211
212 // ContentView ----------------------------------------------------------------
213
214 InfoBubble::ContentView::ContentView(views::View* content, InfoBubble* host)
215 : content_(content),
216 host_(host) {
217 if (UILayoutIsRightToLeft()) {
218 arrow_edge_ = TOP_RIGHT;
219 } else {
220 arrow_edge_ = TOP_LEFT;
221 }
222 }
223
224 gfx::Rect InfoBubble::ContentView::CalculateWindowBoundsAndAjust(
225 const gfx::Rect& position_relative_to) {
226 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider(
227 WindowSizer::CreateDefaultMonitorInfoProvider());
228 gfx::Rect monitor_bounds(
229 monitor_provider->GetMonitorWorkAreaMatching(position_relative_to));
230 // Calculate the bounds using TOP_LEFT (the default).
231 gfx::Rect window_bounds = CalculateWindowBounds(position_relative_to);
232 if (monitor_bounds.IsEmpty() || monitor_bounds.Contains(window_bounds))
233 return window_bounds;
234 // Didn't fit, adjust the edge to fit as much as we can.
235 if (window_bounds.bottom() > monitor_bounds.bottom())
236 SetArrowEdge(BOTTOM_LEFT);
237 if (window_bounds.right() > monitor_bounds.right()) {
238 if (IsTop())
239 SetArrowEdge(TOP_RIGHT);
240 else
241 SetArrowEdge(BOTTOM_RIGHT);
242 }
243 // And return new bounds.
244 return CalculateWindowBounds(position_relative_to);
245 }
246
247 gfx::Size InfoBubble::ContentView::GetPreferredSize() {
248 DCHECK(GetChildViewCount() == 1);
249 View* content = GetChildViewAt(0);
250 gfx::Size pref = content->GetPreferredSize();
251 pref.Enlarge(kBorderSize + kBorderSize + kInfoBubbleViewLeftMargin +
252 kInfoBubbleViewRightMargin,
253 kBorderSize + kBorderSize + kArrowSize +
254 kInfoBubbleViewTopMargin + kInfoBubbleViewBottomMargin);
255 return pref;
256 }
257
258 void InfoBubble::ContentView::Layout() {
259 DCHECK(GetChildViewCount() == 1);
260 View* content = GetChildViewAt(0);
261 int x = kBorderSize;
262 int y = kBorderSize;
263 int content_width = width() - kBorderSize - kBorderSize -
264 kInfoBubbleViewLeftMargin - kInfoBubbleViewRightMargin;
265 int content_height = height() - kBorderSize - kBorderSize - kArrowSize -
266 kInfoBubbleViewTopMargin - kInfoBubbleViewBottomMargin;
267 if (IsTop())
268 y += kArrowSize;
269 x += kInfoBubbleViewLeftMargin;
270 y += kInfoBubbleViewTopMargin;
271 content->SetBounds(x, y, content_width, content_height);
272 }
273
274 void InfoBubble::ContentView::GetMask(const gfx::Size& size, gfx::Path* mask) {
275 // Redefine the window visible region so that our dropshadows look right.
276 SkScalar width = SkIntToScalar(size.width());
277 SkScalar height = SkIntToScalar(size.height());
278 SkScalar arrow_size = SkIntToScalar(kArrowSize);
279 SkScalar arrow_x = SkIntToScalar(
280 (IsLeft() ? kArrowXOffset : width - kArrowXOffset) - 1);
281 SkScalar corner_size = SkIntToScalar(kInfoBubbleCornerHeight);
282
283 if (IsTop()) {
284 // Top left corner.
285 mask->moveTo(0, arrow_size + corner_size - 1);
286 mask->lineTo(corner_size - 1, arrow_size);
287
288 // Draw the arrow and the notch of the arrow.
289 mask->lineTo(arrow_x - arrow_size, arrow_size);
290 mask->lineTo(arrow_x, 0);
291 mask->lineTo(arrow_x + 3, 0);
292 mask->lineTo(arrow_x + arrow_size + 3, arrow_size);
293
294 // Top right corner.
295 mask->lineTo(width - corner_size + 1, arrow_size);
296 mask->lineTo(width, arrow_size + corner_size - 1);
297
298 // Bottom right corner.
299 mask->lineTo(width, height - corner_size);
300 mask->lineTo(width - corner_size, height);
301
302 // Bottom left corner.
303 mask->lineTo(corner_size, height);
304 mask->lineTo(0, height - corner_size);
305 } else {
306 // Top left corner.
307 mask->moveTo(0, corner_size - 1);
308 mask->lineTo(corner_size - 1, 0);
309
310 // Top right corner.
311 mask->lineTo(width - corner_size + 1, 0);
312 mask->lineTo(width, corner_size - 1);
313
314 // Bottom right corner.
315 mask->lineTo(width, height - corner_size - arrow_size);
316 mask->lineTo(width - corner_size, height - arrow_size);
317
318 // Draw the arrow and the notch of the arrow.
319 mask->lineTo(arrow_x + arrow_size + 2, height - arrow_size);
320 mask->lineTo(arrow_x + 2, height);
321 mask->lineTo(arrow_x + 1, height);
322 mask->lineTo(arrow_x - arrow_size + 1, height - arrow_size);
323
324 // Bottom left corner.
325 mask->lineTo(corner_size, height - arrow_size);
326 mask->lineTo(0, height - corner_size - arrow_size);
327 }
328
329 mask->close();
330 }
331
332 void InfoBubble::ContentView::Paint(gfx::Canvas* canvas) {
333 int bubble_x = 0;
334 int bubble_y = 0;
335 int bubble_w = width();
336 int bubble_h = height() - kArrowSize;
337
338 int border_w = bubble_w - 2 * kInfoBubbleCornerWidth;
339 int border_h = bubble_h - 2 * kInfoBubbleCornerHeight;
340
341 if (IsTop())
342 bubble_y += kArrowSize;
343
344 // Fill in the background.
345 // Left side.
346 canvas->FillRectInt(kBackgroundColor,
347 bubble_x, bubble_y + kInfoBubbleCornerHeight,
348 kInfoBubbleCornerWidth, border_h);
349 // Center Column.
350 canvas->FillRectInt(kBackgroundColor,
351 kInfoBubbleCornerWidth, bubble_y,
352 border_w, bubble_h);
353 // Right Column.
354 canvas->FillRectInt(kBackgroundColor,
355 bubble_w - kInfoBubbleCornerWidth,
356 bubble_y + kInfoBubbleCornerHeight,
357 kInfoBubbleCornerWidth, border_h);
358
359 // Draw the border.
360 // Top border.
361 canvas->DrawLineInt(kBorderColor1,
362 kInfoBubbleCornerWidth, bubble_y,
363 kInfoBubbleCornerWidth + border_w, bubble_y);
364 // Bottom border.
365 canvas->DrawLineInt(kBorderColor1,
366 kInfoBubbleCornerWidth, bubble_y + bubble_h - 1,
367 kInfoBubbleCornerWidth + border_w,
368 bubble_y + bubble_h - 1);
369 // Left border.
370 canvas->DrawLineInt(kBorderColor1,
371 bubble_x, bubble_y + kInfoBubbleCornerHeight,
372 bubble_x, bubble_y + kInfoBubbleCornerHeight + border_h);
373
374 // Right border.
375 canvas->DrawLineInt(kBorderColor1,
376 width() - 1, bubble_y + kInfoBubbleCornerHeight,
377 width() - 1,
378 bubble_y + kInfoBubbleCornerHeight + border_h);
379
380 // Draw the corners.
381 canvas->DrawBitmapInt(*kInfoBubbleCornerTopLeft, 0, bubble_y);
382 canvas->DrawBitmapInt(*kInfoBubbleCornerTopRight,
383 bubble_w - kInfoBubbleCornerWidth, bubble_y);
384 canvas->DrawBitmapInt(*kInfoBubbleCornerBottomLeft, 0,
385 bubble_y + bubble_h - kInfoBubbleCornerHeight);
386 canvas->DrawBitmapInt(*kInfoBubbleCornerBottomRight,
387 bubble_w - kInfoBubbleCornerWidth,
388 bubble_y + bubble_h - kInfoBubbleCornerHeight);
389
390 // Draw the arrow and the notch of the arrow.
391 int arrow_x = IsLeft() ? kArrowXOffset : width() - kArrowXOffset;
392 int arrow_y = IsTop() ? bubble_y : bubble_y + bubble_h - 1;
393 const int arrow_delta = IsTop() ? -1 : 1;
394 for (int i = 0, y = arrow_y; i <= kArrowSize; ++i, y += arrow_delta) {
395 if (kArrowSize != i) {
396 // Draw the notch formed by the arrow.
397 canvas->FillRectInt(kBackgroundColor, arrow_x - (kArrowSize - i) + 1,
398 y, (kArrowSize - i) * 2 - 1, 1);
399 }
400 // Draw the sides of the arrow.
401 canvas->FillRectInt(kBorderColor1, arrow_x - (kArrowSize - i), y, 1, 1);
402 canvas->FillRectInt(kBorderColor1, arrow_x + (kArrowSize - i), y, 1, 1);
403 if (i != 0) {
404 canvas->FillRectInt(kBorderColor2, arrow_x - (kArrowSize - i) - 1, y, 1,
405 1);
406 canvas->FillRectInt(kBorderColor2, arrow_x + (kArrowSize - i) + 1, y, 1,
407 1);
408 }
409 }
410 }
411
412 void InfoBubble::ContentView::ViewHierarchyChanged(bool is_add,
413 View* parent,
414 View* child) {
415 if (is_add && child == this)
416 AddChildView(content_);
417 }
418
419 gfx::Rect InfoBubble::ContentView::CalculateWindowBounds(
420 const gfx::Rect& position_relative_to) {
421 gfx::Size pref = GetPreferredSize();
422 int x = position_relative_to.x() + position_relative_to.width() / 2;
423 int y;
424 if (IsLeft())
425 x -= kArrowXOffset;
426 else
427 x = x + kArrowXOffset - pref.width();
428 if (IsTop()) {
429 y = position_relative_to.bottom() + kArrowToContentPadding;
430 } else {
431 y = position_relative_to.y() - kArrowToContentPadding - pref.height();
432 }
433 return gfx::Rect(x, y, pref.width(), pref.height());
434 }
OLDNEW
« no previous file with comments | « chrome/browser/views/info_bubble.h ('k') | chrome/browser/views/location_bar_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698