1 /** 2 * Copyright © Novelate 2020 3 * License: MIT (https://github.com/Novelate/NovelateEngine/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 * Website: https://novelate.com/ 6 * ------ 7 * Novelate is a free and open-source visual novel engine and framework written in the D programming language. 8 * It can be used freely for both personal and commercial projects. 9 * ------ 10 * Module Description: 11 * A layer consists of multiple components that have equal importance in terms of rendering and event delegation. 12 */ 13 module novelate.layer; 14 15 import dsfml.graphics : RenderWindow; 16 import dsfml.system : Vector2f; 17 import dsfml.window : Event, Keyboard, Mouse; 18 19 public alias MouseButton = Mouse.Button; 20 public alias Key = Keyboard.Key; 21 22 import novelate.component; 23 24 /// A layer of components. 25 final class Layer 26 { 27 private: 28 /// The components. 29 Component[string] _components; 30 /// The width of the layer. Usually the resolution width. 31 size_t _width; 32 /// The height of the layer. Usually the resolution height. 33 size_t _height; 34 /// The current mouse position within the window. 35 Vector2f _mousePosition; 36 37 public: 38 final: 39 package (novelate) 40 { 41 /** 42 * Creates a new layer. 43 * Params: 44 * width = The width of the layer. 45 * height = The height of the layer. 46 */ 47 this(size_t width, size_t height) 48 { 49 _width = width; 50 _height = height; 51 } 52 } 53 54 @property 55 { 56 /// Gets the width of the layer. Usually the resolution width. 57 size_t width() { return _width; } 58 59 /// Gets the height of the layer. Usually the resolution height. 60 size_t height() { return _height; } 61 62 /// Gets the amount of components within the layer. 63 size_t length() { return _components ? _components.length : 0; } 64 } 65 66 /// Clears the layer for its components. 67 void clear() 68 { 69 if (!_components) 70 { 71 return; 72 } 73 74 _components.clear(); 75 } 76 77 /** 78 * Adds a component to the layer. 79 * Params: 80 * component = The component to add. 81 * name = The name of the component. This must be unique for the layer, otherwise an existing component will be replaced. 82 */ 83 void addComponent(Component component, string name) 84 { 85 _components[name] = component; 86 } 87 88 /** 89 * Removes a component from the layer. 90 * Params: 91 * name = The name of the component to remove. 92 */ 93 void removeComponent(string name) 94 { 95 if (!_components) 96 { 97 return; 98 } 99 100 _components.remove(name); 101 } 102 103 /** 104 * Gets a component from the layer. You msut cast to the original component type for it to be useful. 105 * Params: 106 * name = The name of the component to get. 107 * Returns: 108 * The component if found, null otherwise. 109 */ 110 Component getComponent(string name) 111 { 112 if (!_components) 113 { 114 return null; 115 } 116 117 return _components.get(name, null); 118 } 119 120 /** 121 * Will render the components of the layer to the given window. 122 * Params: 123 * window = The window to render the components at. 124 */ 125 void render(RenderWindow window) 126 { 127 if (!window) 128 { 129 return; 130 } 131 132 if (!_components) 133 { 134 return; 135 } 136 137 foreach (k,v; _components) 138 { 139 v.render(window); 140 } 141 } 142 143 /** 144 * Refreshes the layer and its components with a given width and height. Usually the resolution width and height. 145 * Params: 146 * width = The width to refresh with. 147 * height = The height to refresh with. 148 */ 149 void refresh(size_t width, size_t height) 150 { 151 _width = width; 152 _height = height; 153 154 if (!_components) 155 { 156 return; 157 } 158 159 foreach (k,v; _components) 160 { 161 v.refresh(_width, _height); 162 } 163 } 164 165 /** 166 * Handles key press events and delegates them to its components. 167 * Params: 168 * key = The key pressed. 169 * stopEvent = (ref) Boolean determining whether the event handling should no longer be delegated. 170 */ 171 void keyPress(Key key, ref bool stopEvent) 172 { 173 if (!_components) 174 { 175 return; 176 } 177 178 foreach (k,v; _components) 179 { 180 if (v.globalKeyPress) 181 { 182 v.globalKeyPress(key, stopEvent); 183 184 if (stopEvent) 185 { 186 break; 187 } 188 } 189 190 if (v.keyPress && v.intersect(_mousePosition)) 191 { 192 v.keyPress(key, stopEvent); 193 194 if (stopEvent) 195 { 196 break; 197 } 198 } 199 } 200 } 201 202 /** 203 * Handles key release events and delegates them to its components. 204 * Params: 205 * key = The key released. 206 * stopEvent = (ref) Boolean determining whether the event handling should no longer be delegated. 207 */ 208 void keyRelease(Key key, ref bool stopEvent) 209 { 210 if (!_components) 211 { 212 return; 213 } 214 215 foreach (k,v; _components) 216 { 217 if (v.globalKeyRelease) 218 { 219 v.globalKeyRelease(key, stopEvent); 220 221 if (stopEvent) 222 { 223 break; 224 } 225 } 226 227 if (v.keyRelease && v.intersect(_mousePosition)) 228 { 229 v.keyRelease(key, stopEvent); 230 231 if (stopEvent) 232 { 233 break; 234 } 235 } 236 } 237 } 238 239 /** 240 * Handles mouse button press events and delegates them to its components. 241 * Params: 242 * button = The mouse button pressed. 243 * stopEvent = (ref) Boolean determining whether the event handling should no longer be delegated. 244 */ 245 void mousePress(MouseButton button, ref bool stopEvent) 246 { 247 if (!_components) 248 { 249 return; 250 } 251 252 foreach (k,v; _components) 253 { 254 if (v.globalMousePress) 255 { 256 v.globalMousePress(button, stopEvent); 257 258 if (stopEvent) 259 { 260 break; 261 } 262 } 263 264 if (v.mousePress && v.intersect(_mousePosition)) 265 { 266 v.mousePress(button, stopEvent); 267 268 if (stopEvent) 269 { 270 break; 271 } 272 } 273 } 274 } 275 276 /** 277 * Handles mouse button release events and delegates them to its components. 278 * Params: 279 * button = The mouse button released. 280 * stopEvent = (ref) Boolean determining whether the event handling should no longer be delegated. 281 */ 282 void mouseRelease(MouseButton button, ref bool stopEvent) 283 { 284 if (!_components) 285 { 286 return; 287 } 288 289 foreach (k,v; _components) 290 { 291 if (v.globalMouseRelease) 292 { 293 v.globalMouseRelease(button, stopEvent); 294 295 if (stopEvent) 296 { 297 break; 298 } 299 } 300 301 if (v.mouseRelease && v.intersect(_mousePosition)) 302 { 303 v.mouseRelease(button, stopEvent); 304 305 if (stopEvent) 306 { 307 break; 308 } 309 } 310 } 311 } 312 313 /** 314 * Handles mouse move events and delegates them to its components. 315 * Params: 316 * x = The x coordinate of the mouse cursor. 317 * y = The y coordinate of the mouse cursor. 318 * stopEvent = (ref) Boolean determining whether the event handling should no longer be delegated. 319 */ 320 void mouseMove(ptrdiff_t x, ptrdiff_t y, ref bool stopEvent) 321 { 322 _mousePosition = Vector2f(x, y); 323 324 if (!_components) 325 { 326 return; 327 } 328 329 foreach (k,v; _components) 330 { 331 if (v.globalMouseMove) 332 { 333 v.globalMouseMove(_mousePosition, stopEvent); 334 335 if (stopEvent) 336 { 337 break; 338 } 339 } 340 341 if (v.mouseMove && v.intersect(_mousePosition)) 342 { 343 v.mouseMove(_mousePosition, stopEvent); 344 345 if (stopEvent) 346 { 347 break; 348 } 349 } 350 } 351 } 352 }