Mercurial > hg > pub > prymula > com
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 |