summaryrefslogtreecommitdiffstats
path: root/ui/views/bubble/bubble_border.h
blob: 4e60fb0360f4e583b675e3e3c6adf69100f7af59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_
#define UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/background.h"
#include "ui/views/border.h"

namespace gfx {
class Rect;
}

namespace views {
class Painter;

namespace internal {

// A helper that combines each border image-set painter with arrows and metrics.
struct BorderImages {
  BorderImages(const int border_image_ids[],
               const int arrow_image_ids[],
               int border_interior_thickness,
               int arrow_interior_thickness,
               int corner_radius);
  virtual ~BorderImages();

  scoped_ptr<Painter> border_painter;
  gfx::ImageSkia left_arrow;
  gfx::ImageSkia top_arrow;
  gfx::ImageSkia right_arrow;
  gfx::ImageSkia bottom_arrow;

  // The thickness of border and arrow images and their interior areas.
  // Thickness is the width of left/right and the height of top/bottom images.
  // The interior is measured without including stroke or shadow pixels.
  int border_thickness;
  int border_interior_thickness;
  int arrow_thickness;
  int arrow_interior_thickness;
  // The corner radius of the bubble's rounded-rect interior area.
  int corner_radius;
};

}  // namespace internal

// Renders a border, with optional arrow, and a custom dropshadow.
// This can be used to produce floating "bubble" objects with rounded corners.
class VIEWS_EXPORT BubbleBorder : public Border {
 public:
  // Possible locations for the (optional) arrow.
  // 0 bit specifies left or right.
  // 1 bit specifies top or bottom.
  // 2 bit specifies horizontal or vertical.
  // 3 bit specifies whether the arrow at the center of its residing edge.
  enum ArrowMask {
    RIGHT    = 0x01,
    BOTTOM   = 0x02,
    VERTICAL = 0x04,
    CENTER   = 0x08,
  };

  enum Arrow {
    TOP_LEFT      = 0,
    TOP_RIGHT     = RIGHT,
    BOTTOM_LEFT   = BOTTOM,
    BOTTOM_RIGHT  = BOTTOM | RIGHT,
    LEFT_TOP      = VERTICAL,
    RIGHT_TOP     = VERTICAL | RIGHT,
    LEFT_BOTTOM   = VERTICAL | BOTTOM,
    RIGHT_BOTTOM  = VERTICAL | BOTTOM | RIGHT,
    TOP_CENTER    = CENTER,
    BOTTOM_CENTER = CENTER | BOTTOM,
    LEFT_CENTER   = CENTER | VERTICAL,
    RIGHT_CENTER  = CENTER | VERTICAL | RIGHT,
    NONE  = 16,  // No arrow. Positioned under the supplied rect.
    FLOAT = 17,  // No arrow. Centered over the supplied rect.
  };

  enum Shadow {
    NO_SHADOW = 0,
    NO_SHADOW_OPAQUE_BORDER,
    BIG_SHADOW,
    SMALL_SHADOW,
    SHADOW_COUNT,
  };

  // The position of the bubble in relation to the anchor.
  enum BubbleAlignment {
    // The tip of the arrow points to the middle of the anchor.
    ALIGN_ARROW_TO_MID_ANCHOR,
    // The edge nearest to the arrow is lined up with the edge of the anchor.
    ALIGN_EDGE_TO_ANCHOR_EDGE,
  };

  // The way the arrow should be painted.
  enum ArrowPaintType {
    // Fully render the arrow.
    PAINT_NORMAL,
    // Leave space for the arrow, but do not paint it.
    PAINT_TRANSPARENT,
    // Neither paint nor leave space for the arrow.
    PAINT_NONE,
  };

  BubbleBorder(Arrow arrow, Shadow shadow, SkColor color);
  ~BubbleBorder() override;

  // Returns the radius of the corner of the border.
  // TODO(xiyuan): Get rid of this since it's part of BorderImages now?
  static int GetCornerRadius() {
    // We can't safely calculate a border radius by comparing the sizes of the
    // side and corner images, because either may have been extended in various
    // directions in order to do more subtle dropshadow fading or other effects.
    // So we hardcode the most accurate value.
    return 4;
  }

  static bool has_arrow(Arrow a) { return a < NONE; }

  static bool is_arrow_on_left(Arrow a) {
    return has_arrow(a) && (a == LEFT_CENTER || !(a & (RIGHT | CENTER)));
  }

