1 /** 2 * PBR widget: on/off switch. 3 * Copyright: Copyright Auburn Sounds 2015 and later. 4 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 5 * Authors: Guillaume Piolat 6 */ 7 module dplug.pbrwidgets.onoffswitch; 8 9 import std.math; 10 import dplug.core.math; 11 import dplug.graphics.drawex; 12 import dplug.gui.element; 13 import dplug.client.params; 14 15 class UIOnOffSwitch : UIElement, IParameterListener 16 { 17 public: 18 nothrow: 19 @nogc: 20 21 enum Orientation 22 { 23 vertical, 24 horizontal 25 } 26 27 RGBA diffuseOff = RGBA(230, 80, 43, 0); 28 RGBA diffuseOn = RGBA(230, 80, 43, 200); 29 RGBA material = RGBA(192, 10, 128, 255); 30 float animationTimeConstant = 10.0f; 31 ushort depthLow = 0; 32 ushort depthHigh = 30000; 33 ushort holeDepth = 0; 34 35 Orientation orientation = Orientation.vertical; 36 37 this(UIContext context, BoolParameter param) 38 { 39 super(context); 40 _param = param; 41 _param.addListener(this); 42 _animation = 0.0f; 43 } 44 45 ~this() 46 { 47 _param.removeListener(this); 48 } 49 50 override void onAnimate(double dt, double time) nothrow @nogc 51 { 52 float target = _param.valueAtomic() ? 1 : 0; 53 54 float newAnimation = lerp(_animation, target, 1.0 - exp(-dt * animationTimeConstant)); 55 56 if (abs(newAnimation - _animation) > 0.001f) 57 { 58 _animation = newAnimation; 59 setDirtyWhole(); 60 } 61 } 62 63 override void onDraw(ImageRef!RGBA diffuseMap, ImageRef!L16 depthMap, ImageRef!RGBA materialMap, box2i[] dirtyRects) nothrow @nogc 64 { 65 // dig a hole 66 depthMap.fillAll(L16(holeDepth)); 67 68 // The switch is in a subrect 69 int width = _position.width; 70 int height = _position.height; 71 float border = 0.1f; 72 box2i switchRect = box2i( cast(int)(0.5f + width * border), 73 cast(int)(0.5f + height * border), 74 cast(int)(0.5f + width * (1 - border)), 75 cast(int)(0.5f + height * (1 - border)) ); 76 77 ubyte red = cast(ubyte)(lerp!float(diffuseOff.r, diffuseOn.r, _animation)); 78 ubyte green = cast(ubyte)(lerp!float(diffuseOff.g, diffuseOn.g, _animation)); 79 ubyte blue = cast(ubyte)(lerp!float(diffuseOff.b, diffuseOn.b, _animation)); 80 int emissive = cast(ubyte)(lerp!float(diffuseOff.a, diffuseOn.a, _animation)); 81 82 if (isMouseOver || isDragged) 83 emissive += 40; 84 85 if (emissive > 255) 86 emissive = 255; 87 88 RGBA diffuseColor = RGBA(red, green, blue, cast(ubyte)emissive); 89 90 diffuseMap.crop(switchRect).fillAll(diffuseColor); 91 92 L16 depthA = L16(cast(short)(lerp!float(depthHigh, depthLow, _animation))); 93 L16 depthB = L16(cast(short)(lerp!float(depthLow, depthHigh, _animation))); 94 95 if (orientation == Orientation.vertical) 96 verticalSlope(depthMap, switchRect, depthA, depthB); 97 else 98 horizontalSlope(depthMap, switchRect, depthA, depthB); 99 100 materialMap.crop(switchRect).fillAll(material); 101 } 102 103 override bool onMouseClick(int x, int y, int button, bool isDoubleClick, MouseState mstate) 104 { 105 // double-click => set to default 106 _param.beginParamEdit(); 107 _param.setFromGUI(!_param.value()); 108 _param.endParamEdit(); 109 return true; 110 } 111 112 override void onMouseEnter() 113 { 114 setDirtyWhole(); 115 } 116 117 override void onMouseExit() 118 { 119 setDirtyWhole(); 120 } 121 122 override void onParameterChanged(Parameter sender) nothrow @nogc 123 { 124 setDirtyWhole(); 125 } 126 127 override void onBeginParameterEdit(Parameter sender) 128 { 129 } 130 131 override void onEndParameterEdit(Parameter sender) 132 { 133 } 134 135 protected: 136 137 /// The parameter this switch is linked with. 138 BoolParameter _param; 139 140 private: 141 float _animation; 142 }