1 module pixelperfectengine.concrete.elements.radiobutton; 2 3 public import pixelperfectengine.concrete.elements.base; 4 import collections.linkedlist; 5 6 /** 7 * Implements a single radio button. 8 * Needs to be grouped to used. 9 * Equality is checked by comparing `source`, so give each RadioButton a different source value. 10 */ 11 public class RadioButton : WindowElement, IRadioButton, ISmallButton { 12 protected IRadioButtonGroup group; ///The group which this object belongs to. 13 //protected bool _isLatched; ///The state of the RadioButton 14 public string iconLatched = "radioButtonB"; ///Sets the icon for latched positions 15 public string iconUnlatched = "radioButtonA"; ///Sets the icon for unlatched positions 16 public this(Text text, string source, Box position, IRadioButtonGroup group = null) { 17 this.position = position; 18 this.text = text; 19 this.source = source; 20 if (group) group.add(this); 21 } 22 ///Ditto 23 public this(dstring text, string source, Box position, IRadioButtonGroup group = null) { 24 this(new Text(text, getStyleSheet().getChrFormatting("checkBox")), source, position, group); 25 } 26 ///Ditto 27 public this(string iconLatched, string iconUnlatched, string source, Box position, IRadioButtonGroup group = null) { 28 this.position = position; 29 this.iconLatched = iconLatched; 30 this.iconUnlatched = iconUnlatched; 31 this.source = source; 32 this.group = group; 33 if (group) 34 group.add(this); 35 } 36 override public void draw() { 37 parent.clearArea(position); 38 StyleSheet ss = getStyleSheet(); 39 Bitmap8Bit icon = isChecked ? ss.getImage(iconLatched) : ss.getImage(iconUnlatched); 40 parent.bitBLT(position.cornerUL, icon); 41 if (text) { 42 Box textPos = position; 43 textPos.left += icon.width + getStyleSheet.drawParameters["TextSpacingSides"]; 44 parent.drawTextSL(textPos, text, Point.init); 45 } 46 47 if (isFocused) { 48 const int textPadding = ss.drawParameters["horizTextPadding"]; 49 parent.drawBoxPattern(position - textPadding, ss.pattern["blackDottedLine"]); 50 } 51 52 if (state == ElementState.Disabled) { 53 parent.bitBLTPattern(Box(position.left, position.top, position.left + icon.width - 1, position.top + icon.height - 1 54 ), ss.getImage("ElementDisabledPtrn")); 55 } 56 if (onDraw !is null) { 57 onDraw(); 58 } 59 } 60 61 public override void passMCE(MouseEventCommons mec, MouseClickEvent mce) { 62 if (state != ElementState.Enabled) return; 63 if (mce.button == MouseButton.Left && mce.state == ButtonState.Pressed) group.latch(this); 64 super.passMCE(mec, mce); 65 } 66 /** 67 * If the radio button is pressed, then it sets to unpressed. Does nothing otherwise. 68 */ 69 public void latchOff() @trusted { 70 if (isChecked) { 71 isChecked = false; 72 draw(); 73 } 74 } 75 /** 76 * Sets the radio button into its pressed state. 77 */ 78 public void latchOn() @trusted { 79 if (!isChecked) { 80 isChecked = true; 81 draw(); 82 } 83 } 84 85 /** 86 * Sets the group of the radio button. 87 */ 88 public void setGroup(IRadioButtonGroup group) @safe @property { 89 this.group = group; 90 } 91 public bool equals(IRadioButton rhs) @safe pure @nogc nothrow const { 92 WindowElement we = cast(WindowElement)rhs; 93 return source == we.source; 94 } 95 public string value() @property @safe @nogc pure nothrow const { 96 return source; 97 } 98 public bool isSmallButtonHeight(int height) { 99 if (text) return false; 100 else if (position.width == height && position.height == height) return true; 101 else return false; 102 } 103 ///Returns true if left side justified, false otherwise. 104 public bool isLeftSide() @nogc @safe pure nothrow const { 105 return flags & IS_LHS ? true : false; 106 } 107 ///Sets the small button to the left side if true. 108 public bool isLeftSide(bool val) @nogc @safe pure nothrow { 109 if (val) flags |= IS_LHS; 110 else flags &= ~IS_LHS; 111 return flags & IS_LHS ? true : false; 112 } 113 } 114 115 /** 116 * Radio Button Group implementation. 117 * Can send events via it's delegates. 118 */ 119 public class RadioButtonGroup : IRadioButtonGroup { 120 alias RadioButtonSet = LinkedList!(IRadioButton, false, "a.equals(b)"); 121 protected RadioButtonSet radioButtons; 122 protected IRadioButton latchedButton; 123 protected size_t _latchPos; 124 public EventDeleg onToggle; ///If set, it'll be called when the group is toggled. 125 ///Empty ctor 126 public this() @safe pure nothrow @nogc { 127 128 } 129 /** 130 * Creates a new group with some starting elements from a compatible range. 131 */ 132 public this(R)(R range) @safe { 133 foreach (key; range) { 134 radioButtons.put(key); 135 } 136 } 137 /** 138 * Adds a new RadioButton to the group. 139 */ 140 public void add(IRadioButton rg) @safe { 141 radioButtons.put(rg); 142 rg.setGroup(this); 143 } 144 /** 145 * Removes the given RadioButton from the group. 146 */ 147 public void remove(IRadioButton rg) @safe { 148 radioButtons.removeByElem(rg); 149 rg.setGroup(null); 150 } 151 /** 152 * Latches the group. 153 */ 154 public void latch(IRadioButton sender) @safe { 155 latchedButton = sender; 156 for (int i ; i < radioButtons.length ; i++) { 157 IRadioButton elem = radioButtons[i]; 158 if (sender.equals(elem)) { 159 _latchPos = i; 160 } 161 elem.latchOff; 162 } 163 sender.latchOn; 164 callOnToggle(new Event(this, cast(Object)sender, EventType.Toggle, SourceType.RadioButtonGroup)); 165 } 166 /** 167 * Latches to the given position. 168 */ 169 public size_t latchPos(size_t val) @safe { 170 foreach(elem; radioButtons) { 171 elem.latchOff; 172 } 173 radioButtons[val].latchOn; 174 _latchPos = val; 175 callOnToggle(new Event(this, cast(Object)radioButtons[val], EventType.Toggle, SourceType.RadioButtonGroup)); 176 return _latchPos; 177 } 178 ///Calls the `onToggle` delegate if set 179 protected void callOnToggle(Event ev) @trusted { 180 if (onToggle !is null) 181 onToggle (ev); 182 } 183 /** 184 * Returns the current latch position. 185 */ 186 public size_t latchPos() @nogc @safe pure nothrow { 187 return _latchPos; 188 } 189 /** 190 * Returns the value of this group. 191 */ 192 public @property string value() const @nogc @safe pure nothrow { 193 if(latchedButton !is null) return latchedButton.value; 194 else return null; 195 } 196 }