1 module evael.graphics.gui.controls.Button; 2 3 import evael.graphics.gui.controls.Control; 4 import evael.graphics.Font; 5 6 import evael.utils.Math; 7 8 import evael.utils.Size; 9 10 class Button : Control 11 { 12 public enum Type 13 { 14 Text = (1u << 0), 15 Icon = (1u << 1) 16 } 17 18 /// Button text 19 private wstring m_text; 20 21 /// Text position 22 private vec2 m_textPosition; 23 24 /// Icon position 25 private vec2 m_iconPosition; 26 27 /// Button type 28 private Type m_type; 29 30 /// Button icon 31 private Icon m_icon; 32 33 public this(in float x, in float y, in int width = 0, in int height = 0) 34 { 35 this("", x, y, width, height); 36 } 37 38 public this(in wstring text, in float x = 0, in float y = 0, in int width = 0, in int height = 0) 39 { 40 this(text, vec2(x, y), Size!int(width, height)); 41 } 42 43 public this(in wstring text, in vec2 position) 44 { 45 this(text, position, Size!int(0, 0)); 46 } 47 48 public this(in wstring text, in vec2 position, in Size!int size) 49 { 50 super(position, size); 51 52 this.m_name = "button"; 53 this.m_text = text; 54 this.m_textPosition = vec2(0.0f, 0.0f); 55 this.m_iconPosition = this.m_textPosition; 56 this.m_type = Type.Text; 57 } 58 59 /** 60 * Renders the button 61 */ 62 public override void draw(in float deltaTime) 63 { 64 if(!this.m_isVisible) 65 return; 66 67 super.draw(deltaTime); 68 69 if(this.m_type & Type.Text) 70 { 71 this.m_theme.font.draw(this.m_text, vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_textPosition, 72 this.m_theme.fontColor, this.m_theme.fontSize, this.m_theme.drawTextShadow); 73 } 74 75 if(this.m_type & Type.Icon) 76 { 77 this.m_theme.iconFont.draw(cpToUtf(this.m_icon), vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_iconPosition, 78 this.m_theme.fontColor, this.m_theme.fontSize); 79 } 80 } 81 82 /** 83 * Event called on mouse button click 84 * Params: 85 * mouseButton : mouse button 86 * mousePosition : mouse position 87 */ 88 public override void onMouseClick(in MouseButton mouseButton, in ref vec2 mousePosition) 89 { 90 super.onMouseClick(mouseButton, mousePosition); 91 92 if(this.m_isEnabled) 93 { 94 this.switchState!(State.Clicked); 95 } 96 } 97 98 /** 99 * Event called on mouse button release 100 * Params: 101 * mouseButton : mouse button 102 */ 103 public override void onMouseUp(in MouseButton mouseButton) 104 { 105 super.onMouseUp(mouseButton); 106 107 if(this.m_isEnabled) 108 { 109 this.switchState!(State.Hovered); 110 } 111 } 112 113 /** 114 * Event called when mouse enters in control's rect 115 * Params: 116 * mousePosition : mouse position 117 */ 118 public override void onMouseMove(in ref vec2 mousePosition) 119 { 120 super.onMouseMove(mousePosition); 121 122 if(this.m_isEnabled) 123 { 124 if(this.isClicked) 125 { 126 this.switchState!(State.Clicked); 127 } 128 else 129 { 130 this.switchState!(State.Hovered); 131 } 132 } 133 } 134 135 /** 136 * Event called when mouse leaves control's rect 137 */ 138 public override void onMouseLeave() 139 { 140 super.onMouseLeave(); 141 142 if(this.m_isEnabled) 143 { 144 this.switchState!(State.Normal); 145 } 146 } 147 148 /** 149 * Initializes control 150 */ 151 public override void initialize() 152 { 153 float width = 0.0f, height = 0.0f; 154 155 if(this.m_type & Type.Text && this.m_text.length) 156 { 157 immutable bounds = this.m_theme.font.getTextBounds(this.m_text, 0, this.m_theme.fontSize); 158 159 width = bounds[2] - bounds[0]; 160 height = bounds[3] - bounds[1]; 161 } 162 163 if (this.m_type & Type.Icon) 164 { 165 immutable bounds = this.m_theme.iconFont.getTextBounds(cpToUtf(this.m_icon), 0, this.m_theme.fontSize); 166 167 width += bounds[2] - bounds[0]; 168 169 // We don't need to add heights together, we just take the highest value 170 immutable iconHeight = bounds[3] - bounds[1]; 171 172 if(iconHeight > height) 173 { 174 height = iconHeight; 175 } 176 } 177 178 if(width > this.m_size.width) 179 { 180 this.m_size.width = cast(int)width + 10; 181 } 182 183 if(height > this.m_size.height) 184 { 185 this.m_size.height = cast(int)height + 5; 186 } 187 188 import std.math : round; 189 190 this.m_textPosition.x = round(this.m_size.halfWidth - (width / 2)); 191 this.m_textPosition.y = round(this.m_size.halfHeight - (height / 2)); 192 193 this.m_iconPosition = this.m_textPosition; 194 195 super.initialize(); 196 } 197 198 @property 199 { 200 public void type(in Type value) nothrow @nogc 201 { 202 this.m_type = value; 203 } 204 205 public void icon(in Icon value) nothrow @nogc 206 { 207 this.m_icon = value; 208 } 209 } 210 211 212 }