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 }