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