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_CONTROLS_BUTTON_IMAGE_BUTTON_H_
6 #define UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_
7 
8 #include <memory>
9 
10 #include "base/gtest_prod_util.h"
11 #include "base/macros.h"
12 #include "ui/base/layout.h"
13 #include "ui/gfx/image/image_skia.h"
14 #include "ui/views/controls/button/button.h"
15 #include "ui/views/metadata/view_factory.h"
16 
17 namespace views {
18 
19 class VIEWS_EXPORT ImageButton : public Button {
20  public:
21   METADATA_HEADER(ImageButton);
22 
23   // An enum describing the horizontal alignment of images on Buttons.
24   enum HorizontalAlignment { ALIGN_LEFT = 0, ALIGN_CENTER, ALIGN_RIGHT };
25 
26   // An enum describing the vertical alignment of images on Buttons.
27   enum VerticalAlignment { ALIGN_TOP = 0, ALIGN_MIDDLE, ALIGN_BOTTOM };
28 
29   explicit ImageButton(PressedCallback callback = PressedCallback());
30   ~ImageButton() override;
31 
32   // Returns the image for a given |state|.
33   virtual const gfx::ImageSkia& GetImage(ButtonState state) const;
34 
35   // Set the image the button should use for the provided state.
36   void SetImage(ButtonState state, const gfx::ImageSkia* image);
37 
38   // As above, but takes a const ref. TODO(estade): all callers should be
39   // updated to use this version, and then the implementations can be
40   // consolidated.
41   virtual void SetImage(ButtonState state, const gfx::ImageSkia& image);
42 
43   // Set the background details.  The background image uses the same alignment
44   // as the image.
45   void SetBackgroundImage(SkColor color,
46                           const gfx::ImageSkia* image,
47                           const gfx::ImageSkia* mask);
48 
49   // How the image is laid out within the button's bounds.
50   HorizontalAlignment GetImageHorizontalAlignment() const;
51   VerticalAlignment GetImageVerticalAlignment() const;
52   void SetImageHorizontalAlignment(HorizontalAlignment h_alignment);
53   void SetImageVerticalAlignment(VerticalAlignment v_alignment);
54 
55   // The minimum size of the contents (not including the border). The contents
56   // will be at least this size, but may be larger if the image itself is
57   // larger.
58   gfx::Size GetMinimumImageSize() const;
59   void SetMinimumImageSize(const gfx::Size& size);
60 
61   // Whether we should draw our images resources horizontally flipped.
SetDrawImageMirrored(bool mirrored)62   void SetDrawImageMirrored(bool mirrored) { draw_image_mirrored_ = mirrored; }
63 
64   // Overridden from View:
65   gfx::Size CalculatePreferredSize() const override;
66   views::PaintInfo::ScaleType GetPaintScaleType() const override;
67 
68  protected:
69   // Overridden from Button:
70   void PaintButtonContents(gfx::Canvas* canvas) override;
71 
72   // Returns the image to paint. This is invoked from paint and returns a value
73   // from images.
74   virtual gfx::ImageSkia GetImageToPaint();
75 
76   // Updates button background for |scale_factor|.
77   void UpdateButtonBackground(ui::ScaleFactor scale_factor);
78 
79   // The images used to render the different states of this button.
80   gfx::ImageSkia images_[STATE_COUNT];
81 
82   gfx::ImageSkia background_image_;
83 
84  private:
85   FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, Basics);
86   FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, ImagePositionWithBorder);
87   FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, LeftAlignedMirrored);
88   FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, RightAlignedMirrored);
89   FRIEND_TEST_ALL_PREFIXES(ImageButtonTest, ImagePositionWithBackground);
90 
91   FRIEND_TEST_ALL_PREFIXES(ImageButtonFactoryTest, CreateVectorImageButton);
92 
93   // Returns the correct position of the image for painting.
94   const gfx::Point ComputeImagePaintPosition(const gfx::ImageSkia& image) const;
95 
96   // Image alignment.
97   HorizontalAlignment h_alignment_ = ALIGN_LEFT;
98   VerticalAlignment v_alignment_ = ALIGN_TOP;
99   gfx::Size minimum_image_size_;
100 
101   // Whether we draw our resources horizontally flipped. This can happen in the
102   // linux titlebar, where image resources were designed to be flipped so a
103   // small curved corner in the close button designed to fit into the frame
104   // resources.
105   bool draw_image_mirrored_ = false;
106 
107   DISALLOW_COPY_AND_ASSIGN(ImageButton);
108 };
109 
BEGIN_VIEW_BUILDER(VIEWS_EXPORT,ImageButton,Button)110 BEGIN_VIEW_BUILDER(VIEWS_EXPORT, ImageButton, Button)
111 VIEW_BUILDER_PROPERTY(bool, DrawImageMirrored)
112 VIEW_BUILDER_PROPERTY(ImageButton::HorizontalAlignment,
113                       ImageHorizontalAlignment)
114 VIEW_BUILDER_PROPERTY(ImageButton::VerticalAlignment, ImageVerticalAlignment)
115 VIEW_BUILDER_PROPERTY(gfx::Size, MinimumImageSize)
116 END_VIEW_BUILDER
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 //
120 // ToggleImageButton
121 //
122 // A toggle-able ImageButton.  It swaps out its graphics when toggled.
123 //
124 ////////////////////////////////////////////////////////////////////////////////
125 class VIEWS_EXPORT ToggleImageButton : public ImageButton {
126  public:
127   METADATA_HEADER(ToggleImageButton);
128 
129   explicit ToggleImageButton(PressedCallback callback = PressedCallback());
130   ~ToggleImageButton() override;
131 
132   // Change the toggled state.
133   bool GetToggled() const;
134   void SetToggled(bool toggled);
135 
136   // Like ImageButton::SetImage(), but to set the graphics used for the
137   // "has been toggled" state.  Must be called for each button state
138   // before the button is toggled.
139   void SetToggledImage(ButtonState state, const gfx::ImageSkia* image);
140 
141   // Get/Set the tooltip text displayed when the button is toggled.
142   base::string16 GetToggledTooltipText() const;
143   void SetToggledTooltipText(const base::string16& tooltip);
144 
145   // Get/Set the accessible text used when the button is toggled.
146   base::string16 GetToggledAccessibleName() const;
147   void SetToggledAccessibleName(const base::string16& name);
148 
149   // Overridden from ImageButton:
150   const gfx::ImageSkia& GetImage(ButtonState state) const override;
151   void SetImage(ButtonState state, const gfx::ImageSkia& image) override;
152 
153   // Overridden from View:
154   base::string16 GetTooltipText(const gfx::Point& p) const override;
155   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
156 
157  private:
158   // The parent class's images_ member is used for the current images,
159   // and this array is used to hold the alternative images.
160   // We swap between the two when toggling.
161   gfx::ImageSkia alternate_images_[STATE_COUNT];
162 
163   // True if the button is currently toggled.
164   bool toggled_ = false;
165 
166   // The parent class's tooltip_text_ is displayed when not toggled, and
167   // this one is shown when toggled.
168   base::string16 toggled_tooltip_text_;
169 
170   // The parent class's accessibility data is used when not toggled, and this
171   // one is used when toggled.
172   base::string16 toggled_accessible_name_;
173 
174   DISALLOW_COPY_AND_ASSIGN(ToggleImageButton);
175 };
176 
177 BEGIN_VIEW_BUILDER(VIEWS_EXPORT, ToggleImageButton, ImageButton)
178 VIEW_BUILDER_PROPERTY(bool, Toggled)
179 VIEW_BUILDER_PROPERTY(base::string16, ToggledTooltipText)
180 VIEW_BUILDER_PROPERTY(base::string16, ToggledAccessibleName)
181 END_VIEW_BUILDER
182 
183 }  // namespace views
184 
185 DEFINE_VIEW_BUILDER(VIEWS_EXPORT, ImageButton)
186 DEFINE_VIEW_BUILDER(VIEWS_EXPORT, ToggleImageButton)
187 
188 #endif  // UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_
189