ExampleUIStates.cpp (9532B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any purpose with 6 * or without fee is hereby granted, provided that the above copyright notice and this 7 * permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD 10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN 11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "DistrhoUI.hpp" 18 #include "Color.hpp" 19 20 START_NAMESPACE_DISTRHO 21 22 /** 23 We need a few classes from DGL. 24 */ 25 using DGL_NAMESPACE::Color; 26 using DGL_NAMESPACE::GraphicsContext; 27 using DGL_NAMESPACE::Rectangle; 28 29 // ----------------------------------------------------------------------------------------------------------- 30 31 class ExampleUIParameters : public UI 32 { 33 public: 34 /** 35 Get key name from an index. 36 */ 37 static const char* getStateKeyFromIndex(const uint32_t index) noexcept 38 { 39 switch (index) 40 { 41 case 0: return "top-left"; 42 case 1: return "top-center"; 43 case 2: return "top-right"; 44 case 3: return "middle-left"; 45 case 4: return "middle-center"; 46 case 5: return "middle-right"; 47 case 6: return "bottom-left"; 48 case 7: return "bottom-center"; 49 case 8: return "bottom-right"; 50 } 51 52 return "unknown"; 53 } 54 55 /* constructor */ 56 ExampleUIParameters() 57 : UI(512, 512) 58 { 59 /** 60 Initialize the grid to all off per default. 61 */ 62 std::memset(fParamGrid, 0, sizeof(bool)*9); 63 64 // TODO explain why this is here 65 setGeometryConstraints(128, 128, true); 66 } 67 68 protected: 69 /* -------------------------------------------------------------------------------------------------------- 70 * DSP/Plugin Callbacks */ 71 72 /** 73 This plugin has no parameters, so we can safely ignore this. 74 */ 75 void parameterChanged(uint32_t, float) override {} 76 77 /** 78 A program has been loaded on the plugin side. 79 This is called by the host to inform the UI about program changes. 80 */ 81 void programLoaded(uint32_t index) override 82 { 83 switch (index) 84 { 85 case 0: 86 fParamGrid[0] = false; 87 fParamGrid[1] = false; 88 fParamGrid[2] = false; 89 fParamGrid[3] = false; 90 fParamGrid[4] = false; 91 fParamGrid[5] = false; 92 fParamGrid[6] = false; 93 fParamGrid[7] = false; 94 fParamGrid[8] = false; 95 break; 96 case 1: 97 fParamGrid[0] = true; 98 fParamGrid[1] = true; 99 fParamGrid[2] = false; 100 fParamGrid[3] = false; 101 fParamGrid[4] = true; 102 fParamGrid[5] = true; 103 fParamGrid[6] = true; 104 fParamGrid[7] = false; 105 fParamGrid[8] = true; 106 break; 107 } 108 repaint(); 109 } 110 111 /** 112 A state has changed on the plugin side. 113 This is called by the host to inform the UI about state changes. 114 */ 115 void stateChanged(const char* key, const char* value) override 116 { 117 const bool valueOnOff = (std::strcmp(value, "true") == 0); 118 119 // check which block changed 120 /**/ if (std::strcmp(key, "top-left") == 0) 121 fParamGrid[0] = valueOnOff; 122 else if (std::strcmp(key, "top-center") == 0) 123 fParamGrid[1] = valueOnOff; 124 else if (std::strcmp(key, "top-right") == 0) 125 fParamGrid[2] = valueOnOff; 126 else if (std::strcmp(key, "middle-left") == 0) 127 fParamGrid[3] = valueOnOff; 128 else if (std::strcmp(key, "middle-center") == 0) 129 fParamGrid[4] = valueOnOff; 130 else if (std::strcmp(key, "middle-right") == 0) 131 fParamGrid[5] = valueOnOff; 132 else if (std::strcmp(key, "bottom-left") == 0) 133 fParamGrid[6] = valueOnOff; 134 else if (std::strcmp(key, "bottom-center") == 0) 135 fParamGrid[7] = valueOnOff; 136 else if (std::strcmp(key, "bottom-right") == 0) 137 fParamGrid[8] = valueOnOff; 138 139 // trigger repaint 140 repaint(); 141 } 142 143 /* -------------------------------------------------------------------------------------------------------- 144 * Widget Callbacks */ 145 146 /** 147 The OpenGL drawing function. 148 This UI will draw a 3x3 grid, with on/off states according to plugin state. 149 */ 150 void onDisplay() override 151 { 152 const GraphicsContext& context(getGraphicsContext()); 153 154 const uint width = getWidth(); 155 const uint height = getHeight(); 156 const uint minwh = std::min(width, height); 157 const uint bgColor = getBackgroundColor(); 158 159 Rectangle<double> r; 160 161 // if host doesn't respect aspect-ratio but supports ui background, draw out-of-bounds color from it 162 if (width != height && bgColor != 0) 163 { 164 const int red = (bgColor >> 24) & 0xff; 165 const int green = (bgColor >> 16) & 0xff; 166 const int blue = (bgColor >> 8) & 0xff; 167 Color(red, green, blue).setFor(context); 168 169 if (width > height) 170 { 171 r.setPos(height, 0); 172 r.setSize(width-height, height); 173 } 174 else 175 { 176 r.setPos(0, width); 177 r.setSize(width, height-width); 178 } 179 180 r.draw(context); 181 } 182 183 r.setWidth(minwh/3 - 6); 184 r.setHeight(minwh/3 - 6); 185 186 // draw left, center and right columns 187 for (int i=0; i<3; ++i) 188 { 189 r.setX(3 + i*minwh/3); 190 191 // top 192 r.setY(3); 193 194 if (fParamGrid[0+i]) 195 Color(0.8f, 0.5f, 0.3f).setFor(context); 196 else 197 Color(0.3f, 0.5f, 0.8f).setFor(context); 198 199 r.draw(context); 200 201 // middle 202 r.setY(3 + minwh/3); 203 204 if (fParamGrid[3+i]) 205 Color(0.8f, 0.5f, 0.3f).setFor(context); 206 else 207 Color(0.3f, 0.5f, 0.8f).setFor(context); 208 209 r.draw(context); 210 211 // bottom 212 r.setY(3 + minwh*2/3); 213 214 if (fParamGrid[6+i]) 215 Color(0.8f, 0.5f, 0.3f).setFor(context); 216 else 217 Color(0.3f, 0.5f, 0.8f).setFor(context); 218 219 r.draw(context); 220 } 221 } 222 223 /** 224 Mouse press event. 225 This UI will de/activate blocks when you click them and report it as a state change to the plugin. 226 */ 227 bool onMouse(const MouseEvent& ev) override 228 { 229 // Test for left-clicked + pressed first. 230 if (ev.button != 1 || ! ev.press) 231 return false; 232 233 const uint width = getWidth(); 234 const uint height = getHeight(); 235 236 Rectangle<double> r; 237 238 r.setWidth(width/3 - 6); 239 r.setHeight(height/3 - 6); 240 241 // handle left, center and right columns 242 for (int i=0; i<3; ++i) 243 { 244 r.setX(3 + i*width/3); 245 246 // top 247 r.setY(3); 248 249 if (r.contains(ev.pos)) 250 { 251 // index that this block applies to 252 const uint32_t index = 0+i; 253 254 // invert block state 255 fParamGrid[index] = !fParamGrid[index]; 256 257 // report change to host (and thus plugin) 258 setState(getStateKeyFromIndex(index), fParamGrid[index] ? "true" : "false"); 259 260 // trigger repaint 261 repaint(); 262 break; 263 } 264 265 // middle 266 r.setY(3 + height/3); 267 268 if (r.contains(ev.pos)) 269 { 270 // same as before 271 const uint32_t index = 3+i; 272 fParamGrid[index] = !fParamGrid[index]; 273 setState(getStateKeyFromIndex(index), fParamGrid[index] ? "true" : "false"); 274 repaint(); 275 break; 276 } 277 278 // bottom 279 r.setY(3 + height*2/3); 280 281 if (r.contains(ev.pos)) 282 { 283 // same as before 284 const uint32_t index = 6+i; 285 fParamGrid[index] = !fParamGrid[index]; 286 setState(getStateKeyFromIndex(index), fParamGrid[index] ? "true" : "false"); 287 repaint(); 288 break; 289 } 290 } 291 292 return true; 293 } 294 295 // ------------------------------------------------------------------------------------------------------- 296 297 private: 298 /** 299 Our states used to display the grid. 300 The host does not know about these. 301 */ 302 bool fParamGrid[9]; 303 304 /** 305 Set our UI class as non-copyable and add a leak detector just in case. 306 */ 307 DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExampleUIParameters) 308 }; 309 310 /* ------------------------------------------------------------------------------------------------------------ 311 * UI entry point, called by DPF to create a new UI instance. */ 312 313 UI* createUI() 314 { 315 return new ExampleUIParameters(); 316 } 317 318 // ----------------------------------------------------------------------------------------------------------- 319 320 END_NAMESPACE_DISTRHO