1 /** @file widgets/labelwidget.h
2  *
3  * @authors Copyright (c) 2013-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  *
5  * @par License
6  * LGPL: http://www.gnu.org/licenses/lgpl.html
7  *
8  * <small>This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or (at your
11  * option) any later version. This program is distributed in the hope that it
12  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
14  * General Public License for more details. You should have received a copy of
15  * the GNU Lesser General Public License along with this program; if not, see:
16  * http://www.gnu.org/licenses</small>
17  */
18 
19 #ifndef LIBAPPFW_LABELWIDGET_H
20 #define LIBAPPFW_LABELWIDGET_H
21 
22 #include "../ui/defs.h"
23 #include "../GuiWidget"
24 #include "../ProceduralImage"
25 #include "../ui/Data"
26 
27 namespace de {
28 
29 class GLUniform;
30 class GridLayout;
31 class Image;
32 
33 /**
34  * Widget showing a label text and/or image.
35  *
36  * LabelWidget offers several parameters for controlling the layout of the text
37  * and image components. The widget is also able to independently determine its
38  * size to exactly fit its contents (according to the LabelWidget::SizePolicy).
39  *
40  * The alignment parameters are applied as follows:
41  *
42  * - LabelWidget::setAlignment() defines where the content of the widget is
43  *   aligned as a group, once the relative positions of the image and the text
44  *   have been determined.
45  *
46  * - LabelWidget::setTextAlignment() defines where the text will be positioned
47  *   in relation to the image. For instance, if the text alignment is AlignRight,
48  *   the text will be placed on the right side of the image. If there is no
49  *   image, this has no effect.
50  *
51  * - LabelWidget::setImageAlignment() defines how the image is aligned in
52  *   relation to text when both are visible. For instance, if text is aligned to
53  *   AlignRight (appearing on the right side of the image), then an image
54  *   alignment of AlignTop would align the top of the image with the top of the
55  *   text. AlignBottom would align the bottom of the image with the bottom of the
56  *   text. This value must be on the perpendicular axis when compared to text
57  *   alignment (otherwise it has no effect).
58  *
59  * - LabelWidget::setTextLineAlignment() defines the alignment of each individual
60  *   wrapped line of text within the text block.
61  *
62  * Additionally, LabelWidget::setImageFit() defines how the image will be
63  * scaled inside the area reserved for the image.
64  *
65  * LabelWidget is an Asset because the preparation of text for drawing occurs
66  * asynchronously, and meanwhile the content size of the text is (0,0).
67  * Observing the asset state allows others to determine when the label is ready
68  * to be drawn/laid out with the final dimensions.
69  *
70  * @ingroup guiWidgets
71  */
72 class LIBAPPFW_PUBLIC LabelWidget : public GuiWidget, public IAssetGroup
73 {
74 public:
75     LabelWidget(String const &name = String());
76 
77     AssetGroup &assets() override;
78 
79     void setText(String const &text);
80     void setImage(Image const &image);
81 
82     /**
83      * Sets the image drawn in the label. Procedural images can generate any
84      * geometry on the fly, so the image can be fully animated.
85      *
86      * @param procImage  Procedural image. LabelWidget takes ownership.
87      */
88     void setImage(ProceduralImage *procImage);
89 
90     /**
91      * Sets the image drawn in the label using a procedural image from the UI style.
92      *
93      * @param id  Image ID.
94      * @param heightFromFont  Optionally overrides the image size using the height of
95      *             this font. Default is to use the image's own size.
96      */
97     void setStyleImage(DotPath const &id, String const &heightFromFont = "");
98 
99     ProceduralImage *image() const;
100 
101     /**
102      * Sets an overlay image that gets drawn over the label contents.
103      *
104      * @param overlayProcImage  Procedural image. LabelWidget takes ownership.
105      * @param alignment         Alignment for the overlaid image.
106      */
107     void setOverlayImage(ProceduralImage *overlayProcImage,
108                          ui::Alignment const &alignment = ui::AlignCenter);
109 
110     String text() const;
111 
112     /**
113      * Returns the actual size of the text in pixels.
114      */
115     Vector2ui textSize() const;
116 
117     Rule const &contentWidth() const;
118     Rule const &contentHeight() const;
119 
120     enum FillMode {
121         FillWithImage,
122         FillWithText
123     };
124 
125     void setFillMode(FillMode fillMode);
126 
127     /**
128      * Sets the gap between the text and image. Defaults to "label.gap".
129      *
130      * @param styleRuleId  Id of a rule in the style.
131      */
132     void setTextGap(DotPath const &styleRuleId);
133 
134     DotPath const &textGap() const;
135 
136     enum TextShadow {
137         NoShadow,
138         RectangleShadow
139     };
140 
141     void setTextShadow(TextShadow shadow, DotPath const &shadowColor = "label.shadow");
142 
143     enum AlignmentMode {
144         AlignByCombination,
145         AlignOnlyByImage,
146         AlignOnlyByText
147     };
148 
149     /**
150      * Sets the alignment of the entire contents of the widget inside its
151      * rectangle.
152      *
153      * @param align      Alignment for all content.
154      * @param alignMode  Mode of alignment (by combo/text/image).
155      */
156     void setAlignment(ui::Alignment const &align,
157                       AlignmentMode alignMode = AlignByCombination);
158 
159     void setTextAlignment(ui::Alignment const &textAlign);
160 
161     ui::Alignment textAlignment() const;
162 
163     void setTextLineAlignment(ui::Alignment const &textLineAlign);
164 
165     void setTextModulationColorf(Vector4f const &colorf);
166 
167     Vector4f textModulationColorf() const;
168 
169     /**
170      * Sets the maximum width used for text. By default, the maximum width is determined
171      * automatically based on the layout of the label content.
172      *
173      * @param pixels  Maximum width of text, or 0 to determine automatically.
174      */
175     void setMaximumTextWidth(int pixels);
176 
177     void setMaximumTextWidth(Rule const &pixels);
178 
179     void setMinimumHeight(Rule const &minHeight);
180 
181     /**
182      * Sets an alternative style for text. By default, the rich text styling comes
183      * from Style.
184      *
185      * @param richStyle  Rich text styling.
186      */
187     void setTextStyle(Font::RichFormat::IStyle const *richStyle);
188 
189     /**
190      * Sets the alignment of the image when there is both an image
191      * and a text in the label.
192      *
193      * @param imageAlign  Alignment for the image.
194      */
195     void setImageAlignment(ui::Alignment const &imageAlign);
196 
197     void setImageFit(ui::ContentFit const &fit);
198 
199     /**
200      * The image's actual size will be overridden by this size.
201      * @param size  Image size.
202      */
203     void setOverrideImageSize(const Rule &width, const Rule &height);
204 
setOverrideImageSize(const ISizeRule & size)205     void setOverrideImageSize(const ISizeRule &size)
206     {
207         setOverrideImageSize(size.width(), size.height());
208     }
209 
setOverrideImageSize(const Rule & widthAndHeight)210     void setOverrideImageSize(const Rule &widthAndHeight)
211     {
212         setOverrideImageSize(widthAndHeight, widthAndHeight);
213     }
214 
215     RulePair overrideImageSize() const;
216 
217     void setImageScale(float scaleFactor);
218 
219     void setImageColor(Vector4f const &imageColor);
220 
221     bool hasImage() const;
222 
223     /**
224      * Sets the policy for the widget to adjust its own width and/or height. By default,
225      * labels do not adjust their own size.
226      * - ui::Fixed means that the content uses its own size and the widget needs to be
227      *   sized by the user.
228      * - ui::Filled means content is expanded to fill the entire contents of the widget
229      *   area, but the widget still needs to be sized by the user.
230      * - ui::Expand means the widget resizes itself to the size of the content.
231      *
232      * @param horizontal  Horizontal sizing policy.
233      * @param vertical    Vertical sizing policy.
234      */
setSizePolicy(ui::SizePolicy horizontal,ui::SizePolicy vertical)235     void setSizePolicy(ui::SizePolicy horizontal, ui::SizePolicy vertical) {
236         setWidthPolicy(horizontal);
237         setHeightPolicy(vertical);
238     }
239 
240     void setWidthPolicy(ui::SizePolicy policy);
241     void setHeightPolicy(ui::SizePolicy policy);
242 
243     enum AppearanceAnimation {
244         AppearInstantly,
245         AppearGrowHorizontally,
246         AppearGrowVertically
247     };
248 
249     /**
250      * Sets the way the label's content affects its size.
251      *
252      * @param method  Method of appearance:
253      * - AppearInstantly: The size is unaffected by the content's state.
254      *                    This is the default.
255      * - AppearGrowHorizontally: The widget's width is initially zero, but when the
256      *                    content is ready for drawing, the width will animate
257      *                    to the appropriate width in the specified time span.
258      * - AppearGrowVertically: The widget's height is initially zero, but when the
259      *                    content is ready for drawing, the height will animate
260      *                    to the appropriate height in the specified time span.
261      * @param span  Animation time span for the appearance.
262      */
263     void setAppearanceAnimation(AppearanceAnimation method, TimeSpan const &span = 0.0);
264 
265     // Events.
266     void update() override;
267     void drawContent() override;
268 
269     struct ContentLayout {
270         Rectanglef image;
271         Rectanglei text;
272     };
273 
274     void contentLayout(ContentLayout &layout);
275 
276 public:
277     static LabelWidget *newWithText(const String &text, GuiWidget *parent = nullptr);
278     static LabelWidget *appendSeparatorWithText(const String &text, GuiWidget *parent = nullptr,
279                                                 GridLayout *appendToGrid = nullptr);
280 
281 protected:
282     void glInit() override;
283     void glDeinit() override;
284     void glMakeGeometry(GuiVertexBuilder &verts) override;
285     void updateStyle() override;
286 
287     /**
288      * Called before drawing to update the model-view-projection matrix.
289      * Derived classes may override this to set a custom matrix for the label.
290      * @return @c true, if a customized matrix was set.
291      */
292     virtual bool updateModelViewProjection(Matrix4f &mvp);
293 
294 private:
295     DENG2_PRIVATE(d)
296 };
297 
298 } // namespace de
299 
300 #endif // LIBAPPFW_LABELWIDGET_H
301