Home | History | Annotate | Download | only in bubble
      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?
    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 
    124   static bool has_arrow(Arrow a) { return a < NONE; }
    125 
    126   static bool is_arrow_on_left(Arrow a) {
    127     return has_arrow(a) && (a == LEFT_CENTER || !(a & (RIGHT | CENTER)));
    128   }
    129 
    130   static bool is_arrow_on_top(Arrow a) {
    131     return has_arrow(a) && (a == TOP_CENTER || !(a & (BOTTOM | CENTER)));
    132   }
    133 
    134   static bool is_arrow_on_horizontal(Arrow a) {
    135     return a >= NONE ? false : !(a & VERTICAL);
    136   }
    137 
    138   static bool is_arrow_at_center(Arrow a) {
    139     return has_arrow(a) && !!(a & CENTER);
    140   }
    141 
    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 
    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.
    153   void set_arrow(Arrow arrow) { arrow_ = arrow; }
    154   Arrow arrow() const { return arrow_; }
    155 
    156   // Get or set the bubble alignment.
    157   void set_alignment(BubbleAlignment alignment) { alignment_ = alignment; }
    158   BubbleAlignment alignment() const { return alignment_; }
    159 
    160   // Get the shadow type.
    161   Shadow shadow() const { return shadow_; }
    162 
    163   // Get or set the background color for the bubble and arrow body.
    164   void set_background_color(SkColor color) { background_color_ = 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.
    169   void set_use_theme_background_color(bool use_theme_background_color) {
    170     use_theme_background_color_ = use_theme_background_color;
    171   }
    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.
    179   void set_arrow_offset(int offset) { arrow_offset_ = offset; }
    180 
    181   // Sets the way the arrow is actually painted.  Default is PAINT_NORMAL.
    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:
    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