1 /* B.Angr
2 * Dynamic distorted bandpass filter plugin
3 *
4 * Copyright (C) 2021 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 "BAngrGUI.hpp"
22 #include <exception>
23 #include "screen.h"
24 #include "BUtilities/vsystem.hpp"
25
26
BAngrGUI(const char * bundle_path,const LV2_Feature * const * features,PuglNativeView parentWindow)27 BAngrGUI::BAngrGUI (const char *bundle_path, const LV2_Feature *const *features, PuglNativeView parentWindow) :
28 Window (1000, 560, "B.Angr", parentWindow, true, PUGL_MODULE, 0),
29 controller (NULL),
30 write_function (NULL),
31 pluginPath (bundle_path ? std::string (bundle_path) : std::string ("")),
32 sz (1.0),
33 bgImageSurface (nullptr),
34 map (nullptr),
35
36 mContainer (0, 0, 1000, 560, "main"),
37 cursor (480, 260, 40, 40, "dot"),
38 poweredLabel (720, 540, 250, 20, "rlabel", BANGR_LABEL_POWERED_BY),
39 helpButton (918, 508, 24, 24, "widget", BANGR_LABEL_HELP),
40 ytButton (948, 508, 24, 24, "widget", BANGR_LABEL_VIDEO),
41 bypassButton (900, 30, 20, 20, "dial"),
42 bypassLabel (880, 60, 60, 20, "label", BANGR_LABEL_BYPASS),
43 drywetDial (940, 20, 40, 40, "dial", 1.0, 0.0, 1.0, 0.0, ""),
44 drywetLabel (930, 60, 60, 20, "label", BANGR_LABEL_DRY_WET),
45 speedDial (370, 460, 60, 60, "dial", 0.5, 0.0, 1.0, 0.0, BIDIRECTIONAL, "%1.2f", ""),
46 speedLabel (370, 520, 60, 20, "label", BANGR_LABEL_SPEED),
47 spinDial (570, 460, 60, 60, "dial", 0.0, -1.0, 1.0, 0.0, BIDIRECTIONAL, "%1.2f", ""),
48 spinLabel (570, 520, 60, 20, "label", BANGR_LABEL_SPIN),
49 speedScreen (180, 480, 100, 35, "screen"),
50 speedFlexLabel (220, 520, 100, 20, "label", BANGR_LABEL_FLEXIBILITY),
51 speedTypeListbox
52 (
53 280, 490, 80, 20, 0, -120, 80, 120, "menu",
54 BItems::ItemList
55 ({
56 {RANDOM, BANGR_LABEL_RANDOM},
57 {LEVEL, BANGR_LABEL_LEVEL},
58 {LOWS, BANGR_LABEL_LOWS},
59 {MIDS, BANGR_LABEL_MIDS},
60 {HIGHS, BANGR_LABEL_HIGHS}
61 }),
62 0),
63 speedAmountSlider (200, 485, 80, 20, "slider", 0.0, 0.0, 1.0, 0.0, "%1.2f"),
64 spinScreen (640, 480, 100, 35, "screen"),
65 spinFlexLabel (680, 520, 100, 20, "label", BANGR_LABEL_FLEXIBILITY),
66 spinTypeListbox
67 (
68 740, 490, 80, 20, 0, -120, 80, 120, "menu",
69 BItems::ItemList
70 ({
71 {RANDOM, BANGR_LABEL_RANDOM},
72 {LEVEL, BANGR_LABEL_LEVEL},
73 {LOWS, BANGR_LABEL_LOWS},
74 {MIDS, BANGR_LABEL_MIDS},
75 {HIGHS, BANGR_LABEL_HIGHS}
76 }),
77 0),
78 spinAmountSlider (660, 485, 80, 20, "slider", 0.0, 0.0, 1.0, 0.0, "%1.2f")
79 {
80 // Init param widgets
81 for (int i = 0; i < NR_FX; ++i)
82 {
83 fx[i].container = BWidgets::Widget (20 + int (i / 2) * 660, 100 + int (((i + 1) & 3) / 2) * 200, 300, 160, "widget");
84 fx[i].paramDials[0] = Dial (0, 10, 60, 60, "dial", 0.5, 0.0, 1.0, 0.0, "%1.2f");
85 fx[i].paramLabels[0] = BWidgets::Label (0, 70, 60, 20, "label", BANGR_LABEL_GAIN);
86 fx[i].paramDials[1] = Dial (80, 10, 60, 60, "dial", 0.5, 0.0, 1.0, 0.0, "%1.2f");
87 fx[i].paramLabels[1] = BWidgets::Label (80, 70, 60, 20, "label", BANGR_LABEL_FIRST);
88 fx[i].paramDials[2] = Dial (160, 10, 60, 60, "dial", 0.5, 0.0, 1.0, 0.0, "%1.2f");
89 fx[i].paramLabels[2] = BWidgets::Label (160, 70, 60, 20, "label", BANGR_LABEL_LAST);
90 fx[i].paramDials[3] = Dial (240, 10, 60, 60, "dial", 0.0, 0.0, 1.0, 0.0, "%1.2f");
91 fx[i].paramLabels[3] = BWidgets::Label (240, 70, 60, 20, "label", BANGR_LABEL_NUKE);
92 fx[i].paramDials[4] = Dial (40, 70, 60, 60, "dial", 1.0, 0.0, 1.0, 0.0, "%1.2f");
93 fx[i].paramLabels[4] = BWidgets::Label (40, 130, 60, 20, "label", BANGR_LABEL_MIX);
94 fx[i].paramDials[5] = Dial (200, 70, 60, 60, "dial", 0.0, -1.0, 1.0, 0.0, "%1.2f");
95 fx[i].paramLabels[5] = BWidgets::Label (200, 130, 60, 20, "label", BANGR_LABEL_PAN);
96 }
97
98 // Link controllers
99 controllerWidgets[BYPASS] = &bypassButton;
100 controllerWidgets[DRY_WET] = &drywetDial;
101 controllerWidgets[SPEED] = &speedDial;
102 controllerWidgets[SPEED_RANGE] = &speedDial.range;
103 controllerWidgets[SPEED_TYPE] = &speedTypeListbox;
104 controllerWidgets[SPEED_AMOUNT] = &speedAmountSlider;
105 controllerWidgets[SPIN] = &spinDial;
106 controllerWidgets[SPIN_RANGE] = &spinDial.range;
107 controllerWidgets[SPIN_TYPE] = &spinTypeListbox;
108 controllerWidgets[SPIN_AMOUNT] = &spinAmountSlider;
109
110 for (int i = 0; i < NR_FX; ++i)
111 {
112 for (int j = 0; j < NR_PARAMS; ++j)
113 {
114 controllerWidgets[FX + i * NR_PARAMS + j] = &fx[i].paramDials[j];
115 }
116 }
117
118 // Configure widgets
119 cursor.setDraggable (true);
120
121
122 // Set callbacks
123 for (BWidgets::ValueWidget* c : controllerWidgets) c->setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BAngrGUI::valueChangedCallback);
124 cursor.setCallbackFunction (BEvents::EventType::POINTER_DRAG_EVENT, BAngrGUI::cursorDraggedCallback);
125 cursor.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BAngrGUI::cursorDraggedCallback);
126 cursor.setCallbackFunction (BEvents::EventType::BUTTON_RELEASE_EVENT, BAngrGUI::cursorReleasedCallback);
127 poweredLabel.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BAngrGUI::xregionClickedCallback);
128 helpButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BAngrGUI::helpButtonClickedCallback);
129 ytButton.setCallbackFunction (BEvents::EventType::BUTTON_PRESS_EVENT, BAngrGUI::ytButtonClickedCallback);
130
131 // Load background & apply theme
132 bgImageSurface = cairo_image_surface_create_from_png ((pluginPath + BG_FILE).c_str());
133 widgetBg.loadFillFromCairoSurface (bgImageSurface);
134 applyTheme (theme);
135
136 // Pack widgets
137 for (Fx& f : fx)
138 {
139 for (Dial& d : f.paramDials) f.container.add (d);
140 for (BWidgets::Label& l : f.paramLabels) f.container.add (l);
141 mContainer.add (f.container);
142 }
143 mContainer.add (bypassButton);
144 mContainer.add (bypassLabel);
145 mContainer.add (drywetDial);
146 mContainer.add (drywetLabel);
147 mContainer.add (speedDial);
148 mContainer.add (speedLabel);
149 mContainer.add (spinDial);
150 mContainer.add (spinLabel);
151 mContainer.add (speedFlexLabel);
152 mContainer.add (speedTypeListbox);
153 mContainer.add (speedAmountSlider);
154 mContainer.add (spinFlexLabel);
155 mContainer.add (spinTypeListbox);
156 mContainer.add (spinAmountSlider);
157 mContainer.add (speedScreen);
158 mContainer.add (spinScreen);
159 mContainer.add (cursor);
160 mContainer.add (poweredLabel);
161 mContainer.add (helpButton);
162 mContainer.add (ytButton);
163 add (mContainer);
164
165 //Scan host features for URID map
166 LV2_URID_Map* m = NULL;
167 // unmap = NULL;
168
169 for (int i = 0; features[i]; ++i)
170 {
171 if (strcmp(features[i]->URI, LV2_URID__map) == 0) m = (LV2_URID_Map*) features[i]->data;
172 // if (strcmp(features[i]->URI, LV2_URID__unmap) == 0) unmap = (LV2_URID_Unmap*) features[i]->data;
173 }
174 if ((!m) /*|| (!unmap)*/ ) throw std::invalid_argument ("Host does not support urid:map");
175
176 //Map URIS
177 map = m;
178 getURIs (map, &urids);
179
180 // Initialize forge
181 lv2_atom_forge_init (&forge,map);
182 }
183
~BAngrGUI()184 BAngrGUI::~BAngrGUI()
185 {}
186
portEvent(uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)187 void BAngrGUI::portEvent(uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
188 {
189 // Notify port
190 if ((format == urids.atom_eventTransfer) && (port_index == NOTIFY))
191 {
192 const LV2_Atom* atom = (const LV2_Atom*) buffer;
193 if (lv2_atom_forge_is_object_type(&forge, atom->type))
194 {
195 const LV2_Atom_Object* obj = (const LV2_Atom_Object*) atom;
196
197 if (obj->body.otype == urids.patch_Set)
198 {
199 const LV2_Atom* property = NULL;
200 const LV2_Atom* value = NULL;
201 lv2_atom_object_get
202 (
203 obj,
204 urids.patch_property, &property,
205 urids.patch_value, &value,
206 NULL
207 );
208
209 if (property && (property->type == urids.atom_URID) && value)
210 {
211 const uint32_t key = ((const LV2_Atom_URID*)property)->body;
212
213 if ((key == urids.bangr_xcursor) && (value->type == urids.atom_Float))
214 {
215 const float xcursor = ((LV2_Atom_Float*)value)->body;
216 cursor.moveTo ((400.0 + xcursor * 200.0) * sz - 0.5 * cursor.getWidth(), cursor.getPosition().y);
217 }
218
219 else if ((key == urids.bangr_ycursor) && (value->type == urids.atom_Float))
220 {
221 const float ycursor = ((LV2_Atom_Float*)value)->body;
222 cursor.moveTo (cursor.getPosition().x, (180.0 + ycursor * 200.0) * sz - 0.5 * cursor.getHeight());
223 }
224 }
225 }
226 }
227 }
228
229 // Scan controller ports
230 else if ((format == 0) && (port_index >= CONTROLLERS) && (port_index < CONTROLLERS + NR_CONTROLLERS))
231 {
232 float* pval = (float*) buffer;
233 controllerWidgets[port_index - CONTROLLERS]->setValue (*pval);
234 }
235 }
236
resizeGUI()237 void BAngrGUI::resizeGUI()
238 {
239 hide ();
240
241 // Resize Fonts
242 defaultFont.setFontSize (12 * sz);
243 rFont.setFontSize (12 * sz);
244 lFont.setFontSize (12 * sz);
245
246 // Resize Background
247 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1000 * sz, 560 * sz);
248 cairo_t* cr = cairo_create (surface);
249 cairo_scale (cr, sz, sz);
250 cairo_set_source_surface(cr, bgImageSurface, 0, 0);
251 cairo_paint(cr);
252 widgetBg.loadFillFromCairoSurface(surface);
253 cairo_destroy (cr);
254 cairo_surface_destroy (surface);
255
256 // Resize widgets
257 RESIZE (mContainer, 0, 0, 1000, 560, sz);
258 cursor.resize (40.0 * sz, 40.0 * sz);
259 RESIZE (poweredLabel, 720, 540, 250, 20, sz);
260 RESIZE (helpButton, 918, 508, 24, 24, sz);
261 RESIZE (ytButton, 948, 508, 24, 24, sz);
262 RESIZE (bypassButton, 900, 30, 20, 20, sz);
263 RESIZE (bypassLabel, 880, 60, 60, 20, sz);
264 RESIZE (drywetDial, 940, 20, 40, 40, sz);
265 RESIZE (drywetLabel, 930, 60, 60, 20, sz);
266 RESIZE (speedDial, 370, 460, 60, 60, sz);
267 RESIZE (speedLabel, 370, 520, 60, 20, sz);
268 RESIZE (spinDial, 570, 460, 60, 60, sz);
269 RESIZE (spinLabel, 570, 520, 60, 20, sz);
270 RESIZE (speedScreen, 180, 480, 100, 35, sz);
271 RESIZE (speedFlexLabel, 220, 520, 100, 20, sz);
272 RESIZE (speedTypeListbox, 280, 490, 80, 20, sz);
273 speedTypeListbox.resizeListBox(BUtilities::Point (80 * sz, 120 * sz));
274 speedTypeListbox.moveListBox(BUtilities::Point (0, -120 * sz));
275 speedTypeListbox.resizeListBoxItems(BUtilities::Point (80 * sz, 20 * sz));
276 RESIZE (speedAmountSlider, 200, 485, 80, 20, sz);
277 RESIZE (spinScreen , 640, 480, 100, 35, sz);
278 RESIZE (spinFlexLabel, 680, 520, 100, 20, sz);
279 RESIZE (spinTypeListbox, 740, 490, 80, 20, sz);
280 spinTypeListbox.resizeListBox(BUtilities::Point (80 * sz, 120 * sz));
281 spinTypeListbox.moveListBox(BUtilities::Point (0, -120 * sz));
282 spinTypeListbox.resizeListBoxItems(BUtilities::Point (80 * sz, 20 * sz));
283 RESIZE (spinAmountSlider, 660, 485, 80, 20, sz);
284
285 for (int i = 0; i < NR_FX; ++i)
286 {
287 RESIZE (fx[i].container, 20 + int (i / 2) * 660, 100 + int (((i + 1) & 3) / 2) * 200, 300, 160, sz);
288 RESIZE (fx[i].paramDials[0], 0, 10, 60, 60, sz);
289 RESIZE (fx[i].paramLabels[0], 0, 70, 60, 20, sz);
290 RESIZE (fx[i].paramDials[1], 80, 10, 60, 60, sz);
291 RESIZE (fx[i].paramLabels[1], 80, 70, 60, 20, sz);
292 RESIZE (fx[i].paramDials[2], 160, 10, 60, 60, sz);
293 RESIZE (fx[i].paramLabels[2], 160, 70, 60, 20, sz);
294 RESIZE (fx[i].paramDials[3], 240, 10, 60, 60, sz);
295 RESIZE (fx[i].paramLabels[3], 240, 70, 60, 20, sz);
296 RESIZE (fx[i].paramDials[4], 40, 70, 60, 60, sz);
297 RESIZE (fx[i].paramLabels[4], 40, 130, 60, 20, sz);
298 RESIZE (fx[i].paramDials[5], 200, 70, 60, 60, sz);
299 RESIZE (fx[i].paramLabels[5], 200, 130, 60, 20, sz);
300 }
301
302 // Apply changes
303 applyTheme (theme);
304 show ();
305 }
306
applyTheme(BStyles::Theme & theme)307 void BAngrGUI::applyTheme (BStyles::Theme& theme)
308 {
309 mContainer.applyTheme (theme);
310 cursor.applyTheme (theme);
311 poweredLabel.applyTheme (theme);
312 helpButton.applyTheme (theme);
313 ytButton.applyTheme (theme);
314 bypassButton.applyTheme (theme);
315 bypassLabel.applyTheme (theme);
316 drywetDial.applyTheme (theme);
317 drywetLabel.applyTheme (theme);
318 speedDial.applyTheme (theme);
319 speedLabel.applyTheme (theme);
320 spinDial.applyTheme (theme);
321 spinLabel.applyTheme (theme);
322 speedScreen.applyTheme (theme);
323 speedFlexLabel.applyTheme (theme);
324 speedTypeListbox.applyTheme (theme);
325 speedAmountSlider.applyTheme (theme);
326 spinScreen.applyTheme (theme);
327 spinFlexLabel.applyTheme (theme);
328 spinTypeListbox.applyTheme (theme);
329 spinAmountSlider.applyTheme (theme);
330
331 for (Fx& f : fx)
332 {
333 for (Dial& d : f.paramDials) d.applyTheme (theme);
334 for (BWidgets::Label& l : f.paramLabels) l.applyTheme (theme);
335 }
336 }
337
onConfigureRequest(BEvents::ExposeEvent * event)338 void BAngrGUI::onConfigureRequest (BEvents::ExposeEvent* event)
339 {
340 Window::onConfigureRequest (event);
341
342 sz = (getWidth() / 1000 > getHeight() / 560 ? getHeight() / 560 : getWidth() / 1000);
343 resizeGUI ();
344 }
345
sendCursor()346 void BAngrGUI::sendCursor ()
347 {
348 sendCursorOn();
349 sendXCursor();
350 sendYCursor();
351 }
352
sendXCursor()353 void BAngrGUI::sendXCursor ()
354 {
355 uint8_t obj_buf[128];
356 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
357
358 LV2_Atom_Forge_Frame frame;
359 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, urids.patch_Set);
360 lv2_atom_forge_key(&forge, urids.patch_property);
361 lv2_atom_forge_urid(&forge, urids.bangr_xcursor);
362 lv2_atom_forge_key(&forge, urids.patch_value);
363 lv2_atom_forge_float(&forge, ((cursor.getPosition().x + 0.5 * cursor.getWidth()) / sz - 400.0) / 200.0);
364 lv2_atom_forge_pop(&forge, &frame);
365 write_function(controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
366 }
367
sendYCursor()368 void BAngrGUI::sendYCursor ()
369 {
370 uint8_t obj_buf[128];
371 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
372
373 LV2_Atom_Forge_Frame frame;
374 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, urids.patch_Set);
375 lv2_atom_forge_key(&forge, urids.patch_property);
376 lv2_atom_forge_urid(&forge, urids.bangr_ycursor);
377 lv2_atom_forge_key(&forge, urids.patch_value);
378 lv2_atom_forge_float(&forge, ((cursor.getPosition().y + 0.5 * cursor.getHeight()) / sz - 180.0) / 200.0);
379 lv2_atom_forge_pop(&forge, &frame);
380 write_function(controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
381 }
382
sendCursorOn()383 void BAngrGUI::sendCursorOn ()
384 {
385 uint8_t obj_buf[64];
386 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
387
388 LV2_Atom_Forge_Frame frame;
389 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, urids.bangr_cursorOn);
390 lv2_atom_forge_pop(&forge, &frame);
391 write_function(controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
392 }
393
sendCursorOff()394 void BAngrGUI::sendCursorOff ()
395 {
396 uint8_t obj_buf[64];
397 lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
398
399 LV2_Atom_Forge_Frame frame;
400 LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, urids.bangr_cursorOff);
401 lv2_atom_forge_pop(&forge, &frame);
402 write_function(controller, CONTROL, lv2_atom_total_size(msg), urids.atom_eventTransfer, msg);
403 }
404
valueChangedCallback(BEvents::Event * event)405 void BAngrGUI::valueChangedCallback (BEvents::Event* event)
406 {
407 if (!event) return;
408 BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
409 if (!widget) return;
410 float value = widget->getValue();
411 BAngrGUI* ui = (BAngrGUI*) widget->getMainWindow();
412 if (!ui) return;
413
414 int controllerNr = -1;
415
416 // Identify controller
417 for (int i = 0; i < NR_CONTROLLERS; ++i)
418 {
419 if (widget == ui->controllerWidgets[i])
420 {
421 controllerNr = i;
422 break;
423 }
424 }
425
426 // Controllers
427 if (controllerNr >= 0)
428 {
429 if (controllerNr == SPEED_TYPE)
430 {
431 if (value == RANDOM) ui->speedScreen.show();
432 else ui->speedScreen.hide();
433 }
434
435 if (controllerNr == SPIN_TYPE)
436 {
437 if (value == RANDOM) ui->spinScreen.show();
438 else ui->spinScreen.hide();
439 }
440
441 ui->write_function(ui->controller, CONTROLLERS + controllerNr, sizeof(float), 0, &value);
442 }
443 }
444
cursorDraggedCallback(BEvents::Event * event)445 void BAngrGUI::cursorDraggedCallback (BEvents::Event* event)
446 {
447 if (!event) return;
448 BEvents::PointerEvent* pev = (BEvents::PointerEvent*)event;
449 Dot* widget = (Dot*) event->getWidget ();
450 if (!widget) return;
451 BAngrGUI* ui = (BAngrGUI*) widget->getMainWindow();
452 if (!ui) return;
453 if (widget != &ui->cursor) return;
454
455 double x = ui->cursor.getPosition().x + 0.5 * ui->cursor.getWidth() + pev->getDelta().x;
456 double y = ui->cursor.getPosition().y + 0.5 * ui->cursor.getHeight() + pev->getDelta().y;
457
458 if (x < 400 * ui->sz) x = 400 * ui->sz;
459 if (x > 600 * ui->sz) x = 600 * ui->sz;
460 if (y < 180 * ui->sz) y = 180 * ui->sz;
461 if (y > 380 * ui->sz) y = 380 * ui->sz;
462
463 ui->cursor.moveTo (x - 0.5 * ui->cursor.getWidth(), y - 0.5 * ui->cursor.getHeight());
464 ui->sendCursor();
465 }
466
cursorReleasedCallback(BEvents::Event * event)467 void BAngrGUI::cursorReleasedCallback (BEvents::Event* event)
468 {
469 if (!event) return;
470 //BEvents::PointerEvent* pev = (BEvents::PointerEvent*)event;
471 Dot* widget = (Dot*) event->getWidget ();
472 if (!widget) return;
473 BAngrGUI* ui = (BAngrGUI*) widget->getMainWindow();
474 if (!ui) return;
475 if (widget != &ui->cursor) return;
476
477 ui->sendCursorOff();
478 }
479
xregionClickedCallback(BEvents::Event * event)480 void BAngrGUI::xregionClickedCallback (BEvents::Event* event)
481 {
482 char cmd[] = WWW_BROWSER_CMD;
483 char param[] = XREGION_URL;
484 char* argv[] = {cmd, param, NULL};
485 std::cerr << "BAngr.lv2#GUI: Call " << XREGION_URL << " for Airwindows XRegion.\n";
486 if (BUtilities::vsystem (argv) == -1) std::cerr << "BAngr.lv2#GUI: Couldn't fork.\n";
487 }
488
helpButtonClickedCallback(BEvents::Event * event)489 void BAngrGUI::helpButtonClickedCallback (BEvents::Event* event)
490 {
491 char cmd[] = WWW_BROWSER_CMD;
492 char param[] = HELP_URL;
493 char* argv[] = {cmd, param, NULL};
494 std::cerr << "BAngr.lv2#GUI: Call " << HELP_URL << " for help.\n";
495 if (BUtilities::vsystem (argv) == -1) std::cerr << "BAngr.lv2#GUI: Couldn't fork.\n";
496 }
497
ytButtonClickedCallback(BEvents::Event * event)498 void BAngrGUI::ytButtonClickedCallback (BEvents::Event* event)
499 {
500 char cmd[] = WWW_BROWSER_CMD;
501 char param[] = YT_URL;
502 char* argv[] = {cmd, param, NULL};
503 std::cerr << "BAngr.lv2#GUI: Call " << YT_URL << " for preview video.\n";
504 if (BUtilities::vsystem (argv) == -1) std::cerr << "BAngr.lv2#GUI: Couldn't fork.\n";
505 }
506
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)507 static LV2UI_Handle instantiate (const LV2UI_Descriptor *descriptor, const char *plugin_uri, const char *bundle_path,
508 LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget *widget,
509 const LV2_Feature *const *features)
510 {
511 PuglNativeView parentWindow = 0;
512 LV2UI_Resize* resize = NULL;
513
514 if (strcmp(plugin_uri, BANGR_URI) != 0)
515 {
516 std::cerr << "BAngr.lv2#GUI: GUI does not support plugin with URI " << plugin_uri << std::endl;
517 return NULL;
518 }
519
520 for (int i = 0; features[i]; ++i)
521 {
522 if (!strcmp(features[i]->URI, LV2_UI__parent)) parentWindow = (PuglNativeView) features[i]->data;
523 else if (!strcmp(features[i]->URI, LV2_UI__resize)) resize = (LV2UI_Resize*)features[i]->data;
524 }
525 if (parentWindow == 0) std::cerr << "BAngr.lv2#GUI: No parent window.\n";
526
527 // New instance
528 BAngrGUI* ui;
529 try {ui = new BAngrGUI (bundle_path, features, parentWindow);}
530 catch (std::exception& exc)
531 {
532 std::cerr << "BAngr.lv2#GUI: Instantiation failed. " << exc.what () << std::endl;
533 return NULL;
534 }
535
536 ui->controller = controller;
537 ui->write_function = write_function;
538
539 // Reduce min GUI size for small displays
540 double sz = 1.0;
541 int screenWidth = getScreenWidth ();
542 int screenHeight = getScreenHeight ();
543 if ((screenWidth < 1040) || (screenHeight < 600)) sz = 0.66;
544
545 /*
546 std::cerr << "BAngrGUI.lv2 screen size " << screenWidth << " x " << screenHeight <<
547 ". Set GUI size to " << 800 * sz << " x " << 560 * sz << ".\n";
548 */
549
550 if (resize) resize->ui_resize(resize->handle, 1000 * sz, 560 * sz);
551
552 *widget = (LV2UI_Widget) puglGetNativeWindow (ui->getPuglView ());
553 return (LV2UI_Handle) ui;
554 }
555
cleanup(LV2UI_Handle ui)556 static void cleanup(LV2UI_Handle ui)
557 {
558 BAngrGUI* pluginGui = (BAngrGUI*) ui;
559 if (pluginGui) delete pluginGui;
560 }
561
portEvent(LV2UI_Handle ui,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)562 static void portEvent(LV2UI_Handle ui, uint32_t port_index, uint32_t buffer_size,
563 uint32_t format, const void* buffer)
564 {
565 BAngrGUI* pluginGui = (BAngrGUI*) ui;
566 if (pluginGui) pluginGui->portEvent(port_index, buffer_size, format, buffer);
567 }
568
callIdle(LV2UI_Handle ui)569 static int callIdle (LV2UI_Handle ui)
570 {
571 BAngrGUI* pluginGui = (BAngrGUI*) ui;
572 if (pluginGui) pluginGui->handleEvents ();
573 return 0;
574 }
575
callResize(LV2UI_Handle ui,int width,int height)576 static int callResize (LV2UI_Handle ui, int width, int height)
577 {
578 BAngrGUI* self = (BAngrGUI*) ui;
579 if (!self) return 0;
580
581 BEvents::ExposeEvent* ev = new BEvents::ExposeEvent (self, self, BEvents::CONFIGURE_REQUEST_EVENT, self->getPosition().x, self->getPosition().y, width, height);
582 self->addEventToQueue (ev);
583 return 0;
584 }
585
586 static const LV2UI_Idle_Interface idle = {callIdle};
587 static const LV2UI_Resize resize = {nullptr, callResize};
588
extensionData(const char * uri)589 static const void* extensionData(const char* uri)
590 {
591 if (!strcmp(uri, LV2_UI__idleInterface)) return &idle;
592 else if(!strcmp(uri, LV2_UI__resize)) return &resize;
593 else return NULL;
594 }
595
596 static const LV2UI_Descriptor guiDescriptor =
597 {
598 BANGR_GUI_URI,
599 instantiate,
600 cleanup,
601 portEvent,
602 extensionData
603 };
604
605 // LV2 Symbol Export
lv2ui_descriptor(uint32_t index)606 LV2_SYMBOL_EXPORT const LV2UI_Descriptor *lv2ui_descriptor(uint32_t index)
607 {
608 switch (index) {
609 case 0: return &guiDescriptor;
610 default:return NULL;
611 }
612 }
613