1 /* B.Shapr
2 * Beat / envelope shaper LV2 plugin
3 *
4 * Copyright (C) 2019 by Sven Jähnichen
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #include "BShaprGUI.hpp"
22
BShaprGUI(const char * bundlePath,const LV2_Feature * const * features,PuglNativeView parentWindow)23 BShaprGUI::BShaprGUI (const char *bundlePath, const LV2_Feature *const *features, PuglNativeView parentWindow) :
24 Window (1200, 710, "B.Shapr", parentWindow, true, PUGL_MODULE, 0),
25 controller (NULL), write_function (NULL),
26 bpm (120), beatsPerBar (4.0), beatUnit (4),
27
28 mContainer (0, 0, 1200, 710, "widget"),
29 messageLabel (500, 45, 500, 20, "label", ""),
30 bypassButton (1090, 15, 16, 16, "redbutton"),
31 drywetDial (1144, 5, 33, 40, "dial", 1.0, 0.0, 1.0, 0.0, "%1.2f"),
32 midiTriggerSwitch (760, 568, 30, 12, "dial", 0),
33 midiPiano (760, 585, 150, 30, "widget", 0, 11),
34 midiThruSwitch (1044, 575, 12, 30, "dial", 0),
35 baseValueSelect (480, 660, 100, 20, "select", 1.0, 1.0, 16.0, 0.01),
36 baseListBox (620, 660, 100, 20, 0, -80, 100, 80, "menu", BItems::ItemList ({{0, "Seconds"}, {1, "Beats"}, {2, "Bars"}})),
37 monitorContainer (24, 134, 1152, 352, "monitor"),
38 monitorHorizon1 (0, 0, 0, 64, 352, "horizon"),
39 monitorHorizon2 (-1152, 0, 0, 64, 352, "horizon"),
40 input1Monitor (0, 0, 1152, 176, "monitor.in"),
41 output1Monitor (0, 0, 1152, 176, "monitor.out"),
42 input2Monitor (0, 176, 1152, 176, "monitor.in"),
43 output2Monitor (0, 176, 1152, 176, "monitor.out"),
44
45 shapeBuffer {0.0},
46 horizonPos (0), monitorScale (0.25), minorXSteps (1.0), majorXSteps (1.0),
47 clipboard (),
48 pluginPath (bundlePath ? std::string (bundlePath) : std::string ("")),
49 sz (1.0),
50 bgImageSurface (nullptr), forge (), urids (), map (NULL)
51
52 {
53 // Init shapes
54 for (int i = 0; i < MAXSHAPES; ++i)
55 {
56 shapeGui[i].tabContainer = BWidgets::Widget (20 + i * 148, 90, 147, 40, "tab");
57 shapeGui[i].tabIcon = BWidgets::ImageIcon (0, 12.5, 120, 15, "widget", pluginPath + "inc/Shape" + std::to_string (i + 1) + ".png");
58 for (int j = 0; j< NRSYMBOLS; ++j) shapeGui[i].tabSymbol[j] = SymbolWidget (120 + (j % 2) * 14 , 8 + int (j / 2) * 14, 10, 10, "symbol", SWSymbol(j));
59 shapeGui[i].shapeContainer = BWidgets::Widget (20, 130, 1160, 510, "widget");
60
61 // Method menu
62 BItems::ItemList il;
63 shapeGui[i].methodIcons = {};
64 for (int j = 0; j < MAXEFFECTS; ++j)
65 {
66 std::string iconPath = "";
67 int index = 0;
68 for (int k = 0; k < MAXEFFECTS; ++k)
69 {
70 if (j == methods[k].listIndex)
71 {
72 iconPath = pluginPath + methods[k].iconFileName;
73 index = k;
74 break;
75 }
76 }
77
78 shapeGui[i].methodIcons.push_back (BWidgets::ImageIcon (0, 0, 154, 54, "icon", std::vector<std::string>{iconPath, iconPath}));
79
80 BWidgets::ImageIcon* icon = &*std::prev (shapeGui[i].methodIcons.end ());
81 cairo_t* cr = cairo_create (icon->getIconSurface (BColors::NORMAL));
82 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
83 cairo_paint (cr);
84 cairo_destroy (cr);
85
86 il.push_back (BItems::Item (index, icon));
87 }
88
89 shapeGui[i].targetListBox = BWidgets::PopupListBox (20, 443, 174, 54, 0, -380, 154, 380, "menu2", il, 0);
90
91 shapeGui[i].shapeWidget = ShapeWidget (4, 4, 1152, 352, "shape");
92 shapeGui[i].tabMsgBox = nullptr;
93 shapeGui[i].tabMsgBoxBg = nullptr;
94 shapeGui[i].smoothingLabel = BWidgets::Label (960, 410, 40, 10, "ssmlabel", "Smooth");
95 shapeGui[i].smoothingDial = BWidgets::DialValue (960, 366, 40, 48, "dial", 20.0, 0.0, 100.0, 0, "%3.1f ms");
96 shapeGui[i].toolSelect = SelectWidget (133, 368, 284, 44, "tool", 44, 44, 5, 2,
97 {"Select", "Point node", "Auto Bezier node", "Symmetric Bezier node", "Asymmetric Bezier node"});
98 for (int j = 0; j < 4; ++j) shapeGui[i].editWidgets[j] = EditWidget (463 + j * 60, 368, 44, 44, "widget", editWidgetLabels[j]);
99 for (int j = 4; j < 7; ++j) shapeGui[i].editWidgets[j] = EditWidget (503 + j * 60, 368, 44, 44, "widget", editWidgetLabels[j]);
100 shapeGui[i].gridSelect = SelectWidget (1043, 368, 104, 44, "tool", 44, 44, 2, 2, {"Show grid", "Snap to grid"});
101 shapeGui[i].drywetLabel = BWidgets::Label (500, 494, 50, 16, "smlabel", "dry/wet");
102 shapeGui[i].drywetDial = BWidgets::DialValue (500, 434, 50, 60, "dial", 1.0, 0.0, 1.0, 0, "%1.2f");
103
104 for (int j = 0; j < MAXOPTIONS; ++j)
105 {
106 switch (options[j].widgetType)
107 {
108 case NO_WIDGET:
109 shapeGui[i].optionWidgets[j] = nullptr;
110 break;
111
112 case DIAL_WIDGET:
113 shapeGui[i].optionWidgets[j] = new BWidgets::DialValue
114 (
115 0, 0, 50, 60, "dial",
116 options[j].value, options[j].limit.min, options[j].limit.max, options[j].limit.step,
117 options[j].param.get<std::string>()
118 );
119 if (!shapeGui[i].optionWidgets[j]) throw std::bad_alloc();
120 shapeGui[i].optionWidgets[j]->setHardChangeable (false);
121 shapeGui[i].optionLabels[j] = BWidgets::Label (220 + j * 70, 494, 70, 16, "smlabel", options[j].name);
122 break;
123
124 case POPUP_WIDGET:
125 {
126 BItems::ItemList il = options[j].param.get<BItems::ItemList>();
127 size_t max = 0;
128 for (BItems::Item const& it : il)
129 {
130 if (it.getWidget())
131 {
132 BWidgets::Label* l = (BWidgets::Label*) it.getWidget();
133 if (l->getText().size() > max) max = l->getText().size();
134 }
135 }
136 int w = max * 9 + 20;
137 w = LIMIT (w, 50, 270 - j * 70);
138 int h = (il.size() + 1) * 20;
139 h = LIMIT (h, 20, 400);
140 shapeGui[i].optionWidgets[j] = new BWidgets::PopupListBox
141 (
142 0, 0, w, 20, 0, -h, w, h, "menu", il,
143 options[j].value
144 );
145 if (!shapeGui[i].optionWidgets[j]) throw std::bad_alloc();
146 shapeGui[i].optionLabels[j] = BWidgets::Label (220 + j * 70, 494, w, 16, "smlabel", options[j].name);
147 }
148 break;
149
150 default:
151 shapeGui[i].optionWidgets[j] = nullptr;
152 break;
153 }
154 }
155 }
156
157 // Init main monitor
158 initMonitors ();
159
160 // Link controller widgets
161 controllerWidgets.fill (nullptr);
162 controllerWidgets[BYPASS] = (BWidgets::ValueWidget*) &bypassButton;
163 controllerWidgets[DRY_WET] = (BWidgets::ValueWidget*) &drywetDial;
164 controllerWidgets[MIDI_CONTROL] = (BWidgets::ValueWidget*) &midiTriggerSwitch;
165 controllerWidgets[MIDI_THRU] = (BWidgets::ValueWidget*) &midiThruSwitch;
166 controllerWidgets[BASE] = (BWidgets::ValueWidget*) &baseListBox;
167 controllerWidgets[BASE_VALUE] = (BWidgets::ValueWidget*) &baseValueSelect;
168 for (int i = 0; i < MAXSHAPES; ++i)
169 {
170 controllerWidgets[SHAPERS + i * SH_SIZE + SH_TARGET] = (BWidgets::ValueWidget*) &shapeGui[i].targetListBox;
171 controllerWidgets[SHAPERS + i * SH_SIZE + SH_SMOOTHING] = (BWidgets::ValueWidget*) &shapeGui[i].smoothingDial;
172 controllerWidgets[SHAPERS + i * SH_SIZE + SH_DRY_WET] = (BWidgets::ValueWidget*) &shapeGui[i].drywetDial;
173
174 for (int j = 0 ; j < MAXOPTIONS; ++j)
175 {
176 controllerWidgets[SHAPERS + i * SH_SIZE + SH_OPTION + j] = (shapeGui[i].optionWidgets[j] ? shapeGui[i].optionWidgets[j] : nullptr);
177 }
178 }
179
180 // Init controllers
181 for (int i = 0; i < NR_CONTROLLERS; ++i) controllers[i] = (controllerWidgets[i] ? controllerWidgets[i]->getValue () : 0);
182
183 // Set callbacks
184 bypassButton.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
185 drywetDial.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
186 midiTriggerSwitch.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
187 midiPiano.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BShaprGUI::pianoCallback);
188 midiPiano.setCallbackFunction (BEvents::EventType::BUTTON_RELEASE_EVENT, BShaprGUI::pianoCallback);
189 midiPiano.setCallbackFunction (BEvents::EventType::POINTER_DRAG_EVENT, BShaprGUI::pianoCallback);
190 midiThruSwitch.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
191 baseValueSelect.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
192 baseListBox.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
193 monitorContainer.setCallbackFunction (BEvents::EventType::WHEEL_SCROLL_EVENT, BShaprGUI::wheelScrolledCallback);
194 for (int i = 0; i < MAXSHAPES; ++i)
195 {
196 shapeGui[i].tabContainer.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BShaprGUI::tabClickedCallback);
197 shapeGui[i].tabIcon.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BShaprGUI::tabClickedCallback);
198 for (int j = 0; j< NRSYMBOLS; ++j) shapeGui[i].tabSymbol[j].setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BShaprGUI::tabClickedCallback);
199 shapeGui[i].smoothingDial.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
200 shapeGui[i].targetListBox.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
201 shapeGui[i].drywetDial.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
202 shapeGui[i].shapeWidget.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::shapeChangedCallback);
203 shapeGui[i].toolSelect.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::toolChangedCallback);
204 for (int j = 0; j < 7; ++j) shapeGui[i].editWidgets[j].setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BShaprGUI::editClickedCallback);
205 for (int j = 0; j < 7; ++j) shapeGui[i].editWidgets[j].setCallbackFunction (BEvents::EventType::BUTTON_RELEASE_EVENT, BShaprGUI::editReleasedCallback);
206 shapeGui[i].gridSelect.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::gridChangedCallback);
207
208 for (int j = 0 ; j < MAXOPTIONS; ++j)
209 {
210 if (shapeGui[i].optionWidgets[j]) shapeGui[i].optionWidgets[j]->setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BShaprGUI::valueChangedCallback);
211 }
212
213 shapeGui[i].shapeWidget.setMergeable (BEvents::POINTER_DRAG_EVENT, false);
214 }
215
216 // Configure widgets
217 calculateXSteps ();
218 mContainer.loadImage (BColors::NORMAL, pluginPath + BG_FILE);
219 std::vector<bool> keys (12, true);
220 drywetDial.setHardChangeable (false);
221 midiPiano.setKeysToggleable (true);
222 midiPiano.pressKeys (keys);
223 midiPiano.hide();
224 monitorContainer.setScrollable (true);
225 input1Monitor.setScrollable (false);
226 output1Monitor.setScrollable (false);
227 input2Monitor.setScrollable (false);
228 output2Monitor.setScrollable (false);
229 shapeGui[0].tabContainer.rename ("activetab");
230 for (unsigned int i = 0; i < MAXSHAPES; ++i)
231 {
232 for (int j = 0; j< NRSYMBOLS; ++j)
233 {
234 if (j != CLOSESYMBOL) shapeGui[i].tabSymbol[j].hide ();
235 }
236 shapeGui[i].shapeWidget.setTool (ToolType::POINT_NODE_TOOL);
237 shapeGui[i].shapeWidget.setScaleParameters (methods[0].anchorYPos, methods[0].anchorValue, methods[0].ratio);
238 shapeGui[i].shapeWidget.setLowerLimit (methods[0].limit.min);
239 shapeGui[i].shapeWidget.setHigherLimit (methods[0].limit.max);
240 shapeGui[i].shapeWidget.setTransformation (methods[0].transformFactor, methods[0].transformOffset);
241 shapeGui[i].smoothingDial.setHardChangeable (false);
242 shapeGui[i].drywetDial.setHardChangeable (false);
243
244 for (int j = 0; j < MAXOPTIONS; ++j)
245 {
246 if (shapeGui[i].optionWidgets[j]) shapeGui[i].optionWidgets[j]->hide ();
247 shapeGui[i].optionLabels[j].hide ();
248 }
249
250 shapeGui[i].shapeContainer.setScrollable (false);
251 if (i >= 1) shapeGui[i].shapeContainer.hide ();
252 }
253 applyChildThemes ();
254 getKeyGrabStack()->add (this);
255
256 // Pack widgets
257 monitorContainer.add (input1Monitor);
258 monitorContainer.add (output1Monitor);
259 monitorContainer.add (input2Monitor);
260 monitorContainer.add (output2Monitor);
261 monitorContainer.add (monitorHorizon1);
262 monitorContainer.add (monitorHorizon2);
263 mContainer.add (monitorContainer);
264 for (unsigned int i = 0; i < MAXSHAPES; ++i)
265 {
266 shapeGui[i].tabContainer.add (shapeGui[i].tabIcon);
267 for (int j = 0; j< NRSYMBOLS; ++j) shapeGui[i].tabContainer.add (shapeGui[i].tabSymbol[j]);
268 mContainer.add (shapeGui[i].tabContainer);
269 shapeGui[i].shapeContainer.add (shapeGui[i].smoothingLabel);
270 shapeGui[i].shapeContainer.add (shapeGui[i].smoothingDial);
271 shapeGui[i].shapeContainer.add (shapeGui[i].drywetLabel);
272 shapeGui[i].shapeContainer.add (shapeGui[i].drywetDial);
273 shapeGui[i].shapeContainer.add (shapeGui[i].shapeWidget);
274 shapeGui[i].shapeContainer.add (shapeGui[i].toolSelect);
275 for (int j = 0; j < 7; ++j) shapeGui[i].shapeContainer.add (shapeGui[i].editWidgets[j]);
276 shapeGui[i].shapeContainer.add (shapeGui[i].gridSelect);
277 shapeGui[i].shapeContainer.add (shapeGui[i].targetListBox);
278
279 for (int j = 0; j < MAXOPTIONS; ++j)
280 {
281 if (shapeGui[i].optionWidgets[j]) shapeGui[i].shapeContainer.add (*shapeGui[i].optionWidgets[j]);
282 shapeGui[i].shapeContainer.add (shapeGui[i].optionLabels[j]);
283 }
284
285 mContainer.add (shapeGui[i].shapeContainer);
286 }
287 mContainer.add (bypassButton);
288 mContainer.add (drywetDial);
289 mContainer.add (midiTriggerSwitch);
290 mContainer.add (midiPiano);
291 mContainer.add (midiThruSwitch);
292 mContainer.add (messageLabel);
293 mContainer.add (baseValueSelect);
294 mContainer.add (baseListBox);
295 add (mContainer);
296
297 // Post addition configurations
298 for (int i = 0; i < MAXSHAPES; ++i)
299 {
300 shapeGui[i].shapeWidget.setDefaultShape();
301 shapeGui[i].shapeWidget.setValueEnabled (true);
302 }
303
304 //Scan host features for URID map
305 LV2_URID_Map* m = NULL;
306 for (int i = 0; features[i]; ++i)
307 {
308 if (strcmp(features[i]->URI, LV2_URID__map) == 0) m = (LV2_URID_Map*) features[i]->data;
309 }
310 if (!m) throw std::invalid_argument ("Host does not support urid:map");
311
312 //Map URIS
313 map = m;
314 mapURIDs (map, &urids);
315
316 // Initialize forge
317 lv2_atom_forge_init (&forge, map);
318 }
319
~BShaprGUI()320 BShaprGUI::~BShaprGUI()
321 {
322 for (int i = 0; i < MAXSHAPES; ++i)
323 {
324 for (int j = 0; j < MAXOPTIONS; ++j)
325 {
326 if (shapeGui[i].optionWidgets[j]) delete shapeGui[i].optionWidgets[j];
327 }
328
329 if (shapeGui[i].tabMsgBox) delete shapeGui[i].tabMsgBox;
330 if (shapeGui[i].tabMsgBoxBg) delete shapeGui[i].tabMsgBoxBg;
331 }
332 sendGuiOff ();
333 }
334
portEvent(uint32_t port,uint32_t bufferSize,uint32_t format,const void * buffer)335 void BShaprGUI::portEvent(uint32_t port, uint32_t bufferSize, uint32_t format, const void* buffer)
336 {
337 // Notify port
338 if ((format == urids.atom_eventTransfer) && (port == NOTIFY))
339 {
340 const LV2_Atom* atom = (const LV2_Atom*) buffer;
341 if ((atom->type == urids.atom_Blank) || (atom->type == urids.atom_Object))
342 {
343 const LV2_Atom_Object* obj = (const LV2_Atom_Object*) atom;
344
345 // Monitor notification
346 if (obj->body.otype == urids.notify_monitorEvent)
347 {
348 const LV2_Atom* data = NULL;
349 lv2_atom_object_get(obj, urids.notify_monitor, &data, 0);
350 if (data && (data->type == urids.atom_Vector))
351 {
352 const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) data;
353 if (vec->body.child_type == urids.atom_Float)
354 {
355 uint32_t notificationsCount = (uint32_t) ((data->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (BShaprNotifications));
356 BShaprNotifications* notifications = (BShaprNotifications*) (&vec->body + 1);
357 if (notificationsCount > 0)
358 {
359 std::pair<int, int> pos = translateNotification (notifications, notificationsCount);
360 int p1 = LIMIT (pos.first, 0, MONITORBUFFERSIZE - 1);
361 int p2 = LIMIT (pos.second, 0, MONITORBUFFERSIZE - 1);
362
363 if (p1 <= p2)
364 {
365 updateMonitors (p1, p2);
366 updateHorizon ();
367 }
368 else
369 {
370 updateMonitors (p1, MONITORBUFFERSIZE - 1);
371 updateMonitors (0, p2);
372 updateHorizon ();
373 }
374 }
375 }
376 }
377 else std::cerr << "BShapr.lv2#GUI: Corrupt audio message." << std::endl;
378 }
379
380 // Message notification
381 else if (obj->body.otype == urids.notify_messageEvent)
382 {
383 const LV2_Atom* data = NULL;
384 lv2_atom_object_get(obj, urids.notify_message, &data, 0);
385 if (data && (data->type == urids.atom_Int))
386 {
387 const int messageNr = ((LV2_Atom_Int*)data)->body;
388 std::string msg = ((messageNr >= NO_MSG) && (messageNr <= MAX_MSG) ? messageStrings[messageNr] : "");
389 messageLabel.setText (msg);
390 }
391 }
392
393 // Status notification
394 else if (obj->body.otype == urids.notify_statusEvent)
395 {
396 const LV2_Atom *oBpb = NULL, *oBu = NULL, *oBpm = NULL;
397 lv2_atom_object_get
398 (
399 obj,
400 urids.time_beatsPerBar, &oBpb,
401 urids.time_beatUnit, &oBu,
402 urids.time_beatsPerMinute, &oBpm,
403 0);
404 if (oBpb && (oBpb->type == urids.atom_Float))
405 {
406 float value = ((LV2_Atom_Float*)oBpb)->body;
407 if (value != 0.0f)
408 {
409 beatsPerBar = value;
410 calculateXSteps ();
411 updateHorizon ();
412 }
413 }
414
415 if (oBu && (oBu->type == urids.atom_Int))
416 {
417 float value = ((LV2_Atom_Float*)oBu)->body;
418 if (int (value) != 0)
419 {
420 beatUnit = value;
421 calculateXSteps ();
422 }
423 }
424
425 if (oBpm && (oBpm->type == urids.atom_Float))
426 {
427 float value = ((LV2_Atom_Float*)oBpm)->body;
428 if (value != 0.0f)
429 {
430 bpm = value;
431 updateHorizon ();
432 }
433 }
434 }
435
436 // Shape notification
437 else if (obj->body.otype == urids.notify_shapeEvent)
438 {
439 LV2_Atom *sNr = NULL, *sData = NULL;
440 lv2_atom_object_get (obj, urids.notify_shapeNr, &sNr,
441 urids.notify_shapeData, &sData, 0);
442
443 if (sNr && (sNr->type == urids.atom_Int) &&
444 sData && (sData->type == urids.atom_Vector))
445 {
446 int shapeNr = ((LV2_Atom_Int*)sNr)->body;
447
448 if ((shapeNr >= 0) && (shapeNr < MAXSHAPES))
449 {
450 const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) sData;
451 size_t vecSize = (sData->size - sizeof(LV2_Atom_Vector_Body)) / (7 * sizeof (float));
452 if (vec->body.child_type == urids.atom_Float)
453 {
454 shapeGui[shapeNr].shapeWidget.setValueEnabled (false);
455 shapeGui[shapeNr].shapeWidget.clearShape ();
456 float* data = (float*)(&vec->body + 1);
457 for (unsigned int nodeNr = 0; (nodeNr < vecSize) && (nodeNr < MAXNODES); ++nodeNr)
458 {
459 Node node (&data[nodeNr * 7]);
460 shapeGui[shapeNr].shapeWidget.appendRawNode (node);
461 }
462 shapeGui[shapeNr].shapeWidget.validateShape();
463 shapeGui[shapeNr].shapeWidget.pushToSnapshots ();
464 shapeGui[shapeNr].shapeWidget.update ();
465 shapeGui[shapeNr].shapeWidget.setValueEnabled (true);
466 }
467 }
468 }
469 }
470 }
471 }
472
473
474 // Scan controller ports
475 else if ((format == 0) && (port >= CONTROLLERS) && (port < CONTROLLERS + NR_CONTROLLERS))
476 {
477 // Calulate controller nr and validate controller value
478 int controllerNr = port - CONTROLLERS;
479 float* pval = (float*) buffer;
480
481 if (controllerNr < SHAPERS)
482 {
483 float oldValue = controllers[controllerNr];
484 float value = globalControllerLimits[controllerNr].validate (*pval);
485 controllers[controllerNr] = value;
486
487 // Active shape
488 if (controllerNr == ACTIVE_SHAPE)
489 {
490 int sh = LIMIT (oldValue, 1, MAXSHAPES) - 1;
491 shapeGui[sh].tabContainer.rename ("tab");
492 shapeGui[sh].tabContainer.applyTheme (theme);
493 shapeGui[sh].shapeContainer.hide();
494 int nsh = value - 1;
495 shapeGui[nsh].tabContainer.rename ("activetab");
496 shapeGui[nsh].tabContainer.applyTheme (theme);
497 shapeGui[nsh].shapeContainer.show();
498 updateHorizon ();
499 }
500
501 // Keys
502 else if (controllerNr == MIDI_KEYS)
503 {
504 uint32_t bits = value;
505 std::vector<bool> keys (12, false);
506 for (int i = 0; i < 12; ++i)
507 {
508 if (bits & (1 << i)) keys[i] = true;
509 }
510 midiPiano.pressKeys (keys);
511 }
512
513 // MIDI connected ?
514 // Show or hide piano
515 else if (controllerNr == MIDI_CONTROL)
516 {
517 if (controllerWidgets[MIDI_CONTROL]) controllerWidgets[MIDI_CONTROL]->setValue (value);
518
519 if (value == 1.0f) midiPiano.show ();
520 else midiPiano.hide ();
521 }
522
523 // Base, base value
524 // Update recalculate shaper grid steps
525 else if ((controllerNr == BASE) || (controllerNr == BASE_VALUE))
526 {
527 if (controllerWidgets[controllerNr]) controllerWidgets[controllerNr]->setValue (value);
528 }
529 }
530
531 // Shapers
532 else if ((controllerNr >= SHAPERS) && (controllerNr < SHAPERS + SH_SIZE * MAXSHAPES))
533 {
534 int shapeNr = (port - CONTROLLERS - SHAPERS) / SH_SIZE;
535 int shapeWidgetNr = port - CONTROLLERS - SHAPERS - shapeNr * SH_SIZE;
536 float value = shapeControllerLimits[shapeWidgetNr].validate (*pval);
537 controllers[controllerNr] = value;
538 if (controllerWidgets[controllerNr]) controllerWidgets[controllerNr]->setValue (value);
539
540 // SH_OUTPUT
541 if (shapeWidgetNr == SH_OUTPUT) updateTabs ();
542 }
543 }
544 }
545
updateTabs()546 void BShaprGUI::updateTabs ()
547 {
548 int lastShape = 0;
549 for (int i = 0; i < MAXSHAPES; ++i)
550 {
551 if (controllers[SHAPERS + i * SH_SIZE + SH_OUTPUT] == AUDIO_OUT) lastShape = i;
552 }
553
554 // Show or hide tabs
555 for (int i = 0; i < MAXSHAPES; ++i)
556 {
557 if (i <= lastShape) shapeGui[i].tabContainer.show ();
558 else shapeGui[i].tabContainer.hide ();
559 }
560
561 // Show or hide tabSymbols
562 for (int i = 0; i < MAXSHAPES; ++i)
563 {
564 if (lastShape + 1 < MAXSHAPES) shapeGui[i].tabSymbol[ADDSYMBOL].show ();
565 else shapeGui[i].tabSymbol[ADDSYMBOL].hide ();
566
567 if ((i > 0) && (i <= lastShape)) shapeGui[i].tabSymbol[LEFTSYMBOL].show ();
568 else shapeGui[i].tabSymbol[LEFTSYMBOL].hide ();
569
570 if (i < lastShape) shapeGui[i].tabSymbol[RIGHTSYMBOL].show ();
571 else shapeGui[i].tabSymbol[RIGHTSYMBOL].hide ();
572 }
573 }
574
resizeGUI(const double sz)575 void BShaprGUI::resizeGUI(const double sz)
576 {
577 hide ();
578
579 // Resize Fonts
580 defaultFont.setFontSize (12.0 * sz);
581 smFont.setFontSize (10.0 * sz);
582 ssmFont.setFontSize (8.0 * sz);
583 lfLabelFont.setFontSize (12.0 * sz);
584
585 // Resize widgets
586 RESIZE (mContainer, 0, 0, 1200, 710, sz);
587 RESIZE (messageLabel, 500, 45, 500, 20, sz);
588 RESIZE (bypassButton, 1090, 15, 16, 16, sz);
589 RESIZE (drywetDial, 1144, 5, 33, 40, sz);
590 RESIZE (midiTriggerSwitch, 760, 568, 30, 12, sz);
591 RESIZE (midiPiano, 760, 585, 150, 30, sz);
592 RESIZE (midiThruSwitch, 1044, 575, 12, 30, sz);
593 RESIZE (baseValueSelect, 480, 660, 100, 20, sz);
594 RESIZE (baseListBox, 620, 660, 100, 20, sz);
595 baseListBox.resizeListBox (BUtilities::Point (100 * sz, 80 * sz));
596 baseListBox.moveListBox (BUtilities::Point (0, -80 * sz));
597 RESIZE (monitorContainer, 24, 134, 1152, 352, sz);
598
599 // monitorHorizon1/2
600 monitorHorizon1.setFadeoutWidth (64 * sz);
601 monitorHorizon2.setFadeoutWidth (64 * sz);
602 monitorHorizon1.setHeight (352 * sz);
603 monitorHorizon2.setHeight (352 * sz);
604
605 RESIZE (input1Monitor, 0, 0, 1152, 176, sz);
606 RESIZE (output1Monitor, 0, 0, 1152, 176, sz);
607 RESIZE (input2Monitor, 0, 176, 1152, 176, sz);
608 RESIZE (output2Monitor, 0, 176, 1152, 176, sz);
609 for (int i = 0; i < MAXSHAPES; ++i)
610 {
611 RESIZE (shapeGui[i].tabContainer, 20 + i * 148, 90, 147, 40, sz);
612 RESIZE (shapeGui[i].tabIcon, 0, 12.5, 120, 15, sz);
613 for (int j = 0; j< NRSYMBOLS; ++j) RESIZE (shapeGui[i].tabSymbol[j], 120 + (j % 2) * 14 , 8 + int (j / 2) * 14, 10, 10, sz);
614 if (shapeGui[i].tabMsgBox)
615 {
616 RESIZE
617 (
618 *shapeGui[i].tabMsgBox,
619 shapeGui[i].tabMsgBox->getPosition().x / this->sz,
620 shapeGui[i].tabMsgBox->getPosition().y / this->sz,
621 shapeGui[i].tabMsgBox->getWidth () / this->sz,
622 shapeGui[i].tabMsgBox->getHeight () / this->sz,
623 sz
624 );
625 }
626 if (shapeGui[i].tabMsgBoxBg) RESIZE (*shapeGui[i].tabMsgBoxBg, 0, 0, 1200, 710, sz);
627 RESIZE (shapeGui[i].shapeContainer, 20, 130, 1160, 590, sz);
628 RESIZE (shapeGui[i].smoothingLabel, 960, 410, 40, 10, sz);
629 RESIZE (shapeGui[i].smoothingDial, 960, 366, 40, 48, sz);
630 RESIZE (shapeGui[i].targetListBox, 20, 443, 174, 54, sz);
631 shapeGui[i].targetListBox.resizeListBox (BUtilities::Point (174 * sz - 20, 380 * sz));
632 shapeGui[i].targetListBox.moveListBox (BUtilities::Point (0, -380 * sz));
633 shapeGui[i].targetListBox.resizeListBoxItems (BUtilities::Point (174 * sz - 20, 54 * sz));
634 RESIZE (shapeGui[i].drywetLabel, 500, 494, 50, 16, sz);
635 RESIZE (shapeGui[i].drywetDial, 500, 434, 50, 60, sz);
636 RESIZE (shapeGui[i].shapeWidget, 4, 4, 1152, 352, sz);
637 RESIZE (shapeGui[i].toolSelect, 133, 368, 284, 44, sz);
638 shapeGui[i].toolSelect.resizeSelection (44 * sz, 44 * sz);
639 for (int j = 0; j < 4; ++j) RESIZE (shapeGui[i].editWidgets[j], 463 + j * 60, 368, 44, 44, sz);
640 for (int j = 4; j < 7; ++j) RESIZE (shapeGui[i].editWidgets[j], 503 + j * 60, 368, 44, 44, sz);
641 RESIZE (shapeGui[i].gridSelect, 1043, 368, 104, 44, sz);
642 shapeGui[i].gridSelect.resizeSelection (44 * sz, 44 * sz);
643
644 int methodNr = shapeGui[i].targetListBox.getValue ();
645
646 for (int j = 0; j < MAXOPTIONWIDGETS; ++j)
647 {
648 int optionNr = methods[methodNr].optionIndexes[j];
649 if (optionNr != NO_OPT)
650 {
651 if (shapeGui[i].optionWidgets[optionNr])
652 {
653 switch (options[optionNr].widgetType)
654 {
655 case DIAL_WIDGET:
656 RESIZE ((*shapeGui[i].optionWidgets[optionNr]), 230 + j * 70, 434, 50, 60, sz);
657 RESIZE ((shapeGui[i].optionLabels[optionNr]), 220 + j * 70, 494, 70, 16, sz);
658 break;
659
660 case POPUP_WIDGET:
661 {
662 BItems::ItemList il = options[optionNr].param.get<BItems::ItemList>();
663 size_t max = 0;
664 for (BItems::Item const& it : il)
665 {
666 if (it.getWidget())
667 {
668 BWidgets::Label* l = (BWidgets::Label*) it.getWidget();
669 if (l->getText().size() > max) max = l->getText().size();
670 }
671 }
672 int w = max * 9 + 20;
673 w = LIMIT (w, 50, 270 - j * 70);
674 int h = (il.size() + 1) * 20;
675 h = LIMIT (h, 20, 400);
676
677 RESIZE ((*shapeGui[i].optionWidgets[optionNr]), 220 + j * 70, 455, w, 20, sz);
678 ((BWidgets::PopupListBox*) shapeGui[i].optionWidgets[optionNr])->resizeListBox (BUtilities::Point (w * sz, h * sz));
679 ((BWidgets::PopupListBox*) shapeGui[i].optionWidgets[optionNr])->moveListBox (BUtilities::Point (0, -h * sz));
680
681 RESIZE ((shapeGui[i].optionLabels[optionNr]), 220 + j * 70, 494, w, 16, sz);
682 }
683 break;
684
685 default:
686 break;
687 }
688 }
689 }
690 }
691 }
692
693 this-> sz = sz;
694
695 // Update monitor, const std::string& name
696 initMonitors ();
697 updateMonitors (0, MONITORBUFFERSIZE - 1);
698 updateHorizon ();
699
700 // Apply changes
701 applyChildThemes ();
702 show ();
703 }
704
applyChildThemes()705 void BShaprGUI::applyChildThemes ()
706 {
707 mContainer.applyTheme (theme);
708 messageLabel.applyTheme (theme);
709 bypassButton.applyTheme (theme);
710 drywetDial.applyTheme (theme);
711 midiTriggerSwitch.applyTheme (theme);
712 midiPiano.applyTheme (theme);
713 midiThruSwitch.applyTheme (theme);
714 baseValueSelect.applyTheme (theme);
715 baseListBox.applyTheme (theme);
716 monitorContainer.applyTheme (theme);
717 input1Monitor.applyTheme (theme);
718 output1Monitor.applyTheme (theme);
719 input2Monitor.applyTheme (theme);
720 output2Monitor.applyTheme (theme);
721 for (unsigned int i = 0; i < MAXSHAPES; ++i)
722 {
723 shapeGui[i].shapeContainer.applyTheme (theme);
724 shapeGui[i].tabContainer.applyTheme (theme);
725 shapeGui[i].tabIcon.applyTheme (theme);
726 for (int j = 0; j< NRSYMBOLS; ++j) shapeGui[i].tabSymbol[j].applyTheme (theme);
727 if (shapeGui[i].tabMsgBox) shapeGui[i].tabMsgBox->applyTheme (theme);
728 if (shapeGui[i].tabMsgBoxBg) shapeGui[i].tabMsgBoxBg->applyTheme (theme);
729 shapeGui[i].smoothingLabel.applyTheme (theme);
730 shapeGui[i].smoothingDial.applyTheme (theme);
731 shapeGui[i].targetListBox.applyTheme (theme);
732 shapeGui[i].drywetLabel.applyTheme (theme);
733 shapeGui[i].drywetDial.applyTheme (theme);
734 shapeGui[i].shapeWidget.applyTheme (theme);
735 shapeGui[i].toolSelect.applyTheme (theme);
736 for (int j = 0; j < 7; ++j) shapeGui[i].editWidgets[j].applyTheme (theme);
737 shapeGui[i].gridSelect.applyTheme (theme);
738
739 int methodNr = shapeGui[i].targetListBox.getValue ();
740 for (int j = 0; j < MAXOPTIONWIDGETS; ++j)
741 {
742 int optionNr = methods[methodNr].optionIndexes[j];
743 if (optionNr != NO_OPT)
744 {
745 if (shapeGui[i].optionWidgets[optionNr]) shapeGui[i].optionWidgets[optionNr]->applyTheme (theme);
746 shapeGui[i].optionLabels[optionNr].applyTheme (theme);
747 }
748 }
749 }
750 }
751
onConfigureRequest(BEvents::ExposeEvent * event)752 void BShaprGUI::onConfigureRequest (BEvents::ExposeEvent* event)
753 {
754 Window::onConfigureRequest (event);
755
756 resizeGUI (getWidth() / 1200 > getHeight() / 710 ? getHeight() / 710 : getWidth() / 1200);
757 }
758
onCloseRequest(BEvents::WidgetEvent * event)759 void BShaprGUI::onCloseRequest (BEvents::WidgetEvent* event)
760 {
761 if (event)
762 {
763 Widget* requestWidget = event->getRequestWidget ();
764 if (requestWidget)
765 {
766 for (int i = 0; i < MAXSHAPES; ++i)
767 {
768 if (requestWidget == ((BWidgets::Widget*)shapeGui[i].tabMsgBox))
769 {
770 double value = shapeGui[i].tabMsgBox->getValue ();
771
772 // Yes
773 if (value == 2) deleteShape (i);
774
775 delete shapeGui[i].tabMsgBox;
776 shapeGui[i].tabMsgBox = nullptr;
777 delete shapeGui[i].tabMsgBoxBg;
778 shapeGui[i].tabMsgBoxBg = nullptr;
779
780 return;
781 }
782 }
783
784 Window::onCloseRequest (event);
785 }
786 }
787 }
788
onKeyPressed(BEvents::KeyEvent * event)789 void BShaprGUI::onKeyPressed (BEvents::KeyEvent* event)
790 {
791 if ((event) && (event->getKey() == BDevices::KEY_SHIFT))
792 {
793 for (int i = 0; i < MAXSHAPES; ++i)
794 {
795 shapeGui[i].shapeWidget.setScrollable (false);
796 }
797 }
798 }
799
onKeyReleased(BEvents::KeyEvent * event)800 void BShaprGUI::onKeyReleased (BEvents::KeyEvent* event)
801 {
802 if ((event) && (event->getKey() == BDevices::KEY_SHIFT))
803 {
804 for (int i = 0; i < MAXSHAPES; ++i)
805 {
806 shapeGui[i].shapeWidget.setScrollable (true);
807 }
808 }
809 }
810
sendGuiOn()811 void BShaprGUI::sendGuiOn ()
812 {
813 uint8_t obj_buf[64];
814 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
815
816 LV2_Atom_Forge_Frame frame;
817 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, urids.ui_on);
818 lv2_atom_forge_pop(&forge, &frame);
819 write_function(controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
820 }
821
sendGuiOff()822 void BShaprGUI::sendGuiOff ()
823 {
824 uint8_t obj_buf[64];
825 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
826
827 LV2_Atom_Forge_Frame frame;
828 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, urids.ui_off);
829 lv2_atom_forge_pop(&forge, &frame);
830 write_function(controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
831 }
832
sendShape(size_t shapeNr)833 void BShaprGUI::sendShape (size_t shapeNr)
834 {
835 size_t size = shapeGui[shapeNr].shapeWidget.size ();
836
837 uint8_t obj_buf[4096];
838 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
839
840 // Load shapeBuffer
841 for (unsigned int i = 0; i < size; ++i)
842 {
843 Node node = shapeGui[shapeNr].shapeWidget.getRawNode (i);
844 shapeBuffer[i * 7 + 0] = (float)node.nodeType;
845 shapeBuffer[i * 7 + 1] = (float)node.point.x;
846 shapeBuffer[i * 7 + 2] = (float)node.point.y;
847 shapeBuffer[i * 7 + 3] = (float)node.handle1.x;
848 shapeBuffer[i * 7 + 4] = (float)node.handle1.y;
849 shapeBuffer[i * 7 + 5] = (float)node.handle2.x;
850 shapeBuffer[i * 7 + 6] = (float)node.handle2.y;
851 }
852
853 // Notify shapeBuffer
854 LV2_Atom_Forge_Frame frame;
855 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object (&forge, &frame, 0, urids.notify_shapeEvent);
856 lv2_atom_forge_key(&forge, urids.notify_shapeNr);
857 lv2_atom_forge_int(&forge, shapeNr);
858 lv2_atom_forge_key(&forge, urids.notify_shapeData);
859 lv2_atom_forge_vector(&forge, sizeof(float), urids.atom_Float, (uint32_t) (7 * size), &shapeBuffer);
860 lv2_atom_forge_pop(&forge, &frame);
861 write_function (controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
862 }
863
864
865
setController(const int controllerNr,const float value)866 void BShaprGUI::setController (const int controllerNr, const float value)
867 {
868 if ((controllerNr < 0) || (controllerNr >= NR_CONTROLLERS)) return;
869
870 if (controllerWidgets[controllerNr]) controllerWidgets[controllerNr]->setValue (value);
871 else
872 {
873 controllers[controllerNr] = value;
874 write_function(controller, CONTROLLERS + controllerNr, sizeof(float), 0, &controllers[controllerNr]);
875 }
876 }
877
deleteShape(const int shapeNr)878 void BShaprGUI::deleteShape (const int shapeNr)
879 {
880 if ((shapeNr < 0) || (shapeNr >= MAXSHAPES)) return;
881
882 // Scan SH_OUTPUT for the last shaper sending data to audio out
883 // Limited backward compatibilty to v0.3.2 or older
884 int lastShape = 0;
885 for (int i = 0; i < MAXSHAPES; ++i)
886 {
887 if (controllers[SHAPERS + i * SH_SIZE + SH_OUTPUT] == AUDIO_OUT) lastShape = i;
888 }
889
890 // Deletion behind last shape (shouldn't happen)
891 if (shapeNr > lastShape)
892 {
893 // Hide all tabContainers > lastShape
894 for (int i = 0; i < MAXSHAPES; ++i)
895 {
896 if (i <= lastShape) shapeGui[i].tabContainer.show ();
897 else shapeGui[i].tabContainer.hide ();
898 }
899
900 // Jump to last valid shape
901 if (controllers[ACTIVE_SHAPE] - 1 > lastShape) switchShape (lastShape);
902
903 // Get sure that SH_INPUT of shape 0 == AUDIO_IN
904 if (controllers[SHAPERS + SH_INPUT] != AUDIO_IN) setController (SHAPERS + SH_INPUT, AUDIO_IN);
905 }
906
907 // Deletion of last shape
908 else if (shapeNr == lastShape)
909 {
910 // shapeNr == 0: Reset shape
911 if (shapeNr == 0)
912 {
913 // Reset shape 0 controllers
914 setController (SHAPERS + SH_INPUT, AUDIO_IN);
915 setController (SHAPERS + SH_INPUT_AMP, 1.0f);
916 shapeGui[0].targetListBox.setValue (0.0);
917 shapeGui[0].drywetDial.setValue (1.0);
918 setController (SHAPERS + SH_OUTPUT, AUDIO_OUT);
919 setController (SHAPERS + SH_OUTPUT_AMP, 1.0f);
920
921 for (int j = 0; j < MAXOPTIONS; ++j)
922 {
923 if (shapeGui[0].optionWidgets[j]) shapeGui[0].optionWidgets[j]->setValue (options[j].value);
924 }
925
926 // Reset shape 0
927 shapeGui[0].shapeWidget.setDefaultShape ();
928
929 // Hide all tabContainers >= 1
930 for (int i = 0; i < MAXSHAPES; ++i)
931 {
932 if (i == 0) shapeGui[i].tabContainer.show ();
933 else shapeGui[i].tabContainer.hide ();
934 }
935
936 // Jump to shape 0
937 switchShape (0);
938 }
939
940 // Otherwise: delete shapeNr
941 else
942 {
943 // Link shapeNr - 1 to audio out; unlink shapeNr
944 setController (SHAPERS + (shapeNr - 1) * SH_SIZE + SH_OUTPUT, AUDIO_OUT);
945 setController (SHAPERS + shapeNr * SH_SIZE + SH_OUTPUT, INTERNAL);
946
947 // Hide all tabContainers >= shapeNr
948 for (int i = 0; i < MAXSHAPES; ++i)
949 {
950 if (i < shapeNr) shapeGui[i].tabContainer.show ();
951 else shapeGui[i].tabContainer.hide ();
952 }
953
954 // Jump to last valid shape
955 if (controllers[ACTIVE_SHAPE] - 1 > shapeNr - 1) switchShape (shapeNr - 1);
956
957 // Get sure that SH_INPUT of shape 0 == AUDIO_IN
958 if (controllers[SHAPERS + SH_INPUT] != AUDIO_IN) setController (SHAPERS + SH_INPUT, AUDIO_IN);
959 }
960 }
961
962 // Deletion of start or middle shape
963 else
964 {
965 // Shift shapers
966 for (int i = shapeNr; i < lastShape; ++i)
967 {
968 // Copy controllers
969 int destNr = SHAPERS + i * SH_SIZE;
970 int srcNr = SHAPERS + (i + 1) * SH_SIZE;
971
972 if (i == 0) setController (destNr + SH_INPUT, AUDIO_IN);
973 else setController (destNr + SH_INPUT, OUTPUT + i - 1);
974
975 setController (destNr + SH_INPUT_AMP, controllers[srcNr + SH_INPUT_AMP]);
976 shapeGui[i].targetListBox.setValue (shapeGui[i + 1].targetListBox.getValue ());
977 shapeGui[i].drywetDial.setValue (shapeGui[i + 1].drywetDial.getValue ());
978
979 if (i == lastShape - 1) setController (destNr + SH_OUTPUT, AUDIO_OUT);
980 else setController (destNr + SH_OUTPUT, controllers[srcNr + SH_OUTPUT]);
981
982 setController (destNr + SH_OUTPUT_AMP, controllers[srcNr + SH_OUTPUT_AMP]);
983
984 for (int j = 0; j < MAXOPTIONS; ++j)
985 {
986 if (shapeGui[i].optionWidgets[j] && shapeGui[i + 1].optionWidgets[j])
987 {
988 shapeGui[i].optionWidgets[j]->setValue (shapeGui[i + 1].optionWidgets[j]->getValue ());
989 }
990 }
991
992 // Copy shapes
993 shapeGui[i].shapeWidget = shapeGui [i + 1].shapeWidget;
994 }
995
996 // Unlink lastShape
997 setController (SHAPERS + lastShape * SH_SIZE + SH_OUTPUT, INTERNAL);
998
999 // Hide all tabContainers >= lastShape
1000 for (int i = 0; i < MAXSHAPES; ++i)
1001 {
1002 if (i < lastShape) shapeGui[i].tabContainer.show ();
1003 else shapeGui[i].tabContainer.hide ();
1004 }
1005
1006 // Jump to last valid shape
1007 if (controllers[ACTIVE_SHAPE] - 1 > lastShape - 1) switchShape (lastShape - 1);
1008
1009 // Get sure that SH_INPUT of shape 0 == AUDIO_IN
1010 if (controllers[SHAPERS + SH_INPUT] != AUDIO_IN) setController (SHAPERS + SH_INPUT, AUDIO_IN);
1011 }
1012
1013 updateTabs ();
1014 }
1015
insertShape(const int shapeNr)1016 void BShaprGUI::insertShape (const int shapeNr)
1017 {
1018 if ((shapeNr < 0) || (shapeNr >= MAXSHAPES - 1)) return;
1019
1020 // Scan SH_OUTPUT for the last shaper sending data to audio out
1021 // Limited backward compatibilty to v0.3.2 or older
1022 int lastShape = 0;
1023 for (int i = 0; i < MAXSHAPES; ++i)
1024 {
1025 if (controllers[SHAPERS + i * SH_SIZE + SH_OUTPUT] == AUDIO_OUT) lastShape = i;
1026 }
1027
1028 if (lastShape >= MAXSHAPES - 1) return;
1029
1030 // Insertion just behind last shape
1031 if (shapeNr >= lastShape)
1032 {
1033 // Init shape lastShape + 1
1034 int destNr = SHAPERS + (lastShape + 1) * SH_SIZE;
1035 int srcNr = SHAPERS + lastShape * SH_SIZE;
1036
1037 setController (destNr + SH_INPUT, OUTPUT + lastShape);
1038 setController (destNr + SH_INPUT_AMP, 1.0f);
1039 shapeGui[lastShape + 1].targetListBox.setValue (0.0);
1040 shapeGui[lastShape + 1].drywetDial.setValue (1.0);
1041 setController (destNr + SH_OUTPUT, AUDIO_OUT);
1042 setController (destNr + SH_OUTPUT_AMP, 1.0f);
1043
1044 for (int j = 0; j < MAXOPTIONS; ++j)
1045 {
1046 if (shapeGui[lastShape + 1].optionWidgets[j]) shapeGui[lastShape + 1].optionWidgets[j]->setValue (options[j].value);
1047 }
1048
1049 // Reset shape
1050 shapeGui[lastShape + 1].shapeWidget.setDefaultShape ();
1051
1052 // Link lastShape
1053 setController (srcNr + SH_OUTPUT, INTERNAL);
1054
1055 // Show lastShape + 1
1056 for (int i = 0; i < MAXSHAPES; ++i)
1057 {
1058 if (i <= lastShape + 1) shapeGui[i].tabContainer.show ();
1059 else shapeGui[i].tabContainer.hide ();
1060 }
1061
1062 switchShape (lastShape + 1);
1063 }
1064
1065 // Insertion in the middlde
1066 else
1067 {
1068 // Shift shapers
1069 for (int i = lastShape; i > shapeNr; --i)
1070 {
1071 int destNr = SHAPERS + (i + 1) * SH_SIZE;
1072 int srcNr = SHAPERS + i * SH_SIZE;
1073
1074 setController (destNr + SH_INPUT, OUTPUT + i);
1075 setController (destNr + SH_INPUT_AMP, controllers[srcNr + SH_INPUT_AMP]);
1076 shapeGui[i + 1].targetListBox.setValue (shapeGui[i].targetListBox.getValue ());
1077 shapeGui[i + 1].drywetDial.setValue (shapeGui[i].drywetDial.getValue ());
1078 setController (destNr + SH_OUTPUT, controllers[srcNr + SH_OUTPUT]);
1079 setController (destNr + SH_OUTPUT_AMP, controllers[srcNr + SH_OUTPUT_AMP]);
1080
1081 for (int j = 0; j < MAXOPTIONS; ++j)
1082 {
1083 if (shapeGui[i].optionWidgets[j] && shapeGui[i + 1].optionWidgets[j])
1084 {
1085 shapeGui[i + 1].optionWidgets[j]->setValue (shapeGui[i].optionWidgets[j]->getValue ());
1086 }
1087 }
1088
1089 // Copy shapes
1090 shapeGui[i + 1].shapeWidget = shapeGui[i].shapeWidget;
1091 }
1092
1093 // Init shape widgets shapeNr + 1
1094 int destNr = SHAPERS + (shapeNr + 1) * SH_SIZE;
1095 setController (destNr + SH_INPUT, OUTPUT + shapeNr);
1096 setController (destNr + SH_INPUT_AMP, 1.0f);
1097 shapeGui[shapeNr + 1].targetListBox.setValue (0.0f);
1098 shapeGui[shapeNr + 1].drywetDial.setValue (1.0f);
1099 setController (destNr + SH_OUTPUT, INTERNAL);
1100 setController (destNr + SH_OUTPUT_AMP, 1.0f);
1101
1102 // Reset shape shapeNr + 1
1103 shapeGui[shapeNr + 1].shapeWidget.setDefaultShape ();
1104
1105 // Show lastShape + 1
1106 for (int i = 0; i < MAXSHAPES; ++i)
1107 {
1108 if (i <= lastShape + 1) shapeGui[i].tabContainer.show ();
1109 else shapeGui[i].tabContainer.hide ();
1110 }
1111
1112 switchShape (shapeNr + 1);
1113 }
1114
1115 updateTabs ();
1116 }
1117
swapShapes(const int source,const int dest)1118 void BShaprGUI::swapShapes (const int source, const int dest)
1119 {
1120 if ((source < 0) || (dest < 0)) return;
1121
1122 // Scan SH_OUTPUT for the last shaper sending data to audio out
1123 // Limited backward compatibilty to v0.3.2 or older
1124 int lastShape = 0;
1125 for (int i = 0; i < MAXSHAPES; ++i)
1126 {
1127 if (controllers[SHAPERS + i * SH_SIZE + SH_OUTPUT] == AUDIO_OUT) lastShape = i;
1128 }
1129
1130 if ((source > lastShape) || (dest > lastShape)) return;
1131
1132 float value;
1133 int destNr = SHAPERS + dest * SH_SIZE;
1134 int srcNr = SHAPERS + source * SH_SIZE;
1135
1136 value = controllers[destNr + SH_TARGET];
1137 shapeGui[dest].targetListBox.setValue (controllers[srcNr + SH_TARGET]);
1138 shapeGui[source].targetListBox.setValue (value);
1139
1140 value = controllers[dest + SH_DRY_WET];
1141 shapeGui[dest].drywetDial.setValue (controllers[srcNr + SH_DRY_WET]);
1142 shapeGui[source].drywetDial.setValue (value);
1143
1144 for (int j = 0; j < MAXOPTIONS; ++j)
1145 {
1146 if (shapeGui[source].optionWidgets[j] && shapeGui[dest].optionWidgets[j])
1147 {
1148 value = shapeGui[dest].optionWidgets[j]->getValue ();
1149 shapeGui[dest].optionWidgets[j]->setValue (shapeGui[source].optionWidgets[j]->getValue ());
1150 shapeGui[source].optionWidgets[j]->setValue (value);
1151 }
1152 }
1153
1154 // Swap shapes
1155 ShapeWidget shBuffer;
1156 shBuffer = shapeGui[dest].shapeWidget;
1157 shapeGui[dest].shapeWidget = shapeGui[source].shapeWidget;
1158 shapeGui[source].shapeWidget = shBuffer;
1159
1160 if (controllers[ACTIVE_SHAPE] - 1 == source) switchShape (dest);
1161 else if (controllers[ACTIVE_SHAPE] - 1 == dest) switchShape (source);
1162 updateTabs ();
1163 }
1164
switchShape(const int shapeNr)1165 void BShaprGUI::switchShape (const int shapeNr)
1166 {
1167 if ((shapeNr < 0) || (shapeNr >= MAXSHAPES) || shapeNr == controllers[ACTIVE_SHAPE] - 1) return;
1168
1169 int oldShapeNr = LIMIT (controllers[ACTIVE_SHAPE], 1, MAXSHAPES) - 1;
1170 shapeGui[oldShapeNr].tabContainer.rename ("tab");
1171 shapeGui[oldShapeNr].tabContainer.applyTheme (theme);
1172 shapeGui[oldShapeNr].shapeContainer.hide();
1173 setController (ACTIVE_SHAPE, shapeNr + 1);
1174 shapeGui[shapeNr].tabContainer.rename ("activetab");
1175 shapeGui[shapeNr].tabContainer.applyTheme (theme);
1176 shapeGui[shapeNr].shapeContainer.show();
1177 updateHorizon ();
1178 }
1179
valueChangedCallback(BEvents::Event * event)1180 void BShaprGUI::valueChangedCallback (BEvents::Event* event)
1181 {
1182 if ((event) && (event->getWidget ()))
1183 {
1184 BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
1185 float value = widget->getValue ();
1186
1187 if (widget->getMainWindow ())
1188 {
1189 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1190 int widgetNr = -1;
1191
1192 for (int i = 0; i < NR_CONTROLLERS; ++i)
1193 {
1194 if (widget == ui->controllerWidgets[i])
1195 {
1196 widgetNr = i;
1197 break;
1198 }
1199 }
1200
1201 // Controllers (menus, dials, selectors, ...)
1202 if (widgetNr >= 0)
1203 {
1204 if (widgetNr == MIDI_CONTROL)
1205 {
1206 if (value == 1.0f) ui->midiPiano.show ();
1207 else ui->midiPiano.hide ();
1208 }
1209
1210 else if ((widgetNr == BASE) || (widgetNr == BASE_VALUE))
1211 {
1212 ui->controllers[widgetNr] = value;
1213 ui->calculateXSteps ();
1214 ui->updateHorizon ();
1215 }
1216
1217 else if (widgetNr >= SHAPERS)
1218 {
1219 int shapeNr = (widgetNr - SHAPERS) / SH_SIZE;
1220 int shapeWidgetNr = (widgetNr - SHAPERS) - shapeNr * SH_SIZE;
1221
1222 // Target
1223 if (shapeWidgetNr == SH_TARGET)
1224 {
1225 int nr = LIMIT (value, 0, MAXEFFECTS - 1);
1226
1227 // Change transformation
1228 ui->shapeGui[shapeNr].shapeWidget.setTransformation (methods[nr].transformFactor, methods[nr].transformOffset);
1229
1230 // Set shapeWidget display parameters (limits, unit, prefix, ...)
1231 ui->shapeGui[shapeNr].shapeWidget.setScaleParameters
1232 (
1233 methods[nr].anchorYPos,
1234 methods[nr].anchorValue,
1235 methods[nr].ratio
1236 );
1237 ui->shapeGui[shapeNr].shapeWidget.setUnit (methods[nr].unit);
1238 ui->shapeGui[shapeNr].shapeWidget.setPrefix (methods[nr].prefix);
1239 ui->shapeGui[shapeNr].shapeWidget.setLowerLimit (methods[nr].limit.min);
1240 ui->shapeGui[shapeNr].shapeWidget.setHigherLimit (methods[nr].limit.max);
1241 ui->shapeGui[shapeNr].shapeWidget.update();
1242
1243 // Hide old controllers
1244 int oldMethodNr = ui->controllers[widgetNr];
1245 for (int i = 0; i < MAXOPTIONWIDGETS; ++i)
1246 {
1247 int optionNr = methods[oldMethodNr].optionIndexes[i];
1248 if (optionNr != NO_OPT)
1249 {
1250 if (ui->shapeGui[shapeNr].optionWidgets[optionNr]) ui->shapeGui[shapeNr].optionWidgets[optionNr]->hide ();
1251 ui->shapeGui[shapeNr].optionLabels[optionNr].hide ();
1252 }
1253 }
1254
1255 // Configure and show new controllers
1256 int methodNr = value;
1257 for (int i = 0; i < MAXOPTIONWIDGETS; ++i)
1258 {
1259 int optionNr = methods[methodNr].optionIndexes[i];
1260
1261 if (optionNr != NO_OPT)
1262 {
1263 if (options[optionNr].widgetType != NO_WIDGET)
1264 {
1265 if (options[optionNr].widgetType == DIAL_WIDGET)
1266 {
1267 if (ui->shapeGui[shapeNr].optionWidgets[optionNr])
1268 {
1269 RESIZE ((*ui->shapeGui[shapeNr].optionWidgets[optionNr]), 230 + i * 70, 434, 50, 60, ui->sz);
1270 RESIZE ((ui->shapeGui[shapeNr].optionLabels[optionNr]), 220 + i * 70, 494, 70, 16, ui->sz);
1271 }
1272 }
1273
1274 else if (options[optionNr].widgetType == POPUP_WIDGET)
1275 {
1276 if (ui->shapeGui[shapeNr].optionWidgets[optionNr])
1277 {
1278 BItems::ItemList il = options[optionNr].param.get<BItems::ItemList>();
1279 size_t max = 0;
1280 for (BItems::Item const& it : il)
1281 {
1282 if (it.getWidget())
1283 {
1284 BWidgets::Label* l = (BWidgets::Label*) it.getWidget();
1285 if (l->getText().size() > max) max = l->getText().size();
1286 }
1287 }
1288 int w = max * 9 + 20;
1289 w = LIMIT (w, 50, 270 - i * 70);
1290 int h = (il.size() + 1) * 20;
1291 h = LIMIT (h, 20, 400);
1292
1293 RESIZE ((*ui->shapeGui[shapeNr].optionWidgets[optionNr]), 220 + i * 70, 455, w, 20, ui->sz);
1294 ((BWidgets::PopupListBox*) ui->shapeGui[shapeNr].optionWidgets[optionNr])->resizeListBox (BUtilities::Point (w * ui->sz, h * ui->sz));
1295 ((BWidgets::PopupListBox*) ui->shapeGui[shapeNr].optionWidgets[optionNr])->moveListBox (BUtilities::Point (0, -h * ui->sz));
1296
1297 RESIZE ((ui->shapeGui[shapeNr].optionLabels[optionNr]), 220 + i * 70, 494, w, 16, ui->sz);
1298 }
1299 }
1300
1301 // Show option controller
1302 if (ui->shapeGui[shapeNr].optionWidgets[optionNr])
1303 {
1304 ui->shapeGui[shapeNr].optionWidgets[optionNr]->applyTheme (ui->theme);
1305 ui->shapeGui[shapeNr].optionWidgets[optionNr]->show ();
1306 }
1307
1308 // Show option label
1309 ui->shapeGui[shapeNr].optionLabels[optionNr].applyTheme (ui->theme);
1310 //RESIZE ((ui->shapeGui[shapeNr].optionLabels[optionNr]), 220 + i * 70, 494, 60, 16, ui->sz);
1311 ui->shapeGui[shapeNr].optionLabels[optionNr].show ();
1312 }
1313 }
1314
1315 }
1316 }
1317
1318 else if (shapeWidgetNr == SH_SMOOTHING)
1319 {
1320 if (shapeNr == ui->controllers[ACTIVE_SHAPE] - 1) ui->updateHorizon ();
1321 }
1322 }
1323 ui->controllers[widgetNr] = value;
1324 ui->write_function(ui->controller, CONTROLLERS + widgetNr, sizeof(float), 0, &ui->controllers[widgetNr]);
1325 }
1326 }
1327 }
1328 }
1329
tabClickedCallback(BEvents::Event * event)1330 void BShaprGUI::tabClickedCallback (BEvents::Event* event)
1331 {
1332 if ((event) && (event->getWidget ()))
1333 {
1334 BWidgets::Widget* widget = (BWidgets::Widget*) event->getWidget ();
1335 if (widget->getMainWindow ())
1336 {
1337 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1338 for (int i = 0; i < MAXSHAPES; ++i)
1339 {
1340 if ((widget == &ui->shapeGui[i].tabIcon) || (widget == &ui->shapeGui[i].tabContainer))
1341 {
1342 ui->switchShape (i);
1343 break;
1344 }
1345
1346 else if (widget == &ui->shapeGui[i].tabSymbol[CLOSESYMBOL])
1347 {
1348 if (ui->shapeGui[i].tabMsgBox) delete ui->shapeGui[i].tabMsgBox;
1349 ui->shapeGui[i].tabMsgBox = nullptr;
1350 if (ui->shapeGui[i].tabMsgBoxBg) delete ui->shapeGui[i].tabMsgBoxBg;
1351 ui->shapeGui[i].tabMsgBoxBg = nullptr;
1352
1353 ui->shapeGui[i].tabMsgBox = new BWidgets::MessageBox (500 * ui->sz, 240 * ui->sz, 200 * ui->sz, 120 * ui->sz, "msgbox", "Delete shape " + std::to_string (i + 1), "Do you really want to delete this shape and all its content and settings ?", {"No", "Yes"});
1354 if (ui->shapeGui[i].tabMsgBox)
1355 {
1356 ui->shapeGui[i].tabMsgBox->applyTheme (ui->theme);
1357
1358 ui->shapeGui[i].tabMsgBoxBg = new BWidgets::Widget (0, 0, 1200 * ui->sz, 710 * ui->sz, "widget");
1359 if (ui->shapeGui[i].tabMsgBoxBg)
1360 {
1361 ui->shapeGui[i].tabMsgBoxBg->applyTheme (ui->theme);
1362 ui->shapeGui[i].tabMsgBoxBg->add (*ui->shapeGui[i].tabMsgBox);
1363 ui->mContainer.add (*ui->shapeGui[i].tabMsgBoxBg);
1364 }
1365 }
1366 break;
1367 }
1368
1369 else if (widget == &ui->shapeGui[i].tabSymbol[ADDSYMBOL])
1370 {
1371 ui->insertShape (i);
1372 break;
1373 }
1374
1375 else if (widget == &ui->shapeGui[i].tabSymbol[LEFTSYMBOL])
1376 {
1377 ui->swapShapes (i, i - 1);
1378 break;
1379 }
1380
1381 else if (widget == &ui->shapeGui[i].tabSymbol[RIGHTSYMBOL])
1382 {
1383 ui->swapShapes (i, i + 1);
1384 break;
1385 }
1386 }
1387 }
1388 }
1389 }
1390
shapeChangedCallback(BEvents::Event * event)1391 void BShaprGUI::shapeChangedCallback (BEvents::Event* event)
1392 {
1393 if ((event) && (event->getWidget ()))
1394 {
1395 BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
1396
1397 if (widget->getMainWindow () && (widget->getValue () == 1))
1398 {
1399 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1400
1401 for (int i = 0; i < MAXSHAPES; ++i)
1402 {
1403 if (widget == (BWidgets::ValueWidget*) &ui->shapeGui[i].shapeWidget)
1404 {
1405 ui->sendShape(i);
1406 break;
1407 }
1408 }
1409 }
1410 }
1411 }
1412
1413
toolChangedCallback(BEvents::Event * event)1414 void BShaprGUI::toolChangedCallback (BEvents::Event* event)
1415 {
1416 if ((event) && (event->getWidget ()))
1417 {
1418 BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
1419
1420 if (widget->getMainWindow ())
1421 {
1422 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1423
1424 for (int i = 0; i < MAXSHAPES; ++i)
1425 {
1426 if (widget == (BWidgets::ValueWidget*) &ui->shapeGui[i].toolSelect)
1427 {
1428 ui->shapeGui[i].shapeWidget.setTool((ToolType) ui->shapeGui[i].toolSelect.getValue ());
1429 break;
1430 }
1431 }
1432 }
1433 }
1434 }
1435
editClickedCallback(BEvents::Event * event)1436 void BShaprGUI::editClickedCallback (BEvents::Event* event)
1437 {
1438 if ((event) && (event->getWidget ()))
1439 {
1440 BWidgets::Widget* widget = (BWidgets::Widget*) event->getWidget ();
1441
1442 if (widget->getMainWindow ())
1443 {
1444 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1445
1446 for (int i = 0; i < MAXSHAPES; ++i)
1447 {
1448 for (int j = 0; j < 7; ++j)
1449 {
1450 if (widget == &ui->shapeGui[i].editWidgets[j])
1451 {
1452 ui->shapeGui[i].editWidgets[j].rename ("frame");
1453 ui->shapeGui[i].editWidgets[j].applyTheme (ui->theme);
1454
1455 switch (j)
1456 {
1457 case 0: ui->clipboard = ui->shapeGui[i].shapeWidget.cutSelection ();
1458 return;
1459
1460 case 1: ui->clipboard = ui->shapeGui[i].shapeWidget.copySelection ();
1461 return;
1462
1463 case 2: ui->shapeGui[i].shapeWidget.pasteSelection (ui->clipboard);
1464 return;
1465
1466 case 3: ui->shapeGui[i].shapeWidget.deleteSelection ();
1467 return;
1468
1469 case 4: ui->shapeGui[i].shapeWidget.reset ();
1470 return;
1471
1472 case 5: ui->shapeGui[i].shapeWidget.undo ();
1473 return;
1474
1475 case 6: ui->shapeGui[i].shapeWidget.redo ();
1476 return;
1477
1478 default: return;
1479 }
1480 }
1481 }
1482 }
1483 }
1484 }
1485 }
1486
editReleasedCallback(BEvents::Event * event)1487 void BShaprGUI::editReleasedCallback (BEvents::Event* event)
1488 {
1489 if ((event) && (event->getWidget ()))
1490 {
1491 BWidgets::Widget* widget = (BWidgets::Widget*) event->getWidget ();
1492
1493 if (widget->getMainWindow ())
1494 {
1495 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1496
1497 for (int i = 0; i < MAXSHAPES; ++i)
1498 {
1499 for (int j = 0; j < 7; ++j)
1500 {
1501 if (widget == &ui->shapeGui[i].editWidgets[j])
1502 {
1503 ui->shapeGui[i].editWidgets[j].rename ("widget");
1504 ui->shapeGui[i].editWidgets[j].applyTheme (ui->theme);
1505 }
1506 }
1507 }
1508 }
1509 }
1510 }
1511
gridChangedCallback(BEvents::Event * event)1512 void BShaprGUI::gridChangedCallback (BEvents::Event* event)
1513 {
1514 if ((event) && (event->getWidget ()))
1515 {
1516 BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
1517
1518 if (widget->getMainWindow ())
1519 {
1520 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1521
1522 for (int i = 0; i < MAXSHAPES; ++i)
1523 {
1524 if (widget == (BWidgets::ValueWidget*) &ui->shapeGui[i].gridSelect)
1525 {
1526 int value = ui->shapeGui[i].gridSelect.getValue ();
1527 switch (value)
1528 {
1529 case 0: ui->shapeGui[i].shapeWidget.hideGrid ();
1530 ui->shapeGui[i].shapeWidget.setSnap (false);
1531 break;
1532
1533 case 1: ui->shapeGui[i].shapeWidget.showGrid ();
1534 ui->shapeGui[i].shapeWidget.setSnap (false);
1535 break;
1536
1537 case 2: ui->shapeGui[i].shapeWidget.showGrid ();
1538 ui->shapeGui[i].shapeWidget.setSnap (true);
1539 break;
1540
1541 default:break;
1542 }
1543 break;
1544 }
1545 }
1546 }
1547 }
1548 }
1549
wheelScrolledCallback(BEvents::Event * event)1550 void BShaprGUI::wheelScrolledCallback (BEvents::Event* event)
1551 {
1552 if ((event) && (event->getWidget ()))
1553 {
1554 BEvents::WheelEvent* we = (BEvents::WheelEvent*) event;
1555 BWidgets::Widget* widget = event->getWidget ();
1556
1557 if (widget->getMainWindow ())
1558 {
1559 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1560
1561 ui->monitorScale = ui->monitorScale * (1 + 0.01 * we->getDelta().y);
1562 if (ui->monitorScale < 0.01) ui->monitorScale = 0.01;
1563 ui->input1Monitor.setZoom (ui->monitorScale);
1564 ui->output1Monitor.setZoom (ui->monitorScale);
1565 ui->input2Monitor.setZoom (ui->monitorScale);
1566 ui->output2Monitor.setZoom (ui->monitorScale);
1567 }
1568 }
1569 }
1570
pianoCallback(BEvents::Event * event)1571 void BShaprGUI::pianoCallback (BEvents::Event* event)
1572 {
1573 if ((event) && (event->getWidget ()))
1574 {
1575 BWidgets::Widget* widget = event->getWidget ();
1576
1577 if (widget->getMainWindow ())
1578 {
1579 BShaprGUI* ui = (BShaprGUI*) widget->getMainWindow ();
1580
1581 std::vector<bool> keys = ui->midiPiano.getPressedKeys ();
1582 size_t sz = (keys.size () < 12 ? keys.size () : 12);
1583 uint32_t bits = 0;
1584
1585 for (unsigned int i = 0; i < sz; ++i)
1586 {
1587 if (keys[i]) bits += (1 << i);
1588 }
1589
1590 if (bits != uint32_t (ui->controllers[MIDI_KEYS]))
1591 {
1592 ui->controllers[MIDI_KEYS] = bits;
1593 ui->write_function(ui->controller, CONTROLLERS + MIDI_KEYS, sizeof(float), 0, &ui->controllers[MIDI_KEYS]);
1594 }
1595 }
1596 }
1597 }
1598
calculateXSteps()1599 void BShaprGUI::calculateXSteps ()
1600 {
1601 majorXSteps = (controllers[BASE_VALUE] != 0.0 ? 1.0 / controllers[BASE_VALUE] : 1.0);
1602
1603 switch ((BShaprBaseIndex)controllers[BASE])
1604 {
1605 case SECONDS: minorXSteps = majorXSteps / 10.0;
1606 break;
1607
1608 case BEATS: if (beatUnit != 0) minorXSteps = majorXSteps / (16.0 / ((double)beatUnit));
1609 else minorXSteps = majorXSteps / 4.0;
1610 break;
1611
1612 case BARS: if (beatsPerBar != 0.0f) minorXSteps = majorXSteps / beatsPerBar;
1613 else minorXSteps = majorXSteps / 4.0;
1614 break;
1615
1616 default: minorXSteps = 1.0;
1617 break;
1618 }
1619
1620 if (controllers[BASE_VALUE] >= 10.0) minorXSteps = majorXSteps;
1621
1622 for (int sh = 0; sh < MAXSHAPES; ++sh)
1623 {
1624 shapeGui[sh].shapeWidget.setMinorXSteps (minorXSteps);
1625 shapeGui[sh].shapeWidget.setMajorXSteps (majorXSteps);
1626 shapeGui[sh].shapeWidget.update ();
1627 }
1628 }
1629
initMonitors()1630 void BShaprGUI::initMonitors ()
1631 {
1632 input1Monitor.clear ();
1633 output1Monitor.clear ();
1634 input2Monitor.clear ();
1635 output2Monitor.clear ();
1636 horizonPos = 0;
1637 }
1638
translateNotification(BShaprNotifications * notifications,uint32_t notificationsCount)1639 std::pair<int, int> BShaprGUI::translateNotification (BShaprNotifications* notifications, uint32_t notificationsCount)
1640 {
1641 if (notificationsCount == 0) return std::make_pair (0, 0);
1642
1643 int startpos = notifications[0].position;
1644 int monitorpos = startpos;
1645 for (unsigned int i = 0; i < notificationsCount; ++i)
1646 {
1647 monitorpos = LIMIT (notifications[i].position, 0, MONITORBUFFERSIZE - 1);
1648
1649 input1Monitor.addData (monitorpos, notifications[i].input1);
1650 output1Monitor.addData (monitorpos, notifications[i].output1);
1651 input2Monitor.addData (monitorpos, notifications[i].input2);
1652 output2Monitor.addData (monitorpos, notifications[i].output2);
1653
1654 horizonPos = double (monitorpos) / MONITORBUFFERSIZE;
1655 }
1656 return std::make_pair (startpos, monitorpos);
1657 }
1658
updateMonitors(int start,int end)1659 void BShaprGUI::updateMonitors (int start, int end)
1660 {
1661 input1Monitor.redrawRange (start, end);
1662 output1Monitor.redrawRange (start, end);
1663 input2Monitor.redrawRange (start, end);
1664 output2Monitor.redrawRange (start, end);
1665 }
1666
updateHorizon()1667 void BShaprGUI::updateHorizon ()
1668 {
1669 double width = monitorContainer.getEffectiveWidth ();
1670 int shapeNr = LIMIT (controllers[ACTIVE_SHAPE], 1, MAXSHAPES) - 1;
1671 double smTime = shapeGui[shapeNr].smoothingDial.getValue () / 1000;
1672
1673 double smWidth;
1674 switch (int (controllers[BASE]))
1675 {
1676 case SECONDS : smWidth = width * smTime / controllers[BASE_VALUE];
1677 break;
1678 case BEATS: smWidth = width * smTime * (bpm / 60.0) / controllers[BASE_VALUE];
1679 break;
1680 case BARS: smWidth = width * smTime * (bpm / 60.0 / beatsPerBar) / controllers[BASE_VALUE];
1681 break;
1682 default: break;
1683 }
1684
1685 monitorHorizon1.setSmoothingWidth (smWidth);
1686 monitorHorizon1.moveLineTo (horizonPos * width, 0);
1687 monitorHorizon2.setSmoothingWidth (smWidth);
1688 monitorHorizon2.moveLineTo ((horizonPos - 1) * width, 0);
1689 }
1690
instantiate(const LV2UI_Descriptor * descriptor,const char * plugin_uri,const char * bundle_path,LV2UI_Write_Function write_function,LV2UI_Controller controller,LV2UI_Widget * widget,const LV2_Feature * const * features)1691 static LV2UI_Handle instantiate (const LV2UI_Descriptor *descriptor, const char *plugin_uri, const char *bundle_path,
1692 LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget *widget,
1693 const LV2_Feature *const *features)
1694 {
1695 PuglNativeView parentWindow = 0;
1696 LV2UI_Resize* resize = NULL;
1697
1698 if (strcmp(plugin_uri, BSHAPR_URI) != 0)
1699 {
1700 std::cerr << "BShapr.lv2#GUI: GUI does not support plugin with URI " << plugin_uri << std::endl;
1701 return NULL;
1702 }
1703
1704 for (int i = 0; features[i]; ++i)
1705 {
1706 if (!strcmp(features[i]->URI, LV2_UI__parent)) parentWindow = (PuglNativeView) features[i]->data;
1707 else if (!strcmp(features[i]->URI, LV2_UI__resize)) resize = (LV2UI_Resize*)features[i]->data;
1708 }
1709 if (parentWindow == 0) std::cerr << "BShapr.lv2#GUI: No parent window.\n";
1710
1711 // New instance
1712 BShaprGUI* ui;
1713 try {ui = new BShaprGUI (bundle_path, features, parentWindow);}
1714 catch (std::exception& exc)
1715 {
1716 std::cerr << "BShapr.lv2#GUI: Instantiation failed. " << exc.what () << std::endl;
1717 return NULL;
1718 }
1719
1720 ui->controller = controller;
1721 ui->write_function = write_function;
1722
1723 // Reduce min GUI size for small displays
1724 double sz = 1.0;
1725 int screenWidth = getScreenWidth ();
1726 int screenHeight = getScreenHeight ();
1727 if ((screenWidth < 1240) || (screenHeight < 720)) sz = 0.66;
1728 if ((screenWidth < 840) || (screenHeight < 530)) sz = 0.50;
1729
1730 if (resize) resize->ui_resize (resize->handle, 1200 * sz, 710 * sz);
1731 *widget = (LV2UI_Widget) puglGetNativeWindow (ui->getPuglView ());
1732 ui->sendGuiOn();
1733
1734 return (LV2UI_Handle) ui;
1735 }
1736
cleanup(LV2UI_Handle ui)1737 static void cleanup(LV2UI_Handle ui)
1738 {
1739 BShaprGUI* pluginGui = (BShaprGUI*) ui;
1740 if (pluginGui) delete pluginGui;
1741 }
1742
portEvent(LV2UI_Handle ui,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)1743 static void portEvent(LV2UI_Handle ui, uint32_t port_index, uint32_t buffer_size,
1744 uint32_t format, const void* buffer)
1745 {
1746 BShaprGUI* pluginGui = (BShaprGUI*) ui;
1747 if (pluginGui) pluginGui->portEvent(port_index, buffer_size, format, buffer);
1748 }
1749
callIdle(LV2UI_Handle ui)1750 static int callIdle (LV2UI_Handle ui)
1751 {
1752 BShaprGUI* pluginGui = (BShaprGUI*) ui;
1753 if (pluginGui) pluginGui->handleEvents ();
1754 return 0;
1755 }
1756
callResize(LV2UI_Handle ui,int width,int height)1757 static int callResize (LV2UI_Handle ui, int width, int height)
1758 {
1759 BShaprGUI* self = (BShaprGUI*) ui;
1760 if (!self) return 0;
1761
1762 BEvents::ExposeEvent* ev = new BEvents::ExposeEvent (self, self, BEvents::CONFIGURE_REQUEST_EVENT, self->getPosition().x, self->getPosition().y, width, height);
1763 self->addEventToQueue (ev);
1764 return 0;
1765 }
1766
1767 static const LV2UI_Idle_Interface idle = {callIdle};
1768 static const LV2UI_Resize resize = {nullptr, callResize};
1769
extensionData(const char * uri)1770 static const void* extensionData(const char* uri)
1771 {
1772 if (!strcmp(uri, LV2_UI__idleInterface)) return &idle;
1773 else if(!strcmp(uri, LV2_UI__resize)) return &resize;
1774 else return NULL;
1775 }
1776
1777 static const LV2UI_Descriptor guiDescriptor = {
1778 BSHAPR_GUI_URI,
1779 instantiate,
1780 cleanup,
1781 portEvent,
1782 extensionData
1783 };
1784
1785 // LV2 Symbol Export
lv2ui_descriptor(uint32_t index)1786 LV2_SYMBOL_EXPORT const LV2UI_Descriptor *lv2ui_descriptor(uint32_t index)
1787 {
1788 switch (index) {
1789 case 0: return &guiDescriptor;
1790 default:return NULL;
1791 }
1792 }
1793