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 ElementState state(ElementState state) @property { 32 ElementState subst = state == ElementState.Enabled ? ElementState.Enabled : ElementState.DisabledWOGray; 33 foreach (WindowElement key; subElems) { 34 key.state = subst; 35 } 36 return super.state(state); 37 } 38 public override void draw() { 39 foreach (key; subElems) { 40 key.draw; 41 } 42 StyleSheet ss = getStyleSheet(); 43 const int textLength = text.getWidth(); 44 Box offsetEdge = position;// - (text.font.size / 2); 45 offsetEdge.top = offsetEdge.top + (text.font.size / 2); 46 const Box textPos = Box(offsetEdge.left + (text.font.size / 2), position.top, 47 offsetEdge.left + textLength + (text.font.size / 2), position.top + text.font.size); 48 with (parent) { 49 drawLine(offsetEdge.cornerUL, Point(offsetEdge.left + (text.font.size / 2), offsetEdge.top), 50 ss.getColor("windowascent")); 51 drawLine(Point(offsetEdge.left + textLength + (text.font.size / 2), offsetEdge.top), offsetEdge.cornerUR, 52 ss.getColor("windowascent")); 53 drawLine(offsetEdge.cornerUL, offsetEdge.cornerLL, ss.getColor("windowascent")); 54 drawLine(offsetEdge.cornerLL, offsetEdge.cornerLR, ss.getColor("windowascent")); 55 drawLine(offsetEdge.cornerUR, offsetEdge.cornerLR, ss.getColor("windowascent")); 56 drawTextSL(textPos, text, Point(0, 0)); 57 } 58 if (super.state == ElementState.Disabled) { 59 parent.bitBLTPattern(position, ss.getImage("ElementDisabledPtrn")); 60 } 61 if (onDraw !is null) { 62 onDraw(); 63 } 64 } 65 /** 66 * Adds an element to the panel 67 */ 68 public void addElement(WindowElement we) { 69 we.setParent(this); 70 subElems.put(we); 71 we.draw(); 72 } 73 74 public Coordinate getAbsolutePosition(WindowElement sender) { 75 return parent.getAbsolutePosition(sender); // TODO: implement 76 } 77 78 /** 79 * Gives focus to the element if applicable 80 */ 81 public void requestFocus(WindowElement sender) { 82 subElems[focusedElem].focusTaken(); 83 focusedElem = subElems.which(sender); 84 subElems[focusedElem].focusGiven(); 85 } 86 ///Called when an object receives focus. 87 public override void focusGiven() { 88 if(subElems.length) subElems[focusedElem].focusGiven(); 89 flags |= IS_FOCUSED; 90 draw; 91 } 92 ///Called when an object loses focus. 93 public override void focusTaken() { 94 subElems[focusedElem].focusTaken(); 95 flags &= ~IS_FOCUSED; 96 draw; 97 } 98 ///Cycles the focus on a single element. 99 ///Returns -1 if end is reached, or the number of remaining elements that 100 ///are cycleable in the direction. 101 public override int cycleFocus(int direction) { 102 if (focusedElem + direction < 0 || focusedElem + direction >= subElems.length) { 103 return -1; 104 } else { 105 if (subElems.length) { 106 const int result = subElems[focusedElem].cycleFocus(direction); 107 if (result == -1) { 108 subElems[focusedElem].focusTaken(); 109 focusedElem += direction; 110 subElems[focusedElem].focusGiven(); 111 } 112 } 113 return direction > 1 ? cast(int)(subElems.length - focusedElem) : cast(int)focusedElem; 114 } 115 } 116 117 public void drawLine(Point from, Point to, ubyte color) @trusted { 118 parent.drawLine(from, to, color); 119 } 120 121 public void drawLinePattern(Point from, Point to, ubyte[] pattern) @trusted { 122 parent.drawLinePattern(from, to, pattern); 123 } 124 125 public void drawBox(Coordinate target, ubyte color) @trusted { 126 parent.drawBox(target, color); 127 } 128 129 public void drawBoxPattern(Coordinate target, ubyte[] pattern) @trusted { 130 parent.drawBoxPattern(target, pattern); 131 } 132 133 public void drawFilledBox(Coordinate target, ubyte color) @trusted { 134 parent.drawFilledBox(target, color); 135 } 136 137 public void bitBLT(Point target, ABitmap source) @trusted { 138 parent.bitBLT(target, source); 139 } 140 141 public void bitBLT(Point target, ABitmap source, Coordinate slice) @trusted { 142 parent.bitBLT(target, source, slice); 143 } 144 145 public void bitBLTPattern(Coordinate target, ABitmap pattern) @trusted { 146 parent.bitBLTPattern(target, pattern); 147 } 148 149 public void xorBitBLT(Coordinate target, ABitmap pattern) @trusted { 150 parent.xorBitBLT(target, pattern); 151 } 152 153 public void xorBitBLT(Coordinate target, ubyte color) @trusted { 154 parent.xorBitBLT(target, color); 155 } 156 157 public void fill(Point target, ubyte color, ubyte background = 0) @trusted { 158 parent.fill(target, color, background); 159 } 160 161 public void drawTextSL(Coordinate target, Text text, Point offset) @trusted { 162 parent.drawTextSL(target, text, offset); 163 } 164 165 public void drawTextML(Coordinate target, Text text, Point offset) @trusted { 166 parent.drawTextML(target, text, offset); 167 } 168 169 public void clearArea(Coordinate target) @trusted { 170 parent.clearArea(target); 171 } 172 /** 173 * Sets the cursor to the given type on request. 174 */ 175 public void requestCursor(CursorType type) { 176 parent.requestCursor(type); 177 } 178 /** 179 * Puts a PopUpElement on the GUI. 180 */ 181 public void addPopUpElement(PopUpElement p) { 182 parent.addPopUpElement(p); 183 } 184 /** 185 * Puts a PopUpElement on the GUI at the given position. 186 */ 187 public void addPopUpElement(PopUpElement p, int x, int y) { 188 parent.addPopUpElement(p, x, y); 189 } 190 /** 191 * Ends the popup session and closes all popups. 192 */ 193 public void endPopUpSession(PopUpElement p) { 194 parent.endPopUpSession(p); 195 } 196 /** 197 * Closes a single popup element. 198 */ 199 public void closePopUp(PopUpElement p) { 200 parent.closePopUp(p); 201 } 202 203 public override void passMCE(MouseEventCommons mec, MouseClickEvent mce) { 204 foreach (WindowElement we; subElems) { 205 if (we.getPosition.isBetween(mce.x, mce.y)) { 206 we.passMCE(mec, mce); 207 focusedElem = subElems.which(we); 208 break; 209 } 210 } 211 super.passMCE(mec, mce); 212 } 213 public override void passMME(MouseEventCommons mec, MouseMotionEvent mme) { 214 if (focusedElem != -1) { 215 subElems[focusedElem].passMME(mec, mme); 216 } 217 super.passMME(mec, mme); 218 } 219 public override void passMWE(MouseEventCommons mec, MouseWheelEvent mwe) { 220 foreach (WindowElement we; subElems) { 221 if (we.getPosition.isBetween(lastMousePosition.x, lastMousePosition.y)) { 222 we.passMWE(mec, mwe); 223 break; 224 } 225 } 226 super.passMWE(mec, mwe); 227 } 228 public int[2] getRasterSizes() { 229 return parent.getRasterSizes(); 230 } 231 }