1 /**
2 Film-strip on/off switch.
3
4 Copyright: Ethan Reker 2017.
5 Copyright: Guillaume Piolat 2018.
6 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 */
8
9 module dplug.flatwidgets.flatswitch;
10
11 import std.math;
12 import dplug.core.math;
13 import dplug.gui.element;
14 import dplug.client.params;
15
16 class UIImageSwitch : UIElement, IParameterListener
17 {
18 public:
19 nothrow:
20 @nogc:
21
22 enum Orientation
23 {
24 vertical,
25 horizontal
26 }
27
28 @ScriptProperty
29 {
30 Orientation orientation = Orientation.vertical;
31 }
32
33 this(UIContext context, BoolParameter param, OwnedImage!RGBA onImage, OwnedImage!RGBA offImage)
34 {
35 super(context, flagRaw);
36 _param = param;
37 _param.addListener(this);
38
39 _onImage = onImage;
40 _offImage = offImage;
41 assert(_onImage.h == _offImage.h);
42 assert(_onImage.w == _offImage.w);
43 _width = _onImage.w;
44 _height = _onImage.h;
45
46 _onImageScaled = mallocNew!(OwnedImage!RGBA)();
47 _offImageScaled = mallocNew!(OwnedImage!RGBA)();
48
49 }
50
51 ~this()
52 {
53 _param.removeListener(this);
54 _onImageScaled.destroyFree();
55 _offImageScaled.destroyFree();
56 }
57
58 bool getState()
59 {
60 return unsafeObjectCast!BoolParameter(_param).valueAtomic();
61 }
62
63 override void reflow()
64 {
65 _onImageScaled.size(position.width, position.height);
66 _offImageScaled.size(position.width, position.height);
67 context.globalImageResizer.resizeImage_sRGBWithAlpha(_onImage.toRef, _onImageScaled.toRef);
68 context.globalImageResizer.resizeImage_sRGBWithAlpha(_offImage.toRef, _offImageScaled.toRef);
69 }
70
71 override void onDrawRaw(ImageRef!RGBA rawMap, box2i[] dirtyRects)
72 {
73 auto _currentImage = getState() ? _onImageScaled : _offImageScaled;
74 foreach(dirtyRect; dirtyRects)
75 {
76 auto croppedRawIn = _currentImage.toRef.cropImageRef(dirtyRect);
77 auto croppedRawOut = rawMap.cropImageRef(dirtyRect);
78
79 int w = dirtyRect.width;
80 int h = dirtyRect.height;
81
82 for(int j = 0; j < h; ++j)
83 {
84 RGBA[] input = croppedRawIn.scanline(j);
85 RGBA[] output = croppedRawOut.scanline(j);
86
87 for(int i = 0; i < w; ++i)
88 {
89 ubyte alpha = input[i].a;
90
91 RGBA color = blendColor(input[i], output[i], alpha);
92 output[i] = color;
93 }
94 }
95 }
96 }
97
98 override Click onMouseClick(int x, int y, int button, bool isDoubleClick, MouseState mstate)
99 {
100 if (!_canBeDragged)
101 {
102 // inside gesture, refuse new clicks that could call
103 // excess beginParamEdit()/endParamEdit()
104 return Click.unhandled;
105 }
106
107 if (mstate.altPressed) // reset on ALT + click
108 {
109 _param.beginParamEdit();
110 _param.setFromGUI(_param.defaultValue());
111 }
112 else
113 {
114 // Any click => invert
115 // Note: double-click doesn't reset to default, would be annoying
116 _param.beginParamEdit();
117 _param.setFromGUI(!_param.value());
118 }
119 _canBeDragged = false;
120 return Click.startDrag;
121 }
122
123 override void onMouseEnter()
124 {
125 _param.beginParamHover();
126 setDirtyWhole();
127 }
128
129 override void onMouseMove(int x, int y, int dx, int dy, MouseState mstate)
130 {
131 }
132
133 override void onMouseExit()
134 {
135 _param.endParamHover();
136 setDirtyWhole();
137 }
138
139 override void onBeginDrag()
140 {
141 }
142
143 override void onStopDrag()
144 {
145 // End parameter edit at end of dragging, even if no parameter change happen,
146 // so that touch automation restore previous parameter value at the end of the mouse
147 // gesture.
148 _param.endParamEdit();
149 _canBeDragged = true;
150 }
151
152 override void onMouseDrag(int x, int y, int dx, int dy, MouseState mstate)
153 {
154 }
155
156 override void onParameterChanged(Parameter sender) nothrow @nogc
157 {
158 setDirtyWhole();
159 }
160
161 override void onBeginParameterEdit(Parameter sender)
162 {
163 }
164
165 override void onEndParameterEdit(Parameter sender)
166 {
167 }
168
169 override void onBeginParameterHover(Parameter sender)
170 {
171 }
172
173 override void onEndParameterHover(Parameter sender)
174 {
175 }
176
177 protected:
178
179 BoolParameter _param;
180 bool _state;
181 OwnedImage!RGBA _onImage;
182 OwnedImage!RGBA _offImage;
183 OwnedImage!RGBA _onImageScaled;
184 OwnedImage!RGBA _offImageScaled;
185 int _width;
186 int _height;
187
188 /// To prevent multiple-clicks having an adverse effect on automation.
189 bool _canBeDragged = true;
190 }