1 /* B.Slizr
2  * Step Sequencer Effect Plugin
3  *
4  * Copyright (C) 2018, 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 <string>
22 #include <iostream>
23 #include <cstdlib>
24 #include <cmath>
25 #include <exception>
26 #include <map>
27 #include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
28 #include <lv2/lv2plug.in/ns/ext/atom/atom.h>
29 #include <lv2/lv2plug.in/ns/ext/atom/forge.h>
30 #include "BWidgets/Widget.hpp"
31 #include "BWidgets/Window.hpp"
32 #include "BWidgets/Label.hpp"
33 #include "BWidgets/DrawingSurface.hpp"
34 #include "BWidgets/HSwitch.hpp"
35 #include "BWidgets/VSlider.hpp"
36 #include "BWidgets/VSliderValue.hpp"
37 #include "BWidgets/HSliderValue.hpp"
38 #include "BWidgets/DialValue.hpp"
39 
40 #include "main.h"
41 #include "screen.h"
42 
43 #ifdef LOCALEFILE
44 #include LOCALEFILE
45 #else
46 #include "Locale_EN.hpp"
47 #endif
48 
49 #ifdef SKINFILE
50 #include SKINFILE
51 #else
52 #include "Skin_Default.hpp"
53 #endif
54 
55 #ifndef MESSAGENR_
56 #define MESSAGENR_
57 enum MessageNr
58 {
59 	NO_MSG		= 0,
60 	JACK_STOP_MSG	= 1,
61 	MAX_MSG		= 1
62 };
63 #endif /* MESSAGENR_ */
64 
65 #define SCALEMIN -60
66 #define SCALEMAX 30
67 #define BG_FILE "surface.png"
68 
69 #define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f)
70 #define CO_DB(g) ((g) > 0.0001f ? logf((g)) / 0.05f : -90.0f)
71 #define LIM(g , max) ((g) > (max) ? (max) : (g))
72 #define INT(g) (int) (g + 0.5)
73 #define RESIZE(widget, x, y, w, h, sz) (widget).moveTo ((x) * (sz), (y) * (sz)); (widget).resize ((w) * (sz), (h) * (sz));
74 
75 const std::string messageStrings[MAX_MSG + 1] =
76 {
77 	"",
78 	"*** " BSLIZR_LABEL_JACK_STOP " ***"
79 };
80 
81 class BSlizr_GUI : public BWidgets::Window
82 {
83 public:
84 	BSlizr_GUI (const char *bundle_path, const LV2_Feature *const *features, PuglNativeView parentWindow);
85 	~BSlizr_GUI ();
86 	void portEvent (uint32_t port_index, uint32_t buffer_size, uint32_t format, const void *buffer);
87 	void send_record_on ();
88 	void send_record_off ();
89 	virtual void onConfigureRequest (BEvents::ExposeEvent* event) override;
90 	void applyTheme (BStyles::Theme& theme) override;
91 
92 	LV2UI_Controller controller;
93 	LV2UI_Write_Function write_function;
94 
95 
96 private:
97 	void resizeGUI ();
98 	void rearrange_step_controllers (float nrSteps_newf);
99 	static void valueChangedCallback (BEvents::Event* event);
100 	bool init_Stepshape ();
101 	void destroy_Stepshape ();
102 	void redrawStepshape ();
103 	bool init_mainMonitor ();
104 	void destroy_mainMonitor ();
105 	void add_monitor_data (BSlizrNotifications* notifications, uint32_t notificationsCount, uint32_t& end);
106 	void redrawMainMonitor ();
107 
108 
109 	BWidgets::Widget mContainer;
110 	BWidgets::Widget sContainer;
111 	BWidgets::HSwitch monitorSwitch;
112 	BWidgets::DrawingSurface monitorDisplay;
113 	BWidgets::Label monitorLabel;
114 	BWidgets::VSlider scaleControl;
115 	BWidgets::DrawingSurface stepshapeDisplay;
116 	BWidgets::DialValue attackControl;
117 	BWidgets::Label attackLabel;
118 	BWidgets::DialValue releaseControl;
119 	BWidgets::Label releaseLabel;
120 	BWidgets::HSliderValue sequencesperbarControl;
121 	BWidgets::Label sequencesperbarLabel;
122 	BWidgets::HSliderValue nrStepsControl;
123 	BWidgets::Label nrStepsLabel;
124 	BWidgets::Label stepshapeLabel;
125 	BWidgets::Label sequencemonitorLabel;
126 	BWidgets::Label messageLabel;
127 	std::array<BWidgets::VSliderValue, MAXSTEPS> stepControl;
128 
129 	cairo_surface_t* surface;
130 	cairo_t* cr1;
131 	cairo_t* cr2;
132 	cairo_t* cr3;
133 	cairo_t* cr4;
134 	cairo_pattern_t* pat1;
135 	cairo_pattern_t* pat2;
136 	cairo_pattern_t* pat3;
137 	cairo_pattern_t* pat4;
138 	cairo_pattern_t* pat5;
139 
140 	struct
141 	{
142 		bool record_on;
143 		uint32_t width;
144 		uint32_t height;
145 		std::array<BSlizrNotifications, MONITORBUFFERSIZE> data;
146 		uint32_t horizonPos;
147 	}  mainMonitor;
148 
149 	std::string pluginPath;
150 	double sz;
151 	cairo_surface_t* bgImageSurface;
152 
153 	float scale;
154 	float attack;
155 	float release;
156 	float nrSteps;
157 	float sequencesperbar;
158 	std::array<float, MAXSTEPS> step;
159 
160 	LV2_Atom_Forge forge;
161 	BSlizrURIs uris;
162 	LV2_URID_Map* map;
163 
164 
165 
166 	// Definition of styles
167 	BColors::ColorSet fgColors = BSLIZR_FG_COLORS;
168 	BColors::ColorSet txColors = BSLIZR_TX_COLORS;
169 	BColors::ColorSet bgColors = BSLIZR_BG_COLORS;
170 	BColors::Color ink = {0.0, 0.75, 0.2, 1.0};
171 
172 	BStyles::Border border = {{ink, 1.0}, 0.0, 2.0, 0.0};
173 	BStyles::Fill widgetBg = BStyles::noFill;
174 	BStyles::Fill screenBg = BStyles::Fill (BColors::Color (BSLIZR_SCREEN_BG_COLORS));
175 	BStyles::Border screenBorder = BStyles::Border (BStyles::Line (BColors::Color (0.0, 0.0, 0.0, 0.75), 4.0));
176 	BStyles::Font defaultFont = BStyles::Font ("Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL, 12.0,
177 						   BStyles::TEXT_ALIGN_CENTER, BStyles::TEXT_VALIGN_MIDDLE);
178 	BStyles::StyleSet defaultStyles = {"default", {{"background", STYLEPTR (&BStyles::noFill)},
179 						       {"border", STYLEPTR (&BStyles::noBorder)}}};
180 	BStyles::StyleSet labelStyles = {"labels", {{"background", STYLEPTR (&BStyles::noFill)},
181 						    {"border", STYLEPTR (&BStyles::noBorder)},
182 						    {"textcolors", STYLEPTR (&txColors)},
183 						    {"font", STYLEPTR (&defaultFont)}}};
184 
185 	BStyles::Theme theme = BStyles::Theme ({
186 		defaultStyles,
187 		{"B.Slizr", 	{{"background", STYLEPTR (&BStyles::blackFill)},
188 				 {"border", STYLEPTR (&BStyles::noBorder)}}},
189 		{"main", 	{{"background", STYLEPTR (&widgetBg)},
190 				 {"border", STYLEPTR (&BStyles::noBorder)}}},
191 		{"widget", 	{{"uses", STYLEPTR (&defaultStyles)}}},
192 		{"monitor", 	{{"background", STYLEPTR (&BStyles::blackFill)},
193 				 {"border", STYLEPTR (&border)}}},
194 		{"dial", 	{{"uses", STYLEPTR (&defaultStyles)},
195 				 {"fgcolors", STYLEPTR (&fgColors)},
196 				 {"bgcolors", STYLEPTR (&bgColors)},
197 				 {"textcolors", STYLEPTR (&fgColors)},
198 				 {"font", STYLEPTR (&defaultFont)}}},
199 		{"dial/focus", 	{{"background", STYLEPTR (&screenBg)},
200 				 {"border", STYLEPTR (&screenBorder)},
201 				 {"textcolors", STYLEPTR (&txColors)},
202 				 {"font", STYLEPTR (&defaultFont)}}},
203 		{"slider",	{{"uses", STYLEPTR (&defaultStyles)},
204 				 {"fgcolors", STYLEPTR (&fgColors)},
205 				 {"bgcolors", STYLEPTR (&bgColors)},
206 				 {"textcolors", STYLEPTR (&fgColors)},
207 				 {"font", STYLEPTR (&defaultFont)}}},
208 		{"slider/focus",{{"background", STYLEPTR (&screenBg)},
209 				 {"border", STYLEPTR (&screenBorder)},
210 				 {"textcolors", STYLEPTR (&txColors)},
211 				 {"font", STYLEPTR (&defaultFont)}}},
212 		{"switch",	{{"uses", STYLEPTR (&defaultStyles)},
213 				 {"fgcolors", STYLEPTR (&fgColors)},
214 				 {"bgcolors", STYLEPTR (&bgColors)}}},
215 		{"switch/focus",{{"background", STYLEPTR (&screenBg)},
216 				 {"border", STYLEPTR (&screenBorder)},
217 				 {"textcolors", STYLEPTR (&txColors)},
218 				 {"font", STYLEPTR (&defaultFont)}}},
219 		{"label",	{{"uses", STYLEPTR (&labelStyles)}}},
220 		{"hilabel",	{{"uses", STYLEPTR (&labelStyles)},
221 				 {"textcolors", STYLEPTR (&BColors::whites)}}},
222 	});
223 };
224 
225 
BSlizr_GUI(const char * bundle_path,const LV2_Feature * const * features,PuglNativeView parentWindow)226 BSlizr_GUI::BSlizr_GUI (const char *bundle_path, const LV2_Feature *const *features, PuglNativeView parentWindow) :
227 	Window (800, 560, "B.Slizr", parentWindow, true, PUGL_MODULE, 0),
228 	controller (NULL), write_function (NULL),
229 	mContainer (0, 0, 800, 560, "main"),
230 	sContainer (260, 330, 480, 130, "widget"),
231 	monitorSwitch (690, 25, 40, 16, "switch", 0.0),
232 	monitorDisplay (260, 70, 480, 240, "monitor"),
233 	monitorLabel (680, 45, 60, 20, "label", BSLIZR_LABEL_MONITOR),
234 	scaleControl (760, 80, 14, 230, "slider", 0.0, SCALEMIN, SCALEMAX, 0.1),
235 	stepshapeDisplay (30, 320, 180, 140, "monitor"),
236 	attackControl (40, 465, 50, 60, "dial", 0.2, 0.01, 1.0, 0.01, "%1.2f"),
237 	attackLabel (20, 520, 90, 20, "label", BSLIZR_LABEL_ATTACK),
238 	releaseControl (150, 465, 50, 60, "dial", 0.2, 0.01, 1.0, -0.01, "%1.2f"),
239 	releaseLabel (130, 520, 90, 20, "label", BSLIZR_LABEL_RELEASE),
240 	sequencesperbarControl (260, 492, 120, 28, "slider", 1.0, 1.0, 8.0, 1.0, "%1.0f"),
241 	sequencesperbarLabel (250, 520, 140, 20, "label", BSLIZR_LABEL_SEQUENCES_PER_BAR),
242 	nrStepsControl (400, 492, 380, 28, "slider", 1.0, 1.0, MAXSTEPS, 1.0, "%2.0f"),
243 	nrStepsLabel (400, 520, 380, 20, "label", BSLIZR_LABEL_NUMBER_OF_STEPS),
244 	stepshapeLabel (33, 323, 100, 20, "label", BSLIZR_LABEL_STEP_SHAPE),
245 	sequencemonitorLabel (263, 73, 140, 20, "label", BSLIZR_LABEL_SEQUENCE_MONITOR),
246 	messageLabel (420, 73, 280, 20, "hilabel", ""),
247 
248 	surface (NULL), cr1 (NULL), cr2 (NULL), cr3 (NULL), cr4 (NULL), pat1 (NULL), pat2 (NULL), pat3 (NULL), pat4 (NULL), pat5 (NULL),
249 	pluginPath (bundle_path ? std::string (bundle_path) : std::string ("")),  sz (1.0), bgImageSurface (nullptr),
250 	scale (DB_CO(0.0)), attack (0.2), release (0.2), nrSteps (16.0), sequencesperbar (4.0), step (),
251 	map (NULL)
252 
253 
254 {
255 	if (!init_mainMonitor () || !init_Stepshape ())
256 	{
257 		std::cerr << "BSlizr.lv2#GUI: Failed to init monitor." <<  std::endl;
258 		destroy_mainMonitor ();
259 		destroy_Stepshape ();
260 		throw std::bad_alloc ();
261 	}
262 
263 	//Initialialize and configure stepControllers
264 	for (int i = 0; i < MAXSTEPS; ++i)
265 	{
266 		stepControl[i] = BWidgets::VSliderValue ((i + 0.5) * 480 / MAXSTEPS - 10, 0, 28, 130, "slider", 1.0, 0.0, 1.0, 0.01, "%1.2f");
267 		stepControl[i].setHardChangeable (false);
268 		stepControl[i].setScrollable (true);
269 		stepControl[i].rename ("slider");
270 		stepControl[i].setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
271 		stepControl[i].applyTheme (theme, "slider");
272 		stepControl[i].getDisplayLabel ()->setState (BColors::ACTIVE);
273 		sContainer.add (stepControl[i]);
274 	}
275 
276 	// Set callbacks
277 	monitorSwitch.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
278 	scaleControl.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
279 	attackControl.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
280 	releaseControl.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
281 	sequencesperbarControl.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
282 	nrStepsControl.setCallbackFunction (BEvents::EventType::VALUE_CHANGED_EVENT, BSlizr_GUI::valueChangedCallback);
283 
284 	// Configure widgets
285 	bgImageSurface = cairo_image_surface_create_from_png ((pluginPath + BG_FILE).c_str());
286 	widgetBg.loadFillFromCairoSurface (bgImageSurface);
287 	scaleControl.setScrollable (true);
288 	attackControl.setScrollable (true);
289 	attackControl.setHardChangeable (false);
290 	releaseControl.setScrollable (true);
291 	releaseControl.setHardChangeable (false);
292 	sequencesperbarControl.setScrollable (true);
293 	nrStepsControl.setScrollable (true);
294 	applyTheme (theme);
295 
296 	// Pack widgets
297 	mContainer.add (monitorSwitch);
298 	mContainer.add (monitorDisplay);
299 	mContainer.add (monitorLabel);
300 	mContainer.add (scaleControl);
301 	mContainer.add (stepshapeDisplay);
302 	mContainer.add (attackControl);
303 	mContainer.add (attackLabel);
304 	mContainer.add (releaseControl);
305 	mContainer.add (releaseLabel);
306 	mContainer.add (sequencesperbarControl);
307 	mContainer.add (sequencesperbarLabel);
308 	mContainer.add (nrStepsControl);
309 	mContainer.add (nrStepsLabel);
310 	mContainer.add (stepshapeLabel);
311 	mContainer.add (sequencemonitorLabel);
312 	mContainer.add (messageLabel);
313 	mContainer.add (sContainer);
314 	add (mContainer);
315 
316 	//Scan host features for URID map
317 	LV2_URID_Map* m = NULL;
318 	for (int i = 0; features[i]; ++i)
319 	{
320 		if (strcmp(features[i]->URI, LV2_URID__map) == 0) m = (LV2_URID_Map*) features[i]->data;
321 	}
322 	if (!m) throw std::invalid_argument ("Host does not support urid:map");
323 
324 	//Map URIS
325 	map = m;
326 	getURIs (map, &uris);
327 
328 	// Initialize forge
329 	lv2_atom_forge_init (&forge,map);
330 }
331 
~BSlizr_GUI()332 BSlizr_GUI::~BSlizr_GUI()
333 {
334 	send_record_off ();
335 	destroy_mainMonitor ();
336 	destroy_Stepshape ();
337 }
338 
portEvent(uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)339 void BSlizr_GUI::portEvent(uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
340 {
341 	// Notify port
342 	if ((format == uris.atom_eventTransfer) && (port_index == Notify))
343 	{
344 		const LV2_Atom* atom = (const LV2_Atom*) buffer;
345 		if ((atom->type == uris.atom_Blank) || (atom->type == uris.atom_Object))
346 		{
347 			const LV2_Atom_Object* obj = (const LV2_Atom_Object*) atom;
348 
349 			// Monitor notification
350 			if (obj->body.otype == uris.notify_event)
351 			{
352 				const LV2_Atom* data = NULL;
353 				lv2_atom_object_get(obj, uris.notify_key, &data, 0);
354 				if (data && (data->type == uris.atom_Vector))
355 				{
356 					const LV2_Atom_Vector* vec = (const LV2_Atom_Vector*) data;
357 					if (vec->body.child_type == uris.atom_Float)
358 					{
359 						uint32_t notificationsCount = (uint32_t) ((data->size - sizeof(LV2_Atom_Vector_Body)) / sizeof (BSlizrNotifications));
360 						BSlizrNotifications* notifications = (BSlizrNotifications*) (&vec->body + 1);
361 						if (notificationsCount > 0)
362 						{
363 							add_monitor_data (notifications, notificationsCount, mainMonitor.horizonPos);
364 							redrawMainMonitor ();
365 						}
366 					}
367 				}
368 				else std::cerr << "BSlizr.lv2#GUI: Corrupt audio message." << std::endl;
369 			}
370 
371 			// Message notification
372 			else if (obj->body.otype == uris.notify_messageEvent)
373 			{
374 				const LV2_Atom* data = NULL;
375 				lv2_atom_object_get(obj, uris.notify_message, &data, 0);
376 				if (data && (data->type == uris.atom_Int))
377 				{
378 					const int messageNr = ((LV2_Atom_Int*)data)->body;
379 					std::string msg = ((messageNr >= NO_MSG) && (messageNr <= MAX_MSG) ? messageStrings[messageNr] : "");
380 					messageLabel.setText (msg);
381 				}
382 			}
383 		}
384 	}
385 
386 	// Scan remaining ports
387 	else if ((format == 0) && (port_index >= Attack) && (port_index < Step_ + MAXSTEPS))
388 	{
389 	float* pval = (float*) buffer;
390 	switch (port_index) {
391 		case Attack:
392 			attack = *pval;
393 			attackControl.setValue (*pval);
394 			break;
395 		case Release:
396 			release = *pval;
397 			releaseControl.setValue (*pval);
398 			break;
399 		case SequencesPerBar:
400 			sequencesperbar = *pval;
401 			sequencesperbarControl.setValue (*pval);
402 			break;
403 		case NrSteps:
404 			if (nrSteps != *pval)
405 			{
406 				rearrange_step_controllers (*pval);
407 				nrSteps = *pval;
408 			}
409 			redrawMainMonitor ();
410 			nrStepsControl.setValue (*pval);
411 			break;
412 		default:
413 			if ((port_index >= Step_) and (port_index < Step_ + MAXSTEPS))
414 			{
415 				step[port_index-Step_] = *pval;
416 				stepControl[port_index-Step_].setValue (*pval);
417 			}
418 		}
419 	}
420 
421 }
422 
resizeGUI()423 void BSlizr_GUI::resizeGUI()
424 {
425 	hide ();
426 
427 	// Resize Fonts
428 	defaultFont.setFontSize (12 * sz);
429 
430 	// Resize Background
431 	cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800 * sz, 560 * sz);
432 	cairo_t* cr = cairo_create (surface);
433 	cairo_scale (cr, sz, sz);
434 	cairo_set_source_surface(cr, bgImageSurface, 0, 0);
435 	cairo_paint(cr);
436 	widgetBg.loadFillFromCairoSurface(surface);
437 	cairo_destroy (cr);
438 	cairo_surface_destroy (surface);
439 
440 	// Resize widgets
441 	RESIZE (mContainer, 0, 0, 800, 560, sz);
442 	RESIZE (monitorSwitch, 690, 25, 40, 16, sz);
443 	RESIZE (monitorDisplay, 260, 70, 480, 240, sz);
444 	RESIZE (monitorLabel, 680, 45, 60, 20, sz);
445 	RESIZE (scaleControl, 760, 80, 14, 230, sz);
446 	RESIZE (stepshapeDisplay, 30, 320, 180, 140, sz);
447 	RESIZE (attackControl, 40, 465, 50, 60, sz);
448 	RESIZE (attackLabel, 20, 520, 90, 20, sz);
449 	RESIZE (releaseControl, 150, 465, 50, 60, sz);
450 	RESIZE (releaseLabel, 130, 520, 90, 20, sz);
451 	RESIZE (sequencesperbarControl, 260, 492, 120, 28, sz);
452 	RESIZE (sequencesperbarLabel, 250, 520, 140, 20, sz);
453 	RESIZE (nrStepsControl, 400, 492, 380, 28, sz);
454 	RESIZE (nrStepsLabel, 400, 520, 380, 20, sz);
455 	RESIZE (stepshapeLabel, 33, 323, 100, 20, sz);
456 	RESIZE (sequencemonitorLabel, 263, 73, 140, 20, sz);
457 	RESIZE (messageLabel, 420, 73, 280, 20,sz);
458 	RESIZE (sContainer, 260, 330, 480, 130, sz);
459 	for (int i = 0; i < MAXSTEPS; ++i) {RESIZE (stepControl[i], (i + 0.5) * 480 / nrSteps - 10, 0, 28, 130, sz);}
460 
461 	// Update monitors
462 	destroy_Stepshape ();
463 	init_Stepshape ();
464 	redrawStepshape ();
465 	destroy_mainMonitor ();
466 	init_mainMonitor ();
467 	redrawMainMonitor ();
468 
469 	// Apply changes
470 	applyTheme (theme);
471 	show ();
472 }
473 
applyTheme(BStyles::Theme & theme)474 void BSlizr_GUI::applyTheme (BStyles::Theme& theme)
475 {
476 	mContainer.applyTheme (theme);
477 	monitorSwitch.applyTheme (theme);
478 	monitorDisplay.applyTheme (theme);
479 	monitorLabel.applyTheme (theme);
480 	scaleControl.applyTheme (theme);
481 	stepshapeDisplay.applyTheme (theme);
482 	attackControl.applyTheme (theme);
483 	attackLabel.applyTheme (theme);
484 	releaseControl.applyTheme (theme);
485 	releaseLabel.applyTheme (theme);
486 	sequencesperbarControl.applyTheme (theme);
487 	sequencesperbarLabel.applyTheme (theme);
488 	nrStepsControl.applyTheme (theme);
489 	nrStepsLabel.applyTheme (theme);
490 	stepshapeLabel.applyTheme (theme);
491 	sequencemonitorLabel.applyTheme (theme);
492 	messageLabel.applyTheme (theme);
493 	sContainer.applyTheme (theme);
494 	for (int i = 0; i < MAXSTEPS; ++i)
495 	{
496 		stepControl[i].applyTheme (theme);
497 		stepControl[i].update ();	// TODO Remove if fixed in BWidgets TK
498 	}
499 }
500 
onConfigureRequest(BEvents::ExposeEvent * event)501 void BSlizr_GUI::onConfigureRequest (BEvents::ExposeEvent* event)
502 {
503 	Window::onConfigureRequest (event);
504 
505 	sz = (getWidth() / 800 > getHeight() / 560 ? getHeight() / 560 : getWidth() / 800);
506 	resizeGUI ();
507 }
508 
send_record_on()509 void BSlizr_GUI::send_record_on ()
510 {
511 	uint8_t obj_buf[64];
512 	lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
513 
514 	LV2_Atom_Forge_Frame frame;
515 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.ui_on);
516 	lv2_atom_forge_pop(&forge, &frame);
517 	write_function(controller, Control_2, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
518 	monitorSwitch.setValue (1.0);
519 }
520 
send_record_off()521 void BSlizr_GUI::send_record_off ()
522 {
523 	uint8_t obj_buf[64];
524 	lv2_atom_forge_set_buffer(&forge, obj_buf, sizeof(obj_buf));
525 
526 	LV2_Atom_Forge_Frame frame;
527 	LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_object(&forge, &frame, 0, uris.ui_off);
528 	lv2_atom_forge_pop(&forge, &frame);
529 	write_function(controller, Control_2, lv2_atom_total_size(msg), uris.atom_eventTransfer, msg);
530 	monitorSwitch.setValue (0.0);
531 }
532 
rearrange_step_controllers(float nrSteps_newf)533 void BSlizr_GUI::rearrange_step_controllers (float nrSteps_newf)
534 {
535 	int nrSteps_old = INT (nrSteps);
536 	int nrSteps_new = INT (nrSteps_newf);
537 
538 	if ((nrSteps_old < 1) || (nrSteps_old > MAXSTEPS) || (nrSteps_new < 1) || (nrSteps_old > MAXSTEPS)) return;
539 
540 	for (int i = 0; i < MAXSTEPS; ++i)
541 	{
542 		if (i < nrSteps_new)
543 		{
544 			stepControl[i].moveTo (((i + 0.5) * 480 / nrSteps_new - 10) * sz, 0);
545 			stepControl[i].show ();
546 		}
547 		else stepControl[i].hide ();
548 	}
549 }
550 
valueChangedCallback(BEvents::Event * event)551 void BSlizr_GUI::valueChangedCallback (BEvents::Event* event)
552 {
553 	if ((event) && (event->getWidget ()))
554 	{
555 		BWidgets::ValueWidget* widget = (BWidgets::ValueWidget*) event->getWidget ();
556 
557 		if (widget->getMainWindow ())
558 		{
559 			BSlizr_GUI* ui = (BSlizr_GUI*) widget->getMainWindow ();
560 
561 			// monitor on/off changed
562 			if (widget == &ui->monitorSwitch)
563 			{
564 				int value = INT (widget->getValue ());
565 				if (value == 1)
566 				{
567 					ui->mainMonitor.record_on = true;
568 					ui->send_record_on ();
569 				}
570 				else
571 				{
572 					ui->mainMonitor.record_on = false;
573 					ui->send_record_off ();
574 				}
575 				return;
576 			}
577 
578 			// Scale changed
579 			if (widget == &ui->scaleControl)
580 			{
581 				float value = (float) widget->getValue ();
582 				ui->scale = DB_CO (value);
583 				if (ui->scale < 0.0001f) ui->scale = 0.0001f;
584 				ui->redrawMainMonitor ();
585 			}
586 
587 			// Attack changed
588 			if (widget == &ui->attackControl)
589 			{
590 				ui->attack = (float) widget->getValue ();
591 				ui->write_function(ui->controller, Attack, sizeof(ui->attack), 0, &ui->attack);
592 				ui->redrawStepshape ();
593 				return;
594 			}
595 
596 			// Release changed
597 			if (widget == &ui->releaseControl)
598 			{
599 				ui->release = (float) widget->getValue ();
600 				ui->write_function(ui->controller, Release, sizeof(ui->release), 0, &ui->release);
601 				ui->redrawStepshape ();
602 				return;
603 			}
604 
605 			// Step size changed
606 			if (widget == &ui->sequencesperbarControl)
607 			{
608 				ui->sequencesperbar = (float) widget->getValue ();
609 				ui->write_function(ui->controller, SequencesPerBar, sizeof(ui->sequencesperbar), 0, &ui->sequencesperbar);
610 				return;
611 			}
612 
613 			// nrSteps changed
614 			if (widget == &ui->nrStepsControl)
615 			{
616 				float nrSteps_new = (float) widget->getValue ();
617 				if (nrSteps_new != ui->nrSteps) ui->rearrange_step_controllers (nrSteps_new);
618 				ui->nrSteps = nrSteps_new;
619 				ui->write_function(ui->controller, NrSteps, sizeof(ui->nrSteps), 0, &ui->nrSteps);
620 				ui->redrawMainMonitor ();
621 				return;
622 			}
623 
624 			// Step controllers changed
625 			for (int i = 0; i < ui->nrSteps; i++)
626 			{
627 				if (widget == &ui->stepControl[i])
628 				{
629 					ui->step[i] = (float) widget->getValue ();
630 					ui->write_function(ui->controller, Step_+i , sizeof(ui->step[i]), 0, &ui->step[i]);
631 					return;
632 				}
633 			}
634 		}
635 	}
636 }
637 
init_Stepshape()638 bool BSlizr_GUI::init_Stepshape ()
639 {
640 	double height = stepshapeDisplay.getEffectiveHeight ();
641 	pat5 = cairo_pattern_create_linear (0, 0, 0, height);
642 
643 	return (pat5 && (cairo_pattern_status (pat5) == CAIRO_STATUS_SUCCESS));
644 }
645 
destroy_Stepshape()646 void BSlizr_GUI::destroy_Stepshape ()
647 {
648 	//Destroy also mainMonitors cairo data
649 	if (pat5 && (cairo_pattern_status (pat5) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat5);
650 }
651 
redrawStepshape()652 void BSlizr_GUI::redrawStepshape ()
653 {
654 	double width = stepshapeDisplay.getEffectiveWidth ();
655 	double height = stepshapeDisplay.getEffectiveHeight ();
656 
657 	cairo_t* cr = cairo_create (stepshapeDisplay.getDrawingSurface ());
658 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
659 
660 	// Draw background
661 	cairo_set_source_rgba (cr, CAIRO_BG_COLOR);
662 	cairo_rectangle (cr, 0.0, 0.0, width, height);
663 	cairo_fill (cr);
664 	cairo_set_source_rgba (cr, CAIRO_BG_COLOR2);
665 	cairo_set_line_width (cr, 1);
666 	cairo_move_to (cr, 0, 0.2 * height);
667 	cairo_line_to (cr, width, 0.2 * height);
668 	cairo_move_to (cr, 0, 0.55 * height);
669 	cairo_line_to (cr, width, 0.55 * height);
670 	cairo_move_to (cr, 0, 0.9 * height);
671 	cairo_line_to (cr, width, 0.9 * height);
672 	cairo_move_to (cr, 0.25 * width, 0);
673 	cairo_line_to (cr, 0.25 * width, height);
674 	cairo_move_to (cr, 0.5 * width, 0);
675 	cairo_line_to (cr, 0.5 * width, height);
676 	cairo_move_to (cr, 0.75 * width, 0);
677 	cairo_line_to (cr, 0.75 * width, height);
678 	cairo_stroke (cr);
679 
680 	// Draw step shape
681 	cairo_set_source_rgba (cr, CAIRO_INK1, 1.0);
682 	cairo_set_line_width (cr, 3);
683 
684 	cairo_move_to (cr, 0, 0.9 * height);
685 	cairo_line_to (cr, width * 0.25, 0.9 * height);
686 	if ((attack + release) > 1)
687 	{
688 		float crosspointX = attack / (attack + release);
689 		float crosspointY = crosspointX / attack - (crosspointX - (1 - release)) / release;
690 		cairo_line_to (cr, width* 0.25 + crosspointX * width * 0.5, 0.9 * height - 0.7 * height * crosspointY);
691 	}
692 	else
693 	{
694 		cairo_line_to (cr, width * 0.25 + attack * width * 0.5 , 0.2 * height);
695 		cairo_line_to (cr, width * 0.75  - release * width * 0.5, 0.2 * height);
696 
697 	}
698 	cairo_line_to (cr, width * 0.75, 0.9 * height);
699 	cairo_line_to (cr, width, 0.9 * height);
700 
701 	cairo_stroke_preserve (cr);
702 
703 	cairo_pattern_add_color_stop_rgba (pat5, 0.1, CAIRO_INK1, 1);
704 	cairo_pattern_add_color_stop_rgba (pat5, 0.9, CAIRO_INK1, 0);
705 	cairo_set_source (cr, pat5);
706 	cairo_line_to(cr, 0, 0.9 * height);
707 	cairo_set_line_width (cr, 0);
708 	cairo_fill (cr);
709 
710 	cairo_destroy (cr);
711 
712 	stepshapeDisplay.update ();
713 }
714 
init_mainMonitor()715 bool BSlizr_GUI::init_mainMonitor ()
716 {
717 	//Initialize mainMonitor
718 	mainMonitor.record_on = true;
719 	mainMonitor.width = 0;
720 	mainMonitor.height = 0;
721 	mainMonitor.data.fill (defaultNotification);
722 	mainMonitor.horizonPos = 0;
723 
724 	//Initialize mainMonitors cairo data
725 	double width = monitorDisplay.getEffectiveWidth ();
726 	double height = monitorDisplay.getEffectiveHeight ();
727 	surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
728 	cr1 = cairo_create (surface);
729 	cr2 = cairo_create (surface);
730 	cr3 = cairo_create (surface);
731 	cr4 = cairo_create (surface);
732 	pat1 = cairo_pattern_create_linear (0, 0, 0, height);
733 	cairo_pattern_add_color_stop_rgba (pat1, 0.1, CAIRO_INK1, 1);
734 	cairo_pattern_add_color_stop_rgba (pat1, 0.6, CAIRO_INK1, 0);
735 	pat2 = cairo_pattern_create_linear (0, 0, 0, height);
736 	cairo_pattern_add_color_stop_rgba (pat2, 0.1, CAIRO_INK2, 1);
737 	cairo_pattern_add_color_stop_rgba (pat2, 0.6, CAIRO_INK2, 0);
738 	pat3 = cairo_pattern_create_linear (0, height, 0, 0);
739 	cairo_pattern_add_color_stop_rgba (pat3, 0.1, CAIRO_INK1, 1);
740 	cairo_pattern_add_color_stop_rgba (pat3, 0.6, CAIRO_INK1, 0);
741 	pat4 = cairo_pattern_create_linear (0, height, 0, 0);
742 	cairo_pattern_add_color_stop_rgba (pat4, 0.1, CAIRO_INK2, 1);
743 	cairo_pattern_add_color_stop_rgba (pat4, 0.6, CAIRO_INK2, 0);
744 
745 	return (pat4 && (cairo_pattern_status (pat4) == CAIRO_STATUS_SUCCESS) &&
746 			pat3 && (cairo_pattern_status (pat3) == CAIRO_STATUS_SUCCESS) &&
747 			pat2 && (cairo_pattern_status (pat2) == CAIRO_STATUS_SUCCESS) &&
748 			pat1 && (cairo_pattern_status (pat1) == CAIRO_STATUS_SUCCESS) &&
749 			cr4 && (cairo_status (cr4) == CAIRO_STATUS_SUCCESS) &&
750 			cr3 && (cairo_status (cr3) == CAIRO_STATUS_SUCCESS)&&
751 			cr2 && (cairo_status (cr2) == CAIRO_STATUS_SUCCESS) &&
752 			cr1 && (cairo_status (cr1) == CAIRO_STATUS_SUCCESS) &&
753 			surface && (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS));
754 }
755 
destroy_mainMonitor()756 void BSlizr_GUI::destroy_mainMonitor ()
757 {
758 	//Destroy also mainMonitors cairo data
759 	if (pat4 && (cairo_pattern_status (pat4) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat4);
760 	if (pat3 && (cairo_pattern_status (pat3) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat3);
761 	if (pat2 && (cairo_pattern_status (pat2) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat2);
762 	if (pat1 && (cairo_pattern_status (pat1) == CAIRO_STATUS_SUCCESS)) cairo_pattern_destroy (pat1);
763 	if (cr4 && (cairo_status (cr4) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr4);
764 	if (cr3 && (cairo_status (cr3) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr3);
765 	if (cr2 && (cairo_status (cr2) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr2);
766 	if (cr1 && (cairo_status (cr1) == CAIRO_STATUS_SUCCESS)) cairo_destroy (cr1);
767 	if (surface && (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)) cairo_surface_destroy (surface);
768 }
769 
add_monitor_data(BSlizrNotifications * notifications,uint32_t notificationsCount,uint32_t & end)770 void BSlizr_GUI::add_monitor_data (BSlizrNotifications* notifications, uint32_t notificationsCount, uint32_t& end)
771 {
772 	for (uint32_t i = 0; i < notificationsCount; ++i)
773 	{
774 		int monitorpos = notifications[i].position;
775 		if (monitorpos >= MONITORBUFFERSIZE) monitorpos = MONITORBUFFERSIZE;
776 		if (monitorpos < 0) monitorpos = 0;
777 
778 		mainMonitor.data[monitorpos].inputMin = notifications[i].inputMin;
779 		mainMonitor.data[monitorpos].inputMax = notifications[i].inputMax;
780 		mainMonitor.data[monitorpos].outputMin = notifications[i].outputMin;
781 		mainMonitor.data[monitorpos].outputMax = notifications[i].outputMax;
782 		mainMonitor.horizonPos = monitorpos;
783 	}
784 }
785 
redrawMainMonitor()786 void BSlizr_GUI::redrawMainMonitor ()
787 {
788 	double width = monitorDisplay.getEffectiveWidth ();
789 	double height = monitorDisplay.getEffectiveHeight ();
790 
791 	cairo_t* cr = cairo_create (monitorDisplay.getDrawingSurface ());
792 	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return;
793 
794 	// Draw background
795 	cairo_set_source_rgba (cr, CAIRO_BG_COLOR);
796 	cairo_rectangle (cr, 0, 0, width, height);
797 	cairo_fill (cr);
798 
799 	cairo_set_source_rgba (cr, CAIRO_BG_COLOR2);
800 	cairo_set_line_width (cr, 1);
801 	cairo_move_to (cr, 0, 0.1 * height);
802 	cairo_line_to (cr, width, 0.1 * height);
803 	cairo_move_to (cr, 0, 0.5 * height);
804 	cairo_line_to (cr, width, 0.5 * height);
805 	cairo_move_to (cr, 0, 0.9 * height);
806 	cairo_line_to (cr, width, 0.9 * height);
807 
808 	uint32_t steps = (uint32_t) nrSteps;
809 	for (uint32_t i = 1; i < steps; ++i)
810 	{
811 		uint32_t x = uint32_t (i * width / steps);
812 		cairo_move_to (cr, x, 0);
813 		cairo_line_to (cr, x, height);
814 	}
815 	cairo_stroke (cr);
816 
817 	if (mainMonitor.record_on)
818 	{
819 		cairo_surface_clear (surface);
820 
821 		// Draw input (cr, cr3) and output (cr2, cr4) curves
822 		cairo_move_to (cr1, 0, height * (0.5  - (0.4 * LIM ((mainMonitor.data[0].inputMax / scale), 1.0f))));
823 		cairo_move_to (cr2, 0, height * (0.5  - (0.4 * LIM ((mainMonitor.data[0].outputMax / scale), 1.0f))));
824 		cairo_move_to (cr3, 0, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[0].inputMin / scale), 1.0f))));
825 		cairo_move_to (cr4, 0, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[0].outputMin / scale), 1.0f))));
826 
827 		for (int i = 0; i < MONITORBUFFERSIZE; ++i)
828 		{
829 			double pos = ((double) i) / (MONITORBUFFERSIZE - 1.0f);
830 			cairo_line_to (cr1, pos * width, height * (0.5  - (0.4 * LIM ((mainMonitor.data[i].inputMax / scale), 1.0f))));
831 			cairo_line_to (cr2, pos * width, height * (0.5  - (0.4 * LIM ((mainMonitor.data[i].outputMax / scale), 1.0f))));
832 			cairo_line_to (cr3, pos * width, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[i].inputMin / scale), 1.0f))));
833 			cairo_line_to (cr4, pos * width, height * (0.5  + (0.4 * LIM (-(mainMonitor.data[i].outputMin / scale), 1.0f))));
834 		}
835 
836 		// Visualize input (cr, cr3) and output (cr2, cr4) curves
837 		cairo_set_source_rgba (cr1, CAIRO_INK1, 1.0);
838 		cairo_set_line_width (cr1, 3);
839 		cairo_set_source_rgba (cr2, CAIRO_INK2, 1.0);
840 		cairo_set_line_width (cr2, 3);
841 		cairo_stroke_preserve (cr1);
842 		cairo_stroke_preserve (cr2);
843 		cairo_set_source_rgba (cr3, CAIRO_INK1, 1.0);
844 		cairo_set_line_width (cr3, 3);
845 		cairo_set_source_rgba (cr4, CAIRO_INK2, 1.0);
846 		cairo_set_line_width (cr4, 3);
847 		cairo_stroke_preserve (cr3);
848 		cairo_stroke_preserve (cr4);
849 
850 		// Visualize input (cr, cr3) and output (cr2, cr4) areas under the curves
851 		cairo_line_to (cr1, width, height * 0.5);
852 		cairo_line_to (cr1, 0, height * 0.5);
853 		cairo_close_path (cr1);
854 		cairo_line_to (cr2, width, height * 0.5);
855 		cairo_line_to (cr2, 0, height * 0.5);
856 		cairo_close_path (cr2);
857 		cairo_set_source (cr1, pat1);
858 		cairo_set_line_width (cr1, 0);
859 		cairo_set_source (cr2, pat2);
860 		cairo_set_line_width (cr2, 0);
861 		cairo_fill (cr1);
862 		cairo_fill (cr2);
863 		cairo_line_to (cr3, width, height * 0.5);
864 		cairo_line_to (cr3, 0, height * 0.5);
865 		cairo_close_path (cr3);
866 		cairo_line_to (cr4, width, height * 0.5);
867 		cairo_line_to (cr4, 0, height * 0.5);
868 		cairo_close_path (cr4);
869 		cairo_set_source (cr3, pat3);
870 		cairo_set_line_width (cr3, 0);
871 		cairo_set_source (cr4, pat4);
872 		cairo_set_line_width (cr4, 0);
873 		cairo_fill (cr3);
874 		cairo_fill (cr4);
875 
876 		// Draw fade out
877 		double horizon = ((double) mainMonitor.horizonPos) / (MONITORBUFFERSIZE - 1.0f);
878 		cairo_pattern_t* pat6 = cairo_pattern_create_linear (horizon * width, 0, horizon * width + 63, 0);
879 		if (cairo_pattern_status (pat6) == CAIRO_STATUS_SUCCESS)
880 		{
881 			cairo_pattern_add_color_stop_rgba (pat6, 0.0, CAIRO_BG_COLOR);
882 			cairo_pattern_add_color_stop_rgba (pat6, 1.0, CAIRO_TRANSPARENT);
883 			cairo_set_line_width (cr1, 0.0);
884 			cairo_set_source (cr1, pat6);
885 			cairo_rectangle (cr1, horizon * width, 0, 63, height);
886 			cairo_fill (cr1);
887 			cairo_pattern_destroy (pat6);
888 		}
889 
890 		if (horizon * width > width - 63)
891 		{
892 			cairo_pattern_t* pat6 = cairo_pattern_create_linear ((horizon - 1) * width, 0, (horizon - 1) * width + 63, 0);
893 			if (cairo_pattern_status (pat6) == CAIRO_STATUS_SUCCESS)
894 			{
895 				cairo_pattern_add_color_stop_rgba (pat6, 0.0, CAIRO_BG_COLOR);
896 				cairo_pattern_add_color_stop_rgba (pat6, 1.0, CAIRO_TRANSPARENT);
897 				cairo_set_line_width (cr1, 0.0);
898 				cairo_set_source (cr1, pat6);
899 				cairo_rectangle (cr1, (horizon - 1) * width, 0, 63, height);
900 				cairo_fill (cr1);
901 				cairo_pattern_destroy (pat6);
902 			}
903 		}
904 
905 		// Draw horizon line
906 		cairo_set_source_rgba (cr1, CAIRO_FG_COLOR);
907 		cairo_set_line_width (cr1, 1);
908 		cairo_move_to (cr1, horizon * width, 0);
909 		cairo_line_to (cr1, horizon * width, height);
910 		cairo_stroke (cr1);
911 	}
912 
913 	cairo_set_source_surface (cr, surface, 0, 0);
914 	cairo_paint (cr);
915 
916 	cairo_destroy (cr);
917 
918 	monitorDisplay.update ();
919 }
920 
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)921 static LV2UI_Handle instantiate (const LV2UI_Descriptor *descriptor, const char *plugin_uri, const char *bundle_path,
922 						  LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget *widget,
923 						  const LV2_Feature *const *features)
924 {
925 	PuglNativeView parentWindow = 0;
926 	LV2UI_Resize* resize = NULL;
927 
928 	if (strcmp(plugin_uri, BSLIZR_URI) != 0)
929 	{
930 		std::cerr << "BSlizr.lv2#GUI: GUI does not support plugin with URI " << plugin_uri << std::endl;
931 		return NULL;
932 	}
933 
934 	for (int i = 0; features[i]; ++i)
935 	{
936 		if (!strcmp(features[i]->URI, LV2_UI__parent)) parentWindow = (PuglNativeView) features[i]->data;
937 		else if (!strcmp(features[i]->URI, LV2_UI__resize)) resize = (LV2UI_Resize*)features[i]->data;
938 	}
939 	if (parentWindow == 0) std::cerr << "BSlizr.lv2#GUI: No parent window.\n";
940 
941 	// New instance
942 	BSlizr_GUI* ui;
943 	try {ui = new BSlizr_GUI (bundle_path, features, parentWindow);}
944 	catch (std::exception& exc)
945 	{
946 		std::cerr << "BSlizr.lv2#GUI: Instantiation failed. " << exc.what () << std::endl;
947 		return NULL;
948 	}
949 
950 	ui->controller = controller;
951 	ui->write_function = write_function;
952 
953 	// Reduce min GUI size for small displays
954 	double sz = 1.0;
955 	int screenWidth  = getScreenWidth ();
956 	int screenHeight = getScreenHeight ();
957 	if ((screenWidth < 820) || (screenHeight < 600)) sz = 0.66;
958 
959 	/*
960 	std::cerr << "BSlizr_GUI.lv2 screen size " << screenWidth << " x " << screenHeight <<
961 			". Set GUI size to " << 800 * sz << " x " << 560 * sz << ".\n";
962 	*/
963 
964 	if (resize) resize->ui_resize(resize->handle, 800 * sz, 560 * sz);
965 
966 	*widget = (LV2UI_Widget) puglGetNativeWindow (ui->getPuglView ());
967 	ui->send_record_on();
968 	return (LV2UI_Handle) ui;
969 }
970 
cleanup(LV2UI_Handle ui)971 static void cleanup(LV2UI_Handle ui)
972 {
973 	BSlizr_GUI* pluginGui = (BSlizr_GUI*) ui;
974 	if (pluginGui) delete pluginGui;
975 }
976 
portEvent(LV2UI_Handle ui,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)977 static void portEvent(LV2UI_Handle ui, uint32_t port_index, uint32_t buffer_size,
978 	uint32_t format, const void* buffer)
979 {
980 	BSlizr_GUI* pluginGui = (BSlizr_GUI*) ui;
981 	if (pluginGui) pluginGui->portEvent(port_index, buffer_size, format, buffer);
982 }
983 
callIdle(LV2UI_Handle ui)984 static int callIdle (LV2UI_Handle ui)
985 {
986 	BSlizr_GUI* pluginGui = (BSlizr_GUI*) ui;
987 	if (pluginGui) pluginGui->handleEvents ();
988 	return 0;
989 }
990 
callResize(LV2UI_Handle ui,int width,int height)991 static int callResize (LV2UI_Handle ui, int width, int height)
992 {
993 	BSlizr_GUI* self = (BSlizr_GUI*) ui;
994 	if (!self) return 0;
995 
996 	BEvents::ExposeEvent* ev = new BEvents::ExposeEvent (self, self, BEvents::CONFIGURE_REQUEST_EVENT, self->getPosition().x, self->getPosition().y, width, height);
997 	self->addEventToQueue (ev);
998 	return 0;
999 }
1000 
1001 static const LV2UI_Idle_Interface idle = {callIdle};
1002 static const LV2UI_Resize resize = {nullptr, callResize};
1003 
extensionData(const char * uri)1004 static const void* extensionData(const char* uri)
1005 {
1006 	if (!strcmp(uri, LV2_UI__idleInterface)) return &idle;
1007 	else if(!strcmp(uri, LV2_UI__resize)) return &resize;
1008 	else return NULL;
1009 }
1010 
1011 static const LV2UI_Descriptor guiDescriptor = {
1012 		BSLIZR_GUI_URI,
1013 		instantiate,
1014 		cleanup,
1015 		portEvent,
1016 		extensionData
1017 };
1018 
1019 // LV2 Symbol Export
lv2ui_descriptor(uint32_t index)1020 LV2_SYMBOL_EXPORT const LV2UI_Descriptor *lv2ui_descriptor(uint32_t index)
1021 {
1022 	switch (index) {
1023 	case 0: return &guiDescriptor;
1024 	default:return NULL;
1025     }
1026 }
1027