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