1 /// 2 module nanogui.checkbox; 3 4 /* 5 NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>. 6 The widget drawing code is based on the NanoVG demo application 7 by Mikko Mononen. 8 9 All rights reserved. Use of this source code is governed by a 10 BSD-style license that can be found in the LICENSE.txt file. 11 */ 12 13 import nanogui.widget; 14 import nanogui.common : Vector2i, Vector2f, MouseButton; 15 16 /** 17 * Two-state check box widget. 18 * 19 * Remarks: 20 * This class overrides `nanogui.Widget.mIconExtraScale` to be `1.2f`, 21 * which affects all subclasses of this Widget. Subclasses must explicitly 22 * set a different value if needed (e.g., in their constructor). 23 */ 24 class CheckBox : Widget 25 { 26 public: 27 /** 28 * Adds a CheckBox to the specified `parent`. 29 * 30 * Params: 31 * parent = The Widget to add this CheckBox to. 32 * caption = The caption text of the CheckBox (default `"Untitled"`). 33 * callback = If provided, the callback to execute when the CheckBox is 34 * checked or unchecked. Default parameter function does nothing. See 35 * `nanogui.CheckBox.mPushed` for the difference between "pushed" 36 * and "checked". 37 */ 38 this(Widget parent, const string caption, void delegate(bool) callback) 39 { 40 super(parent); 41 mCaption = caption; 42 mPushed = false; 43 mChecked = false; 44 mCallback = callback; 45 mIconExtraScale = 1.2f;// widget override} 46 } 47 48 /// The caption of this CheckBox. 49 final string caption() const { return mCaption; } 50 51 /// Sets the caption of this CheckBox. 52 final void caption(string caption) { mCaption = caption; } 53 54 /// Whether or not this CheckBox is currently checked. 55 final bool checked() const { return mChecked; } 56 57 /// Sets whether or not this CheckBox is currently checked. 58 final void checked(bool checked) { mChecked = checked; } 59 60 /// Whether or not this CheckBox is currently pushed. See `nanogui.CheckBox.mPushed`. 61 final bool pushed() const { return mPushed; } 62 63 /// Sets whether or not this CheckBox is currently pushed. See `nanogui.CheckBox.mPushed`. 64 final void pushed(bool pushed) { mPushed = pushed; } 65 66 /// Returns the current callback of this CheckBox. 67 final void delegate(bool) callback() const { return mCallback; } 68 69 /// Sets the callback to be executed when this CheckBox is checked / unchecked. 70 final void callback(void delegate(bool) callback) { mCallback = callback; } 71 72 /** 73 * The mouse button callback will return `true` when all three conditions are met: 74 * 75 * 1. This CheckBox is "enabled" (see `nanogui.Widget.mEnabled`). 76 * 2. `p` is inside this CheckBox. 77 * 3. `button` is `MouseButton.Left`. 78 * 79 * Since a mouse button event is issued for both when the mouse is pressed, as well 80 * as released, this function sets `nanogui.CheckBox.mPushed` to `true` when 81 * parameter `down == true`. When the second event (`down == false`) is fired, 82 * `nanogui.CheckBox.mChecked` is inverted and `nanogui.CheckBox.mCallback` 83 * is called. 84 * 85 * That is, the callback provided is only called when the mouse button is released, 86 * **and** the click location remains within the CheckBox boundaries. If the user 87 * clicks on the CheckBox and releases away from the bounds of the CheckBox, 88 * `nanogui.CheckBox.mPushed` is simply set back to `false`. 89 */ 90 override bool mouseButtonEvent(Vector2i p, MouseButton button, bool down, int modifiers) 91 { 92 super.mouseButtonEvent(p, button, down, modifiers); 93 if (!mEnabled) 94 return false; 95 96 if (button == MouseButton.Left) 97 { 98 if (down) 99 { 100 mPushed = true; 101 } 102 else if (mPushed) 103 { 104 if (contains(p)) 105 { 106 mChecked = !mChecked; 107 if (mCallback) 108 mCallback(mChecked); 109 } 110 mPushed = false; 111 } 112 return true; 113 } 114 return false; 115 } 116 117 /// The preferred size of this CheckBox. 118 override Vector2i preferredSize(NanoContext ctx) const 119 { 120 if (mFixedSize != Vector2i()) 121 return mFixedSize; 122 ctx.fontSize(fontSize()); 123 ctx.fontFace("sans"); 124 float[4] bounds; 125 return cast(Vector2i) Vector2f( 126 (ctx.textBounds(0, 0, mCaption, bounds[]) + 127 1.8f * fontSize()), 128 fontSize() * 1.3f); 129 } 130 131 /// Draws this CheckBox. 132 override void draw(ref NanoContext ctx) 133 { 134 super.draw(ctx); 135 136 ctx.fontSize(fontSize); 137 ctx.fontFace("sans"); 138 ctx.fillColor(mEnabled ? mTheme.mTextColor : mTheme.mDisabledTextColor); 139 NVGTextAlign algn; 140 algn.left = true; 141 algn.middle = true; 142 ctx.textAlign(algn); 143 ctx.text(mPos.x + 1.6f * fontSize, mPos.y + mSize.y * 0.5f, 144 mCaption); 145 146 NVGPaint bg = ctx.boxGradient(mPos.x + 1.5f, mPos.y + 1.5f, 147 mSize.y - 2.0f, mSize.y - 2.0f, 3, 3, 148 mPushed ? Color(0, 0, 0, 100) : Color(0, 0, 0, 32), 149 Color(0, 0, 0, 180)); 150 151 ctx.beginPath; 152 ctx.roundedRect(mPos.x + 1.0f, mPos.y + 1.0f, mSize.y - 2.0f, 153 mSize.y - 2.0f, 3); 154 ctx.fillPaint(bg); 155 ctx.fill; 156 157 if (mChecked) 158 { 159 ctx.fontSize(mSize.y * icon_scale()); 160 ctx.fontFace("icons"); 161 ctx.fillColor(mEnabled ? mTheme.mIconColor 162 : mTheme.mDisabledTextColor); 163 algn = NVGTextAlign(); 164 algn.center = true; 165 algn.middle = true; 166 ctx.textAlign(algn); 167 ctx.text(mPos.x + mSize.y * 0.5f + 1, 168 mPos.y + mSize.y * 0.5f, [mTheme.mCheckBoxIcon]); 169 } 170 } 171 172 // // Saves this CheckBox to the specified Serializer. 173 //override void save(Serializer &s) const; 174 175 // // Loads the state of the specified Serializer to this CheckBox. 176 //override bool load(Serializer &s); 177 178 protected: 179 /// The caption text of this CheckBox. 180 string mCaption; 181 182 /** 183 * Internal tracking variable to distinguish between mouse click and release. 184 * `nanogui.CheckBox.mCallback` is only called upon release. See 185 * `nanogui.CheckBox.mouseButtonEvent` for specific conditions. 186 */ 187 bool mPushed; 188 189 /// Whether or not this CheckBox is currently checked or unchecked. 190 bool mChecked; 191 192 /// The function to execute when `nanogui.CheckBox.mChecked` is changed. 193 void delegate(bool) mCallback; 194 }