1 module pixelperfectengine.concrete.popup.popupmenu; 2 3 import pixelperfectengine.concrete.popup.base; 4 5 /** 6 * To create drop-down lists, menu bars, etc. 7 */ 8 public class PopUpMenu : PopUpElement { 9 protected int width, height, select; 10 PopUpMenuElement[] elements; 11 public EventDeleg onMenuSelect; 12 /** 13 * Creates a single PopUpMenu. 14 * Params: 15 * elements = entries for the menu. 16 * source = source identifier. 17 * onMenuSelect = event delegate called on item selection. 18 */ 19 public this(PopUpMenuElement[] elements, string source, EventDeleg onMenuSelect){ 20 this.elements = elements; 21 this.source = source; 22 //this. iconWidth = iconWidth; 23 select = -1; 24 this.onMenuSelect = onMenuSelect; 25 } 26 public override void draw(){ 27 StyleSheet ss = getStyleSheet(); 28 if(output is null){ 29 foreach(e; elements){ 30 int newwidth;// = e.text.getWidth(); 31 if(e.text !is null) newwidth = e.text.getWidth(); 32 if(e.secondaryText !is null) newwidth += e.secondaryText.getWidth() + ss.drawParameters["PopUpMenuMinTextSpace"]; 33 if(newwidth > width){ 34 width = newwidth; 35 } 36 if(e.text !is null) height += e.text.getHeight + (ss.drawParameters["PopUpMenuVertPadding"] * 2); 37 else height += ss.drawParameters["PopUpMenuSeparatorSize"]; 38 } 39 width += (ss.drawParameters["PopUpMenuHorizPadding"] * 2); 40 height += ss.drawParameters["PopUpMenuVertPadding"] * 2; 41 position = Box(0, 0, width - 1, height - 1); 42 output = new BitmapDrawer(width, height); 43 } 44 Box position0 = Box(0, 0, width - 1, height - 1); 45 output.drawFilledBox(position0, ss.getColor("window"));//output.drawFilledRectangle(0,width - 1,0,height - 1,ss.getColor("window")); 46 47 /* if(select > -1){ 48 int y0 = cast(int)((height / elements.length) * select); 49 int y1 = cast(int)((height / elements.length) + y0); 50 output.drawFilledBox(Box(1, y0 + 1, position0.width - 1, y1 - 1), ss.getColor("selection")); //output.drawFilledRectangle(1, width - 1, y0 + 1, y1 + 1, ss.getColor("selection")); 51 } */ 52 53 54 int y = 1 + ss.drawParameters["PopUpMenuVertPadding"]; 55 foreach(size_t i, PopUpMenuElement e; elements){ 56 if (e.text !is null) { //Draw normal menuelement 57 58 const Box textPos = Box(ss.drawParameters["PopUpMenuHorizPadding"], y, 59 position0.width - ss.drawParameters["PopUpMenuHorizPadding"], y + e.text.getHeight()); 60 if (select == i) { 61 output.drawFilledBox(Box(textPos.left, textPos.top + 1, textPos.right, textPos.bottom - 1), 62 ss.getColor("selection")); 63 } 64 output.drawSingleLineText(textPos, e.text); 65 if (e.secondaryText !is null) { 66 67 const Box textPos0 = Box(ss.drawParameters["PopUpMenuHorizPadding"], y, 68 position0.width - ss.drawParameters["PopUpMenuHorizPadding"], y + e.secondaryText.getHeight()); 69 output.drawSingleLineText(textPos0, e.secondaryText); 70 } 71 y += e.text.getHeight() + (ss.drawParameters["PopUpMenuVertPadding"] * 2); 72 } else { //Draw separator 73 const int linePoint = ss.drawParameters["PopUpMenuSeparatorSize"] / 2 + 74 (ss.drawParameters["PopUpMenuSeparatorSize"] & 1); 75 output.drawLine(Point(ss.drawParameters["PopUpMenuHorizPadding"], y + linePoint), 76 Point(position.width - ss.drawParameters["PopUpMenuHorizPadding"] - 1, y + linePoint), 77 ss.getColor("windowinactive")); 78 y += ss.drawParameters["PopUpMenuSeparatorSize"]; 79 } 80 } 81 82 //output.drawRectangle(1,1,height-1,width-1,ss.getColor("windowascent")); 83 /+output.drawLine(0,0,0,height-1,ss.getColor("windowascent")); 84 output.drawLine(0,width-1,0,0,ss.getColor("windowascent")); 85 output.drawLine(0,width-1,height-1,height-1,ss.getColor("windowdescent")); 86 output.drawLine(width-1,width-1,0,height-1,ss.getColor("windowdescent"));+/ 87 with (output) { 88 drawLine(position0.cornerUL, position0.cornerUR, ss.getColor("windowascent")); 89 drawLine(position0.cornerUL, position0.cornerLL, ss.getColor("windowascent")); 90 drawLine(position0.cornerLL, position0.cornerLR, ss.getColor("windowdescent")); 91 drawLine(position0.cornerUR, position0.cornerLR, ss.getColor("windowdescent")); 92 } 93 if(onDraw !is null){ 94 onDraw(); 95 } 96 } 97 public override void passMCE(MouseEventCommons mec, MouseClickEvent mce) { 98 if (mce.state) { 99 mce.y -= position.top; 100 /* mce.y /= height / elements.length; 101 mce.y = mce.y >= elements.length ? cast(int)elements.length - 1 : mce.y; */ 102 int num, vPos = 1 + getStyleSheet().drawParameters["PopUpMenuVertPadding"]; 103 foreach (PopUpMenuElement key; elements) { 104 if (key.text !is null) { 105 vPos += key.text.getHeight() + getStyleSheet.drawParameters["PopUpMenuVertPadding"] * 2; 106 } else { 107 vPos += getStyleSheet.drawParameters["PopUpMenuSeparatorSize"]; 108 } 109 if (vPos > mce.y) { 110 break; 111 } else { 112 num++; 113 } 114 } 115 if (num >= elements.length) return; 116 if (elements[num].source == "\\submenu\\") { 117 PopUpMenu m = new PopUpMenu(elements[mce.y].subElements, this.source, onMenuSelect); 118 m.onMouseClick = onMouseClick; 119 //parent.getAbsolutePosition() 120 parent.addPopUpElement(m, position.left + width, position.top + vPos - text.getHeight); 121 //parent.closePopUp(this); 122 } else if (elements[num].text !is null) { 123 //invokeActionEvent(new Event(elements[offsetY].source, source, null, null, null, offsetY, EventType.CLICK)); 124 if(onMenuSelect !is null) 125 onMenuSelect(new MenuEvent(this, SourceType.PopUpElement, elements[num].text, num, elements[num].source)); 126 parent.endPopUpSession(this); 127 //parent.closePopUp(this); 128 } 129 } 130 131 } 132 public override void passMME(MouseEventCommons mec, MouseMotionEvent mme) { 133 if (!position.isBetween(mme.x, mme.y)) { 134 if(select != -1){ 135 select = -1; 136 } 137 } else { 138 int num, vPos = 1 + getStyleSheet().drawParameters["PopUpMenuVertPadding"]; 139 mme.y -= position.top; 140 foreach (PopUpMenuElement key; elements) { 141 if (key.text !is null) { 142 vPos += key.text.getHeight() + getStyleSheet.drawParameters["PopUpMenuVertPadding"] * 2; 143 } else { 144 vPos += getStyleSheet.drawParameters["PopUpMenuSeparatorSize"]; 145 } 146 if (vPos > mme.y) { 147 select = num; 148 break; 149 } 150 num++; 151 152 } 153 } 154 draw(); 155 } 156 157 } 158 /** 159 * Defines a single MenuElement, also can contain multiple subelements. 160 */ 161 public class PopUpMenuElement { 162 public string source; ///Source identifier. 163 public Text text, secondaryText; ///Primary and secondary display texts 164 //protected Bitmap8Bit icon; 165 private PopUpMenuElement[] subElements; ///Any child element the menu may have 166 //private ushort keymod; 167 //private int keycode; 168 //public int iconWidth; 169 170 /** 171 * Generates a menu element with the supplied parameters. 172 * Uses the default formatting to initialize texts. 173 * Params: 174 * source = source identifier. 175 * text = primary text, forced to be left justified. 176 * secondaryText = secondary text, forced to be right justified. 177 * subElements = any child elements for further submenus. 178 */ 179 public this(string source, dstring text, dstring secondaryText = "", PopUpMenuElement[] subElements = null) { 180 StyleSheet ss = globalDefaultStyle; 181 Text st; 182 if (secondaryText.length) { 183 st = new Text(secondaryText, ss.getChrFormatting("popUpMenuSecondary")); 184 } 185 this(source, new Text(text, ss.getChrFormatting("popUpMenu")), st, subElements); 186 } 187 /** 188 * Generates a menu element with the supplied parameters. 189 * Text formatting can be supplied with the objects. 190 * Params: 191 * source = source identifier. 192 * text = primary text, forced to be left justified. 193 * secondaryText = secondary text, forced to be right justified. 194 * subElements = any child elements for further submenus. 195 */ 196 public this(string source, Text text, Text secondaryText = null, PopUpMenuElement[] subElements = []) { 197 this.source = source; 198 this.text = text; 199 this.secondaryText = secondaryText; 200 this.subElements = subElements; 201 } 202 ///Creates an empty separator element. 203 public static PopUpMenuElement createSeparator() { 204 Text nulltext = null; 205 return new PopUpMenuElement("\\separator\\", nulltext, nulltext); 206 } 207 ///DEPRECATED! 208 ///REMOVE BY VER 0.11! 209 public deprecated Bitmap8Bit getIcon(){ 210 return text.icon; 211 } 212 ///DEPRECATED! 213 ///REMOVE BY VER 0.11! 214 public deprecated void setIcon(Bitmap8Bit icon){ 215 text.icon = icon; 216 } 217 ///Returns all subelements of this menu element. 218 public PopUpMenuElement[] getSubElements() { 219 return subElements; 220 } 221 /** 222 * Assigns this current object's all subelements at once. 223 */ 224 public void loadSubElements(PopUpMenuElement[] e){ 225 subElements = e; 226 } 227 /** 228 * Gets the subelement at the given index. 229 */ 230 public PopUpMenuElement opIndex(size_t i){ 231 return subElements[i]; 232 } 233 /** 234 * Sets the subelement at the given index. 235 */ 236 public PopUpMenuElement opIndexAssign(PopUpMenuElement value, size_t i){ 237 subElements[i] = value; 238 return value; 239 } 240 /** 241 * Implements appending to the last position of the underlying array. 242 */ 243 public PopUpMenuElement opOpAssign(string op)(PopUpMenuElement value){ 244 static if(op == "~"){ 245 subElements ~= value; 246 return value; 247 }else static assert("Operator " ~ op ~ " not supported!"); 248 } 249 ///Returns the lenght of the underlying array. 250 public size_t getLength(){ 251 return subElements.length; 252 } 253 ///Sets the lenght of the underlying array. 254 public void setLength(int l){ 255 subElements.length = l; 256 } 257 258 }