Line data Source code
1 : #include "MultiHandleSliderLogic.h"
2 : #include "RangeSliderLogic.h"
3 : #include <algorithm>
4 : #include <cmath>
5 :
6 56 : MultiHandleSliderLogic::MultiHandleSliderLogic(double maxValue)
7 : : loopEnd_(std::max(0.0, maxValue)),
8 28 : maxValue_(std::max(0.0, maxValue)) {
9 28 : }
10 :
11 18 : void MultiHandleSliderLogic::setLoopStart(double v) {
12 18 : loopStart_ = std::clamp(v, 0.0, loopEnd_);
13 18 : }
14 :
15 10 : void MultiHandleSliderLogic::setPlayhead(double v) {
16 10 : playhead_ = std::clamp(v, 0.0, maxValue_);
17 10 : }
18 :
19 18 : void MultiHandleSliderLogic::setLoopEnd(double v) {
20 18 : loopEnd_ = std::clamp(v, loopStart_, maxValue_);
21 18 : }
22 :
23 3 : void MultiHandleSliderLogic::setMaxValue(double v) {
24 3 : const double oldMax = maxValue_;
25 3 : maxValue_ = std::max(0.0, v);
26 : // When transitioning from uninitialized (0) to a real duration,
27 : // expand loopEnd to cover the full range.
28 3 : if (oldMax <= 0.0 && maxValue_ > 0.0)
29 1 : loopEnd_ = maxValue_;
30 3 : loopEnd_ = std::min(loopEnd_, maxValue_);
31 3 : loopStart_ = std::min(loopStart_, loopEnd_);
32 3 : playhead_ = std::min(playhead_, maxValue_);
33 3 : }
34 :
35 : MultiHandleSliderLogic::HandleType
36 5 : MultiHandleSliderLogic::hitTest(float mouseX,
37 : float trackStart, float trackWidth,
38 : float thumbRadius) const {
39 5 : if (maxValue_ <= 0.0)
40 0 : return HandleType::None;
41 :
42 10 : const float lsPx = RangeSliderLogic::valueToPixel(loopStart_, 0.0, maxValue_,
43 5 : trackStart, trackWidth);
44 10 : const float phPx = RangeSliderLogic::valueToPixel(playhead_, 0.0, maxValue_,
45 5 : trackStart, trackWidth);
46 10 : const float lePx = RangeSliderLogic::valueToPixel(loopEnd_, 0.0, maxValue_,
47 5 : trackStart, trackWidth);
48 :
49 5 : const float dLS = std::abs(mouseX - lsPx);
50 5 : const float dPH = std::abs(mouseX - phPx);
51 5 : const float dLE = std::abs(mouseX - lePx);
52 :
53 : // Find the closest handle within thumbRadius
54 5 : float bestDist = thumbRadius + 1.0f;
55 5 : HandleType best = HandleType::None;
56 :
57 5 : if (dLS <= thumbRadius && dLS < bestDist) {
58 1 : bestDist = dLS;
59 1 : best = HandleType::LoopStart;
60 1 : }
61 5 : if (dPH <= thumbRadius && dPH < bestDist) {
62 1 : bestDist = dPH;
63 1 : best = HandleType::Playhead;
64 1 : }
65 5 : if (dLE <= thumbRadius && dLE < bestDist) {
66 1 : bestDist = dLE;
67 1 : best = HandleType::LoopEnd;
68 1 : }
69 :
70 5 : if (best != HandleType::None)
71 3 : return best;
72 :
73 : // Check middle zone between loop handles
74 4 : if (RangeSliderLogic::isInMiddleZone(mouseX, loopStart_, loopEnd_,
75 2 : 0.0, maxValue_, trackStart, trackWidth,
76 2 : thumbRadius))
77 1 : return HandleType::MiddleZone;
78 :
79 1 : return HandleType::None;
80 5 : }
81 :
82 6 : void MultiHandleSliderLogic::dragHandle(HandleType handle, float mouseX,
83 : float trackStart, float trackWidth) {
84 6 : if (maxValue_ <= 0.0)
85 0 : return;
86 :
87 12 : const double val = RangeSliderLogic::pixelToValue(mouseX, 0.0, maxValue_, trackStart,
88 6 : trackWidth);
89 :
90 6 : switch (handle) {
91 : case HandleType::LoopStart:
92 2 : loopStart_ = std::clamp(val, 0.0, loopEnd_);
93 2 : break;
94 : case HandleType::Playhead:
95 2 : playhead_ = std::clamp(val, 0.0, maxValue_);
96 2 : break;
97 : case HandleType::LoopEnd:
98 2 : loopEnd_ = std::clamp(val, loopStart_, maxValue_);
99 2 : break;
100 : default:
101 0 : break;
102 : }
103 6 : }
104 :
105 3 : void MultiHandleSliderLogic::dragMiddleZone(double initialLoopStart,
106 : double initialLoopEnd,
107 : float deltaPixels,
108 : float trackStart, float trackWidth) {
109 6 : auto [newStart, newEnd] = RangeSliderLogic::applyDrag(
110 3 : initialLoopStart, initialLoopEnd, 0.0, maxValue_, deltaPixels, trackStart,
111 3 : trackWidth);
112 3 : loopStart_ = newStart;
113 3 : loopEnd_ = newEnd;
114 3 : }
115 :
116 4 : std::string MultiHandleSliderLogic::formatTime(double seconds) {
117 4 : if (seconds < 0.0)
118 0 : seconds = 0.0;
119 4 : const int totalSec = static_cast<int>(seconds);
120 4 : const int mins = totalSec / 60;
121 4 : const int secs = totalSec % 60;
122 :
123 : char buf[16];
124 4 : std::snprintf(buf, sizeof (buf), "%d:%02d", mins, secs);
125 4 : return buf;
126 : }
|