tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_CurveEditor.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
14CurveEditorPoint::~CurveEditorPoint()
15{
16 notifyListenersOfDeletion();
17}
18
19static CurveEditor* getPointIndexes (juce::Array<int>& set, const SelectableList& items)
20{
21 set.ensureStorageAllocated (items.size());
22 CurveEditor* ed = nullptr;
23
24 for (auto point : items.getItemsOfType<CurveEditorPoint>())
25 {
26 ed = point->editor;
27 set.add (point->index);
28 }
29
30 std::sort (set.begin(), set.end());
31 return ed;
32}
33
34bool CurveEditorPoint::arePointsOnSameCurve (const SelectableList& items)
35{
36 CurveEditor* ed = nullptr;
37
38 for (auto point : items.getItemsOfType<CurveEditorPoint>())
39 {
40 if (ed == nullptr)
41 ed = point->editor;
42 else if (ed != point->editor)
43 return false;
44 }
45
46 return true;
47}
48
49bool CurveEditorPoint::arePointsConsecutive (const SelectableList& items)
50{
52 getPointIndexes (set, items);
53
54 for (int i = 0; i < set.size() - 1; ++i)
55 if (set[i + 1] > set[i] + 1)
56 return false;
57
58 return arePointsOnSameCurve (items);
59}
60
61TimeRange CurveEditorPoint::getPointTimeRange (const SelectableList& items)
62{
64
65 if (auto ed = getPointIndexes (set, items))
66 return { ed->getPointTime (set.getFirst()),
67 ed->getPointTime (set.getLast()) };
68
69 return {};
70}
71
73{
74 if (editor != nullptr)
75 {
76 editor->updateLineThickness();
77 editor->repaint();
78 }
79}
80
81//==============================================================================
82CurveEditor::CurveEditor (Edit& e, SelectionManager& sm)
83 : MouseHoverDetector (200),
84 edit (e),
85 undoManager (edit.getUndoManager()),
86 selectionManager (sm)
87{
88 setAlwaysOnTop (true);
89 setHoverComponent (this, false);
90 selectionManager.addChangeListener (this);
91}
92
93CurveEditor::~CurveEditor()
94{
95 selectionManager.removeChangeListener (this);
96
97 for (auto p : selectionManager.getItemsOfType<CurveEditorPoint>())
98 if (p->editor == this)
99 selectionManager.deselect (p);
100
102}
103
104void CurveEditor::updateLineThickness()
105{
106 auto newthickness = (isMouseOverOrDragging() || isCurveSelected || areAnyPointsSelected())
107 ? 2.0f : 1.0f;
108
109 if (lineThickness != newthickness)
110 {
111 lineThickness = newthickness;
112 repaint();
113 }
114}
115
116void CurveEditor::paint (juce::Graphics& g)
117{
119
120 if ((rightTime - leftTime) == TimeDuration())
121 return;
122
123 const bool isOver = isMouseOverOrDragging();
124 auto curveColour = getCurrentLineColour();
125 auto backgroundColour = getBackgroundColour();
126
127 // draw the name of the curve
128 if (isOver || isCurveSelected)
129 {
130 g.setColour (getCurveNameTextBackgroundColour());
131 auto text = getCurveName();
132 g.setFont (13.0f);
133 auto tw = g.getCurrentFont().getStringWidth (text);
134 auto tx = getCurveNameOffset() - (tw + 8);
135 g.fillRect (tx, 0, tw + 6, 16);
136
137 g.setColour (getDefaultLineColour());
138 g.drawText (text, tx, 0, tw + 6, 16,
140 }
141
142 // draw the line to the first point, or all the way across if there are no points
143 const int start = std::max (0, nextIndexAfter (leftTime) - 1);
144 const int numPoints = getNumPoints();
145
146 auto clipBounds = g.getClipBounds();
147
148 {
149 const auto startX = std::max (0.0f, timeToX ({}));
150 auto lastY = valueToY (getValueAt (leftTime));
151
152 juce::Path curvePath;
153 curvePath.startNewSubPath (startX, lastY);
154 curvePath.preallocateSpace (numPoints * 5 + 1);
155
156 if (numPoints > 0)
157 {
158 for (int index = start; index < numPoints - 1; ++index)
159 {
160 if (index == start)
161 curvePath.lineTo (getPosition (index));
162
163 auto p2 = getPosition (index + 1);
164 auto c = getPointCurve (index);
165
166 if (c == 0)
167 {
168 curvePath.lineTo (p2);
169 }
170 else
171 {
172 auto bp = getPosition (getBezierPoint (index));
173
174 if (c >= -0.5 && c <= 0.5)
175 {
176 curvePath.quadraticTo (bp, p2);
177 }
178 else
179 {
180 double lineX1, lineX2;
181 float lineY1, lineY2;
182 getBezierEnds (index, lineX1, lineY1, lineX2, lineY2);
183
184 curvePath.lineTo (getPosition ({ TimePosition::fromSeconds (lineX1), lineY1 }));
185 curvePath.quadraticTo (bp, getPosition ({ TimePosition::fromSeconds (lineX2), lineY2 }));
186 curvePath.lineTo (p2);
187 }
188 }
189
190 lastY = p2.y;
191
192 if (p2.x > clipBounds.getRight())
193 break;
194 }
195 }
196
197 curvePath.lineTo ((float) getWidth(), lastY);
198
199 if (auto fillCol = getCurrentFillColour(); ! fillCol.isTransparent())
200 {
201 juce::Path fillPath (curvePath);
202 const auto y = getHeight() + 1.0f;
203 fillPath.lineTo ((float) getWidth(), y);
204 fillPath.lineTo (startX, y);
205 fillPath.closeSubPath();
206
207 g.setColour (fillCol);
208 g.fillPath (fillPath);
209 }
210
211 g.setColour (getCurrentLineColour());
212 g.strokePath (curvePath, juce::PathStrokeType (lineThickness));
213 }
214
215 // draw the points along the line - the points, the add point and the curve point
216 const bool anySelected = areAnyPointsSelected();
217
218 if (isOver || isCurveSelected || anySelected)
219 {
220 juce::RectangleList<float> rects, selectedRects, fills;
221 rects.ensureStorageAllocated (numPoints);
222
223 if (anySelected)
224 fills.ensureStorageAllocated (numPoints);
225
226 // draw the white points
227 for (int i = start; i < numPoints; ++i)
228 {
229 auto pos = getPosition (i);
230
231 juce::Rectangle<float> r (pos.x - pointRadius,
232 pos.y - pointRadius,
233 pointRadius * 2,
234 pointRadius * 2);
235 r = r.reduced (2);
236
237 if (r.getX() > clipBounds.getRight())
238 break;
239
240 const bool isSelected = isPointSelected (i);
241
242 if (isSelected)
243 selectedRects.addWithoutMerging (r);
244 else
245 rects.addWithoutMerging (r);
246
247 if (! isSelected && i != pointUnderMouse)
248 fills.addWithoutMerging (r.reduced (1.0f));
249 }
250
251 g.setColour (getPointOutlineColour());
252 g.fillRectList (rects);
253
254 g.setColour (backgroundColour);
255 g.fillRectList (fills);
256
257 g.setColour (getSelectedLineColour());
258 g.fillRectList (selectedRects);
259
260 // draw the curve points
261 for (int i = start; i < numPoints - 1; ++i)
262 {
263 auto pos = getPosition (getBezierHandle (i));
264
265 juce::Rectangle<float> r (pos.x - pointRadius,
266 pos.y - pointRadius,
267 pointRadius * 2,
268 pointRadius * 2);
269 r = r.reduced (2);
270
271 if (r.getX() > clipBounds.getRight())
272 break;
273
274 g.setColour (curveColour);
275 g.fillEllipse (r);
276
277 if (i != curveUnderMouse && ! isPointSelected (i))
278 {
279 g.setColour (backgroundColour);
280 g.fillEllipse (r.reduced (1.0f));
281 }
282 }
283 }
284}
285
286bool CurveEditor::hitTest (int x, int y)
287{
288 auto py1 = valueToY (getValueAt (xToTime (x - 3.0f)));
289 auto py2 = valueToY (getValueAt (xToTime (x + 3.0f)));
290
291 if (y > std::min (py1, py2) - 4.0f && y < std::max (py1, py2) + 4.0f)
292 return true;
293
294 for (int i = firstIndexOnScreen; i < getNumPoints(); ++i)
295 {
296 auto t = getPointTime (i);
297
298 if (t >= rightTime)
299 break;
300
301 auto px = timeToX (t);
302 auto py = valueToY (getPointValue (i));
303
304 if (std::abs (x - px) < pointRadius
305 && std::abs (y - py) < pointRadius + 2)
306 return true;
307 }
308
309 return false;
310}
311
312void CurveEditor::visibilityChanged()
313{
314 updateLineThickness();
315}
316
317void CurveEditor::mouseDown (const juce::MouseEvent& e)
318{
320
321 if (getItem() == nullptr)
322 return;
323
325 {
326 mouseDoubleClick(e);
327 return;
328 }
329
330 dragged = false;
331 pointBeingMoved = pointUnderMouse;
332
333 if (pointBeingMoved >= 0)
334 movingAllPoints = e.mods.isShiftDown() && e.mods.isCommandDown();
335 else
336 movingAllPoints = false;
337
338 if (pointUnderMouse != -1)
339 {
340 if (e.mods.isShiftDown() && areAnyPointsSelected())
341 {
342 int selPoint = 0;
343
344 if (auto firstPoint = selectionManager.getFirstItemOfType<CurveEditorPoint>())
345 selPoint = firstPoint->index;
346
347 int start = std::min (selPoint, pointUnderMouse);
348 int end = std::max (selPoint, pointUnderMouse);
349
350 selectionManager.deselectAll();
351
352 for (int i = start; i <= end; ++i)
353 selectPoint (i, true);
354 }
355 else if (e.mods.isCommandDown())
356 {
357 if (isPointSelected (pointUnderMouse))
358 selectionManager.deselect (getSelectedPoint (pointUnderMouse));
359 else
360 selectionManager.addToSelection (createPoint (pointUnderMouse));
361 }
362 else
363 {
364 selectionManager.deselectAll();
365 selectPoint (pointUnderMouse, false);
366 }
367 }
368 else if (curveUnderMouse != -1)
369 {
370 selectionManager.deselectAll();
371 selectPoint (curveUnderMouse, false);
372 }
373 else
374 {
375 selectionManager.select (getItem(), e.mods.isShiftDown());
376 }
377}
378
379juce::Colour CurveEditor::getCurrentFillColour()
380{
381 return juce::Colours::transparentWhite;
382}
383
384void CurveEditor::selectPoint (int pointIdx, bool addToSelection)
385{
386 if (pointIdx >= 0 && pointIdx < getNumPoints() && ! isPointSelected (pointIdx))
387 selectionManager.select (createPoint (pointIdx), addToSelection);
388}
389
390void CurveEditor::mouseDrag (const juce::MouseEvent& e)
391{
392 yieldGUIThread();
393
394 if (getItem() == nullptr)
395 return;
396
397 // test if we are just starting to drag and the mouse has moved
398 if (! dragged)
399 {
400 if (e.getDistanceFromDragStart() <= 1)
401 return;
402
404 dragged = true;
405
406 if (realTimeDrag)
407 undoManager.beginNewTransaction();
408 else
409 nonRealTimeDragStart();
410
411 mouseDownTime = xToTime (e.mouseDownPosition.x);
412 mouseDownValue = yToValue (e.mouseDownPosition.y);
413 mouseDownCurve = curveUnderMouse >= 0 ? getPointCurve (curveUnderMouse) : 0.0f;
414
415 if (lineUnderMouse >= 0)
416 {
417 // add new endpoints to the line
418 if (e.mods.isCommandDown())
419 {
420 auto t1 = getPointTime (lineUnderMouse);
421 auto t2 = getPointTime (lineUnderMouse + 1);
422 auto v1 = getPointValue (lineUnderMouse);
423 auto v2 = getPointValue (lineUnderMouse + 1);
424 auto c1 = getPointCurve (lineUnderMouse);
425 auto c2 = getPointCurve (lineUnderMouse + 1);
426
427 addPoint (t1, v1, c1);
428 addPoint (t2 - TimeDuration::fromSeconds (0.0000001), v2, c2); // Shift this a fraction forwards so it inserts before any existing points
429
430 lineUnderMouse++;
431
432 selectionManager.deselectAll();
433 selectPoint (lineUnderMouse, true);
434 selectPoint (lineUnderMouse + 1, true);
435 }
436
437 point1 = getPointValue (lineUnderMouse);
438 point2 = getPointValue (lineUnderMouse + 1);
439 }
440 else if (curveUnderMouse == -1 && pointUnderMouse == -1 && getNumPoints() <= 1)
441 {
442 if (getNumPoints() == 1)
443 point1 = getPointValue (0);
444 else
445 point1 = getValueAt ({});
446 }
447 else if (getNumPoints())
448 {
449 point1 = getPointValue (0);
450 point2 = getPointValue (getNumPoints() - 1);
451 }
452 }
453
454 if (pointBeingMoved >= 0 && realTimeDrag)
455 undoManager.undoCurrentTransactionOnly();
456
457 // bend a line or move a line
458 if (curveUnderMouse >= 0)
459 {
461
462 // bend a curve
463 auto mult = getPointValue (curveUnderMouse) < getPointValue (curveUnderMouse + 1) ? 1 : -1;
464 auto c = juce::jlimit (-1.0f, 1.0f, mult * e.getDistanceFromDragStartY() / 75.0f + mouseDownCurve);
465 curvePoint (curveUnderMouse, c);
466 showBubbleForPointUnderMouse();
467 }
468 // move a point around
469 else if (pointBeingMoved >= 0)
470 {
472 auto t = snapTime (xToTime (e.position.x), e.mods);
473
474 if (movingAllPoints)
475 {
476 auto delta = t - mouseDownTime;
477
478 if (delta > TimeDuration())
479 {
480 for (int i = getNumPoints(); --i >= pointBeingMoved;)
481 movePoint (i, getPointTime (i) + delta, getPointValue (i), false);
482 }
483 else
484 {
485 bool firstPoint = true;
486
487 for (int i = pointBeingMoved; i < getNumPoints(); ++i)
488 {
489 auto newIndex = movePoint (i,
490 getPointTime (i) + delta,
491 getPointValue (i),
492 i == pointBeingMoved
495
496 if (firstPoint)
497 {
498 firstPoint = false;
499
500 i -= pointBeingMoved - newIndex;
501 pointUnderMouse = newIndex;
502 }
503 }
504 }
505 }
506 else
507 {
508 auto newTime = t;
509 auto newValue = yToValue (e.position.y);
510
511 if (juce::ModifierKeys::getCurrentModifiers().isShiftDown())
512 {
513 if (std::abs (e.getDistanceFromDragStartX()) > std::abs (e.getDistanceFromDragStartY()))
514 newValue = getPointValue(pointBeingMoved);
515 else
516 newTime = getPointTime(pointBeingMoved);
517 }
518
519 pointUnderMouse = movePoint (pointBeingMoved, newTime, newValue,
522 }
523
524 showBubbleForPointUnderMouse();
525 }
526 else if (lineUnderMouse >= 0)
527 {
528 // move a line up and down
530 auto offset = mouseDownValue - yToValue (e.position.y);
531
532 movePoint (lineUnderMouse, getPointTime(lineUnderMouse), point1 - offset, false);
533 movePoint (lineUnderMouse + 1, getPointTime(lineUnderMouse + 1), point2 - offset, false);
534 }
535 else
536 {
538 auto offset = mouseDownValue - yToValue (e.position.y);
539
540 if (getNumPoints() <= 0)
541 setValueWhenNoPoints (point1 - offset);
542 else if (getNumPoints() == 1 || mouseDownTime < getPointTime (0))
543 movePoint (0, getPointTime (0), point1 - offset, false);
544 else if (mouseDownTime > getPointTime (getNumPoints() - 1))
545 movePoint (getNumPoints() - 1, getPointTime (getNumPoints() - 1), point2 - offset, false);
546 }
547
549 updateLineThickness();
550 repaint();
551
552 if (areAnyPointsSelected())
553 for (auto c : selectionManager.getItemsOfType<CurveEditorPoint>())
554 c->changed();
555}
556
557void CurveEditor::mouseUp (const juce::MouseEvent& e)
558{
559 if (getItem() == nullptr)
560 return;
561
562 if (dragged)
563 {
564 if (pointBeingMoved >= 0)
565 {
566 auto newPoint = getPosition (pointUnderMouse);
567
568 for (int i = std::max (0, pointBeingMoved - 1); i < std::min (pointBeingMoved + 2, getNumPoints()); ++i)
569 {
570 auto pos = getPosition (i);
571
572 if (i != pointBeingMoved && pos.getDistanceFrom (newPoint) < 7.0f)
573 {
574 // too near to an existing point - so remove it..
575 removePoint (pointBeingMoved);
576 break;
577 }
578 }
579 }
580
581 if (realTimeDrag)
582 undoManager.beginNewTransaction();
583 else
584 nonRealTimeDragEnd();
585 }
586
587 dragged = false;
588 pointBeingMoved = -1;
589
590 updatePointUnderMouse (e.position);
591 updateLineThickness();
592 repaint();
593
594 hideBubble();
595}
596
597void CurveEditor::mouseDoubleClick (const juce::MouseEvent& e)
598{
599 if (getItem() == nullptr)
600 return;
601
602 if (pointUnderMouse >= 0 && ! dragged)
603 {
604 if (auto p = getSelectedPoint (pointUnderMouse))
605 p->deselect();
606
607 removePoint (pointUnderMouse);
608 }
609 else if (pointUnderMouse < 0)
610 {
611 auto t = snapTime (xToTime (e.position.x), e.mods);
612 auto value = getValueAt (t);
613
614 if (juce::Point<float> (e.position.x, valueToY (value)).getDistanceFrom (e.position) < 8.0f)
615 {
616 // add a new point on the line if we've clicked near enough
617 undoManager.beginNewTransaction();
618
619 auto pnt = addPoint (t, value, defaultCurve);
620
621 if (pnt >= 0)
622 selectPoint (pnt, false);
623
624 undoManager.beginNewTransaction();
625 }
626 }
627}
628
629void CurveEditor::mouseMove (const juce::MouseEvent& e)
630{
631 if (getItem() == nullptr)
632 return;
633
634 updatePointUnderMouse (e.position);
635 updateLineThickness();
636}
637
638void CurveEditor::mouseEnter (const juce::MouseEvent& e)
639{
640 mouseMove (e);
641 updateLineThickness();
642}
643
644void CurveEditor::mouseExit (const juce::MouseEvent& e)
645{
646 mouseMove (e);
647 updateLineThickness();
648}
649
650void CurveEditor::mouseHovered (int, int)
651{
652 showBubbleForPointUnderMouse();
653}
654
655void CurveEditor::mouseMovedAfterHover()
656{
657 hideBubble();
658}
659
660juce::MouseCursor CurveEditor::getMouseCursor()
661{
662 if (pointUnderMouse != -1 || curveUnderMouse != -1
665
667}
668
669void CurveEditor::updatePointUnderMouse (juce::Point<float> pos)
670{
671 if (getItem() == nullptr || pointBeingMoved >= 0)
672 return;
673
674 pos.x = std::max (timeToX ({}), pos.x);
675
676 const auto captureRadius = pointRadius * pointRadius;
677 int point = -1;
678 int curvePoint = -1;
679
680 for (int i = firstIndexOnScreen; i < getNumPoints(); ++i)
681 {
682 auto t = getPointTime (i);
683
684 if (t >= rightTime)
685 break;
686
687 // check if there is a point under the mouse
688 if (getPosition ({ t, getPointValue (i) }).getDistanceSquaredFrom (pos) < captureRadius)
689 {
690 point = i;
691 break;
692 }
693
694 // check if there is a curve dragger under the mouse
695 if (i < getNumPoints() - 1)
696 if (getPosition (getBezierHandle (i)).getDistanceSquaredFrom (pos) < captureRadius)
697 curvePoint = i;
698 }
699
700 if (pointUnderMouse != point)
701 {
702 pointUnderMouse = point;
703 repaint();
704 }
705
706 if (! dragged)
707 {
708 if (pointUnderMouse != -1)
709 curvePoint = -1;
710
711 if (curveUnderMouse != curvePoint)
712 {
713 curveUnderMouse = curvePoint;
714 repaint();
715 }
716
717 int newLineUnderMouse = -1;
718
719 if (pointUnderMouse == -1 && curveUnderMouse == -1)
720 {
721 auto numPoints = getNumPoints();
722
723 for (int i = 0; i < numPoints - 1; ++i)
724 {
725 auto t = xToTime (pos.x);
726
727 if (t > getPointTime(i) && t < getPointTime (i + 1))
728 newLineUnderMouse = i;
729 }
730 }
731
732 if (newLineUnderMouse != lineUnderMouse)
733 {
734 lineUnderMouse = newLineUnderMouse;
735 repaint();
736 }
737 }
738}
739
740void CurveEditor::setTimes (TimePosition l, TimePosition r)
741{
742 leftTime = l;
743 rightTime = r;
744}
745
746float CurveEditor::timeToX (TimePosition t) const
747{
748 return (float) (getWidth() * ((t - leftTime) / (rightTime - leftTime)));
749}
750
751TimePosition CurveEditor::xToTime (double x) const
752{
753 return TimePosition::fromSeconds (std::max (0.0, leftTime.inSeconds() + (x * (rightTime - leftTime).inSeconds()) / getWidth()));
754}
755
756float CurveEditor::valueToY (float val) const
757{
758 return 1.0f + (1.0f - (val - parameterMinValue) / parameterRange) * (getHeight() - 2);
759}
760
761float CurveEditor::yToValue (double y) const
762{
763 return (float) ((1.0 - (y - 1) / (getHeight() - 2)) * parameterRange + parameterMinValue);
764}
765
767{
768 return { timeToX (toTime (p.time, edit.tempoSequence)), valueToY (p.value) };
769}
770
772{
773 return getPosition ({ getPointTime (index), getPointValue (index) });
774}
775
776void CurveEditor::selectableObjectChanged (Selectable*)
777{
778 updateLineThickness();
779}
780
781void CurveEditor::selectableObjectAboutToBeDeleted (Selectable*)
782{
783 updateLineThickness();
784}
785
786void CurveEditor::changeListenerCallback (juce::ChangeBroadcaster* cb)
787{
788 if (cb == &selectionManager)
789 {
790 const bool selectedNow = selectionManager.isSelected (getItem());
791
792 if (isCurveSelected != selectedNow)
793 {
794 isCurveSelected = selectedNow;
795 repaint();
796 }
797 }
798 else
799 {
800 updatePointUnderMouse (getMouseXYRelative().toFloat());
801 repaint();
802 }
803
804 if (isVisible())
805 updateLineThickness();
806}
807
808Edit& CurveEditor::getEdit() const
809{
810 return edit;
811}
812
813TimePosition CurveEditor::snapTime (TimePosition time, juce::ModifierKeys)
814{
815 return time;
816}
817
818bool CurveEditor::isPointSelected (int idx)
819{
820 for (auto p : selectionManager.getItemsOfType<CurveEditorPoint>())
821 if (p->editor == this && p->index == idx)
822 return true;
823
824 return false;
825}
826
827bool CurveEditor::areAnyPointsSelected()
828{
829 for (auto p : selectionManager.getItemsOfType<CurveEditorPoint>())
830 if (p->editor == this)
831 return true;
832
833 return false;
834}
835
836CurveEditorPoint* CurveEditor::getSelectedPoint (int idx)
837{
838 for (auto p : selectionManager.getItemsOfType<CurveEditorPoint>())
839 if (p->editor == this && p->index == idx)
840 return p;
841
842 return {};
843}
844
845}} // namespace tracktion { inline namespace engine
void ensureStorageAllocated(int minNumElements)
int size() const noexcept
ElementType getFirst() const noexcept
ElementType * begin() noexcept
ElementType * end() noexcept
void add(const ElementType &newElement)
ElementType getLast() const noexcept
void removeChangeListener(ChangeListener *listener)
bool isTransparent() const noexcept
void deleteAllChildren()
bool isMouseOverOrDragging(bool includeChildren=false) const
bool isVisible() const noexcept
Point< int > getPosition() const noexcept
int getHeight() const noexcept
Point< int > getMouseXYRelative() const
int getWidth() const noexcept
int getStringWidth(const String &text) const
void drawText(const String &text, int x, int y, int width, int height, Justification justificationType, bool useEllipsesIfTooBig=true) const
Font getCurrentFont() const
void setFont(const Font &newFont)
void fillRectList(const RectangleList< float > &rectangles) const
void fillRect(Rectangle< int > rectangle) const
void fillPath(const Path &path) const
Rectangle< int > getClipBounds() const
void setColour(Colour newColour)
void strokePath(const Path &path, const PathStrokeType &strokeType, const AffineTransform &transform={}) const
void fillEllipse(float x, float y, float width, float height) const
bool testFlags(int flagsToTest) const noexcept
static ModifierKeys getCurrentModifiers() noexcept
bool isCommandDown() const noexcept
bool isShiftDown() const noexcept
const Point< float > mouseDownPosition
const ModifierKeys mods
const Point< float > position
int getDistanceFromDragStart() const noexcept
int getDistanceFromDragStartY() const noexcept
int getDistanceFromDragStartX() const noexcept
void startNewSubPath(float startX, float startY)
void preallocateSpace(int numExtraCoordsToMakeSpaceFor)
void quadraticTo(float controlPointX, float controlPointY, float endPointX, float endPointY)
void lineTo(float endX, float endY)
ValueType y
ValueType x
void addWithoutMerging(RectangleType rect)
void ensureStorageAllocated(int minNumRectangles)
void beginNewTransaction()
bool undoCurrentTransactionOnly()
void selectionStatusChanged(bool isNowSelected) override
Can be overridden to tell this object that it has just been selected or deselected.
The Tracktion Edit class!
TempoSequence tempoSequence
The global TempoSequence of this Edit.
Manages a list of items that are currently selected.
T end(T... args)
T max(T... args)
T min(T... args)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
TimePosition toTime(BeatPosition bp, const TempoSequence &ts)
Converts a BeatPosition to a TimePosition given a TempoSequence.
RangeType< TimePosition > TimeRange
A RangeType based on real time (i.e.
T sort(T... args)
constexpr double inSeconds() const
Returns the TimePosition as a number of seconds.
time
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.