1 module glui.border; 2 3 import raylib; 4 5 import glui.style; 6 7 8 @safe: 9 10 11 /// Interface for borders 12 interface GluiBorder { 13 14 /// Apply the border, drawing it in the given box. 15 abstract void apply(Rectangle borderBox, uint[4] size) const; 16 17 /// Get the rectangle for the given side of the border. 18 final Rectangle sideRect(Rectangle source, uint[4] size, Style.Side side) const { 19 20 final switch (side) { 21 22 // Left side 23 case Style.Side.left: 24 return Rectangle( 25 source.x, 26 source.y + size.sideTop, 27 size.sideLeft, 28 source.height - size.sideTop - size.sideBottom, 29 ); 30 31 // Right side 32 case Style.Side.right: 33 return Rectangle( 34 source.x + source.width - size.sideRight, 35 source.y + size.sideTop, 36 size.sideRight, 37 source.height - size.sideTop - size.sideBottom, 38 ); 39 40 // Top side 41 case Style.Side.top: 42 return Rectangle( 43 source.x + size.sideLeft, 44 source.y, 45 source.width - size.sideLeft - size.sideRight, 46 size.sideTop 47 ); 48 49 // Bottom side 50 case Style.Side.bottom: 51 return Rectangle( 52 source.x + size.sideLeft, 53 source.y + source.height - size.sideBottom, 54 source.width - size.sideLeft - size.sideRight, 55 size.sideBottom 56 ); 57 58 } 59 60 } 61 62 /// Get square for corner next counter-clockwise to the given side. 63 /// Note: returned rectangles may have negative size; rect start position will always point to the corner itself. 64 final Rectangle cornerRect(Rectangle source, uint[4] size, Style.Side side) const { 65 66 final switch (side) { 67 68 case Style.Side.left: 69 return Rectangle( 70 source.x, 71 source.y + source.height, 72 size.sideLeft, 73 -cast(float) size.sideBottom, 74 ); 75 76 case Style.Side.right: 77 return Rectangle( 78 source.x + source.width, 79 source.y, 80 -cast(float) size.sideRight, 81 size.sideTop, 82 ); 83 84 case Style.Side.top: 85 return Rectangle( 86 source.x, 87 source.y, 88 size.sideLeft, 89 size.sideTop, 90 ); 91 92 case Style.Side.bottom: 93 return Rectangle( 94 source.x + source.width, 95 source.y + source.height, 96 -cast(float) size.sideRight, 97 -cast(float) size.sideBottom, 98 ); 99 100 } 101 102 } 103 104 } 105 106 107 108 ColorBorder colorBorder(Color color) { 109 110 return colorBorder([color]); 111 112 } 113 114 ColorBorder colorBorder(size_t n)(Color[n] color) { 115 116 auto result = new ColorBorder; 117 result.color = normalizeSideArray!Color(color); 118 return result; 119 120 } 121 122 class ColorBorder : GluiBorder { 123 124 Color[4] color; 125 126 void apply(Rectangle borderBox, uint[4] size) const @trusted { 127 128 // For each side 129 foreach (sideIndex; 0..4) { 130 131 const side = cast(Style.Side) sideIndex; 132 const nextSide = cast(Style.Side) ((sideIndex + 1) % 4); 133 134 // Draw all the fragments 135 DrawRectangleRec(sideRect(borderBox, size, side), color[side]); 136 137 // Draw triangles in the corner 138 foreach (shift; 0..2) { 139 140 // Get the corner 141 const cornerSide = shiftSide(side, shift); 142 143 // Get corner parameters 144 const corner = cornerRect(borderBox, size, cornerSide); 145 const cornerStart = Vector2(corner.x, corner.y); 146 const cornerSize = Vector2(corner.w, corner.h); 147 const cornerEnd = side < 2 148 ? Vector2(0, corner.h) 149 : Vector2(corner.w, 0); 150 151 // Draw the first triangle 152 if (!shift) 153 DrawTriangle( 154 cornerStart, 155 cornerStart + cornerSize, 156 cornerStart + cornerEnd, 157 color[side], 158 ); 159 160 // Draw the second one 161 else 162 DrawTriangle( 163 cornerStart, 164 cornerStart + cornerEnd, 165 cornerStart + cornerSize, 166 color[side], 167 ); 168 169 } 170 171 } 172 173 } 174 175 }