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 #ifndef UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_ 6 #define UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_ 7 8 #include "base/basictypes.h" 9 #include "base/compiler_specific.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "ui/gfx/image/image_skia.h" 12 #include "ui/views/background.h" 13 #include "ui/views/border.h" 14 15 namespace gfx { 16 class Rect; 17 } 18 19 namespace views { 20 class Painter; 21 22 namespace internal { 23 24 // A helper that combines each border image-set painter with arrows and metrics. 25 struct BorderImages { 26 BorderImages(const int border_image_ids[], 27 const int arrow_image_ids[], 28 int border_interior_thickness, 29 int arrow_interior_thickness, 30 int corner_radius); 31 virtual ~BorderImages(); 32 33 scoped_ptr<Painter> border_painter; 34 gfx::ImageSkia left_arrow; 35 gfx::ImageSkia top_arrow; 36 gfx::ImageSkia right_arrow; 37 gfx::ImageSkia bottom_arrow; 38 39 // The thickness of border and arrow images and their interior areas. 40 // Thickness is the width of left/right and the height of top/bottom images. 41 // The interior is measured without including stroke or shadow pixels. 42 int border_thickness; 43 int border_interior_thickness; 44 int arrow_thickness; 45 int arrow_interior_thickness; 46 // The corner radius of the bubble's rounded-rect interior area. 47 int corner_radius; 48 }; 49 50 } // namespace internal 51 52 // Renders a border, with optional arrow, and a custom dropshadow. 53 // This can be used to produce floating "bubble" objects with rounded corners. 54 class VIEWS_EXPORT BubbleBorder : public Border { 55 public: 56 // Possible locations for the (optional) arrow. 57 // 0 bit specifies left or right. 58 // 1 bit specifies top or bottom. 59 // 2 bit specifies horizontal or vertical. 60 // 3 bit specifies whether the arrow at the center of its residing edge. 61 enum ArrowMask { 62 RIGHT = 0x01, 63 BOTTOM = 0x02, 64 VERTICAL = 0x04, 65 CENTER = 0x08, 66 }; 67 68 enum Arrow { 69 TOP_LEFT = 0, 70 TOP_RIGHT = RIGHT, 71 BOTTOM_LEFT = BOTTOM, 72 BOTTOM_RIGHT = BOTTOM | RIGHT, 73 LEFT_TOP = VERTICAL, 74 RIGHT_TOP = VERTICAL | RIGHT, 75 LEFT_BOTTOM = VERTICAL | BOTTOM, 76 RIGHT_BOTTOM = VERTICAL | BOTTOM | RIGHT, 77 TOP_CENTER = CENTER, 78 BOTTOM_CENTER = CENTER | BOTTOM, 79 LEFT_CENTER = CENTER | VERTICAL, 80 RIGHT_CENTER = CENTER | VERTICAL | RIGHT, 81 NONE = 16, // No arrow. Positioned under the supplied rect. 82 FLOAT = 17, // No arrow. Centered over the supplied rect. 83 }; 84 85 enum Shadow { 86 NO_SHADOW = 0, 87 NO_SHADOW_OPAQUE_BORDER, 88 BIG_SHADOW, 89 SMALL_SHADOW, 90 SHADOW_COUNT, 91 }; 92 93 // The position of the bubble in relation to the anchor. 94 enum BubbleAlignment { 95 // The tip of the arrow points to the middle of the anchor. 96 ALIGN_ARROW_TO_MID_ANCHOR, 97 // The edge nearest to the arrow is lined up with the edge of the anchor. 98 ALIGN_EDGE_TO_ANCHOR_EDGE, 99 }; 100 101 // The way the arrow should be painted. 102 enum ArrowPaintType { 103 // Fully render the arrow. 104 PAINT_NORMAL, 105 // Leave space for the arrow, but do not paint it. 106 PAINT_TRANSPARENT, 107 // Neither paint nor leave space for the arrow. 108 PAINT_NONE, 109 }; 110 111 BubbleBorder(Arrow arrow, Shadow shadow, SkColor color); 112 virtual ~BubbleBorder(); 113 114 // Returns the radius of the corner of the border. 115 // TODO(xiyuan): Get rid of this since it's part of BorderImages now? GetCornerRadius()116 static int GetCornerRadius() { 117 // We can't safely calculate a border radius by comparing the sizes of the 118 // side and corner images, because either may have been extended in various 119 // directions in order to do more subtle dropshadow fading or other effects. 120 // So we hardcode the most accurate value. 121 return 4; 122 } 123 has_arrow(Arrow a)124 static bool has_arrow(Arrow a) { return a < NONE; } 125 is_arrow_on_left(Arrow a)126 static bool is_arrow_on_left(Arrow a) { 127 return has_arrow(a) && (a == LEFT_CENTER || !(a & (RIGHT | CENTER))); 128 } 129 is_arrow_on_top(Arrow a)130 static bool is_arrow_on_top(Arrow a) { 131 return has_arrow(a) && (a == TOP_CENTER || !(a & (BOTTOM | CENTER))); 132 } 133 is_arrow_on_horizontal(Arrow a)134 static bool is_arrow_on_horizontal(Arrow a) { 135 return a >= NONE ? false : !(a & VERTICAL); 136 } 137 is_arrow_at_center(Arrow a)138 static bool is_arrow_at_center(Arrow a) { 139 return has_arrow(a) && !!(a & CENTER); 140 } 141 horizontal_mirror(Arrow a)142 static Arrow horizontal_mirror(Arrow a) { 143 return (a == TOP_CENTER || a == BOTTOM_CENTER || a >= NONE) ? 144 a : static_cast<Arrow>(a ^ RIGHT); 145 } 146 vertical_mirror(Arrow a)147 static Arrow vertical_mirror(Arrow a) { 148 return (a == LEFT_CENTER || a == RIGHT_CENTER || a >= NONE) ? 149 a : static_cast<Arrow>(a ^ BOTTOM); 150 } 151 152 // Get or set the arrow type. set_arrow(Arrow arrow)153 void set_arrow(Arrow arrow) { arrow_ = arrow; } arrow()154 Arrow arrow() const { return arrow_; } 155 156 // Get or set the bubble alignment. set_alignment(BubbleAlignment alignment)157 void set_alignment(BubbleAlignment alignment) { alignment_ = alignment; } alignment()158 BubbleAlignment alignment() const { return alignment_; } 159 160 // Get the shadow type. shadow()161 Shadow shadow() const { return shadow_; } 162 163 // Get or set the background color for the bubble and arrow body. set_background_color(SkColor color)164 void set_background_color(SkColor color) { background_color_ = color; } background_color()165 SkColor background_color() const { return background_color_; } 166 167 // If true, the background color should be determined by the host's 168 // NativeTheme. set_use_theme_background_color(bool use_theme_background_color)169 void set_use_theme_background_color(bool use_theme_background_color) { 170 use_theme_background_color_ = use_theme_background_color; 171 } use_theme_background_color()172 bool use_theme_background_color() { return use_theme_background_color_; } 173 174 // Sets a desired pixel distance between the arrow tip and the outside edge of 175 // the neighboring border image. For example: |----offset----| 176 // '(' represents shadow around the '{' edge: ((({ ^ }))) 177 // The arrow will still anchor to the same location but the bubble will shift 178 // location to place the arrow |offset| pixels from the perpendicular edge. set_arrow_offset(int offset)179 void set_arrow_offset(int offset) { arrow_offset_ = offset; } 180 181 // Sets the way the arrow is actually painted. Default is PAINT_NORMAL. set_paint_arrow(ArrowPaintType value)182 void set_paint_arrow(ArrowPaintType value) { arrow_paint_type_ = value; } 183 184 // Get the desired widget bounds (in screen coordinates) given the anchor rect 185 // and bubble content size; calculated from shadow and arrow image dimensions. 186 virtual gfx::Rect GetBounds(const gfx::Rect& anchor_rect, 187 const gfx::Size& contents_size) const; 188 189 // Get the border exterior thickness, including stroke and shadow, in pixels. 190 int GetBorderThickness() const; 191 192 // Returns the corner radius of the current image set. 193 int GetBorderCornerRadius() const; 194 195 // Gets the arrow offset to use. 196 int GetArrowOffset(const gfx::Size& border_size) const; 197 198 // Overridden from Border: 199 virtual void Paint(const View& view, gfx::Canvas* canvas) OVERRIDE; 200 virtual gfx::Insets GetInsets() const OVERRIDE; 201 virtual gfx::Size GetMinimumSize() const OVERRIDE; 202 203 private: 204 FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetSizeForContentsSizeTest); 205 FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetBoundsOriginTest); 206 207 // The border and arrow stroke size used in image assets, in pixels. 208 static const int kStroke; 209 210 gfx::Size GetSizeForContentsSize(const gfx::Size& contents_size) const; 211 gfx::ImageSkia* GetArrowImage() const; 212 gfx::Rect GetArrowRect(const gfx::Rect& bounds) const; 213 void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const; 214 215 internal::BorderImages* GetImagesForTest() const; 216 217 Arrow arrow_; 218 int arrow_offset_; 219 ArrowPaintType arrow_paint_type_; 220 BubbleAlignment alignment_; 221 Shadow shadow_; 222 internal::BorderImages* images_; 223 SkColor background_color_; 224 bool use_theme_background_color_; 225 226 DISALLOW_COPY_AND_ASSIGN(BubbleBorder); 227 }; 228 229 // A Background that clips itself to the specified BubbleBorder and uses 230 // the background color of the BubbleBorder. 231 class VIEWS_EXPORT BubbleBackground : public Background { 232 public: BubbleBackground(BubbleBorder * border)233 explicit BubbleBackground(BubbleBorder* border) : border_(border) {} 234 235 // Overridden from Background: 236 virtual void Paint(gfx::Canvas* canvas, View* view) const OVERRIDE; 237 238 private: 239 BubbleBorder* border_; 240 241 DISALLOW_COPY_AND_ASSIGN(BubbleBackground); 242 }; 243 244 } // namespace views 245 246 #endif // UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_ 247