1 /** 2 * Module for graphics. 3 * 4 * Authors: 5 * Jacob Jensen 6 * License: 7 * https://github.com/PoisonEngine/poison-ui/blob/master/LICENSE 8 */ 9 module poison.ui.graphics; 10 11 import dsfml.graphics : RectangleShape; 12 import dsfml.system : Vector2f; 13 14 import poison.ui.paint; 15 import poison.core : Size, Point; 16 import poison.ui.picture; 17 import poison.ui.fonts; 18 19 /// Original space struct for graphical elements. 20 private struct OriginalSpace(TPosition,TSize) { 21 /// The original x position. 22 TPosition x; 23 24 /// The original y position. 25 TPosition y; 26 27 /// The original width. 28 TSize width; 29 30 /// The original height. 31 TSize height; 32 } 33 34 /// A sub rect of overflow calculation results. 35 private struct SubRect { 36 /// The x coordinate. 37 float x; 38 39 /// The y coordinate. 40 float y; 41 42 /// The width. 43 float width; 44 45 /// The height. 46 float height; 47 48 /// The overflow top. 49 float overflowTop; 50 51 /// The overflow right. 52 float overflowRight; 53 54 /// The overflow bottom. 55 float overflowBottom; 56 57 /// The overflow left. 58 float overflowLeft; 59 } 60 61 /// Graphics wrapper for components. 62 class Graphics { 63 private: 64 /// The background paint. 65 Paint _backgroundPaint; 66 67 /// The foreground paint. 68 Paint _foregroundPaint; 69 70 /// The low-level background rectangle. 71 RectangleShape _backgroundRect; 72 73 /// The original background rectangle's space. 74 OriginalSpace!(float,float) _originalBackgroundRect; 75 76 /// The background picture. 77 Picture _backgroundPicture; 78 79 /// The original background ´picture's space. 80 OriginalSpace!(ptrdiff_t,int) _originalBackgroundPicture; 81 82 /// The size. 83 Size _size; 84 85 /// The position. 86 Point _position; 87 88 /// The font. 89 Font _font; 90 91 /// The font size. 92 uint _fontSize; 93 94 /// Boolean determining whether the background rectangle is displayable or not. 95 bool _displayableBackgroundRect; 96 97 /// Boolean determining whether the background picture is displayable or not. 98 bool _displayableBackgroundPicture; 99 100 /// Boolean determining whether the graphics has a size. 101 bool _hasSize; 102 103 /// Boolean determining whether the graphics has a position. 104 bool _hasPosition; 105 106 public: 107 final: 108 /// Creates a new graphics wrapper. 109 this() { 110 _backgroundPaint = transparent; 111 _foregroundPaint = transparent; 112 113 _size = new Size(0,0); 114 _position = new Point(0,0); 115 116 _fontSize = 13; 117 _displayableBackgroundRect = true; 118 _displayableBackgroundPicture = true; 119 _originalBackgroundRect = OriginalSpace!(float,float)(0,0,0,0); 120 _originalBackgroundPicture = OriginalSpace!(ptrdiff_t, int)(0,0,0,0); 121 } 122 123 @property { 124 /// Gets the background paint. 125 Paint backgroundPaint() { return _backgroundPaint; } 126 127 /// Sets the background paint. 128 void backgroundPaint(Paint newPaint) { 129 _backgroundPaint = newPaint; 130 131 if (_backgroundRect) { 132 _backgroundRect.fillColor = _backgroundPaint.sfmlColor; 133 } 134 } 135 136 /// Gets the foreground paint. 137 Paint foregroundPaint() { return _foregroundPaint; } 138 139 /// Sets the foreground paint. 140 void foregroundPaint(Paint newPaint) { 141 _foregroundPaint = newPaint; 142 } 143 144 /// Gets the low-level background rectangle. 145 RectangleShape backgroundRect() { return _backgroundRect; } 146 147 /// Gets the background picture. 148 Picture backgroundPicture() { return _backgroundPicture; } 149 150 /// Sets the background picture. 151 void backgroundPicture(Picture newBackgroundPicture) { 152 _backgroundPicture = newBackgroundPicture; 153 154 if (_backgroundPicture) { 155 _backgroundPicture.position = _position; 156 157 _originalBackgroundPicture.x = _position.x; 158 _originalBackgroundPicture.y = _position.y; 159 160 _originalBackgroundPicture.width = _size.width; 161 _originalBackgroundPicture.height = _size.height; 162 } 163 } 164 165 /// Gets the font. 166 Font font() { return _font; } 167 168 /// Sets the font. 169 void font(Font newFont) { 170 _font = newFont; 171 } 172 173 /// Gets the font size. 174 uint fontSize() { return _fontSize; } 175 176 /// Sets the font size. 177 void fontSize(uint newFontSize) { 178 _fontSize = newFontSize; 179 } 180 } 181 182 package(poison): 183 @property { 184 /// Sets the position of the graphics. 185 void position(Point newPosition) { 186 _position = newPosition; 187 188 if (_backgroundRect) { 189 _backgroundRect.position = Vector2f(cast(float)_position.x, cast(float)_position.y); 190 _originalBackgroundRect.x = _backgroundRect.position.x; 191 _originalBackgroundRect.y = _backgroundRect.position.y; 192 } 193 194 if (_backgroundPicture) { 195 _backgroundPicture.position = _position; 196 _originalBackgroundPicture.x = cast(int)_position.x; 197 _originalBackgroundPicture.y = cast(int)_position.y; 198 } 199 } 200 201 /// Sets the size of the graphics. 202 void size(Size newSize) { 203 _size = newSize; 204 205 _backgroundRect = new RectangleShape(Vector2f(cast(float)_size.width, cast(float)_size.height)); 206 backgroundPaint = _backgroundPaint; 207 position = _position; 208 209 _originalBackgroundRect.width = _backgroundRect.size.x; 210 _originalBackgroundRect.height = _backgroundRect.size.y; 211 212 _originalBackgroundPicture.width = cast(int)_size.width; 213 _originalBackgroundPicture.height = cast(int)_size.height; 214 } 215 } 216 217 package(poison): 218 @property { 219 /// Gets a boolean determining whether the background rectangle is displayable. 220 bool displayableBackgroundRect() { return _displayableBackgroundRect; } 221 222 /// Gets a boolean determining whether the background picture is displayable. 223 bool displayableBackgroundPicture() { return _displayableBackgroundPicture; } 224 225 /// Gets the size of the graphics. Use hasSize before using this. 226 Size size() { return _size; } 227 228 /// Gets the position of the graphics. Use hasPosition before using this. 229 Point position() { return _position; } 230 231 /// Gets a boolean determining whether the graphics has a size or not. 232 bool hasSize() { return _hasSize; } 233 234 /// Sets a boolean determining whether the graphics has a size or not. 235 void hasSize(bool setHasSize) { 236 _hasSize = setHasSize; 237 } 238 239 /// Gets a boolean determining whether the graphics has a position or not. 240 bool hasPosition() { return _hasPosition; } 241 242 /// Sets a boolean determining whether the graphics has a position or not. 243 void hasPosition(bool setHasPosition) { 244 _hasPosition = setHasPosition; 245 } 246 } 247 248 /** 249 * Finalizes paint inputs for the graphics. 250 * Params: 251 * position = The position of the paint input. 252 * size = The size of the paint input. 253 * paint = The paint. 254 */ 255 void finalizePaint(Point position, Size size, Paint paint) { 256 if (!_backgroundPicture) { 257 _backgroundPicture = new Picture(size, transparent); 258 } 259 260 _backgroundPicture.draw(position, size, paint); 261 } 262 263 /** 264 * Finalizes vertical gradient inputs for the graphics. 265 * Params: 266 * position = The position of the graident. 267 * size = The size of the gradient. 268 * fromPaint = The paint to draw the gradient from. 269 * toPaint = The paint to draw the gradient to. 270 */ 271 void finalizeGradientVertical(Point position, Size size, Paint fromPaint, Paint toPaint) { 272 if (!_backgroundPicture) { 273 _backgroundPicture = new Picture(size, transparent); 274 } 275 276 _backgroundPicture.gradientVertical(position, size, fromPaint, toPaint); 277 } 278 279 /** 280 * Finalizes horizontal gradient inputs for the graphics. 281 * Params: 282 * position = The position of the graident. 283 * size = The size of the gradient. 284 * fromPaint = The paint to draw the gradient from. 285 * toPaint = The paint to draw the gradient to. 286 */ 287 void finalizeGradientHorizontal(Point position, Size size, Paint fromPaint, Paint toPaint) { 288 if (!_backgroundPicture) { 289 _backgroundPicture = new Picture(size, transparent); 290 } 291 292 _backgroundPicture.gradientHorizontal(position, size, fromPaint, toPaint); 293 } 294 295 /** 296 * Renders the sub rectangles for the graphics elements. 297 * Params: 298 * position = The position to be relative to. 299 * size = The size to be relative to. 300 */ 301 void renderSub(Point position, Size size) { 302 import dsfml.graphics : IntRect; 303 import dsfml.system : Vector2f; 304 305 SubRect calculateOverflow(float targetX, float targetY, float targetWidth, float targetHeight) { 306 import std.math : fmax; 307 308 float overflowTop = fmax(0, (cast(float)position.y - targetY)); 309 float overflowRight = fmax(0, (targetX + targetWidth) - (cast(float)position.x + cast(float)size.width)); 310 float overflowBottom = fmax(0, (targetY + targetHeight) - (cast(float)position.y + cast(float)size.height)); 311 float overflowLeft = fmax(0, (cast(float)position.x - targetX)); 312 313 targetY += overflowTop; 314 targetHeight -= overflowTop; 315 targetWidth -= overflowRight; 316 targetHeight -= overflowBottom; 317 targetX += overflowLeft; 318 targetWidth -= overflowLeft; 319 320 return SubRect(targetX, targetY, targetWidth, targetHeight, overflowTop, overflowRight, overflowBottom, overflowLeft); 321 } 322 323 bool intersect(float width, float height, float x, float y) { 324 return(x < cast(float)position.x + cast(float)size.width) && 325 (cast(float)position.x < (x + width)) && 326 (y < cast(float)position.y + cast(float)size.height) && 327 (cast(float)position.y < y + height); 328 } 329 330 if (_backgroundRect) { 331 _backgroundRect.size = Vector2f(_originalBackgroundRect.width, _originalBackgroundRect.height); 332 _backgroundRect.position = Vector2f(_originalBackgroundRect.x, _originalBackgroundRect.y); 333 334 auto rectSize = _backgroundRect.size; 335 auto rectPosition = _backgroundRect.position; 336 337 _displayableBackgroundRect = intersect(rectSize.x, rectSize.y, rectPosition.x, rectPosition.y); 338 339 if (_displayableBackgroundRect) { 340 auto overflow = calculateOverflow(rectPosition.x, rectPosition.y, rectSize.x, rectSize.y); 341 342 _backgroundRect.size = Vector2f(overflow.width, overflow.height); 343 _backgroundRect.position = Vector2f(overflow.x, overflow.y); 344 } 345 } 346 347 if (_backgroundPicture) { 348 _displayableBackgroundPicture = intersect(cast(float)_originalBackgroundPicture.x, cast(float)_originalBackgroundPicture.y, cast(float)_originalBackgroundPicture.width, cast(float)_originalBackgroundPicture.height); 349 350 if (_displayableBackgroundPicture) { 351 auto backgroundSprite = _backgroundPicture.backgroundSprite; 352 auto drawingSprite = _backgroundPicture.drawingSprite; 353 354 if (backgroundSprite) { 355 backgroundSprite.position = new Point(_originalBackgroundPicture.x, _originalBackgroundPicture.y); 356 backgroundSprite.textureRect = IntRect(0, 0, cast(int)_originalBackgroundPicture.width, cast(int)_originalBackgroundPicture.height); 357 } 358 359 if (drawingSprite) { 360 drawingSprite.position = new Point(_originalBackgroundPicture.x, _originalBackgroundPicture.y); 361 drawingSprite.textureRect = IntRect(0, 0, cast(int)_originalBackgroundPicture.width, cast(int)_originalBackgroundPicture.height); 362 } 363 364 auto overflow = calculateOverflow(cast(float)_originalBackgroundPicture.x, cast(float)_originalBackgroundPicture.y, cast(float)_originalBackgroundPicture.width, cast(float)_originalBackgroundPicture.height); 365 366 if (backgroundSprite) { 367 backgroundSprite.textureRect = IntRect(cast(int)overflow.overflowLeft, cast(int)overflow.overflowTop, cast(int)overflow.width, cast(int)overflow.height); 368 backgroundSprite.position = new Point(cast(ptrdiff_t)overflow.x, cast(ptrdiff_t)overflow.y); 369 } 370 371 if (drawingSprite) { 372 drawingSprite.textureRect = IntRect(cast(int)overflow.overflowLeft, cast(int)overflow.overflowTop, cast(int)overflow.width, cast(int)overflow.height); 373 drawingSprite.position = new Point(cast(ptrdiff_t)overflow.x, cast(ptrdiff_t)overflow.y); 374 } 375 } 376 } 377 } 378 }