1 #ifndef Magnum_Ui_Style_h
2 #define Magnum_Ui_Style_h
3 /*
4     This file is part of Magnum.
5 
6     Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019
7               Vladimír Vondruš <mosra@centrum.cz>
8 
9     Permission is hereby granted, free of charge, to any person obtaining a
10     copy of this software and associated documentation files (the "Software"),
11     to deal in the Software without restriction, including without limitation
12     the rights to use, copy, modify, merge, publish, distribute, sublicense,
13     and/or sell copies of the Software, and to permit persons to whom the
14     Software is furnished to do so, subject to the following conditions:
15 
16     The above copyright notice and this permission notice shall be included
17     in all copies or substantial portions of the Software.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 */
27 
28 /** @file
29  * @brief Class @ref Magnum::Ui::StyleConfiguration, enum @ref Magnum::Ui::Type, @ref Magnum::Ui::Style
30  */
31 
32 #include <Magnum/Math/Color.h>
33 #include <Magnum/Math/Range.h>
34 
35 #include "Magnum/Ui/AbstractUiShader.h"
36 #include "Magnum/Ui/Ui.h"
37 #include "Magnum/Ui/visibility.h"
38 
39 namespace Magnum { namespace Ui {
40 
41 namespace Implementation {
42     enum: std::size_t {
43         BackgroundColorCount = 14,
44         ForegroundColorCount = 64,
45         TextColorCount = 87
46     };
47 
48     UnsignedByte MAGNUM_UI_EXPORT backgroundColorIndex(Type type, Style style, State state);
49     UnsignedByte MAGNUM_UI_EXPORT backgroundColorIndex(Type type, Style style, WidgetFlags flags);
50     UnsignedByte MAGNUM_UI_EXPORT foregroundColorIndex(Type type, Style style, State state);
51     UnsignedByte MAGNUM_UI_EXPORT foregroundColorIndex(Type type, Style style, WidgetFlags flags);
52     UnsignedByte MAGNUM_UI_EXPORT textColorIndex(Type type, Style style, State state);
53     UnsignedByte MAGNUM_UI_EXPORT textColorIndex(Type type, Style style, WidgetFlags flags);
54 }
55 
56 /**
57 @brief Widget type
58 
59 @experimental
60 */
61 enum class Type: UnsignedInt {
62     Button = 0,     /**< @ref Button */
63     Label = 1,      /**< @ref Label */
64     Input = 2,      /**< @ref Input */
65     Modal = 3       /**< @ref Modal */
66 };
67 
68 /** @debugoperatorenum{Magnum::Ui::Type}
69  * @experimental
70  */
71 MAGNUM_UI_EXPORT Debug& operator<<(Debug& debug, Type value);
72 
73 /**
74 @brief Widget state
75 
76 Extracted from @ref WidgetFlags, see particular values for details.
77 @see @ref Widget::flags()
78 @experimental
79 */
80 enum class State: UnsignedInt {
81     /** Default state */
82     Default = 0,
83 
84     /**
85      * The widget was hovered. Note that to reduce combinatorial explosion of
86      * colors, @ref Style::Hover gets a preference over @ref Style::Pressed,
87      * but not before @ref Style::Active (so if the widget is both pressed and
88      * hovered, hover style gets a preference).
89      */
90     Hover = 1,
91 
92     /**
93      * The widget was pressed. Note that to reduce combinatorial explosion of
94      * colors, @ref Style::Hover gets a preference over @ref Style::Pressed, if
95      * the widget is both pressed and hovered.
96      */
97     Pressed = 2,
98 
99     /**
100      * The widget is active. Note that to reduce combinatorial explosion of
101      * colors, @ref Style::Active gets a preference over @ref Style::Hover, if
102      * the widget is both active and hovered.
103      */
104     Active = 3,
105 
106     /** The widget is disabled. */
107     Disabled = 4,
108 
109     /** The widget is hidden. This is implicitly mapped to transparent colors. */
110     Hidden = 5
111 };
112 
113 /** @debugoperatorenum{Magnum::Ui::State}
114  * @experimental
115  */
116 MAGNUM_UI_EXPORT Debug& operator<<(Debug& debug, State value);
117 
118 /**
119 @brief Widget style
120 
121 @experimental
122 */
123 enum class Style: UnsignedInt {
124     /** Default. Used for common widgets that don't stand out. */
125     Default = 0,
126 
127     /** Primary. Denotes primary widget. */
128     Primary = 1,
129 
130     /** Success. Colored green. */
131     Success = 2,
132 
133     /** Info. Colored light blue. */
134     Info = 3,
135 
136     /** Warning. Colored yellow. */
137     Warning = 4,
138 
139     /** Danger. Colored red. */
140     Danger = 5,
141 
142     /**
143      * Dim. Toned-down version of @ref Style::Default that tries hard to not
144      * gain attention. Used also for dimming out the background.
145      */
146     Dim = 6,
147 
148     /** Flat version of @ref Style::Default. */
149     Flat = 7
150 };
151 
152 /** @debugoperatorenum{Magnum::Ui::Style}
153  * @experimental
154  */
155 MAGNUM_UI_EXPORT Debug& operator<<(Debug& debug, Style value);
156 
157 /**
158 @brief Style configuration
159 
160 @experimental
161 */
162 class MAGNUM_UI_EXPORT StyleConfiguration {
163     public:
164         /**
165          * @brief Default constructor
166          *
167          * Sets everything to zero or transparent.
168          */
169         explicit StyleConfiguration();
170 
171         /** @brief Font size */
fontSize()172         Float fontSize() const { return _fontSize; }
173 
174         /**
175          * @brief Set font size
176          * @return Reference to self (for method chaining)
177          */
setFontSize(Float size)178         StyleConfiguration& setFontSize(Float size) {
179             _fontSize = size;
180             return *this;
181         }
182 
183         /** @brief Border width */
borderWidth()184         Float borderWidth() const { return _foreground.borderWidth; }
185 
186         /**
187          * @brief Set border width
188          * @return Reference to self (for method chaining)
189          */
setBorderWidth(Float width)190         StyleConfiguration& setBorderWidth(Float width) {
191             _foreground.borderWidth = width;
192             return *this;
193         }
194 
195         /** @brief Corner radius */
cornerRadius()196         Float cornerRadius() const { return _foreground.cornerRadius; }
197 
198         /**
199          * @brief Set corner radius
200          * @return Reference to self (for method chaining)
201          */
setCornerRadius(Float radius)202         StyleConfiguration& setCornerRadius(Float radius) {
203             _background.cornerRadius = _foreground.cornerRadius = radius;
204             return *this;
205         }
206 
207         /** @brief Corner smoothness inside */
cornerSmoothnessIn()208         Float cornerSmoothnessIn() const { return _foreground.cornerSmoothnessIn; }
209 
210         /**
211          * @brief Set corner smoothness inside
212          * @return Reference to self (for method chaining)
213          */
setCornerSmoothnessIn(Float smoothness)214         StyleConfiguration& setCornerSmoothnessIn(Float smoothness) {
215             _foreground.cornerSmoothnessIn = smoothness;
216             return *this;
217         }
218 
219         /** @brief Corner smoothness outside */
cornerSmoothnessOut()220         Float cornerSmoothnessOut() const { return _foreground.cornerSmoothnessOut; }
221 
222         /**
223          * @brief Set corner smoothness outside
224          * @return Reference to self (for method chaining)
225          */
setCornerSmoothnessOut(Float smoothness)226         StyleConfiguration& setCornerSmoothnessOut(Float smoothness) {
227             _background.cornerSmoothnessOut = _foreground.cornerSmoothnessOut = smoothness;
228             return *this;
229         }
230 
231         /** @brief Padding inside of a widget */
padding()232         Vector2 padding() const { return _padding; }
233 
234         /**
235          * @brief Set padding inside of a widget
236          * @return Reference to self (for method chaining)
237          */
setPadding(const Vector2 & padding)238         StyleConfiguration& setPadding(const Vector2& padding) {
239             _padding = padding;
240             return *this;
241         }
242 
243         /** @brief Margin between widgets */
margin()244         Vector2 margin() const { return _margin; }
245 
246         /**
247          * @brief Set margin between widgets
248          * @return Reference to self (for method chaining)
249          */
setMargin(const Vector2 & margin)250         StyleConfiguration& setMargin(const Vector2& margin) {
251             _margin = margin;
252             return *this;
253         }
254 
255         /**
256          * @brief Background color
257          *
258          * Expects that given combination is supported.
259          */
backgroundColor(Type type,Style style,State state)260         Color4 backgroundColor(Type type, Style style, State state) const {
261             return _background.colors[Implementation::backgroundColorIndex(type, style, state)];
262         }
263 
264         /**
265          * @brief Set background color
266          * @return Reference to self (for method chaining)
267          *
268          * Expects that given combination is supported.
269          */
setBackgroundColor(Type type,Style style,State state,const Color4 & color)270         StyleConfiguration& setBackgroundColor(Type type, Style style, State state, const Color4& color) {
271             _background.colors[Implementation::backgroundColorIndex(type, style, state)] = color;
272             return *this;
273         }
274 
275         /**
276          * @brief Top fill color
277          *
278          * Expects that given combination is supported.
279          */
topFillColor(Type type,Style style,State state)280         Color4 topFillColor(Type type, Style style, State state) const {
281             return _foreground.colors[Implementation::foregroundColorIndex(type, style, state)*3 + 0];
282         }
283 
284         /**
285          * @brief Set top fill color
286          * @return Reference to self (for method chaining)
287          *
288          * Top color of the fill gradient. Expects that given combination is
289          * supported.
290          */
setTopFillColor(Type type,Style style,State state,const Color4 & color)291         StyleConfiguration& setTopFillColor(Type type, Style style, State state, const Color4& color) {
292             _foreground.colors[Implementation::foregroundColorIndex(type, style, state)*3 + 0] = color;
293             return *this;
294         }
295 
296         /**
297          * @brief Bottom fill color
298          *
299          * Expects that given combination is supported.
300          */
bottomFillColor(Type type,Style style,State state)301         Color4 bottomFillColor(Type type, Style style, State state) const {
302             return _foreground.colors[Implementation::foregroundColorIndex(type, style, state)*3 + 1];
303         }
304 
305         /**
306          * @brief Set bottom fill color
307          * @return Reference to self (for method chaining)
308          *
309          * Bottom color of the fill gradient. Expects that given combination is
310          * supported.
311          */
setBottomFillColor(Type type,Style style,State state,const Color4 & color)312         StyleConfiguration& setBottomFillColor(Type type, Style style, State state, const Color4& color) {
313             _foreground.colors[Implementation::foregroundColorIndex(type, style, state)*3 + 1] = color;
314             return *this;
315         }
316 
317         /**
318          * @brief Border color
319          *
320          * Expects that given combination is supported.
321          */
borderColor(Type type,Style style,State state)322         Color4 borderColor(Type type, Style style, State state) const {
323             return _foreground.colors[Implementation::foregroundColorIndex(type, style, state)*3 + 2];
324         }
325 
326         /**
327          * @brief Set border color
328          * @return Reference to self (for method chaining)
329          *
330          * Expects that given combination is supported.
331          */
setBorderColor(Type type,Style style,State state,const Color4 & color)332         StyleConfiguration& setBorderColor(Type type, Style style, State state, const Color4& color) {
333             _foreground.colors[Implementation::foregroundColorIndex(type, style, state)*3 + 2] = color;
334             return *this;
335         }
336 
337         /**
338          * @brief Text color
339          *
340          * Expects that given combination is supported.
341          */
textColor(Type type,Style style,State state)342         Color4 textColor(Type type, Style style, State state) const {
343             return _text.colors[Implementation::textColorIndex(type, style, state)];
344         }
345 
346         /**
347          * @brief Set text color
348          * @return Reference to self (for method chaining)
349          *
350          * Expects that given combination is supported.
351          */
setTextColor(Type type,Style style,State state,const Color4 & color)352         StyleConfiguration& setTextColor(Type type, Style style, State state, const Color4& color) {
353             _text.colors[Implementation::textColorIndex(type, style, state)] = color;
354             return *this;
355         }
356 
357         /** @brief Pack style configuration into OpenGL uniform buffers */
358         void pack(GL::Buffer& backgroundUniforms, GL::Buffer& foregroundUniforms, GL::Buffer& textUniforms) const;
359 
360     private:
361         struct Background {
362             Int:32;
363             Float cornerRadius{};
364             Int:32;
365             Float cornerSmoothnessOut{};
366             Color4 colors[Implementation::BackgroundColorCount];
367         } _background;
368 
369         struct Foreground {
370             Float borderWidth{};
371             Float cornerRadius{};
372             Float cornerSmoothnessIn{};
373             Float cornerSmoothnessOut{};
374             Color4 colors[Implementation::ForegroundColorCount*3];
375         } _foreground;
376 
377         struct Text {
378             Color4 colors[Implementation::TextColorCount];
379         } _text;
380 
381         Float _fontSize{};
382         Vector2 _padding;
383         Vector2 _margin;
384 };
385 
386 /**
387 @brief Default style configuration
388 
389 @experimental
390 */
391 MAGNUM_UI_EXPORT StyleConfiguration defaultStyleConfiguration();
392 
393 /**
394 @brief m.css dark style configuration
395 
396 The dark CSS theme from http://mcss.mosra.cz.
397 @experimental
398 */
399 MAGNUM_UI_EXPORT StyleConfiguration mcssDarkStyleConfiguration();
400 
401 namespace Implementation {
402 
403 struct QuadVertex {
404     /* 0---2 0---2 5
405        |   | |  / /|
406        |   | | / / |
407        |   | |/ /  |
408        1---3 1 3---4 */
409     Vector2 position;
410 
411     /*  x = 0 at the left
412         y = 0 at the right
413         z = 0 at the bottom
414         w = 0 at the top */
415     Vector4 edgeDistance;
416 };
417 
418 struct QuadInstance {
419     Range2D rect;
420     UnsignedShort colorIndex;
421     UnsignedShort:16;
422 };
423 
424 struct TextVertex {
425     Vector2 position;
426     Vector2 textureCoordinates;
427     UnsignedShort colorIndex;
428     UnsignedShort:16;
429 };
430 
431 using QuadLayer = BasicInstancedGLLayer<QuadInstance>;
432 using TextLayer = BasicGLLayer<TextVertex>;
433 
434 class AbstractQuadShader: public AbstractUiShader {
435     public:
436         typedef GL::Attribute<0, Vector2> Position;
437         typedef GL::Attribute<1, Vector4> EdgeDistance;
438         typedef GL::Attribute<2, Vector4> Rect;
439         typedef GL::Attribute<3, Int> ColorIndex;
440 
441         AbstractQuadShader& bindCornerTexture(GL::Texture2D& texture);
442 };
443 
444 class MAGNUM_UI_EXPORT BackgroundShader: public AbstractQuadShader {
445     public:
446         explicit BackgroundShader();
447 
bindCornerTexture(GL::Texture2D & texture)448         BackgroundShader& bindCornerTexture(GL::Texture2D& texture) {
449             AbstractQuadShader::bindCornerTexture(texture);
450             return *this;
451         }
452         BackgroundShader& bindStyleBuffer(GL::Buffer& buffer);
453 };
454 
455 class MAGNUM_UI_EXPORT ForegroundShader: public AbstractQuadShader {
456     public:
457         explicit ForegroundShader();
458 
bindCornerTexture(GL::Texture2D & texture)459         ForegroundShader& bindCornerTexture(GL::Texture2D& texture) {
460             AbstractQuadShader::bindCornerTexture(texture);
461             return *this;
462         }
463         ForegroundShader& bindStyleBuffer(GL::Buffer& buffer);
464 };
465 
466 class MAGNUM_UI_EXPORT TextShader: public AbstractUiShader {
467     public:
468         typedef GL::Attribute<0, Vector2> Position;
469         typedef GL::Attribute<1, Vector2> TextureCoordinates;
470         typedef GL::Attribute<2, Int> ColorIndex;
471 
472         explicit TextShader();
473 
474         TextShader& bindGlyphCacheTexture(GL::Texture2D& texture);
475         TextShader& bindStyleBuffer(GL::Buffer& buffer);
476 };
477 
478 }
479 
480 }}
481 
482 #endif
483