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 }