1 module PixelPerfectEngine.concrete.elements.panel;
2 
3 import PixelPerfectEngine.concrete.elements.base;
4 
5 import PixelPerfectEngine.system.etc : clamp, cmpObjPtr;
6 
7 import collections.linkedlist;
8 
9 
10 /**
11  * Panel for grouping elements.
12  * Does not directly handle elements, instead relies on blitter transparency. However, can handle
13  * the state of the elements.
14  */
15 public class Panel : WindowElement, ElementContainer {
16 	alias WESet = LinkedList!(WindowElement, false, "a is b");
17 	protected WESet subElems;			///Contains all elements within the panel
18 	protected sizediff_t focusedElem;				///Index of the currently focused element
19 	/**
20 	 * Default CTOR
21 	 */
22 	public this(Text text, string source, Coordinate coordinates) {
23 		position = coordinates;
24 		this.text = text;
25 		this.source = source;
26 	}
27 	///Ditto
28 	public this(dstring text, string source, Coordinate position) {
29 		this(new Text(text, getStyleSheet().getChrFormatting("panel")), source, position);
30 	}
31 	public override void draw() {
32 		foreach (key; subElems) {
33 			key.draw;
34 		}
35 		StyleSheet ss = getStyleSheet();
36 		const int textLength = text.getWidth();
37 		const Box offsetEdge = position - (text.font.size / 2);
38 		const Box textPos = Box(offsetEdge.left, position.top, offsetEdge.left + textLength, position.top + text.font.size);
39 		with (parent) {
40 			drawLine(Point(offsetEdge.left + textLength, offsetEdge.top), offsetEdge.cornerUR, ss.getColor("windowAscent"));
41 			drawLine(offsetEdge.cornerUL, offsetEdge.cornerLL, ss.getColor("windowAscent"));
42 			drawLine(offsetEdge.cornerLL, offsetEdge.cornerLR, ss.getColor("windowAscent"));
43 			drawLine(offsetEdge.cornerUR, offsetEdge.cornerLR, ss.getColor("windowAscent"));
44 			drawTextSL(textPos, text, Point(0, 0));
45 		}
46 		if (state == ElementState.Disabled) {
47 			parent.bitBLTPattern(position, ss.getImage("ElementDisabledPtrn"));
48 		}
49 	}
50 	
51 	public Coordinate getAbsolutePosition(WindowElement sender) {
52 		return parent.getAbsolutePosition(sender); // TODO: implement
53 	}
54 	
55 	/**
56 	 * Gives focus to the element if applicable
57 	 */
58 	public void requestFocus(WindowElement sender) {
59 		subElems[focusedElem].focusTaken();
60 		focusedElem = subElems.which(sender);
61 		subElems[focusedElem].focusGiven();
62 	}
63 	///Called when an object receives focus.
64 	public override void focusGiven() {
65 		if(subElems.length) subElems[focusedElem].focusGiven();
66 		flags |= IS_FOCUSED;
67 		draw;
68 	}
69 	///Called when an object loses focus.
70 	public override void focusTaken() {
71 		subElems[focusedElem].focusTaken();
72 		flags &= ~IS_FOCUSED;
73 		draw;
74 	}
75 	///Cycles the focus on a single element.
76 	///Returns -1 if end is reached, or the number of remaining elements that
77 	///are cycleable in the direction.
78 	public override int cycleFocus(int direction) {
79 		if (focusedElem + direction < 0 || focusedElem + direction >= subElems.length) {
80 			return -1;
81 		} else {
82 			if (subElems.length) {
83 				const int result = subElems[focusedElem].cycleFocus(direction);
84 				if (result == -1) {
85 					subElems[focusedElem].focusTaken();
86 					focusedElem += direction;
87 					subElems[focusedElem].focusGiven();
88 				}
89 			}
90 			return direction > 1 ? cast(int)(subElems.length - focusedElem) : cast(int)focusedElem;
91 		}
92 	}
93 	
94 	public void drawLine(Point from, Point to, ubyte color) @trusted {
95 		parent.drawLine(from, to, color);
96 	}
97 	
98 	public void drawLinePattern(Point from, Point to, ubyte[] pattern) @trusted {
99 		parent.drawLinePattern(from, to, pattern);
100 	}
101 	
102 	public void drawBox(Coordinate target, ubyte color) @trusted {
103 		parent.drawBox(target, color);
104 	}
105 	
106 	public void drawBoxPattern(Coordinate target, ubyte[] pattern) @trusted {
107 		parent.drawBoxPattern(target, pattern);
108 	}
109 	
110 	public void drawFilledBox(Coordinate target, ubyte color) @trusted {
111 		parent.drawFilledBox(target, color);
112 	}
113 	
114 	public void bitBLT(Point target, ABitmap source) @trusted {
115 		parent.bitBLT(target, source);
116 	}
117 	
118 	public void bitBLT(Point target, ABitmap source, Coordinate slice) @trusted {
119 		parent.bitBLT(target, source, slice);
120 	}
121 	
122 	public void bitBLTPattern(Coordinate target, ABitmap pattern) @trusted {
123 		parent.bitBLTPattern(target, pattern);
124 	}
125 	
126 	public void xorBitBLT(Coordinate target, ABitmap pattern) @trusted {
127 		parent.xorBitBLT(target, pattern);
128 	}
129 	
130 	public void xorBitBLT(Coordinate target, ubyte color) @trusted {
131 		parent.xorBitBLT(target, color);
132 	}
133 	
134 	public void fill(Point target, ubyte color, ubyte background = 0) @trusted {
135 		parent.fill(target, color, background);
136 	}
137 	
138 	public void drawTextSL(Coordinate target, Text text, Point offset) @trusted {
139 		parent.drawTextSL(target, text, offset);
140 	}
141 	
142 	public void drawTextML(Coordinate target, Text text, Point offset) @trusted {
143 		parent.drawTextML(target, text, offset);
144 	}
145 	
146 	public void clearArea(Coordinate target) @trusted {
147 		parent.clearArea(target);
148 	}
149 	/**
150 	 * Sets the cursor to the given type on request.
151 	 */
152 	public void requestCursor(CursorType type) {
153 		parent.requestCursor(type);
154 	}
155 	/**
156 	 * Puts a PopUpElement on the GUI.
157 	 */
158 	public void addPopUpElement(PopUpElement p) {
159 		parent.addPopUpElement(p);
160 	}
161 	/**
162 	 * Puts a PopUpElement on the GUI at the given position.
163 	 */
164 	public void addPopUpElement(PopUpElement p, int x, int y) {
165 		parent.addPopUpElement(p, x, y);
166 	}
167 	/** 
168 	 * Ends the popup session and closes all popups.
169 	 */
170 	public void endPopUpSession(PopUpElement p) {
171 		parent.endPopUpSession(p);
172 	}
173 	/**
174 	 * Closes a single popup element.
175 	 */
176 	public void closePopUp(PopUpElement p) {
177 		parent.closePopUp(p);
178 	}
179 }