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 	//private wstring[] texts;
10 	//private string[] sources;
11 
12 	//private uint[int] hotkeyCodes;
13 	//protected Bitmap8Bit[int] icons;
14 	protected int width, height, select;
15 	PopUpMenuElement[] elements;
16 	public EventDeleg onMenuSelect;
17 	/**
18 	 * Creates a single PopUpMenu.
19 	 */
20 	public this(PopUpMenuElement[] elements, string source, EventDeleg onMenuSelect){
21 		this.elements = elements;
22 		this.source = source;
23 		//this. iconWidth = iconWidth;
24 		select = -1;
25 		this.onMenuSelect = onMenuSelect;
26 	}
27 	public override void draw(){
28 		StyleSheet ss = getStyleSheet();
29 		if(output is null){
30 
31 			//minwidth = (ss.drawParameters["PopUpMenuVertPadding"] * 2);
32 			//int width;
33 			foreach(e; elements){
34 				int newwidth = e.text.getWidth();// + (e is null) ? 0 : e.secondaryText.getWidth();
35 				if(e.secondaryText !is null) newwidth += e.secondaryText.getWidth() + ss.drawParameters["PopUpMenuMinTextSpace"];
36 				//assert(newwidth);
37 				//writeln(e.text.getWidth());
38 				if(newwidth > width){
39 					width = newwidth;
40 					//writeln(width);
41 				}
42 				height += e.text.font.size + (ss.drawParameters["PopUpMenuVertPadding"] * 2);
43 			}
44 			width += (ss.drawParameters["PopUpMenuHorizPadding"] * 2);
45 			height += ss.drawParameters["PopUpMenuVertPadding"] * 2;
46 			position = Box(0, 0, width - 1, height - 1);
47 			output = new BitmapDrawer(width, height);
48 		}
49 		Box position0 = Box(0, 0, width - 1, height - 1);
50 		output.drawFilledBox(position0, ss.getColor("window"));//output.drawFilledRectangle(0,width - 1,0,height - 1,ss.getColor("window"));
51 
52 		if(select > -1){
53 			int y0 = cast(int)((height / elements.length) * select);
54 			int y1 = cast(int)((height / elements.length) + y0);
55 			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"));
56 		}
57 
58 
59 		int y = 1 + ss.drawParameters["PopUpMenuVertPadding"];
60 		foreach(e; elements){
61 			if(e.secondaryText !is null){
62 				/+output.drawColorText(width - ss.drawParameters["PopUpMenuHorizPadding"] - 1, y, e.secondaryText,
63 						ss.getFontset("default"), ss.getColor("PopUpMenuSecondaryTextColor"), FontFormat.RightJustified);+/
64 				//const int textLength = e.secondaryText.getWidth;
65 				const Box textPos = Box(ss.drawParameters["PopUpMenuHorizPadding"], y,
66 						position0.width - ss.drawParameters["PopUpMenuHorizPadding"], y + e.secondaryText.font.size);
67 				output.drawSingleLineText(textPos, e.secondaryText);
68 			}
69 			/+output.drawColorText(ss.drawParameters["PopUpMenuHorizPadding"] + iconWidth, y, e.text, ss.getFontset("default"),
70 					ss.getColor("normaltext"), 0);+/
71 			//const int textLength = e.text.getWidth;
72 			const Box textPos = Box(ss.drawParameters["PopUpMenuHorizPadding"], y,
73 					position0.width - ss.drawParameters["PopUpMenuHorizPadding"], y + e.text.font.size);
74 			output.drawSingleLineText(textPos, e.text);
75 			/+if(e.getIcon() !is null){
76 				//output.insertBitmap(ss.drawParameters["PopUpMenuHorizPadding"], y, e.getIcon());
77 			}+/
78 			y += e.text.font.size + (ss.drawParameters["PopUpMenuVertPadding"] * 2);
79 		}
80 
81 		//output.drawRectangle(1,1,height-1,width-1,ss.getColor("windowascent"));
82 		/+output.drawLine(0,0,0,height-1,ss.getColor("windowascent"));
83 		output.drawLine(0,width-1,0,0,ss.getColor("windowascent"));
84 		output.drawLine(0,width-1,height-1,height-1,ss.getColor("windowdescent"));
85 		output.drawLine(width-1,width-1,0,height-1,ss.getColor("windowdescent"));+/
86 		with (output) {
87 			drawLine(position0.cornerUL, position0.cornerUR, ss.getColor("windowascent"));
88 			drawLine(position0.cornerUL, position0.cornerLL, ss.getColor("windowascent"));
89 			drawLine(position0.cornerLL, position0.cornerLR, ss.getColor("windowdescent"));
90 			drawLine(position0.cornerUR, position0.cornerLR, ss.getColor("windowdescent"));
91 		}
92 		if(onDraw !is null){
93 			onDraw();
94 		}
95 	}
96 	public override void passMCE(MouseEventCommons mec, MouseClickEvent mce) {
97 		if (mce.state) {
98 			mce.y -= position.top;
99 			mce.y /= height / elements.length;
100 			if(elements[mce.y].source == "\\submenu\\"){
101 				PopUpMenu m = new PopUpMenu(elements[mce.y].subElements, this.source, onMenuSelect);
102 				m.onMouseClick = onMouseClick;
103 				//parent.getAbsolutePosition()
104 				parent.addPopUpElement(m, position.left + width, position.top + mce.y * cast(int)(height / elements.length));
105 				//parent.closePopUp(this);
106 			}else{
107 				//invokeActionEvent(new Event(elements[offsetY].source, source, null, null, null, offsetY, EventType.CLICK));
108 				if(onMenuSelect !is null)
109 					onMenuSelect(new MenuEvent(this, SourceType.PopUpElement, elements[mce.y].text, mce.y, elements[mce.y].source));
110 				parent.endPopUpSession(this);
111 				//parent.closePopUp(this);
112 			}
113 		}
114 
115 	}
116 	public override void passMME(MouseEventCommons mec, MouseMotionEvent mme) {
117 		if(!position.isBetween(mme.x, mme.y)){
118 			if(select != -1){
119 				select = -1;
120 				draw;
121 			}
122 		}else{
123 			mme.y -= position.top;
124 			mme.y /= height / elements.length;
125 			if(mme.y < elements.length){
126 				select = mme.y;
127 			}
128 			draw();
129 		}
130 	}
131 
132 }
133 /**
134 * Defines a single MenuElement, also can contain multiple subelements.
135 */
136 public class PopUpMenuElement {
137 	public string source;
138 	public Text text, secondaryText;
139 	//protected Bitmap8Bit icon;
140 	private PopUpMenuElement[] subElements;
141 	private ushort keymod;
142 	private int keycode;
143 	public int iconWidth;
144 
145 	/**
146 	 * Generates a menu element with the supplied parameters.
147 	 * Uses the default formatting to initialize texts.
148 	 */
149 	public this(string source, dstring text, dstring secondaryText = "", PopUpMenuElement[] subElements = null) {
150 		StyleSheet ss = globalDefaultStyle;
151 		Text st;
152 		if (secondaryText.length) {
153 			st = new Text(secondaryText, ss.getChrFormatting("popUpMenuSecondary"));
154 		}
155 		this(source, new Text(text, ss.getChrFormatting("popUpMenu")), st, subElements);
156 	}
157 	/**
158 	 * Generates a menu element with the supplied parameters.
159 	 * Text formatting can be supplied with the objects.
160 	 */
161 	public this(string source, Text text, Text secondaryText = null, PopUpMenuElement[] subElements = []) {
162 		this.source = source;
163 		this.text = text;
164 		this.secondaryText = secondaryText;
165 		this.subElements = subElements;
166 	}
167 	///DEPRECATED!
168 	///REMOVE BY VER 0.11!
169 	public Bitmap8Bit getIcon(){
170 		return text.icon;
171 	}
172 	///DEPRECATED!
173 	///REMOVE BY VER 0.11!
174 	public void setIcon(Bitmap8Bit icon){
175 		text.icon = icon;
176 	}
177 	///Returns all subelements of this menu element.
178 	public PopUpMenuElement[] getSubElements() {
179 		return subElements;
180 	}
181 	/**
182 	 * Assigns this current object's all subelements at once.
183 	 */
184 	public void loadSubElements(PopUpMenuElement[] e){
185 		subElements = e;
186 	}
187 	/**
188 	 * Gets the subelement at the given index.
189 	 */
190 	public PopUpMenuElement opIndex(size_t i){
191 		return subElements[i];
192 	}
193 	/**
194 	 * Sets the subelement at the given index.
195 	 */
196 	public PopUpMenuElement opIndexAssign(PopUpMenuElement value, size_t i){
197 		subElements[i] = value;
198 		return value;
199 	}
200 	/**
201 	 * Implements appending to the last position of the underlying array.
202 	 */
203 	public PopUpMenuElement opOpAssign(string op)(PopUpMenuElement value){
204 		static if(op == "~"){
205 			subElements ~= value;
206 			return value;
207 		}else static assert("Operator " ~ op ~ " not supported!");
208 	}
209 	///Returns the lenght of the underlying array.
210 	public size_t getLength(){
211 		return subElements.length;
212 	}
213 	///Sets the lenght of the underlying array.
214 	public void setLength(int l){
215 		subElements.length = l;
216 	}
217 
218 }