comparison DPF-Prymula-audioplugins/dpf/dgl/src/EventHandlers.cpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "../EventHandlers.hpp"
18 #include "../SubWidget.hpp"
19
20 START_NAMESPACE_DGL
21
22 // --------------------------------------------------------------------------------------------------------------------
23
24 struct ButtonEventHandler::PrivateData {
25 ButtonEventHandler* const self;
26 SubWidget* const widget;
27 ButtonEventHandler::Callback* internalCallback;
28 ButtonEventHandler::Callback* userCallback;
29
30 int button;
31 int state;
32 bool checkable;
33 bool checked;
34
35 Point<double> lastClickPos;
36 Point<double> lastMotionPos;
37
38 PrivateData(ButtonEventHandler* const s, SubWidget* const w)
39 : self(s),
40 widget(w),
41 internalCallback(nullptr),
42 userCallback(nullptr),
43 button(-1),
44 state(kButtonStateDefault),
45 checkable(false),
46 checked(false),
47 lastClickPos(0, 0),
48 lastMotionPos(0, 0) {}
49
50 bool mouseEvent(const Widget::MouseEvent& ev)
51 {
52 lastClickPos = ev.pos;
53
54 // button was released, handle it now
55 if (button != -1 && ! ev.press)
56 {
57 DISTRHO_SAFE_ASSERT(state & kButtonStateActive);
58
59 // release button
60 const int button2 = button;
61 button = -1;
62
63 const int state2 = state;
64 state &= ~kButtonStateActive;
65
66 self->stateChanged(static_cast<State>(state), static_cast<State>(state2));
67 widget->repaint();
68
69 // cursor was moved outside the button bounds, ignore click
70 if (! widget->contains(ev.pos))
71 return true;
72
73 // still on bounds, register click
74 if (checkable)
75 checked = !checked;
76
77 if (internalCallback != nullptr)
78 internalCallback->buttonClicked(widget, button2);
79 else if (userCallback != nullptr)
80 userCallback->buttonClicked(widget, button2);
81
82 return true;
83 }
84
85 // button was pressed, wait for release
86 if (ev.press && widget->contains(ev.pos))
87 {
88 const int state2 = state;
89 button = static_cast<int>(ev.button);
90 state |= kButtonStateActive;
91 self->stateChanged(static_cast<State>(state), static_cast<State>(state2));
92 widget->repaint();
93 return true;
94 }
95
96 return false;
97 }
98
99 bool motionEvent(const Widget::MotionEvent& ev)
100 {
101 // keep pressed
102 if (button != -1)
103 {
104 lastMotionPos = ev.pos;
105 return true;
106 }
107
108 bool ret = false;
109
110 if (widget->contains(ev.pos))
111 {
112 // check if entering hover
113 if ((state & kButtonStateHover) == 0x0)
114 {
115 const int state2 = state;
116 state |= kButtonStateHover;
117 ret = widget->contains(lastMotionPos);
118 self->stateChanged(static_cast<State>(state), static_cast<State>(state2));
119 widget->repaint();
120 }
121 }
122 else
123 {
124 // check if exiting hover
125 if (state & kButtonStateHover)
126 {
127 const int state2 = state;
128 state &= ~kButtonStateHover;
129 ret = widget->contains(lastMotionPos);
130 self->stateChanged(static_cast<State>(state), static_cast<State>(state2));
131 widget->repaint();
132 }
133 }
134
135 lastMotionPos = ev.pos;
136 return ret;
137 }
138
139 void setActive(const bool active2, const bool sendCallback) noexcept
140 {
141 const bool active = state & kButtonStateActive;
142 if (active == active2)
143 return;
144
145 state |= kButtonStateActive;
146 widget->repaint();
147
148 if (sendCallback)
149 {
150 if (internalCallback != nullptr)
151 internalCallback->buttonClicked(widget, -1);
152 else if (userCallback != nullptr)
153 userCallback->buttonClicked(widget, -1);
154 }
155 }
156
157 void setChecked(const bool checked2, const bool sendCallback) noexcept
158 {
159 if (checked == checked2)
160 return;
161
162 checked = checked2;
163 widget->repaint();
164
165 if (sendCallback)
166 {
167 if (internalCallback != nullptr)
168 internalCallback->buttonClicked(widget, -1);
169 else if (userCallback != nullptr)
170 userCallback->buttonClicked(widget, -1);
171 }
172 }
173
174 DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
175 };
176
177 // --------------------------------------------------------------------------------------------------------------------
178
179 ButtonEventHandler::ButtonEventHandler(SubWidget* const self)
180 : pData(new PrivateData(this, self)) {}
181
182 ButtonEventHandler::~ButtonEventHandler()
183 {
184 delete pData;
185 }
186
187 bool ButtonEventHandler::isActive() noexcept
188 {
189 return pData->state & kButtonStateActive;
190 }
191
192 void ButtonEventHandler::setActive(const bool active, const bool sendCallback) noexcept
193 {
194 pData->setActive(active, sendCallback);
195 }
196
197 bool ButtonEventHandler::isChecked() const noexcept
198 {
199 return pData->checked;
200 }
201
202 void ButtonEventHandler::setChecked(const bool checked, const bool sendCallback) noexcept
203 {
204 pData->setChecked(checked, sendCallback);
205 }
206
207 bool ButtonEventHandler::isCheckable() const noexcept
208 {
209 return pData->checkable;
210 }
211
212 void ButtonEventHandler::setCheckable(const bool checkable) noexcept
213 {
214 if (pData->checkable == checkable)
215 return;
216
217 pData->checkable = checkable;
218 }
219
220 Point<double> ButtonEventHandler::getLastClickPosition() const noexcept
221 {
222 return pData->lastClickPos;
223 }
224
225 Point<double> ButtonEventHandler::getLastMotionPosition() const noexcept
226 {
227 return pData->lastMotionPos;
228 }
229
230 void ButtonEventHandler::setCallback(Callback* const callback) noexcept
231 {
232 pData->userCallback = callback;
233 }
234
235 bool ButtonEventHandler::mouseEvent(const Widget::MouseEvent& ev)
236 {
237 return pData->mouseEvent(ev);
238 }
239
240 bool ButtonEventHandler::motionEvent(const Widget::MotionEvent& ev)
241 {
242 return pData->motionEvent(ev);
243 }
244
245 ButtonEventHandler::State ButtonEventHandler::getState() const noexcept
246 {
247 return static_cast<State>(pData->state);
248 }
249
250 void ButtonEventHandler::clearState() noexcept
251 {
252 pData->state = kButtonStateDefault;
253 }
254
255 void ButtonEventHandler::stateChanged(State, State)
256 {
257 }
258
259 void ButtonEventHandler::setInternalCallback(Callback* const callback) noexcept
260 {
261 pData->internalCallback = callback;
262 }
263
264 void ButtonEventHandler::triggerUserCallback(SubWidget* const widget, const int button)
265 {
266 if (pData->userCallback != nullptr)
267 pData->userCallback->buttonClicked(widget, button);
268 }
269
270 // --------------------------------------------------------------------------------------------------------------------
271
272 struct KnobEventHandler::PrivateData {
273 KnobEventHandler* const self;
274 SubWidget* const widget;
275 KnobEventHandler::Callback* callback;
276
277 float accel;
278 float minimum;
279 float maximum;
280 float step;
281 float value;
282 float valueDef;
283 float valueTmp;
284 bool usingDefault;
285 bool usingLog;
286 Orientation orientation;
287 int state;
288
289 double lastX;
290 double lastY;
291 uint lastClickTime;
292
293 PrivateData(KnobEventHandler* const s, SubWidget* const w)
294 : self(s),
295 widget(w),
296 callback(nullptr),
297 accel(200.f),
298 minimum(0.f),
299 maximum(1.f),
300 step(0.0f),
301 value(0.5f),
302 valueDef(value),
303 valueTmp(value),
304 usingDefault(false),
305 usingLog(false),
306 orientation(Vertical),
307 state(kKnobStateDefault),
308 lastX(0.0),
309 lastY(0.0),
310 lastClickTime(0) {}
311
312 PrivateData(KnobEventHandler* const s, SubWidget* const w, PrivateData* const other)
313 : self(s),
314 widget(w),
315 callback(other->callback),
316 accel(other->accel),
317 minimum(other->minimum),
318 maximum(other->maximum),
319 step(other->step),
320 value(other->value),
321 valueDef(other->valueDef),
322 valueTmp(value),
323 usingDefault(other->usingDefault),
324 usingLog(other->usingLog),
325 orientation(other->orientation),
326 state(kKnobStateDefault),
327 lastX(0.0),
328 lastY(0.0),
329 lastClickTime(0) {}
330
331 void assignFrom(PrivateData* const other)
332 {
333 callback = other->callback;
334 accel = other->accel;
335 minimum = other->minimum;
336 maximum = other->maximum;
337 step = other->step;
338 value = other->value;
339 valueDef = other->valueDef;
340 valueTmp = value;
341 usingDefault = other->usingDefault;
342 usingLog = other->usingLog;
343 orientation = other->orientation;
344 state = kKnobStateDefault;
345 lastX = 0.0;
346 lastY = 0.0;
347 lastClickTime = 0;
348 }
349
350 inline float logscale(const float v) const
351 {
352 const float b = std::log(maximum/minimum)/(maximum-minimum);
353 const float a = maximum/std::exp(maximum*b);
354 return a * std::exp(b*v);
355 }
356
357 inline float invlogscale(const float v) const
358 {
359 const float b = std::log(maximum/minimum)/(maximum-minimum);
360 const float a = maximum/std::exp(maximum*b);
361 return std::log(v/a)/b;
362 }
363
364 bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor)
365 {
366 if (ev.button != 1)
367 return false;
368
369 if (ev.press)
370 {
371 if (! widget->contains(ev.pos))
372 return false;
373
374 if ((ev.mod & kModifierShift) != 0 && usingDefault)
375 {
376 setValue(valueDef, true);
377 valueTmp = value;
378 return true;
379 }
380
381 lastX = ev.pos.getX() / scaleFactor;
382 lastY = ev.pos.getY() / scaleFactor;
383
384 if (lastClickTime > 0 && ev.time > lastClickTime && ev.time - lastClickTime <= 300)
385 {
386 lastClickTime = 0;
387
388 if (callback != nullptr)
389 callback->knobDoubleClicked(widget);
390
391 return true;
392 }
393
394 lastClickTime = ev.time;
395 state |= kKnobStateDragging;
396 widget->repaint();
397
398 if (callback != nullptr)
399 callback->knobDragStarted(widget);
400
401 return true;
402 }
403 else if (state & kKnobStateDragging)
404 {
405 state &= ~kKnobStateDragging;
406 widget->repaint();
407
408 if (callback != nullptr)
409 callback->knobDragFinished(widget);
410
411 return true;
412 }
413
414 return false;
415 }
416
417 bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor)
418 {
419 if ((state & kKnobStateDragging) == 0x0)
420 return false;
421
422 float movDiff;
423
424 switch (orientation)
425 {
426 case Horizontal:
427 movDiff = ev.pos.getX() / scaleFactor - lastX;
428 break;
429 case Vertical:
430 movDiff = lastY - ev.pos.getY() / scaleFactor;
431 break;
432 case Both:
433 {
434 const float movDiffX = ev.pos.getX() / scaleFactor - lastX;
435 const float movDiffY = lastY - ev.pos.getY() / scaleFactor;
436 movDiff = std::abs(movDiffX) > std::abs(movDiffY) ? movDiffX : movDiffY;
437 }
438 break;
439 default:
440 return false;
441 }
442
443 if (d_isZero(movDiff))
444 return true;
445
446 const float divisor = (ev.mod & kModifierControl) ? accel * 10.f : accel;
447 valueTmp += (maximum - minimum) / divisor * movDiff;
448
449 if (usingLog)
450 valueTmp = logscale(valueTmp);
451
452 float value2;
453 bool valueChanged = false;
454
455 if (valueTmp < minimum)
456 {
457 valueTmp = value2 = minimum;
458 valueChanged = true;
459 }
460 else if (valueTmp > maximum)
461 {
462 valueTmp = value2 = maximum;
463 valueChanged = true;
464 }
465 else
466 {
467 if (d_isNotZero(step))
468 {
469 if (std::abs(valueTmp - value) >= step)
470 {
471 const float rest = std::fmod(valueTmp, step);
472 valueChanged = true;
473 value2 = valueTmp - rest;
474
475 if (rest < 0 && rest < step * -0.5f)
476 value2 -= step;
477 else if (rest > 0 && rest > step * 0.5f)
478 value2 += step;
479
480 if (value2 < minimum)
481 value2 = minimum;
482 else if (value2 > maximum)
483 value2 = maximum;
484 }
485 }
486 else
487 {
488 value2 = valueTmp;
489 valueChanged = true;
490 }
491 }
492
493 if (valueChanged)
494 setValue(value2, true);
495
496 lastX = ev.pos.getX() / scaleFactor;
497 lastY = ev.pos.getY() / scaleFactor;
498
499 return true;
500 }
501
502 bool scrollEvent(const Widget::ScrollEvent& ev)
503 {
504 if (! widget->contains(ev.pos))
505 return false;
506
507 const float dir = (ev.delta.getY() > 0.f) ? 1.f : -1.f;
508 const float d = (ev.mod & kModifierControl) ? accel * 10.f : accel;
509 float value2 = (usingLog ? invlogscale(valueTmp) : valueTmp)
510 + ((maximum - minimum) / d * 10.f * dir);
511
512 if (usingLog)
513 value2 = logscale(value2);
514
515 if (value2 < minimum)
516 {
517 valueTmp = value2 = minimum;
518 }
519 else if (value2 > maximum)
520 {
521 valueTmp = value2 = maximum;
522 }
523 else
524 {
525 valueTmp = value2;
526
527 if (d_isNotZero(step))
528 {
529 const float rest = std::fmod(value2, step);
530 value2 = value2 - rest + (rest > step/2.0f ? step : 0.0f);
531 }
532 }
533
534 setValue(value2, true);
535 return true;
536 }
537
538 float getNormalizedValue() const noexcept
539 {
540 const float diff = maximum - minimum;
541 return ((usingLog ? invlogscale(value) : value) - minimum) / diff;
542 }
543
544 void setRange(const float min, const float max) noexcept
545 {
546 DISTRHO_SAFE_ASSERT_RETURN(max > min,);
547
548 if (value < min)
549 {
550 valueTmp = value = min;
551 widget->repaint();
552 }
553 else if (value > max)
554 {
555 valueTmp = value = max;
556 widget->repaint();
557 }
558
559 minimum = min;
560 maximum = max;
561 }
562
563 bool setValue(const float value2, const bool sendCallback)
564 {
565 if (d_isEqual(value, value2))
566 return false;
567
568 valueTmp = value = value2;
569 widget->repaint();
570
571 if (sendCallback && callback != nullptr)
572 {
573 try {
574 callback->knobValueChanged(widget, value);
575 } DISTRHO_SAFE_EXCEPTION("KnobEventHandler::setValue");
576 }
577
578 return true;
579 }
580 };
581
582 // --------------------------------------------------------------------------------------------------------------------
583
584 KnobEventHandler::KnobEventHandler(SubWidget* const self)
585 : pData(new PrivateData(this, self)) {}
586
587 KnobEventHandler::KnobEventHandler(SubWidget* const self, const KnobEventHandler& other)
588 : pData(new PrivateData(this, self, other.pData)) {}
589
590 KnobEventHandler& KnobEventHandler::operator=(const KnobEventHandler& other)
591 {
592 pData->assignFrom(other.pData);
593 return *this;
594 }
595
596 KnobEventHandler::~KnobEventHandler()
597 {
598 delete pData;
599 }
600
601 bool KnobEventHandler::isInteger() const noexcept
602 {
603 return d_isEqual(pData->step, 1.f);
604 }
605
606 float KnobEventHandler::getValue() const noexcept
607 {
608 return pData->value;
609 }
610
611 bool KnobEventHandler::setValue(const float value, const bool sendCallback) noexcept
612 {
613 return pData->setValue(value, sendCallback);
614 }
615
616 float KnobEventHandler::getNormalizedValue() const noexcept
617 {
618 return pData->getNormalizedValue();
619 }
620
621 void KnobEventHandler::setDefault(const float def) noexcept
622 {
623 pData->valueDef = def;
624 pData->usingDefault = true;
625 }
626
627 void KnobEventHandler::setRange(const float min, const float max) noexcept
628 {
629 pData->setRange(min, max);
630 }
631
632 void KnobEventHandler::setStep(const float step) noexcept
633 {
634 pData->step = step;
635 }
636
637 void KnobEventHandler::setUsingLogScale(const bool yesNo) noexcept
638 {
639 pData->usingLog = yesNo;
640 }
641
642 KnobEventHandler::Orientation KnobEventHandler::getOrientation() const noexcept
643 {
644 return pData->orientation;
645 }
646
647 void KnobEventHandler::setOrientation(const Orientation orientation) noexcept
648 {
649 pData->orientation = orientation;
650 }
651
652 void KnobEventHandler::setCallback(Callback* const callback) noexcept
653 {
654 pData->callback = callback;
655 }
656
657 void KnobEventHandler::setMouseDeceleration(float accel) noexcept
658 {
659 pData->accel = accel;
660 }
661
662 bool KnobEventHandler::mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor)
663 {
664 return pData->mouseEvent(ev, scaleFactor);
665 }
666
667 bool KnobEventHandler::motionEvent(const Widget::MotionEvent& ev, const double scaleFactor)
668 {
669 return pData->motionEvent(ev, scaleFactor);
670 }
671
672 bool KnobEventHandler::scrollEvent(const Widget::ScrollEvent& ev)
673 {
674 return pData->scrollEvent(ev);
675 }
676
677 KnobEventHandler::State KnobEventHandler::getState() const noexcept
678 {
679 return static_cast<State>(pData->state);
680 }
681
682 // --------------------------------------------------------------------------------------------------------------------
683
684 END_NAMESPACE_DGL