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 }