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

Side by Side Diff: views/bubble/bubble_border.cc

Issue 8588064: views: Move bubble, events, focus and layout to ui/views/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month 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 | « views/bubble/bubble_border.h ('k') | views/bubble/bubble_delegate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "views/bubble/bubble_border.h"
6
7 #include <algorithm> // for std::max
8
9 #include "base/logging.h"
10 #include "grit/ui_resources.h"
11 #include "grit/ui_resources_standard.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #include "ui/base/resource/resource_bundle.h"
14 #include "ui/gfx/canvas_skia.h"
15 #include "ui/gfx/path.h"
16
17 namespace views {
18
19 struct BubbleBorder::BorderImages {
20 BorderImages()
21 : left(NULL),
22 top_left(NULL),
23 top(NULL),
24 top_right(NULL),
25 right(NULL),
26 bottom_right(NULL),
27 bottom(NULL),
28 bottom_left(NULL),
29 left_arrow(NULL),
30 top_arrow(NULL),
31 right_arrow(NULL),
32 bottom_arrow(NULL) {
33 }
34
35 SkBitmap* left;
36 SkBitmap* top_left;
37 SkBitmap* top;
38 SkBitmap* top_right;
39 SkBitmap* right;
40 SkBitmap* bottom_right;
41 SkBitmap* bottom;
42 SkBitmap* bottom_left;
43 SkBitmap* left_arrow;
44 SkBitmap* top_arrow;
45 SkBitmap* right_arrow;
46 SkBitmap* bottom_arrow;
47 };
48
49 // static
50 struct BubbleBorder::BorderImages* BubbleBorder::normal_images_ = NULL;
51 struct BubbleBorder::BorderImages* BubbleBorder::shadow_images_ = NULL;
52
53
54 // The height inside the arrow image, in pixels.
55 static const int kArrowInteriorHeight = 7;
56
57 BubbleBorder::BubbleBorder(ArrowLocation arrow_location, Shadow shadow)
58 : override_arrow_offset_(0),
59 arrow_location_(arrow_location),
60 alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
61 background_color_(SK_ColorWHITE) {
62 images_ = GetBorderImages(shadow);
63
64 // Calculate horizontal and vertical insets for arrow by ensuring that
65 // the widest arrow and corner images will have enough room to avoid overlap
66 int offset_x =
67 (std::max(images_->top_arrow->width(),
68 images_->bottom_arrow->width()) / 2) +
69 std::max(std::max(images_->top_left->width(),
70 images_->top_right->width()),
71 std::max(images_->bottom_left->width(),
72 images_->bottom_right->width()));
73 int offset_y =
74 (std::max(images_->left_arrow->height(),
75 images_->right_arrow->height()) / 2) +
76 std::max(std::max(images_->top_left->height(),
77 images_->top_right->height()),
78 std::max(images_->bottom_left->height(),
79 images_->bottom_right->height()));
80 arrow_offset_ = std::max(offset_x, offset_y);
81 }
82
83 gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to,
84 const gfx::Size& contents_size) const {
85 // Desired size is size of contents enlarged by the size of the border images.
86 gfx::Size border_size(contents_size);
87 gfx::Insets insets;
88 GetInsets(&insets);
89 border_size.Enlarge(insets.left() + insets.right(),
90 insets.top() + insets.bottom());
91
92 // Screen position depends on the arrow location.
93 // The arrow should overlap the target by some amount since there is space
94 // for shadow between arrow tip and bitmap bounds.
95 const int kArrowOverlap = 3;
96 int x = position_relative_to.x();
97 int y = position_relative_to.y();
98 int w = position_relative_to.width();
99 int h = position_relative_to.height();
100 int arrow_offset = override_arrow_offset_ ? override_arrow_offset_ :
101 arrow_offset_;
102
103 // Calculate bubble x coordinate.
104 switch (arrow_location_) {
105 case TOP_LEFT:
106 case BOTTOM_LEFT:
107 x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? w / 2 - arrow_offset :
108 -kArrowOverlap;
109 break;
110
111 case TOP_RIGHT:
112 case BOTTOM_RIGHT:
113 x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ?
114 w / 2 + arrow_offset - border_size.width() + 1 :
115 w - border_size.width() + kArrowOverlap;
116 break;
117
118 case LEFT_TOP:
119 case LEFT_BOTTOM:
120 x += w - kArrowOverlap;
121 break;
122
123 case RIGHT_TOP:
124 case RIGHT_BOTTOM:
125 x += kArrowOverlap - border_size.width();
126 break;
127
128 case NONE:
129 case FLOAT:
130 x += w / 2 - border_size.width() / 2;
131 break;
132 }
133
134 // Calculate bubble y coordinate.
135 switch (arrow_location_) {
136 case TOP_LEFT:
137 case TOP_RIGHT:
138 y += h - kArrowOverlap;
139 break;
140
141 case BOTTOM_LEFT:
142 case BOTTOM_RIGHT:
143 y += kArrowOverlap - border_size.height();
144 break;
145
146 case LEFT_TOP:
147 case RIGHT_TOP:
148 y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? h / 2 - arrow_offset :
149 -kArrowOverlap;
150 break;
151
152 case LEFT_BOTTOM:
153 case RIGHT_BOTTOM:
154 y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ?
155 h / 2 + arrow_offset - border_size.height() + 1 :
156 h - border_size.height() + kArrowOverlap;
157 break;
158
159 case NONE:
160 y += h;
161 break;
162
163 case FLOAT:
164 y += h / 2 - border_size.height() / 2;
165 break;
166 }
167
168 return gfx::Rect(x, y, border_size.width(), border_size.height());
169 }
170
171 void BubbleBorder::GetInsets(gfx::Insets* insets) const {
172 int top = images_->top->height();
173 int bottom = images_->bottom->height();
174 int left = images_->left->width();
175 int right = images_->right->width();
176 switch (arrow_location_) {
177 case TOP_LEFT:
178 case TOP_RIGHT:
179 top = std::max(top, images_->top_arrow->height());
180 break;
181
182 case BOTTOM_LEFT:
183 case BOTTOM_RIGHT:
184 bottom = std::max(bottom, images_->bottom_arrow->height());
185 break;
186
187 case LEFT_TOP:
188 case LEFT_BOTTOM:
189 left = std::max(left, images_->left_arrow->width());
190 break;
191
192 case RIGHT_TOP:
193 case RIGHT_BOTTOM:
194 right = std::max(right, images_->right_arrow->width());
195 break;
196
197 case NONE:
198 case FLOAT:
199 // Nothing to do.
200 break;
201 }
202 insets->Set(top, left, bottom, right);
203 }
204
205 int BubbleBorder::SetArrowOffset(int offset, const gfx::Size& contents_size) {
206 gfx::Size border_size(contents_size);
207 gfx::Insets insets;
208 GetInsets(&insets);
209 border_size.Enlarge(insets.left() + insets.right(),
210 insets.top() + insets.bottom());
211 offset = std::max(arrow_offset_,
212 std::min(offset, (is_arrow_on_horizontal(arrow_location_) ?
213 border_size.width() : border_size.height()) - arrow_offset_));
214 override_arrow_offset_ = offset;
215 return override_arrow_offset_;
216 }
217
218 // static
219 BubbleBorder::BorderImages* BubbleBorder::GetBorderImages(Shadow shadow) {
220 if (shadow == SHADOW && shadow_images_ == NULL) {
221 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
222 shadow_images_ = new BorderImages();
223 shadow_images_->left = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_L);
224 shadow_images_->top_left = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_TL);
225 shadow_images_->top = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_T);
226 shadow_images_->top_right = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_TR);
227 shadow_images_->right = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_R);
228 shadow_images_->bottom_right = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_BR);
229 shadow_images_->bottom = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_B);
230 shadow_images_->bottom_left = rb.GetBitmapNamed(IDR_BUBBLE_SHADOW_BL);
231 shadow_images_->left_arrow = new SkBitmap();
232 shadow_images_->top_arrow = new SkBitmap();
233 shadow_images_->right_arrow = new SkBitmap();
234 shadow_images_->bottom_arrow = new SkBitmap();
235 } else if (shadow == NO_SHADOW && normal_images_ == NULL) {
236 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
237 normal_images_ = new BorderImages();
238 normal_images_->left = rb.GetBitmapNamed(IDR_BUBBLE_L);
239 normal_images_->top_left = rb.GetBitmapNamed(IDR_BUBBLE_TL);
240 normal_images_->top = rb.GetBitmapNamed(IDR_BUBBLE_T);
241 normal_images_->top_right = rb.GetBitmapNamed(IDR_BUBBLE_TR);
242 normal_images_->right = rb.GetBitmapNamed(IDR_BUBBLE_R);
243 normal_images_->bottom_right = rb.GetBitmapNamed(IDR_BUBBLE_BR);
244 normal_images_->bottom = rb.GetBitmapNamed(IDR_BUBBLE_B);
245 normal_images_->bottom_left = rb.GetBitmapNamed(IDR_BUBBLE_BL);
246 normal_images_->left_arrow = rb.GetBitmapNamed(IDR_BUBBLE_L_ARROW);
247 normal_images_->top_arrow = rb.GetBitmapNamed(IDR_BUBBLE_T_ARROW);
248 normal_images_->right_arrow = rb.GetBitmapNamed(IDR_BUBBLE_R_ARROW);
249 normal_images_->bottom_arrow = rb.GetBitmapNamed(IDR_BUBBLE_B_ARROW);
250 }
251 return shadow == SHADOW ? shadow_images_ : normal_images_;
252 }
253
254 BubbleBorder::~BubbleBorder() {}
255
256 void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const {
257 // Convenience shorthand variables.
258 const int tl_width = images_->top_left->width();
259 const int tl_height = images_->top_left->height();
260 const int t_height = images_->top->height();
261 const int tr_width = images_->top_right->width();
262 const int tr_height = images_->top_right->height();
263 const int l_width = images_->left->width();
264 const int r_width = images_->right->width();
265 const int br_width = images_->bottom_right->width();
266 const int br_height = images_->bottom_right->height();
267 const int b_height = images_->bottom->height();
268 const int bl_width = images_->bottom_left->width();
269 const int bl_height = images_->bottom_left->height();
270
271 gfx::Insets insets;
272 GetInsets(&insets);
273 const int top = insets.top() - t_height;
274 const int bottom = view.height() - insets.bottom() + b_height;
275 const int left = insets.left() - l_width;
276 const int right = view.width() - insets.right() + r_width;
277 const int height = bottom - top;
278 const int width = right - left;
279
280 // |arrow_offset| is offset of arrow from the begining of the edge.
281 int arrow_offset = arrow_offset_;
282 if (override_arrow_offset_)
283 arrow_offset = override_arrow_offset_;
284 else if (is_arrow_on_horizontal(arrow_location_) &&
285 !is_arrow_on_left(arrow_location_)) {
286 arrow_offset = view.width() - arrow_offset - 1;
287 } else if (!is_arrow_on_horizontal(arrow_location_) &&
288 !is_arrow_on_top(arrow_location_)) {
289 arrow_offset = view.height() - arrow_offset - 1;
290 }
291
292 // Left edge.
293 if (arrow_location_ == LEFT_TOP || arrow_location_ == LEFT_BOTTOM) {
294 int start_y = top + tl_height;
295 int before_arrow =
296 arrow_offset - start_y - images_->left_arrow->height() / 2;
297 int after_arrow = height - tl_height - bl_height -
298 images_->left_arrow->height() - before_arrow;
299 int tip_y = start_y + before_arrow + images_->left_arrow->height() / 2;
300 DrawArrowInterior(canvas,
301 false,
302 images_->left_arrow->width() - kArrowInteriorHeight,
303 tip_y,
304 kArrowInteriorHeight,
305 images_->left_arrow->height() / 2 - 1);
306 DrawEdgeWithArrow(canvas,
307 false,
308 images_->left,
309 images_->left_arrow,
310 left,
311 start_y,
312 before_arrow,
313 after_arrow,
314 images_->left->width() - images_->left_arrow->width());
315 } else {
316 canvas->TileImageInt(*images_->left, left, top + tl_height, l_width,
317 height - tl_height - bl_height);
318 }
319
320 // Top left corner.
321 canvas->DrawBitmapInt(*images_->top_left, left, top);
322
323 // Top edge.
324 if (arrow_location_ == TOP_LEFT || arrow_location_ == TOP_RIGHT) {
325 int start_x = left + tl_width;
326 int before_arrow = arrow_offset - start_x - images_->top_arrow->width() / 2;
327 int after_arrow = width - tl_width - tr_width -
328 images_->top_arrow->width() - before_arrow;
329 DrawArrowInterior(canvas,
330 true,
331 start_x + before_arrow + images_->top_arrow->width() / 2,
332 images_->top_arrow->height() - kArrowInteriorHeight,
333 1 - images_->top_arrow->width() / 2,
334 kArrowInteriorHeight);
335 DrawEdgeWithArrow(canvas,
336 true,
337 images_->top,
338 images_->top_arrow,
339 start_x,
340 top,
341 before_arrow,
342 after_arrow,
343 images_->top->height() - images_->top_arrow->height());
344 } else {
345 canvas->TileImageInt(*images_->top, left + tl_width, top,
346 width - tl_width - tr_width, t_height);
347 }
348
349 // Top right corner.
350 canvas->DrawBitmapInt(*images_->top_right, right - tr_width, top);
351
352 // Right edge.
353 if (arrow_location_ == RIGHT_TOP || arrow_location_ == RIGHT_BOTTOM) {
354 int start_y = top + tr_height;
355 int before_arrow =
356 arrow_offset - start_y - images_->right_arrow->height() / 2;
357 int after_arrow = height - tl_height - bl_height -
358 images_->right_arrow->height() - before_arrow;
359 int tip_y = start_y + before_arrow + images_->right_arrow->height() / 2;
360 DrawArrowInterior(canvas,
361 false,
362 right - r_width + kArrowInteriorHeight,
363 tip_y,
364 -kArrowInteriorHeight,
365 images_->right_arrow->height() / 2 - 1);
366 DrawEdgeWithArrow(canvas,
367 false,
368 images_->right,
369 images_->right_arrow,
370 right - r_width,
371 start_y,
372 before_arrow,
373 after_arrow,
374 0);
375 } else {
376 canvas->TileImageInt(*images_->right, right - r_width, top + tr_height,
377 r_width, height - tr_height - br_height);
378 }
379
380 // Bottom right corner.
381 canvas->DrawBitmapInt(*images_->bottom_right,
382 right - br_width,
383 bottom - br_height);
384
385 // Bottom edge.
386 if (arrow_location_ == BOTTOM_LEFT || arrow_location_ == BOTTOM_RIGHT) {
387 int start_x = left + bl_width;
388 int before_arrow =
389 arrow_offset - start_x - images_->bottom_arrow->width() / 2;
390 int after_arrow = width - bl_width - br_width -
391 images_->bottom_arrow->width() - before_arrow;
392 int tip_x = start_x + before_arrow + images_->bottom_arrow->width() / 2;
393 DrawArrowInterior(canvas,
394 true,
395 tip_x,
396 bottom - b_height + kArrowInteriorHeight,
397 1 - images_->bottom_arrow->width() / 2,
398 -kArrowInteriorHeight);
399 DrawEdgeWithArrow(canvas,
400 true,
401 images_->bottom,
402 images_->bottom_arrow,
403 start_x,
404 bottom - b_height,
405 before_arrow,
406 after_arrow,
407 0);
408 } else {
409 canvas->TileImageInt(*images_->bottom, left + bl_width, bottom - b_height,
410 width - bl_width - br_width, b_height);
411 }
412
413 // Bottom left corner.
414 canvas->DrawBitmapInt(*images_->bottom_left, left, bottom - bl_height);
415 }
416
417 void BubbleBorder::DrawEdgeWithArrow(gfx::Canvas* canvas,
418 bool is_horizontal,
419 SkBitmap* edge,
420 SkBitmap* arrow,
421 int start_x,
422 int start_y,
423 int before_arrow,
424 int after_arrow,
425 int offset) const {
426 /* Here's what the parameters mean:
427 * start_x
428 * .
429 * . ┌───┐ ┬ offset
430 * start_y..........┌────┬────────┤ ▲ ├────────┬────┐
431 * │ / │--------│∙ ∙│--------│ \ │
432 * │ / ├────────┴───┴────────┤ \ │
433 * ├───┬┘ └┬───┤
434 * └───┬────┘ └───┬────┘
435 * before_arrow ─┘ └─ after_arrow
436 */
437 if (before_arrow) {
438 canvas->TileImageInt(*edge, start_x, start_y,
439 is_horizontal ? before_arrow : edge->width(),
440 is_horizontal ? edge->height() : before_arrow);
441 }
442
443 canvas->DrawBitmapInt(*arrow,
444 start_x + (is_horizontal ? before_arrow : offset),
445 start_y + (is_horizontal ? offset : before_arrow));
446
447 if (after_arrow) {
448 start_x += (is_horizontal ? before_arrow + arrow->width() : 0);
449 start_y += (is_horizontal ? 0 : before_arrow + arrow->height());
450 canvas->TileImageInt(*edge, start_x, start_y,
451 is_horizontal ? after_arrow : edge->width(),
452 is_horizontal ? edge->height() : after_arrow);
453 }
454 }
455
456 void BubbleBorder::DrawArrowInterior(gfx::Canvas* canvas,
457 bool is_horizontal,
458 int tip_x,
459 int tip_y,
460 int shift_x,
461 int shift_y) const {
462 /* This function fills the interior of the arrow with background color.
463 * It draws isosceles triangle under semitransparent arrow tip.
464 *
465 * Here's what the parameters mean:
466 *
467 * ┌──────── |tip_x|
468 * ┌─────┐
469 * │ ▲ │ ──── |tip y|
470 * │∙∙∙∙∙│ ┐
471 * └─────┘ └─── |shift_x| (offset from tip to vertexes of isosceles triangle)
472 * └────────── |shift_y|
473 */
474 SkPaint paint;
475 paint.setStyle(SkPaint::kFill_Style);
476 paint.setColor(background_color_);
477 gfx::Path path;
478 path.incReserve(4);
479 path.moveTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y));
480 path.lineTo(SkIntToScalar(tip_x + shift_x),
481 SkIntToScalar(tip_y + shift_y));
482 if (is_horizontal)
483 path.lineTo(SkIntToScalar(tip_x - shift_x), SkIntToScalar(tip_y + shift_y));
484 else
485 path.lineTo(SkIntToScalar(tip_x + shift_x), SkIntToScalar(tip_y - shift_y));
486 path.close();
487 canvas->GetSkCanvas()->drawPath(path, paint);
488 }
489
490 /////////////////////////
491
492 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
493 // The border of this view creates an anti-aliased round-rect region for the
494 // contents, which we need to fill with the background color.
495 // NOTE: This doesn't handle an arrow location of "NONE", which has square top
496 // corners.
497 SkPaint paint;
498 paint.setAntiAlias(true);
499 paint.setStyle(SkPaint::kFill_Style);
500 paint.setColor(border_->background_color());
501 gfx::Path path;
502 gfx::Rect bounds(view->GetContentsBounds());
503 SkRect rect;
504 rect.set(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()),
505 SkIntToScalar(bounds.right()), SkIntToScalar(bounds.bottom()));
506 SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius());
507 path.addRoundRect(rect, radius, radius);
508 canvas->GetSkCanvas()->drawPath(path, paint);
509 }
510
511 } // namespace views
OLDNEW
« no previous file with comments | « views/bubble/bubble_border.h ('k') | views/bubble/bubble_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698