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