1 /** 2 * Widget for displaying an editable textbox. User must click on widget to edit, 3 * and mouse must be over box while editing. 4 * 5 * Copyright: Copyright Auburn Sounds 2015-2017. 6 * Copyright: Cut Through Recordings 2017. 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Authors: Ethan Reker 9 */ 10 module dplug.pbrwidgets.textbox; 11 12 import dplug.gui.element; 13 import dplug.core.nogc; 14 import dplug.core.vec; 15 import dplug.window.window : getCharFromKey; 16 17 private import core.stdc.stdlib : malloc, free; 18 private import core.stdc.stdio : snprintf, printf; 19 private import core.stdc..string : strcmp, strlen; 20 21 deprecated("Use the UITextBox name instead of UITextbox") 22 alias UITextbox = UITextBox; 23 24 class UITextBox : UIElement 25 { 26 public: 27 nothrow: 28 @nogc: 29 30 this(UIContext context, Font font, int textSize, RGBA textColor = RGBA(200, 200, 200, 255), RGBA backgroundColor = RGBA(0, 0, 0, 255)) 31 { 32 super(context); 33 _font = font; 34 _textSize = textSize; 35 _textColor = textColor; 36 _backgroundColor = backgroundColor; 37 charBuffer = makeVec!char(); 38 } 39 40 ~this() 41 { 42 } 43 44 @property const(char)[] getText() 45 { 46 return displayString(); 47 } 48 49 override void onDraw(ImageRef!RGBA diffuseMap, ImageRef!L16 depthMap, ImageRef!RGBA materialMap, box2i[] dirtyRects) 50 { 51 float textPosx = position.width * 0.5f; 52 float textPosy = position.height * 0.5f; 53 54 foreach(dirtyRect; dirtyRects) 55 { 56 auto croppedDiffuse = diffuseMap.cropImageRef(dirtyRect); 57 vec2f positionInDirty = vec2f(textPosx, textPosy) - dirtyRect.min; 58 59 croppedDiffuse.fillAll(_backgroundColor); 60 croppedDiffuse.fillText(_font, displayString(), _textSize, 0.5, _textColor, positionInDirty.x, positionInDirty.y); 61 } 62 } 63 64 override bool onMouseClick(int x, int y, int button, bool isDoubleClick, MouseState mstate) 65 { 66 // Left click 67 _isActive = true; 68 69 setDirtyWhole(); 70 return true; 71 } 72 73 override void onMouseEnter() 74 { 75 setDirtyWhole(); 76 } 77 78 override void onMouseExit() 79 { 80 _isActive = false; 81 setDirtyWhole(); 82 } 83 84 override bool onKeyDown(Key key) 85 { 86 if(_isActive) 87 { 88 const char c = cast(char)getCharFromKey(key); 89 if(c == '\t') 90 { 91 if (charBuffer.length > 0) 92 { 93 charBuffer.popBack(); 94 } 95 } 96 else if(c != '\0') 97 charBuffer.pushBack(c); 98 setDirtyWhole(); 99 return true; 100 } 101 102 return false; 103 } 104 105 private: 106 107 Font _font; 108 int _textSize; 109 RGBA _textColor; 110 RGBA _backgroundColor; 111 bool _isActive; 112 Vec!char charBuffer; 113 114 const(char)[] displayString() nothrow @nogc 115 { 116 return charBuffer[]; 117 } 118 119 final bool containsPoint(int x, int y) 120 { 121 box2i subSquare = getSubsquare(); 122 float centerx = (subSquare.min.x + subSquare.max.x - 1) * 0.5f; 123 float centery = (subSquare.min.y + subSquare.max.y - 1) * 0.5f; 124 125 float minx = centerx - (_position.width / 2); 126 float maxx = centerx + (_position.width / 2); 127 float miny = centery - (_position.height / 2); 128 float maxy = centery + (_position.height / 2); 129 130 return x > minx && x < maxx && y > miny && y < maxy; 131 } 132 133 /// Returns: largest square centered in _position 134 final box2i getSubsquare() pure const 135 { 136 // We'll draw entirely in the largest centered square in _position. 137 box2i subSquare; 138 if (_position.width > _position.height) 139 { 140 int offset = (_position.width - _position.height) / 2; 141 int minX = offset; 142 subSquare = box2i(minX, 0, minX + _position.height, _position.height); 143 } 144 else 145 { 146 int offset = (_position.height - _position.width) / 2; 147 int minY = offset; 148 subSquare = box2i(0, minY, _position.width, minY + _position.width); 149 } 150 return subSquare; 151 } 152 153 final float getRadius() pure const 154 { 155 return getSubsquare().width * 0.5f; 156 157 } 158 159 final vec2f getCenter() pure const 160 { 161 box2i subSquare = getSubsquare(); 162 float centerx = (subSquare.min.x + subSquare.max.x - 1) * 0.5f; 163 float centery = (subSquare.min.y + subSquare.max.y - 1) * 0.5f; 164 return vec2f(centerx, centery); 165 } 166 167 }