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 * An image component allows for images to be rendered with a set of extra features and flexibility such as fading etc. 12 */ 13 module novelate.ui.imagecomponent; 14 15 import std.conv : to; 16 17 import novelate.ui.component; 18 import novelate.buildstate; 19 20 /// Wrapepr around an image component. 21 final class ImageComponent : Component 22 { 23 private: 24 /// The image. 25 ExternalImage _image; 26 /// Boolean determining whether the image is full-screen or not. 27 bool _fullScreen; 28 /// The alpha channel. 29 ubyte _alpha; 30 /// The current fade-in amount. 31 ubyte _fadingIn; 32 /// The current fade-out amount. 33 ubyte _fadingOut; 34 35 public: 36 final: 37 /** 38 * Creates a new image component. 39 * Params: 40 * path = The path of the image. 41 */ 42 this(string path) 43 { 44 _image = new ExternalImage(); 45 _image.loadFromFile(path); 46 _image.position = FloatVector(0, 0); 47 48 _alpha = 255; 49 50 auto bounds = _image.bounds; 51 52 super(bounds.x, bounds.y); 53 } 54 55 @property 56 { 57 /// Gets a boolean determining whether the image is full-screen or not. 58 bool fullScreen() { return _fullScreen; } 59 60 /// Sets a boolean determining whether the image is full-screen or not. 61 void fullScreen(bool isFullScreen) 62 { 63 _fullScreen = isFullScreen; 64 } 65 /// Gets the alpha channel. 66 ubyte alpha() { return _alpha; } 67 /// Sets the alpha channel. 68 void alpha(ubyte newAlpha) 69 { 70 _alpha = newAlpha; 71 72 _image.color = Paint(255, 255, 255, _alpha); 73 } 74 } 75 76 /// A handler for when the image has faded out. 77 void delegate() fadedOut; 78 /// A handler for when the image has faded in. 79 void delegate() fadedIn; 80 /// A handler for when the image is fading out. 81 void delegate(ubyte) fadingOut; 82 /// A handler for when the image is fading in. 83 void delegate(ubyte) fadingIn; 84 85 /** 86 * Fades out the image. 87 * Params: 88 * speed = The speed at which the image will fade. 89 */ 90 void fadeOut(ubyte speed) 91 { 92 if (_fadingOut) 93 { 94 return; 95 } 96 97 _fadingIn = 0; 98 _fadingOut = speed; 99 alpha = 255; 100 } 101 102 /** 103 * Fades in the image. 104 * Params: 105 * speed = The speed at which the image will fade. 106 */ 107 void fadeIn(ubyte speed) 108 { 109 if (_fadingIn) 110 { 111 return; 112 } 113 114 _fadingOut = 0; 115 _fadingIn = speed; 116 alpha = 0; 117 } 118 119 /// See: Component.render() 120 override void render(ExternalWindow window) 121 { 122 if (_image) 123 { 124 ptrdiff_t oldAlpha = cast(ptrdiff_t)_alpha; 125 126 if (_fadingIn && oldAlpha < 255) 127 { 128 oldAlpha += _fadingIn; 129 130 if (fadingIn) 131 { 132 fadingIn(cast(ubyte)oldAlpha); 133 } 134 135 if (oldAlpha >= 255) 136 { 137 oldAlpha = 255; 138 139 if (fadedIn) 140 { 141 fadedIn(); 142 } 143 } 144 145 alpha = cast(ubyte)oldAlpha; 146 } 147 else if (_fadingOut && _alpha > 0) 148 { 149 oldAlpha -= _fadingOut; 150 151 if (fadingOut) 152 { 153 fadingOut(cast(ubyte)oldAlpha); 154 } 155 156 if (oldAlpha <= 0) 157 { 158 oldAlpha = 0; 159 160 if (fadedOut) 161 { 162 fadedOut(); 163 } 164 } 165 166 alpha = cast(ubyte)oldAlpha; 167 } 168 169 _image.draw(window); 170 } 171 } 172 173 /// See: Component.refresh() 174 override void refresh(size_t width, size_t height) 175 { 176 if (!_fullScreen) 177 { 178 return; 179 } 180 181 auto bounds = _image.bounds; 182 183 _image.scale = 184 FloatVector 185 ( 186 cast(int)width / bounds.x, 187 cast(int)height / bounds.y 188 ); 189 } 190 191 /// See: Component.updateSize() 192 override void updateSize() 193 { 194 if (_fullScreen) 195 { 196 return; 197 } 198 199 auto bounds = _image.bounds; 200 201 _image.scale = 202 FloatVector 203 ( 204 cast(int)super.width / bounds.x, 205 cast(int)super.height / bounds.y 206 ); 207 } 208 209 /// See: Component.fitToSize() 210 void fitToSize(double maxWidth, double maxHeight, bool enlarge = false) 211 { 212 import std.math : fmin, round; 213 214 auto src = super.size; 215 216 maxWidth = enlarge ? cast(double)maxWidth : fmin(maxWidth, cast(double)src.x); 217 maxHeight = enlarge ? cast(double)maxHeight : fmin(maxHeight, cast(double)src.y); 218 219 double rnd = fmin(maxWidth / cast(double)src.x, maxHeight / cast(double)src.y); 220 221 auto newWidth = round(src.x * rnd); 222 auto newHeight = round(src.y * rnd); 223 224 super.size = FloatVector(newWidth, newHeight); 225 } 226 227 /// See: Component.updatePosition() 228 override void updatePosition() 229 { 230 _image.position = super.position; 231 } 232 233 static if (isManualMemory) 234 { 235 /// See: Component.clean() 236 override void clean() 237 { 238 if (_image) 239 { 240 _image.clean(); 241 } 242 } 243 } 244 }