  static bool is_arrow_on_top(Arrow a) {
    return has_arrow(a) && (a == TOP_CENTER || !(a & (BOTTOM | CENTER)));
  }

  static bool is_arrow_on_horizontal(Arrow a) {
    return a >= NONE ? false : !(a & VERTICAL);
  }

  static bool is_arrow_at_center(Arrow a) {
    return has_arrow(a) && !!(a & CENTER);
  }

  static Arrow horizontal_mirror(Arrow a) {
    return (a == TOP_CENTER || a == BOTTOM_CENTER || a >= NONE) ?
        a : static_cast<Arrow>(a ^ RIGHT);
  }

  static Arrow vertical_mirror(Arrow a) {
    return (a == LEFT_CENTER || a == RIGHT_CENTER || a >= NONE) ?
        a : static_cast<Arrow>(a ^ BOTTOM);
  }

  // Get or set the arrow type.
  void set_arrow(Arrow arrow) { arrow_ = arrow; }
  Arrow arrow() const { return arrow_; }

  // Get or set the bubble alignment.
  void set_alignment(BubbleAlignment alignment) { alignment_ = alignment; }
  BubbleAlignment alignment() const { return alignment_; }

  // Get the shadow type.
  Shadow shadow() const { return shadow_; }

  // Get or set the background color for the bubble and arrow body.
  void set_background_color(SkColor color) { background_color_ = color; }
  SkColor background_color() const { return background_color_; }

  // If true, the background color should be determined by the host's
  // NativeTheme.
  void set_use_theme_background_color(bool use_theme_background_color) {
    use_theme_background_color_ = use_theme_background_color;
  }
  bool use_theme_background_color() { return use_theme_background_color_; }

  // Sets a desired pixel distance between the arrow tip and the outside edge of
  // the neighboring border image. For example:    |----offset----|
  // '(' represents shadow around the '{' edge:    ((({           ^   })))
  // The arrow will still anchor to the same location but the bubble will shift
  // location to place the arrow |offset| pixels from the perpendicular edge.
  void set_arrow_offset(int offset) { arrow_offset_ = offset; }

  // Sets the way the arrow is actually painted.  Default is PAINT_NORMAL.
  void set_paint_arrow(ArrowPaintType value) { arrow_paint_type_ = value; }

  // Get the desired widget bounds (in screen coordinates) given the anchor rect
  // and bubble content size; calculated from shadow and arrow image dimensions.
  virtual gfx::Rect GetBounds(const gfx::Rect& anchor_rect,
                              const gfx::Size& contents_size) const;

  // Get the border exterior thickness, including stroke and shadow, in pixels.
  int GetBorderThickness() const;

  // Returns the corner radius of the current image set.
  int GetBorderCornerRadius() const;

  // Gets the arrow offset to use.
  int GetArrowOffset(const gfx::Size& border_size) const;

  // Overridden from Border:
  void Paint(const View& view, gfx::Canvas* canvas) override;
  gfx::Insets GetInsets() const override;
  gfx::Size GetMinimumSize() const override;

 private:
  FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetSizeForContentsSizeTest);
  FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetBoundsOriginTest);

  // The border and arrow stroke size used in image assets, in pixels.
  static const int kStroke;

  gfx::Size GetSizeForContentsSize(const gfx::Size& contents_size) const;
  gfx::ImageSkia* GetArrowImage() const;
  gfx::Rect GetArrowRect(const gfx::Rect& bounds) const;
  void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const;

  internal::BorderImages* GetImagesForTest() const;

  Arrow arrow_;
  int arrow_offset_;
  ArrowPaintType arrow_paint_type_;
  BubbleAlignment alignment_;
  Shadow shadow_;
  internal::BorderImages* images_;
  SkColor background_color_;
  bool use_theme_background_color_;

  DISALLOW_COPY_AND_ASSIGN(BubbleBorder);
};

// A Background that clips itself to the specified BubbleBorder and uses
// the background color of the BubbleBorder.
class VIEWS_EXPORT BubbleBackground : public Background {
 public:
  explicit BubbleBackground(BubbleBorder* border) : border_(border) {}

  // Overridden from Background:
  void Paint(gfx::Canvas* canvas, View* view) const override;

 private:
  BubbleBorder* border_;

  DISALLOW_COPY_AND_ASSIGN(BubbleBackground);
};

}  // namespace views

#endif  // UI_VIEWS_BUBBLE_BUBBLE_BORDER_H_