1 module evael.graphics.gui.controls.ContextMenuStrip; 2 3 import std.conv; 4 5 import evael.graphics.gui.controls.Container; 6 7 import evael.utils.Math; 8 9 import evael.utils.Size; 10 import evael.utils.Color; 11 12 class ContextMenuStrip : Container 13 { 14 /// Item size 15 private Size!int m_itemSize; 16 17 /// Position for the next item 18 private vec2 m_nextItemPosition; 19 20 public this(in float x, in float y, in int width = 0) 21 { 22 this(vec2(x, y), Size!int(width, 0)); 23 } 24 25 public this(in vec2 position, in Size!int size) 26 { 27 super(position, size); 28 29 this.m_name = "contextMenuStrip"; 30 31 this.m_itemSize = Size!int(this.m_size.width, 0); 32 33 this.m_movable = false; 34 } 35 36 public override void draw(in float deltaTime) 37 { 38 super.draw(deltaTime); 39 } 40 41 42 /** 43 * Adds item 44 * Params: 45 * itemText : item text 46 */ 47 public void addItem(in string itemText, OnClickEvent onClick) 48 { 49 this.addItem(itemText.to!wstring, onClick); 50 } 51 52 public void addItem(in wstring itemText, OnClickEvent onClick) 53 {/* 54 this.m_size.height = this.m_size.height + 20; 55 56 // 1.0f = Border pixel 57 this.m_nextItemPosition = vec2(1.0f, this.m_size.height - 19.0f); 58 */ 59 auto item = new ContextMenuStripItem(this.m_controls.length, itemText, vec2(0), this.m_itemSize); 60 item.onClickEvent = onClick; 61 62 this.addChild(item); 63 } 64 65 /** 66 * Initializes control 67 */ 68 public override void initialize() 69 { 70 super.initialize(); 71 72 // Now that child controls have been correctly sized, we can defines ContextMenuStrip's height 73 74 int y = 0; 75 int height = 0; 76 77 foreach(control; this.m_controls) 78 { 79 height += control.size.height; 80 control.position = vec2(0, y); 81 control.realPosition = control.position + this.m_realPosition; 82 y += height; 83 } 84 85 this.m_size.height = height; 86 } 87 } 88 89 90 class ContextMenuStripItem : Control 91 { 92 /// Item text 93 private wstring m_text; 94 95 /// Item text position 96 private vec2 m_textPosition; 97 98 /// Item index 99 private int m_index; 100 101 public this(in int index, in wstring text, in vec2 position, in Size!int size) 102 { 103 super(position, size); 104 105 this.m_name = "contextMenuStripItem"; 106 this.m_index = index; 107 this.m_text = text; 108 } 109 110 111 /** 112 * Renders the item 113 */ 114 public override void draw(in float deltaTime) 115 { 116 if(!this.m_isVisible) 117 return; 118 119 super.draw(deltaTime); 120 121 this.m_theme.font.draw(this.m_text, vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_textPosition, 122 this.m_theme.fontColor, this.m_theme.fontSize); 123 } 124 125 /** 126 * Initializes control 127 */ 128 public override void initialize() 129 { 130 if(this.m_text.length) 131 { 132 float[4] bounds = this.m_theme.font.getTextBounds(this.m_text, 0, this.m_theme.fontSize); 133 134 immutable float w = bounds[2] - bounds[0]; 135 immutable float h = bounds[3] - bounds[1]; 136 137 if(w > this.m_size.width) 138 { 139 this.m_size.width = cast(int)w + 10; 140 } 141 142 if(h > this.m_size.height) 143 { 144 this.m_size.height = cast(int)h + 5; 145 } 146 147 import std.math : round; 148 149 this.m_textPosition.x = 2.0f; 150 this.m_textPosition.y = round(this.m_size.halfHeight - (h / 2)); 151 } 152 153 super.initialize(); 154 } 155 156 /** 157 * Event called on mouse button click 158 * Params: 159 * mouseButton : mouse button 160 * mousePosition : mouse position 161 */ 162 public override void onMouseClick(in MouseButton mouseButton, in ref vec2 mousePosition) 163 { 164 super.onMouseClick(mouseButton, mousePosition); 165 this.switchState!(State.Clicked); 166 } 167 168 /** 169 * Event called on mouse button release 170 * Params: 171 * mouseButton : mouse button 172 */ 173 public override void onMouseUp(in MouseButton mouseButton) 174 { 175 super.onMouseUp(mouseButton); 176 this.switchState!(State.Hovered); 177 } 178 179 /** 180 * Event called when mouse enters in control's rect 181 * Params: 182 * mousePosition : mouse position 183 */ 184 public override void onMouseMove(in ref vec2 mousePosition) 185 { 186 if(this.hasFocus) 187 { 188 return; 189 } 190 191 super.onMouseMove(mousePosition); 192 193 if(this.isClicked) 194 { 195 this.switchState!(State.Clicked); 196 } 197 else 198 { 199 this.switchState!(State.Hovered); 200 } 201 } 202 203 /** 204 * Event called when mouse leaves in control's rect 205 */ 206 public override void onMouseLeave() 207 { 208 super.onMouseLeave(); 209 210 this.switchState!(State.Normal); 211 } 212 213 /** 214 * Properties 215 */ 216 @property 217 public int index() const nothrow @nogc 218 { 219 return this.m_index; 220 } 221 222 }