1 module poison.ui.graphics; 2 3 import dsfml.graphics : RectangleShape; 4 import dsfml.system : Vector2f; 5 6 import poison.ui.paint; 7 import poison.core : Size, Point; 8 import poison.ui.picture; 9 import poison.ui.fonts; 10 11 /// Original space struct for graphical elements. 12 private struct OriginalSpace(TPosition,TSize) { 13 /// The original x position. 14 TPosition x; 15 16 /// The original y position. 17 TPosition y; 18 19 /// The original width. 20 TSize width; 21 22 /// The original height. 23 TSize height; 24 } 25 26 /// A sub rect of overflow calculation results. 27 private struct SubRect { 28 /// The x coordinate. 29 float x; 30 31 /// The y coordinate. 32 float y; 33 34 /// The width. 35 float width; 36 37 /// The height. 38 float height; 39 40 /// The overflow top. 41 float overflowTop; 42 43 /// The overflow right. 44 float overflowRight; 45 46 /// The overflow bottom. 47 float overflowBottom; 48 49 /// The overflow left. 50 float overflowLeft; 51 } 52 53 /// Graphics wrapper for components. 54 class Graphics { 55 private: 56 /// The background paint. 57 Paint _backgroundPaint; 58 59 /// The foreground paint. 60 Paint _foregroundPaint; 61 62 /// The low-level background rectangle. 63 RectangleShape _backgroundRect; 64 65 /// The original background rectangle's space. 66 OriginalSpace!(float,float) _originalBackgroundRect; 67 68 /// The background picture. 69 Picture _backgroundPicture; 70 71 /// The original background ´picture's space. 72 OriginalSpace!(ptrdiff_t,int) _originalBackgroundPicture; 73 74 /// The size. 75 Size _size; 76 77 /// The position. 78 Point _position; 79 80 /// The font. 81 Font _font; 82 83 /// The font size. 84 uint _fontSize; 85 86 /// Boolean determining whether the background rectangle is displayable or not. 87 bool _displayableBackgroundRect; 88 89 /// Boolean determining whether the background picture is displayable or not. 90 bool _displayableBackgroundPicture; 91 92 public: 93 final: 94 /// Creates a new graphics wrapper. 95 this() { 96 _backgroundPaint = transparent; 97 _foregroundPaint = transparent; 98 99 _size = new Size(0,0); 100 _position = new Point(0,0); 101 102 _fontSize = 13; 103 _displayableBackgroundRect = true; 104 _displayableBackgroundPicture = true; 105 _originalBackgroundRect = OriginalSpace!(float,float)(0,0,0,0); 106 _originalBackgroundPicture = OriginalSpace!(ptrdiff_t, int)(0,0,0,0); 107 } 108 109 @property { 110 /// Gets the background paint. 111 Paint backgroundPaint() { return _backgroundPaint; } 112 113 /// Sets the background paint. 114 void backgroundPaint(Paint newPaint) { 115 _backgroundPaint = newPaint; 116 117 if (_backgroundRect) { 118 _backgroundRect.fillColor = _backgroundPaint.sfmlColor; 119 } 120 } 121 122 /// Gets the foreground paint. 123 Paint foregroundPaint() { return _foregroundPaint; } 124 125 /// Sets the foreground paint. 126 void foregroundPaint(Paint newPaint) { 127 _foregroundPaint = newPaint; 128 } 129 130 /// Gets the low-level background rectangle. 131 RectangleShape backgroundRect() { return _backgroundRect; } 132 133 /// Gets the background picture. 134 Picture backgroundPicture() { return _backgroundPicture; } 135 136 /// Sets the background picture. 137 void backgroundPicture(Picture newBackgroundPicture) { 138 _backgroundPicture = newBackgroundPicture; 139 140 if (_backgroundPicture) { 141 _backgroundPicture.position = _position; 142 143 _originalBackgroundPicture.x = _position.x; 144 _originalBackgroundPicture.y = _position.y; 145 146 _originalBackgroundPicture.width = _size.width; 147 _originalBackgroundPicture.height = _size.height; 148 } 149 } 150 151 /// Gets the font. 152 Font font() { return _font; } 153 154 /// Sets the font. 155 void font(Font newFont) { 156 _font = newFont; 157 } 158 159 /// Gets the font size. 160 uint fontSize() { return _fontSize; } 161 162 /// Sets the font size. 163 void fontSize(uint newFontSize) { 164 _fontSize = newFontSize; 165 } 166 } 167 168 package(poison): 169 @property { 170 /// Sets the position of the graphics. 171 void position(Point newPosition) { 172 _position = newPosition; 173 174 if (_backgroundRect) { 175 _backgroundRect.position = Vector2f(cast(float)_position.x, cast(float)_position.y); 176 _originalBackgroundRect.x = _backgroundRect.position.x; 177 _originalBackgroundRect.y = _backgroundRect.position.y; 178 } 179 180 if (_backgroundPicture) { 181 _backgroundPicture.position = _position; 182 _originalBackgroundPicture.x = cast(int)_position.x; 183 _originalBackgroundPicture.y = cast(int)_position.y; 184 } 185 } 186 } 187 188 /// Sets the size of the graphics. 189 void size(Size newSize) { 190 _size = newSize; 191 192 _backgroundRect = new RectangleShape(Vector2f(cast(float)_size.width, cast(float)_size.height)); 193 backgroundPaint = _backgroundPaint; 194 position = _position; 195 196 _originalBackgroundRect.width = _backgroundRect.size.x; 197 _originalBackgroundRect.height = _backgroundRect.size.y; 198 199 _originalBackgroundPicture.width = cast(int)_size.width; 200 _originalBackgroundPicture.height = cast(int)_size.height; 201 } 202 203 package(poison): 204 @property { 205 /// Gets a boolean determining whether the background rectangle is displayable. 206 bool displayableBackgroundRect() { return _displayableBackgroundRect; } 207 208 /// Gets a boolean determining whether the background picture is displayable. 209 bool displayableBackgroundPicture() { return _displayableBackgroundPicture; } 210 } 211 212 /** 213 * Renders the sub rectangles for the graphics elements. 214 * Params: 215 * position = The position to be relative to. 216 * size = The size to be relative to. 217 */ 218 void renderSub(Point position, Size size) { 219 import dsfml.graphics : IntRect; 220 import dsfml.system : Vector2f; 221 222 SubRect calculateOverflow(float targetX, float targetY, float targetWidth, float targetHeight) { 223 import std.math : fmax; 224 225 float overflowTop = fmax(0, (cast(float)position.y - targetY)); 226 float overflowRight = fmax(0, (targetX + targetWidth) - (cast(float)position.x + cast(float)size.width)); 227 float overflowBottom = fmax(0, (targetY + targetHeight) - (cast(float)position.y + cast(float)size.height)); 228 float overflowLeft = fmax(0, (cast(float)position.x - targetX)); 229 230 targetY += overflowTop; 231 targetHeight -= overflowTop; 232 targetWidth -= overflowRight; 233 targetHeight -= overflowBottom; 234 targetX += overflowLeft; 235 targetWidth -= overflowLeft; 236 237 return SubRect(targetX, targetY, targetWidth, targetHeight, overflowTop, overflowRight, overflowBottom, overflowLeft); 238 } 239 240 bool intersect(float width, float height, float x, float y) { 241 return(x < cast(float)position.x + cast(float)size.width) && 242 (cast(float)position.x < (x + width)) && 243 (y < cast(float)position.y + cast(float)size.height) && 244 (cast(float)position.y < y + height); 245 } 246 247 if (_backgroundRect) { 248 _backgroundRect.size = Vector2f(_originalBackgroundRect.width, _originalBackgroundRect.height); 249 _backgroundRect.position = Vector2f(_originalBackgroundRect.x, _originalBackgroundRect.y); 250 251 auto rectSize = _backgroundRect.size; 252 auto rectPosition = _backgroundRect.position; 253 254 _displayableBackgroundRect = intersect(rectSize.x, rectSize.y, rectPosition.x, rectPosition.y); 255 256 if (_displayableBackgroundRect) { 257 auto overflow = calculateOverflow(rectPosition.x, rectPosition.y, rectSize.x, rectSize.y); 258 259 _backgroundRect.size = Vector2f(overflow.width, overflow.height); 260 _backgroundRect.position = Vector2f(overflow.x, overflow.y); 261 } 262 } 263 264 if (_backgroundPicture) { 265 _displayableBackgroundPicture = intersect(cast(float)_originalBackgroundPicture.x, cast(float)_originalBackgroundPicture.y, cast(float)_originalBackgroundPicture.width, cast(float)_originalBackgroundPicture.height); 266 267 if (_displayableBackgroundPicture) { 268 auto backgroundSprite = _backgroundPicture.backgroundSprite; 269 auto drawingSprite = _backgroundPicture.drawingSprite; 270 271 if (backgroundSprite) { 272 backgroundSprite.position = new Point(_originalBackgroundPicture.x, _originalBackgroundPicture.y); 273 backgroundSprite.textureRect = IntRect(0, 0, cast(int)_originalBackgroundPicture.width, cast(int)_originalBackgroundPicture.height); 274 } 275 276 if (drawingSprite) { 277 drawingSprite.position = new Point(_originalBackgroundPicture.x, _originalBackgroundPicture.y); 278 drawingSprite.textureRect = IntRect(0, 0, cast(int)_originalBackgroundPicture.width, cast(int)_originalBackgroundPicture.height); 279 } 280 281 auto overflow = calculateOverflow(cast(float)_originalBackgroundPicture.x, cast(float)_originalBackgroundPicture.y, cast(float)_originalBackgroundPicture.width, cast(float)_originalBackgroundPicture.height); 282 283 if (backgroundSprite) { 284 backgroundSprite.textureRect = IntRect(cast(int)overflow.overflowLeft, cast(int)overflow.overflowTop, cast(int)overflow.width, cast(int)overflow.height); 285 backgroundSprite.position = new Point(cast(ptrdiff_t)overflow.x, cast(ptrdiff_t)overflow.y); 286 } 287 288 if (drawingSprite) { 289 drawingSprite.textureRect = IntRect(cast(int)overflow.overflowLeft, cast(int)overflow.overflowTop, cast(int)overflow.width, cast(int)overflow.height); 290 drawingSprite.position = new Point(cast(ptrdiff_t)overflow.x, cast(ptrdiff_t)overflow.y); 291 } 292 } 293 } 294 } 295 }